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

int.cc

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, 2002
00008  *
00009  *  Last modified:
00010  *     $Date: 2008-07-11 09:39:08 +0200 (Fri, 11 Jul 2008) $ by $Author: tack $
00011  *     $Revision: 7297 $
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 "gecode/int.hh"
00039 
00040 namespace Gecode { namespace Int {
00041 
00042   forceinline bool
00043   IntVarImp::closer_min(int n) const {
00044     unsigned int l = static_cast<unsigned int>(n - dom.min());
00045     unsigned int r = static_cast<unsigned int>(dom.max() - n);
00046     return l < r;
00047   }
00048 
00049   int
00050   IntVarImp::med(void) const {
00051     // Computes the median
00052     if (fst() == NULL)
00053       return (dom.min()+dom.max())/2;
00054     unsigned int i = size() / 2;
00055     const RangeList* p = NULL;
00056     const RangeList* c = fst();
00057     while (i >= c->width()) {
00058       i -= c->width();
00059       const RangeList* n=c->next(p); p=c; c=n;
00060     }
00061     return c->min() + static_cast<int>(i);
00062   }
00063 
00064   bool
00065   IntVarImp::in_full(int m) const {
00066     if (closer_min(m)) {
00067       const RangeList* p = NULL;
00068       const RangeList* c = fst();
00069       while (m > c->max()) {
00070         const RangeList* n=c->next(p); p=c; c=n;
00071       }
00072       return (m >= c->min());
00073     } else {
00074       const RangeList* n = NULL;
00075       const RangeList* c = lst();
00076       while (m < c->min()) {
00077         const RangeList* p=c->prev(n); n=c; c=p;
00078       }
00079       return (m <= c->max());
00080     }
00081   }
00082 
00083   /*
00084    * "Standard" tell operations
00085    *
00086    */
00087 
00088   ModEvent
00089   IntVarImp::lq_full(Space* home, int m) {
00090     assert((m >= dom.min()) && (m <= dom.max()));
00091     IntDelta d(m+1,dom.max());
00092     ModEvent me = ME_INT_BND;
00093     if (range()) { // Is already range...
00094       dom.max(m);
00095       if (assigned()) me = ME_INT_VAL;
00096     } else if (m < fst()->next(NULL)->min()) { // Becomes range...
00097       dom.max(std::min(m,fst()->max()));
00098       fst()->dispose(home,NULL,lst());
00099       fst(NULL); holes = 0;
00100       if (assigned()) me = ME_INT_VAL;
00101     } else { // Stays non-range...
00102       RangeList* n = NULL;
00103       RangeList* c = lst();
00104       unsigned int h = 0;
00105       while (m < c->min()) {
00106         RangeList* p = c->prev(n); c->fix(n);
00107         h += (c->min() - p->max() - 1);
00108         n=c; c=p;
00109       }
00110       holes -= h;
00111       int max_c = std::min(m,c->max());
00112       dom.max(max_c); c->max(max_c);
00113       if (c != lst()) {
00114         lst()->dispose(home,n);
00115         c->next(n,NULL); lst(c);
00116       }
00117     }
00118     return notify(home,me,&d);
00119   }
00120 
00121   ModEvent
00122   IntVarImp::gq_full(Space* home, int m) {
00123     assert((m >= dom.min()) && (m <= dom.max()));
00124     IntDelta d(dom.min(),m-1);
00125     ModEvent me = ME_INT_BND;
00126     if (range()) { // Is already range...
00127       dom.min(m);
00128       if (assigned()) me = ME_INT_VAL;
00129     } else if (m > lst()->prev(NULL)->max()) { // Becomes range...
00130       dom.min(std::max(m,lst()->min()));
00131       fst()->dispose(home,NULL,lst());
00132       fst(NULL); holes = 0;
00133       if (assigned()) me = ME_INT_VAL;
00134     } else { // Stays non-range...
00135       RangeList* p = NULL;
00136       RangeList* c = fst();
00137       unsigned int h = 0;
00138       while (m > c->max()) {
00139         RangeList* n = c->next(p); c->fix(n);
00140         h += (n->min() - c->max() - 1);
00141         p=c; c=n;
00142       }
00143       holes -= h;
00144       int min_c = std::max(m,c->min());
00145       dom.min(min_c); c->min(min_c);
00146       if (c != fst()) {
00147         fst()->dispose(home,p);
00148         c->prev(p,NULL); fst(c);
00149       }
00150     }
00151     return notify(home,me,&d);
00152   }
00153 
00154   ModEvent
00155   IntVarImp::eq_full(Space* home, int m) {
00156     dom.min(m); dom.max(m);
00157     if (!range()) {
00158       bool failed = false;
00159       RangeList* p = NULL;
00160       RangeList* c = fst();
00161       while (m > c->max()) {
00162         RangeList* n=c->next(p); c->fix(n); p=c; c=n;
00163       }
00164       if (m < c->min())
00165         failed = true;
00166       while (c != NULL) {
00167         RangeList* n=c->next(p); c->fix(n); p=c; c=n;
00168       }
00169       assert(p == lst());
00170       fst()->dispose(home,p);
00171       fst(NULL); holes = 0;
00172       if (failed)
00173         return ME_INT_FAILED;
00174     }
00175     IntDelta d;
00176     return notify(home,ME_INT_VAL,&d);
00177   }
00178 
00179   ModEvent
00180   IntVarImp::nq_full(Space* home, int m) {
00181     assert(!((m < dom.min()) || (m > dom.max())));
00182     ModEvent me = ME_INT_DOM;
00183     if (range()) {
00184       if ((m == dom.min()) && (m == dom.max()))
00185         return ME_INT_FAILED;
00186       if (m == dom.min()) {
00187         dom.min(m+1);
00188         me = assigned() ? ME_INT_VAL : ME_INT_BND;
00189       } else if (m == dom.max()) {
00190         dom.max(m-1);
00191         me = assigned() ? ME_INT_VAL : ME_INT_BND;
00192       } else {
00193         RangeList* f = new (home) RangeList(dom.min(),m-1);
00194         RangeList* l = new (home) RangeList(m+1,dom.max());
00195         f->prevnext(NULL,l);
00196         l->prevnext(f,NULL);
00197         fst(f); lst(l); holes = 1;
00198       }
00199     } else if (m < fst()->next(NULL)->min()) { // Concerns the first range...
00200       int f_max = fst()->max();
00201       if (m > f_max)
00202         return ME_INT_NONE;
00203       int f_min = dom.min();
00204       if ((m == f_min) && (m == f_max)) {
00205         RangeList* f_next = fst()->next(NULL);
00206         dom.min(f_next->min());
00207         if (f_next == lst()) { // Turns into range
00208           // Works as at the ends there are only NULL pointers
00209           fst()->dispose(home,f_next);
00210           fst(NULL); holes = 0;
00211           me = assigned() ? ME_INT_VAL : ME_INT_BND;
00212         } else { // Remains non-range
00213           f_next->prev(fst(),NULL);
00214           fst()->dispose(home); fst(f_next);
00215           holes -= dom.min() - f_min - 1;
00216           me = ME_INT_BND;
00217         }
00218       } else if (m == f_min) {
00219         dom.min(m+1); fst()->min(m+1);
00220         me = ME_INT_BND;
00221       } else if (m == f_max) {
00222         fst()->max(m-1); holes += 1;
00223       } else {
00224         // Create new hole
00225         RangeList* f = new (home) RangeList(f_min,m-1);
00226         f->prevnext(NULL,fst());
00227         fst()->min(m+1); fst()->prev(NULL,f);
00228         fst(f); holes += 1;
00229       }
00230     } else if (m > lst()->prev(NULL)->max()) { // Concerns the last range...
00231       int l_min = lst()->min();
00232       if (m < l_min)
00233         return ME_INT_NONE;
00234       int l_max = dom.max();
00235       if ((m == l_min) && (m == l_max)) {
00236         RangeList* l_prev = lst()->prev(NULL);
00237         dom.max(l_prev->max());
00238         if (l_prev == fst()) {
00239           // Turns into range
00240           l_prev->dispose(home,lst());
00241           fst(NULL); holes = 0;
00242           me = assigned() ? ME_INT_VAL : ME_INT_BND;
00243         } else { // Remains non-range
00244           l_prev->next(lst(),NULL);
00245           lst()->dispose(home); lst(l_prev);
00246           holes -= l_max - dom.max() - 1;
00247           me = ME_INT_BND;
00248         }
00249       } else if (m == l_max) {
00250         dom.max(m-1); lst()->max(m-1);
00251         me = ME_INT_BND;
00252       } else if (m == l_min) {
00253         lst()->min(m+1); holes += 1;
00254       } else { // Create new hole
00255         RangeList* l = new (home) RangeList(m+1,l_max);
00256         l->prevnext(lst(),NULL);
00257         lst()->max(m-1); lst()->next(NULL,l);
00258         lst(l); holes += 1;
00259       }
00260     } else { // Concerns element in the middle of the list of ranges
00261       RangeList* p;
00262       RangeList* c;
00263       RangeList* n;
00264       if (closer_min(m)) {
00265         assert(m > fst()->max());
00266         p = NULL;
00267         c = fst();
00268         do {
00269           n=c->next(p); p=c; c=n;
00270         } while (m > c->max());
00271         if (m < c->min())
00272           return ME_INT_NONE;
00273         n=c->next(p);
00274       } else {
00275         assert(m < lst()->min());
00276         n = NULL;
00277         c = lst();
00278         do {
00279           p=c->prev(n); n=c; c=p;
00280         } while (m < c->min());
00281         if (m > c->max())
00282           return ME_INT_NONE;
00283         p=c->prev(n);
00284       }
00285       assert((fst() != c) && (lst() != c));
00286       assert((m >= c->min()) && (m <= c->max()));
00287       holes += 1;
00288       int c_min = c->min();
00289       int c_max = c->max();
00290       if ((c_min == m) && (c_max == m)) {
00291         c->dispose(home);
00292         p->next(c,n); n->prev(c,p);
00293       } else if (c_min == m) {
00294         c->min(m+1);
00295       } else {
00296         c->max(m-1);
00297         if (c_max != m) {
00298           RangeList* l = new (home) RangeList(m+1,c_max);
00299           l->prevnext(c,n);
00300           c->next(n,l);
00301           n->prev(c,l);
00302         }
00303       }
00304     }
00305     IntDelta d(m,m);
00306     return notify(home,me,&d);
00307   }
00308 
00309 
00310 
00311   /*
00312    * Copying variables
00313    *
00314    */
00315 
00316   forceinline
00317   IntVarImp::IntVarImp(Space* home, bool share, IntVarImp& x)
00318     : IntVarImpBase(home,share,x), dom(x.dom.min(),x.dom.max()) { 
00319     holes = x.holes;
00320     if (holes) {
00321       int m = 1;
00322       // Compute length
00323       {
00324         RangeList* s_p = x.fst();
00325         RangeList* s_c = s_p->next(NULL);
00326         do {
00327           m++;
00328           RangeList* s_n = s_c->next(s_p); s_p=s_c; s_c=s_n;
00329         } while (s_c != NULL);
00330       }
00331       RangeList* d_c =
00332         static_cast<RangeList*>(home->alloc(m*sizeof(RangeList)));
00333       fst(d_c); lst(d_c+m-1);
00334       d_c->min(x.fst()->min());
00335       d_c->max(x.fst()->max());
00336       d_c->prevnext(NULL,NULL);
00337       RangeList* s_p = x.fst();
00338       RangeList* s_c = s_p->next(NULL);
00339       do {
00340         RangeList* d_n = d_c + 1;
00341         d_c->next(NULL,d_n);
00342         d_n->prevnext(d_c,NULL);
00343         d_n->min(s_c->min()); d_n->max(s_c->max());
00344         d_c = d_n;
00345         RangeList* s_n=s_c->next(s_p); s_p=s_c; s_c=s_n;
00346       } while (s_c != NULL);
00347       d_c->next(NULL,NULL);
00348     } else {
00349       fst(NULL);
00350     }
00351   }
00352 
00353   IntVarImp*
00354   IntVarImp::perform_copy(Space* home, bool share) {
00355     return new (home) IntVarImp(home,share,*this);
00356   }
00357 
00358   Reflection::Arg*
00359   IntVarImp::spec(const Space*, Reflection::VarMap& m) const {
00360     int varIndex = m.index(this);
00361     if (varIndex != -1)
00362       return Reflection::Arg::newVar(varIndex);
00363 
00364     int count = 0;
00365     const RangeList* p=NULL;
00366     const RangeList* c=ranges_fwd();
00367     while (c != NULL) {
00368       const RangeList* n = c->next(p); p=c; c=n;
00369       count++;
00370     }
00371     Reflection::IntArrayArg* args = Reflection::Arg::newIntArray(count*2);
00372 
00373     Reflection::VarSpec* spec = new Reflection::VarSpec(vti, args, 
00374                                                         assigned());
00375 
00376     count = 0;
00377     p=NULL;
00378     c=ranges_fwd();
00379     while (c != NULL) {
00380       (*args)[count++] = c->min();
00381       (*args)[count++] = c->max();
00382       const RangeList* n = c->next(p); p=c; c=n;
00383     }
00384 
00385     return Reflection::Arg::newVar(m.put(this, spec));
00386   }
00387 
00388   VarImpBase*
00389   IntVarImp::create(Space* home, Reflection::VarSpec& spec) {
00390     Reflection::IntArrayArgRanges ai(spec.dom()->toIntArray());
00391     return new (home) IntVarImp(home, IntSet(ai));
00392   }
00393 
00394   void
00395   IntVarImp::constrain(Space* home, VarImpBase* v,
00396                        Reflection::VarSpec& spec) {
00397     Reflection::IntArrayArgRanges ai(spec.dom()->toIntArray());
00398     GECODE_ME_FAIL(home,
00399       static_cast<Int::IntVarImp*>(v)->inter_r(home, ai, false));
00400   }
00401 
00402   namespace {
00403     Reflection::VarImpRegistrar<IntVarImp> registerIntVarImp;
00404   }
00405 
00406 }}
00407 
00408 // STATISTICS: int-var