Generated on Wed Mar 13 11:48:33 2013 for Gecode by doxygen 1.6.3

path.hh

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, 2003
00008  *
00009  *  Last modified:
00010  *     $Date: 2013-02-26 10:47:43 +0100 (Tue, 26 Feb 2013) $ by $Author: schulte $
00011  *     $Revision: 13414 $
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 #ifndef __GECODE_SEARCH_PARALLEL_PATH_HH__
00039 #define __GECODE_SEARCH_PARALLEL_PATH_HH__
00040 
00041 #include <gecode/search.hh>
00042 
00043 namespace Gecode { namespace Search { namespace Parallel {
00044 
00058   class Path {
00059   public:
00061     class Edge {
00062     protected:
00064       Space* _space;
00066       unsigned int _alt;
00068       unsigned int _alt_max;
00070       const Choice* _choice;
00071     public:
00073       Edge(void);
00075       Edge(Space* s, Space* c);
00076       
00078       Space* space(void) const;
00080       void space(Space* s);
00081       
00083       const Choice* choice(void) const;
00084       
00086       unsigned int alt(void) const;
00088       bool rightmost(void) const;
00090       bool lao(void) const;
00092       bool work(void) const;
00094       void next(void);
00096       unsigned int steal(void);
00097       
00099       void dispose(void);
00100     };
00101   protected:
00103     Support::DynamicStack<Edge,Heap> ds;
00105     unsigned int n_work;
00106   public:
00108     Path(void);
00110     const Choice* push(Worker& stat, Space* s, Space* c);
00112     bool next(Worker& s);
00114     Edge& top(void) const;
00116     bool empty(void) const;
00118     int lc(void) const;
00120     void unwind(int l);
00122     void commit(Space* s, int i) const;
00124     Space* recompute(unsigned int& d, unsigned int a_d, Worker& s);
00126     Space* recompute(unsigned int& d, unsigned int a_d, Worker& s,
00127                      const Space* best, int& mark);
00129     int entries(void) const;
00131     size_t size(void) const;
00133     void reset(void);
00135     bool steal(void) const;
00137     Space* steal(Worker& stat, unsigned long int& d);
00138   };
00139 
00140 
00141   /*
00142    * Edge for recomputation
00143    *
00144    */
00145   forceinline
00146   Path::Edge::Edge(void) {}
00147 
00148   forceinline
00149   Path::Edge::Edge(Space* s, Space* c)
00150     : _space(c), _alt(0), _choice(s->choice()) {
00151     _alt_max = _choice->alternatives()-1;
00152   }
00153 
00154   forceinline Space*
00155   Path::Edge::space(void) const {
00156     return _space;
00157   }
00158   forceinline void
00159   Path::Edge::space(Space* s) {
00160     _space = s;
00161   }
00162 
00163   forceinline unsigned int
00164   Path::Edge::alt(void) const {
00165     return _alt;
00166   }
00167   forceinline bool
00168   Path::Edge::rightmost(void) const {
00169     return _alt >= _alt_max;
00170   }
00171   forceinline bool
00172   Path::Edge::lao(void) const {
00173     return _alt > _alt_max;
00174   }
00175   forceinline bool
00176   Path::Edge::work(void) const {
00177     return _alt < _alt_max;
00178   }
00179   forceinline void
00180   Path::Edge::next(void) {
00181     _alt++;
00182   }
00183   forceinline unsigned int
00184   Path::Edge::steal(void) {
00185     assert(work());
00186     return _alt_max--;
00187   }
00188 
00189   forceinline const Choice*
00190   Path::Edge::choice(void) const {
00191     return _choice;
00192   }
00193 
00194   forceinline void
00195   Path::Edge::dispose(void) {
00196     delete _space;
00197     delete _choice;
00198   }
00199 
00200 
00201 
00202   /*
00203    * Depth-first stack with recomputation
00204    *
00205    */
00206 
00207   forceinline
00208   Path::Path(void) : ds(heap), n_work(0) {}
00209 
00210   forceinline const Choice*
00211   Path::push(Worker& stat, Space* s, Space* c) {
00212     if (!ds.empty() && ds.top().lao()) {
00213       // Topmost stack entry was LAO -> reuse
00214       stat.pop(ds.top().space(),ds.top().choice());
00215       ds.pop().dispose();
00216     }
00217     Edge sn(s,c);
00218     if (sn.work())
00219       n_work++;
00220     ds.push(sn);
00221     stat.stack_depth(static_cast<unsigned long int>(ds.entries()));
00222     return sn.choice();
00223   }
00224 
00225   forceinline bool
00226   Path::next(Worker& stat) {
00227     while (!ds.empty())
00228       if (ds.top().rightmost()) {
00229         stat.pop(ds.top().space(),ds.top().choice());
00230         ds.pop().dispose();
00231       } else {
00232         assert(ds.top().work());
00233         ds.top().next();
00234         if (!ds.top().work())
00235           n_work--;
00236         return true;
00237       }
00238     return false;
00239   }
00240 
00241   forceinline Path::Edge&
00242   Path::top(void) const {
00243     assert(!ds.empty());
00244     return ds.top();
00245   }
00246 
00247   forceinline bool
00248   Path::empty(void) const {
00249     return ds.empty();
00250   }
00251 
00252   forceinline void
00253   Path::commit(Space* s, int i) const {
00254     const Edge& n = ds[i];
00255     s->commit(*n.choice(),n.alt());
00256   }
00257 
00258   forceinline int
00259   Path::lc(void) const {
00260     int l = ds.entries()-1;
00261     while (ds[l].space() == NULL)
00262       l--;
00263     return l;
00264   }
00265 
00266   forceinline int
00267   Path::entries(void) const {
00268     return ds.entries();
00269   }
00270 
00271   forceinline size_t
00272   Path::size(void) const {
00273     return ds.size();
00274   }
00275 
00276   forceinline void
00277   Path::unwind(int l) {
00278     assert((ds[l].space() == NULL) || ds[l].space()->failed());
00279     int n = ds.entries();
00280     for (int i=l; i<n; i++) {
00281       if (ds.top().work())
00282         n_work--;
00283       ds.pop().dispose();
00284     }
00285     assert(ds.entries() == l);
00286   }
00287 
00288   forceinline void
00289   Path::reset(void) {
00290     n_work = 0;
00291     while (!ds.empty())
00292       ds.pop().dispose();
00293   }
00294 
00295   forceinline bool
00296   Path::steal(void) const {
00297     return n_work > Config::steal_limit;
00298   }
00299 
00300   forceinline Space*
00301   Path::steal(Worker& stat, unsigned long int& d) {
00302     // Find position to steal: leave sufficient work
00303     int n = ds.entries()-1;
00304     unsigned int w = 0;
00305     while (n >= 0) {
00306       if (ds[n].work())
00307         w++;
00308       if (w > Config::steal_limit) {
00309         // Okay, there is sufficient work left
00310         int l=n;
00311         // Find last copy
00312         while (ds[l].space() == NULL)
00313           l--;
00314         Space* c = ds[l].space()->clone(false);
00315         // Recompute, if necessary
00316         for (int i=l; i<n; i++)
00317           commit(c,i);
00318         c->commit(*ds[n].choice(),ds[n].steal());
00319         if (!ds[n].work())
00320           n_work--;
00321         d = stat.steal_depth(static_cast<unsigned long int>(n+1));
00322         return c;
00323       }
00324       n--;
00325     }
00326     return NULL;
00327   }
00328 
00329   forceinline Space*
00330   Path::recompute(unsigned int& d, unsigned int a_d, Worker& stat) {
00331     assert(!ds.empty());
00332     // Recompute space according to path
00333     // Also say distance to copy (d == 0) requires immediate copying
00334 
00335     // Check for LAO
00336     if ((ds.top().space() != NULL) && ds.top().rightmost()) {
00337       Space* s = ds.top().space();
00338       stat.lao(s);
00339       s->commit(*ds.top().choice(),ds.top().alt());
00340       assert(ds.entries()-1 == lc());
00341       ds.top().space(NULL);
00342       // Mark as reusable
00343       ds.top().next();
00344       d = 0;
00345       return s;
00346     }
00347     // General case for recomputation
00348     int l = lc();             // Position of last clone
00349     int n = ds.entries();     // Number of stack entries
00350     // New distance, if no adaptive recomputation
00351     d = static_cast<unsigned int>(n - l);
00352 
00353     Space* s = ds[l].space()->clone(); // Last clone
00354 
00355     if (d < a_d) {
00356       // No adaptive recomputation
00357       for (int i=l; i<n; i++)
00358         commit(s,i);
00359     } else {
00360       int m = l + static_cast<int>(d >> 1); // Middle between copy and top
00361       int i = l; // To iterate over all entries
00362       // Recompute up to middle
00363       for (; i<m; i++ )
00364         commit(s,i);
00365       // Skip over all rightmost branches
00366       for (; (i<n) && ds[i].rightmost(); i++)
00367         commit(s,i);
00368       // Is there any point to make a copy?
00369       if (i<n-1) {
00370         // Propagate to fixpoint
00371         SpaceStatus ss = s->status(stat);
00372         /*
00373          * Again, the space might already propagate to failure (due to
00374          * weakly monotonic propagators).
00375          */
00376         if (ss == SS_FAILED) {
00377           // s must be deleted as it is not on the stack
00378           delete s;
00379           stat.fail++;
00380           unwind(i);
00381           return NULL;
00382         }
00383         ds[i].space(s->clone());
00384         stat.adapt(ds[i].space());
00385         d = static_cast<unsigned int>(n-i);
00386       }
00387       // Finally do the remaining commits
00388       for (; i<n; i++)
00389         commit(s,i);
00390     }
00391     return s;
00392   }
00393 
00394   forceinline Space*
00395   Path::recompute(unsigned int& d, unsigned int a_d, Worker& stat,
00396                   const Space* best, int& mark) {
00397     assert(!ds.empty());
00398     // Recompute space according to path
00399     // Also say distance to copy (d == 0) requires immediate copying
00400 
00401     // Check for LAO
00402     if ((ds.top().space() != NULL) && ds.top().rightmost()) {
00403       Space* s = ds.top().space();
00404       stat.lao(s);
00405       s->commit(*ds.top().choice(),ds.top().alt());
00406       assert(ds.entries()-1 == lc());
00407       if (mark > ds.entries()-1) {
00408         mark = ds.entries()-1;
00409         s->constrain(*best);
00410       }
00411       ds.top().space(NULL);
00412       // Mark as reusable
00413       ds.top().next();
00414       d = 0;
00415       return s;
00416     }
00417     // General case for recomputation
00418     int l = lc();             // Position of last clone
00419     int n = ds.entries();     // Number of stack entries
00420     // New distance, if no adaptive recomputation
00421     d = static_cast<unsigned int>(n - l);
00422 
00423     Space* s = ds[l].space(); // Last clone
00424 
00425     if (l < mark) {
00426       mark = l;
00427       s->constrain(*best);
00428       // The space on the stack could be failed now as an additional
00429       // constraint might have been added.
00430       if (s->status(stat) == SS_FAILED) {
00431         // s does not need deletion as it is on the stack (unwind does this)
00432         stat.fail++;
00433         unwind(l);
00434         return NULL;
00435       }
00436       // It is important to replace the space on the stack with the
00437       // copy: a copy might be much smaller due to flushed caches
00438       // of propagators
00439       Space* c = s->clone();
00440       ds[l].space(c);
00441       stat.constrained(s,c);
00442     } else {
00443       s = s->clone();
00444     }
00445 
00446     if (d < a_d) {
00447       // No adaptive recomputation
00448       for (int i=l; i<n; i++)
00449         commit(s,i);
00450     } else {
00451       int m = l + static_cast<int>(d >> 1); // Middle between copy and top
00452       int i = l;            // To iterate over all entries
00453       // Recompute up to middle
00454       for (; i<m; i++ )
00455         commit(s,i);
00456       // Skip over all rightmost branches
00457       for (; (i<n) && ds[i].rightmost(); i++)
00458         commit(s,i);
00459       // Is there any point to make a copy?
00460       if (i<n-1) {
00461         // Propagate to fixpoint
00462         SpaceStatus ss = s->status(stat);
00463         /*
00464          * Again, the space might already propagate to failure
00465          *
00466          * This can be for two reasons:
00467          *  - constrain is true, so we fail
00468          *  - the space has weakly monotonic propagators
00469          */
00470         if (ss == SS_FAILED) {
00471           // s must be deleted as it is not on the stack
00472           delete s;
00473           stat.fail++;
00474           unwind(i);
00475           return NULL;
00476         }
00477         ds[i].space(s->clone());
00478         stat.adapt(ds[i].space());
00479         d = static_cast<unsigned int>(n-i);
00480       }
00481       // Finally do the remaining commits
00482       for (; i<n; i++)
00483         commit(s,i);
00484     }
00485     return s;
00486   }
00487 
00488 }}}
00489 
00490 #endif
00491 
00492 // STATISTICS: search-parallel