/* -*- 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: 2011-04-02 00:26:13 +1100 (Sat, 02 Apr 2011) $ by $Author: tack $ * $Revision: 11858 $ * * 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; /// 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 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, Offset& ox, Info* y, Offset& oy, int& n_na, ProcessStack& xa, ProcessStack& ya) { do { int i = xa.pop(); int j = ox(x[i].view).val(); // Assign the y variable to i (or test if already assigned!) { ModEvent me = oy(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 = ox(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, Offset& ox, Info* y, Offset& oy, int& n_na, ProcessStack& xa, ProcessStack& ya) { if (xa.empty()) return ES_OK; return doprop_val(home,n,x,ox,y,oy,n_na,xa,ya); } /* * The actual propagator * */ template forceinline Val::Val(Home home, int n, ValInfo* xy, Offset& ox, Offset& oy) : Base,Offset,PC_INT_VAL>(home,n,xy,ox,oy) {} template forceinline Val::Val(Space& home, bool share, Val& p) : Base,Offset,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, const ModEventDelta&) { Region r(home); ProcessStack xa(r,n); ProcessStack ya(r,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,ox,y,oy,n_na,xa,ya))); // Propagate assigned views for y GECODE_ES_CHECK((prop_val > (home,n,y,oy,x,ox,n_na,ya,xa))); assert(ya.empty()); } while (!xa.empty()); if (n_na == 0) return home.ES_SUBSUMED(*this); return shared ? ES_NOFIX : ES_FIX; } template ExecStatus Val::post(Home home, int n, ValInfo* xy, Offset& ox, Offset& oy) { assert(n > 0); if (n == 1) { GECODE_ME_CHECK(ox(xy[0].view).eq(home,0)); GECODE_ME_CHECK(oy(xy[1].view).eq(home,0)); return ES_OK; } for (int i=n; i--; ) { GECODE_ME_CHECK(ox(xy[i ].view).gq(home,0)); GECODE_ME_CHECK(ox(xy[i ].view).le(home,n)); GECODE_ME_CHECK(oy(xy[i+n].view).gq(home,0)); GECODE_ME_CHECK(oy(xy[i+n].view).le(home,n)); } (void) new (home) Val(home,n,xy,ox,oy); return ES_OK; } }}} // STATISTICS: int-prop