/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Christian Schulte * * Copyright: * Christian Schulte, 2004 * * Last modified: * $Date: 2008-02-21 07:49:55 +0100 (Thu, 21 Feb 2008) $ by $Author: schulte $ * $Revision: 6262 $ * * This file is part of Gecode, the generic constraint * development environment: * http://www.gecode.org * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include namespace Gecode { namespace Int { namespace Extensional { /** * \brief States are described by number of incoming and outgoing edges */ class State { public: unsigned int i_deg; unsigned int o_deg; }; /** * \brief %Edge in the layered graph */ class Edge { public: State* i_state; ///< Pointer to in-state State* o_state; ///< Pointer to out-state Edge* next; ///< Next edge in support list /// Construct new edge and increment states Edge(State& i, State& o, Edge* n); static void operator delete(void*, size_t); static void operator delete(void*,Space*); static void* operator new(size_t, Space*); }; forceinline Edge::Edge(State& i, State& o, Edge* n) : i_state(&i), o_state(&o), next(n) { i_state->o_deg++; o_state->i_deg++; } forceinline void Edge::operator delete(void*, size_t) {} forceinline void Edge::operator delete(void*,Space*) {} forceinline void* Edge::operator new(size_t s, Space* home) { return home->alloc(s); } /// Support information for a value class Support { public: int val; ///< Supported value Edge* edges; ///< Supporting edges in layered graph }; /// Layer for a view in the layered graph class Layer { public: unsigned int size; ///< Number of supported values Support* support; ///< Supported values }; /// Iterator for telling variable domains by scanning support class LayerValues { private: const Support* s1; ///< Current support const Support* s2; ///< End of support public: /// Default constructor LayerValues(void); /// Initialize for support of layer \a l LayerValues(const Layer& l); /// Initialize for support of layer \a l void init(const Layer& l); /// Test whether more values supported bool operator()(void) const; /// Move to next supported value void operator++(void); /// Return supported value int val(void) const; }; forceinline LayerValues::LayerValues(void) {} forceinline LayerValues::LayerValues(const Layer& l) : s1(l.support), s2(l.support+l.size) {} forceinline void LayerValues::init(const Layer& l) { s1=l.support; s2=l.support+l.size; } forceinline bool LayerValues::operator()(void) const { return s1val; } /* * Index advisors * */ template forceinline LayeredGraph::Index::Index(Space* home, Propagator* p, Council& c, int i0) : Advisor(home,p,c), i(i0) {} template forceinline LayeredGraph::Index::Index(Space* home, bool share, Index& a) : Advisor(home,share,a), i(a.i) {} template forceinline void LayeredGraph::Index::dispose(Space* home, Council& c) { Advisor::dispose(home,c); } /* * Index ranges * */ template forceinline LayeredGraph::IndexRange::IndexRange(void) : _fst(INT_MAX), _lst(INT_MIN) {} template forceinline void LayeredGraph::IndexRange::reset(void) { _fst=INT_MAX; _lst=INT_MIN; } template forceinline void LayeredGraph::IndexRange::add(int i) { _fst=std::min(_fst,i); _lst=std::max(_lst,i); } template forceinline int LayeredGraph::IndexRange::fst(void) const { return _fst; } template forceinline int LayeredGraph::IndexRange::lst(void) const { return _lst; } /* * The layered graph * */ template forceinline bool LayeredGraph::constructed(void) const { return layers != NULL; } template forceinline void LayeredGraph::eliminate(void) { if (!constructed() || (layers[0].size > 1)) return; assert(layers[0].size == 1); // Skip all layers corresponding to assigned views int i = 1; while (layers[i].size == 1) i++; // There is only a single edge Edge* e = layers[i-1].support[0].edges; assert((e->next == NULL) && (e->o_state->i_deg == 1)); // Map the state address to the state start = static_cast(e->o_state-states) % dfa.n_states(); layers += i; x.drop_fst(i); for (Advisors as(c); as(); ++as) as.advisor()->i -= i; } template forceinline ExecStatus LayeredGraph::construct(Space* home) { int n = x.size(); layers = static_cast(home->alloc(sizeof(Layer)*(n+2)))+1; unsigned int n_states = dfa.n_states(); // Allocate memory states = static_cast (home->alloc(sizeof(State)*(n+1)*n_states)); // Initialize states (indegree and outdegree) for (int i = (n+1)*n_states; i--; ) states[i].i_deg = states[i].o_deg = 0; // Mark initial state as being reachable states[start].i_deg = 1; // Mark final states as reachable as well for (int s = dfa.final_fst(); s < dfa.final_lst(); s++) states[n*n_states + s].o_deg = 1; // Forward pass: add transitions for (int i=0; i(home->alloc(x[i].size()*sizeof(Support))); unsigned int j=0; // Enter links leaving reachable states (indegree != 0) for (ViewValues nx(x[i]); nx(); ++nx) { Edge* e = NULL; for (DFA::Transitions t(dfa,nx.val()); t(); ++t) if (states[i*n_states + t.i_state()].i_deg != 0) e = new (home) Edge(states[i*n_states + t.i_state()], states[(i+1)*n_states + t.o_state()], e); // Found support for value if (e != NULL) { layers[i].support[j].val = nx.val(); layers[i].support[j].edges = e; j++; } } if ((layers[i].size = j) == 0) return ES_FAILED; } // Backward pass: prune all transitions that do not lead to final state for (int i=n; i--; ) { unsigned int k=0; for (unsigned int j=0; jo_state->o_deg != 0) { // This state is still reachable, keep edge p = &e->next; } else { // Unreachable state, prune edge e->i_state->o_deg--; e->o_state->i_deg--; *p = e->next; } e = e->next; } while (e != NULL); // Write endmarker for edges *p = NULL; // Value has support, copy the support information if (layers[i].support[j].edges != NULL) layers[i].support[k++]=layers[i].support[j]; } if ((layers[i].size = k) == 0) return ES_FAILED; LayerValues lv(layers[i]); GECODE_ME_CHECK(x[i].narrow_v(home,lv,false)); } if (c.empty()) return ES_SUBSUMED(this,home); return ES_FIX; } template forceinline ExecStatus LayeredGraph::prune(Space* home) { // Forward pass for (int i=i_ch.fst(); i<=i_ch.lst(); i++) { bool i_mod = false; bool o_mod = false; unsigned int j=0; unsigned int k=0; unsigned int s=layers[i].size; do { // Some edges might have lost support Edge** p = &layers[i].support[j].edges; Edge* e = *p; do { if (e->i_state->i_deg == 0) { // Adapt states o_mod |= ((--e->i_state->o_deg) == 0); i_mod |= ((--e->o_state->i_deg) == 0); // Remove edge *p = e->next; } else { // Keep edge p = &e->next; } e = e->next; } while (e != NULL); // Write endmarker for edges *p=NULL; // Check whether value is still supported if (layers[i].support[j].edges == NULL) { layers[i].size--; GECODE_ME_CHECK(x[i].nq(home,layers[i].support[j++].val)); } else { layers[i].support[k++]=layers[i].support[j++]; } } while (j 0); // Update modification information if (o_mod) o_ch.add(i-1); if (i_mod) i_ch.add(i+1); } i_ch.reset(); // Backward pass for (int i=o_ch.lst(); i>=o_ch.fst(); i--) { bool o_mod = false; unsigned int j=0; unsigned int k=0; unsigned int s=layers[i].size; do { Edge** p = &layers[i].support[j].edges; Edge* e = *p; do { if (e->o_state->o_deg != 0) { // This state is still reachable, keep edge p = &e->next; } else { // Unreachable state, prune edge o_mod |= (--e->i_state->o_deg == 0); --e->o_state->i_deg; *p = e->next; } e = e->next; } while (e != NULL); // Write endmarker for edges *p = NULL; // Check whether value has still support if (layers[i].support[j].edges == NULL) { layers[i].size--; GECODE_ME_CHECK(x[i].nq(home,layers[i].support[j++].val)); } else { layers[i].support[k++]=layers[i].support[j++]; } } while (j 0); // Update modification information if (o_mod) o_ch.add(i-1); } o_ch.reset(); // Check subsumption if (c.empty()) return ES_SUBSUMED(this,home); return ES_FIX; } template ExecStatus LayeredGraph::advise(Space* home, Advisor* _a, const Delta* d) { Index* a = static_cast(_a); int i = a->i; bool i_mod = false; bool o_mod = false; Layer& l = layers[i]; if (!constructed()) goto nofix; if (l.size == x[i].size()) goto fix; if (View::modevent(d) == ME_INT_VAL) { int n = x[i].val(); unsigned int j=0; for (; l.support[j].val < n; j++) // Supported value not any longer in view for (Edge* e=l.support[j].edges; e!=NULL; e=e->next) { // Adapt states o_mod |= ((--e->i_state->o_deg) == 0); i_mod |= ((--e->o_state->i_deg) == 0); } assert(l.support[j].val == n); l.support[0] = l.support[j++]; unsigned int s=l.size; l.size = 1; for (; jnext) { // Adapt states o_mod |= ((--e->i_state->o_deg) == 0); i_mod |= ((--e->o_state->i_deg) == 0); } } else if (x[i].any(d)) { unsigned int j=0; unsigned int k=0; unsigned int s=l.size; for (ViewRanges rx(x[i]); rx() && (jnext) { // Adapt states o_mod |= ((--e->i_state->o_deg) == 0); i_mod |= ((--e->o_state->i_deg) == 0); } ++j; } else if (l.support[j].val > rx.max()) { ++rx; } else { l.support[k++]=l.support[j++]; } assert(k > 0); l.size = k; // Remove remaining values for (; jnext) { // Adapt states o_mod |= ((--e->i_state->o_deg) == 0); i_mod |= ((--e->o_state->i_deg) == 0); } } else { int min = x[i].min(d); unsigned int j=0; // Skip values smaller than min (to keep) for (; l.support[j].val < min; j++) {} int max = x[i].max(d); unsigned int k=j; unsigned int s=l.size; // Remove pruned values for (; (jnext) { // Adapt states o_mod |= ((--e->i_state->o_deg) == 0); i_mod |= ((--e->o_state->i_deg) == 0); } // Keep remaining values while (j 0); } if (!i_mod && !o_mod) goto fix; if (o_mod) o_ch.add(i-1); if (i_mod) i_ch.add(i+1); goto nofix; nofix: return (View::modevent(d) == ME_INT_VAL) ? ES_SUBSUMED_NOFIX(a,home,c) : ES_NOFIX; fix: if (View::modevent(d) == ME_INT_VAL) { a->dispose(home,c); return c.empty() ? ES_NOFIX : ES_FIX; } return ES_FIX; } template ExecStatus LayeredGraph::propagate(Space* home, ModEventDelta) { ExecStatus es = constructed() ? prune(home) : construct(home); return es; } template forceinline LayeredGraph::LayeredGraph(Space* home, ViewArray& x0, DFA& d) : Propagator(home), c(home), x(x0), dfa(d), start(0), layers(NULL) { assert(x.size() > 0); ModEvent me = ME_INT_BND; for (int i=x.size(); i--; ) if (x[i].assigned()) me = ME_INT_VAL; else x[i].subscribe(home, new (home) Index(home,this,c,i)); View::schedule(home,this,me); this->force(home); } template <> forceinline LayeredGraph::LayeredGraph(Space* home, ViewArray& x0, DFA& d) : Propagator(home), c(home), x(x0), dfa(d), start(0), layers(NULL) { assert(x.size() > 0); for (int i=x.size(); i--; ) if (!x[i].assigned()) x[i].subscribe(home, new (home) Index(home,this,c,i)); BoolView::schedule(home,this,ME_BOOL_VAL); this->force(home); } template forceinline size_t LayeredGraph::dispose(Space* home) { this->unforce(home); c.dispose(home); dfa.~DFA(); (void) Propagator::dispose(home); return sizeof(*this); } template ExecStatus LayeredGraph::post(Space* home, ViewArray& x, DFA& d) { if (x.size() == 0) { // Check whether the start state 0 is also a final state if ((d.final_fst() <= 0) && (d.final_lst() >= 0)) return ES_OK; return ES_FAILED; } assert(x.size() > 0); for (int i=x.size(); i--; ) { DFA::Symbols s(d); GECODE_ME_CHECK(x[i].inter_v(home,s,false)); } (void) new (home) LayeredGraph(home,x,d); return ES_OK; } template forceinline LayeredGraph::LayeredGraph(Space* home, bool share, LayeredGraph& p) : Propagator(home,share,p), layers(NULL) { assert(p.x.size() > 0); p.eliminate(); c.update(home,share,p.c); x.update(home,share,p.x); dfa.update(home,share,p.dfa); start = p.start; } template PropCost LayeredGraph::cost(ModEventDelta) const { return cost_hi(x.size(), PC_LINEAR_HI); } template Gecode::Support::Symbol LayeredGraph::ati(void) { return Reflection::mangle("Gecode::Int::Extensional::LayeredGraph"); } template Reflection::ActorSpec LayeredGraph::spec(const Space* home, Reflection::VarMap& m) const { Reflection::ActorSpec s(ati()); return s << x.spec(home, m) << dfa.spec(m); } template void LayeredGraph::post(Space* home, Reflection::VarMap& vars, const Reflection::ActorSpec& spec) { spec.checkArity(2); ViewArray x(home, vars, spec[0]); DFA dfa(vars, spec[1]); (void) new (home) LayeredGraph(home,x,dfa); } template Actor* LayeredGraph::copy(Space* home, bool share) { return new (home) LayeredGraph(home,share,*this); } }}} // STATISTICS: int-prop