/* * Main authors: * Christian Schulte * * Copyright: * Christian Schulte, 2006 * * Last modified: * $Date: 2006-09-06 15:51:28 +0200 (Wed, 06 Sep 2006) $ by $Author: schulte $ * $Revision: 3604 $ * * 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 #include "gecode/int/bool.hh" namespace Gecode { namespace Int { namespace Linear { /* * Baseclass for integer Boolean sum * */ template forceinline LinBoolInt::LinBoolInt(Space* home, ViewArray& x0, int n_s0, int c0) : Propagator(home), x(x0), n_s(n_s0), c(c0) { for (int i=n_s; i--; ) x[i].subscribe(home,this,PC_INT_VAL); } template size_t LinBoolInt::dispose(Space* home) { assert(!home->failed()); for (int i=n_s; i--; ) x[i].cancel(home,this,PC_INT_VAL); (void) Propagator::dispose(home); return sizeof(*this); } template forceinline LinBoolInt::LinBoolInt(Space* home, bool share, LinBoolInt& p) : Propagator(home,share,p), x(home,p.x.size()), n_s(p.n_s) { // Update views not assigned and subscribed to for (int i=n_s; i--; ) x[i].update(home,share,p.x[i]); // Eliminate assigned but not subscribed views in original // and update remaining ones int n_x = p.x.size(); int p_c = p.c; for (int i=n_x; i-- > n_s; ) if (p.x[i].zero()) { n_x--; p.x[i]=p.x[n_x]; x[i]=x[n_x]; } else if (p.x[i].one()) { n_x--; p_c--; p.x[i]=p.x[n_x]; x[i]=x[n_x]; } else { x[i].update(home,share,p.x[i]); } p.c = p_c; c = p_c; p.x.size(n_x); x.size(n_x); } template PropCost LinBoolInt::cost(void) const { return cost_lo(x.size(),PC_LINEAR_LO); } /* * Less or equal propagator (integer rhs) * */ template forceinline GqBoolInt::GqBoolInt(Space* home, ViewArray& x, int n_s, int c) : LinBoolInt(home,x,n_s,c) {} template ExecStatus GqBoolInt::post(Space* home, ViewArray& x, int c) { if (c == 1) return Bool::NaryOrTrue::post(home,x); // Eliminate assigned views int n_x = x.size(); for (int i=n_x; i--; ) if (x[i].zero()) { x[i] = x[--n_x]; } else if (x[i].one()) { x[i] = x[--n_x]; c--; } // 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 one to satisfy inequality if (c == n_x) { for (int i=n_x; i--; ) x[i].t_one_none(home); return ES_OK; } // This is the needed invariant as c+1 subscriptions must be created assert(n_x > c); x.size(n_x); (void) new (home) GqBoolInt(home,x,c+1,c); return ES_OK; } template forceinline GqBoolInt::GqBoolInt(Space* home, bool share, GqBoolInt& p) : LinBoolInt(home,share,p) {} template Actor* GqBoolInt::copy(Space* home, bool share) { return new (home) GqBoolInt(home,share,*this); } template ExecStatus GqBoolInt::propagate(Space* home) { // Eliminate assigned views from subscribed views int n_x = x.size(); for (int i=n_s; i--; ) if (x[i].zero()) { x[i]=x[--n_s]; x[n_s]=x[--n_x]; } else if (x[i].one()) { x[i]=x[--n_s]; x[n_s]=x[--n_x]; c--; } x.size(n_x); if (n_x < c) return ES_FAILED; if (c <= 0) return ES_SUBSUMED; // Find unassigned variables to subscribe to while ((n_s < n_x) && (n_s <= c)) if (x[n_s].zero()) { x[n_s]=x[--n_x]; } else if (x[n_s].one()) { x[n_s]=x[--n_x]; c--; } else { x[n_s++].subscribe(home,this,PC_INT_VAL,false); } x.size(n_x); if (n_x < c) return ES_FAILED; if (c <= 0) return ES_SUBSUMED; if (c == n_x) { // These are known to be not assigned for (int i=n_s; i--; ) x[i].t_one_none(home); // These are not known to be assigned for (int i=n_s+1; i forceinline EqBoolInt::EqBoolInt(Space* home, ViewArray& x, int n_s, int c) : LinBoolInt(home,x,n_s,c) {} template ExecStatus EqBoolInt::post(Space* home, ViewArray& x, int c) { // Eliminate assigned views int n_x = x.size(); for (int i=n_x; i--; ) if (x[i].zero()) { x[i] = x[--n_x]; } else if (x[i].one()) { x[i] = x[--n_x]; c--; } // RHS too small or too large if ((c < 0) || (c > n_x)) return ES_FAILED; // All views must be zero to satisfy equality if (c == 0) { for (int i=n_x; i--; ) x[i].t_zero_none(home); return ES_OK; } // All views must be one to satisfy equality if (c == n_x) { for (int i=n_x; i--; ) x[i].t_one_none(home); return ES_OK; } x.size(n_x); // 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) EqBoolInt(home,x,n_s,c); return ES_OK; } template forceinline EqBoolInt::EqBoolInt(Space* home, bool share, EqBoolInt& p) : LinBoolInt(home,share,p) {} template Actor* EqBoolInt::copy(Space* home, bool share) { return new (home) EqBoolInt(home,share,*this); } template ExecStatus EqBoolInt::propagate(Space* home) { // Eliminate assigned views from subscribed views int n_x = x.size(); for (int i=n_s; i--; ) if (x[i].zero()) { x[i]=x[--n_s]; x[n_s]=x[--n_x]; } else if (x[i].one()) { x[i]=x[--n_s]; x[n_s]=x[--n_x]; c--; } x.size(n_x); if ((c < 0) || (c > n_x)) return ES_FAILED; // Find unassigned variables to subscribe to while ((n_s < n_x) && ((n_s <= c) || (n_s <= n_x-c))) if (x[n_s].zero()) { x[n_s]=x[--n_x]; } else if (x[n_s].one()) { x[n_s]=x[--n_x]; c--; } else { x[n_s++].subscribe(home,this,PC_INT_VAL,false); } x.size(n_x); if ((c < 0) || (c > n_x)) return ES_FAILED; if (c == 0) { // These are known to be not assigned for (int i=n_s; i--; ) x[i].t_zero_none(home); // These are not known to be assigned for (int i=n_s+1; i forceinline NqBoolInt::NqBoolInt(Space* home, ViewArray& b, int c0) : BinaryPropagator(home, b[b.size()-2], b[b.size()-1]), x(b), c(c0) { assert(x.size() >= 2); x.size(x.size()-2); } template forceinline NqBoolInt::NqBoolInt(Space* home, bool share, NqBoolInt& p) : BinaryPropagator(home,share,p), x(home,p.x.size()) { // Eliminate all zeros and ones in original and update int n = p.x.size(); int p_c = p.c; for (int i=n; i--; ) if (p.x[i].zero()) { n--; p.x[i]=p.x[n]; x[i]=x[n]; } else if (p.x[i].one()) { n--; p_c--; p.x[i]=p.x[n]; x[i]=x[n]; } else { x[i].update(home,share,p.x[i]); } c = p_c; p.c = p_c; x.size(n); p.x.size(n); } template forceinline ExecStatus NqBoolInt::post(Space* home, ViewArray& x, int c) { int n = x.size(); for (int i=n; i--; ) if (x[i].one()) { x[i]=x[--n]; c--; } else if (x[i].zero()) { x[i]=x[--n]; } x.size(n); if ((n < c) || (c < 0)) return ES_OK; if (n == 0) return (c == 0) ? ES_FAILED : ES_OK; if (n == 1) { if (c == 1) x[0].t_zero_none(home); else x[0].t_one_none(home); return ES_OK; } (void) new (home) NqBoolInt(home,x,c); return ES_OK; } template Actor* NqBoolInt::copy(Space* home, bool share) { return new (home) NqBoolInt(home,share,*this); } template PropCost NqBoolInt::cost(void) const { return PC_LINEAR_LO; } template forceinline bool NqBoolInt::resubscribe(Space* home, VX& y) { if (y.one()) c--; int n = x.size(); for (int i=n; i--; ) if (x[i].one()) { c--; x[i]=x[--n]; } else if (x[i].zero()) { x[i] = x[--n]; } else { // New unassigned view found assert(!x[i].zero() && !x[i].one()); // Move to y and subscribe y=x[i]; x[i]=x[--n]; x.size(n); y.subscribe(home,this,PC_INT_VAL,false); return true; } // All views have been assigned! x.size(0); return false; } template ExecStatus NqBoolInt::propagate(Space* home) { bool s0 = true; if (x0.zero() || x0.one()) s0 = resubscribe(home,x0); bool s1 = true; if (x1.zero() || x1.one()) 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) { if (c == 1) x0.t_zero_none(home); else x0.t_one_none(home); } else { assert(s1); if (c == 1) x1.t_zero_none(home); else x1.t_one_none(home); } return ES_SUBSUMED; } return ES_FIX; } }}} // STATISTICS: int-prop