381 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			381 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // -*- 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); }
 | |
| 
 | |
| }
 |