/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Christian Schulte * * Copyright: * Christian Schulte, 2006 * * 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 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 forceinline size_t BaseInt::dispose(Space* home) { 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(ModEventDelta) const { return cost_lo(x.size(),PC_LINEAR_LO); } template Reflection::ActorSpec BaseInt::spec(const Space* home, Reflection::VarMap& m, const Support::Symbol& ati) const { Reflection::ActorSpec s(ati); return s << x.spec(home, m) << n_s << y.spec(home, m) << c; } /* * 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) return post_false(home,x,y) ? ES_FAILED : ES_OK; // All views must be equal if (c == n_x) return post_true(home,x,y) ? ES_FAILED : ES_OK; // 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 Support::Symbol EqInt::ati(void) { return Reflection::mangle("Gecode::Int::Count::EqInt"); } template Reflection::ActorSpec EqInt::spec(const Space* home, Reflection::VarMap& m) const { return BaseInt::spec(home, m, ati()); } template void EqInt::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(4); ViewArray x(home, vars, spec[0]); int n_s = spec[1]->toInt(); VY y(home, vars, spec[2]); int c = spec[3]->toInt(); (void) new (home) EqInt(home, x, n_s, y, c); } template ExecStatus EqInt::propagate(Space* home, ModEventDelta) { // 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) ? ES_FAILED : ES_SUBSUMED(this,home); if (c == n_x) // All views must be equal return post_true(home,x,y) ? ES_FAILED : ES_SUBSUMED(this,home); 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) return post_true(home,x,y) ? ES_FAILED : ES_OK; (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 Support::Symbol GqInt::ati(void) { return Reflection::mangle("Gecode::Int::Count::GqInt"); } template Reflection::ActorSpec GqInt::spec(const Space* home, Reflection::VarMap& m) const { return BaseInt::spec(home, m, ati()); } template void GqInt::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(4); ViewArray x(home, vars, spec[0]); int n_s = spec[1]->toInt(); VY y(home, vars, spec[2]); int c = spec[3]->toInt(); (void) new (home) GqInt(home, x, n_s, y, c); } template ExecStatus GqInt::propagate(Space* home, ModEventDelta) { // 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(this,home); // 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(this,home); if (c == n_x) // All views must be equal return post_true(home,x,y) ? ES_FAILED : ES_SUBSUMED(this,home); // 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) return post_false(home,x,y) ? ES_FAILED : ES_OK; (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 Support::Symbol LqInt::ati(void) { return Reflection::mangle("Gecode::Int::Count::LqInt"); } template Reflection::ActorSpec LqInt::spec(const Space* home, Reflection::VarMap& m) const { return BaseInt::spec(home, m, ati()); } template void LqInt::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(4); ViewArray x(home, vars, spec[0]); int n_s = spec[1]->toInt(); VY y(home, vars, spec[2]); int c = spec[3]->toInt(); (void) new (home) LqInt(home, x, n_s, y, c); } template ExecStatus LqInt::propagate(Space* home, ModEventDelta) { // 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(this,home); // 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(this,home); if (c == 0) // All views must be different return post_false(home,x,y) ? ES_FAILED : ES_SUBSUMED(this,home); // 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 forceinline size_t NqInt::dispose(Space* home) { 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) if (c == 1) return post_false(home,x[0],y) ? ES_FAILED : ES_OK; else return post_true(home,x[0],y) ? ES_FAILED : ES_OK; (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(ModEventDelta) const { return PC_LINEAR_LO; } template Support::Symbol NqInt::ati(void) { return Reflection::mangle("Gecode::Int::Count::NqInt"); } template Reflection::ActorSpec NqInt::spec(const Space* home, Reflection::VarMap& m) const { Reflection::ActorSpec s = BinaryPropagator::spec(home, m, ati()); return s << x.spec(home, m) << y.spec(home, m) << c; } template void NqInt::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(5); VX x0(home, vars, spec[0]); VX x1(home, vars, spec[1]); ViewArray xx(home, vars, spec[2]); ViewArray x(home, xx.size()+2); for (int i=xx.size(); i--; ) x[i] = xx[i]; x[xx.size()] = x0; x[xx.size()+1] = x1; VY y(home, vars, spec[3]); int c = spec[4]->toInt(); (void) new (home) NqInt(home, x, y, c); } 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, ModEventDelta) { bool s0 = resubscribe(home,x0); bool s1 = resubscribe(home,x1); int n = x.size() + s0 + s1; if ((n < c) || (c < 0)) return ES_SUBSUMED(this,home); if (n == 0) return (c == 0) ? ES_FAILED : ES_SUBSUMED(this,home); if (n == 1) { if (s0) if (c == 1) return post_false(home,x0,y) ? ES_FAILED : ES_SUBSUMED(this,home); else return post_true(home,x0,y) ? ES_FAILED : ES_SUBSUMED(this,home); else if (c == 1) return post_false(home,x1,y) ? ES_FAILED : ES_SUBSUMED(this,home); else return post_true(home,x1,y) ? ES_FAILED : ES_SUBSUMED(this,home); } return ES_FIX; } }}} // STATISTICS: int-prop