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

reco-stack.icc

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: 2008-08-20 15:55:47 +0200 (Wed, 20 Aug 2008) $ by $Author: tack $
00011  *     $Revision: 7658 $
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 namespace Gecode { namespace Search {
00039 
00040   /*
00041    * Node for recomputation
00042    *
00043    */
00044 
00045   forceinline
00046   ReCoNode::ReCoNode(Space* s, Space* c)
00047     : _space(c), _alt(0), _desc(s->description()) {}
00048 
00049   forceinline Space*
00050   ReCoNode::space(void) const {
00051     return _space;
00052   }
00053   forceinline void
00054   ReCoNode::space(Space* s) {
00055     _space = s;
00056   }
00057 
00058   forceinline unsigned int
00059   ReCoNode::alt(void) const {
00060     return _alt;
00061   }
00062   forceinline bool
00063   ReCoNode::rightmost(void) const {
00064     return _alt+1 == _desc->alternatives();
00065   }
00066   forceinline void
00067   ReCoNode::next(void) {
00068     _alt++;
00069   }
00070 
00071   forceinline const BranchingDesc*
00072   ReCoNode::desc(void) const {
00073     return _desc;
00074   }
00075 
00076   forceinline void
00077   ReCoNode::dispose(void) {
00078     delete _space;
00079     delete _desc;
00080   }
00081 
00082 
00083 
00084   /*
00085    * Depth-first stack with recomputation
00086    *
00087    */
00088 
00089   forceinline
00090   ReCoStack::ReCoStack(unsigned int a_d0) : a_d(a_d0) {}
00091 
00092   forceinline const BranchingDesc*
00093   ReCoStack::push(Space* s, Space* c) {
00094     ReCoNode sn(s,c);
00095     ds.push(sn);
00096     return sn.desc();
00097   }
00098 
00099   template <class DescType>
00100   forceinline const BranchingDesc*
00101   ReCoStack::nextDesc(EngineCtrl& stat, int& alt, int& closedDescs) {
00102     closedDescs = 0;
00103     while (!ds.empty())
00104       if (ds.top().rightmost()) {
00105         stat.pop(ds.top().space(),ds.top().desc());
00106         if (dynamic_cast<const DescType*>(ds.top().desc()))
00107           closedDescs++;
00108         ds.pop().dispose();
00109       } else {
00110         ds.top().next();
00111         alt = ds.top().alt();
00112         return ds.top().desc();
00113       }
00114     return NULL;
00115   }
00116 
00117   template <class DescType, bool inclusive>
00118   forceinline void
00119   ReCoStack::closeBranch(EngineCtrl& stat) {
00120     while (!ds.empty()) {
00121       if (dynamic_cast<const DescType*>(ds.top().desc())) {
00122         if (inclusive && !ds.empty()) {
00123           stat.pop(ds.top().space(),ds.top().desc());
00124           ds.pop().dispose();      
00125         }
00126         break;       
00127       }
00128       stat.pop(ds.top().space(),ds.top().desc());
00129       ds.pop().dispose();
00130     }
00131   }
00132 
00133   forceinline bool
00134   ReCoStack::next(EngineCtrl& stat) {
00135     // Generate path for next node and return whether node exists.
00136     while (!ds.empty())
00137       if (ds.top().rightmost()) {
00138         stat.pop(ds.top().space(),ds.top().desc());
00139         ds.pop().dispose();
00140       } else {
00141         ds.top().next();
00142         return true;
00143       }
00144     return false;
00145   }
00146 
00147   forceinline void
00148   ReCoStack::commit(Space* s, int i) const {
00149     const ReCoNode& n = ds[i];
00150     s->commit(n.desc(),n.alt());
00151   }
00152 
00153   forceinline int
00154   ReCoStack::lc(Space*& s) const {
00155     int l = ds.entries()-1;
00156     while (ds[l].space() == NULL)
00157       l--;
00158     s = ds[l].space();
00159     return l;
00160   }
00161 
00162   forceinline int
00163   ReCoStack::entries(void) const {
00164     return ds.entries();
00165   }
00166 
00167   forceinline size_t
00168   ReCoStack::stacksize(void) const {
00169     return ds.size();
00170   }
00171 
00172   forceinline void
00173   ReCoStack::unwind(int l) {
00174     assert((ds[l].space() == NULL) || ds[l].space()->failed());
00175     int n = ds.entries();
00176     for (int i=l; i<n; i++)
00177       ds.pop().dispose();
00178     assert(ds.entries() == l);
00179   }
00180 
00181   inline void
00182   ReCoStack::reset(void) {
00183     while (!ds.empty())
00184       ds.pop().dispose();
00185   }
00186 
00187   template <bool constrained>
00188   forceinline Space*
00189   ReCoStack::recompute(unsigned int& d, EngineCtrl& stat) {
00190     assert(!ds.empty());
00191     // Recompute space according to path
00192     // Also say distance to copy (d == 0) requires immediate copying
00193 
00194     // Check for LAO
00195     if ((ds.top().space() != NULL) && ds.top().rightmost()) {
00196       Space* s = ds.top().space();
00197       s->commit(ds.top().desc(),ds.top().alt());
00198       ds.top().space(NULL);
00199       stat.lao(s);
00200       d = 0;
00201       stat.commit++;
00202       return s;
00203     }
00204     // General case for recomputation
00205     Space* s;             // Last clone
00206     int l = lc(s);        // Position of last clone
00207     int n = ds.entries(); // Number of stack entries
00208     d = static_cast<unsigned int>(n - l); // New distance, if no adaptive recomputation
00209 
00210     if (constrained) {
00211       // The space on the stack could be failed now as an additional
00212       // constraint might have been added.
00213       if (s->status(stat.propagate) == SS_FAILED) {
00214         // s does not need deletion as it is on the stack (unwind does this)
00215         stat.fail++;
00216         unwind(l);
00217         return NULL;
00218       }
00219       // It is important to replace the space on the stack with the
00220       // copy: a copy might be much smaller due to flushed caches
00221       // of propagators
00222       Space* c = s->clone();
00223       ds[l].space(c);
00224       stat.constrained(s,c);
00225     } else {
00226       s = s->clone();
00227     }
00228     stat.clone++;
00229 
00230     if (d < a_d) {
00231       // No adaptive recomputation
00232       for (int i=l; i<n; i++)
00233         commit(s,i);
00234     } else {
00235       int m = l + static_cast<int>(d >> 1); // Middle between copy and top
00236       int i = l;            // To iterate over all entries
00237       // Recompute up to middle
00238       for (; i<m; i++ )
00239         commit(s,i);
00240       // Skip over all rightmost branches
00241       for (; (i<n) && ds[i].rightmost(); i++)
00242         commit(s,i);
00243       // Is there any point to make a copy?
00244       if (i<n-1) {
00245         // Propagate to fixpoint
00246         SpaceStatus ss = s->status(stat.propagate);
00247         /*
00248          * Again, the space might already propagate to failure
00249          *
00250          * This can be for two reasons:
00251          *  - constrain is true, so we fail
00252          *  - the space has weakly monotonic propagators
00253          */
00254         if (ss == SS_FAILED) {
00255           // s must be deleted as it is not on the stack
00256           delete s;
00257           stat.commit += (i-l);
00258           stat.fail++;
00259           unwind(i);
00260           return NULL;
00261         }
00262         stat.clone++;
00263         ds[i].space(s->clone());
00264         stat.adapt(ds[i].space());
00265         d = static_cast<unsigned int>(n-i);
00266       }
00267       // Finally do the remaining commits
00268       for (; i<n; i++)
00269         commit(s,i);
00270     }
00271     stat.commit += d;
00272     return s;
00273   }
00274 
00275 }}
00276 
00277 // STATISTICS: search-any