/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Christian Schulte * * Copyright: * Christian Schulte, 2003 * * Last modified: * $Date: 2008-01-31 18:29:16 +0100 (Thu, 31 Jan 2008) $ by $Author: tack $ * $Revision: 6017 $ * * 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 Linear { /* * Ternary linear propagators * */ template forceinline LinTer::LinTer(Space* home, A y0, B y1, C y2, Val c0) : Propagator(home), x0(y0), x1(y1), x2(y2), c(c0) { x0.subscribe(home,this,pc); x1.subscribe(home,this,pc); x2.subscribe(home,this,pc); } template forceinline LinTer::LinTer(Space* home, bool share, LinTer& p) : Propagator(home,share,p), c(p.c) { x0.update(home,share,p.x0); x1.update(home,share,p.x1); x2.update(home,share,p.x2); } template forceinline LinTer::LinTer(Space* home, bool share, Propagator& p, A y0, B y1, C y2, Val c0) : Propagator(home,share,p), c(c0) { x0.update(home,share,y0); x1.update(home,share,y1); x2.update(home,share,y2); } template PropCost LinTer::cost(ModEventDelta) const { return PC_TERNARY_LO; } template forceinline size_t LinTer::dispose(Space* home) { assert(!home->failed()); x0.cancel(home,this,pc); x1.cancel(home,this,pc); x2.cancel(home,this,pc); (void) Propagator::dispose(home); return sizeof(*this); } template Reflection::ActorSpec LinTer::spec(const Space* home, Reflection::VarMap& m, const Support::Symbol& ati) const { Reflection::ActorSpec s(ati); return s << x0.spec(home, m) << x1.spec(home, m) << x2.spec(home, m) << c; } /* * Equality propagator * */ template forceinline EqTer::EqTer(Space* home, A x0, B x1, C x2, Val c) : LinTer(home,x0,x1,x2,c) {} template ExecStatus EqTer::post(Space* home, A x0, B x1, C x2, Val c) { (void) new (home) EqTer(home,x0,x1,x2,c); return ES_OK; } template forceinline EqTer::EqTer(Space* home, bool share, EqTer& p) : LinTer(home,share,p) {} template forceinline EqTer::EqTer(Space* home, bool share, Propagator& p, A x0, B x1, C x2, Val c) : LinTer(home,share,p,x0,x1,x2,c) {} template Actor* EqTer::copy(Space* home, bool share) { return new (home) EqTer(home,share,*this); } template inline Support::Symbol EqTer::ati(void) { return Reflection::mangle("Gecode::Int::Linear::EqTer"); } template Reflection::ActorSpec EqTer::spec(const Space* home, Reflection::VarMap& m) const { return LinTer::spec(home, m, ati()); } template void EqTer::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(4); A x0(home, vars, spec[0]); B x1(home, vars, spec[1]); C x2(home, vars, spec[2]); Val c = spec[3]->toInt(); (void) new (home) EqTer(home, x0, x1, x2, c); } /// Describe which view has been modified how enum TerMod { TM_X0_MIN = 1<<0, TM_X0_MAX = 1<<1, TM_X1_MIN = 1<<2, TM_X1_MAX = 1<<3, TM_X2_MIN = 1<<4, TM_X2_MAX = 1<<5, TM_ALL = TM_X0_MIN|TM_X0_MAX|TM_X1_MIN|TM_X1_MAX|TM_X2_MIN|TM_X2_MAX }; #define GECODE_INT_PV(CASE,TELL,UPDATE) \ if (bm & (CASE)) { \ bm -= (CASE); ModEvent me = (TELL); \ if (me_failed(me)) return ES_FAILED; \ if (me_modified(me)) bm |= (UPDATE); \ } template ExecStatus EqTer::propagate(Space* home, ModEventDelta) { int bm = TM_ALL; do { GECODE_INT_PV(TM_X0_MIN, x0.gq(home,c-x1.max()-x2.max()), TM_X1_MAX | TM_X2_MAX); GECODE_INT_PV(TM_X1_MIN, x1.gq(home,c-x0.max()-x2.max()), TM_X0_MAX | TM_X2_MAX); GECODE_INT_PV(TM_X2_MIN, x2.gq(home,c-x0.max()-x1.max()), TM_X0_MAX | TM_X1_MAX); GECODE_INT_PV(TM_X0_MAX, x0.lq(home,c-x1.min()-x2.min()), TM_X1_MIN | TM_X2_MIN); GECODE_INT_PV(TM_X1_MAX, x1.lq(home,c-x0.min()-x2.min()), TM_X0_MIN | TM_X2_MIN); GECODE_INT_PV(TM_X2_MAX, x2.lq(home,c-x0.min()-x1.min()), TM_X0_MIN | TM_X1_MIN); } while (bm); return (x0.assigned() && x1.assigned()) ? ES_SUBSUMED(this,sizeof(*this)) : ES_FIX; } #undef GECODE_INT_PV /* * Disequality propagator * */ template forceinline NqTer::NqTer(Space* home, A x0, B x1, C x2, Val c) : LinTer(home,x0,x1,x2,c) {} template ExecStatus NqTer::post(Space* home, A x0, B x1, C x2, Val c) { (void) new (home) NqTer(home,x0,x1,x2,c); return ES_OK; } template forceinline NqTer::NqTer(Space* home, bool share, NqTer& p) : LinTer(home,share,p) {} template Actor* NqTer::copy(Space* home, bool share) { return new (home) NqTer(home,share,*this); } template inline Support::Symbol NqTer::ati(void) { return Reflection::mangle("Gecode::Int::Linear::NqTer"); } template Reflection::ActorSpec NqTer::spec(const Space* home, Reflection::VarMap& m) const { return LinTer::spec(home, m, ati()); } template void NqTer::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(4); A x0(home, vars, spec[0]); B x1(home, vars, spec[1]); C x2(home, vars, spec[2]); Val c = spec[3]->toInt(); (void) new (home) NqTer(home, x0, x1, x2, c); } template forceinline NqTer::NqTer(Space* home, bool share, Propagator& p, A x0, B x1, C x2, Val c) : LinTer(home,share,p,x0,x1,x2,c) {} template ExecStatus NqTer::propagate(Space* home, ModEventDelta) { if (x0.assigned() && x1.assigned()) { GECODE_ME_CHECK(x2.nq(home,c-x0.val()-x1.val())); return ES_SUBSUMED(this,home); } if (x0.assigned() && x2.assigned()) { GECODE_ME_CHECK(x1.nq(home,c-x0.val()-x2.val())); return ES_SUBSUMED(this,home); } if (x1.assigned() && x2.assigned()) { GECODE_ME_CHECK(x0.nq(home,c-x1.val()-x2.val())); return ES_SUBSUMED(this,home); } return ES_FIX; } /* * Inequality propagator * */ template forceinline LqTer::LqTer(Space* home, A x0, B x1, C x2, Val c) : LinTer(home,x0,x1,x2,c) {} template ExecStatus LqTer::post(Space* home, A x0, B x1, C x2, Val c) { (void) new (home) LqTer(home,x0,x1,x2,c); return ES_OK; } template forceinline LqTer::LqTer(Space* home, bool share, LqTer& p) : LinTer(home,share,p) {} template Actor* LqTer::copy(Space* home, bool share) { return new (home) LqTer(home,share,*this); } template inline Support::Symbol LqTer::ati(void) { return Reflection::mangle("Gecode::Int::Linear::LqTer"); } template Reflection::ActorSpec LqTer::spec(const Space* home, Reflection::VarMap& m) const { return LinTer::spec(home, m, ati()); } template void LqTer::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(4); A x0(home, vars, spec[0]); B x1(home, vars, spec[1]); C x2(home, vars, spec[2]); Val c = spec[3]->toInt(); (void) new (home) LqTer(home, x0, x1, x2, c); } template forceinline LqTer::LqTer(Space* home, bool share, Propagator& p, A x0, B x1, C x2, Val c) : LinTer(home,share,p,x0,x1,x2,c) {} template ExecStatus LqTer::propagate(Space* home, ModEventDelta) { GECODE_ME_CHECK(x0.lq(home,c-x1.min()-x2.min())); GECODE_ME_CHECK(x1.lq(home,c-x0.min()-x2.min())); GECODE_ME_CHECK(x2.lq(home,c-x0.min()-x1.min())); return (x0.max()+x1.max()+x2.max() <= c) ? ES_SUBSUMED(this,home) : ES_FIX; } }}} // STATISTICS: int-prop