Generated on Tue May 22 09:40:14 2018 for Gecode by doxygen 1.6.3

minmax.hpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Guido Tack <tack@gecode.org>
00005  *     Christian Schulte <schulte@gecode.org>
00006  *     Gabor Szokoli <szokoli@gecode.org>
00007  *     Denys Duchier <denys.duchier@univ-orleans.fr>
00008  *
00009  *  Copyright:
00010  *     Guido Tack, 2004
00011  *     Christian Schulte, 2004
00012  *     Gabor Szokoli, 2004
00013  *
00014  *  This file is part of Gecode, the generic constraint
00015  *  development environment:
00016  *     http://www.gecode.org
00017  *
00018  *  Permission is hereby granted, free of charge, to any person obtaining
00019  *  a copy of this software and associated documentation files (the
00020  *  "Software"), to deal in the Software without restriction, including
00021  *  without limitation the rights to use, copy, modify, merge, publish,
00022  *  distribute, sublicense, and/or sell copies of the Software, and to
00023  *  permit persons to whom the Software is furnished to do so, subject to
00024  *  the following conditions:
00025  *
00026  *  The above copyright notice and this permission notice shall be
00027  *  included in all copies or substantial portions of the Software.
00028  *
00029  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00030  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00031  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00032  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00033  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00034  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00035  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00036  *
00037  */
00038 
00039 
00040 
00041 #include <gecode/set.hh>
00042 #include <gecode/int.hh>
00043 
00044 namespace Gecode { namespace Set { namespace Int {
00045 
00046   template<class View>
00047   forceinline
00048   MinElement<View>::MinElement(Home home, View y0, Gecode::Int::IntView y1)
00049     : MixBinaryPropagator<View,PC_SET_ANY,Gecode::Int::IntView,Gecode::Int::PC_INT_BND> (home, y0, y1) {}
00050 
00051   template<class View>
00052   forceinline ExecStatus
00053   MinElement<View>::post(Home home, View x0, Gecode::Int::IntView x1) {
00054     GECODE_ME_CHECK(x0.cardMin(home,1));
00055     (void) new (home) MinElement(home,x0,x1);
00056     return ES_OK;
00057   }
00058 
00059   template<class View>
00060   forceinline
00061   MinElement<View>::MinElement(Space& home, MinElement& p)
00062     : MixBinaryPropagator<View,PC_SET_ANY,Gecode::Int::IntView,Gecode::Int::PC_INT_BND> (home, p) {}
00063 
00064   template<class View>
00065   Actor*
00066   MinElement<View>::copy(Space& home) {
00067    return new (home) MinElement(home,*this);
00068   }
00069 
00070   template<class View>
00071   ExecStatus
00072   MinElement<View>::propagate(Space& home, const ModEventDelta&) {
00073     //x1 is an element of x0.ub
00074     //x1 =< smallest element of x0.lb
00075     //x1 =< x0.cardinialityMin-est largest element of x0.ub
00076     //(these 2 take care of determined x0)
00077     //No element in x0 is smaller than x1
00078     //if x1 is determined, it is part of the ub.
00079 
00080     //Consequently:
00081     //The domain of x1 is a subset of x0.ub up to the first element in x0.lb.
00082     //x0 lacks everything smaller than smallest possible x1.
00083 
00084     {
00085       LubRanges<View> ub(x0);
00086       GECODE_ME_CHECK(x1.inter_r(home,ub,false));
00087     }
00088     GECODE_ME_CHECK(x1.lq(home,x0.glbMin()));
00089     //if cardMin>lbSize?
00090     assert(x0.cardMin()>=1);
00091 
00092     {
00094       unsigned int size = 0;
00095       int maxN = BndSet::MAX_OF_EMPTY;
00096       for (LubRanges<View> ubr(x0); ubr(); ++ubr, ++size) {}
00097       Region r;
00098       int* ub = r.alloc<int>(size*2);
00099       {
00100         int i=0;
00101         for (LubRanges<View> ubr(x0); ubr(); ++ubr, ++i) {
00102           ub[2*i]   = ubr.min();
00103           ub[2*i+1] = ubr.max();
00104         }
00105       }
00106       unsigned int x0cm = x0.cardMin()-1;
00107       for (unsigned int i=size; i--;) {
00108         unsigned int width = static_cast<unsigned int>(ub[2*i+1]-ub[2*i]+1);
00109         if (width > x0cm) {
00110           maxN = static_cast<int>(ub[2*i+1]-x0cm);
00111           break;
00112         }
00113         x0cm -= width;
00114       }
00115       GECODE_ME_CHECK(x1.lq(home,maxN));
00116     }
00117 
00118     GECODE_ME_CHECK( x0.exclude(home,
00119                                 Limits::min, x1.min()-1) );
00120 
00121     if (x1.assigned()) {
00122       GECODE_ME_CHECK(x0.include(home,x1.val()));
00123       GECODE_ME_CHECK(x0.exclude(home,
00124                                  Limits::min, x1.val()-1));
00125       return home.ES_SUBSUMED(*this);
00126     }
00127 
00128     return ES_FIX;
00129   }
00130 
00131 
00132   template<class View>
00133   forceinline
00134   NotMinElement<View>::NotMinElement(Home home, View y0,
00135                                      Gecode::Int::IntView y1)
00136     : MixBinaryPropagator<View,PC_SET_ANY,
00137       Gecode::Int::IntView,Gecode::Int::PC_INT_DOM> (home, y0, y1) {}
00138 
00139   template<class View>
00140   forceinline ExecStatus
00141   NotMinElement<View>::post(Home home, View x0, Gecode::Int::IntView x1) {
00142     (void) new (home) NotMinElement(home,x0,x1);
00143     return ES_OK;
00144   }
00145 
00146   template<class View>
00147   forceinline
00148   NotMinElement<View>::NotMinElement(Space& home, NotMinElement& p)
00149     : MixBinaryPropagator<View,PC_SET_ANY,
00150       Gecode::Int::IntView,Gecode::Int::PC_INT_DOM> (home, p) {}
00151 
00152   template<class View>
00153   Actor*
00154   NotMinElement<View>::copy(Space& home) {
00155     return new (home) NotMinElement(home,*this);
00156   }
00157 
00158   template<class View>
00159   ExecStatus
00160   NotMinElement<View>::propagate(Space& home, const ModEventDelta&) {
00161     // cheap tests for entailment:
00162     // if x0 is empty, then entailed
00163     // if max(x1) < min(x0.lub) or min(x1) > max(x0.lub), then entailed
00164     // if min(x0.glb) < min(x1), then entailed
00165     if ((x0.cardMax() == 0) ||
00166         ((x1.max() < x0.lubMin()) || (x1.min() > x0.lubMax())) ||
00167         ((x0.glbSize() > 0) && (x0.glbMin() < x1.min())))
00168       return home.ES_SUBSUMED(*this);
00169     // if x1 is determined and = x0.lub.min: remove it from x0,
00170     // then entailed
00171     if (x1.assigned() && x1.val()==x0.lubMin()) {
00172       GECODE_ME_CHECK(x0.exclude(home,x1.val()));
00173       return home.ES_SUBSUMED(*this);
00174     }
00175     // if min(x0) is decided: remove min(x0) from the domain of x1
00176     // then entailed
00177     if (x0.glbMin() == x0.lubMin()) {
00178       GECODE_ME_CHECK(x1.nq(home,x0.glbMin()));
00179       return home.ES_SUBSUMED(*this);
00180     }
00181     // if x1 is determined and = x0.glb.min, then we need at least
00182     // one more element; if there is only one below, then we must
00183     // take it.
00184     if (x1.assigned() && x0.glbSize() > 0 && x1.val()==x0.glbMin()) {
00185       unsigned int oldGlbSize = x0.glbSize();
00186       // if there is only 1 unknown below x1, then we must take it
00187       UnknownRanges<View> ur(x0);
00188       assert(ur());
00189       // the iterator is not empty: otherwise x0 would be determined
00190       // and min(x0) would have been decided and the preceding if
00191       // would have caught it.  Also, the first range is not above
00192       // x1 otherwise the very first if would have caught it.
00193       // so let's check if the very first range of unknowns is of
00194       // size 1 and there is no second one or it starts above x1.
00195       if (ur.width()==1) {
00196         int i=ur.min();
00197         ++ur;
00198         if (!ur() || ur.min()>x1.val()) {
00199           GECODE_ME_CHECK(x0.include(home,i));
00200           return home.ES_SUBSUMED(*this);
00201         }
00202       }
00203       GECODE_ME_CHECK(x0.cardMin(home, oldGlbSize+1));
00204     }
00205     // if dom(x1) and lub(x0) are disjoint, then entailed;
00206     {
00207       LubRanges<View> ub(x0);
00208       Gecode::Int::ViewRanges<Gecode::Int::IntView> d(x1);
00209       Gecode::Iter::Ranges::Inter<LubRanges<View>,
00210         Gecode::Int::ViewRanges<Gecode::Int::IntView> > ir(ub,d);
00211       if (!ir()) return home.ES_SUBSUMED(*this);
00212     }
00213     // x0 is fated to eventually contain at least x0.cardMin elements.
00214     // therefore min(x0) <= x0.cardMin-th largest element of x0.lub
00215     // if x1 > than that, then entailed.
00216     {
00217       // to find the x0.cardMin-th largest element of x0.lub, we need
00218       // some sort of reverse range iterator. we will need to fake one
00219       // by storing the ranges of the forward iterator in an array.
00220       // first we need to know how large the array needs to be. so, let's
00221       // count the ranges:
00222       int num_ranges = 0;
00223       for (LubRanges<View> ur(x0); ur(); ++ur, ++num_ranges) {}
00224       // create an array for storing min and max of each range
00225       Region r;
00226       int* _ur = r.alloc<int>(num_ranges*2);
00227       // now, we fill the array:
00228       int i = 0;
00229       for (LubRanges<View> ur(x0); ur(); ++ur, ++i) {
00230         _ur[2*i  ] = ur.min();
00231         _ur[2*i+1] = ur.max();
00232       }
00233       // now we search from the top the range that contains the
00234       // nth largest value.
00235       unsigned int n = x0.cardMin();
00236       int nth_largest = BndSet::MAX_OF_EMPTY;
00237       for (int i=num_ranges; i--; ) {
00238         // number of values in range
00239         unsigned int num_values = static_cast<unsigned int>(_ur[2*i+1]-_ur[2*i]+1);
00240         // does the range contain the value?
00241         if (num_values >= n) {
00242           // record it and exit the loop
00243           nth_largest = static_cast<int>(_ur[2*i+1]-n+1);
00244           break;
00245         }
00246         // otherwise, we skipped num_values
00247         n -= num_values;
00248       }
00249       // if x1.min > nth_largest, then entailed
00250       if (x1.min() > nth_largest)
00251         return home.ES_SUBSUMED(*this);
00252     }
00253     return ES_FIX;
00254   }
00255 
00256   template<class View, ReifyMode rm>
00257   forceinline
00258   ReMinElement<View,rm>::ReMinElement(Home home, View y0,
00259                                       Gecode::Int::IntView y1,
00260                                       Gecode::Int::BoolView b2)
00261     : Gecode::Int::ReMixBinaryPropagator<View,PC_SET_ANY,
00262       Gecode::Int::IntView,Gecode::Int::PC_INT_DOM,
00263       Gecode::Int::BoolView> (home, y0, y1, b2) {}
00264 
00265   template<class View, ReifyMode rm>
00266   forceinline ExecStatus
00267   ReMinElement<View,rm>::post(Home home, View x0, Gecode::Int::IntView x1,
00268                               Gecode::Int::BoolView b2) {
00269     (void) new (home) ReMinElement(home,x0,x1,b2);
00270     return ES_OK;
00271   }
00272 
00273   template<class View, ReifyMode rm>
00274   forceinline
00275   ReMinElement<View,rm>::ReMinElement(Space& home, ReMinElement& p)
00276     : Gecode::Int::ReMixBinaryPropagator<View,PC_SET_ANY,
00277       Gecode::Int::IntView,Gecode::Int::PC_INT_DOM,
00278       Gecode::Int::BoolView> (home, p) {}
00279 
00280   template<class View, ReifyMode rm>
00281   Actor*
00282   ReMinElement<View,rm>::copy(Space& home) {
00283    return new (home) ReMinElement(home,*this);
00284   }
00285 
00286   template<class View, ReifyMode rm>
00287   ExecStatus
00288   ReMinElement<View,rm>::propagate(Space& home, const ModEventDelta&) {
00289     // check if b is determined
00290     if (b.one()) {
00291       if (rm == RM_PMI)
00292         return home.ES_SUBSUMED(*this);
00293       GECODE_REWRITE(*this, (MinElement<View>::post(home(*this),x0,x1)));
00294     }
00295     if (b.zero()) {
00296       if (rm == RM_IMP)
00297         return home.ES_SUBSUMED(*this);
00298       GECODE_REWRITE(*this, (NotMinElement<View>::post(home(*this),x0,x1)));
00299     }
00300     // cheap tests for => b=0
00301     // if x0 is empty, then b=0 and entailed
00302     // if max(x1) < min(x0.lub) or min(x1) > max(x0.lub), then b=0 and entailed
00303     // if min(x0.glb) < min(x1), then b=0 and entailed
00304     if ((x0.cardMax() == 0) ||
00305         ((x1.max() < x0.lubMin()) || (x1.min() > x0.lubMax())) ||
00306         ((x0.glbSize() > 0) && (x0.glbMin() < x1.min())))
00307       {
00308         if (rm != RM_PMI)
00309           GECODE_ME_CHECK(b.zero(home));
00310         return home.ES_SUBSUMED(*this);
00311       }
00312     // if min(x0) is decided
00313     if (x0.glbMin() == x0.lubMin()) {
00314       // if x1 is det: check if = min(x0), assign b, entailed
00315       if (x1.assigned()) {
00316         if (x1.val() == x0.glbMin()) {
00317           if (rm != RM_IMP)
00318             GECODE_ME_CHECK(b.one(home));
00319         } else {
00320           if (rm != RM_PMI)
00321             GECODE_ME_CHECK(b.zero(home));
00322         }
00323         return home.ES_SUBSUMED(*this);
00324       }
00325       // if min(x0) not in dom(x1): b=0, entailed
00326       else if ((x0.glbMin() < x1.min()) ||
00327                (x0.glbMin() > x1.max()) ||
00328                !x1.in(x0.glbMin()))
00329         {
00330           if (rm != RM_PMI)
00331             GECODE_ME_CHECK(b.zero(home));
00332           return home.ES_SUBSUMED(*this);
00333         }
00334     }
00335     // // if dom(x1) and lub(x0) are disjoint, then b=0, entailed;
00336     // {
00337     //   LubRanges<View> ub(x0);
00338     //   Gecode::Int::ViewRanges<Gecode::Int::IntView> d(x1);
00339     //   Gecode::Iter::Ranges::Inter<LubRanges<View>,
00340     //     Gecode::Int::ViewRanges<Gecode::Int::IntView> > ir(ub,d);
00341     //   if (!ir()) {
00342     //     GECODE_ME_CHECK(b.zero(home));
00343     //     return home.ES_SUBSUMED(*this);
00344     //   }
00345     // }
00346     // // x0 is fated to eventually contain at least x0.cardMin elements.
00347     // // therefore min(x0) <= x0.cardMin-th largest element of x0.lub
00348     // // if x1 > than that, then b=0 and entailed.
00349     // {
00350     //   // to find the x0.cardMin-th largest element of x0.lub, we need
00351     //   // some sort of reverse range iterator. we will need to fake one
00352     //   // by storing the ranges of the forward iterator in an array.
00353     //   // first we need to know how large the array needs to be. so, let's
00354     //   // count the ranges:
00355     //   int num_ranges = 0;
00356     //   for (LubRanges<View> ur(x0); ur(); ++ur, ++num_ranges) {}
00357     //   // create an array for storing min and max of each range
00358     //   Region re(home);
00359     //   int* _ur = re.alloc<int>(num_ranges*2);
00360     //   // now, we fill the array:
00361     //   int i = 0;
00362     //   for (LubRanges<View> ur(x0); ur(); ++ur, ++i) {
00363     //     _ur[2*i  ] = ur.min();
00364     //     _ur[2*i+1] = ur.max();
00365     //   }
00366     //   // now we search from the top the range that contains the
00367     //   // nth largest value.
00368     //   int n = x0.cardMin();
00369     //   int nth_largest = BndSet::MAX_OF_EMPTY;
00370     //   for (int i=num_ranges; i--; ) {
00371     //     // number of values in range
00372     //     int num_values = _ur[2*i+1]-_ur[2*i]+1;
00373     //     // does the range contain the value?
00374     //     if (num_values >= n)
00375     //       {
00376     //         // record it and exit the loop
00377     //         nth_largest = _ur[2*i+1]-n+1;
00378     //         break;
00379     //       }
00380     //     // otherwise, we skipped num_values
00381     //     n -= num_values;
00382     //   }
00383     //   // if x1.min > nth_largest, then entailed
00384     //   if (x1.min() > nth_largest) {
00385     //     GECODE_ME_CHECK(b.zero(home));
00386     //     return home.ES_SUBSUMED(*this);
00387     //   }
00388     // }
00389     return ES_FIX;
00390   }
00391 
00392   template<class View>
00393   forceinline
00394   MaxElement<View>::MaxElement(Home home, View y0, Gecode::Int::IntView y1)
00395     : MixBinaryPropagator<View,PC_SET_ANY,
00396       Gecode::Int::IntView,Gecode::Int::PC_INT_BND> (home, y0, y1) {}
00397 
00398   template<class View>
00399   forceinline
00400   MaxElement<View>::MaxElement(Space& home, MaxElement& p)
00401     : MixBinaryPropagator<View,PC_SET_ANY,
00402       Gecode::Int::IntView,Gecode::Int::PC_INT_BND> (home, p) {}
00403 
00404   template<class View>
00405   ExecStatus
00406   MaxElement<View>::post(Home home, View x0,
00407                               Gecode::Int::IntView x1) {
00408     GECODE_ME_CHECK(x0.cardMin(home,1));
00409     (void) new (home) MaxElement(home,x0,x1);
00410     return ES_OK;
00411   }
00412 
00413   template<class View>
00414   Actor*
00415   MaxElement<View>::copy(Space& home) {
00416     return new (home) MaxElement(home,*this);
00417   }
00418 
00419   template<class View>
00420   ExecStatus
00421   MaxElement<View>::propagate(Space& home, const ModEventDelta&) {
00422     LubRanges<View> ub(x0);
00423     GECODE_ME_CHECK(x1.inter_r(home,ub,false));
00424     GECODE_ME_CHECK(x1.gq(home,x0.glbMax()));
00425     assert(x0.cardMin()>=1);
00426     GECODE_ME_CHECK(x1.gq(home,x0.lubMinN(x0.cardMin()-1)));
00427     GECODE_ME_CHECK(x0.exclude(home,
00428                                x1.max()+1,Limits::max) );
00429 
00430     if (x1.assigned()) {
00431       GECODE_ME_CHECK(x0.include(home,x1.val()));
00432       GECODE_ME_CHECK( x0.exclude(home,
00433                                   x1.val()+1,Limits::max) );
00434       return home.ES_SUBSUMED(*this);
00435     }
00436 
00437     return ES_FIX;
00438   }
00439 
00440   template<class View>
00441   forceinline
00442   NotMaxElement<View>::NotMaxElement(Home home, View y0,
00443                                      Gecode::Int::IntView y1)
00444     : MixBinaryPropagator<View,PC_SET_ANY,
00445       Gecode::Int::IntView,Gecode::Int::PC_INT_DOM> (home, y0, y1) {}
00446 
00447   template<class View>
00448   forceinline
00449   NotMaxElement<View>::NotMaxElement(Space& home, NotMaxElement& p)
00450     : MixBinaryPropagator<View,PC_SET_ANY,
00451       Gecode::Int::IntView,Gecode::Int::PC_INT_DOM> (home, p) {}
00452 
00453   template<class View>
00454   ExecStatus
00455   NotMaxElement<View>::post(Home home, View x0, Gecode::Int::IntView x1) {
00456     (void) new (home) NotMaxElement(home,x0,x1);
00457     return ES_OK;
00458   }
00459 
00460   template<class View>
00461   Actor*
00462   NotMaxElement<View>::copy(Space& home) {
00463     return new (home) NotMaxElement(home,*this);
00464   }
00465 
00466   template<class View>
00467   ExecStatus
00468   NotMaxElement<View>::propagate(Space& home, const ModEventDelta&) {
00469     // cheap tests for entailment:
00470     // if x0 is empty, then entailed
00471     // if max(x1) < min(x0.lub) or min(x1) > max(x0.lub), then entailed
00472     // if max(x0.glb) > max(x1), then entailed
00473     if ((x0.cardMax() == 0) ||
00474         ((x1.max() < x0.lubMin()) || (x1.min() > x0.lubMax())) ||
00475         ((x0.glbSize() > 0) && (x0.glbMax() > x1.max())))
00476       return home.ES_SUBSUMED(*this);
00477     // if x1 is determined and = max(x0.lub): remove it from x0,
00478     // then entailed
00479     if (x1.assigned() && x1.val()==x0.lubMax()) {
00480       GECODE_ME_CHECK(x0.exclude(home,x1.val()));
00481       return home.ES_SUBSUMED(*this);
00482     }
00483     // if max(x0) is decided: remove max(x0) from the domain of x1
00484     // then entailed
00485     if (x0.glbMax() == x0.lubMax()) {
00486       GECODE_ME_CHECK(x1.nq(home,x0.glbMax()));
00487       return home.ES_SUBSUMED(*this);
00488     }
00489     // if x1 is determined and = max(x0.glb), then we need at least
00490     // one more element; if there is only one above, then we must
00491     // take it.
00492     if (x1.assigned() && x0.glbSize() > 0 && x1.val()==x0.glbMax()) {
00493       unsigned int oldGlbSize = x0.glbSize();
00494       // if there is only 1 unknown above x1, then we must take it
00495       UnknownRanges<View> ur(x0);
00496       // there is at least one unknown above x1 otherwise it would
00497       // have been caught by the if for x1=max(x0.lub)
00498       while (ur.max() < x1.val()) {
00499         assert(ur());
00500         ++ur;
00501       };
00502       // if the first range above x1 contains just 1 element,
00503       // and is the last range, then take that element
00504       if (ur.width() == 1) {
00505         int i = ur.min();
00506         ++ur;
00507         if (!ur()) {
00508           // last range
00509           GECODE_ME_CHECK(x0.include(home,i));
00510           return home.ES_SUBSUMED(*this);
00511         }
00512       }
00513       GECODE_ME_CHECK(x0.cardMin(home, oldGlbSize+1));
00514     }
00515     // if dom(x1) and lub(x0) are disjoint, then entailed
00516     {
00517       LubRanges<View> ub(x0);
00518       Gecode::Int::ViewRanges<Gecode::Int::IntView> d(x1);
00519       Gecode::Iter::Ranges::Inter<LubRanges<View>,
00520         Gecode::Int::ViewRanges<Gecode::Int::IntView> > ir(ub,d);
00521       if (!ir()) return home.ES_SUBSUMED(*this);
00522     }
00523     // x0 is fated to eventually contain at least x0.cardMin elements.
00524     // therefore max(x0) >= x0.cardMin-th smallest element of x0.lub.
00525     // if x1 < than that, then entailed.
00526     {
00527       unsigned int n = x0.cardMin();
00528       int nth_smallest = BndSet::MIN_OF_EMPTY;
00529       for (LubRanges<View> ur(x0); ur(); ++ur) {
00530         if (ur.width() >= n) {
00531           // record it and exit the loop
00532           nth_smallest = static_cast<int>(ur.min() + n - 1);
00533           break;
00534         }
00535         // otherwise, we skipped ur.width() values
00536         n -= ur.width();
00537       }
00538       // if x1.max < nth_smallest, then entailed
00539       if (x1.max() < nth_smallest)
00540         return home.ES_SUBSUMED(*this);
00541     }
00542     return ES_FIX;
00543   }
00544 
00545   template<class View, ReifyMode rm>
00546   forceinline
00547   ReMaxElement<View,rm>::ReMaxElement(Home home, View y0,
00548                                       Gecode::Int::IntView y1,
00549                                       Gecode::Int::BoolView b2)
00550     : Gecode::Int::ReMixBinaryPropagator<View,PC_SET_ANY,
00551       Gecode::Int::IntView,Gecode::Int::PC_INT_DOM,
00552       Gecode::Int::BoolView> (home, y0, y1, b2) {}
00553 
00554   template<class View, ReifyMode rm>
00555   forceinline
00556   ReMaxElement<View,rm>::ReMaxElement(Space& home, ReMaxElement& p)
00557     : Gecode::Int::ReMixBinaryPropagator<View,PC_SET_ANY,
00558       Gecode::Int::IntView,Gecode::Int::PC_INT_DOM,
00559       Gecode::Int::BoolView> (home, p) {}
00560 
00561   template<class View, ReifyMode rm>
00562   ExecStatus
00563   ReMaxElement<View,rm>::post(Home home, View x0,
00564                               Gecode::Int::IntView x1,
00565                               Gecode::Int::BoolView b2) {
00566     (void) new (home) ReMaxElement(home,x0,x1,b2);
00567     return ES_OK;
00568   }
00569 
00570   template<class View, ReifyMode rm>
00571   Actor*
00572   ReMaxElement<View,rm>::copy(Space& home) {
00573     return new (home) ReMaxElement(home,*this);
00574   }
00575 
00576   template<class View, ReifyMode rm>
00577   ExecStatus
00578   ReMaxElement<View,rm>::propagate(Space& home, const ModEventDelta&) {
00579     // check if b is determined
00580     if (b.one()) {
00581       if (rm == RM_PMI)
00582         return home.ES_SUBSUMED(*this);
00583       GECODE_REWRITE(*this, (MaxElement<View>::post(home(*this),x0,x1)));
00584     }
00585     if (b.zero()) {
00586       if (rm == RM_IMP)
00587         return home.ES_SUBSUMED(*this);
00588       GECODE_REWRITE(*this, (NotMaxElement<View>::post(home(*this),x0,x1)));
00589     }
00590     // cheap tests for => b=0
00591     // if x0 is empty, then b=0 and entailed
00592     // if max(x1) < min(x0.lub) or min(x1) > max(x0.lub), then b=0 and entailed
00593     // if max(x0.glb) > max(x1), then b=0 and entailed
00594     if ((x0.cardMax() == 0) ||
00595         ((x1.max() < x0.lubMin()) || (x1.min() > x0.lubMax())) ||
00596         ((x0.glbSize() > 0) && (x0.glbMax() > x1.max())))
00597       {
00598         if (rm != RM_PMI)
00599           GECODE_ME_CHECK(b.zero(home));
00600         return home.ES_SUBSUMED(*this);
00601       }
00602     // if max(x0) is decided
00603     if (x0.glbMax() == x0.lubMax()) {
00604       // if x1 is det: check if = max(x0), assign b, entailed
00605       if (x1.assigned()) {
00606         if (x1.val() == x0.glbMax()) {
00607           if (rm != RM_IMP)
00608             GECODE_ME_CHECK(b.one(home));
00609         } else {
00610           if (rm != RM_PMI)
00611             GECODE_ME_CHECK(b.zero(home));
00612         }
00613         return home.ES_SUBSUMED(*this);
00614       }
00615       // if max(x0) not in dom(x1): b=0, entailed
00616       else if ((x0.glbMax() < x1.min()) ||
00617                (x0.glbMax() > x1.max()) ||
00618                !x1.in(x0.glbMax()))
00619         {
00620           if (rm != RM_PMI)
00621             GECODE_ME_CHECK(b.zero(home));
00622           return home.ES_SUBSUMED(*this);
00623         }
00624     }
00625     // if dom(x1) and lub(x0) are disjoint, then b=0, entailed
00626     {
00627       LubRanges<View> ub(x0);
00628       Gecode::Int::ViewRanges<Gecode::Int::IntView> d(x1);
00629       Gecode::Iter::Ranges::Inter<LubRanges<View>,
00630         Gecode::Int::ViewRanges<Gecode::Int::IntView> > ir(ub,d);
00631       if (!ir()) {
00632         if (rm != RM_PMI)
00633           GECODE_ME_CHECK(b.zero(home));
00634         return home.ES_SUBSUMED(*this);
00635       }
00636     }
00637     // x0 is fated to eventually contain at least x0.cardMin elements.
00638     // therefore max(x0) >= x0.cardMin-th smallest element of x0.lub.
00639     // if x1 < than that, then b=0, entailed.
00640     {
00641       unsigned int n = x0.cardMin();
00642       int nth_smallest = BndSet::MIN_OF_EMPTY;
00643       for (LubRanges<View> ur(x0); ur(); ++ur) {
00644         if (ur.width() >= n)
00645           {
00646             // record it and exit the loop
00647             nth_smallest = static_cast<int>(ur.min() + n - 1);
00648             break;
00649           }
00650         // otherwise, we skipped ur.width() values
00651         n -= ur.width();
00652       }
00653       // if x1.max < nth_smallest, then entailed
00654       if (x1.max() < nth_smallest) {
00655         if (rm != RM_PMI)
00656           GECODE_ME_CHECK(b.zero(home));
00657         return home.ES_SUBSUMED(*this);
00658       }
00659     }
00660     return ES_FIX;
00661   }
00662 
00663 }}}
00664 
00665 // STATISTICS: set-prop