Generated on Mon Aug 25 11:35:35 2008 for Gecode by doxygen 1.5.6

mult.icc

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Christian Schulte <schulte@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Christian Schulte, 2004
00008  *
00009  *  Last modified:
00010  *     $Date: 2008-07-11 10:52:51 +0200 (Fri, 11 Jul 2008) $ by $Author: tack $
00011  *     $Revision: 7352 $
00012  *
00013  *  This file is part of Gecode, the generic constraint
00014  *  development environment:
00015  *     http://www.gecode.org
00016  *
00017  *  Permission is hereby granted, free of charge, to any person obtaining
00018  *  a copy of this software and associated documentation files (the
00019  *  "Software"), to deal in the Software without restriction, including
00020  *  without limitation the rights to use, copy, modify, merge, publish,
00021  *  distribute, sublicense, and/or sell copies of the Software, and to
00022  *  permit persons to whom the Software is furnished to do so, subject to
00023  *  the following conditions:
00024  *
00025  *  The above copyright notice and this permission notice shall be
00026  *  included in all copies or substantial portions of the Software.
00027  *
00028  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00029  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00030  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00031  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00032  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00033  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00034  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00035  *
00036  */
00037 
00038 #include <cmath>
00039 #include <climits>
00040 
00041 #include "gecode/int/support-values.hh"
00042 
00043 namespace Gecode { namespace Int { namespace Arithmetic {
00044 
00045   /*
00046    * Arithmetic help functions
00047    *
00048    */
00049 
00051   template<class Val>
00052   Val m(int x, int y);
00053 
00055   template<class Val>
00056   Val m(int x, double y);
00057 
00058   template<>
00059   forceinline double
00060   m(int x, int y) {
00061     return static_cast<double>(x)*static_cast<double>(y);
00062   }
00063 
00064   template<>
00065   forceinline double
00066   m(int x, double y) {
00067     return static_cast<double>(x)*y;
00068   }
00069 
00070   template<>
00071   forceinline int
00072   m(int x, int y) {
00073     return x*y;
00074   }
00075 
00077   template<class Val>
00078   int c_d_p(int x, Val y);
00080   template<class Val>
00081   int f_d_p(int x, Val y);
00082 
00083   template <>
00084   forceinline int
00085   c_d_p<int>(int x, int y) {
00086     assert((x >= 0) && (y >= 0));
00087     return (x+y-1)/y;
00088   }
00089   template <>
00090   forceinline int
00091   c_d_p<double>(int x, double y) {
00092     assert((x >= 0) && (y >= 0));
00093     return static_cast<int>(ceil(static_cast<double>(x) / y));
00094   }
00095   template <>
00096   forceinline int
00097   f_d_p<int>(int x, int y) {
00098     assert((x >= 0) && (y >= 0));
00099     return x/y;
00100   }
00101   template <>
00102   forceinline int
00103   f_d_p<double>(int x, double y) {
00104     assert((x >= 0) && (y >= 0));
00105     return static_cast<int>(floor(static_cast<double>(x) / y));
00106   }
00107 
00108 
00110   forceinline int
00111   f_d(int x, int y) {
00112     return static_cast<int>(floor(static_cast<double>(x) /
00113                                   static_cast<double>(y)));
00114   }
00115 
00117   forceinline int
00118   c_d(int x, int y) {
00119     return static_cast<int>(ceil(static_cast<double>(x) /
00120                                  static_cast<double>(y)));
00121   }
00122 
00124   template <class View>
00125   forceinline bool
00126   pos(const View& x) {
00127     return x.min() > 0;
00128   }
00130   template <class View>
00131   forceinline bool
00132   neg(const View& x) {
00133     return x.max() < 0;
00134   }
00136   template <class View>
00137   forceinline bool
00138   any(const View& x) {
00139     return (x.min() <= 0) && (x.max() >= 0);
00140   }
00141 
00142 
00143   /*
00144    * Propagator for x * y = x
00145    *
00146    */
00147 
00148   template <class View, PropCond pc>
00149   forceinline
00150   MultZeroOne<View,pc>::MultZeroOne(Space* home, View x0, View x1)
00151     : BinaryPropagator<View,pc>(home,x0,x1) {}
00152 
00153   template <class View, PropCond pc>
00154   forceinline RelTest
00155   MultZeroOne<View,pc>::equal(View x, int n) {
00156     if (pc == PC_INT_DOM) {
00157       return rtest_eq_dom(x,n);
00158     } else {
00159       return rtest_eq_bnd(x,n);
00160     }
00161   }
00162 
00163   template <class View, PropCond pc>
00164   forceinline ExecStatus
00165   MultZeroOne<View,pc>::post(Space* home, View x0, View x1) {
00166     switch (equal(x0,0)) {
00167     case RT_FALSE:
00168       GECODE_ME_CHECK(x1.eq(home,1)); 
00169       break;
00170     case RT_TRUE:
00171       break;
00172     case RT_MAYBE:
00173       switch (equal(x1,1)) {
00174       case RT_FALSE:
00175         GECODE_ME_CHECK(x0.eq(home,0)); 
00176         break;
00177       case RT_TRUE:
00178         break;
00179       case RT_MAYBE:
00180         (void) new (home) MultZeroOne<View,pc>(home,x0,x1); 
00181         break;
00182       default: GECODE_NEVER;
00183       }
00184       break;
00185     default: GECODE_NEVER;
00186     }
00187     return ES_OK;
00188   }
00189 
00190   template <class View, PropCond pc>
00191   forceinline void
00192   MultZeroOne<View,pc>::post(Space* home, Reflection::VarMap& vars,
00193                           const Reflection::ActorSpec& spec) {
00194      spec.checkArity(2);
00195      View x0(home, vars, spec[0]);
00196      View x1(home, vars, spec[1]);
00197      (void) new (home) MultZeroOne<View,pc>(home,x0,x1);
00198   }
00199 
00200   template <class View, PropCond pc>
00201   forceinline
00202   MultZeroOne<View,pc>::MultZeroOne(Space* home, bool share, 
00203                                     MultZeroOne<View,pc>& p)
00204     : BinaryPropagator<View,pc>(home,share,p) {}
00205 
00206   template <class View, PropCond pc>
00207   Actor*
00208   MultZeroOne<View,pc>::copy(Space* home, bool share) {
00209     return new (home) MultZeroOne<View,pc>(home,share,*this);
00210   }
00211 
00212   template <class View, PropCond pc>
00213   ExecStatus
00214   MultZeroOne<View,pc>::propagate(Space* home, ModEventDelta) {
00215     switch (equal(x0,0)) {
00216     case RT_FALSE:
00217       GECODE_ME_CHECK(x1.eq(home,1)); 
00218       break;
00219     case RT_TRUE:
00220       break;
00221     case RT_MAYBE:
00222       switch (equal(x1,1)) {
00223       case RT_FALSE:
00224         GECODE_ME_CHECK(x0.eq(home,0)); 
00225         break;
00226       case RT_TRUE:
00227         break;
00228       case RT_MAYBE:
00229         return ES_FIX;
00230       default: GECODE_NEVER;
00231       }
00232       break;
00233     default: GECODE_NEVER;
00234     }
00235     return ES_SUBSUMED(this,home);
00236   }
00237 
00238   template <class View, PropCond pc>
00239   Support::Symbol
00240   MultZeroOne<View,pc>::ati(void) {
00241     return Reflection::mangle<View>
00242       ("Gecode::Int::Arithmetic::MultZeroOne", pc);
00243   }
00244 
00245   template <class View, PropCond pc>
00246   Reflection::ActorSpec
00247   MultZeroOne<View,pc>::spec(const Space* home, Reflection::VarMap& m) const {
00248     return BinaryPropagator<View,pc>::spec(home, m, ati());
00249   }
00250 
00251 
00252   /*
00253    * Positive bounds consistent multiplication
00254    *
00255    */
00256   template <class Val, class VA, class VB, class VC>
00257   forceinline ExecStatus
00258   prop_mult_plus_bnd(Space* home, Propagator* p, VA x0, VB x1, VC x2) {
00259     assert(pos(x0) && pos(x1) && pos(x2));
00260     bool mod;
00261     do {
00262       mod = false;
00263       {
00264         ModEvent me = x2.lq(home,m<Val>(x0.max(),x1.max()));
00265         if (me_failed(me)) return ES_FAILED;
00266         mod |= me_modified(me);
00267       }
00268       {
00269         ModEvent me = x2.gq(home,m<Val>(x0.min(),x1.min()));
00270         if (me_failed(me)) return ES_FAILED;
00271         mod |= me_modified(me);
00272       }
00273       {
00274         ModEvent me = x0.lq(home,f_d_p<Val>(x2.max(),x1.min()));
00275         if (me_failed(me)) return ES_FAILED;
00276         mod |= me_modified(me);
00277       }
00278       {
00279         ModEvent me = x0.gq(home,c_d_p<Val>(x2.min(),x1.max()));
00280         if (me_failed(me)) return ES_FAILED;
00281         mod |= me_modified(me);
00282       }
00283       {
00284         ModEvent me = x1.lq(home,f_d_p<Val>(x2.max(),x0.min()));
00285         if (me_failed(me)) return ES_FAILED;
00286         mod |= me_modified(me);
00287       }
00288       {
00289         ModEvent me = x1.gq(home,c_d_p<Val>(x2.min(),x0.max()));
00290         if (me_failed(me)) return ES_FAILED;
00291         mod |= me_modified(me);
00292       }
00293     } while (mod);
00294     return x0.assigned() && x1.assigned() ?
00295       ES_SUBSUMED(p,sizeof(*p)) : ES_FIX;
00296   }
00297 
00298   template <class Val, class VA, class VB, class VC>
00299   forceinline
00300   MultPlusBnd<Val,VA,VB,VC>::MultPlusBnd(Space* home, VA x0, VB x1, VC x2)
00301     : MixTernaryPropagator<VA,PC_INT_BND,VB,PC_INT_BND,VC,PC_INT_BND>
00302   (home,x0,x1,x2) {}
00303 
00304   template <class Val, class VA, class VB, class VC>
00305   forceinline
00306   MultPlusBnd<Val,VA,VB,VC>::MultPlusBnd(Space* home, bool share, 
00307                                    MultPlusBnd<Val,VA,VB,VC>& p)
00308     : MixTernaryPropagator<VA,PC_INT_BND,VB,PC_INT_BND,VC,PC_INT_BND>
00309   (home,share,p) {}
00310 
00311   template <class Val, class VA, class VB, class VC>
00312   Actor*
00313   MultPlusBnd<Val,VA,VB,VC>::copy(Space* home, bool share) {
00314     return new (home) MultPlusBnd<Val,VA,VB,VC>(home,share,*this);
00315   }
00316 
00317   template <class Val, class VA, class VB, class VC>
00318   ExecStatus
00319   MultPlusBnd<Val,VA,VB,VC>::propagate(Space* home, ModEventDelta) {
00320     return prop_mult_plus_bnd<Val,VA,VB,VC>(home,this,x0,x1,x2);
00321   }
00322 
00323   template <class Val, class VA, class VB, class VC>
00324   forceinline ExecStatus
00325   MultPlusBnd<Val,VA,VB,VC>::post(Space* home, VA x0, VB x1, VC x2) {
00326     GECODE_ME_CHECK(x0.gr(home,0));
00327     GECODE_ME_CHECK(x1.gr(home,0));
00328     GECODE_ME_CHECK(x2.gq(home,(static_cast<double>(x0.min()) * 
00329                                 static_cast<double>(x1.min()))));
00330     double u = static_cast<double>(x0.max()) * static_cast<double>(x1.max());
00331     if (u > INT_MAX) {
00332       (void) new (home) MultPlusBnd<double,VA,VB,VC>(home,x0,x1,x2);
00333     } else {
00334       GECODE_ME_CHECK(x2.lq(home,u));
00335       (void) new (home) MultPlusBnd<int,VA,VB,VC>(home,x0,x1,x2);
00336     }
00337     return ES_OK;
00338   }
00339 
00340   template <class Val, class VA, class VB, class VC>
00341   forceinline void
00342   MultPlusBnd<Val,VA,VB,VC>::post(Space* home, Reflection::VarMap& vars,
00343                                   const Reflection::ActorSpec& spec) {
00344      spec.checkArity(3);
00345      VA x0(home, vars, spec[0]);
00346      VB x1(home, vars, spec[1]);
00347      VC x2(home, vars, spec[2]);
00348      (void) new (home) MultPlusBnd<Val,VA,VB,VC>(home,x0,x1,x2);
00349   }
00350 
00351   template <class Val, class VA, class VB, class VC>
00352   Support::Symbol
00353   MultPlusBnd<Val,VA,VB,VC>::ati(void) {
00354     return Reflection::mangle<VA,VB,VC,Val>
00355       ("Gecode::Int::Arithmetic::MultPlusBnd");
00356   }
00357 
00358   template <class Val, class VA, class VB, class VC>
00359   Reflection::ActorSpec
00360   MultPlusBnd<Val,VA,VB,VC>::spec(const Space* home,
00361                                Reflection::VarMap& m) const {
00362     return MixTernaryPropagator<VA,PC_INT_BND,VB,PC_INT_BND,VC,PC_INT_BND>
00363       ::spec(home, m, ati());
00364   }
00365 
00366 
00367   /*
00368    * Bounds consistent multiplication
00369    *
00370    */
00371   template <class View>
00372   forceinline
00373   MultBnd<View>::MultBnd(Space* home, View x0, View x1, View x2)
00374     : TernaryPropagator<View,PC_INT_BND>(home,x0,x1,x2) {}
00375 
00376   template <class View>
00377   forceinline
00378   MultBnd<View>::MultBnd(Space* home, bool share, MultBnd<View>& p)
00379     : TernaryPropagator<View,PC_INT_BND>(home,share,p) {}
00380 
00381   template <class View>
00382   Actor*
00383   MultBnd<View>::copy(Space* home, bool share) {
00384     return new (home) MultBnd<View>(home,share,*this);
00385   }
00386 
00387   template <class View>
00388   ExecStatus
00389   MultBnd<View>::propagate(Space* home, ModEventDelta) {
00390     if (pos(x0)) {
00391       if (pos(x1) || pos(x2)) goto rewrite_ppp;
00392       if (neg(x1) || neg(x2)) goto rewrite_pnn;
00393       goto prop_pxx;
00394     }
00395     if (neg(x0)) {
00396       if (neg(x1) || pos(x2)) goto rewrite_nnp;
00397       if (pos(x1) || neg(x2)) goto rewrite_npn;
00398       goto prop_nxx;
00399     }
00400     if (pos(x1)) {
00401       if (pos(x2)) goto rewrite_ppp;
00402       if (neg(x2)) goto rewrite_npn;
00403       goto prop_xpx;
00404     }
00405     if (neg(x1)) {
00406       if (pos(x2)) goto rewrite_nnp;
00407       if (neg(x2)) goto rewrite_pnn;
00408       goto prop_xnx;
00409     }
00410 
00411     assert(any(x0) && any(x1));
00412     GECODE_ME_CHECK(x2.lq(home,std::max(m<double>(x0.max(),x1.max()),
00413                                         m<double>(x0.min(),x1.min()))));
00414     GECODE_ME_CHECK(x2.gq(home,std::min(m<double>(x0.min(),x1.max()),
00415                                         m<double>(x0.max(),x1.min()))));
00416 
00417     if (x0.assigned()) {
00418       assert((x0.val() == 0) && (x2.val() == 0));
00419       return ES_SUBSUMED(this,home);
00420     }
00421 
00422     if (x1.assigned()) {
00423       assert((x1.val() == 0) && (x2.val() == 0));
00424       return ES_SUBSUMED(this,home);
00425     }
00426 
00427     return ES_NOFIX;
00428 
00429   prop_xpx:
00430     std::swap(x0,x1);
00431   prop_pxx:
00432     assert(pos(x0) && any(x1) && any(x2));
00433 
00434     GECODE_ME_CHECK(x2.lq(home,m<double>(x0.max(),x1.max())));
00435     GECODE_ME_CHECK(x2.gq(home,m<double>(x0.max(),x1.min())));
00436 
00437     if (pos(x2)) goto rewrite_ppp;
00438     if (neg(x2)) goto rewrite_pnn;
00439 
00440     GECODE_ME_CHECK(x1.lq(home,f_d(x2.max(),x0.min())));
00441     GECODE_ME_CHECK(x1.gq(home,c_d(x2.min(),x0.min())));
00442 
00443     if (x0.assigned() && x1.assigned()) {
00444       GECODE_ME_CHECK(x2.eq(home,m<double>(x0.val(),x1.val())));
00445       return ES_SUBSUMED(this,sizeof(*this));
00446     }
00447 
00448     return ES_NOFIX;
00449 
00450   prop_xnx:
00451     std::swap(x0,x1);
00452   prop_nxx:
00453     assert(neg(x0) && any(x1) && any(x2));
00454 
00455     GECODE_ME_CHECK(x2.lq(home,m<double>(x0.min(),x1.min())));
00456     GECODE_ME_CHECK(x2.gq(home,m<double>(x0.min(),x1.max())));
00457 
00458     if (pos(x2)) goto rewrite_nnp;
00459     if (neg(x2)) goto rewrite_npn;
00460 
00461     GECODE_ME_CHECK(x1.lq(home,f_d(x2.min(),x0.max())));
00462     GECODE_ME_CHECK(x1.gq(home,c_d(x2.max(),x0.max())));
00463 
00464     if (x0.assigned() && x1.assigned()) {
00465       GECODE_ME_CHECK(x2.eq(home,m<double>(x0.val(),x1.val())));
00466       return ES_SUBSUMED(this,sizeof(*this));
00467     }
00468 
00469     return ES_NOFIX;
00470 
00471   rewrite_ppp:
00472     GECODE_REWRITE(this,(MultPlusBnd<double,IntView,IntView,IntView>
00473                          ::post(home,x0,x1,x2)));
00474   rewrite_nnp:
00475     GECODE_REWRITE(this,(MultPlusBnd<double,MinusView,MinusView,IntView>
00476                          ::post(home,x0,x1,x2)));
00477   rewrite_pnn:
00478     std::swap(x0,x1);
00479   rewrite_npn:
00480     GECODE_REWRITE(this,(MultPlusBnd<double,MinusView,IntView,MinusView>
00481                          ::post(home,x0,x1,x2)));
00482   }
00483 
00484   template <class View>
00485   ExecStatus
00486   MultBnd<View>::post(Space* home, View x0, View x1, View x2) {
00487     if (same(x0,x1))
00488       return SqrBnd<View>::post(home,x0,x2);
00489     if (same(x0,x2))
00490       return MultZeroOne<View,PC_INT_BND>::post(home,x0,x1);
00491     if (same(x1,x2))
00492       return MultZeroOne<View,PC_INT_BND>::post(home,x1,x0);
00493     if (pos(x0)) {
00494       if (pos(x1) || pos(x2)) goto post_ppp;
00495       if (neg(x1) || neg(x2)) goto post_pnn;
00496     } else if (neg(x0)) {
00497       if (neg(x1) || pos(x2)) goto post_nnp;
00498       if (pos(x1) || neg(x2)) goto post_npn;
00499     } else if (pos(x1)) {
00500       if (pos(x2)) goto post_ppp;
00501       if (neg(x2)) goto post_npn;
00502     } else if (neg(x1)) {
00503       if (pos(x2)) goto post_nnp;
00504       if (neg(x2)) goto post_pnn;
00505     }
00506     {
00507       double a =
00508         static_cast<double>(x0.min()) * static_cast<double>(x1.min());
00509       double b =
00510         static_cast<double>(x0.min()) * static_cast<double>(x1.max());
00511       double c =
00512         static_cast<double>(x0.max()) * static_cast<double>(x1.min());
00513       double d =
00514         static_cast<double>(x0.max()) * static_cast<double>(x1.max());
00515       GECODE_ME_CHECK(x2.gq(home,std::min(std::min(a,b),std::min(c,d))));
00516       GECODE_ME_CHECK(x2.lq(home,std::max(std::max(a,b),std::max(c,d))));
00517       (void) new (home) MultBnd<View>(home,x0,x1,x2);
00518     }
00519     return ES_OK;
00520 
00521   post_ppp:
00522     return MultPlusBnd<double,IntView,IntView,IntView>::post(home,x0,x1,x2);
00523   post_nnp:
00524     return MultPlusBnd<double,MinusView,MinusView,IntView>::post(home,x0,x1,x2);
00525   post_pnn:
00526     std::swap(x0,x1);
00527   post_npn:
00528     return MultPlusBnd<double,MinusView,IntView,MinusView>::post(home,x0,x1,x2);
00529   }
00530 
00531   template <class View>
00532   forceinline void
00533   MultBnd<View>::post(Space* home, Reflection::VarMap& vars,
00534                    const Reflection::ActorSpec& spec) {
00535      spec.checkArity(3);
00536      View x0(home, vars, spec[0]);
00537      View x1(home, vars, spec[1]);
00538      View x2(home, vars, spec[2]);
00539      (void) new (home) MultBnd<View>(home,x0,x1,x2);
00540   }
00541 
00542   template <class View>
00543   Support::Symbol
00544   MultBnd<View>::ati(void) {
00545     return Reflection::mangle<View>("Gecode::Int::Arithmetic::MultBnd");
00546   }
00547 
00548   template <class View>
00549   Reflection::ActorSpec
00550   MultBnd<View>::spec(const Space* home, Reflection::VarMap& m) const {
00551     return TernaryPropagator<View,PC_INT_BND>::spec(home, m, ati());
00552   }
00553 
00554 
00555 
00556   /*
00557    * Positive domain consistent multiplication
00558    *
00559    */
00560   template <class Val, class View>
00561   forceinline ExecStatus
00562   prop_mult_dom(Space* home, Propagator* p, View x0, View x1, View x2) {
00563     SupportValues<View> s0(x0), s1(x1), s2(x2);
00564     while (s0()) {
00565       while (s1()) {
00566         if (s2.support(m<Val>(s0.val(),s1.val()))) {
00567           s0.support(); s1.support();
00568         }
00569         ++s1;
00570       }
00571       s1.reset(); ++s0;
00572     }
00573     GECODE_ME_CHECK(s0.tell(home));
00574     GECODE_ME_CHECK(s1.tell(home));
00575     GECODE_ME_CHECK(s2.tell(home));
00576     return x0.assigned() && x1.assigned() ? ES_SUBSUMED(p,sizeof(*p)) : ES_FIX;
00577   }
00578 
00579   template <class Val, class VA, class VB, class VC>
00580   forceinline
00581   MultPlusDom<Val,VA,VB,VC>::MultPlusDom(Space* home, VA x0, VB x1, VC x2)
00582     : MixTernaryPropagator<VA,PC_INT_DOM,VB,PC_INT_DOM,VC,PC_INT_DOM>
00583   (home,x0,x1,x2) {}
00584 
00585   template <class Val, class VA, class VB, class VC>
00586   forceinline
00587   MultPlusDom<Val,VA,VB,VC>::MultPlusDom(Space* home, bool share, 
00588                                          MultPlusDom<Val,VA,VB,VC>& p)
00589     : MixTernaryPropagator<VA,PC_INT_DOM,VB,PC_INT_DOM,VC,PC_INT_DOM>
00590       (home,share,p) {}
00591 
00592   template <class Val, class VA, class VB, class VC>
00593   Actor*
00594   MultPlusDom<Val,VA,VB,VC>::copy(Space* home, bool share) {
00595     return new (home) MultPlusDom<Val,VA,VB,VC>(home,share,*this);
00596   }
00597 
00598   template <class Val, class VA, class VB, class VC>
00599   PropCost
00600   MultPlusDom<Val,VA,VB,VC>::cost(ModEventDelta med) const {
00601     return (VA::me(med) == ME_INT_DOM) ? PC_TERNARY_HI : PC_TERNARY_LO;
00602   }
00603 
00604   template <class Val, class VA, class VB, class VC>
00605   ExecStatus
00606   MultPlusDom<Val,VA,VB,VC>::propagate(Space* home, ModEventDelta med) {
00607     if (VA::me(med) != ME_INT_DOM) {
00608       GECODE_ES_CHECK((prop_mult_plus_bnd<Val,VA,VB,VC>(home,this,x0,x1,x2)));
00609       return ES_FIX_PARTIAL(this,VA::med(ME_INT_DOM));
00610     }
00611     IntView y0(x0.var()), y1(x1.var()), y2(x2.var());
00612     return prop_mult_dom<Val,IntView>(home,this,y0,y1,y2);
00613   }
00614 
00615   template <class Val, class VA, class VB, class VC>
00616   forceinline ExecStatus
00617   MultPlusDom<Val,VA,VB,VC>::post(Space* home, VA x0, VB x1, VC x2) {
00618     GECODE_ME_CHECK(x0.gr(home,0));
00619     GECODE_ME_CHECK(x1.gr(home,0));
00620     GECODE_ME_CHECK(x2.gq(home,(static_cast<double>(x0.min()) * 
00621                                 static_cast<double>(x1.min()))));
00622     double u = static_cast<double>(x0.max()) * static_cast<double>(x1.max());
00623     if (u > INT_MAX) {
00624       (void) new (home) MultPlusDom<double,VA,VB,VC>(home,x0,x1,x2);
00625     } else {
00626       GECODE_ME_CHECK(x2.lq(home,u));
00627       (void) new (home) MultPlusDom<int,VA,VB,VC>(home,x0,x1,x2);
00628     }
00629     return ES_OK;
00630   }
00631 
00632   template <class Val, class VA, class VB, class VC>
00633   forceinline void
00634   MultPlusDom<Val,VA,VB,VC>::post(Space* home, Reflection::VarMap& vars,
00635                                   const Reflection::ActorSpec& spec) {
00636      spec.checkArity(3);
00637      VA x0(home, vars, spec[0]);
00638      VB x1(home, vars, spec[1]);
00639      VC x2(home, vars, spec[2]);
00640      (void) new (home) MultPlusDom<Val,VA,VB,VC>(home,x0,x1,x2);
00641   }
00642 
00643   template <class Val, class VA, class VB, class VC>
00644   Support::Symbol
00645   MultPlusDom<Val,VA,VB,VC>::ati(void) {
00646     return Reflection::mangle<VA,VB,VC,Val>
00647       ("Gecode::Int::Arithmetic::MultPlusDom");
00648   }
00649 
00650   template <class Val, class VA, class VB, class VC>
00651   Reflection::ActorSpec
00652   MultPlusDom<Val,VA,VB,VC>::spec(const Space* home,
00653                                Reflection::VarMap& m) const {
00654     return MixTernaryPropagator<VA,PC_INT_DOM,VB,PC_INT_DOM,VC,PC_INT_DOM>
00655       ::spec(home, m, ati());
00656   }
00657 
00658 
00659   /*
00660    * Bounds consistent multiplication
00661    *
00662    */
00663   template <class View>
00664   forceinline
00665   MultDom<View>::MultDom(Space* home, View x0, View x1, View x2)
00666     : TernaryPropagator<View,PC_INT_DOM>(home,x0,x1,x2) {}
00667 
00668   template <class View>
00669   forceinline
00670   MultDom<View>::MultDom(Space* home, bool share, MultDom<View>& p)
00671     : TernaryPropagator<View,PC_INT_DOM>(home,share,p) {}
00672 
00673   template <class View>
00674   Actor*
00675   MultDom<View>::copy(Space* home, bool share) {
00676     return new (home) MultDom<View>(home,share,*this);
00677   }
00678 
00679   template <class View>
00680   PropCost
00681   MultDom<View>::cost(ModEventDelta med) const {
00682     return (View::me(med) == ME_INT_DOM) ? PC_TERNARY_HI : PC_TERNARY_LO;
00683   }
00684 
00685   template <class View>
00686   ExecStatus
00687   MultDom<View>::propagate(Space* home, ModEventDelta med) {
00688     if (View::me(med) != ME_INT_DOM) {
00689       if (pos(x0)) {
00690         if (pos(x1) || pos(x2)) goto rewrite_ppp;
00691         if (neg(x1) || neg(x2)) goto rewrite_pnn;
00692         goto prop_pxx;
00693       }
00694       if (neg(x0)) {
00695         if (neg(x1) || pos(x2)) goto rewrite_nnp;
00696         if (pos(x1) || neg(x2)) goto rewrite_npn;
00697         goto prop_nxx;
00698       }
00699       if (pos(x1)) {
00700         if (pos(x2)) goto rewrite_ppp;
00701         if (neg(x2)) goto rewrite_npn;
00702         goto prop_xpx;
00703       }
00704       if (neg(x1)) {
00705         if (pos(x2)) goto rewrite_nnp;
00706         if (neg(x2)) goto rewrite_pnn;
00707         goto prop_xnx;
00708       }
00709 
00710       assert(any(x0) && any(x1));
00711       GECODE_ME_CHECK(x2.lq(home,std::max(m<double>(x0.max(),x1.max()),
00712                                           m<double>(x0.min(),x1.min()))));
00713       GECODE_ME_CHECK(x2.gq(home,std::min(m<double>(x0.min(),x1.max()),
00714                                           m<double>(x0.max(),x1.min()))));
00715 
00716       if (x0.assigned()) {
00717         assert((x0.val() == 0) && (x2.val() == 0));
00718         return ES_SUBSUMED(this,home);
00719       }
00720 
00721       if (x1.assigned()) {
00722         assert((x1.val() == 0) && (x2.val() == 0));
00723         return ES_SUBSUMED(this,home);
00724       }
00725 
00726       return ES_NOFIX_PARTIAL(this,View::med(ME_INT_DOM));
00727       
00728     prop_xpx:
00729       std::swap(x0,x1);
00730     prop_pxx:
00731       assert(pos(x0) && any(x1) && any(x2));
00732       
00733       GECODE_ME_CHECK(x2.lq(home,m<double>(x0.max(),x1.max())));
00734       GECODE_ME_CHECK(x2.gq(home,m<double>(x0.max(),x1.min())));
00735       
00736       if (pos(x2)) goto rewrite_ppp;
00737       if (neg(x2)) goto rewrite_pnn;
00738       
00739       GECODE_ME_CHECK(x1.lq(home,f_d(x2.max(),x0.min())));
00740       GECODE_ME_CHECK(x1.gq(home,c_d(x2.min(),x0.min())));
00741       
00742       if (x0.assigned() && x1.assigned()) {
00743         GECODE_ME_CHECK(x2.eq(home,m<double>(x0.val(),x1.val())));
00744         return ES_SUBSUMED(this,sizeof(*this));
00745       }
00746       
00747       return ES_NOFIX_PARTIAL(this,View::med(ME_INT_DOM));
00748       
00749     prop_xnx:
00750       std::swap(x0,x1);
00751     prop_nxx:
00752       assert(neg(x0) && any(x1) && any(x2));
00753       
00754       GECODE_ME_CHECK(x2.lq(home,m<double>(x0.min(),x1.min())));
00755       GECODE_ME_CHECK(x2.gq(home,m<double>(x0.min(),x1.max())));
00756       
00757       if (pos(x2)) goto rewrite_nnp;
00758       if (neg(x2)) goto rewrite_npn;
00759       
00760       GECODE_ME_CHECK(x1.lq(home,f_d(x2.min(),x0.max())));
00761       GECODE_ME_CHECK(x1.gq(home,c_d(x2.max(),x0.max())));
00762       
00763       if (x0.assigned() && x1.assigned()) {
00764         GECODE_ME_CHECK(x2.eq(home,m<double>(x0.val(),x1.val())));
00765         return ES_SUBSUMED(this,sizeof(*this));
00766       }
00767       
00768       return ES_NOFIX_PARTIAL(this,View::med(ME_INT_DOM));
00769       
00770     rewrite_ppp:
00771       GECODE_REWRITE(this,(MultPlusDom<double,IntView,IntView,IntView>
00772                            ::post(home,x0,x1,x2)));
00773     rewrite_nnp:
00774       GECODE_REWRITE(this,(MultPlusDom<double,MinusView,MinusView,IntView>
00775                            ::post(home,x0,x1,x2)));
00776     rewrite_pnn:
00777       std::swap(x0,x1);
00778     rewrite_npn:
00779       GECODE_REWRITE(this,(MultPlusDom<double,MinusView,IntView,MinusView>
00780                            ::post(home,x0,x1,x2)));
00781     }
00782     return prop_mult_dom<double,View>(home,this,x0,x1,x2);
00783   }
00784 
00785   template <class View>
00786   ExecStatus
00787   MultDom<View>::post(Space* home, View x0, View x1, View x2) {
00788     if (same(x0,x1))
00789       return SqrDom<View>::post(home,x0,x2);
00790     if (same(x0,x2))
00791       return MultZeroOne<View,PC_INT_DOM>::post(home,x0,x1);
00792     if (same(x1,x2))
00793       return MultZeroOne<View,PC_INT_DOM>::post(home,x1,x0);
00794     if (pos(x0)) {
00795       if (pos(x1) || pos(x2)) goto post_ppp;
00796       if (neg(x1) || neg(x2)) goto post_pnn;
00797     } else if (neg(x0)) {
00798       if (neg(x1) || pos(x2)) goto post_nnp;
00799       if (pos(x1) || neg(x2)) goto post_npn;
00800     } else if (pos(x1)) {
00801       if (pos(x2)) goto post_ppp;
00802       if (neg(x2)) goto post_npn;
00803     } else if (neg(x1)) {
00804       if (pos(x2)) goto post_nnp;
00805       if (neg(x2)) goto post_pnn;
00806     }
00807     {
00808       double a =
00809         static_cast<double>(x0.min()) * static_cast<double>(x1.min());
00810       double b =
00811         static_cast<double>(x0.min()) * static_cast<double>(x1.max());
00812       double c =
00813         static_cast<double>(x0.max()) * static_cast<double>(x1.min());
00814       double d =
00815         static_cast<double>(x0.max()) * static_cast<double>(x1.max());
00816       GECODE_ME_CHECK(x2.gq(home,std::min(std::min(a,b),std::min(c,d))));
00817       GECODE_ME_CHECK(x2.lq(home,std::max(std::max(a,b),std::max(c,d))));
00818       (void) new (home) MultDom<View>(home,x0,x1,x2);
00819     }
00820     return ES_OK;
00821 
00822   post_ppp:
00823     return MultPlusDom<double,IntView,IntView,IntView>::post(home,x0,x1,x2);
00824   post_nnp:
00825     return MultPlusDom<double,MinusView,MinusView,IntView>::post(home,x0,x1,x2);
00826   post_pnn:
00827     std::swap(x0,x1);
00828   post_npn:
00829     return MultPlusDom<double,MinusView,IntView,MinusView>::post(home,x0,x1,x2);
00830   }
00831 
00832   template <class View>
00833   forceinline void
00834   MultDom<View>::post(Space* home, Reflection::VarMap& vars,
00835                       const Reflection::ActorSpec& spec) {
00836      spec.checkArity(3);
00837      View x0(home, vars, spec[0]);
00838      View x1(home, vars, spec[1]);
00839      View x2(home, vars, spec[2]);
00840      (void) new (home) MultDom<View>(home,x0,x1,x2);
00841   }
00842 
00843   template <class View>
00844   Support::Symbol
00845   MultDom<View>::ati(void) {
00846     return Reflection::mangle<View>("Gecode::Int::Arithmetic::MultDom");
00847   }
00848 
00849   template <class View>
00850   Reflection::ActorSpec
00851   MultDom<View>::spec(const Space* home, Reflection::VarMap& m) const {
00852     return TernaryPropagator<View,PC_INT_DOM>::spec(home, m, ati());
00853   }
00854 
00855 }}}
00856 
00857 // STATISTICS: int-prop
00858