// -*- c++ -*- //============================================================================= // Copyright (C) 2011 by Denys Duchier // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program. If not, see . //============================================================================= #include "disjunctor.hh" namespace Gecode { namespace Disjunctor_ { //========================================================================= // Disjunctor (following example in MPG) //========================================================================= struct DisjunctorObject: public LocalObject { int n; DisjunctorObject(Space& home) : LocalObject(home), n(0) {} DisjunctorObject(Space& home, bool share, DisjunctorObject& d) : LocalObject(home, share, d), n(d.n) {} virtual LocalObject* copy(Space& home, bool share) { return new (home) DisjunctorObject(home, share, *this); } virtual size_t dispose(Space&) { return sizeof(*this); } }; Disjunctor::Disjunctor(): LocalHandle() {} Disjunctor::Disjunctor(Space& home) : LocalHandle(new (home) DisjunctorObject(home)) {} Disjunctor::Disjunctor(const Disjunctor& d): LocalHandle(d) {} int Disjunctor::get() const { return static_cast(object())->n; } void Disjunctor::incr() { static_cast(object())->n += 1; } void Disjunctor::decr() { static_cast(object())->n -= 1; } void Disjunctor::dispose(Space& home) { static_cast(object())->dispose(home); } //========================================================================= // Forwarder // used to forward the domain of a view V1 into a view V2 located in a // subspace (the subspace of a speculative clause). V2 represents V1 in // that space. // // BasicForwarder // base class of all Forwarders. It declares the virtual functions // that must be implemented to do the actual work, and contains the pointer // implementing the singly-linked list of Forwarders associated with each // clause. It also redefines new and delete to manage memory in the // subspace. //========================================================================= struct BasicForwarder { BasicForwarder* next; BasicForwarder() : next(NULL) {} // forward V1's domain into V2. This is used each time the Clause (as a // a propagator) is woken to perform propagation. virtual ExecStatus forward_in(Space& inner_home) = 0; // forward V2's domain into V1. This is used after propagation in the // case where the Clause has been committed to (because it is the last // one remaining). virtual void forward_out(Space& outer_home) = 0; // needed by delete to know how much to free virtual size_t size() const = 0; // usage: new (home) FRWRDR(...); // to allocate the instance of FRWRDR on home's heap static void* operator new(size_t n, Space& home) { return home.ralloc(n); } // usage: delete (home) PTR; // to free the instance pointed to by PTR from home's heap static void operator delete(void* ptr, Space& home) { home.rfree(ptr, ((BasicForwarder*)ptr)->size()); } virtual BasicForwarder* copy(Space& outer_home, Space& inner_home, bool share) = 0; virtual void cancel(Space& home, Clause&) = 0; }; // Forwarder parametrized by View template struct Forwarder: public BasicForwarder { View outer; View inner; Forwarder(View v1, View v2): outer(v1), inner(v2) {} Forwarder() {} virtual ExecStatus forward_in(Space& home); virtual void forward_out(Space& home); virtual size_t size() const { return sizeof(*this); } virtual BasicForwarder* copy(Space& outer_home, Space& inner_home, bool share) { Forwarder* fwd = new (inner_home) Forwarder(); fwd->outer.update(outer_home, share, outer); fwd->inner.update(inner_home, share, inner); return fwd; } virtual void cancel(Space& home, Clause& c); }; // instances of Forwarder that we actually use typedef Forwarder IntForwarder; typedef Forwarder BoolForwarder; typedef Forwarder SetForwarder; //========================================================================= // IntForwarder //========================================================================= template <> ExecStatus IntForwarder::forward_in(Space& home) // inner home { Int::ViewRanges r(outer); GECODE_ME_CHECK(inner.inter_r(home,r)); return ES_OK; } template <> void IntForwarder::forward_out(Space& home) // outer home { // it is guaranteed by design that after successful propagation the // domain of the inner variable is a non-empty narrowing of the domain of // the outer variable. therefore, we can simply replace the domain of // the outer variable with the domain of the inner variable. Int::ViewRanges r(inner); outer.narrow_r(home, r, false); } template <> void IntForwarder::cancel(Space& home, Clause& c) { outer.cancel(home, c, Int::PC_INT_DOM); } //========================================================================= // BoolForwarder //========================================================================= template <> ExecStatus BoolForwarder::forward_in(Space& home) { Int::ViewRanges r(outer); GECODE_ME_CHECK(inner.inter_r(home,r)); return ES_OK; } template <> void BoolForwarder::forward_out(Space& home) { Int::ViewRanges r(inner); outer.narrow_r(home, r, false); } template <> void BoolForwarder::cancel(Space& home, Clause& c) { outer.cancel(home, c, Int::PC_INT_DOM); } //========================================================================= // SetForwarder //========================================================================= template <> ExecStatus SetForwarder::forward_in(Space& home) { Set::GlbRanges gr(outer); GECODE_ME_CHECK(inner.includeI(home,gr)); Set::LubRanges lr(outer); GECODE_ME_CHECK(inner.intersectI(home,lr)); GECODE_ME_CHECK(inner.cardMin(home, outer.cardMin())); GECODE_ME_CHECK(inner.cardMax(home, outer.cardMax())); return ES_OK; } template <> void SetForwarder::forward_out(Space& home) { Set::GlbRanges gr(inner); outer.includeI(home, gr); Set::LubRanges lr(inner); outer.intersectI(home, lr); outer.cardMin(home, inner.cardMin()); outer.cardMax(home, inner.cardMax()); } template <> void SetForwarder::cancel(Space& home, Clause& c) { outer.cancel(home, c, Set::PC_SET_ANY); } //========================================================================= // SubSpace //========================================================================= void SubSpace::forward(IntView outer, IntView inner) { BasicForwarder* fwd = new (*this) IntForwarder(outer, inner); fwd->next = forwarder; forwarder = fwd; } void SubSpace::forward(BoolView outer, BoolView inner) { BasicForwarder* fwd = new (*this) BoolForwarder(outer, inner); fwd->next = forwarder; forwarder = fwd; } void SubSpace::forward(SetView outer, SetView inner) { BasicForwarder* fwd = new (*this) SetForwarder(outer, inner); fwd->next = forwarder; forwarder = fwd; } ExecStatus SubSpace::forward_in() { for (BasicForwarder* p=forwarder; p!=NULL; p=p->next) GECODE_ES_CHECK(p->forward_in(*this)); return ES_OK; } ExecStatus SubSpace::forward_out(Space& home) // outer home { for (BasicForwarder* p=forwarder; p!=NULL; p=p->next) p->forward_out(home); return ES_OK; } SubSpace::SubSpace(): GenericSpace(), forwarder(NULL) {} SubSpace::SubSpace(bool share, SubSpace& s) : GenericSpace(share, s), forwarder(NULL) { BasicForwarder** prev = &forwarder; for (BasicForwarder* p=s.forwarder; p!=NULL; p=p->next) { BasicForwarder* fwd = p->copy(*s.homeDuringCloning, *this, share); *prev = fwd; prev = &fwd->next; } } Space* SubSpace::copy(bool share) { return new SubSpace(share,*this); } SubSpace* SubSpace::copy(Space& home, bool share) { homeDuringCloning = &home; return static_cast(clone(share)); } void SubSpace::cancel(Space& home, Clause& c) { for (BasicForwarder*p = forwarder; p!=NULL; p=p->next) p->cancel(home, c); } //========================================================================= // Clause //========================================================================= Clause::operator GenericSpace&() { return *subhome; } Clause::operator Space&() { return *subhome; } Clause::operator Home() { return *subhome; } GenericSpace* Clause::generic_space() const { return subhome; } Space* Clause::space() const { return subhome; } Clause::Clause(Space& home_, Disjunctor disj_) : Propagator(home_), disj(disj_), subhome(new SubSpace()) { disj.incr(); } Clause::Clause(Space& home, bool share, Clause& c) : Propagator(home, share, c), subhome(c.subhome->copy(home, share)) { disj.update(home, share, c.disj); } Propagator* Clause::copy(Space& home, bool share) { return new (home) Clause(home, share, *this); } void Clause::forward(Space& home, IntVar outer, IntVar inner) { IntView oview(outer); IntView iview(inner); subhome->forward(oview, iview); oview.subscribe(home, *this, Int::PC_INT_DOM); } void Clause::forward(Space& home, BoolVar outer, BoolVar inner) { BoolView oview(outer); BoolView iview(inner); subhome->forward(oview, iview); oview.subscribe(home, *this, Int::PC_INT_DOM); } void Clause::forward(Space& home, SetVar outer, SetVar inner) { SetView oview(outer); SetView iview(inner); subhome->forward(oview, iview); oview.subscribe(home, *this, Set::PC_SET_ANY); } ExecStatus Clause::forward_in() { return subhome->forward_in(); } ExecStatus Clause::forward_out(Space& home) // outer home { return subhome->forward_out(home); } inline bool Clause::committed() const { return disj.get() == 1; } ExecStatus Clause::propagate(Space& home, const ModEventDelta&) { if (forward_in() == ES_FAILED || subhome->status() == SS_FAILED ) { if (committed()) return ES_FAILED; disj.decr(); return home.ES_SUBSUMED(*this); } if (committed()) forward_out(home); // maybe do something clever about subsumption later return ES_FIX; } size_t Clause::dispose(Space& home) { subhome->cancel(home, *this); delete subhome; // the memory for the disj's LocalObject is not recovered (void) Propagator::dispose(home); return sizeof(*this); } PropCost Clause::cost(const Space&, const ModEventDelta&) const { // consider a clause to be crazy expensive return PropCost::crazy(PropCost::HI,10); } } //=========================================================================== // Clause (user API) //=========================================================================== Clause::Clause(generic_gecode::GenericSpace& home, Disjunctor disj) : _home(home), _clause(new (home) Disjunctor_::Clause(home, disj)) {} Clause::operator generic_gecode::GenericSpace&() { return *_clause; } Clause::operator Space&() { return *_clause; } Clause::operator Home() { return *_clause; } generic_gecode::GenericSpace* Clause::generic_space() { return _clause->generic_space(); } generic_gecode::GenericSpace* Clause::generic_parent() { return &_home; } Space* Clause::space() { return _clause->space(); } void Clause::forward(IntVar outer, IntVar inner) { _clause->forward(_home, outer, inner); } void Clause::forward(BoolVar outer, BoolVar inner) { _clause->forward(_home, outer, inner); } void Clause::forward(SetVar outer, SetVar inner) { _clause->forward(_home, outer, inner); } }