/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Christian Schulte * * Copyright: * Christian Schulte, 2003 * * This file is part of Gecode, the generic constraint * development environment: * http://www.gecode.org * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ namespace Gecode { namespace Search { namespace Par { /* * Edge for recomputation * */ template forceinline Path::Edge::Edge(void) {} template forceinline Path::Edge::Edge(Space* s, Space* c, unsigned int nid) : _space(c), _alt(0), _choice(s->choice()), _nid(nid) { _alt_max = _choice->alternatives()-1; } template forceinline Space* Path::Edge::space(void) const { return _space; } template forceinline void Path::Edge::space(Space* s) { _space = s; } template forceinline unsigned int Path::Edge::alt(void) const { return _alt; } template forceinline unsigned int Path::Edge::nid(void) const { return _nid; } template forceinline unsigned int Path::Edge::truealt(void) const { return std::min(_alt,_choice->alternatives()-1); } template forceinline bool Path::Edge::rightmost(void) const { return _alt >= _alt_max; } template forceinline bool Path::Edge::lao(void) const { return _alt > _alt_max; } template forceinline bool Path::Edge::work(void) const { return _alt < _alt_max; } template forceinline void Path::Edge::next(void) { _alt++; } template forceinline unsigned int Path::Edge::steal(void) { assert(work()); return _alt_max--; } template forceinline const Choice* Path::Edge::choice(void) const { return _choice; } template forceinline void Path::Edge::dispose(void) { delete _space; delete _choice; } /* * Depth-first stack with recomputation * */ template forceinline Path::Path(unsigned int l) : ds(heap), _ngdl(l), n_work(0) {} template forceinline unsigned int Path::ngdl(void) const { return _ngdl; } template forceinline void Path::ngdl(unsigned int l) { _ngdl = l; } template forceinline const Choice* Path::push(Worker& stat, Space* s, Space* c, unsigned int nid) { if (!ds.empty() && ds.top().lao()) { // Topmost stack entry was LAO -> reuse ds.pop().dispose(); } Edge sn(s,c,nid); if (sn.work()) n_work++; ds.push(sn); stat.stack_depth(static_cast(ds.entries())); return sn.choice(); } template forceinline void Path::next(void) { while (!ds.empty()) if (ds.top().rightmost()) { ds.pop().dispose(); } else { assert(ds.top().work()); ds.top().next(); if (!ds.top().work()) n_work--; return; } } template forceinline typename Path::Edge& Path::top(void) const { assert(!ds.empty()); return ds.top(); } template forceinline bool Path::empty(void) const { return ds.empty(); } template forceinline void Path::commit(Space* s, int i) const { const Edge& n = ds[i]; s->commit(*n.choice(),n.alt()); } template forceinline int Path::lc(void) const { int l = ds.entries()-1; while (ds[l].space() == nullptr) l--; return l; } template forceinline int Path::entries(void) const { return ds.entries(); } template forceinline void Path::unwind(int l, Tracer& t) { assert((ds[l].space() == nullptr) || ds[l].space()->failed()); int n = ds.entries(); if (t) { for (int i=l; i::Edge& top = ds.top(); unsigned int fa = (i != l) ? top.alt() + 1 : top.alt(); for (unsigned int a = fa; a < top.choice()->alternatives(); a++) { SearchTracer::EdgeInfo ei(t.wid(), top.nid(), a); t.skip(ei); } if (ds.top().work()) n_work--; ds.pop().dispose(); } } else { for (int i=l; i forceinline void Path::reset(unsigned int l) { n_work = 0; while (!ds.empty()) ds.pop().dispose(); _ngdl = l; } template forceinline bool Path::steal(void) const { return n_work > Config::steal_limit; } template forceinline Space* Path::steal(Worker& stat, unsigned long int& d, Tracer& myt, Tracer& ot) { // Find position to steal: leave sufficient work int n = ds.entries()-1; unsigned int w = 0; while (n >= 0) { if (ds[n].work()) w++; if (w > Config::steal_limit) { // Okay, there is sufficient work left int l=n; // Find last copy while (ds[l].space() == nullptr) l--; Space* c = ds[l].space()->clone(); // Recompute, if necessary for (int i=l; icommit(*ds[n].choice(),a); if (!ds[n].work()) n_work--; // No no-goods can be extracted above n ngdl(std::min(ngdl(),static_cast(n))); d = stat.steal_depth(static_cast(n+1)); if (myt && ot) { ot.ei()->init(myt.wid(),ds[n].nid(), a, *c, *ds[n].choice()); } return c; } n--; } return nullptr; } template forceinline Space* Path::recompute(unsigned int& d, unsigned int a_d, Worker& stat, Tracer& t) { assert(!ds.empty()); // Recompute space according to path // Also say distance to copy (d == 0) requires immediate copying // Check for LAO if ((ds.top().space() != nullptr) && ds.top().rightmost()) { Space* s = ds.top().space(); s->commit(*ds.top().choice(),ds.top().alt()); assert(ds.entries()-1 == lc()); ds.top().space(nullptr); // Mark as reusable if (static_cast(ds.entries()) > ngdl()) ds.top().next(); d = 0; return s; } // General case for recomputation int l = lc(); // Position of last clone int n = ds.entries(); // Number of stack entries // New distance, if no adaptive recomputation d = static_cast(n - l); Space* s = ds[l].space()->clone(); // Last clone if (d < a_d) { // No adaptive recomputation for (int i=l; i(d >> 1); // Middle between copy and top int i = l; // To iterate over all entries // Recompute up to middle for (; istatus(stat); /* * Again, the space might already propagate to failure (due to * weakly monotonic propagators). */ if (ss == SS_FAILED) { // s must be deleted as it is not on the stack delete s; stat.fail++; unwind(i,t); return nullptr; } ds[i].space(s->clone()); d = static_cast(n-i); } // Finally do the remaining commits for (; i forceinline Space* Path::recompute(unsigned int& d, unsigned int a_d, Worker& stat, const Space& best, int& mark, Tracer& t) { assert(!ds.empty()); // Recompute space according to path // Also say distance to copy (d == 0) requires immediate copying // Check for LAO if ((ds.top().space() != nullptr) && ds.top().rightmost()) { Space* s = ds.top().space(); s->commit(*ds.top().choice(),ds.top().alt()); assert(ds.entries()-1 == lc()); if (mark > ds.entries()-1) { mark = ds.entries()-1; s->constrain(best); } ds.top().space(nullptr); // Mark as reusable if (static_cast(ds.entries()) > ngdl()) ds.top().next(); d = 0; return s; } // General case for recomputation int l = lc(); // Position of last clone int n = ds.entries(); // Number of stack entries // New distance, if no adaptive recomputation d = static_cast(n - l); Space* s = ds[l].space(); // Last clone if (l < mark) { mark = l; s->constrain(best); // The space on the stack could be failed now as an additional // constraint might have been added. if (s->status(stat) == SS_FAILED) { // s does not need deletion as it is on the stack (unwind does this) stat.fail++; unwind(l,t); return nullptr; } // It is important to replace the space on the stack with the // copy: a copy might be much smaller due to flushed caches // of propagators Space* c = s->clone(); ds[l].space(c); } else { s = s->clone(); } if (d < a_d) { // No adaptive recomputation for (int i=l; i(d >> 1); // Middle between copy and top int i = l; // To iterate over all entries // Recompute up to middle for (; istatus(stat); /* * Again, the space might already propagate to failure * * This can be for two reasons: * - constrain is true, so we fail * - the space has weakly monotonic propagators */ if (ss == SS_FAILED) { // s must be deleted as it is not on the stack delete s; stat.fail++; unwind(i,t); return nullptr; } ds[i].space(s->clone()); d = static_cast(n-i); } // Finally do the remaining commits for (; i void Path::post(Space& home) const { GECODE_ES_FAIL(NoGoodsProp::post(home,*this)); } }}} // STATISTICS: search-par