/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Christian Schulte * * Copyright: * Christian Schulte, 2004, 2016 * * 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 Seq { /* * Nodes for the probing engine (just remember next alternative * to try) * */ template forceinline Probe::Node::Node(void) {} template forceinline Probe::Node::Node(Space* s, const Choice* c, unsigned int a, unsigned int nid) : _space(s), _choice(c), _alt(a), _nid(nid) {} template forceinline Space* Probe::Node::space(void) const { return _space; } template forceinline const Choice* Probe::Node::choice(void) const { return _choice; } template forceinline unsigned int Probe::Node::alt(void) const { return _alt; } template forceinline unsigned int Probe::Node::nid(void) const { return _nid; } template forceinline void Probe::Node::next(void) { _alt--; } /* * The probing engine: computes all solutions with * exact number of discrepancies (solutions with * fewer discrepancies are discarded) * */ template forceinline Probe::Probe(const Options& opt) : tracer(opt.tracer), ds(heap) { tracer.engine(SearchTracer::EngineType::LDS, 1U); tracer.worker(); } template forceinline void Probe::init(Space* s) { cur = s; d = 0U; exhausted = true; if (tracer) tracer.ei()->invalidate(); } template forceinline void Probe::reset(Space* s, unsigned int d0) { tracer.round(); delete cur; while (!ds.empty()) delete ds.pop().space(); cur = s; d = d0; exhausted = true; if (tracer) tracer.ei()->invalidate(); Worker::reset(0); } template forceinline Statistics Probe::statistics(void) const { return *this; } template forceinline bool Probe::done(void) const { return exhausted; } template forceinline Probe::~Probe(void) { tracer.done(); delete cur; while (!ds.empty()) delete ds.pop().space(); } template forceinline Space* Probe::next(const Options& opt) { start(); while (true) { if (cur == nullptr) { backtrack: if (ds.empty()) return nullptr; if (stop(opt)) return nullptr; unsigned int a = ds.top().alt(); const Choice* ch = ds.top().choice(); unsigned int nid = ds.top().nid(); if (a == 0) { cur = ds.pop().space(); if (tracer) tracer.ei()->init(tracer.wid(), nid, 0, *cur, *ch); cur->commit(*ch,0); delete ch; } else { ds.top().next(); cur = ds.top().space()->clone(); if (tracer) tracer.ei()->init(tracer.wid(), nid, a, *cur, *ch); cur->commit(*ch,a); } node++; d++; } check_discrepancy: if (d == 0) { Space* s = cur; while (s->status(*this) == SS_BRANCH) { if (stop(opt)) { cur = s; return nullptr; } const Choice* ch = s->choice(); if (ch->alternatives() > 1) exhausted = false; if (tracer) { unsigned int nid = tracer.nid(); SearchTracer::NodeInfo ni(SearchTracer::NodeType::BRANCH, tracer.wid(), nid, *s, ch); tracer.node(*tracer.ei(),ni); if (tracer) tracer.ei()->init(tracer.wid(), nid, 0, *cur, *ch); } s->commit(*ch,0); node++; delete ch; } cur = nullptr; if (s->failed()) { if (tracer) { SearchTracer::NodeInfo ni(SearchTracer::NodeType::FAILED, tracer.wid(), tracer.nid(), *s); tracer.node(*tracer.ei(),ni); } fail++; delete s; goto backtrack; } else { if (tracer) { SearchTracer::NodeInfo ni(SearchTracer::NodeType::SOLVED, tracer.wid(), tracer.nid(), *s); tracer.node(*tracer.ei(),ni); } // Deletes all pending branchings (void) s->choice(); return s; } } else { node++; switch (cur->status(*this)) { case SS_FAILED: if (tracer) { SearchTracer::NodeInfo ni(SearchTracer::NodeType::FAILED, tracer.wid(), tracer.nid(), *cur); tracer.node(*tracer.ei(),ni); } fail++; delete cur; cur = nullptr; goto backtrack; case SS_SOLVED: if (tracer) { tracer.skip(*tracer.ei()); } delete cur; cur = nullptr; goto backtrack; case SS_BRANCH: { const Choice* ch = cur->choice(); unsigned int alt = ch->alternatives(); unsigned int nid = tracer.nid(); if (tracer) { SearchTracer::NodeInfo ni(SearchTracer::NodeType::BRANCH, tracer.wid(), nid, *cur, ch); tracer.node(*tracer.ei(),ni); } if (alt > 1) { if (d < alt-1) exhausted = false; unsigned int d_a = (d >= alt-1) ? alt-1 : d; Space* cc = cur->clone(); Node sn(cc,ch,d_a-1,nid); ds.push(sn); stack_depth(static_cast(ds.entries())); if (tracer) tracer.ei()->init(tracer.wid(), nid, d_a, *cur, *ch); cur->commit(*ch,d_a); d -= d_a; } else { if (tracer) tracer.ei()->init(tracer.wid(), nid, 0, *cur, *ch); cur->commit(*ch,0); node++; delete ch; } goto check_discrepancy; } default: GECODE_NEVER; } } } } template forceinline LDS::LDS(Space* s, const Options& o) : opt(o), e(opt), root(nullptr), d(0) { e.node = 1; if (s->status(e) == SS_FAILED) { e.fail++; e.init(nullptr); } else { Space* c = snapshot(s,opt); if (opt.d_l > 0) { root = c->clone(); } e.init(c); } } template Space* LDS::next(void) { while (true) { Space* s = e.next(opt); if (s != nullptr) return s; if (((s == nullptr) && e.stopped()) || (++d > opt.d_l) || e.done()) break; if (d == opt.d_l) { if (root != nullptr) e.reset(root,d); root = nullptr; } else if (root != nullptr) { e.reset(root->clone(),d); } } return nullptr; } template bool LDS::stopped(void) const { return e.stopped(); } template Statistics LDS::statistics(void) const { return e.statistics(); } template forceinline void LDS::reset(Space* s) { delete root; root=nullptr; d=0; e.node = 1; if ((s == nullptr) || (s->status(e) == SS_FAILED)) { delete s; e.fail++; e.reset(nullptr,0); } else { if (opt.d_l > 0) { root = s->clone(); } e.reset(s,0); } } template forceinline void LDS::constrain(const Space& b) { (void) b; assert(false); } template LDS::~LDS(void) { delete root; } }}} // STATISTICS: search-seq