/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Mikael Lagerkvist * * Contributing authors: * Christian Schulte * * Copyright: * Mikael Lagerkvist, 2007 * Christian Schulte, 2008 * * Last modified: * $Date: 2010-07-15 01:46:18 +1000 (Thu, 15 Jul 2010) $ by $Author: schulte $ * $Revision: 11192 $ * * 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 Extensional { /* * Support advisor * */ template forceinline Incremental::SupportAdvisor:: SupportAdvisor(Space& home, Propagator& p, Council& c, int i0) : Advisor(home,p,c), i(i0) {} template forceinline Incremental::SupportAdvisor:: SupportAdvisor(Space& home, bool share, SupportAdvisor& a) : Advisor(home,share,a), i(a.i) {} template forceinline void Incremental::SupportAdvisor:: dispose(Space& home, Council& c) { Advisor::dispose(home,c); } /* * Support entries * */ template forceinline Incremental::SupportEntry::SupportEntry(Tuple t0) : t(t0) {} template forceinline Incremental::SupportEntry::SupportEntry(Tuple t0, SupportEntry* n) : FreeList(n), t(t0) {} template forceinline typename Incremental::SupportEntry* Incremental::SupportEntry::next(void) const { return static_cast(FreeList::next()); } template forceinline typename Incremental::SupportEntry** Incremental::SupportEntry::nextRef(void) { return reinterpret_cast(FreeList::nextRef()); } template forceinline void Incremental::SupportEntry::operator delete(void*) {} template forceinline void Incremental::SupportEntry::operator delete(void*, Space&) { GECODE_NEVER; } template forceinline void* Incremental::SupportEntry::operator new(size_t, Space& home) { return home.fl_alloc(); } template forceinline void Incremental::SupportEntry::dispose(Space& home) { home.fl_dispose(this,this); } template forceinline void Incremental::SupportEntry::dispose(Space& home, SupportEntry* l) { home.fl_dispose(this,l); } /* * Work entries * */ template forceinline Incremental::WorkEntry::WorkEntry(int i0, int n0, WorkEntry* n) : FreeList(n), i(i0), n(n0) {} template forceinline typename Incremental::WorkEntry* Incremental::WorkEntry::next(void) const { return static_cast(FreeList::next()); } template forceinline void Incremental::WorkEntry::next(WorkEntry* n) { return FreeList::next(n); } template forceinline void Incremental::WorkEntry::operator delete(void*) {} template forceinline void Incremental::WorkEntry::operator delete(void*, Space&) { GECODE_NEVER; } template forceinline void* Incremental::WorkEntry::operator new(size_t, Space& home) { return home.fl_alloc(); } template forceinline void Incremental::WorkEntry::dispose(Space& home) { home.fl_dispose(this,this); } /* * Work stack * */ template forceinline Incremental::Work::Work(void) : we(NULL) {} template forceinline bool Incremental::Work::empty(void) const { return we == NULL; } template forceinline void Incremental::Work::push(Space& home, int i, int n) { we = new (home) WorkEntry(i,n,we); } template forceinline void Incremental::Work::pop(Space& home, int& i, int& n) { WorkEntry* d = we; we = we->next(); i=d->i; n=d->n; d->dispose(home); } /* * Support management * */ template forceinline typename Incremental::SupportEntry* Incremental::support(int i, int n) { return support_data[(i*(ts()->domsize)) + (n - ts()->min)]; } template forceinline void Incremental::init_support(Space& home) { assert(support_data == NULL); int literals = static_cast(ts()->domsize*x.size()); support_data = home.alloc(literals); for (int i = literals; i--; ) support_data[i] = NULL; } template forceinline void Incremental::add_support(Space& home, Tuple l) { for (int i = x.size(); i--; ) { int pos = (i*static_cast(ts()->domsize)) + (l[i] - ts()->min); support_data[pos] = new (home) SupportEntry(l, support_data[pos]); } } template forceinline void Incremental::find_support(Space& home, Domain dom, int i, int n) { if (support(i,n) == NULL) { // Find support for value vv.val() in view i Tuple l = Base::find_support(dom,i,n - ts()->min); if (l == NULL) { // No possible supports left w_remove.push(home,i,n); } else { // Mark values in support as supported add_support(home,l); } } } template forceinline void Incremental::remove_support(Space& home, Tuple l, int i, int n) { (void) n; for (int j = x.size(); j--; ) { int v = l[j]; int ov = v - ts()->min; int pos = (j*(static_cast(ts()->domsize))) + ov; assert(support_data[pos] != NULL); SupportEntry** a = &(support_data[pos]); while ((*a)->t != l) { assert((*a)->next() != NULL); a = (*a)->nextRef(); } SupportEntry* old = *a; *a = (*a)->next(); old->dispose(home); if ((i != j) && (support_data[pos] == NULL)) w_support.push(home, j, v); } } /* * The propagator proper * */ template forceinline Incremental::Incremental(Home home, ViewArray& x, const TupleSet& t) : Base(home,x,t), support_data(NULL), unassigned(x.size()), ac(home) { init_support(home); // Post advisors for (int i = x.size(); i--; ) if (x[i].assigned()) { --unassigned; } else { x[i].subscribe(home,*new (home) SupportAdvisor(home,*this,ac,i)); } Region r(home); // Add initial supports BitSet* dom = r.alloc(x.size()); init_dom(home, dom); for (int i = x.size(); i--; ) for (ViewValues vv(x[i]); vv(); ++vv) find_support(home, dom, i, vv.val()); // Work to be done or subsumption if (!w_support.empty() || !w_remove.empty() || (unassigned == 0)) View::schedule(home,*this, (unassigned != x.size()) ? ME_INT_VAL : ME_INT_DOM); } template forceinline ExecStatus Incremental::post(Home home, ViewArray& x, const TupleSet& t) { // All variables in the correct domain for (int i = x.size(); i--; ) { GECODE_ME_CHECK(x[i].gq(home, t.min())); GECODE_ME_CHECK(x[i].lq(home, t.max())); } (void) new (home) Incremental(home,x,t); return ES_OK; } template forceinline Incremental::Incremental(Space& home, bool share, Incremental& p) : Base(home,share,p), support_data(NULL), unassigned(p.unassigned) { ac.update(home,share,p.ac); init_support(home); for (int i = static_cast(ts()->domsize*x.size()); i--; ) { SupportEntry** n = &(support_data[i]); SupportEntry* o = p.support_data[i]; while (o != NULL) { // Allocate new support entry SupportEntry* s = new (home) SupportEntry(o->t); // Link in support entry (*n) = s; n = s->nextRef(); // move to next one o = o->next(); } *n = NULL; } } template PropCost Incremental::cost(const Space&, const ModEventDelta& med) const { if (View::me(med) == ME_INT_VAL) return PropCost::quadratic(PropCost::HI,x.size()); else return PropCost::cubic(PropCost::HI,x.size()); } template Actor* Incremental::copy(Space& home, bool share) { return new (home) Incremental(home,share,*this); } template forceinline size_t Incremental::dispose(Space& home) { if (!home.failed()) { int literals = static_cast(ts()->domsize*x.size()); for (int i = literals; i--; ) if (support_data[i]) { SupportEntry* lastse = support_data[i]; while (lastse->next() != NULL) lastse = lastse->next(); support_data[i]->dispose(home, lastse); } home.rfree(support_data, sizeof(SupportEntry*)*literals); } ac.dispose(home); (void) Base::dispose(home); return sizeof(*this); } template ExecStatus Incremental::propagate(Space& home, const ModEventDelta&) { assert(!w_support.empty() || !w_remove.empty() || unassigned==0); // Set up datastructures // Bit-sets for amortized O(1) access to domains Region r(home); // Add initial supports BitSet* dom = r.alloc(x.size()); init_dom(home, dom); // Work loop while (!w_support.empty() || !w_remove.empty()) { while (!w_remove.empty()) { int i, n; w_remove.pop(home,i,n); // Work is still relevant if (dom[i].get(static_cast(n-ts()->min))) { GECODE_ME_CHECK(x[i].nq(home,n)); dom[i].clear(static_cast(n-ts()->min)); } } while (!w_support.empty()) { int i, n; w_support.pop(home,i,n); // Work is still relevant if (dom[i].get(static_cast(n-ts()->min))) find_support(home, dom, i, n); } } if (unassigned != 0) return ES_FIX; return home.ES_SUBSUMED(*this); } template ExecStatus Incremental::advise(Space& home, Advisor& _a, const Delta& d) { SupportAdvisor& a = static_cast(_a); ModEvent me = View::modevent(d); bool scheduled = !w_support.empty() || !w_remove.empty(); if (x[a.i].any(d)) { ViewValues vv(x[a.i]); for (int n = ts()->min; n <= ts()->max; n++) { if (vv() && (n == vv.val())) { ++vv; continue; } while (SupportEntry* s = support(a.i,n)) remove_support(home, s->t, a.i, n); } } else { for (int n = x[a.i].min(d); n <= x[a.i].max(d); n++) while (SupportEntry* s = support(a.i,n)) remove_support(home, s->t, a.i, n); } if (me == ME_INT_VAL) { --unassigned; // nothing to do or already scheduled // propagator is not subsumed since unassigned!=0 if (((w_support.empty() && w_remove.empty()) || scheduled) && (unassigned != 0)) return home.ES_FIX_DISPOSE(ac,a); else return home.ES_NOFIX_DISPOSE(ac,a); } else if ((w_support.empty() && w_remove.empty()) || scheduled) { // nothing to do or already scheduled return ES_FIX; } return ES_NOFIX; } }}} // STATISTICS: int-prop