/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Christian Schulte * * Contributing authors: * Guido Tack * * Copyright: * Christian Schulte, 2004 * Guido Tack, 2004 * * Last modified: * $Date: 2011-08-09 02:04:53 +1000 (Tue, 09 Aug 2011) $ by $Author: schulte $ * $Revision: 12253 $ * * 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. * */ #include namespace Gecode { namespace Int { namespace Element { /// VarArg type for integer views template<> class ViewToVarArg { public: typedef IntVarArgs argtype; }; /// VarArg type for Boolean views template<> class ViewToVarArg { public: typedef BoolVarArgs argtype; }; /** * \brief Class for pair of index and view * */ template class IdxView { public: int idx; View view; static IdxView* allocate(Space&, int); }; template forceinline IdxView* IdxView::allocate(Space& home, int n) { return home.alloc >(n); } template IdxViewArray::IdxViewArray(void) : xs(NULL), n(0) {} template IdxViewArray::IdxViewArray(const IdxViewArray& a) { n = a.n; xs = a.xs; } template IdxViewArray::IdxViewArray(Space& home, const typename ViewToVarArg::argtype& xa) : xs(NULL) { n = xa.size(); if (n>0) { xs = IdxView::allocate(home, n); for (int i = n; i--; ) { xs[i].idx = i; xs[i].view = xa[i]; } } } template IdxViewArray::IdxViewArray(Space& home, int n0) : xs(NULL) { n = n0; if (n>0) { xs = IdxView::allocate(home, n); } } template forceinline int IdxViewArray::size(void) const { return n; } template forceinline void IdxViewArray::size(int n0) { n = n0; } template forceinline IdxView& IdxViewArray::operator [](int i) { assert((i >= 0) && (i < size())); return xs[i]; } template forceinline const IdxView& IdxViewArray::operator [](int i) const { assert((i >= 0) && (i < size())); return xs[i]; } template void IdxViewArray::subscribe(Space& home, Propagator& p, PropCond pc, bool process) { for (int i = n; i--; ) xs[i].view.subscribe(home,p,pc,process); } template void IdxViewArray::cancel(Space& home, Propagator& p, PropCond pc) { for (int i = n; i--; ) xs[i].view.cancel(home,p,pc); } template void IdxViewArray::update(Space& home, bool share, IdxViewArray& a) { n = a.size(); if (n>0) { xs = IdxView::allocate(home,n); for (int i=n; i--; ) { xs[i].idx = a[i].idx; xs[i].view.update(home,share,a[i].view); } } } /** * \brief Class for bounds-equality test * */ template class RelTestBnd { public: RelTest operator ()(VA,VC); }; /** * \brief Class for bounds-equality test (specialized) * */ template class RelTestBnd { public: RelTest operator ()(VA,ConstIntView); }; /** * \brief Class for domain-equality test * */ template class RelTestDom { public: RelTest operator ()(VA,VC); }; /** * \brief Class for domain-equality test (specialized) * */ template class RelTestDom { public: RelTest operator ()(VA,ConstIntView); }; template forceinline RelTest RelTestBnd::operator ()(VA x, VC y) { return rtest_eq_bnd(x,y); } template forceinline RelTest RelTestBnd::operator ()(VA x, ConstIntView y) { return rtest_eq_bnd(x,y.val()); } template forceinline RelTest RelTestDom::operator ()(VA x, VC y) { return rtest_eq_dom(x,y); } template forceinline RelTest RelTestDom::operator ()(VA x, ConstIntView y) { return rtest_eq_dom(x,y.val()); } /* * Base class * */ template View::View(Home home, IdxViewArray& iv0, VB y0, VC y1) : Propagator(home), iv(iv0), x0(y0), x1(y1) { x0.subscribe(home,*this,PC_INT_DOM); x1.subscribe(home,*this,pc_ac); iv.subscribe(home,*this,pc_ac); } template forceinline View::View(Space& home, bool share, View& p) : Propagator(home,share,p) { x0.update(home,share,p.x0); x1.update(home,share,p.x1); iv.update(home,share,p.iv); } template PropCost View::cost(const Space&, const ModEventDelta&) const { // This is required for subscribing to variables in the // above constructor, but this is then the only time this // virtual function is ever used! return PropCost::linear(PropCost::LO,iv.size()+2); } template forceinline size_t View::dispose(Space& home) { x0.cancel(home,*this,PC_INT_DOM); x1.cancel(home,*this,pc_ac); iv.cancel(home,*this,pc_ac); (void) Propagator::dispose(home); return sizeof(*this); } /** * \brief Value iterator for indices in index-view map * */ template class IterIdxView { private: const IdxView *cur, *end; public: IterIdxView(void); IterIdxView(const IdxView*, const IdxView*); void init(const IdxView*, const IdxView*); bool operator ()(void) const; void operator ++(void); int val(void) const; }; template forceinline IterIdxView::IterIdxView(void) {} template forceinline IterIdxView::IterIdxView(const IdxView* b, const IdxView* e) : cur(b), end(e) {} template forceinline void IterIdxView::init(const IdxView* b, const IdxView* e) { cur=b; end=e; } template forceinline bool IterIdxView::operator ()(void) const { return cur < end; } template forceinline void IterIdxView::operator ++(void) { cur++; } template forceinline int IterIdxView::val(void) const { return cur->idx; } /* * Generic scanning: does all but computing new domain for result * (which is specific to bounds/domain version) * */ template ExecStatus scan(Space& home, IdxViewArray& iv, VB x0, VC x1, Propagator& p, RelTest rt) { assert(iv.size() > 1); /* * Prunes pairs of index, variable * - checks for idx value removed * - checks for disequal variables * */ ViewValues vx0(x0); int i = 0; int j = 0; while (vx0() && (i < iv.size())) { if (iv[i].idx < vx0.val()) { iv[i].view.cancel(home,p,pc_ac); ++i; } else if (iv[i].idx > vx0.val()) { ++vx0; } else { assert(iv[i].idx == vx0.val()); switch (rt(iv[i].view,x1)) { case RT_FALSE: iv[i].view.cancel(home,p,pc_ac); break; case RT_TRUE: case RT_MAYBE: iv[j++] = iv[i]; break; default: GECODE_NEVER; } ++vx0; ++i; } } while (i < iv.size()) iv[i++].view.cancel(home,p,pc_ac); bool adjust = (j v(&iv[0],&iv[0]+iv.size()); GECODE_ME_CHECK(x0.narrow_v(home,v,false)); assert(x0.size() == static_cast(iv.size())); } return ES_OK; } /* * Bounds consistent propagator * */ template forceinline ViewBnd::ViewBnd(Home home, IdxViewArray& iv, VB x0, VC x1) : View(home,iv,x0,x1) {} template ExecStatus ViewBnd::post(Home home, IdxViewArray& iv, VB x0, VC x1) { GECODE_ME_CHECK(x0.gq(home,0)); GECODE_ME_CHECK(x0.le(home,iv.size())); if (x0.assigned()) { (void) new (home) Rel::EqBnd(home,iv[x0.val()].view,x1); return ES_OK; } else { assert(iv.size()>1); (void) new (home) ViewBnd(home,iv,x0,x1); } return ES_OK; } template forceinline ViewBnd::ViewBnd(Space& home, bool share, ViewBnd& p) : View(home,share,p) {} template Actor* ViewBnd::copy(Space& home, bool share) { return new (home) ViewBnd(home,share,*this); } template ExecStatus ViewBnd::propagate(Space& home, const ModEventDelta&) { assert(iv.size() > 1); RelTestBnd rt; GECODE_ES_CHECK((scan > (home,iv,x0,x1,*this,rt))); if (iv.size() == 1) { ExecStatus es = home.ES_SUBSUMED(*this); (void) new (home) Rel::EqBnd(home,iv[0].view,x1); return es; } assert(iv.size() > 1); // Compute new result int min = iv[iv.size()-1].view.min(); int max = iv[iv.size()-1].view.max(); for (int i=iv.size()-1; i--; ) { min = std::min(iv[i].view.min(),min); max = std::max(iv[i].view.max(),max); } ExecStatus es = shared(x0,x1) ? ES_NOFIX : ES_FIX; { ModEvent me = x1.lq(home,max); if (me_failed(me)) return ES_FAILED; if (me_modified(me) && (x1.max() != max)) es = ES_NOFIX; } { ModEvent me = x1.gq(home,min); if (me_failed(me)) return ES_FAILED; if (me_modified(me) && (x1.min() != min)) es = ES_NOFIX; } return (x1.assigned() && (min == max)) ? home.ES_SUBSUMED(*this) : es; } /* * Domain consistent propagator * */ template forceinline ViewDom::ViewDom(Home home, IdxViewArray& iv, VB x0, VC x1) : View(home,iv,x0,x1) {} template ExecStatus ViewDom::post(Home home, IdxViewArray& iv, VB x0, VC x1){ GECODE_ME_CHECK(x0.gq(home,0)); GECODE_ME_CHECK(x0.le(home,iv.size())); if (x0.assigned()) { (void) new (home) Rel::EqDom(home,iv[x0.val()].view,x1); return ES_OK; } else { assert(iv.size()>1); (void) new (home) ViewDom(home,iv,x0,x1); } return ES_OK; } template forceinline ViewDom::ViewDom(Space& home, bool share, ViewDom& p) : View(home,share,p) {} template Actor* ViewDom::copy(Space& home, bool share) { return new (home) ViewDom(home,share,*this); } template PropCost ViewDom::cost(const Space&, const ModEventDelta& med) const { return PropCost::linear((VA::me(med) != ME_INT_DOM) ? PropCost::LO : PropCost::HI, iv.size()+2); } template ExecStatus ViewDom::propagate(Space& home, const ModEventDelta& med) { assert(iv.size() > 1); if (VA::me(med) != ME_INT_DOM) { RelTestBnd rt; GECODE_ES_CHECK((scan > (home,iv,x0,x1,*this,rt))); if (iv.size() == 1) { ExecStatus es = home.ES_SUBSUMED(*this); (void) new (home) Rel::EqDom(home,iv[0].view,x1); return es; } // Compute new result int min = iv[iv.size()-1].view.min(); int max = iv[iv.size()-1].view.max(); for (int i=iv.size()-1; i--; ) { min = std::min(iv[i].view.min(),min); max = std::max(iv[i].view.max(),max); } GECODE_ME_CHECK(x1.lq(home,max)); GECODE_ME_CHECK(x1.gq(home,min)); return (x1.assigned() && (min == max)) ? home.ES_SUBSUMED(*this) : home.ES_NOFIX_PARTIAL(*this,VA::med(ME_INT_DOM)); } RelTestDom rt; GECODE_ES_CHECK((scan > (home,iv,x0,x1,*this,rt))); if (iv.size() == 1) { ExecStatus es = home.ES_SUBSUMED(*this); (void) new (home) Rel::EqDom(home,iv[0].view,x1); return es; } assert(iv.size() > 1); Region r(home); ViewRanges* i_view = r.alloc >(iv.size()); for (int i = iv.size(); i--; ) i_view[i].init(iv[i].view); Iter::Ranges::NaryUnion i_val(r, i_view, iv.size()); ModEvent me = x1.inter_r(home,i_val); r.free >(i_view,iv.size()); GECODE_ME_CHECK(me); return (shared(x0,x1) || me_modified(me)) ? ES_NOFIX : ES_FIX; } }}} // STATISTICS: int-prop