Generated on Mon Jul 6 18:09:17 2009 for Gecode by doxygen 1.5.9

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