/* * Main authors: * Christian Schulte * * Copyright: * Christian Schulte, 2006 * * Last modified: * $Date: 2006-08-08 20:36:53 +0200 (Tue, 08 Aug 2006) $ by $Author: schulte $ * $Revision: 3538 $ * * 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. * */ namespace Gecode { namespace Int { namespace Count { /* * General baseclass * */ template forceinline BaseInt::BaseInt(Space* home, ViewArray& x0, int n_s0, VY y0, int c0) : Propagator(home), x(x0), n_s(n_s0), y(y0), c(c0) { for (int i=n_s; i--; ) x[i].subscribe(home,this,PC_INT_DOM); y.subscribe(home,this,PC_INT_DOM); } template size_t BaseInt::dispose(Space* home) { assert(!home->failed()); for (int i=n_s; i--; ) x[i].cancel(home,this,PC_INT_DOM); y.cancel(home,this,PC_INT_DOM); (void) Propagator::dispose(home); return sizeof(*this); } template forceinline BaseInt::BaseInt(Space* home, bool share, BaseInt& p) : Propagator(home,share,p), n_s(p.n_s), c(p.c) { x.update(home,share,p.x); y.update(home,share,p.y); } template PropCost BaseInt::cost(void) const { return cost_lo(x.size(),PC_LINEAR_LO); } /* * Equal propagator (integer rhs) * */ template forceinline EqInt::EqInt(Space* home, ViewArray& x, int n_s, VY y, int c) : BaseInt(home,x,n_s,y,c) {} template ExecStatus EqInt::post(Space* home, ViewArray& x, VY y, int c) { // Eliminate decided views int n_x = x.size(); for (int i=n_x; i--; ) switch (holds(x[i],y)) { case RT_FALSE: x[i] = x[--n_x]; break; case RT_TRUE: x[i] = x[--n_x]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n_x); // RHS too small or too large if ((c < 0) || (c > n_x)) return ES_FAILED; // All views must be different if (c == 0) { ExecStatus es = post_false(home,x,y); return (es == ES_SUBSUMED) ? ES_OK : es; } // All views must be equal if (c == n_x) { ExecStatus es = post_true(home,x,y); return (es == ES_SUBSUMED) ? ES_OK : es; } // Compute how many subscriptions must be created int n_s = std::max(c,n_x-c)+1; assert(n_s <= n_x); (void) new (home) EqInt(home,x,n_s,y,c); return ES_OK; } template forceinline EqInt::EqInt(Space* home, bool share, EqInt& p) : BaseInt(home,share,p) {} template Actor* EqInt::copy(Space* home, bool share) { return new (home) EqInt(home,share,*this); } template ExecStatus EqInt::propagate(Space* home) { // Eliminate decided views from subscribed views int n_x = x.size(); for (int i=n_s; i--; ) switch (holds(x[i],y)) { case RT_FALSE: x[i].cancel(home,this,PC_INT_DOM); x[i]=x[--n_s]; x[n_s]=x[--n_x]; break; case RT_TRUE: x[i].cancel(home,this,PC_INT_DOM); x[i]=x[--n_s]; x[n_s]=x[--n_x]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n_x); if ((c < 0) || (c > n_x)) return ES_FAILED; // Eliminate decided views from unsubscribed views for (int i=n_x; i-- > n_s; ) switch (holds(x[i],y)) { case RT_FALSE: x[i]=x[--n_x]; break; case RT_TRUE: x[i]=x[--n_x]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n_x); if ((c < 0) || (c > n_x)) return ES_FAILED; if (c == 0) // All views must be different return post_false(home,x,y); if (c == n_x) // All views must be equal return post_true(home,x,y); int m = std::max(c,n_x-c)+1; assert(m <= n_x); // Now, there must be new subscriptions from x[n_s] up to x[m-1] while (n_s < m) x[n_s++].subscribe(home,this,PC_INT_DOM,false); return ES_FIX; } /* * Greater or equal propagator (integer rhs) * */ template forceinline GqInt::GqInt(Space* home, ViewArray& x, int n_s, VY y, int c) : BaseInt(home,x,n_s,y,c) {} template ExecStatus GqInt::post(Space* home, ViewArray& x, VY y, int c) { // Eliminate decided views int n_x = x.size(); for (int i=n_x; i--; ) switch (holds(x[i],y)) { case RT_FALSE: x[i] = x[--n_x]; break; case RT_TRUE: x[i] = x[--n_x]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n_x); // RHS too large if (n_x < c) return ES_FAILED; // Whatever the x[i] take for values, the inequality is subsumed if (c <= 0) return ES_OK; // All views must be equal if (c == n_x) { ExecStatus es = post_true(home,x,y); return (es == ES_SUBSUMED) ? ES_OK : es; } (void) new (home) GqInt(home,x,c+1,y,c); return ES_OK; } template forceinline GqInt::GqInt(Space* home, bool share, GqInt& p) : BaseInt(home,share,p) {} template Actor* GqInt::copy(Space* home, bool share) { return new (home) GqInt(home,share,*this); } template ExecStatus GqInt::propagate(Space* home) { // Eliminate decided views from subscribed views int n_x = x.size(); for (int i=n_s; i--; ) switch (holds(x[i],y)) { case RT_FALSE: x[i].cancel(home,this,PC_INT_DOM); x[i]=x[--n_s]; x[n_s]=x[--n_x]; break; case RT_TRUE: x[i].cancel(home,this,PC_INT_DOM); x[i]=x[--n_s]; x[n_s]=x[--n_x]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n_x); if (n_x < c) return ES_FAILED; if (c <= 0) return ES_SUBSUMED; // Eliminate decided views from unsubscribed views for (int i=n_x; i-- > n_s; ) switch (holds(x[i],y)) { case RT_FALSE: x[i]=x[--n_x]; break; case RT_TRUE: x[i]=x[--n_x]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n_x); if (n_x < c) return ES_FAILED; if (c <= 0) return ES_SUBSUMED; if (c == n_x) // All views must be equal return post_true(home,x,y); // Now, there must be new subscriptions from x[n_s] up to x[c+1] while (n_s <= c) x[n_s++].subscribe(home,this,PC_INT_DOM,false); return ES_FIX; } /* * Less or equal propagator (integer rhs) * */ template forceinline LqInt::LqInt(Space* home, ViewArray& x, int n_s, VY y, int c) : BaseInt(home,x,n_s,y,c) {} template ExecStatus LqInt::post(Space* home, ViewArray& x, VY y, int c) { // Eliminate decided views int n_x = x.size(); for (int i=n_x; i--; ) switch (holds(x[i],y)) { case RT_FALSE: x[i] = x[--n_x]; break; case RT_TRUE: x[i] = x[--n_x]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n_x); if (c < 0) return ES_FAILED; if (c >= n_x) return ES_OK; // All views must be different if (c == 0) { ExecStatus es = post_false(home,x,y); return (es == ES_SUBSUMED) ? ES_OK : es; } (void) new (home) LqInt(home,x,n_x-c+1,y,c); return ES_OK; } template forceinline LqInt::LqInt(Space* home, bool share, LqInt& p) : BaseInt(home,share,p) {} template Actor* LqInt::copy(Space* home, bool share) { return new (home) LqInt(home,share,*this); } template ExecStatus LqInt::propagate(Space* home) { // Eliminate decided views from subscribed views int n_x = x.size(); for (int i=n_s; i--; ) switch (holds(x[i],y)) { case RT_FALSE: x[i].cancel(home,this,PC_INT_DOM); x[i]=x[--n_s]; x[n_s]=x[--n_x]; break; case RT_TRUE: x[i].cancel(home,this,PC_INT_DOM); x[i]=x[--n_s]; x[n_s]=x[--n_x]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n_x); if (c < 0) return ES_FAILED; if (c >= n_x) return ES_SUBSUMED; // Eliminate decided views from unsubscribed views for (int i=n_x; i-- > n_s; ) switch (holds(x[i],y)) { case RT_FALSE: x[i]=x[--n_x]; break; case RT_TRUE: x[i]=x[--n_x]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n_x); if (c < 0) return ES_FAILED; if (c >= n_x) return ES_SUBSUMED; if (c == 0) // All views must be different return post_false(home,x,y); // Now, there must be new subscriptions from x[n_s] up to x[n_x-c+1] int m = n_x-c; while (n_s <= m) x[n_s++].subscribe(home,this,PC_INT_DOM,false); return ES_FIX; } /* * Not-equal propagator (integer rhs) * */ template forceinline NqInt::NqInt(Space* home, ViewArray& x0, VY y0, int c0) : BinaryPropagator(home, x0[x0.size()-2], x0[x0.size()-1]), x(x0), y(y0), c(c0) { assert(x.size() >= 2); x.size(x.size()-2); y.subscribe(home,this,PC_INT_DOM); } template size_t NqInt::dispose(Space* home) { assert(!home->failed()); y.cancel(home,this,PC_INT_DOM); (void) BinaryPropagator::dispose(home); return sizeof(*this); } template forceinline NqInt::NqInt(Space* home, bool share, NqInt& p) : BinaryPropagator(home,share,p), c(p.c) { x.update(home,share,p.x); y.update(home,share,p.y); } template forceinline ExecStatus NqInt::post(Space* home, ViewArray& x, VY y, int c) { int n = x.size(); for (int i=n; i--; ) switch (holds(x[i],y)) { case RT_FALSE: x[i]=x[--n]; break; case RT_TRUE: x[i]=x[--n]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n); if ((n < c) || (c < 0)) return ES_OK; if (n == 0) return (c == 0) ? ES_FAILED : ES_OK; if (n == 1) { ExecStatus es = (c == 1) ? post_false(home,x[0],y) : post_true(home,x[0],y); return (es == ES_SUBSUMED) ? ES_OK : es; } (void) new (home) NqInt(home,x,y,c); return ES_OK; } template Actor* NqInt::copy(Space* home, bool share) { return new (home) NqInt(home,share,*this); } template PropCost NqInt::cost(void) const { return PC_LINEAR_LO; } template forceinline bool NqInt::resubscribe(Space* home, VX& z) { switch (holds(z,y)) { case RT_FALSE: break; case RT_TRUE: c--; break; case RT_MAYBE: return true; default: GECODE_NEVER; } int n = x.size(); for (int i=n; i--; ) switch (holds(x[i],y)) { case RT_FALSE: x[i]=x[--n]; break; case RT_TRUE: x[i]=x[--n]; c--; break; case RT_MAYBE: // New undecided view found z.cancel(home,this,PC_INT_DOM); z=x[i]; x[i]=x[--n]; x.size(n); z.subscribe(home,this,PC_INT_DOM,false); return true; default: GECODE_NEVER; } // All views have been decided x.size(0); return false; } template ExecStatus NqInt::propagate(Space* home) { bool s0 = resubscribe(home,x0); bool s1 = resubscribe(home,x1); int n = x.size() + s0 + s1; if ((n < c) || (c < 0)) return ES_SUBSUMED; if (n == 0) return (c == 0) ? ES_FAILED : ES_SUBSUMED; if (n == 1) { if (s0) { return (c == 1) ? post_false(home,x0,y) : post_true(home,x0,y); } else { assert(s1); return (c == 1) ? post_false(home,x1,y) : post_true(home,x1,y); } return ES_SUBSUMED; } return ES_FIX; } }}} // STATISTICS: int-prop