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); }
|
|
|
|
}
|