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

imp.cc

Go to the documentation of this file.
00001 /*
00002  *  Main authors:
00003  *     Christian Schulte <schulte@gecode.org>
00004  *
00005  *  Copyright:
00006  *     Christian Schulte, 2002
00007  *
00008  *  Last modified:
00009  *     $Date: 2006-08-25 10:43:21 +0200 (Fri, 25 Aug 2006) $ by $Author: schulte $
00010  *     $Revision: 3568 $
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 #include "gecode/int.hh"
00023 
00024 #include "gecode/limits.hh"
00025 
00026 #include "gecode/int/var/imp-body.icc"
00027 
00028 namespace Gecode { namespace Int {
00029 
00030   forceinline bool
00031   IntVarImp::closer_min(int n) const {
00032     unsigned int l = n - dom.min();
00033     unsigned int r = dom.max() - n;
00034     return l < r;
00035   }
00036 
00037   int
00038   IntVarImp::med(void) const {
00039     // Computes the median
00040     if (fst() == NULL)
00041       return (dom.min()+dom.max())/2;
00042     unsigned int i = size() / 2;
00043     const RangeList* p = NULL;
00044     const RangeList* c = fst();
00045     while (i >= c->width()) {
00046       i -= c->width();
00047       const RangeList* n=c->next(p); p=c; c=n;
00048     }
00049     return c->min() + static_cast<int>(i);
00050   }
00051 
00052   bool
00053   IntVarImp::in_full(int m) const {
00054     if (closer_min(m)) {
00055       const RangeList* p = NULL;
00056       const RangeList* c = fst();
00057       while (m > c->max()) {
00058         const RangeList* n=c->next(p); p=c; c=n;
00059       }
00060       return (m >= c->min());
00061     } else {
00062       const RangeList* n = NULL;
00063       const RangeList* c = lst();
00064       while (m < c->min()) {
00065         const RangeList* p=c->prev(n); n=c; c=p;
00066       }
00067       return (m <= c->max());
00068     }
00069   }
00070 
00071   /*
00072    * "Standard" tell operations
00073    *
00074    */
00075 
00076   void
00077   IntVarImp::lq_full(Space* home, int m) {
00078     assert((m >= dom.min()) && (m <= dom.max()));
00079     if (range()) { // Is already range...
00080       dom.max(m);
00081       if (assigned()) goto notify_val;
00082     } else if (m < fst()->next(NULL)->min()) { // Becomes range...
00083       dom.max(std::min(m,fst()->max()));
00084       fst()->dispose(home,NULL,lst());
00085       fst(NULL); holes = 0;
00086       if (assigned()) goto notify_val;
00087     } else { // Stays non-range...
00088       RangeList* n = NULL;
00089       RangeList* c = lst();
00090       unsigned int h = 0;
00091       while (m < c->min()) {
00092         RangeList* p = c->prev(n); c->fix(n);
00093         h += (c->min() - p->max() - 1);
00094         n=c; c=p;
00095       }
00096       holes -= h;
00097       int max_c = std::min(m,c->max());
00098       dom.max(max_c); c->max(max_c);
00099       if (c != lst()) {
00100         lst()->dispose(home,n);
00101         c->next(n,NULL); lst(c);
00102       }
00103     }
00104     notify(home,ME_INT_BND);
00105     return;
00106   notify_val:
00107     notify(home,ME_INT_VAL);
00108   }
00109 
00110   void
00111   IntVarImp::gq_full(Space* home, int m) {
00112     assert((m >= dom.min()) && (m <= dom.max()));
00113     if (range()) { // Is already range...
00114       dom.min(m);
00115       if (assigned()) goto notify_val;
00116     } else if (m > lst()->prev(NULL)->max()) { // Becomes range...
00117       dom.min(std::max(m,lst()->min()));
00118       fst()->dispose(home,NULL,lst());
00119       fst(NULL); holes = 0;
00120       if (assigned()) goto notify_val;
00121     } else { // Stays non-range...
00122       RangeList* p = NULL;
00123       RangeList* c = fst();
00124       unsigned int h = 0;
00125       while (m > c->max()) {
00126         RangeList* n = c->next(p); c->fix(n);
00127         h += (n->min() - c->max() - 1);
00128         p=c; c=n;
00129       }
00130       holes -= h;
00131       int min_c = std::max(m,c->min());
00132       dom.min(min_c); c->min(min_c);
00133       if (c != fst()) {
00134         fst()->dispose(home,p);
00135         c->prev(p,NULL); fst(c);
00136       }
00137     }
00138     notify(home,ME_INT_BND);
00139     return;
00140   notify_val:
00141     notify(home,ME_INT_VAL);
00142   }
00143 
00144   void
00145   IntVarImp::eq_full(Space* home, int m) {
00146     if (!range()) {
00147       RangeList* p = NULL;
00148       RangeList* c = fst();
00149       while (m > c->max()) {
00150         RangeList* n=c->next(p); c->fix(n); p=c; c=n;
00151       }
00152       if (m < c->min()) {
00153         dom.min(Limits::Int::int_max+1);
00154         return;
00155       }
00156       while (c != NULL) {
00157         RangeList* n=c->next(p); c->fix(n); p=c; c=n;
00158       }
00159       assert(p == lst());
00160       fst()->dispose(home,p);
00161       fst(NULL); holes = 0;
00162     }
00163     dom.min(m); dom.max(m);
00164     notify(home,ME_INT_VAL);
00165   }
00166 
00167   ModEvent
00168   IntVarImp::nq_full(Space* home, int m) {
00169     assert(!((m < dom.min()) || (m > dom.max())));
00170     if (range()) {
00171       if ((m == dom.min()) && (m == dom.max()))
00172         return ME_INT_FAILED;
00173       if (m == dom.min()) {
00174         dom.min(m+1); goto notify_bnd_or_val;
00175       }
00176       if (m == dom.max()) {
00177         dom.max(m-1); goto notify_bnd_or_val;
00178       }
00179       RangeList* f = new (home) RangeList(dom.min(),m-1);
00180       RangeList* l = new (home) RangeList(m+1,dom.max());
00181       f->prevnext(NULL,l);
00182       l->prevnext(f,NULL);
00183       fst(f); lst(l); holes = 1;
00184     } else if (m < fst()->next(NULL)->min()) { // Concerns the first range...
00185       int f_max = fst()->max();
00186       if (m > f_max)
00187         return ME_INT_NONE;
00188       int f_min = dom.min();
00189       if ((m == f_min) && (m == f_max)) {
00190         RangeList* f_next = fst()->next(NULL);
00191         dom.min(f_next->min());
00192         if (f_next == lst()) { // Turns into range
00193           // Works as at the ends there are only NULL pointers
00194           fst()->dispose(home,f_next);
00195           fst(NULL); holes = 0;
00196           goto notify_bnd_or_val;
00197         } else { // Remains non-range
00198           f_next->prev(fst(),NULL);
00199           fst()->dispose(home); fst(f_next);
00200           holes -= dom.min() - f_min - 1;
00201           goto notify_bnd;
00202         }
00203       } else if (m == f_min) {
00204         dom.min(m+1); fst()->min(m+1);
00205         goto notify_bnd;
00206       } else if (m == f_max) {
00207         fst()->max(m-1); holes += 1;
00208       } else {
00209         // Create new hole
00210         RangeList* f = new (home) RangeList(f_min,m-1);
00211         f->prevnext(NULL,fst());
00212         fst()->min(m+1); fst()->prev(NULL,f);
00213         fst(f); holes += 1;
00214       }
00215     } else if (m > lst()->prev(NULL)->max()) { // Concerns the last range...
00216       int l_min = lst()->min();
00217       if (m < l_min)
00218         return ME_INT_NONE;
00219       int l_max = dom.max();
00220       if ((m == l_min) && (m == l_max)) {
00221         RangeList* l_prev = lst()->prev(NULL);
00222         dom.max(l_prev->max());
00223         if (l_prev == fst()) {
00224           // Turns into range
00225           l_prev->dispose(home,lst());
00226           fst(NULL); holes = 0;
00227           goto notify_bnd_or_val;
00228         } else { // Remains non-range
00229           l_prev->next(lst(),NULL);
00230           lst()->dispose(home); lst(l_prev);
00231           holes -= l_max - dom.max() - 1;
00232           goto notify_bnd;
00233         }
00234       } else if (m == l_max) {
00235         dom.max(m-1); lst()->max(m-1);
00236         goto notify_bnd;
00237       } else if (m == l_min) {
00238         lst()->min(m+1); holes += 1;
00239       } else { // Create new hole
00240         RangeList* l = new (home) RangeList(m+1,l_max);
00241         l->prevnext(lst(),NULL);
00242         lst()->max(m-1); lst()->next(NULL,l);
00243         lst(l); holes += 1;
00244       }
00245     } else { // Concerns element in the middle of the list of ranges
00246       RangeList* p;
00247       RangeList* c;
00248       RangeList* n;
00249       if (closer_min(m)) {
00250         assert(m > fst()->max());
00251         p = NULL;
00252         c = fst();
00253         do {
00254           n=c->next(p); p=c; c=n;
00255         } while (m > c->max());
00256         if (m < c->min())
00257           return ME_INT_NONE;
00258         n=c->next(p);
00259       } else {
00260         assert(m < lst()->min());
00261         n = NULL;
00262         c = lst();
00263         do {
00264           p=c->prev(n); n=c; c=p;
00265         } while (m < c->min());
00266         if (m > c->max())
00267           return ME_INT_NONE;
00268         p=c->prev(n);
00269       }
00270       assert((fst() != c) && (lst() != c));
00271       assert((m >= c->min()) && (m <= c->max()));
00272       holes += 1;
00273       int c_min = c->min();
00274       int c_max = c->max();
00275       if ((c_min == m) && (c_max == m)) {
00276         c->dispose(home);
00277         p->next(c,n); n->prev(c,p);
00278       } else if (c_min == m) {
00279         c->min(m+1);
00280       } else {
00281         c->max(m-1);
00282         if (c_max != m) {
00283           RangeList* l = new (home) RangeList(m+1,c_max);
00284           l->prevnext(c,n);
00285           c->next(n,l);
00286           n->prev(c,l);
00287         }
00288       }
00289     }
00290     notify(home,ME_INT_DOM);
00291     return ME_INT_DOM;
00292   notify_bnd_or_val:
00293     if (assigned()) {
00294       notify(home,ME_INT_VAL);
00295       return ME_INT_VAL;
00296     }
00297   notify_bnd:
00298     notify(home,ME_INT_BND);
00299     return ME_INT_BND;
00300   }
00301 
00302 
00303 
00304   /*
00305    * Copying variables
00306    *
00307    */
00308 
00309   forceinline
00310   IntVarImp::IntVarImp(Space* home, bool share, IntVarImp& x, bool is_bool)
00311     : IntVarImpBase(home,share,x), dom(x.dom.min(),x.dom.max()) { 
00312     if (is_bool) {
00313       holes = 0; fst(NULL);
00314     } else {
00315       holes = x.holes;
00316       if (holes) {
00317         int m = 1;
00318         // Compute length
00319         {
00320           RangeList* s_p = x.fst();
00321           RangeList* s_c = s_p->next(NULL);
00322           do {
00323             m++;
00324             RangeList* s_n = s_c->next(s_p); s_p=s_c; s_c=s_n;
00325           } while (s_c != NULL);
00326         }
00327         RangeList* d_c =
00328           reinterpret_cast<RangeList*>(home->alloc(m*sizeof(RangeList)));
00329         fst(d_c); lst(d_c+m-1);
00330         d_c->min(x.fst()->min());
00331         d_c->max(x.fst()->max());
00332         d_c->prevnext(NULL,NULL);
00333         RangeList* s_p = x.fst();
00334         RangeList* s_c = s_p->next(NULL);
00335         do {
00336           RangeList* d_n = d_c + 1;
00337           d_c->next(NULL,d_n);
00338           d_n->prevnext(d_c,NULL);
00339           d_n->min(s_c->min()); d_n->max(s_c->max());
00340           d_c = d_n;
00341           RangeList* s_n=s_c->next(s_p); s_p=s_c; s_c=s_n;
00342         } while (s_c != NULL);
00343         d_c->next(NULL,NULL);
00344       } else {
00345         fst(NULL);
00346       }
00347     }
00348   }
00349 
00350   IntVarImp*
00351   IntVarImp::perform_copy(Space* home, bool share) {
00352     return new (home) IntVarImp(home,share,*this,false);
00353   }
00354   IntVarImp*
00355   IntVarImp::perform_copy_bool(Space* home, bool share) {
00356     return new (home) IntVarImp(home,share,*this,true);
00357   }
00358 
00359 }}
00360 
00361 // STATISTICS: int-var