// -*- 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 . //============================================================================= #ifndef __GECODE_DISJUNCTOR_HH__ #define __GECODE_DISJUNCTOR_HH__ #include #include #include namespace Gecode { namespace Disjunctor_ { using namespace generic_gecode; //========================================================================= // from a user perspective, a Disjunctor corresponds to a set of // speculative clauses: // // - when a non-committed clause fails, it is simply discarded // - when a single clause remains, it is committed // // from an implementation perspective, a Disjunctor is an object shared by // several clauses, that contains a counter keeping track of how many // clauses remain. when the counter reaches 1, the remaining clause // becomes committed. //========================================================================= // following the example in MPG struct Disjunctor: public LocalHandle { Disjunctor(); Disjunctor(Space& home); Disjunctor(const Disjunctor& d); int get() const; void incr(); void decr(); void dispose(Space& home); }; //========================================================================= // a Clause encapsulates the speculative execution of a set of propagators. // Therefore, these propagators must be posted in a separate (sub)space. // However they normally want to constrain variables of the original home // space: for each such variable X, a variable Y local to the subspace must // be created and used instead, and a forwarder must be created from X to // Y. A Clause is then a Propagator that subscribes to the Xs. Whenever a // X changes, the domains of the Xs are forwarded into the Ys and // constraint propagation is run in the subspace. When a clause is // committed, after propagation, the domains of Ys are forwarded back into // the Xs. //========================================================================= // TODO: copy (difficulty is forwarder list) class SubSpace; class Clause: public Propagator { Disjunctor disj; SubSpace*const subhome; public: Clause(Space& home_, Disjunctor disj_); Clause(Space& home, bool share, Clause& c); virtual Propagator* copy(Space& home, bool share); virtual size_t dispose(Space& home); virtual PropCost cost(const Space&, const ModEventDelta&) const; virtual ExecStatus propagate(Space& home, const ModEventDelta&); // user API operator GenericSpace&(); operator Space&(); operator Home(); GenericSpace* generic_space() const; Space* space() const; void forward(Space& home, IntVar outer, IntVar inner); void forward(Space& home, BoolVar outer, BoolVar inner); void forward(Space& home, SetVar outer, SetVar inner); protected: ExecStatus forward_in(); ExecStatus forward_out(Space& outer_home); bool committed() const; }; //========================================================================= // a SubSpace is the Space associated with a Clause. It also contains the // forwarder linked-list because we want it to manage the memory for that // list. //========================================================================= struct BasicForwarder; using Int::IntView; using Int::BoolView; using Set::SetView; class SubSpace: public GenericSpace { private: Space* homeDuringCloning; // linked-list of pairs of a variable in the parent space and a // corresponding variable in the subspace BasicForwarder* forwarder; // auxiliary methods for adding an entry to the forwarder list void forward(IntView outer, IntView inner); void forward(BoolView outer, BoolView inner); void forward(SetView outer, SetView inner); // for forwarding domains into and out of the subhome ExecStatus forward_in(); ExecStatus forward_out(Space&); // for cancelling subscriptions void cancel(Space& home, Clause&); // allow Clause to use this private API friend class Clause; public: SubSpace(); SubSpace(bool share, SubSpace& s); virtual Space* copy(bool share); SubSpace* copy(Space& home, bool share); }; }} namespace Gecode { using Disjunctor_::Disjunctor; class Clause { generic_gecode::GenericSpace& _home; Disjunctor_::Clause* _clause; public: Clause(generic_gecode::GenericSpace& home, Disjunctor disj); operator generic_gecode::GenericSpace&(); operator Space&(); operator Home(); generic_gecode::GenericSpace* generic_space(); generic_gecode::GenericSpace* generic_parent(); Space* space(); void forward(IntVar outer, IntVar inner); void forward(BoolVar outer, BoolVar inner); void forward(SetVar outer, SetVar inner); }; } #endif