Generated on Mon Jul 6 18:09:03 2009 for Gecode by doxygen 1.5.9

mult.hpp

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: 2009-02-03 11:13:22 +0100 (Tue, 03 Feb 2009) $ by $Author: schulte $
00011  *     $Revision: 8129 $
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
00192   MultZeroOne<View,pc>::MultZeroOne(Space& home, bool share,
00193                                     MultZeroOne<View,pc>& p)
00194     : BinaryPropagator<View,pc>(home,share,p) {}
00195 
00196   template <class View, PropCond pc>
00197   Actor*
00198   MultZeroOne<View,pc>::copy(Space& home, bool share) {
00199     return new (home) MultZeroOne<View,pc>(home,share,*this);
00200   }
00201 
00202   template <class View, PropCond pc>
00203   ExecStatus
00204   MultZeroOne<View,pc>::propagate(Space& home, const ModEventDelta&) {
00205     switch (equal(x0,0)) {
00206     case RT_FALSE:
00207       GECODE_ME_CHECK(x1.eq(home,1));
00208       break;
00209     case RT_TRUE:
00210       break;
00211     case RT_MAYBE:
00212       switch (equal(x1,1)) {
00213       case RT_FALSE:
00214         GECODE_ME_CHECK(x0.eq(home,0));
00215         break;
00216       case RT_TRUE:
00217         break;
00218       case RT_MAYBE:
00219         return ES_FIX;
00220       default: GECODE_NEVER;
00221       }
00222       break;
00223     default: GECODE_NEVER;
00224     }
00225     return ES_SUBSUMED(*this,home);
00226   }
00227 
00228 
00229   /*
00230    * Positive bounds consistent multiplication
00231    *
00232    */
00233   template <class Val, class VA, class VB, class VC>
00234   forceinline ExecStatus
00235   prop_mult_plus_bnd(Space& home, Propagator& p, VA x0, VB x1, VC x2) {
00236     assert(pos(x0) && pos(x1) && pos(x2));
00237     bool mod;
00238     do {
00239       mod = false;
00240       {
00241         ModEvent me = x2.lq(home,m<Val>(x0.max(),x1.max()));
00242         if (me_failed(me)) return ES_FAILED;
00243         mod |= me_modified(me);
00244       }
00245       {
00246         ModEvent me = x2.gq(home,m<Val>(x0.min(),x1.min()));
00247         if (me_failed(me)) return ES_FAILED;
00248         mod |= me_modified(me);
00249       }
00250       {
00251         ModEvent me = x0.lq(home,f_d_p<Val>(x2.max(),x1.min()));
00252         if (me_failed(me)) return ES_FAILED;
00253         mod |= me_modified(me);
00254       }
00255       {
00256         ModEvent me = x0.gq(home,c_d_p<Val>(x2.min(),x1.max()));
00257         if (me_failed(me)) return ES_FAILED;
00258         mod |= me_modified(me);
00259       }
00260       {
00261         ModEvent me = x1.lq(home,f_d_p<Val>(x2.max(),x0.min()));
00262         if (me_failed(me)) return ES_FAILED;
00263         mod |= me_modified(me);
00264       }
00265       {
00266         ModEvent me = x1.gq(home,c_d_p<Val>(x2.min(),x0.max()));
00267         if (me_failed(me)) return ES_FAILED;
00268         mod |= me_modified(me);
00269       }
00270     } while (mod);
00271     return x0.assigned() && x1.assigned() ?
00272       ES_SUBSUMED(p,sizeof(p)) : ES_FIX;
00273   }
00274 
00275   template <class Val, class VA, class VB, class VC>
00276   forceinline
00277   MultPlusBnd<Val,VA,VB,VC>::MultPlusBnd(Space& home, VA x0, VB x1, VC x2)
00278     : MixTernaryPropagator<VA,PC_INT_BND,VB,PC_INT_BND,VC,PC_INT_BND>
00279   (home,x0,x1,x2) {}
00280 
00281   template <class Val, class VA, class VB, class VC>
00282   forceinline
00283   MultPlusBnd<Val,VA,VB,VC>::MultPlusBnd(Space& home, bool share,
00284                                    MultPlusBnd<Val,VA,VB,VC>& p)
00285     : MixTernaryPropagator<VA,PC_INT_BND,VB,PC_INT_BND,VC,PC_INT_BND>
00286   (home,share,p) {}
00287 
00288   template <class Val, class VA, class VB, class VC>
00289   Actor*
00290   MultPlusBnd<Val,VA,VB,VC>::copy(Space& home, bool share) {
00291     return new (home) MultPlusBnd<Val,VA,VB,VC>(home,share,*this);
00292   }
00293 
00294   template <class Val, class VA, class VB, class VC>
00295   ExecStatus
00296   MultPlusBnd<Val,VA,VB,VC>::propagate(Space& home, const ModEventDelta&) {
00297     return prop_mult_plus_bnd<Val,VA,VB,VC>(home,*this,x0,x1,x2);
00298   }
00299 
00300   template <class Val, class VA, class VB, class VC>
00301   forceinline ExecStatus
00302   MultPlusBnd<Val,VA,VB,VC>::post(Space& home, VA x0, VB x1, VC x2) {
00303     GECODE_ME_CHECK(x0.gr(home,0));
00304     GECODE_ME_CHECK(x1.gr(home,0));
00305     GECODE_ME_CHECK(x2.gq(home,(static_cast<double>(x0.min()) *
00306                                 static_cast<double>(x1.min()))));
00307     double u = static_cast<double>(x0.max()) * static_cast<double>(x1.max());
00308     if (u > INT_MAX) {
00309       (void) new (home) MultPlusBnd<double,VA,VB,VC>(home,x0,x1,x2);
00310     } else {
00311       GECODE_ME_CHECK(x2.lq(home,u));
00312       (void) new (home) MultPlusBnd<int,VA,VB,VC>(home,x0,x1,x2);
00313     }
00314     return ES_OK;
00315   }
00316 
00317 
00318   /*
00319    * Bounds consistent multiplication
00320    *
00321    */
00322   template <class View>
00323   forceinline
00324   MultBnd<View>::MultBnd(Space& home, View x0, View x1, View x2)
00325     : TernaryPropagator<View,PC_INT_BND>(home,x0,x1,x2) {}
00326 
00327   template <class View>
00328   forceinline
00329   MultBnd<View>::MultBnd(Space& home, bool share, MultBnd<View>& p)
00330     : TernaryPropagator<View,PC_INT_BND>(home,share,p) {}
00331 
00332   template <class View>
00333   Actor*
00334   MultBnd<View>::copy(Space& home, bool share) {
00335     return new (home) MultBnd<View>(home,share,*this);
00336   }
00337 
00338   template <class View>
00339   ExecStatus
00340   MultBnd<View>::propagate(Space& home, const ModEventDelta&) {
00341     if (pos(x0)) {
00342       if (pos(x1) || pos(x2)) goto rewrite_ppp;
00343       if (neg(x1) || neg(x2)) goto rewrite_pnn;
00344       goto prop_pxx;
00345     }
00346     if (neg(x0)) {
00347       if (neg(x1) || pos(x2)) goto rewrite_nnp;
00348       if (pos(x1) || neg(x2)) goto rewrite_npn;
00349       goto prop_nxx;
00350     }
00351     if (pos(x1)) {
00352       if (pos(x2)) goto rewrite_ppp;
00353       if (neg(x2)) goto rewrite_npn;
00354       goto prop_xpx;
00355     }
00356     if (neg(x1)) {
00357       if (pos(x2)) goto rewrite_nnp;
00358       if (neg(x2)) goto rewrite_pnn;
00359       goto prop_xnx;
00360     }
00361 
00362     assert(any(x0) && any(x1));
00363     GECODE_ME_CHECK(x2.lq(home,std::max(m<double>(x0.max(),x1.max()),
00364                                         m<double>(x0.min(),x1.min()))));
00365     GECODE_ME_CHECK(x2.gq(home,std::min(m<double>(x0.min(),x1.max()),
00366                                         m<double>(x0.max(),x1.min()))));
00367 
00368     if (x0.assigned()) {
00369       assert((x0.val() == 0) && (x2.val() == 0));
00370       return ES_SUBSUMED(*this,home);
00371     }
00372 
00373     if (x1.assigned()) {
00374       assert((x1.val() == 0) && (x2.val() == 0));
00375       return ES_SUBSUMED(*this,home);
00376     }
00377 
00378     return ES_NOFIX;
00379 
00380   prop_xpx:
00381     std::swap(x0,x1);
00382   prop_pxx:
00383     assert(pos(x0) && any(x1) && any(x2));
00384 
00385     GECODE_ME_CHECK(x2.lq(home,m<double>(x0.max(),x1.max())));
00386     GECODE_ME_CHECK(x2.gq(home,m<double>(x0.max(),x1.min())));
00387 
00388     if (pos(x2)) goto rewrite_ppp;
00389     if (neg(x2)) goto rewrite_pnn;
00390 
00391     GECODE_ME_CHECK(x1.lq(home,f_d(x2.max(),x0.min())));
00392     GECODE_ME_CHECK(x1.gq(home,c_d(x2.min(),x0.min())));
00393 
00394     if (x0.assigned() && x1.assigned()) {
00395       GECODE_ME_CHECK(x2.eq(home,m<double>(x0.val(),x1.val())));
00396       return ES_SUBSUMED(*this,sizeof(*this));
00397     }
00398 
00399     return ES_NOFIX;
00400 
00401   prop_xnx:
00402     std::swap(x0,x1);
00403   prop_nxx:
00404     assert(neg(x0) && any(x1) && any(x2));
00405 
00406     GECODE_ME_CHECK(x2.lq(home,m<double>(x0.min(),x1.min())));
00407     GECODE_ME_CHECK(x2.gq(home,m<double>(x0.min(),x1.max())));
00408 
00409     if (pos(x2)) goto rewrite_nnp;
00410     if (neg(x2)) goto rewrite_npn;
00411 
00412     GECODE_ME_CHECK(x1.lq(home,f_d(x2.min(),x0.max())));
00413     GECODE_ME_CHECK(x1.gq(home,c_d(x2.max(),x0.max())));
00414 
00415     if (x0.assigned() && x1.assigned()) {
00416       GECODE_ME_CHECK(x2.eq(home,m<double>(x0.val(),x1.val())));
00417       return ES_SUBSUMED(*this,sizeof(*this));
00418     }
00419 
00420     return ES_NOFIX;
00421 
00422   rewrite_ppp:
00423     GECODE_REWRITE(*this,(MultPlusBnd<double,IntView,IntView,IntView>
00424                          ::post(home,x0,x1,x2)));
00425   rewrite_nnp:
00426     GECODE_REWRITE(*this,(MultPlusBnd<double,MinusView,MinusView,IntView>
00427                          ::post(home,x0,x1,x2)));
00428   rewrite_pnn:
00429     std::swap(x0,x1);
00430   rewrite_npn:
00431     GECODE_REWRITE(*this,(MultPlusBnd<double,MinusView,IntView,MinusView>
00432                          ::post(home,x0,x1,x2)));
00433   }
00434 
00435   template <class View>
00436   ExecStatus
00437   MultBnd<View>::post(Space& home, View x0, View x1, View x2) {
00438     if (same(x0,x1))
00439       return SqrBnd<View>::post(home,x0,x2);
00440     if (same(x0,x2))
00441       return MultZeroOne<View,PC_INT_BND>::post(home,x0,x1);
00442     if (same(x1,x2))
00443       return MultZeroOne<View,PC_INT_BND>::post(home,x1,x0);
00444     if (pos(x0)) {
00445       if (pos(x1) || pos(x2)) goto post_ppp;
00446       if (neg(x1) || neg(x2)) goto post_pnn;
00447     } else if (neg(x0)) {
00448       if (neg(x1) || pos(x2)) goto post_nnp;
00449       if (pos(x1) || neg(x2)) goto post_npn;
00450     } else if (pos(x1)) {
00451       if (pos(x2)) goto post_ppp;
00452       if (neg(x2)) goto post_npn;
00453     } else if (neg(x1)) {
00454       if (pos(x2)) goto post_nnp;
00455       if (neg(x2)) goto post_pnn;
00456     }
00457     {
00458       double a =
00459         static_cast<double>(x0.min()) * static_cast<double>(x1.min());
00460       double b =
00461         static_cast<double>(x0.min()) * static_cast<double>(x1.max());
00462       double c =
00463         static_cast<double>(x0.max()) * static_cast<double>(x1.min());
00464       double d =
00465         static_cast<double>(x0.max()) * static_cast<double>(x1.max());
00466       GECODE_ME_CHECK(x2.gq(home,std::min(std::min(a,b),std::min(c,d))));
00467       GECODE_ME_CHECK(x2.lq(home,std::max(std::max(a,b),std::max(c,d))));
00468       (void) new (home) MultBnd<View>(home,x0,x1,x2);
00469     }
00470     return ES_OK;
00471 
00472   post_ppp:
00473     return MultPlusBnd<double,IntView,IntView,IntView>::post(home,x0,x1,x2);
00474   post_nnp:
00475     return MultPlusBnd<double,MinusView,MinusView,IntView>::post(home,x0,x1,x2);
00476   post_pnn:
00477     std::swap(x0,x1);
00478   post_npn:
00479     return MultPlusBnd<double,MinusView,IntView,MinusView>::post(home,x0,x1,x2);
00480   }
00481 
00482 
00483   /*
00484    * Positive domain consistent multiplication
00485    *
00486    */
00487   template <class Val, class View>
00488   forceinline ExecStatus
00489   prop_mult_dom(Space& home, Propagator& p, View x0, View x1, View x2) {
00490     Region r(home);
00491     SupportValues<View,Region> s0(r,x0), s1(r,x1), s2(r,x2);
00492     while (s0()) {
00493       while (s1()) {
00494         if (s2.support(m<Val>(s0.val(),s1.val()))) {
00495           s0.support(); s1.support();
00496         }
00497         ++s1;
00498       }
00499       s1.reset(); ++s0;
00500     }
00501     GECODE_ME_CHECK(s0.tell(home));
00502     GECODE_ME_CHECK(s1.tell(home));
00503     GECODE_ME_CHECK(s2.tell(home));
00504     return x0.assigned() && x1.assigned() ? ES_SUBSUMED(p,sizeof(p)) : ES_FIX;
00505   }
00506 
00507   template <class Val, class VA, class VB, class VC>
00508   forceinline
00509   MultPlusDom<Val,VA,VB,VC>::MultPlusDom(Space& home, VA x0, VB x1, VC x2)
00510     : MixTernaryPropagator<VA,PC_INT_DOM,VB,PC_INT_DOM,VC,PC_INT_DOM>
00511   (home,x0,x1,x2) {}
00512 
00513   template <class Val, class VA, class VB, class VC>
00514   forceinline
00515   MultPlusDom<Val,VA,VB,VC>::MultPlusDom(Space& home, bool share,
00516                                          MultPlusDom<Val,VA,VB,VC>& p)
00517     : MixTernaryPropagator<VA,PC_INT_DOM,VB,PC_INT_DOM,VC,PC_INT_DOM>
00518       (home,share,p) {}
00519 
00520   template <class Val, class VA, class VB, class VC>
00521   Actor*
00522   MultPlusDom<Val,VA,VB,VC>::copy(Space& home, bool share) {
00523     return new (home) MultPlusDom<Val,VA,VB,VC>(home,share,*this);
00524   }
00525 
00526   template <class Val, class VA, class VB, class VC>
00527   PropCost
00528   MultPlusDom<Val,VA,VB,VC>::cost(const Space&,
00529                                   const ModEventDelta& med) const {
00530     if (VA::me(med) == ME_INT_DOM)
00531       return PropCost::ternary(PropCost::HI);
00532     else
00533       return PropCost::ternary(PropCost::LO);
00534   }
00535 
00536   template <class Val, class VA, class VB, class VC>
00537   ExecStatus
00538   MultPlusDom<Val,VA,VB,VC>::propagate(Space& home, const ModEventDelta& med) {
00539     if (VA::me(med) != ME_INT_DOM) {
00540       GECODE_ES_CHECK((prop_mult_plus_bnd<Val,VA,VB,VC>(home,*this,x0,x1,x2)));
00541       return ES_FIX_PARTIAL(*this,VA::med(ME_INT_DOM));
00542     }
00543     IntView y0(x0.var()), y1(x1.var()), y2(x2.var());
00544     return prop_mult_dom<Val,IntView>(home,*this,y0,y1,y2);
00545   }
00546 
00547   template <class Val, class VA, class VB, class VC>
00548   forceinline ExecStatus
00549   MultPlusDom<Val,VA,VB,VC>::post(Space& home, VA x0, VB x1, VC x2) {
00550     GECODE_ME_CHECK(x0.gr(home,0));
00551     GECODE_ME_CHECK(x1.gr(home,0));
00552     GECODE_ME_CHECK(x2.gq(home,(static_cast<double>(x0.min()) *
00553                                 static_cast<double>(x1.min()))));
00554     double u = static_cast<double>(x0.max()) * static_cast<double>(x1.max());
00555     if (u > INT_MAX) {
00556       (void) new (home) MultPlusDom<double,VA,VB,VC>(home,x0,x1,x2);
00557     } else {
00558       GECODE_ME_CHECK(x2.lq(home,u));
00559       (void) new (home) MultPlusDom<int,VA,VB,VC>(home,x0,x1,x2);
00560     }
00561     return ES_OK;
00562   }
00563 
00564 
00565   /*
00566    * Bounds consistent multiplication
00567    *
00568    */
00569   template <class View>
00570   forceinline
00571   MultDom<View>::MultDom(Space& home, View x0, View x1, View x2)
00572     : TernaryPropagator<View,PC_INT_DOM>(home,x0,x1,x2) {}
00573 
00574   template <class View>
00575   forceinline
00576   MultDom<View>::MultDom(Space& home, bool share, MultDom<View>& p)
00577     : TernaryPropagator<View,PC_INT_DOM>(home,share,p) {}
00578 
00579   template <class View>
00580   Actor*
00581   MultDom<View>::copy(Space& home, bool share) {
00582     return new (home) MultDom<View>(home,share,*this);
00583   }
00584 
00585   template <class View>
00586   PropCost
00587   MultDom<View>::cost(const Space&, const ModEventDelta& med) const {
00588     if (View::me(med) == ME_INT_DOM)
00589       return PropCost::ternary(PropCost::HI);
00590     else
00591       return PropCost::ternary(PropCost::LO);
00592   }
00593 
00594   template <class View>
00595   ExecStatus
00596   MultDom<View>::propagate(Space& home, const ModEventDelta& med) {
00597     if (View::me(med) != ME_INT_DOM) {
00598       if (pos(x0)) {
00599         if (pos(x1) || pos(x2)) goto rewrite_ppp;
00600         if (neg(x1) || neg(x2)) goto rewrite_pnn;
00601         goto prop_pxx;
00602       }
00603       if (neg(x0)) {
00604         if (neg(x1) || pos(x2)) goto rewrite_nnp;
00605         if (pos(x1) || neg(x2)) goto rewrite_npn;
00606         goto prop_nxx;
00607       }
00608       if (pos(x1)) {
00609         if (pos(x2)) goto rewrite_ppp;
00610         if (neg(x2)) goto rewrite_npn;
00611         goto prop_xpx;
00612       }
00613       if (neg(x1)) {
00614         if (pos(x2)) goto rewrite_nnp;
00615         if (neg(x2)) goto rewrite_pnn;
00616         goto prop_xnx;
00617       }
00618 
00619       assert(any(x0) && any(x1));
00620       GECODE_ME_CHECK(x2.lq(home,std::max(m<double>(x0.max(),x1.max()),
00621                                           m<double>(x0.min(),x1.min()))));
00622       GECODE_ME_CHECK(x2.gq(home,std::min(m<double>(x0.min(),x1.max()),
00623                                           m<double>(x0.max(),x1.min()))));
00624 
00625       if (x0.assigned()) {
00626         assert((x0.val() == 0) && (x2.val() == 0));
00627         return ES_SUBSUMED(*this,home);
00628       }
00629 
00630       if (x1.assigned()) {
00631         assert((x1.val() == 0) && (x2.val() == 0));
00632         return ES_SUBSUMED(*this,home);
00633       }
00634 
00635       return ES_NOFIX_PARTIAL(*this,View::med(ME_INT_DOM));
00636 
00637     prop_xpx:
00638       std::swap(x0,x1);
00639     prop_pxx:
00640       assert(pos(x0) && any(x1) && any(x2));
00641 
00642       GECODE_ME_CHECK(x2.lq(home,m<double>(x0.max(),x1.max())));
00643       GECODE_ME_CHECK(x2.gq(home,m<double>(x0.max(),x1.min())));
00644 
00645       if (pos(x2)) goto rewrite_ppp;
00646       if (neg(x2)) goto rewrite_pnn;
00647 
00648       GECODE_ME_CHECK(x1.lq(home,f_d(x2.max(),x0.min())));
00649       GECODE_ME_CHECK(x1.gq(home,c_d(x2.min(),x0.min())));
00650 
00651       if (x0.assigned() && x1.assigned()) {
00652         GECODE_ME_CHECK(x2.eq(home,m<double>(x0.val(),x1.val())));
00653         return ES_SUBSUMED(*this,sizeof(*this));
00654       }
00655 
00656       return ES_NOFIX_PARTIAL(*this,View::med(ME_INT_DOM));
00657 
00658     prop_xnx:
00659       std::swap(x0,x1);
00660     prop_nxx:
00661       assert(neg(x0) && any(x1) && any(x2));
00662 
00663       GECODE_ME_CHECK(x2.lq(home,m<double>(x0.min(),x1.min())));
00664       GECODE_ME_CHECK(x2.gq(home,m<double>(x0.min(),x1.max())));
00665 
00666       if (pos(x2)) goto rewrite_nnp;
00667       if (neg(x2)) goto rewrite_npn;
00668 
00669       GECODE_ME_CHECK(x1.lq(home,f_d(x2.min(),x0.max())));
00670       GECODE_ME_CHECK(x1.gq(home,c_d(x2.max(),x0.max())));
00671 
00672       if (x0.assigned() && x1.assigned()) {
00673         GECODE_ME_CHECK(x2.eq(home,m<double>(x0.val(),x1.val())));
00674         return ES_SUBSUMED(*this,sizeof(*this));
00675       }
00676 
00677       return ES_NOFIX_PARTIAL(*this,View::med(ME_INT_DOM));
00678 
00679     rewrite_ppp:
00680       GECODE_REWRITE(*this,(MultPlusDom<double,IntView,IntView,IntView>
00681                            ::post(home,x0,x1,x2)));
00682     rewrite_nnp:
00683       GECODE_REWRITE(*this,(MultPlusDom<double,MinusView,MinusView,IntView>
00684                            ::post(home,x0,x1,x2)));
00685     rewrite_pnn:
00686       std::swap(x0,x1);
00687     rewrite_npn:
00688       GECODE_REWRITE(*this,(MultPlusDom<double,MinusView,IntView,MinusView>
00689                            ::post(home,x0,x1,x2)));
00690     }
00691     return prop_mult_dom<double,View>(home,*this,x0,x1,x2);
00692   }
00693 
00694   template <class View>
00695   ExecStatus
00696   MultDom<View>::post(Space& home, View x0, View x1, View x2) {
00697     if (same(x0,x1))
00698       return SqrDom<View>::post(home,x0,x2);
00699     if (same(x0,x2))
00700       return MultZeroOne<View,PC_INT_DOM>::post(home,x0,x1);
00701     if (same(x1,x2))
00702       return MultZeroOne<View,PC_INT_DOM>::post(home,x1,x0);
00703     if (pos(x0)) {
00704       if (pos(x1) || pos(x2)) goto post_ppp;
00705       if (neg(x1) || neg(x2)) goto post_pnn;
00706     } else if (neg(x0)) {
00707       if (neg(x1) || pos(x2)) goto post_nnp;
00708       if (pos(x1) || neg(x2)) goto post_npn;
00709     } else if (pos(x1)) {
00710       if (pos(x2)) goto post_ppp;
00711       if (neg(x2)) goto post_npn;
00712     } else if (neg(x1)) {
00713       if (pos(x2)) goto post_nnp;
00714       if (neg(x2)) goto post_pnn;
00715     }
00716     {
00717       double a =
00718         static_cast<double>(x0.min()) * static_cast<double>(x1.min());
00719       double b =
00720         static_cast<double>(x0.min()) * static_cast<double>(x1.max());
00721       double c =
00722         static_cast<double>(x0.max()) * static_cast<double>(x1.min());
00723       double d =
00724         static_cast<double>(x0.max()) * static_cast<double>(x1.max());
00725       GECODE_ME_CHECK(x2.gq(home,std::min(std::min(a,b),std::min(c,d))));
00726       GECODE_ME_CHECK(x2.lq(home,std::max(std::max(a,b),std::max(c,d))));
00727       (void) new (home) MultDom<View>(home,x0,x1,x2);
00728     }
00729     return ES_OK;
00730 
00731   post_ppp:
00732     return MultPlusDom<double,IntView,IntView,IntView>::post(home,x0,x1,x2);
00733   post_nnp:
00734     return MultPlusDom<double,MinusView,MinusView,IntView>::post(home,x0,x1,x2);
00735   post_pnn:
00736     std::swap(x0,x1);
00737   post_npn:
00738     return MultPlusDom<double,MinusView,IntView,MinusView>::post(home,x0,x1,x2);
00739   }
00740 
00741 }}}
00742 
00743 // STATISTICS: int-prop
00744