/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack * * Copyright: * Guido Tack, 2011 * * Last modified: * $Date: 2011-08-25 00:34:16 +1000 (Thu, 25 Aug 2011) $ by $Author: tack $ * $Revision: 12346 $ * * 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. * */ namespace Gecode { namespace Set { namespace Rel { /** * \brief Representation of the characteristic functions of two sets */ class CharacteristicSets { protected: /// Size of the combined upper bounds unsigned int xsize; /// Storage for the characteristic functions Support::BitSetBase b; /// Elements in the combined upper bounds int* ub; /// Whether lower bound of x was updated bool xlm; /// Whether upper bound of x was updated bool xum; /// Whether lower bound of y was updated bool ylm; /// Whether upper bound of y was updated bool yum; /// Set bit \a i to value \a j void set(int i, bool j) { if (j) b.set(i); else b.clear(i); } /// \brief Value iterator for characteristic function class CSIter { public: /// Pointer to the underlying set CharacteristicSets* cs; /// Current position unsigned int i; /// Offset from start of bitset int xoff; /// Offset for each element (0=lower bound, 1=upper bound) int yoff; /// Move iterator to next element void operator++ (void) { i++; while (ixsize && !cs->b.get(xoff+2*i+yoff)) i++; } /// Default constructor CSIter(void) {} /// Constructor CSIter(CharacteristicSets& cs0, int xoff0, int yoff0) : cs(&cs0), i(-1), xoff(xoff0), yoff(yoff0) { ++(*this); } /// Test if iterator is finished bool operator() (void) const { return ixsize; } /// Value of current iterator position int val(void) const { return cs->ub[i]; } }; public: /// Constructor template CharacteristicSets(Region& re, View0 x, View1 y); /// Return minimum of element \a i for variable x bool xmin(int i) const { return b.get(2*i); } /// Return maximum of element \a i for variable x bool xmax(int i) const { return b.get(2*i+1); } /// Return minimum of element \a i for variable y bool ymin(int i) const { return b.get(2*xsize+2*i); } /// Return maximum of element \a i for variable y bool ymax(int i) const { return b.get(2*xsize+2*i+1); } /// Set minimum of element \a i for variable x to \a j void xmin(int i, bool j) { set(2*i,j); } /// Set maximum of element \a i for variable x to \a j void xmax(int i, bool j) { set(2*i+1,j); } /// Set minimum of element \a i for variable y to \a j void ymin(int i, bool j) { set(2*xsize+2*i,j); } /// Set maximum of element \a i for variable y to \a j void ymax(int i, bool j) { set(2*xsize+2*i+1,j); } /// Update upper bound of \f$x_i\f$ to \a j ModEvent xlq(int i, bool j) { if (!j) { if (xmin(i)) return ME_SET_FAILED; if (xmax(i)) { xmax(i,false); xum=true; } } return ME_SET_NONE; } /// Update lower bound of \f$x_i\f$ to \a j ModEvent xgq(int i, bool j) { if (j) { if (!xmax(i)) return ME_SET_FAILED; if (!xmin(i)) { xmin(i,true); xlm=true; } } return ME_SET_NONE; } /// Update upper bound of \f$y_i\f$ to \a j ModEvent ylq(int i, bool j) { if (!j) { if (ymin(i)) return ME_SET_FAILED; if (ymax(i)) { ymax(i,false); yum=true; } } return ME_SET_NONE; } /// Update lower bound of \f$y_i\f$ to \a j ModEvent ygq(int i, bool j) { if (j) { if (!ymax(i)) return ME_SET_FAILED; if (!ymin(i)) { ymin(i,true); ylm=true; } } return ME_SET_NONE; } /// Return size of combined upper bounds int size(void) const { return xsize; } /// Prune \a x and \a y using computed bounds template ExecStatus prune(Space& home, View0 x, View1 y) { if (xlm) { CSIter i(*this,0,0); Iter::Values::ToRanges ir(i); GECODE_ME_CHECK(x.includeI(home,ir)); } if (xum) { CSIter i(*this,0,1); Iter::Values::ToRanges ir(i); GECODE_ME_CHECK(x.intersectI(home,ir)); } if (ylm) { CSIter i(*this,2*xsize,0); Iter::Values::ToRanges ir(i); GECODE_ME_CHECK(y.includeI(home,ir)); } if (yum) { CSIter i(*this,2*xsize,1); Iter::Values::ToRanges ir(i); GECODE_ME_CHECK(y.intersectI(home,ir)); } return ES_OK; } }; template CharacteristicSets::CharacteristicSets(Region& re,View0 x, View1 y) : xlm(false), xum(false), ylm(false), yum(false) { LubRanges xlub(x); LubRanges ylub(y); Iter::Ranges::Union,LubRanges > xylub(xlub,ylub); Iter::Ranges::Cache xylubc(re,xylub); xsize = Iter::Ranges::size(xylubc); b.init(re,4*xsize); ub = re.alloc(xsize); xylubc.reset(); Iter::Ranges::ToValues xylubv(xylubc); LubRanges xur(x); GlbRanges xlr(x); LubRanges yur(y); GlbRanges ylr(y); Iter::Ranges::ToValues > xuv(xur); Iter::Ranges::ToValues > xlv(xlr); Iter::Ranges::ToValues > yuv(yur); Iter::Ranges::ToValues > ylv(ylr); for (int i=0; xylubv(); ++xylubv, ++i) { ub[i] = xylubv.val(); if (xlv() && xylubv.val()==xlv.val()) { b.set(2*i); ++xlv; } if (xuv() && xylubv.val()==xuv.val()) { b.set(2*i+1); ++xuv; } if (ylv() && xylubv.val()==ylv.val()) { b.set(2*xsize+2*i); ++ylv; } if (yuv() && xylubv.val()==yuv.val()) { b.set(2*xsize+2*i+1); ++yuv; } } } template forceinline Lq::Lq(Home home, View0 x, View1 y) : MixBinaryPropagator(home,x,y) {} template forceinline Lq::Lq(Space& home, bool share, Lq& p) : MixBinaryPropagator(home,share,p) {} template ExecStatus Lq::post(Home home, View0 x, View1 y) { if (strict) GECODE_ME_CHECK(y.cardMin(home,1)); (void) new (home) Lq(home,x,y); return ES_OK; } template Actor* Lq::copy(Space& home, bool share) { return new (home) Lq(home,share,*this); } template ExecStatus Lq::propagate(Space& home, const ModEventDelta&) { if ( (!strict) && x1.cardMax()==0) { GECODE_ME_CHECK(x0.cardMax(home,0)); } if (x0.cardMax()==0) { return home.ES_SUBSUMED(*this); } if (x0.glbMin() < x1.lubMin()) return ES_FAILED; if (x1.glbMin() < x0.lubMin()) return home.ES_SUBSUMED(*this); bool assigned = x0.assigned() && x1.assigned(); Region re(home); CharacteristicSets cs(re,x0,x1); /* * State 1 * */ int i=0; int firsti=0; int n=cs.size(); while ((i= GECODE_ME_CHECK(cs.xlq(i,cs.ymax(i))); GECODE_ME_CHECK(cs.ygq(i,cs.xmin(i))); i++; } if (i == n) {// case: $ if (strict) { return ES_FAILED; } else { GECODE_ES_CHECK(cs.prune(home,x0,x1)); return home.ES_SUBSUMED(*this); } } // Possible cases left: <, <=, > (yields failure), ? GECODE_ME_CHECK(cs.xlq(i,cs.ymax(i))); GECODE_ME_CHECK(cs.ygq(i,cs.xmin(i))); if (cs.xmax(i) < cs.ymin(i)) { // case: < (after tell) GECODE_ES_CHECK(cs.prune(home,x0,x1)); return home.ES_SUBSUMED(*this); } firsti=i; /* * State 2 * prefix: (?|<=) * */ i++; while ((i < n) && (cs.xmin(i) == cs.ymax(i)) && (cs.xmax(i) == cs.ymin(i))) { // case: = i++; } if (i == n) { // case: $ if (strict) goto rewrite_le; else goto rewrite_lq; } if (cs.xmax(i) < cs.ymin(i)) // case: < goto rewrite_lq; if (cs.xmin(i) > cs.ymax(i)) // case: > goto rewrite_le; if (cs.xmax(i) <= cs.ymin(i)) { // case: <= (invariant: not =, <) /* * State 3 * prefix: (?|<=),<= * */ i++; while ((i < n) && (cs.xmax(i) == cs.ymin(i))) {// case: <=, = i++; } if (i == n) { // case: $ if (strict) { GECODE_ES_CHECK(cs.prune(home,x0,x1)); return assigned ? home.ES_SUBSUMED(*this) : ES_NOFIX; } else { goto rewrite_lq; } } if (cs.xmax(i) < cs.ymin(i)) // case: < goto rewrite_lq; GECODE_ES_CHECK(cs.prune(home,x0,x1)); return assigned ? home.ES_SUBSUMED(*this) : ES_NOFIX; } if (cs.xmin(i) >= cs.ymax(i)) { // case: >= (invariant: not =, >) /* * State 4 * prefix: (?|<=) >= * */ i++; while ((i < n) && (cs.xmin(i) == cs.ymax(i))) { // case: >=, = i++; } if (i == n) { // case: $ if (strict) { goto rewrite_le; } else { GECODE_ES_CHECK(cs.prune(home,x0,x1)); return assigned ? home.ES_SUBSUMED(*this) : ES_NOFIX; } } if (cs.xmin(i) > cs.ymax(i)) // case: > goto rewrite_le; GECODE_ES_CHECK(cs.prune(home,x0,x1)); return assigned ? home.ES_SUBSUMED(*this) : ES_NOFIX; } GECODE_ES_CHECK(cs.prune(home,x0,x1)); return assigned ? home.ES_SUBSUMED(*this) : ES_NOFIX; rewrite_le: GECODE_ME_CHECK(cs.xlq(firsti,false)); GECODE_ME_CHECK(cs.ygq(firsti,true)); GECODE_ES_CHECK(cs.prune(home,x0,x1)); return home.ES_SUBSUMED(*this); rewrite_lq: GECODE_ES_CHECK(cs.prune(home,x0,x1)); return assigned ? home.ES_SUBSUMED(*this) : ES_NOFIX; } }}} // STATISTICS: set-prop