Generated on Wed Nov 1 15:04:33 2006 for Gecode by doxygen 1.4.5

bnd.icc

Go to the documentation of this file.
00001 /*
00002  *  Main authors:
00003  *     Patrick Pekczynski <pekczynski@ps.uni-sb.de>
00004  *
00005  *  Copyright:
00006  *     Patrick Pekczynski, 2004/2005
00007  *
00008  *  Last modified:
00009  *     $Date: 2006-08-04 16:03:26 +0200 (Fri, 04 Aug 2006) $ by $Author: schulte $
00010  *     $Revision: 3512 $
00011  *
00012  *  This file is part of Gecode, the generic constraint
00013  *  development environment:
00014  *     http://www.gecode.org
00015  *
00016  *  See the file "LICENSE" for information on usage and
00017  *  redistribution of this file, and for a
00018  *     DISCLAIMER OF ALL WARRANTIES.
00019  *
00020  */
00021 
00022 namespace Gecode { namespace Int { namespace GCC {
00023 
00025   template <class View, class Card, bool isView, bool shared>
00026   inline ExecStatus
00027   prop_bnd(Space* home, ViewArray<View>& x, ViewArray<Card>& k,
00028            PartialSum<Card>*& lps, PartialSum<Card>*& ups,
00029            bool card_fixed, bool card_all, bool nolbc){         
00030 
00031     bool all_assigned = true;
00032     bool mod          = false;
00033     int  smin         = 0;
00034     int  smax         = 0;
00035 
00036     if (isView) {
00037       // if a cardinality of first or last value is
00038       // out of the variable bounds (cardvar == 0)
00039       // reduce cardinality variables
00040 
00041       int m = k.size();
00042       bool locut = k[0].max() == 0;
00043       bool hicut = k[m - 1].max() == 0;
00044 
00045       if (locut) {
00046         int low = k[0].card();
00047         for (int i = 0; i < x.size(); i++) {
00048           ModEvent me = x[i].gr(home, low);
00049           GECODE_ME_CHECK(me);
00050           mod |= me_modified(me) && (x[i].min() != low + 1);
00051           mod |= shared && me_modified(me);
00052         }
00053       }
00054       if (hicut) {
00055         int hi = k[m - 1].card();
00056         for (int i = 0; i < x.size(); i++) {
00057           ModEvent me = x[i].le(home, hi);
00058           GECODE_ME_CHECK(me);
00059           mod |= me_modified(me) && (x[i].max() != hi - 1);
00060           mod |= shared && me_modified(me);
00061         }
00062       }
00063 
00064       if (locut || hicut) {
00065         int cmin = k[0].card();
00066         int cmax = k[m - 1].card();
00067         if (k[0].max() == 0) {
00068           cmin = k[1].card();
00069         }
00070         if (k[m - 1].max() == 0) {
00071           cmax = k[m - 2].card();
00072         }
00073         reduce_card<Card>(cmin, cmax, k);
00074 
00075         if (lps != NULL) {
00076           delete lps; lps = NULL;
00077           assert(ups != NULL);
00078           delete ups; ups = NULL;
00079         }
00080       }
00081     }
00082 
00083     GECODE_AUTOARRAY(int, count, k.size());
00084     for (int i = k.size(); i--; ) {
00085       count[i] = 0;
00086     }
00087 
00088     int noa = 0;
00089     int single = 0;
00090     int xlb = 0;
00091     int xub = 0;
00092 
00093     for (int i = x.size(); i--; ) {
00094       bool b = x[i].assigned();
00095       xlb += x[i].min();
00096       xub += x[i].max();
00097       all_assigned &= b;
00098       if (b) {
00099         noa++;
00100         int idx = lookupValue(k,x[i].val());
00101         // reduction is essential for order on value nodes in dom
00102         // hence introduce test for failed lookup
00103         if (idx == -1) {
00104           return ES_FAILED;
00105         }
00106         count[idx]++;
00107       } else {
00108         single = i;
00109       }
00110     }
00111 
00112     if (isView) {
00113       // before propagation performs inferences on cardinality variables:
00114       if (noa > 0) {
00115         int n  = x.size();
00116         int ks = k.size();
00117 
00118         for (int i = ks; i--; ) {
00119           if (!k[i].assigned()) {
00120             int ub = n - (noa - count[i]);
00121             int lb = count[i];
00122             ModEvent melq = k[i].lq(home, ub);
00123             GECODE_ME_CHECK(melq);
00124             mod |= me_modified(melq) && (k[i].max() != ub);
00125             mod |= shared && me_modified(melq);
00126 
00127             ModEvent megq = k[i].gq(home, lb);
00128             GECODE_ME_CHECK(megq);
00129             mod |= me_modified(megq) && (k[i].min() != lb);
00130             mod |= shared && me_modified(megq);
00131           }
00132         }
00133       }
00134 
00135       if (!card_consistent<View, Card>(smin, smax, x, k, card_all)) {
00136         return ES_FAILED;
00137       }
00138 
00139       // can only modified cardinality variables
00140       GECODE_ES_CHECK((prop_card<View, Card, shared>(home, x, k, mod)));
00141 
00142       // mimicking linear constraint
00143       int smax = 0;
00144       int smin = 0;
00145       int total_min = 0;
00146       int total_max = 0;
00147       for (int i = k.size(); i--; ) {
00148         smax += k[i].max();
00149         total_min += k[i].card() * k[i].min();
00150         total_max += k[i].card() * k[i].max();
00151       }
00152       int xsmax = x.size() - smax;
00153       int xsmin = x.size() - smin;
00154       smax = 0;
00155       smin = 0;
00156       bool card_ass = true;
00157       for (int i = k.size(); i--; ) {
00158         int lb = xsmax + k[i].max();
00159         int ub = xsmin + k[i].min();
00160         ModEvent me = k[i].gq(home, lb);
00161         GECODE_ME_CHECK(me);
00162         mod |= me_modified(me) && (k[i].min() != lb);
00163         mod |= shared && me_modified(me);
00164         smax += k[i].max();
00165 
00166         me = k[i].lq(home, ub);
00167         GECODE_ME_CHECK(me);
00168         mod |= me_modified(me) && (k[i].max() != ub);
00169         mod |= shared && me_modified(me);
00170         card_ass &= k[i].assigned();
00171       }
00172       if (card_ass) {
00173         if (smax < x.size() || smax > x.size()) {
00174           return ES_FAILED;
00175         }
00176 
00177         // redundant linear constraint
00178         for (int i = x.size(); i--; ) {
00179           if (!x[i].assigned()) {
00180             int xmin = xub - x[i].max();
00181             int xgq  = total_max - xmin;
00182 
00183             int xmax = xlb - x[i].min();
00184             int xlq  = total_max - xmax;
00185 
00186             ModEvent me = x[i].gq(home, xgq);
00187             GECODE_ME_CHECK(me);
00188             mod |= me_modified(me) && (x[i].min() != xgq);
00189             mod |= shared && me_modified(me);
00190 
00191             me = x[i].lq(home, xlq);
00192             GECODE_ME_CHECK(me);
00193             mod |= me_modified(me) && (x[i].max() != xlq);
00194             mod |= shared && me_modified(me);
00195           }
00196         }
00197       }
00198     }
00199 
00200     for (int i = k.size(); i--; ) {
00201       count[i] = 0;
00202     }
00203 
00204     all_assigned = true;
00205     noa = 0;
00206     single = 0;
00207 
00208     for (int i = x.size(); i--; ) {
00209       bool b = x[i].assigned();
00210       xlb += x[i].min();
00211       xub += x[i].max();
00212       all_assigned &= b;
00213       if (b) {
00214         noa++;
00215         int idx = lookupValue(k,x[i].val());
00216         // reduction is essential for order on value nodes in dom
00217         // hence introduce test for failed lookup
00218         if (idx == -1) {
00219           return ES_FAILED;
00220         }
00221         count[idx]++;
00222       } else {
00223         single = i;
00224       }
00225     }
00226 
00227     if (all_assigned) {
00228       for (int i = k.size(); i--; ) {
00229         int ci = count[i];
00230         if (! (k[i].min() <= ci && ci <= k[i].max())) {
00231           return ES_FAILED;
00232         } else {
00233           if (isView) {
00234             if (!k[i].assigned()) {
00235               ModEvent me = k[i].eq(home, ci);
00236               GECODE_ME_CHECK(me);
00237               mod |= k[i].assigned();
00238             }   
00239             all_assigned &= k[i].assigned();
00240           }
00241         }
00242       }
00243       if (all_assigned) {
00244         return ES_SUBSUMED;
00245       }
00246     }
00247 
00248     if (isView) {
00249       // check again for zero entries at first or last position
00250       int m = k.size();
00251       bool locut = k[0].max() == 0;
00252       bool hicut = k[m - 1].max() == 0;
00253 
00254       if (locut) {
00255         int low = k[0].card();
00256         for (int i = 0; i < x.size(); i++) {
00257           ModEvent me = x[i].gr(home, low);
00258           GECODE_ME_CHECK(me);
00259           mod |= me_modified(me) && (x[i].min() != low + 1);
00260           mod |= shared && me_modified(me);
00261         }
00262       }
00263       if (hicut) {
00264         int hi = k[m - 1].card();
00265         for (int i = 0; i < x.size(); i++) {
00266           ModEvent me = x[i].le(home, hi);
00267           GECODE_ME_CHECK(me);
00268           mod |= me_modified(me) && (x[i].max() != hi - 1);
00269           mod |= shared && me_modified(me);
00270         }
00271       }
00272 
00273       if (locut || hicut) {
00274         int cmin = k[0].card();
00275         int cmax = k[m - 1].card();
00276         if (k[0].max() == 0) {
00277           cmin = k[1].card();
00278         }
00279         if (k[m - 1].max() == 0) {
00280           cmax = k[m - 2].card();
00281         }
00282         reduce_card<Card>(cmin, cmax, k);
00283 
00284         if (lps != NULL) {
00285           delete lps;
00286           lps = NULL;
00287           assert(ups != NULL);
00288           delete ups;
00289           ups = NULL;
00290         }
00291       }
00292     }
00293 
00294     ExecStatus es_ubc = ES_FIX;
00295     ExecStatus es_lbc = ES_FIX;
00296     int n = x.size();
00297 
00298     GECODE_AUTOARRAY(int, mu, n);
00299     GECODE_AUTOARRAY(int, nu, n);
00300 
00301     for (int i = n; i--; ) {
00302       nu[i] = i;
00303       mu[i] = i;
00304     }
00305     // Create sorting permutation mu according to the variables upper bounds
00306     MaxInc<View> max_inc(x);
00307     Support::quicksort<int, MaxInc<View> >(mu, n, max_inc);
00308 
00309     // Create sorting permutation nu according to the variables lower bounds
00310     MinInc<View> min_inc(x);
00311     Support::quicksort<int, MinInc<View> >(nu, n, min_inc);
00312 
00313     if (isView) {
00314       // assert guaranteed bounds in the set of all values for variable case
00315       assert(k[0].card() == x[nu[0]].min());
00316     }
00317 
00318     // ensure that only values are considered lying in the variable domain
00319     int cur_minx = x[nu[0]].min();
00320     if (lps == NULL) {
00321       assert (ups == NULL);
00322       lps = new PartialSum<Card>(cur_minx,  k.size(), k, false);
00323       ups = new PartialSum<Card>(cur_minx,  k.size(), k, true);
00324     }
00325 
00326     if (isView) {
00327       // if there has been a change to the cardinality variables
00328       // reconstruction of the partial sum structure is necessary
00329       if (lps->check_update_min(k)) {
00330         delete lps;
00331         lps = new PartialSum<Card>(cur_minx,  k.size(), k, false);
00332       }
00333 
00334       if (ups->check_update_max(k)) {
00335         delete ups;
00336         ups = new PartialSum<Card>(cur_minx,  k.size(), k, true);
00337       }
00338     }
00339 
00340     // already holds by construction
00341     assert(lps->minValue() == ups->minValue());
00342     assert(lps->maxValue() == ups->maxValue());
00343 
00344     bool minima_equal = lps->minValue() == ups->minValue();
00345     bool maxima_equal = lps->maxValue() == ups->maxValue();
00346 
00347     if (!minima_equal || !maxima_equal ) {
00348       delete lps;
00349       lps = new PartialSum<Card>(cur_minx, k.size(), k, false);
00350       delete ups;
00351       ups = new PartialSum<Card>(cur_minx, k.size(), k, true);
00352     }
00353 
00354     // assert that the minimal value of the partial sum structure for
00355     // LBC is consistent with the smallest value a variable can take
00356     assert(lps->minValue() <= x[nu[0]].min());
00357     // assert that the maximal value of the partial sum structure for
00358     // UBC is consistent with the largest value a variable can take
00359     assert(x[mu[x.size() - 1]].max() <= ups->maxValue());
00360 
00361     /*
00362      *  Setup rank and bounds info
00363      *  Since this implementation is based on the theory of Hall Intervals
00364      *  additional datastructures are needed in order to represent these
00365      *  intervals and the "partial-sum" data structure (cf."gcc/gccbndsup.icc")
00366      *
00367      */
00368 
00369     GECODE_AUTOARRAY(HallInfo, hall, (2 * n + 2));
00370     GECODE_AUTOARRAY(Rank,     rank, n);
00371 
00372     int nb = 0;
00373     // setup bounds and rank
00374     int min        = x[nu[0]].min();
00375     int max        = x[mu[0]].max() + 1;
00376     int last       = lps->firstValue + 1; //equivalent to last = min -2
00377     hall[0].bounds = last;
00378 
00379     /*
00380      * First the algorithm merges the arrays minsorted and maxsorted
00381      * into bounds i.e. hall[].bounds contains the ordered union
00382      * of the lower and upper domain bounds including two sentinels
00383      * at the beginning and at the end of the set
00384      * ( the upper variable bounds in this union are increased by 1 )
00385      */
00386 
00387     {
00388       int i = 0;
00389       int j = 0;
00390       while (true) {
00391         if (i < n && min < max) {
00392           if (min != last) {
00393             last = min;
00394             hall[++nb].bounds = last;
00395           }
00396           rank[nu[i]].min = nb;
00397           if (++i < n) {
00398             min = x[nu[i]].min();
00399           }
00400         } else {
00401           if (max != last) {
00402             last = max;
00403             hall[++nb].bounds = last;
00404           }
00405           rank[mu[j]].max = nb;
00406           if (++j == n) {
00407             break;
00408           }
00409           max = x[mu[j]].max() + 1;
00410         }
00411       }
00412     }
00413 
00414     int rightmost = nb + 1; // rightmost accesible value in bounds
00415     hall[rightmost].bounds = ups->lastValue + 1 ;
00416 
00417     nolbc = true;
00418     for (int i = k.size(); i--; ) {
00419       nolbc &= (k[i].min() == 0);
00420     }
00421 
00422     if (!card_fixed && !nolbc) {
00423       es_lbc = lbc<View, Card, shared>(home, x, nb, hall, rank,lps, mu, nu);
00424       if (es_lbc == ES_FAILED || es_lbc == ES_SUBSUMED) {
00425         return es_lbc;
00426       }
00427       mod |= (es_lbc == ES_NOFIX);
00428     }
00429 
00430     es_ubc = ubc<View, Card, shared>(home, x, nb, hall, rank, ups, mu, nu);
00431     if (es_ubc == ES_FAILED || es_ubc == ES_SUBSUMED) {
00432       return es_ubc;
00433     }
00434     mod |= (es_ubc == ES_NOFIX);
00435 
00436     if (isView) {
00437       GECODE_ES_CHECK((prop_card<View, Card, shared>(home, x, k, mod)));
00438     }
00439 
00440     all_assigned = true;
00441     noa = 0;
00442     single = 0;
00443     for (int i = k.size(); i--; ) {
00444       count[i] = 0;
00445     }
00446 
00447     for (int i = x.size(); i--; ) {
00448       bool b = x[i].assigned();
00449       all_assigned &= b;
00450       if (b) {
00451         noa++;
00452         int idx = lookupValue(k,x[i].val());
00453         count[idx]++;
00454       } else {
00455         single = i;
00456       }
00457     }
00458 
00459     if (all_assigned) {
00460       for (int i = k.size(); i--; ) {
00461         int ci = count[i];
00462         if (! (k[i].min() <= ci && ci <= k[i].max())) {
00463           return ES_FAILED;
00464         } else {
00465           if (isView) {
00466             if (!k[i].assigned()) {
00467               ModEvent me = k[i].eq(home, ci);
00468               GECODE_ME_CHECK(me);
00469               mod |= k[i].assigned();
00470             }
00471             all_assigned &= k[i].assigned();
00472           }
00473         }
00474       }
00475       if (all_assigned) {
00476         return ES_SUBSUMED;
00477       }
00478     }
00479 
00480     return mod ? ES_NOFIX : ES_FIX;
00481   }
00482 
00483   // for posting
00484   template <class View, class Card, bool isView, bool shared>
00485   inline
00486   BndImp<View, Card, isView, shared>::
00487   BndImp(Space* home, ViewArray<View>& x0, ViewArray<Card>& k0,
00488          bool cf,  bool all, bool nolbc) :
00489     Propagator(home, true), x(x0), k(k0), lps(NULL), ups(NULL),
00490     card_fixed(cf), card_all(all), skip_lbc(nolbc) {
00491     x.subscribe(home, this, PC_INT_BND);
00492     k.subscribe(home, this, PC_INT_BND);
00493   }
00494 
00495   // for cloning
00496   template <class View, class Card, bool isView, bool shared>
00497   forceinline
00498   BndImp<View, Card, isView, shared>::
00499   BndImp(Space* home, bool share, BndImp<View, Card, isView, shared>& p)
00500     : Propagator(home, share, p), lps(NULL), ups(NULL),
00501       card_fixed(p.card_fixed), card_all(p.card_all),
00502       skip_lbc(p.skip_lbc) {
00503     x.update(home, share, p.x);
00504     k.update(home, share, p.k);
00505   }
00506 
00507   template <class View, class Card, bool isView, bool shared>
00508   size_t
00509   BndImp<View, Card, isView, shared>::dispose(Space* home){
00510     if (!home->failed()) {
00511       x.cancel(home,this, PC_INT_BND);
00512       k.cancel(home,this, PC_INT_BND);
00513     }
00514     if (lps != NULL) {
00515       delete lps;
00516     }
00517     if (ups != NULL) {
00518       delete ups;
00519     }
00520     (void) Propagator::dispose(home);
00521     return sizeof(*this);
00522   }
00523 
00524   template <class View, class Card, bool isView, bool shared>
00525   Actor*
00526   BndImp<View, Card, isView, shared>::copy(Space* home, bool share){
00527     return new (home) BndImp<View, Card, isView, shared>
00528       (home, share, *this);
00529   }
00530 
00531   template <class View, class Card, bool isView, bool shared>
00532   PropCost
00533   BndImp<View, Card, isView, shared>::cost (void) const {
00534     /*
00535      * The bounds consistent version of the Global Cardinality constraint
00536      * has a theoretical complexity of
00537      *   O(t + n\cdot log(n)) with
00538      *   n = number of variables
00539      *   t = time needed to sort the domain bounds of the variables
00540      */
00541     PropCost pc = PC_LINEAR_HI;
00542     return cost_hi(x.size(),pc);
00543   }
00544 
00545   template <class View, class Card, bool isView, bool shared>
00546   ExecStatus
00547   BndImp<View, Card, isView, shared>::propagate(Space* home) {
00548     return prop_bnd<View, Card, isView, shared>
00549       (home, x, k, lps, ups, card_fixed, card_all, skip_lbc);
00550   }
00551 
00560   template <class View1, class View2>
00561   class SharingTest {
00562   public:
00567     static bool shared(Space* home, ViewArray<View1>& x0,
00568                        ViewArray<View2>& k0) {
00569       ViewArray<View1> xc(home, x0.size()+k0.size());
00570       for (int i = 0; i < x0.size(); i++) {
00571         xc[i] = x0[i];
00572       }
00573       for (int i = x0.size(); i < x0.size()+k0.size(); i++) {
00574         xc[i] = k0[i - x0.size()].intview();
00575       }
00576       return xc.shared();
00577     }
00578   };
00579 
00584   template <>
00585   class SharingTest<IntView,OccurBndsView> {
00586   public:
00588     static bool shared(Space* home,
00589                        ViewArray<IntView>& xs, ViewArray<OccurBndsView>&) {
00590       return xs.shared();
00591     }
00592   };
00593 
00594   template <class View, class Card, bool isView>
00595   ExecStatus
00596   Bnd<View, Card, isView>::post(Space* home,
00597                                 ViewArray<View>& x0,
00598                                 ViewArray<Card>& k0,
00599                                 bool all) {
00600     bool cardfix = true;
00601     bool nolbc = true;
00602     for (int i = k0.size(); i--; ) {
00603       cardfix &= k0[i].assigned();
00604       nolbc &= (k0[i].min() == 0);
00605     }
00606 
00607     if (SharingTest<View,Card>::shared(home,x0,k0)) {
00608       new (home) BndImp<View, Card, isView, true>
00609         (home, x0, k0, cardfix, all, nolbc);
00610     } else {
00611       new (home) BndImp<View, Card, isView, false>
00612         (home, x0, k0, cardfix, all, nolbc);
00613     }
00614     return ES_OK;
00615   }
00616 
00617   template <class View, class Card, bool isView, bool shared>
00618   void
00619   BndImp<View, Card, isView, shared>::flush(void){
00620     delete lps;
00621     lps = NULL;
00622     delete ups;
00623     ups = NULL;
00624   }
00625 
00626 }}}
00627 
00628 // STATISTICS: int-prop
00629