/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Christian Schulte * * Copyright: * Christian Schulte, 2004 * * Last modified: * $Date: 2008-07-11 10:49:55 +0200 (Fri, 11 Jul 2008) $ by $Author: tack $ * $Revision: 7348 $ * * 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 { /* * Binary bounds consistent equality * */ template forceinline EqBnd::EqBnd(Space* home, View0 x0, View1 x1) : MixBinaryPropagator(home,x0,x1) {} template ExecStatus EqBnd::post(Space* home, View0 x0, View1 x1){ if (x0.assigned()) { GECODE_ME_CHECK(x1.eq(home,x0.val())); } else if (x1.assigned()) { GECODE_ME_CHECK(x0.eq(home,x1.val())); } else if (!same(x0,x1)) { GECODE_ME_CHECK(x0.lq(home,x1.max())); GECODE_ME_CHECK(x1.lq(home,x0.max())); GECODE_ME_CHECK(x0.gq(home,x1.min())); GECODE_ME_CHECK(x1.gq(home,x0.min())); (void) new (home) EqBnd(home,x0,x1); } return ES_OK; } template forceinline EqBnd::EqBnd(Space* home, bool share, EqBnd& p) : MixBinaryPropagator(home,share,p) {} template forceinline EqBnd::EqBnd(Space* home, bool share, Propagator& p, View0 x0, View1 x1) : MixBinaryPropagator(home,share,p, x0,x1) {} template Actor* EqBnd::copy(Space* home, bool share) { return new (home) EqBnd(home,share,*this); } template inline Support::Symbol EqBnd::ati(void) { return Reflection::mangle("Gecode::Int::Rel::EqBnd"); } template Reflection::ActorSpec EqBnd::spec(const Space* home, Reflection::VarMap& m) const { return MixBinaryPropagator ::spec(home, m, ati()); } template void EqBnd::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(2); View0 x0(home, vars, spec[0]); View1 x1(home, vars, spec[1]); (void) new (home) EqBnd(home, x0, x1); } template ExecStatus EqBnd::propagate(Space* home, ModEventDelta) { if (x0.assigned()) { GECODE_ME_CHECK(x1.eq(home,x0.val())); } else if (x1.assigned()) { GECODE_ME_CHECK(x0.eq(home,x1.val())); } else { do { GECODE_ME_CHECK(x0.gq(home,x1.min())); GECODE_ME_CHECK(x1.gq(home,x0.min())); } while (x0.min() != x1.min()); do { GECODE_ME_CHECK(x0.lq(home,x1.max())); GECODE_ME_CHECK(x1.lq(home,x0.max())); } while (x0.max() != x1.max()); if (!x0.assigned()) return ES_FIX; } assert(x0.assigned() && x1.assigned()); return ES_SUBSUMED(this,sizeof(*this)); } /* * Binary domain consistent equality * */ template forceinline EqDom::EqDom(Space* home, View0 x0, View1 x1) : MixBinaryPropagator(home,x0,x1) {} template ExecStatus EqDom::post(Space* home, View0 x0, View1 x1){ if (x0.assigned()) { GECODE_ME_CHECK(x1.eq(home,x0.val())); } else if (x1.assigned()) { GECODE_ME_CHECK(x0.eq(home,x1.val())); } else if (!same(x0,x1)) { GECODE_ME_CHECK(x0.lq(home,x1.max())); GECODE_ME_CHECK(x1.lq(home,x0.max())); GECODE_ME_CHECK(x0.gq(home,x1.min())); GECODE_ME_CHECK(x1.gq(home,x0.min())); (void) new (home) EqDom(home,x0,x1); } return ES_OK; } template forceinline EqDom::EqDom(Space* home, bool share, EqDom& p) : MixBinaryPropagator(home,share,p) {} template forceinline EqDom::EqDom(Space* home, bool share, Propagator& p, View0 x0, View1 x1) : MixBinaryPropagator(home,share,p, x0,x1) {} template Actor* EqDom::copy(Space* home, bool share) { return new (home) EqDom(home,share,*this); } template inline Support::Symbol EqDom::ati(void) { return Reflection::mangle("Gecode::Int::Rel::EqDom"); } template Reflection::ActorSpec EqDom::spec(const Space* home, Reflection::VarMap& m) const { return MixBinaryPropagator ::spec(home, m, ati()); } template void EqDom::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(2); View0 x0(home, vars, spec[0]); View1 x1(home, vars, spec[1]); (void) new (home) EqDom(home, x0, x1); } template PropCost EqDom::cost(ModEventDelta med) const { if ((View0::me(med) == ME_INT_VAL) || (View1::me(med) == ME_INT_VAL)) return PC_UNARY_LO; if ((View0::me(med) == ME_INT_DOM) || (View1::me(med) == ME_INT_DOM)) return PC_BINARY_HI; return PC_BINARY_LO; } template ExecStatus EqDom::propagate(Space* home, ModEventDelta med) { if (x0.assigned()) { GECODE_ME_CHECK(x1.eq(home,x0.val())); return ES_SUBSUMED(this,sizeof(*this)); } if (x1.assigned()) { GECODE_ME_CHECK(x0.eq(home,x1.val())); return ES_SUBSUMED(this,sizeof(*this)); } if ((View0::me(med) != ME_INT_DOM) && (View1::me(med) != ME_INT_DOM)) { do { GECODE_ME_CHECK(x0.gq(home,x1.min())); GECODE_ME_CHECK(x1.gq(home,x0.min())); } while (x0.min() != x1.min()); do { GECODE_ME_CHECK(x0.lq(home,x1.max())); GECODE_ME_CHECK(x1.lq(home,x0.max())); } while (x0.max() != x1.max()); if (x0.assigned()) return ES_SUBSUMED(this,sizeof(*this)); if (x0.range() && x1.range()) return ES_FIX; return ES_FIX_PARTIAL(this,View0::med(ME_INT_DOM)); } ViewRanges r0(x0); GECODE_ME_CHECK(x1.inter_r(home,r0,false)); ViewRanges r1(x1); GECODE_ME_CHECK(x0.narrow_r(home,r1,false)); if (x0.assigned()) return ES_SUBSUMED(this,sizeof(*this)); return ES_FIX; } /* * Nary domain consistent equality * */ template forceinline NaryEqDom::NaryEqDom(Space* home, ViewArray& x) : NaryPropagator(home,x) {} template ExecStatus NaryEqDom::post(Space* home, ViewArray& x) { x.unique(); if (x.size() == 2) { return EqDom::post(home,x[0],x[1]); } else if (x.size() > 2) { int l = x[0].min(); int u = x[0].max(); for (int i=x.size(); i-- > 1; ) { l = std::max(l,x[i].min()); u = std::min(u,x[i].max()); } for (int i=x.size(); i--; ) { GECODE_ME_CHECK(x[i].gq(home,l)); GECODE_ME_CHECK(x[i].lq(home,u)); } (void) new (home) NaryEqDom(home,x); } return ES_OK; } template forceinline NaryEqDom::NaryEqDom(Space* home, bool share, NaryEqDom& p) : NaryPropagator(home,share,p) {} template Actor* NaryEqDom::copy(Space* home, bool share) { return new (home) NaryEqDom(home,share,*this); } template inline Support::Symbol NaryEqDom::ati(void) { return Reflection::mangle("Gecode::Int::Rel::NaryEqDom"); } template Reflection::ActorSpec NaryEqDom::spec(const Space* home, Reflection::VarMap& m) const { return NaryPropagator ::spec(home, m, ati()); } template void NaryEqDom::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(1); ViewArray x(home, vars, spec[0]); (void) new (home) NaryEqDom(home, x); } template PropCost NaryEqDom::cost(ModEventDelta med) const { if (View::me(med) == ME_INT_VAL) return PC_UNARY_LO; if (View::me(med) == ME_INT_DOM) return cost_hi(x.size(),PC_LINEAR_HI); return cost_lo(x.size(),PC_LINEAR_LO); } template ExecStatus NaryEqDom::propagate(Space* home, ModEventDelta med) { assert(x.size() > 2); ModEvent me = View::me(med); if (me == ME_INT_VAL) { // One of the variables is assigned for (int i = 0; ; i++) if (x[i].assigned()) { int n = x[i].val(); x.move_lst(i); for (int j = x.size(); j--; ) GECODE_ME_CHECK(x[j].eq(home,n)); return ES_SUBSUMED(this,sizeof(*this)); } GECODE_NEVER; return ES_SUBSUMED(this,sizeof(*this)); } if (me == ME_INT_BND) { { // One of the mins has changed int mn = x[0].min(); restart_min: for (int i = x.size(); i--; ) { GECODE_ME_CHECK(x[i].gq(home,mn)); if (mn < x[i].min()) { mn = x[i].min(); goto restart_min; } } } { // One of the maxs has changed int mx = x[0].max(); restart_max: for (int i = x.size(); i--; ) { GECODE_ME_CHECK(x[i].lq(home,mx)); if (mx > x[i].max()) { mx = x[i].max(); goto restart_max; } } } if (x[0].assigned()) return ES_SUBSUMED(this,sizeof(*this)); return ES_FIX_PARTIAL(this,View::med(ME_INT_DOM)); } int n = x.size(); GECODE_AUTOARRAY(ViewRanges, i_x, n); for (int i = n; i--; ) { ViewRanges i_xi(x[i]); i_x[i] = i_xi; } Iter::Ranges::NaryInter > r(i_x,n); Iter::Ranges::Cache > > rc(r); if (!rc()) return ES_FAILED; ++rc; if (!rc()) { rc.reset(); for (int i = n; i--; ) { GECODE_ME_CHECK(x[i].gq(home,rc.min())); GECODE_ME_CHECK(x[i].lq(home,rc.max())); } } else { for (int i = n; i--; ) { rc.reset(); GECODE_ME_CHECK(x[i].narrow_r(home,rc,false)); } } return ES_FIX; } /* * Nary bound consistent equality * */ template forceinline NaryEqBnd::NaryEqBnd(Space* home, ViewArray& x) : NaryPropagator(home,x) {} template ExecStatus NaryEqBnd::post(Space* home, ViewArray& x) { if (x.size() == 2) { return EqBnd::post(home,x[0],x[1]); } else if (x.size() > 2) { int l = x[0].min(); int u = x[0].max(); for (int i=x.size(); i-- > 1; ) { l = std::max(l,x[i].min()); u = std::min(u,x[i].max()); } for (int i=x.size(); i--; ) { GECODE_ME_CHECK(x[i].gq(home,l)); GECODE_ME_CHECK(x[i].lq(home,u)); } (void) new (home) NaryEqBnd(home,x); } return ES_OK; } template forceinline NaryEqBnd::NaryEqBnd(Space* home, bool share, NaryEqBnd& p) : NaryPropagator(home,share,p) {} template Actor* NaryEqBnd::copy(Space* home, bool share) { return new (home) NaryEqBnd(home,share,*this); } template PropCost NaryEqBnd::cost(ModEventDelta med) const { if (View::me(med) == ME_INT_VAL) return PC_UNARY_LO; return cost_lo(x.size(),PC_LINEAR_LO); } template inline Support::Symbol NaryEqBnd::ati(void) { return Reflection::mangle("Gecode::Int::Rel::NaryEqBnd"); } template Reflection::ActorSpec NaryEqBnd::spec(const Space* home, Reflection::VarMap& m) const { return NaryPropagator ::spec(home, m, ati()); } template void NaryEqBnd::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(1); ViewArray x(home, vars, spec[0]); (void) new (home) NaryEqBnd(home, x); } template ExecStatus NaryEqBnd::propagate(Space* home, ModEventDelta med) { assert(x.size() > 2); if (View::me(med) == ME_INT_VAL) { // One of the variables is assigned for (int i = 0; ; i++) if (x[i].assigned()) { int n = x[i].val(); x.move_lst(i); for (int j = x.size(); j--; ) GECODE_ME_CHECK(x[j].eq(home,n)); return ES_SUBSUMED(this,sizeof(*this)); } GECODE_NEVER; return ES_SUBSUMED(this,sizeof(*this)); } int mn = x[0].min(); restart_min: for (int i = x.size(); i--; ) { GECODE_ME_CHECK(x[i].gq(home,mn)); if (mn < x[i].min()) { mn = x[i].min(); goto restart_min; } } int mx = x[0].max(); restart_max: for (int i = x.size(); i--; ) { GECODE_ME_CHECK(x[i].lq(home,mx)); if (mx > x[i].max()) { mx = x[i].max(); goto restart_max; } } return x[0].assigned() ? ES_SUBSUMED(this,sizeof(*this)) : ES_FIX; } /* * Reified domain consistent equality * */ template forceinline ReEqDom::ReEqDom(Space* home, View x0, View x1, CtrlView b) : ReBinaryPropagator(home,x0,x1,b) {} template ExecStatus ReEqDom::post(Space* home, View x0, View x1, CtrlView b) { if (b.one()) return EqDom::post(home,x0,x1); if (b.zero()) return Nq::post(home,x0,x1); if (!same(x0,x1)) { (void) new (home) ReEqDom(home,x0,x1,b); } else { GECODE_ME_CHECK(b.one(home)); } return ES_OK; } template forceinline ReEqDom::ReEqDom(Space* home, bool share, ReEqDom& p) : ReBinaryPropagator(home,share,p) {} template Actor* ReEqDom::copy(Space* home, bool share) { return new (home) ReEqDom(home,share,*this); } template inline Support::Symbol ReEqDom::ati(void) { return Reflection::mangle("Gecode::Int::Rel::ReEqDom"); } template Reflection::ActorSpec ReEqDom::spec(const Space* home, Reflection::VarMap& m) const { return ReBinaryPropagator ::spec(home, m, ati()); } template void ReEqDom::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(3); View x0(home, vars, spec[0]); View x1(home, vars, spec[1]); CtrlView b(home, vars, spec[2]); (void) new (home) ReEqDom(home, x0, x1, b); } template ExecStatus ReEqDom::propagate(Space* home, ModEventDelta) { if (b.one()) GECODE_REWRITE(this,(EqDom::post(home,x0,x1))); if (b.zero()) GECODE_REWRITE(this,Nq::post(home,x0,x1)); switch (rtest_eq_dom(x0,x1)) { case RT_TRUE: GECODE_ME_CHECK(b.one_none(home)); return ES_SUBSUMED(this,home); case RT_FALSE: GECODE_ME_CHECK(b.zero_none(home)); return ES_SUBSUMED(this,home); case RT_MAYBE: break; default: GECODE_NEVER; } return ES_FIX; } /* * Reified bounds consistent equality * */ template forceinline ReEqBnd::ReEqBnd(Space* home, View x0, View x1, CtrlView b) : ReBinaryPropagator(home,x0,x1,b) {} template ExecStatus ReEqBnd::post(Space* home, View x0, View x1, CtrlView b){ if (b.one()) return EqBnd::post(home,x0,x1); if (b.zero()) return Nq::post(home,x0,x1); if (!same(x0,x1)) { (void) new (home) ReEqBnd(home,x0,x1,b); } else { GECODE_ME_CHECK(b.one(home)); } return ES_OK; } template forceinline ReEqBnd::ReEqBnd(Space* home, bool share, ReEqBnd& p) : ReBinaryPropagator(home,share,p) {} template Actor* ReEqBnd::copy(Space* home, bool share) { return new (home) ReEqBnd(home,share,*this); } template inline Support::Symbol ReEqBnd::ati(void) { return Reflection::mangle("Gecode::Int::Rel::ReEqBnd"); } template Reflection::ActorSpec ReEqBnd::spec(const Space* home, Reflection::VarMap& m) const { return ReBinaryPropagator ::spec(home, m, ati()); } template void ReEqBnd::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(3); View x0(home, vars, spec[0]); View x1(home, vars, spec[1]); CtrlView b(home, vars, spec[2]); (void) new (home) ReEqBnd(home, x0, x1, b); } template ExecStatus ReEqBnd::propagate(Space* home, ModEventDelta) { if (b.one()) GECODE_REWRITE(this,(EqBnd::post(home,x0,x1))); if (b.zero()) GECODE_REWRITE(this,Nq::post(home,x0,x1)); switch (rtest_eq_bnd(x0,x1)) { case RT_TRUE: GECODE_ME_CHECK(b.one_none(home)); return ES_SUBSUMED(this,home); case RT_FALSE: GECODE_ME_CHECK(b.zero_none(home)); return ES_SUBSUMED(this,home); case RT_MAYBE: break; default: GECODE_NEVER; } return ES_FIX; } /* * Reified domain consistent equality (one variable) * */ template forceinline ReEqDomInt::ReEqDomInt (Space* home, View x, int c0, CtrlView b) : ReUnaryPropagator(home,x,b), c(c0) {} template ExecStatus ReEqDomInt::post(Space* home, View x, int c, CtrlView b) { if (b.one()) { GECODE_ME_CHECK(x.eq(home,c)); } else if (b.zero()) { GECODE_ME_CHECK(x.nq(home,c)); } else if (x.assigned()) { assert(b.none()); if (x.val() == c) { GECODE_ME_CHECK(b.one_none(home)); } else { GECODE_ME_CHECK(b.zero_none(home)); } } else { (void) new (home) ReEqDomInt(home,x,c,b); } return ES_OK; } template forceinline ReEqDomInt::ReEqDomInt(Space* home, bool share, ReEqDomInt& p) : ReUnaryPropagator(home,share,p), c(p.c) {} template Actor* ReEqDomInt::copy(Space* home, bool share) { return new (home) ReEqDomInt(home,share,*this); } template inline Support::Symbol ReEqDomInt::ati(void) { return Reflection::mangle("Gecode::Int::Rel::ReEqDomInt"); } template Reflection::ActorSpec ReEqDomInt::spec(const Space* home, Reflection::VarMap& m) const { return ReUnaryPropagator ::spec(home, m, ati()) << c; } template void ReEqDomInt::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(3); View x0(home, vars, spec[0]); CtrlView b(home, vars, spec[1]); int c = spec[2]->toInt(); (void) new (home) ReEqDomInt(home, x0, c, b); } template ExecStatus ReEqDomInt::propagate(Space* home, ModEventDelta) { if (b.one()) { GECODE_ME_CHECK(x0.eq(home,c)); assert(x0.assigned()); goto subsumed; } if (b.zero()) { GECODE_ME_CHECK(x0.nq(home,c)); x0.cancel(home,this,PC_INT_DOM); goto subsumed; } switch (rtest_eq_dom(x0,c)) { case RT_TRUE: GECODE_ME_CHECK(b.one_none(home)); assert(x0.assigned()); goto subsumed; case RT_FALSE: GECODE_ME_CHECK(b.zero_none(home)); x0.cancel(home,this,PC_INT_DOM); goto subsumed; case RT_MAYBE: break; default: GECODE_NEVER; } return ES_FIX; subsumed: return ES_SUBSUMED(this,sizeof(*this)); } /* * Reified bounds consistent equality (one variable) * */ template forceinline ReEqBndInt::ReEqBndInt (Space* home, View x, int c0, CtrlView b) : ReUnaryPropagator(home,x,b), c(c0) {} template ExecStatus ReEqBndInt::post(Space* home, View x, int c, CtrlView b) { if (b.one()) { GECODE_ME_CHECK(x.eq(home,c)); } else if (b.zero()) { GECODE_ME_CHECK(x.nq(home,c)); } else if (x.assigned()) { assert(b.none()); if (x.val() == c) { GECODE_ME_CHECK(b.one_none(home)); } else { GECODE_ME_CHECK(b.zero_none(home)); } } else { (void) new (home) ReEqBndInt(home,x,c,b); } return ES_OK; } template forceinline ReEqBndInt::ReEqBndInt(Space* home, bool share, ReEqBndInt& p) : ReUnaryPropagator(home,share,p), c(p.c) {} template Actor* ReEqBndInt::copy(Space* home, bool share) { return new (home) ReEqBndInt(home,share,*this); } template inline Support::Symbol ReEqBndInt::ati(void) { return Reflection::mangle("Gecode::Int::Rel::ReEqBndInt"); } template Reflection::ActorSpec ReEqBndInt::spec(const Space* home, Reflection::VarMap& m) const { return ReUnaryPropagator ::spec(home, m, ati()) << c; } template void ReEqBndInt::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(3); View x0(home, vars, spec[0]); CtrlView b(home, vars, spec[1]); int c = spec[2]->toInt(); (void) new (home) ReEqBndInt(home, x0, c, b); } template ExecStatus ReEqBndInt::propagate(Space* home, ModEventDelta) { if (b.one()) { GECODE_ME_CHECK(x0.eq(home,c)); assert(x0.assigned()); goto subsumed; } if (b.zero()) { GECODE_ME_CHECK(x0.nq(home,c)); x0.cancel(home,this,PC_INT_BND); goto subsumed; } switch (rtest_eq_bnd(x0,c)) { case RT_TRUE: GECODE_ME_CHECK(b.one_none(home)); assert(x0.assigned()); goto subsumed; case RT_FALSE: GECODE_ME_CHECK(b.zero_none(home)); x0.cancel(home,this,PC_INT_BND); goto subsumed; case RT_MAYBE: break; default: GECODE_NEVER; } return ES_FIX; subsumed: return ES_SUBSUMED(this,sizeof(*this)); } }}} // STATISTICS: int-prop