/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Christian Schulte * * Contributing authors: * Mikael Lagerkvist * * Copyright: * Christian Schulte, 2006 * Mikael Lagerkvist, 2006 * * Last modified: * $Date: 2008-07-11 09:32:27 +0200 (Fri, 11 Jul 2008) $ by $Author: tack $ * $Revision: 7289 $ * * 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 Channel { /** * \brief Combine view with information for value propagation * */ template class ValInfo { public: /// The view View view; /// Whether it has been propagated that view is assigned bool a; /// Allocate memory from space \a home for \a n elements static ValInfo* allocate(Space* home, int n); /// Initialize void init(View x, int n); /// Update during cloning void update(Space* home, bool share, ValInfo& vi); /// Check whether propagation for assignment is to be done bool doval(void) const; /// Check whether propagation for domain is to be done bool dodom(void) const; /// Record that view got assigned void assigned(void); /// Record that one value got removed void removed(int i); /// Update the cardinality and bounds information after pruning void done(void); }; template forceinline ValInfo* ValInfo::allocate(Space* home, int n) { return static_cast*> (home->alloc(n*sizeof(ValInfo))); } template forceinline void ValInfo::init(View x, int) { view = x; a = false; } template forceinline void ValInfo::update(Space* home, bool share, ValInfo& vi) { view.update(home,share,vi.view); a = vi.a; } template forceinline bool ValInfo::doval(void) const { return !a && view.assigned(); } template forceinline bool ValInfo::dodom(void) const { return false; } template forceinline void ValInfo::assigned(void) { a = true; } template forceinline void ValInfo::removed(int) {} template forceinline void ValInfo::done(void) {} // Propagate assigned views for x template ExecStatus doprop_val(Space* home, int n, Info* x, Info* y, int& n_na, ProcessStack& xa, ProcessStack& ya) { do { int i = xa.pop(); int j = x[i].view.val(); // Assign the y variable to i (or test if already assigned!) { ModEvent me = y[j].view.eq(home,i); if (me_failed(me)) return ES_FAILED; // Record that y[j] has been assigned and must be propagated if (me_modified(me)) ya.push(j); } // Prune the value j from all x variables for (int k=i; k--; ) { ModEvent me = x[k].view.nq(home,j); if (me_failed(me)) return ES_FAILED; if (me_modified(me)) { if (me == ME_INT_VAL) { // Record that x[k] has been assigned and must be propagated xa.push(k); } else { // One value has been removed and this removal does not need // to be propagated again: after all y[j] = i, so it holds // that y[j] != k. x[k].removed(j); } } } // The same for the other views for (int k=i+1; k forceinline ExecStatus prop_val(Space* home, int n, Info* x, Info* y, int& n_na, ProcessStack& xa, ProcessStack& ya) { if (xa.empty()) return ES_OK; return doprop_val(home,n,x,y,n_na,xa,ya); } /* * The actual propagator * */ template forceinline Val::Val(Space* home, int n, ValInfo* xy) : Base,PC_INT_VAL>(home,n,xy) {} template forceinline Val::Val(Space* home, bool share, Val& p) : Base,PC_INT_VAL>(home,share,p) {} template Actor* Val::copy(Space* home, bool share) { return new (home) Val(home,share,*this); } template ExecStatus Val::propagate(Space* home, ModEventDelta) { GECODE_AUTOSTACK(int,-1, xa, n); GECODE_AUTOSTACK(int,-1, ya, n); ValInfo* x = xy; ValInfo* y = xy+n; // Scan x and y for assigned but not yet propagated views for (int i = n; i--; ) { if (x[i].doval()) xa.push(i); if (y[i].doval()) ya.push(i); } do { // Propagate assigned views for x GECODE_ES_CHECK((prop_val >(home,n,x,y,n_na,xa,ya))); // Propagate assigned views for y GECODE_ES_CHECK((prop_val >(home,n,y,x,n_na,ya,xa))); assert(ya.empty()); } while (!xa.empty()); if (n_na == 0) return ES_SUBSUMED(this,home); return shared ? ES_NOFIX : ES_FIX; } template Support::Symbol Val::ati(void) { return Reflection::mangle("Gecode::Int::Channel::Val",shared); } template Reflection::ActorSpec Val::spec(const Space* home, Reflection::VarMap& m) const { return Base,PC_INT_VAL>::spec(home, m, ati()); } template void Val::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { const int n = spec.noOfArgs(); ValInfo* vi = ValInfo::allocate(home,n); for (int i=0; i(home,n/2,vi); } template ExecStatus Val::post(Space* home, int n, ValInfo* xy) { assert(n > 0); if (n == 1) { GECODE_ME_CHECK(xy[0].view.eq(home,0)); GECODE_ME_CHECK(xy[1].view.eq(home,0)); return ES_OK; } for (int i=2*n; i--; ) { GECODE_ME_CHECK(xy[i].view.gq(home,0)); GECODE_ME_CHECK(xy[i].view.le(home,n)); } (void) new (home) Val(home,n,xy); return ES_OK; } }}} // STATISTICS: int-prop