/* * Main authors: * Christian Schulte * * Copyright: * Christian Schulte, 2004 * * Last modified: * $Date: 2006-08-04 16:03:26 +0200 (Fri, 04 Aug 2006) $ by $Author: schulte $ * $Revision: 3512 $ * * This file is part of Gecode, the generic constraint * development environment: * http://www.gecode.org * * See the file "LICENSE" for information on usage and * redistribution of this file, and for a * DISCLAIMER OF ALL WARRANTIES. * */ #include namespace Gecode { namespace Int { namespace Arithmetic { /* * Arithmetic help functions * */ /// Multiply \a a and \a b as double forceinline double m(int a, int b) { return static_cast(a)*static_cast(b); } /// Compute \f$\lfloor x/y\rfloor\f$ forceinline int f_d(int x, int y) { return static_cast(floor(static_cast(x) / static_cast(y))); } /// Compute \f$\lceil x/y\rceil\f$ forceinline int c_d(int x, int y) { return static_cast(ceil(static_cast(x) / static_cast(y))); } /// Test whether \a x is postive template forceinline bool p(const View& x) { return x.min() > 0; } /// Test whether \a x is negative template forceinline bool n(const View& x) { return x.max() < 0; } /// Test whether \a x is neither positive nor negative template forceinline bool x(const View& x) { return (x.min() <= 0) && (x.max() >= 0); } /* * Positive bounds-consistent squaring * */ template forceinline SquarePlus::SquarePlus(Space* home, VA y0, VB y1) : Propagator(home), x0(y0), x1(y1) { x0.subscribe(home,this,PC_INT_BND); x1.subscribe(home,this,PC_INT_BND); } template forceinline ExecStatus SquarePlus::post(Space* home, VA x0, VB x1) { (void) new (home) SquarePlus(home,x0,x1); return ES_OK; } template forceinline SquarePlus::SquarePlus(Space* home, bool share, SquarePlus& p) : Propagator(home,share,p) { x0.update(home,share,p.x0); x1.update(home,share,p.x1); } template Actor* SquarePlus::copy(Space* home, bool share) { return new (home) SquarePlus(home,share,*this); } template PropCost SquarePlus::cost(void) const { return PC_TERNARY_HI; } template ExecStatus SquarePlus::propagate(Space* home) { bool mod; do { mod = false; { ModEvent me = x0.lq(home,floor(sqrt(static_cast(x1.max())))); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } { ModEvent me = x0.gq(home,ceil(sqrt(static_cast(x1.min())))); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } { ModEvent me = x1.lq(home,x0.max()*x0.max()); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } { ModEvent me = x1.gq(home,x0.min()*x0.min()); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } } while (mod); return x0.assigned() ? ES_SUBSUMED : ES_FIX; } template size_t SquarePlus::dispose(Space* home) { assert(!home->failed()); x0.cancel(home,this,PC_INT_BND); x1.cancel(home,this,PC_INT_BND); (void) Propagator::dispose(home); return sizeof(*this); } /* * Bounds-consistent Square * */ template forceinline Square::Square(Space* home, View x0, View x1) : BinaryPropagator(home,x0,x1) {} template forceinline ExecStatus Square::post(Space* home, View x0, View x1) { GECODE_ME_CHECK(x1.gq(home,0)); GECODE_ME_CHECK(x0.lq(home,floor(sqrt(static_cast (Limits::Int::int_max))))); if (x0.min() >= 0) return SquarePlus::post(home,x0,x1); if (x0.max() <= 0) return SquarePlus::post(home,x0,x1); (void) new (home) Square(home,x0,x1); return ES_OK; } template forceinline Square::Square(Space* home, bool share, Square& p) : BinaryPropagator(home,share,p) {} template Actor* Square::copy(Space* home, bool share) { return new (home) Square(home,share,*this); } template PropCost Square::cost(void) const { return PC_BINARY_HI; } template ExecStatus Square::propagate(Space* home) { // x0 * x0 = x1 assert(x1.min() >= 0); if (x0.min() >= 0) return (SquarePlus::post(home,x0,x1) == ES_FAILED) ? ES_FAILED : ES_SUBSUMED; if (x0.max() <= 0) return (SquarePlus::post(home,x0,x1) == ES_FAILED) ? ES_FAILED : ES_SUBSUMED; GECODE_ME_CHECK(x1.lq(home,std::max(x0.min()*x0.min(), x0.max()*x0.max()))); int s = static_cast(floor(sqrt(static_cast(x1.max())))); GECODE_ME_CHECK(x0.gq(home,-s)); GECODE_ME_CHECK(x0.lq(home,s)); if (x0.assigned() && x1.assigned()) return (x0.val()*x0.val() == x1.val()) ? ES_SUBSUMED : ES_FAILED; return ES_NOFIX; } /* * Positive bounds-consistent multiplication * */ template inline MultPlus::MultPlus(Space* home, VA y0, VB y1, VC y2) : Propagator(home), x0(y0), x1(y1), x2(y2) { x0.subscribe(home,this,PC_INT_BND); x1.subscribe(home,this,PC_INT_BND); x2.subscribe(home,this,PC_INT_BND); } template inline ExecStatus MultPlus::post(Space* home, VA x0, VB x1, VC x2) { GECODE_ME_CHECK(x0.gr(home,0)); GECODE_ME_CHECK(x1.gr(home,0)); GECODE_ME_CHECK(x2.gr(home,0)); (void) new (home) MultPlus(home,x0,x1,x2); return ES_OK; } template forceinline MultPlus::MultPlus(Space* home, bool share, MultPlus& p) : Propagator(home,share,p) { x0.update(home,share,p.x0); x1.update(home,share,p.x1); x2.update(home,share,p.x2); } template Actor* MultPlus::copy(Space* home, bool share) { return new (home) MultPlus(home,share,*this); } template PropCost MultPlus::cost(void) const { return PC_TERNARY_HI; } template ExecStatus MultPlus::propagate(Space* home) { assert(p(x0) && p(x1) && p(x2)); bool mod; do { mod = false; { ModEvent me = x2.lq(home,m(x0.max(),x1.max())); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } { ModEvent me = x2.gq(home,m(x0.min(),x1.min())); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } { ModEvent me = x0.lq(home,f_d(x2.max(),x1.min())); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } { ModEvent me = x0.gq(home,c_d(x2.min(),x1.max())); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } { ModEvent me = x1.lq(home,f_d(x2.max(),x0.min())); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } { ModEvent me = x1.gq(home,c_d(x2.min(),x0.max())); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } } while (mod); return x0.assigned() && x1.assigned() ? ES_SUBSUMED : ES_FIX; } template size_t MultPlus::dispose(Space* home) { assert(!home->failed()); x0.cancel(home,this,PC_INT_BND); x1.cancel(home,this,PC_INT_BND); x2.cancel(home,this,PC_INT_BND); (void) Propagator::dispose(home); return sizeof(*this); } /* * Bounds-consistent multiplication * */ template forceinline Mult::Mult(Space* home, View x0, View x1, View x2) : TernaryPropagator(home,x0,x1,x2) {} template forceinline Mult::Mult(Space* home, bool share, Mult& p) : TernaryPropagator(home,share,p) {} template Actor* Mult::copy(Space* home, bool share) { return new (home) Mult(home,share,*this); } template PropCost Mult::cost(void) const { return PC_TERNARY_HI; } template ExecStatus Mult::propagate(Space* home) { if (p(x0)) { if (p(x1) || p(x2)) goto rewrite_ppp; if (n(x1) || n(x2)) goto rewrite_pnn; goto prop_pxx; } if (n(x0)) { if (n(x1) || p(x2)) goto rewrite_nnp; if (p(x1) || n(x2)) goto rewrite_npn; goto prop_nxx; } if (p(x1)) { if (p(x2)) goto rewrite_ppp; if (n(x2)) goto rewrite_npn; goto prop_xpx; } if (n(x1)) { if (p(x2)) goto rewrite_nnp; if (n(x2)) goto rewrite_pnn; goto prop_xnx; } assert(x(x0) && x(x1)); GECODE_ME_CHECK(x2.lq(home,std::max(m(x0.max(),x1.max()), m(x0.min(),x1.min())))); GECODE_ME_CHECK(x2.gq(home,std::min(m(x0.min(),x1.max()), m(x0.max(),x1.min())))); if (x0.assigned()) { assert((x0.val() == 0) && (x2.val() == 0)); return ES_SUBSUMED; } if (x1.assigned()) { assert((x1.val() == 0) && (x2.val() == 0)); return ES_SUBSUMED; } return ES_NOFIX; prop_xpx: std::swap(x0,x1); prop_pxx: assert(p(x0) && x(x1) && x(x2)); GECODE_ME_CHECK(x2.lq(home,m(x0.max(),x1.max()))); GECODE_ME_CHECK(x2.gq(home,m(x0.max(),x1.min()))); if (p(x2)) goto rewrite_ppp; if (n(x2)) goto rewrite_pnn; GECODE_ME_CHECK(x1.lq(home,f_d(x2.max(),x0.min()))); GECODE_ME_CHECK(x1.gq(home,c_d(x2.min(),x0.min()))); if (x0.assigned() && x1.assigned()) { GECODE_ME_CHECK(x2.eq(home,m(x0.val(),x1.val()))); return ES_SUBSUMED; } return ES_NOFIX; prop_xnx: std::swap(x0,x1); prop_nxx: assert(n(x0) && x(x1) && x(x2)); GECODE_ME_CHECK(x2.lq(home,m(x0.min(),x1.min()))); GECODE_ME_CHECK(x2.gq(home,m(x0.min(),x1.max()))); if (p(x2)) goto rewrite_nnp; if (n(x2)) goto rewrite_npn; GECODE_ME_CHECK(x1.lq(home,f_d(x2.min(),x0.max()))); GECODE_ME_CHECK(x1.gq(home,c_d(x2.max(),x0.max()))); if (x0.assigned() && x1.assigned()) { GECODE_ME_CHECK(x2.eq(home,m(x0.val(),x1.val()))); return ES_SUBSUMED; } return ES_NOFIX; rewrite_ppp: return (MultPlus::post(home,x0,x1,x2) == ES_FAILED) ? ES_FAILED : ES_SUBSUMED; rewrite_nnp: return (MultPlus::post(home,x0,x1,x2) == ES_FAILED) ? ES_FAILED : ES_SUBSUMED; rewrite_pnn: std::swap(x0,x1); rewrite_npn: return (MultPlus::post(home,x0,x1,x2) == ES_FAILED) ? ES_FAILED : ES_SUBSUMED; } template ExecStatus Mult::post(Space* home, View x0, View x1, View x2) { if (same(x0,x1)) return Square::post(home,x0,x2); if (p(x0)) { if (p(x1) || p(x2)) goto post_ppp; if (n(x1) || n(x2)) goto post_pnn; } else if (n(x0)) { if (n(x1) || p(x2)) goto post_nnp; if (p(x1) || n(x2)) goto post_npn; } else if (p(x1)) { if (p(x2)) goto post_ppp; if (n(x2)) goto post_npn; } else if (n(x1)) { if (p(x2)) goto post_nnp; if (n(x2)) goto post_pnn; } (void) new (home) Mult(home,x0,x1,x2); return ES_OK; post_ppp: return MultPlus::post(home,x0,x1,x2); post_nnp: return MultPlus::post(home,x0,x1,x2); post_pnn: std::swap(x0,x1); post_npn: return MultPlus::post(home,x0,x1,x2); } }}} // STATISTICS: int-prop