/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Christian Schulte * * Copyright: * Christian Schulte, 2004 * * Last modified: * $Date: 2011-09-19 22:02:26 +1000 (Mon, 19 Sep 2011) $ by $Author: schulte $ * $Revision: 12400 $ * * 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 Element { // Index value pairs template forceinline void Int::IdxVal::mark(void) { idx = -1; } template forceinline bool Int::IdxVal::marked(void) const { return idx<0; } // Index iterator template forceinline Int::IterIdxUnmark::IterIdxUnmark(IdxVal* iv0) : iv(iv0) { Idx p=0; i = iv[p].idx_next; while ((i != 0) && iv[i].marked()) i=iv[i].idx_next; iv[p].idx_next=i; } template forceinline bool Int::IterIdxUnmark::operator ()(void) const { return i != 0; } template forceinline void Int::IterIdxUnmark::operator ++(void) { int p=i; i = iv[p].idx_next; while ((i != 0) && iv[i].marked()) i=iv[i].idx_next; iv[p].idx_next=i; } template forceinline Idx Int::IterIdxUnmark::val(void) const { assert(!iv[i].marked()); return iv[i].idx; } template forceinline Int::IterVal::IterVal(IdxVal* iv0) : iv(iv0), i(iv[0].val_next) {} template forceinline bool Int::IterVal::operator ()(void) const { return i != 0; } template forceinline void Int::IterVal::operator ++(void) { i=iv[i].val_next; } template forceinline Val Int::IterVal::val(void) const { assert(!iv[i].marked()); return iv[i].val; } template forceinline Int::IterValUnmark::IterValUnmark(IdxVal* iv0) : iv(iv0) { Idx p=0; i = iv[p].val_next; while ((i != 0) && iv[i].marked()) i=iv[i].val_next; iv[p].val_next=i; } template forceinline bool Int::IterValUnmark::operator ()(void) const { return i != 0; } template forceinline void Int::IterValUnmark::operator ++(void) { int p=i; i = iv[p].val_next; while ((i != 0) && iv[i].marked()) i=iv[i].val_next; iv[p].val_next=i; } template forceinline Val Int::IterValUnmark::val(void) const { assert(!iv[i].marked()); return iv[i].val; } // Sort function template forceinline Int::ByVal::ByVal(const IdxVal* iv0) : iv(iv0) {} template forceinline bool Int::ByVal::operator ()(Idx& i, Idx& j) { return iv[i].val < iv[j].val; } /* * Element propagator proper * */ template forceinline Int::Int(Home home, IntSharedArray& c0, V0 y0, V1 y1) : Propagator(home), x0(y0), s0(0), x1(y1), s1(0), c(c0), iv(NULL) { home.notice(*this,AP_DISPOSE); x0.subscribe(home,*this,PC_INT_DOM); x1.subscribe(home,*this,PC_INT_DOM); } template forceinline size_t Int::dispose(Space& home) { home.ignore(*this,AP_DISPOSE); x0.cancel(home,*this,PC_INT_DOM); x1.cancel(home,*this,PC_INT_DOM); c.~IntSharedArray(); (void) Propagator::dispose(home); return sizeof(*this); } template ExecStatus Int::post(Home home, IntSharedArray& c, V0 x0, V1 x1) { if (x0.assigned()) { GECODE_ME_CHECK(x1.eq(home,c[x0.val()])); } else if (x1.assigned()) { GECODE_ES_CHECK(assigned_val(home,c,x0,x1)); } else { (void) new (home) Int(home,c,x0,x1); } return ES_OK; } template forceinline Int::Int(Space& home, bool share, Int& p) : Propagator(home,share,p), s0(0), s1(0), iv(NULL) { c.update(home,share,p.c); x0.update(home,share,p.x0); x1.update(home,share,p.x1); } template Actor* Int::copy(Space& home, bool share) { return new (home) Int(home,share,*this); } template PropCost Int::cost(const Space&, const ModEventDelta& med) const { if ((V0::me(med) == ME_INT_VAL) || (V1::me(med) == ME_INT_VAL)) return PropCost::unary(PropCost::LO); else return PropCost::binary(PropCost::HI); } template void Int::prune_idx(void) { Idx p = 0; Idx i = iv[p].idx_next; ViewRanges v(x0); while (v() && (i != 0)) { assert(!iv[i].marked()); if (iv[i].idx < v.min()) { iv[i].mark(); i=iv[i].idx_next; iv[p].idx_next=i; } else if (iv[i].idx > v.max()) { ++v; } else { p=i; i=iv[i].idx_next; } } iv[p].idx_next = 0; while (i != 0) { iv[i].mark(); i=iv[i].idx_next; } } template void Int::prune_val(void) { Idx p = 0; Idx i = iv[p].val_next; ViewRanges v(x1); while (v() && (i != 0)) { if (iv[i].marked()) { i=iv[i].val_next; iv[p].val_next=i; } else if (iv[i].val < v.min()) { iv[i].mark(); i=iv[i].val_next; iv[p].val_next=i; } else if (iv[i].val > v.max()) { ++v; } else { p=i; i=iv[i].val_next; } } iv[p].val_next = 0; while (i != 0) { iv[i].mark(); i=iv[i].val_next; } } template ExecStatus Int::assigned_val(Space& home, IntSharedArray& c, V0 x0, V1 x1) { Region r(home); int* v = r.alloc(x0.size()); int n = 0; for (ViewValues i(x0); i(); ++i) if (c[i.val()] != x1.val()) v[n++]=i.val(); Iter::Values::Array iv(v,n); GECODE_ME_CHECK(x0.minus_v(home,iv,false)); return ES_OK; } template ExecStatus Int::propagate(Space& home, const ModEventDelta&) { if (x0.assigned()) { GECODE_ME_CHECK(x1.eq(home,c[x0.val()])); return home.ES_SUBSUMED(*this); } if (x1.assigned() && (iv == NULL)) { GECODE_ES_CHECK(assigned_val(home,c,x0,x1)); return home.ES_SUBSUMED(*this); } if ((static_cast(x1.size()) == s1) && (static_cast(x0.size()) != s0)) { assert(iv != NULL); assert(!shared(x0,x1)); prune_idx(); IterValUnmark v(iv); GECODE_ME_CHECK(x1.narrow_v(home,v,false)); s1=static_cast(x1.size()); assert(!x0.assigned()); return x1.assigned() ? home.ES_SUBSUMED(*this) : ES_FIX; } if ((static_cast(x0.size()) == s0) && (static_cast(x1.size()) != s1)) { assert(iv != NULL); assert(!shared(x0,x1)); prune_val(); IterIdxUnmark i(iv); GECODE_ME_CHECK(x0.narrow_v(home,i,false)); s0=static_cast(x0.size()); return (x0.assigned() || x1.assigned()) ? home.ES_SUBSUMED(*this) : ES_FIX; } bool assigned = x0.assigned() && x1.assigned(); if (iv == NULL) { // Initialize data structure iv = home.alloc(x0.size() + 1); // The first element in iv[0] is used as sentinel // Enter information sorted by idx IdxVal* by_idx = &iv[1]; Idx size = 0; for (ViewValues v(x0); v(); ++v) if ((x1.min() <= c[v.val()]) && (x1.max() >= c[v.val()])) { by_idx[size].idx = static_cast(v.val()); by_idx[size].val = static_cast(c[v.val()]); size++; } if (size == 0) return ES_FAILED; // Create val links sorted by val Region r(home); Idx* by_val = r.alloc(size); if (x1.width() <= 128) { int n_buckets = static_cast(x1.width()); int* pos = r.alloc(n_buckets); int* buckets = pos - x1.min(); for (int i=n_buckets; i--; ) pos[i]=0; for (Idx i=size; i--; ) buckets[by_idx[i].val]++; int p=0; for (int i=0; i(by_val,size,less); } // Create val links for (Idx i = size-1; i--; ) { by_idx[i].idx_next = i+2; iv[by_val[i]].val_next = by_val[i+1]; } by_idx[size-1].idx_next = 0; iv[by_val[size-1]].val_next = 0; // Set up sentinel element: iv[0] iv[0].idx_next = 1; iv[0].val_next = by_val[0]; } else { prune_idx(); } // Prune values prune_val(); // Peform tell { IterIdxUnmark i(iv); GECODE_ME_CHECK(x0.narrow_v(home,i,false)); IterVal v(iv); if (shared(x0,x1)) { GECODE_ME_CHECK(x1.inter_v(home,v,false)); s0=static_cast(x0.size()); s1=static_cast(x1.size()); return assigned ? home.ES_SUBSUMED(*this) : ES_NOFIX; } else { GECODE_ME_CHECK(x1.narrow_v(home,v,false)); s0=static_cast(x0.size()); s1=static_cast(x1.size()); return (x0.assigned() || x1.assigned()) ? home.ES_SUBSUMED(*this) : ES_FIX; } } } template forceinline ExecStatus post_int(Home home, IntSharedArray& c, V0 x0, V1 x1) { assert(c.size() > 0); GECODE_ME_CHECK(x0.gq(home,0)); GECODE_ME_CHECK(x0.le(home,c.size())); Support::IntType idx_type = Support::s_type(c.size()); int min = c[0]; int max = c[0]; for (int i=1; i::post(home,c,x0,x1); case Support::IT_SHRT: return Int::post(home,c,x0,x1); default: break; } break; case Support::IT_SHRT: switch (val_type) { case Support::IT_CHAR: case Support::IT_SHRT: return Int::post(home,c,x0,x1); default: break; } break; default: break; } return Int::post(home,c,x0,x1); } }}} // STATISTICS: int-prop