381 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			381 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | // -*- 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 <http://www.gnu.org/licenses/>. | ||
|  | //============================================================================= | ||
|  | #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<DisjunctorObject*>(object())->n; } | ||
|  |     void Disjunctor::incr() { static_cast<DisjunctorObject*>(object())->n += 1; } | ||
|  |     void Disjunctor::decr() { static_cast<DisjunctorObject*>(object())->n -= 1; } | ||
|  |     void Disjunctor::dispose(Space& home) | ||
|  |     { static_cast<DisjunctorObject*>(object())->dispose(home); } | ||
|  | 
 | ||
|  |     //========================================================================= | ||
|  |     // Forwarder<View> | ||
|  |     //     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 <typename View> | ||
|  |     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<View>* fwd = new (inner_home) Forwarder<View>(); | ||
|  | 	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<Int::IntView> IntForwarder; | ||
|  |     typedef Forwarder<Int::BoolView> BoolForwarder; | ||
|  |     typedef Forwarder<Set::SetView> SetForwarder; | ||
|  | 
 | ||
|  |     //========================================================================= | ||
|  |     // IntForwarder | ||
|  |     //========================================================================= | ||
|  | 
 | ||
|  |     template <> | ||
|  |     ExecStatus IntForwarder::forward_in(Space& home) // inner home | ||
|  |     { | ||
|  |       Int::ViewRanges<Int::IntView> 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<Int::IntView> 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<Int::BoolView> r(outer); | ||
|  |       GECODE_ME_CHECK(inner.inter_r(home,r)); | ||
|  |       return ES_OK; | ||
|  |     } | ||
|  | 
 | ||
|  |     template <> | ||
|  |     void BoolForwarder::forward_out(Space& home) | ||
|  |     { | ||
|  |       Int::ViewRanges<Int::BoolView> 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<SetView> gr(outer); | ||
|  |       GECODE_ME_CHECK(inner.includeI(home,gr)); | ||
|  |       Set::LubRanges<SetView> 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<SetView> gr(inner); | ||
|  |       outer.includeI(home, gr); | ||
|  |       Set::LubRanges<SetView> 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<SubSpace*>(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); } | ||
|  | 
 | ||
|  | } |