/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Christian Schulte * Gabor Szokoli * * Copyright: * Christian Schulte, 2003 * Gabor Szokoli, 2003 * * Last modified: * $Date: 2011-07-14 02:58:53 +1000 (Thu, 14 Jul 2011) $ by $Author: tack $ * $Revision: 12196 $ * * 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 Int { namespace Rel { /* * Less or equal propagator * */ template forceinline Lq::Lq(Home home, View x0, View x1) : BinaryPropagator(home,x0,x1) {} template ExecStatus Lq::post(Home home, View x0, View x1) { GECODE_ME_CHECK(x0.lq(home,x1.max())); GECODE_ME_CHECK(x1.gq(home,x0.min())); if (!same(x0,x1) && (x0.max() > x1.min())) (void) new (home) Lq(home,x0,x1); return ES_OK; } template forceinline Lq::Lq(Space& home, bool share, Lq& p) : BinaryPropagator(home,share,p) {} template Actor* Lq::copy(Space& home, bool share) { return new (home) Lq(home,share,*this); } template ExecStatus Lq::propagate(Space& home, const ModEventDelta&) { GECODE_ME_CHECK(x0.lq(home,x1.max())); GECODE_ME_CHECK(x1.gq(home,x0.min())); return (x0.max() <= x1.min()) ? home.ES_SUBSUMED(*this) : ES_FIX; } /* * Less propagator * */ template forceinline Le::Le(Home home, View x0, View x1) : BinaryPropagator(home,x0,x1) {} template ExecStatus Le::post(Home home, View x0, View x1) { if (same(x0,x1)) return ES_FAILED; GECODE_ME_CHECK(x0.le(home,x1.max())); GECODE_ME_CHECK(x1.gr(home,x0.min())); if (x0.max() >= x1.min()) (void) new (home) Le(home,x0,x1); return ES_OK; } template forceinline Le::Le(Space& home, bool share, Le& p) : BinaryPropagator(home,share,p) {} template Actor* Le::copy(Space& home, bool share) { return new (home) Le(home,share,*this); } template ExecStatus Le::propagate(Space& home, const ModEventDelta&) { GECODE_ME_CHECK(x0.le(home,x1.max())); GECODE_ME_CHECK(x1.gr(home,x0.min())); return (x0.max() < x1.min()) ? home.ES_SUBSUMED(*this) : ES_FIX; } /* * Nary less and less or equal propagator * */ template forceinline NaryLqLe::Index::Index(Space& home, Propagator& p, Council& c, int i0) : Advisor(home,p,c), i(i0) {} template forceinline NaryLqLe::Index::Index(Space& home, bool share, Index& a) : Advisor(home,share,a), i(a.i) {} template forceinline NaryLqLe::Pos::Pos(int p0, Pos* n) : FreeList(n), p(p0) {} template forceinline typename NaryLqLe::Pos* NaryLqLe::Pos::next(void) const { return static_cast(FreeList::next()); } template forceinline void NaryLqLe::Pos::operator delete(void*) {} template forceinline void NaryLqLe::Pos::operator delete(void*, Space&) { GECODE_NEVER; } template forceinline void* NaryLqLe::Pos::operator new(size_t, Space& home) { return home.fl_alloc(); } template forceinline void NaryLqLe::Pos::dispose(Space& home) { home.fl_dispose(this,this); } template forceinline bool NaryLqLe::empty(void) const { return pos == NULL; } template forceinline void NaryLqLe::push(Space& home, int p) { // Try to avoid entering same position twice if ((pos != NULL) && (pos->p == p)) return; pos = new (home) Pos(p,pos); } template forceinline int NaryLqLe::pop(Space& home) { Pos* t = pos; int p = t->p; pos = pos->next(); t->dispose(home); return p; } template forceinline NaryLqLe::NaryLqLe(Home home, ViewArray& x) : NaryPropagator(home,x), c(home), pos(NULL), run(false), n_subsumed(0) { for (int i=x.size(); i--; ) x[i].subscribe(home, *new (home) Index(home,*this,c,i)); } template ExecStatus NaryLqLe::post(Home home, ViewArray& x) { assert((o == 0) || (o == 1)); // Check for sharing if (x.same(home)) { if (o == 1) return ES_FAILED; /* * Eliminate sharing: if a view occurs twice, all views in between * must be equal. */ int n = x.size(); for (int i=0; ii; j--) if (same(x[i],x[j])) { if (i+1 != j) { // Create equality propagator for elements i+1 ... j ViewArray y(home,j-i); for (int k=j-i; k--; ) y[k] = x[i+1+k]; GECODE_ES_CHECK(NaryEqBnd::post(home,y)); } for (int k=0; k 0) && (x[i-1].max()+o <= x[i].min())) i--; x.drop_lst(i); } // Eliminate in the middle if (x.size() > 1) { int j=1; for (int i=1; i+1 x[i].min()) || (x[i].max()+o > x[i+1].min())) x[j++]=x[i]; x[j++]=x[x.size()-1]; x.size(j); } } if (x.size() == 2) { if (o == 0) return Lq::post(home,x[0],x[1]); else return Le::post(home,x[0],x[1]); } else if (x.size() >= 2) { (void) new (home) NaryLqLe(home,x); } return ES_OK; } template forceinline NaryLqLe::NaryLqLe(Space& home, bool share, NaryLqLe& p) : NaryPropagator(home,share,p), pos(NULL), run(false), n_subsumed(p.n_subsumed) { assert(p.pos == NULL); c.update(home, share, p.c); } template Actor* NaryLqLe::copy(Space& home, bool share) { if (n_subsumed > n_threshold) { Region r(home); // Record for which views there is an advisor Support::BitSet a(r,static_cast(x.size())); for (Advisors as(c); as(); ++as) a.set(static_cast(as.advisor().i)); // Compact view array and compute map for advisors int* m = r.alloc(x.size()); int j=0; for (int i=0; i(i))) { m[i] = j; x[j++] = x[i]; } x.size(j); // Remap advisors for (Advisors as(c); as(); ++as) as.advisor().i = m[as.advisor().i]; n_subsumed = 0; } return new (home) NaryLqLe(home,share,*this); } template PropCost NaryLqLe::cost(const Space&, const ModEventDelta&) const { return PropCost::binary(PropCost::HI); } template forceinline size_t NaryLqLe::dispose(Space& home) { for (Advisors as(c); as(); ++as) x[as.advisor().i].cancel(home,as.advisor()); c.dispose(home); while (!empty()) (void) pop(home); (void) NaryPropagator::dispose(home); return sizeof(*this); } template ExecStatus NaryLqLe::advise(Space& home, Advisor& _a, const Delta& d) { Index& a = static_cast(_a); const int i = a.i; switch (View::modevent(d)) { case ME_INT_VAL: a.dispose(home,c); n_subsumed++; break; case ME_INT_BND: if (((i == 0) || (x[i-1].max()+o <= x[i].min())) && ((i == x.size()-1) || (x[i].max()+o <= x[i+1].min()))) { x[i].cancel(home,a); a.dispose(home,c); n_subsumed++; return (run || (n_subsumed + 1 < x.size())) ? ES_FIX : ES_NOFIX; } break; default: return ES_FIX; } if (run) return ES_FIX; if (((i < x.size()-1) && (x[i+1].min() < x[i].min()+o)) || ((i > 0) && (x[i-1].max() > x[i].max()-o))) { push(home,i); return ES_NOFIX; } return (n_subsumed+1 >= x.size()) ? ES_NOFIX : ES_FIX; } template ExecStatus NaryLqLe::propagate(Space& home, const ModEventDelta&) { run = true; int n = x.size(); while (!empty()) { int p = pop(home); for (int i=p; i0; i--) { ModEvent me = x[i-1].lq(home,x[i].max()-o); if (me_failed(me)) return ES_FAILED; if (!me_modified(me)) break; } } #ifdef GECODE_AUDIT for (int i=0; i0; i--) assert(!me_modified(x[i-1].lq(home,x[i].max()-o))); #endif if (n_subsumed+1 >= n) return home.ES_SUBSUMED(*this); run = false; return ES_FIX; } /* * Reified less or equal propagator * */ template forceinline ReLq::ReLq(Home home, View x0, View x1, CtrlView b) : ReBinaryPropagator(home,x0,x1,b) {} template ExecStatus ReLq::post(Home home, View x0, View x1, CtrlView b) { if (b.one()) return Lq::post(home,x0,x1); if (b.zero()) return Le::post(home,x1,x0); if (!same(x0,x1)) { switch (rtest_lq(x0,x1)) { case RT_TRUE: GECODE_ME_CHECK(b.one_none(home)); break; case RT_FALSE: GECODE_ME_CHECK(b.zero_none(home)); break; case RT_MAYBE: (void) new (home) ReLq(home,x0,x1,b); break; default: GECODE_NEVER; } } else { GECODE_ME_CHECK(b.one_none(home)); } return ES_OK; } template forceinline ReLq::ReLq(Space& home, bool share, ReLq& p) : ReBinaryPropagator(home,share,p) {} template Actor* ReLq::copy(Space& home, bool share) { return new (home) ReLq(home,share,*this); } template ExecStatus ReLq::propagate(Space& home, const ModEventDelta&) { if (b.one()) GECODE_REWRITE(*this,Lq::post(home(*this),x0,x1)); if (b.zero()) GECODE_REWRITE(*this,Le::post(home(*this),x1,x0)); switch (rtest_lq(x0,x1)) { case RT_TRUE: GECODE_ME_CHECK(b.one_none(home)); return home.ES_SUBSUMED(*this); case RT_FALSE: GECODE_ME_CHECK(b.zero_none(home)); return home.ES_SUBSUMED(*this); case RT_MAYBE: break; default: GECODE_NEVER; } return ES_FIX; } /* * Reified less or equal propagator involving one variable * */ template forceinline ReLqInt::ReLqInt(Home home, View x, int c0, CtrlView b) : ReUnaryPropagator(home,x,b), c(c0) {} template ExecStatus ReLqInt::post(Home home, View x, int c, CtrlView b) { if (b.one()) { GECODE_ME_CHECK(x.lq(home,c)); } else if (b.zero()) { GECODE_ME_CHECK(x.gr(home,c)); } else { switch (rtest_lq(x,c)) { case RT_TRUE: GECODE_ME_CHECK(b.one_none(home)); break; case RT_FALSE: GECODE_ME_CHECK(b.zero_none(home)); break; case RT_MAYBE: (void) new (home) ReLqInt(home,x,c,b); break; default: GECODE_NEVER; } } return ES_OK; } template forceinline ReLqInt::ReLqInt(Space& home, bool share, ReLqInt& p) : ReUnaryPropagator(home,share,p), c(p.c) {} template Actor* ReLqInt::copy(Space& home, bool share) { return new (home) ReLqInt(home,share,*this); } template ExecStatus ReLqInt::propagate(Space& home, const ModEventDelta&) { if (b.one()) { GECODE_ME_CHECK(x0.lq(home,c)); goto subsumed; } if (b.zero()) { GECODE_ME_CHECK(x0.gr(home,c)); goto subsumed; } switch (rtest_lq(x0,c)) { case RT_TRUE: GECODE_ME_CHECK(b.one_none(home)); goto subsumed; case RT_FALSE: GECODE_ME_CHECK(b.zero_none(home)); goto subsumed; case RT_MAYBE: break; default: GECODE_NEVER; } return ES_FIX; subsumed: return home.ES_SUBSUMED(*this); } }}} // STATISTICS: int-prop