This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/packages/gecode/disjunctor.icc
2013-11-03 14:12:38 +00:00

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