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-08 20:33:02 +0200 (Fri, 08 May 2009) $ by $Author: schulte $
00011  *     $Revision: 9047 $
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_SEQUENTIAL_PATH_HH__
00039 #define __GECODE_SEARCH_SEQUENTIAL_PATH_HH__
00040 
00041 #include <gecode/search.hh>
00042 
00043 namespace Gecode { namespace Search { namespace Sequential {
00044 
00058   class Path {
00059   public:
00061     class Node {
00062     protected:
00064       Space* _space;
00066       unsigned int _alt;
00068       const BranchingDesc* _desc;
00069     public:
00071       Node(void);
00073       Node(Space* s, Space* c);
00074       
00076       Space* space(void) const;
00078       void space(Space* s);
00079       
00081       const BranchingDesc* desc(void) const;
00082       
00084       unsigned int alt(void) const;
00086       bool rightmost(void) const;
00088       void next(void);
00089       
00091       void dispose(void);
00092     };
00094     Support::DynamicStack<Node,Heap> ds;
00095   public:
00097     Path(void);
00099     const BranchingDesc* push(Worker& stat, Space* s, Space* c);
00101     bool next(Worker& s);
00103     int lc(void) const;
00105     void unwind(int l);
00107     void commit(Space* s, int i) const;
00109     Space* recompute(unsigned int& d, unsigned int a_d, Worker& s);
00111     Space* recompute(unsigned int& d, unsigned int a_d, Worker& s,
00112                      const Space* best, int& mark);
00114     int entries(void) const;
00116     size_t size(void) const;
00118     void reset(void);
00119   };
00120 
00121 
00122   /*
00123    * Node for recomputation
00124    *
00125    */
00126   forceinline
00127   Path::Node::Node(void) {}
00128 
00129   forceinline
00130   Path::Node::Node(Space* s, Space* c)
00131     : _space(c), _alt(0), _desc(s->description()) {}
00132 
00133   forceinline Space*
00134   Path::Node::space(void) const {
00135     return _space;
00136   }
00137   forceinline void
00138   Path::Node::space(Space* s) {
00139     _space = s;
00140   }
00141 
00142   forceinline unsigned int
00143   Path::Node::alt(void) const {
00144     return _alt;
00145   }
00146   forceinline bool
00147   Path::Node::rightmost(void) const {
00148     return _alt+1 == _desc->alternatives();
00149   }
00150   forceinline void
00151   Path::Node::next(void) {
00152     _alt++;
00153   }
00154 
00155   forceinline const BranchingDesc*
00156   Path::Node::desc(void) const {
00157     return _desc;
00158   }
00159 
00160   forceinline void
00161   Path::Node::dispose(void) {
00162     delete _space;
00163     delete _desc;
00164   }
00165 
00166 
00167 
00168   /*
00169    * Depth-first stack with recomputation
00170    *
00171    */
00172 
00173   forceinline
00174   Path::Path(void) : ds(heap) {}
00175 
00176   forceinline const BranchingDesc*
00177   Path::push(Worker& stat, Space* s, Space* c) {
00178     Node sn(s,c);
00179     ds.push(sn);
00180     stat.stack_depth(static_cast<unsigned long int>(ds.entries()));
00181     return sn.desc();
00182   }
00183 
00184   forceinline bool
00185   Path::next(Worker& stat) {
00186     // Generate path for next node and return whether node exists.
00187     while (!ds.empty())
00188       if (ds.top().rightmost()) {
00189         stat.pop(ds.top().space(),ds.top().desc());
00190         ds.pop().dispose();
00191       } else {
00192         ds.top().next();
00193         return true;
00194       }
00195     return false;
00196   }
00197 
00198   forceinline void
00199   Path::commit(Space* s, int i) const {
00200     const Node& n = ds[i];
00201     s->commit(*n.desc(),n.alt());
00202   }
00203 
00204   forceinline int
00205   Path::lc(void) const {
00206     int l = ds.entries()-1;
00207     while (ds[l].space() == NULL)
00208       l--;
00209     return l;
00210   }
00211 
00212   forceinline int
00213   Path::entries(void) const {
00214     return ds.entries();
00215   }
00216 
00217   forceinline size_t
00218   Path::size(void) const {
00219     return ds.size();
00220   }
00221 
00222   forceinline void
00223   Path::unwind(int l) {
00224     assert((ds[l].space() == NULL) || ds[l].space()->failed());
00225     int n = ds.entries();
00226     for (int i=l; i<n; i++)
00227       ds.pop().dispose();
00228     assert(ds.entries() == l);
00229   }
00230 
00231   inline void
00232   Path::reset(void) {
00233     while (!ds.empty())
00234       ds.pop().dispose();
00235   }
00236 
00237   forceinline Space*
00238   Path::recompute(unsigned int& d, unsigned int a_d, Worker& stat) {
00239     assert(!ds.empty());
00240     // Recompute space according to path
00241     // Also say distance to copy (d == 0) requires immediate copying
00242 
00243     // Check for LAO
00244     if ((ds.top().space() != NULL) && ds.top().rightmost()) {
00245       Space* s = ds.top().space();
00246       s->commit(*ds.top().desc(),ds.top().alt());
00247       assert(ds.entries()-1 == lc());
00248       ds.top().space(NULL);
00249       stat.lao(s);
00250       d = 0;
00251       return s;
00252     }
00253     // General case for recomputation
00254     int l = lc();             // Position of last clone
00255     int n = ds.entries();     // Number of stack entries
00256     // New distance, if no adaptive recomputation
00257     d = static_cast<unsigned int>(n - l);
00258 
00259     Space* s = ds[l].space()->clone(); // Last clone
00260 
00261     if (d < a_d) {
00262       // No adaptive recomputation
00263       for (int i=l; i<n; i++)
00264         commit(s,i);
00265     } else {
00266       int m = l + static_cast<int>(d >> 1); // Middle between copy and top
00267       int i = l; // To iterate over all entries
00268       // Recompute up to middle
00269       for (; i<m; i++ )
00270         commit(s,i);
00271       // Skip over all rightmost branches
00272       for (; (i<n) && ds[i].rightmost(); i++)
00273         commit(s,i);
00274       // Is there any point to make a copy?
00275       if (i<n-1) {
00276         // Propagate to fixpoint
00277         SpaceStatus ss = s->status(stat);
00278         /*
00279          * Again, the space might already propagate to failure (due to
00280          * weakly monotonic propagators).
00281          */
00282         if (ss == SS_FAILED) {
00283           // s must be deleted as it is not on the stack
00284           delete s;
00285           stat.fail++;
00286           unwind(i);
00287           return NULL;
00288         }
00289         ds[i].space(s->clone());
00290         stat.adapt(ds[i].space());
00291         d = static_cast<unsigned int>(n-i);
00292       }
00293       // Finally do the remaining commits
00294       for (; i<n; i++)
00295         commit(s,i);
00296     }
00297     return s;
00298   }
00299 
00300   forceinline Space*
00301   Path::recompute(unsigned int& d, unsigned int a_d, Worker& stat,
00302                   const Space* best, int& mark) {
00303     assert(!ds.empty());
00304     // Recompute space according to path
00305     // Also say distance to copy (d == 0) requires immediate copying
00306 
00307     // Check for LAO
00308     if ((ds.top().space() != NULL) && ds.top().rightmost()) {
00309       Space* s = ds.top().space();
00310       s->commit(*ds.top().desc(),ds.top().alt());
00311       assert(ds.entries()-1 == lc());
00312       if (mark > ds.entries()-1) {
00313         mark = ds.entries()-1;
00314         s->constrain(*best);
00315       }
00316       ds.top().space(NULL);
00317       stat.lao(s);
00318       d = 0;
00319       return s;
00320     }
00321     // General case for recomputation
00322     int l = lc();             // Position of last clone
00323     int n = ds.entries();     // Number of stack entries
00324     // New distance, if no adaptive recomputation
00325     d = static_cast<unsigned int>(n - l);
00326 
00327     Space* s = ds[l].space(); // Last clone
00328 
00329     if (l < mark) {
00330       mark = l;
00331       s->constrain(*best);
00332       // The space on the stack could be failed now as an additional
00333       // constraint might have been added.
00334       if (s->status(stat) == SS_FAILED) {
00335         // s does not need deletion as it is on the stack (unwind does this)
00336         stat.fail++;
00337         unwind(l);
00338         return NULL;
00339       }
00340       // It is important to replace the space on the stack with the
00341       // copy: a copy might be much smaller due to flushed caches
00342       // of propagators
00343       Space* c = s->clone();
00344       ds[l].space(c);
00345       stat.constrained(s,c);
00346     } else {
00347       s = s->clone();
00348     }
00349 
00350     if (d < a_d) {
00351       // No adaptive recomputation
00352       for (int i=l; i<n; i++)
00353         commit(s,i);
00354     } else {
00355       int m = l + static_cast<int>(d >> 1); // Middle between copy and top
00356       int i = l;            // To iterate over all entries
00357       // Recompute up to middle
00358       for (; i<m; i++ )
00359         commit(s,i);
00360       // Skip over all rightmost branches
00361       for (; (i<n) && ds[i].rightmost(); i++)
00362         commit(s,i);
00363       // Is there any point to make a copy?
00364       if (i<n-1) {
00365         // Propagate to fixpoint
00366         SpaceStatus ss = s->status(stat);
00367         /*
00368          * Again, the space might already propagate to failure
00369          *
00370          * This can be for two reasons:
00371          *  - constrain is true, so we fail
00372          *  - the space has weakly monotonic propagators
00373          */
00374         if (ss == SS_FAILED) {
00375           // s must be deleted as it is not on the stack
00376           delete s;
00377           stat.fail++;
00378           unwind(i);
00379           return NULL;
00380         }
00381         ds[i].space(s->clone());
00382         stat.adapt(ds[i].space());
00383         d = static_cast<unsigned int>(n-i);
00384       }
00385       // Finally do the remaining commits
00386       for (; i<n; i++)
00387         commit(s,i);
00388     }
00389     return s;
00390   }
00391 
00392 }}}
00393 
00394 #endif
00395 
00396 // STATISTICS: search-sequential