ExecStatus ReEq<View,CtrlView,rm>::propagate(Space& home, const ModEventDelta&) { if (b.one()) { if (rm == RM_PMI) return home.ES_SUBSUMED(*this); GECODE_REWRITE(*this,(Eq<View,View>::post(home(*this),x0,x1))); } if (b.zero()) { if (rm == RM_IMP) return home.ES_SUBSUMED(*this); GECODE_REWRITE(*this,(Nq<View,View>::post(home(*this),x0,x1))); } switch (rtest_eq(x0,x1)) { case RT_TRUE: if (rm != RM_IMP) GECODE_ME_CHECK(b.one_none(home)); break; case RT_FALSE: if (rm != RM_PMI) GECODE_ME_CHECK(b.zero_none(home)); break; case RT_MAYBE: return ES_FIX; default: GECODE_NEVER; } return home.ES_SUBSUMED(*this); }
ExecStatus ReLq<View,CtrlView,rm>::propagate(Space& home, const ModEventDelta&) { if (b.one()) { if (rm != RM_PMI) GECODE_REWRITE(*this,Lq<View>::post(home(*this),x0,x1)); } else if (b.zero()) { if (rm != RM_IMP) GECODE_REWRITE(*this,Le<View>::post(home(*this),x1,x0)); } else { switch (rtest_lq(x0,x1)) { case RT_TRUE: if (rm != RM_IMP) GECODE_ME_CHECK(b.one_none(home)); break; case RT_FALSE: if (rm != RM_PMI) GECODE_ME_CHECK(b.zero_none(home)); break; case RT_MAYBE: if (!x0.assigned() || !x1.assigned()) return ES_FIX; else { if (rm != RM_IMP) GECODE_ME_CHECK(b.one_none(home)); break; } default: GECODE_NEVER; } } return home.ES_SUBSUMED(*this); }
ExecStatus ReEqBin<Val,A,B,Ctrl,rm>::propagate(Space& home, const ModEventDelta&) { if (b.zero()) { if (rm == RM_IMP) return home.ES_SUBSUMED(*this); GECODE_REWRITE(*this,(NqBin<Val,A,B>::post(home(*this),x0,x1,c))); } if (b.one()) { if (rm == RM_PMI) return home.ES_SUBSUMED(*this); GECODE_REWRITE(*this,(EqBin<Val,A,B>::post(home(*this),x0,x1,c))); } if ((x0.min() + x1.min() > c) || (x0.max() + x1.max() < c)) { if (rm != RM_PMI) GECODE_ME_CHECK(b.zero_none(home)); return home.ES_SUBSUMED(*this); } if (x0.assigned() && x1.assigned()) { assert(x0.val() + x1.val() == c); if (rm != RM_IMP) GECODE_ME_CHECK(b.one_none(home)); return home.ES_SUBSUMED(*this); } return ES_FIX; }
ExecStatus ReEq<View0,View1>::propagate(Space& home, const ModEventDelta&) { if (b.one()) GECODE_REWRITE(*this,(Eq<View0,View1>::post(home(*this),x0,x1))); if (b.zero()) GECODE_REWRITE(*this,(Distinct<View0,View1>::post(home(*this),x0,x1))); if (x0.assigned() && x1.assigned()) { // directly test x0==x1 GlbRanges<View0> x0lb(x0); GlbRanges<View1> x1lb(x1); for (; x0lb() && x1lb(); ++x0lb, ++x1lb) { if (x0lb.min() != x1lb.min() || x0lb.max() != x1lb.max()) { GECODE_ME_CHECK(b.zero_none(home)); return home.ES_SUBSUMED(*this); } } if (!x0lb() && !x1lb()) { GECODE_ME_CHECK(b.one_none(home)); return home.ES_SUBSUMED(*this); } else { GECODE_ME_CHECK(b.zero_none(home)); return home.ES_SUBSUMED(*this); } } // check whether cardinalities still allow equality if (x0.cardMin() > x1.cardMax() || x1.cardMin() > x0.cardMax()) { GECODE_ME_CHECK(b.zero_none(home)); return home.ES_SUBSUMED(*this); } // check glb(x0) subset lub(x1) GlbRanges<View0> x0lb(x0); LubRanges<View1> x1ub(x1); Iter::Ranges::Diff<GlbRanges<View0>, LubRanges<View1> > diff1(x0lb, x1ub); if ( diff1() ) { GECODE_ME_CHECK(b.zero_none(home)); return home.ES_SUBSUMED(*this); } // check glb(x1) subset lub(x0) GlbRanges<View1> x1lb(x1); LubRanges<View0> x0ub(x0); Iter::Ranges::Diff<GlbRanges<View1>, LubRanges<View0> > diff2(x1lb, x0ub); if ( diff2() ) { GECODE_ME_CHECK(b.zero_none(home)); return home.ES_SUBSUMED(*this); } return ES_FIX; }
ExecStatus ReSubset<View0,View1>::propagate(Space& home, const ModEventDelta&) { if (b.one()) GECODE_REWRITE(*this,(Subset<View0,View1>::post(home(*this),x0,x1))); if (b.zero()) GECODE_REWRITE(*this,(NoSubset<View0,View1>::post(home(*this),x0,x1))); // check whether cardinalities still allow subset if (x0.cardMin() > x1.cardMax()) { GECODE_ME_CHECK(b.zero_none(home)); return home.ES_SUBSUMED(*this); } // check lub(x0) subset glb(x1) { LubRanges<View0> x0ub(x0); GlbRanges<View1> x1lb(x1); Iter::Ranges::Diff<LubRanges<View0>,GlbRanges<View1> > d(x0ub,x1lb); if (!d()) { GECODE_ME_CHECK(b.one_none(home)); return home.ES_SUBSUMED(*this); } } // check glb(x0) subset lub(x1) { GlbRanges<View0> x0lb(x0); LubRanges<View1> x1ub(x1); Iter::Ranges::Diff<GlbRanges<View0>,LubRanges<View1> > d(x0lb,x1ub); if (d()) { GECODE_ME_CHECK(b.zero_none(home)); return home.ES_SUBSUMED(*this); } else if (x0.assigned() && x1.assigned()) { GECODE_ME_CHECK(b.one_none(home)); return home.ES_SUBSUMED(*this); } } if (x0.cardMin() > 0) { LubRanges<View0> x0ub(x0); LubRanges<View1> x1ub(x1); Iter::Ranges::Inter<LubRanges<View0>,LubRanges<View1> > i(x0ub,x1ub); if (!i()) { GECODE_ME_CHECK(b.zero_none(home)); return home.ES_SUBSUMED(*this); } } return ES_FIX; }
ExecStatus Distinct<View0,View1>::propagate(Space& home, const ModEventDelta&) { assert(x0.assigned()||x1.assigned()); if (x0.assigned()) { GlbRanges<View0> xr(x0); IntSet xs(xr); ConstSetView cv(home, xs); GECODE_REWRITE(*this,(DistinctDoit<View1>::post(home(*this),x1,cv))); } else { GlbRanges<View1> yr(x1); IntSet ys(yr); ConstSetView cv(home, ys); GECODE_REWRITE(*this,(DistinctDoit<View0>::post(home(*this),x0,cv))); } }
ExecStatus EqBoolView<XV,YV>::propagate(Space& home, const ModEventDelta&) { int n = x.size(); for (int i = n; i--; ) if (x[i].one()) { x[i]=x[--n]; c--; } else if (x[i].zero()) { x[i]=x[--n]; } x.size(n); GECODE_ME_CHECK(y.lq(home,n-c)); GECODE_ME_CHECK(y.gq(home,-c)); if (n == 0) return home.ES_SUBSUMED(*this); if (y.min()+c == n) { assert(y.assigned()); for (int i = n; i--; ) GECODE_ME_CHECK(x[i].one_none(home)); return home.ES_SUBSUMED(*this); } if (y.max()+c == 0) { assert(y.assigned()); for (int i = n; i--; ) GECODE_ME_CHECK(x[i].zero_none(home)); return home.ES_SUBSUMED(*this); } if (y.assigned()) GECODE_REWRITE(*this,EqBoolInt<XV>::post(home(*this),x,y.val()+c)); return ES_FIX; }
ExecStatus ManProp<ManTask,Cap>::propagate(Space& home, const ModEventDelta& med) { // Only bounds changes? if (Int::IntView::me(med) != Int::ME_INT_DOM) GECODE_ES_CHECK(overload(home,c.max(),t)); GECODE_ES_CHECK(edgefinding(home,c.max(),t)); bool subsumed; ExecStatus es = basic(home,subsumed,c,t); GECODE_ES_CHECK(es); if (subsumed) return home.ES_SUBSUMED(*this); if (Cap::varderived() && c.assigned() && c.val()==1) { // Check that tasks do not overload resource for (int i=t.size(); i--; ) if (t[i].c() > 1) return ES_FAILED; // Rewrite to unary resource constraint TaskArray<typename TaskTraits<ManTask>::UnaryTask> ut(home,t.size()); for (int i=t.size(); i--;) ut[i]=t[i]; GECODE_REWRITE(*this, (Unary::ManProp<typename TaskTraits<ManTask>::UnaryTask> ::post(home(*this),ut))); } else { return es; } }
ExecStatus ManProp<ManTask,Cap,PL>::propagate(Space& home, const ModEventDelta& med) { // Only bounds changes? if (IntView::me(med) != ME_INT_DOM) GECODE_ES_CHECK(overload(home,c.max(),t)); if (PL::advanced) GECODE_ES_CHECK(edgefinding(home,c.max(),t)); if (PL::basic) GECODE_ES_CHECK(timetabling(home,*this,c,t)); if (Cap::varderived() && c.assigned() && (c.val() == 1)) { // Check that tasks do not overload resource for (int i=t.size(); i--; ) if (t[i].c() > 1) return ES_FAILED; // Rewrite to unary resource constraint TaskArray<typename TaskTraits<ManTask>::UnaryTask> ut(home,t.size()); for (int i=t.size(); i--;) ut[i]=t[i]; GECODE_REWRITE(*this, (Unary::ManProp<typename TaskTraits<ManTask>::UnaryTask,PL> ::post(home(*this),ut))); } if (!PL::basic && c.assigned()) GECODE_ES_CHECK(subsumed(home,*this,c.val(),t)); return ES_NOFIX; }
ExecStatus IteBnd<View>::propagate(Space& home, const ModEventDelta&) { if (b.one()) GECODE_REWRITE(*this,(Rel::EqBnd<View,View>::post(home(*this),x2,x0))); if (b.zero()) GECODE_REWRITE(*this,(Rel::EqBnd<View,View>::post(home(*this),x2,x1))); GECODE_ME_CHECK(x2.lq(home,std::max(x0.max(),x1.max()))); GECODE_ME_CHECK(x2.gq(home,std::min(x0.min(),x1.min()))); RelTest eq20 = rtest_eq_bnd(x2,x0); RelTest eq21 = rtest_eq_bnd(x2,x1); if ((eq20 == RT_FALSE) && (eq21 == RT_FALSE)) return ES_FAILED; if (eq20 == RT_FALSE) { GECODE_ME_CHECK(b.zero_none(home)); if (eq21 == RT_TRUE) return home.ES_SUBSUMED(*this); else GECODE_REWRITE(*this,(Rel::EqBnd<View,View>::post(home(*this),x2,x1))); } if (eq21 == RT_FALSE) { GECODE_ME_CHECK(b.one_none(home)); if (eq20 == RT_TRUE) return home.ES_SUBSUMED(*this); else GECODE_REWRITE(*this,(Rel::EqBnd<View,View>::post(home(*this),x2,x0))); } if ((eq20 == RT_TRUE) && (eq21 == RT_TRUE)) return home.ES_SUBSUMED(*this); return ES_FIX; }
ExecStatus ReLqBin<Val,A,B,rm>::propagate(Space& home, const ModEventDelta&) { if (b.one()) { if (rm == RM_PMI) return home.ES_SUBSUMED(*this); GECODE_REWRITE(*this,(LqBin<Val,A,B>::post(home(*this),x0,x1,c))); } if (b.zero()) { if (rm == RM_IMP) return home.ES_SUBSUMED(*this); GECODE_REWRITE(*this,(GqBin<Val,A,B>::post(home(*this),x0,x1,c+1))); } if (x0.max() + x1.max() <= c) { if (rm != RM_IMP) GECODE_ME_CHECK(b.one_none(home)); return home.ES_SUBSUMED(*this); } if (x0.min() + x1.min() > c) { if (rm != RM_PMI) GECODE_ME_CHECK(b.zero_none(home)); return home.ES_SUBSUMED(*this); } return ES_FIX; }
ExecStatus Pair::propagate(Space& home, const ModEventDelta&) { Region r(home); if (x0.assigned()) { // Bitset for supported div and mod values Support::BitSet<Region> d(r,static_cast<unsigned int>((x2.max() / w)+1)); for (ViewValues<IntView> i(x2); i(); ++i) { d.set(static_cast<unsigned int>(i.val() / w)); } Iter::Values::BitSet<Support::BitSet<Region> > id(d,x1.min(),x1.max()); GECODE_ME_CHECK(x1.inter_v(home,id,false)); } else { // Bitset for supported div and mod values Support::BitSet<Region> d(r,static_cast<unsigned int>((x2.max() / w)+1)), m(r,static_cast<unsigned int>(w)); for (ViewValues<IntView> i(x2); i(); ++i) { d.set(static_cast<unsigned int>(i.val() / w)); m.set(static_cast<unsigned int>(i.val() % w)); } Iter::Values::BitSet<Support::BitSet<Region> > im(m,x0.min(),x0.max()); GECODE_ME_CHECK(x0.inter_v(home,im,false)); Iter::Values::BitSet<Support::BitSet<Region> > id(d,x1.min(),x1.max()); GECODE_ME_CHECK(x1.inter_v(home,id,false)); } if (x0.assigned() && x1.assigned()) { GECODE_ME_CHECK(x2.eq(home,x0.val()+w*x1.val())); return home.ES_SUBSUMED(*this); } else if (x1.assigned()) { OffsetView x0x1w(x0,x1.val()*w); GECODE_REWRITE(*this,(Rel::EqDom<OffsetView,IntView> ::post(home(*this),x0x1w,x2))); } PairValues xy(x0,x1,w); GECODE_ME_CHECK(x2.inter_v(home,xy,false)); if (x2.assigned()) { GECODE_ME_CHECK(x0.eq(home,x2.val() % w)); GECODE_ME_CHECK(x1.eq(home,static_cast<int>(x2.val() / w))); return home.ES_SUBSUMED(*this); } return ES_NOFIX; }
ExecStatus LqView<VX,VY,VZ,shr>::propagate(Space& home, const ModEventDelta&) { count(home); GECODE_ME_CHECK(z.gq(home,atleast())); if (z.max() == atleast()) { GECODE_ES_CHECK(post_false(home,x,y)); return home.ES_SUBSUMED(*this); } if (x.size() == 0) return home.ES_SUBSUMED(*this); if (z.assigned()) { VY yc(y); GECODE_REWRITE(*this,(LqInt<VX,VY>::post(home(*this),x,yc,z.val()+c))); } return shr ? ES_NOFIX : ES_FIX; }
ExecStatus EqView<VX,VY,VZ,shr,dom>::propagate(Space& home, const ModEventDelta&) { count(home); GECODE_ME_CHECK(z.gq(home,atleast())); GECODE_ME_CHECK(z.lq(home,atmost())); if (z.assigned()) { if (z.val() == atleast()) { GECODE_ES_CHECK(post_false(home,x,y)); return home.ES_SUBSUMED(*this); } if (z.val() == atmost()) { GECODE_ES_CHECK(post_true(home,x,y)); return home.ES_SUBSUMED(*this); } if (!dom || (vtd(y) != VTD_VARVIEW)) { VY yc(y); GECODE_REWRITE(*this,(EqInt<VX,VY> ::post(home(*this),x,yc,z.val()+c))); } } if (dom && (vtd(y) == VTD_VARVIEW) && (z.min() > 0)) { /* * Only if the propagator is at fixpoint here, continue * when things are shared: the reason is that prune * requires that the views in x overlap with y! */ if (shr && (VX::me(Propagator::modeventdelta()) != ME_INT_NONE)) return ES_NOFIX; GECODE_ES_CHECK(prune(home,x,y)); return ES_NOFIX; } return shr ? ES_NOFIX : ES_FIX; }
ExecStatus Subset<View0,View1>::propagate(Space& home, const ModEventDelta&) { bool oneassigned = x0.assigned() || x1.assigned(); unsigned int x0glbsize; do { GlbRanges<View0> x0lb(x0); GECODE_ME_CHECK ( x1.includeI(home,x0lb) ); GECODE_ME_CHECK ( x1.cardMin(home,x0.cardMin()) ); LubRanges<View1> x1ub(x1); x0glbsize = x0.glbSize(); GECODE_ME_CHECK ( x0.intersectI(home,x1ub) ); GECODE_ME_CHECK ( x0.cardMax(home,x1.cardMax()) ); } while (x0.glbSize() > x0glbsize); if (x0.cardMin() == x1.cardMax()) GECODE_REWRITE(*this,(Eq<View0,View1>::post(home(*this),x0,x1))); if (shared(x0,x1)) { return oneassigned ? home.ES_SUBSUMED(*this) : ES_NOFIX; } return (x0.assigned() || x1.assigned()) ? home.ES_SUBSUMED(*this) : ES_FIX; }
forceinline ExecStatus IntBase<VY>::prune_upper(Space& home, Graph& g) { if (!g.initialized()) { g.init(home,vs,x); } else { g.purge(); g.sync(home); } GECODE_ME_CHECK(y.lq(home, g.size())); if (y.min() == g.size()) { // All values must be taken on if (vs.size() + x.size() == g.size()) { // This is in fact a distinct, simplify and rewrite for (int i=x.size(); i--; ) { ValSet::Ranges vsr(vs); GECODE_ME_CHECK(x[i].minus_r(home, vsr, false)); } GECODE_REWRITE(*this,Distinct::Dom<IntView>::post(home,x)); } if (g.mark(home)) GECODE_ES_CHECK(g.prune(home)); } return ES_OK; }
ExecStatus ReLq<View0,View1,strict>::propagate(Space& home, const ModEventDelta&) { if (b.one()) GECODE_REWRITE(*this,(Lq<View0,View1,strict>::post(home(*this),x0,x1))); if (b.zero()) GECODE_REWRITE(*this,(Lq<View1,View0,!strict>::post(home(*this),x1,x0))); if (x0.cardMax() == 0) { if ( (!strict) || x1.cardMin() > 0) { GECODE_ME_CHECK(b.one_none(home)); return home.ES_SUBSUMED(*this); } if (strict && x1.cardMax() == 0) { GECODE_ME_CHECK(b.zero_none(home)); return home.ES_SUBSUMED(*this); } } if (x0.assigned() && x1.assigned()) { // directly test x0<=x1 int min01; { GlbRanges<View0> x0l(x0); GlbRanges<View1> x1l(x1); Iter::Ranges::Diff<GlbRanges<View1>,GlbRanges<View0> > d(x1l,x0l); if (!d()) { if ((!strict) && x0.cardMax() == x1.cardMax()) { // equal GECODE_ME_CHECK(b.one_none(home)); } else { // subset GECODE_ME_CHECK(b.zero_none(home)); } return home.ES_SUBSUMED(*this); } min01 = d.min(); } int min10; { GlbRanges<View0> x0l(x0); GlbRanges<View1> x1l(x1); Iter::Ranges::Diff<GlbRanges<View0>,GlbRanges<View1> > d(x0l,x1l); if (!d()) { if (strict && x0.cardMax() == x1.cardMax()) { // equal GECODE_ME_CHECK(b.zero_none(home)); } else { // subset GECODE_ME_CHECK(b.one_none(home)); } return home.ES_SUBSUMED(*this); } min10 = d.min(); } assert(min01 != min10); if (min01<min10) { GECODE_ME_CHECK(b.one_none(home)); } else { GECODE_ME_CHECK(b.zero_none(home)); } return home.ES_SUBSUMED(*this); } // min(x0lb - x1ub) < min(x1ub) -> b=0 if (x1.cardMax() > 0) { GlbRanges<View0> x0l(x0); LubRanges<View1> x1u(x1); int x1umin=x1u.min(); Iter::Ranges::Diff<GlbRanges<View0>,LubRanges<View1> > d(x0l,x1u); if (d() && d.min() < x1umin) { GECODE_ME_CHECK(b.zero_none(home)); return home.ES_SUBSUMED(*this); } } // min(x1lb - x0ub) < min(x0ub) -> b=1 if (x0.cardMax() > 0) { LubRanges<View0> x0u(x0); GlbRanges<View1> x1l(x1); int x0umin=x0u.min(); Iter::Ranges::Diff<GlbRanges<View1>,LubRanges<View0> > d(x1l,x0u); if (d() && d.min() < x0umin) { GECODE_ME_CHECK(b.one_none(home)); return home.ES_SUBSUMED(*this); } } return ES_FIX; }
ExecStatus ReProp<View,rm>::propagate(Space& home, const ModEventDelta& med) { // Add assigned views to value set if (View::me(med) == ME_INT_VAL) add(home,vs,x); if (b.one()) { if (rm == RM_PMI) return home.ES_SUBSUMED(*this); ValSet vsc(vs); vs.flush(); GECODE_REWRITE(*this,Prop<View>::post(home,vsc,x,y)); } if (b.zero()) { if (rm != RM_IMP) { ValSet::Ranges vsr(vs); GECODE_ME_CHECK(y.minus_r(home,vsr,false)); for (int i=x.size(); i--; ) GECODE_ES_CHECK(Rel::Nq<View>::post(home,x[i],y)); } return home.ES_SUBSUMED(*this); } // Eliminate views from x eliminate(home); switch (vs.compare(y)) { case Iter::Ranges::CS_SUBSET: if (rm != RM_IMP) GECODE_ME_CHECK(b.one(home)); return home.ES_SUBSUMED(*this); case Iter::Ranges::CS_DISJOINT: if (x.size() == 0) { if (rm != RM_PMI) GECODE_ME_CHECK(b.zero(home)); return home.ES_SUBSUMED(*this); } break; case Iter::Ranges::CS_NONE: break; default: GECODE_NEVER; } // Check whether y is in union of x and value set if (x.size() > 0) { Region r(home); ValSet::Ranges vsr(vs); ViewRanges<View> xsr(x[x.size()-1]); Iter::Ranges::NaryUnion u(r,vsr,xsr); for (int i=x.size()-1; i--; ) { ViewRanges<View> xir(x[i]); u |= xir; } ViewRanges<View> yr(y); if (Iter::Ranges::disjoint(u,yr)) { if (rm != RM_PMI) GECODE_ME_CHECK(b.zero(home)); return home.ES_SUBSUMED(*this); } } return ES_FIX; }
ExecStatus IteDom<View>::propagate(Space& home, const ModEventDelta& med) { if (b.one()) GECODE_REWRITE(*this,(Rel::EqDom<View,View>::post(home(*this),x2,x0))); if (b.zero()) GECODE_REWRITE(*this,(Rel::EqDom<View,View>::post(home(*this),x2,x1))); GECODE_ME_CHECK(x2.lq(home,std::max(x0.max(),x1.max()))); GECODE_ME_CHECK(x2.gq(home,std::min(x0.min(),x1.min()))); if (View::me(med) != ME_INT_DOM) { RelTest eq20 = rtest_eq_bnd(x2,x0); RelTest eq21 = rtest_eq_bnd(x2,x1); if ((eq20 == RT_FALSE) && (eq21 == RT_FALSE)) return ES_FAILED; if (eq20 == RT_FALSE) { GECODE_ME_CHECK(b.zero_none(home)); if (eq21 == RT_TRUE) return home.ES_SUBSUMED(*this); else GECODE_REWRITE(*this, (Rel::EqDom<View,View>::post(home(*this),x2,x1))); } if (eq21 == RT_FALSE) { GECODE_ME_CHECK(b.one_none(home)); if (eq20 == RT_TRUE) return home.ES_SUBSUMED(*this); else GECODE_REWRITE(*this, (Rel::EqDom<View,View>::post(home(*this),x2,x0))); } if ((eq20 == RT_TRUE) && (eq21 == RT_TRUE)) return home.ES_SUBSUMED(*this); return home.ES_FIX_PARTIAL(*this,View::med(ME_INT_DOM)); } RelTest eq20 = rtest_eq_dom(x2,x0); RelTest eq21 = rtest_eq_dom(x2,x1); if ((eq20 == RT_FALSE) && (eq21 == RT_FALSE)) return ES_FAILED; if (eq20 == RT_FALSE) { GECODE_ME_CHECK(b.zero_none(home)); if (eq21 == RT_TRUE) return home.ES_SUBSUMED(*this); else GECODE_REWRITE(*this, (Rel::EqDom<View,View>::post(home(*this),x2,x1))); } if (eq21 == RT_FALSE) { GECODE_ME_CHECK(b.one_none(home)); if (eq20 == RT_TRUE) return home.ES_SUBSUMED(*this); else GECODE_REWRITE(*this, (Rel::EqDom<View,View>::post(home(*this),x2,x0))); } assert((eq20 != RT_TRUE) || (eq21 != RT_TRUE)); ViewRanges<View> r0(x0), r1(x1); Iter::Ranges::Union<ViewRanges<View>,ViewRanges<View> > u(r0,r1); if (!same(x0,x2) && !same(x1,x2)) GECODE_ME_CHECK(x2.inter_r(home,u,false)); else GECODE_ME_CHECK(x2.inter_r(home,u,true)); return ES_FIX; }
ExecStatus ElementUnion<SView,RView>::propagate(Space& home, const ModEventDelta&) { Region r(home); int n = iv.size(); bool loopVar; do { loopVar = false; // Cache the upper bound iterator, as we have to // modify the upper bound while iterating LubRanges<RView> x1ub(x1); Iter::Ranges::Cache<LubRanges<RView> > x1ubc(r,x1ub); Iter::Ranges::ToValues<Iter::Ranges::Cache<LubRanges<RView> > > vx1ub(x1ubc); GlbRanges<RView> x1lb(x1); Iter::Ranges::Cache<GlbRanges<RView> > x1lbc(r,x1lb); Iter::Ranges::ToValues<Iter::Ranges::Cache<GlbRanges<RView> > > vx1(x1lbc); // In the first iteration, compute in before[i] the union // of all the upper bounds of the x_i. At the same time, // exclude inconsistent x_i from x1 and remove them from // the list, cancel their dependencies. GLBndSet sofarBefore(home); LUBndSet selectedInter(home, IntSet (Limits::min, Limits::max)); GLBndSet* before = static_cast<GLBndSet*>(r.ralloc(sizeof(GLBndSet)*n)); int j = 0; int i = 0; unsigned int maxCard = 0; unsigned int minCard = Limits::card; while ( vx1ub() ) { // Remove vars at indices not in the upper bound if (iv[i].idx < vx1ub.val()) { iv[i].view.cancel(home,*this, PC_SET_ANY); ++i; continue; } assert(iv[i].idx == vx1ub.val()); iv[j] = iv[i]; SView candidate = iv[j].view; int candidateInd = iv[j].idx; // inter = glb(candidate) & complement(lub(x0)) GlbRanges<SView> candlb(candidate); LubRanges<SView> x0ub(x0); Iter::Ranges::Diff<GlbRanges<SView>, LubRanges<SView> > diff(candlb, x0ub); bool selectSingleInconsistent = false; if (x1.cardMax() <= 1) { GlbRanges<SView> x0lb(x0); LubRanges<SView> candub(candidate); Iter::Ranges::Diff<GlbRanges<SView>, LubRanges<SView> > diff2(x0lb, candub); selectSingleInconsistent = diff2() || candidate.cardMax() < x0.cardMin(); } // exclude inconsistent x_i // an x_i is inconsistent if // * at most one x_i can be selected and there are // elements in x_0 that can't be in x_i // (selectSingleInconsistent) // * its min cardinality is greater than maxCard of x0 // * inter is not empty (there are elements in x_i // that can't be in x_0) if (selectSingleInconsistent || candidate.cardMin() > x0.cardMax() || diff()) { ModEvent me = (x1.exclude(home,candidateInd)); loopVar |= me_modified(me); GECODE_ME_CHECK(me); iv[j].view.cancel(home,*this, PC_SET_ANY); ++i; ++vx1ub; continue; } else { // if x_i is consistent, check whether we know // that its index is in x1 if (vx1() && vx1.val()==candidateInd) { // x0 >= candidate, candidate <= x0 GlbRanges<SView> candlb(candidate); ModEvent me = x0.includeI(home,candlb); loopVar |= me_modified(me); GECODE_ME_CHECK(me); LubRanges<SView> x0ub(x0); me = candidate.intersectI(home,x0ub); loopVar |= me_modified(me); GECODE_ME_CHECK(me); ++vx1; } new (&before[j]) GLBndSet(home); before[j].update(home,sofarBefore); LubRanges<SView> cub(candidate); sofarBefore.includeI(home,cub); GlbRanges<SView> clb(candidate); selectedInter.intersectI(home,clb); maxCard = std::max(maxCard, candidate.cardMax()); minCard = std::min(minCard, candidate.cardMin()); } ++vx1ub; ++i; ++j; } // cancel the variables with index greater than // max of lub(x1) for (int k=i; k<n; k++) { iv[k].view.cancel(home,*this, PC_SET_ANY); } n = j; iv.size(n); if (x1.cardMax()==0) { // Selector is empty, hence the result must be empty { GECODE_ME_CHECK(x0.cardMax(home,0)); } for (int i=n; i--;) before[i].dispose(home); return home.ES_SUBSUMED(*this); } if (x1.cardMin() > 0) { // Selector is not empty, hence the intersection of the // possibly selected lower bounds is contained in x0 BndSetRanges si(selectedInter); ModEvent me = x0.includeI(home, si); loopVar |= me_modified(me); GECODE_ME_CHECK(me); me = x0.cardMin(home, minCard); loopVar |= me_modified(me); GECODE_ME_CHECK(me); } selectedInter.dispose(home); if (x1.cardMax() <= 1) { ModEvent me = x0.cardMax(home, maxCard); loopVar |= me_modified(me); GECODE_ME_CHECK(me); } { // x0 <= sofarBefore BndSetRanges sfB(sofarBefore); ModEvent me = x0.intersectI(home,sfB); loopVar |= me_modified(me); GECODE_ME_CHECK(me); } sofarBefore.dispose(home); GLBndSet sofarAfter(home); // In the second iteration, this time backwards, compute // sofarAfter as the union of all lub(x_j) with j>i for (int i=n; i--;) { // TODO: check for size of universe here? // if (sofarAfter.size() == 0) break; // extra = inter(before[i], sofarAfter) - lub(x0) BndSetRanges b(before[i]); BndSetRanges s(sofarAfter); GlbRanges<SView> x0lb(x0); Iter::Ranges::Union<BndSetRanges, BndSetRanges> inter(b,s); Iter::Ranges::Diff<GlbRanges<SView>, Iter::Ranges::Union<BndSetRanges,BndSetRanges> > diff(x0lb, inter); if (diff()) { ModEvent me = (x1.include(home,iv[i].idx)); loopVar |= me_modified(me); GECODE_ME_CHECK(me); // candidate != extra me = iv[i].view.includeI(home,diff); loopVar |= me_modified(me); GECODE_ME_CHECK(me); } LubRanges<SView> iviub(iv[i].view); sofarAfter.includeI(home,iviub); before[i].dispose(home); } sofarAfter.dispose(home); } while (loopVar); // Test whether we determined x1 without determining x0 if (x1.assigned() && !x0.assigned()) { int ubsize = static_cast<int>(x1.lubSize()); if (ubsize > 2) { assert(ubsize==n); ViewArray<SView> is(home,ubsize); for (int i=n; i--;) is[i]=iv[i].view; GECODE_REWRITE(*this,(RelOp::UnionN<SView, SView> ::post(home(*this),is,x0))); } else if (ubsize == 2) { assert(n==2); SView a = iv[0].view; SView b = iv[1].view; GECODE_REWRITE(*this,(RelOp::Union<SView, SView, SView> ::post(home(*this),a,b,x0))); } else if (ubsize == 1) { assert(n==1); GECODE_REWRITE(*this,(Rel::Eq<SView,SView>::post(home(*this),x0,iv[0].view))); } else { GECODE_ME_CHECK(x0.cardMax(home, 0)); return home.ES_SUBSUMED(*this); } } bool allAssigned = true; for (int i=iv.size(); i--;) { if (!iv[i].view.assigned()) { allAssigned = false; break; } } if (x0.assigned() && x1.assigned() && allAssigned) { return home.ES_SUBSUMED(*this); } return ES_FIX; }
ExecStatus Union<View0,View1,View2>::propagate(Space& home, const ModEventDelta& med) { // This propagator implements the constraint // x2 = x0 u x1 bool x0ass = x0.assigned(); bool x1ass = x1.assigned(); bool x2ass = x2.assigned(); ModEvent me0 = View0::me(med); ModEvent me1 = View1::me(med); ModEvent me2 = View2::me(med); bool x0ubmod = false; bool x1ubmod = false; bool modified = false; do { modified = false; do { // 4) lub(x2) <= lub(x0) u lub(x1) { LubRanges<View0> x0ub(x0); LubRanges<View1> x1ub(x1); Iter::Ranges::Union<LubRanges<View0>, LubRanges<View1> > u2(x0ub,x1ub); GECODE_ME_CHECK_MODIFIED(modified, x2.intersectI(home,u2) ); } if (modified || Rel::testSetEventUB(me2) ) { modified = false; // 5) x0 <= x2 LubRanges<View2> x2ub1(x2); GECODE_ME_CHECK_MODIFIED(modified, x0.intersectI(home,x2ub1) ); x0ubmod |= modified; // 6) x1 <= x2 bool modified2=false; LubRanges<View2> x2ub2(x2); GECODE_ME_CHECK_MODIFIED(modified2, x1.intersectI(home,x2ub2) ); x1ubmod |= modified2; modified |= modified2; } } while (modified); modified = false; do { bool modifiedOld = modified; modified = false; if (Rel::testSetEventLB(me2) || Rel::testSetEventUB(me0) || x0ubmod || modifiedOld) { // 1) glb(x0) \ lub(x1) <= glb(x2) GlbRanges<View2> x2lb(x2); LubRanges<View0> x0ub(x0); Iter::Ranges::Diff<GlbRanges<View2>, LubRanges<View0> > diff(x2lb, x0ub); GECODE_ME_CHECK_MODIFIED(modified, x1.includeI(home,diff) ); } if (Rel::testSetEventLB(me2) || Rel::testSetEventUB(me1) || x1ubmod || modifiedOld) { // 2) glb(x0) \ lub(x2) <= glb(x1) GlbRanges<View2> x2lb(x2); LubRanges<View1> x1ub(x1); Iter::Ranges::Diff<GlbRanges<View2>, LubRanges<View1> > diff(x2lb, x1ub); GECODE_ME_CHECK_MODIFIED(modified, x0.includeI(home,diff) ); } if (Rel::testSetEventLB(me0,me1) || modified) { // modified = false; // 3) glb(x1) u glb(x2) <= glb(x0) GlbRanges<View0> x0lb(x0); GlbRanges<View1> x1lb(x1); Iter::Ranges::Union<GlbRanges<View0>, GlbRanges<View1> > u1(x0lb,x1lb); GECODE_ME_CHECK_MODIFIED(modified, x2.includeI(home,u1) ); } } while(modified); modified = false; { // cardinality ExecStatus ret = unionCard(home,modified, x0, x1, x2); GECODE_ES_CHECK(ret); } if (x2.cardMax() == 0) { GECODE_ME_CHECK( x0.cardMax(home, 0) ); GECODE_ME_CHECK( x1.cardMax(home, 0) ); return home.ES_SUBSUMED(*this); } if (x0.cardMax() == 0) GECODE_REWRITE(*this,(Rel::Eq<View1,View2>::post(home(*this),x1,x2))); if (x1.cardMax() == 0) GECODE_REWRITE(*this,(Rel::Eq<View0,View2>::post(home(*this),x0,x2))); } while(modified); if (shared(x0,x1,x2)) { return (x0ass && x1ass && x2ass) ? home.ES_SUBSUMED(*this) : ES_NOFIX; } else { if (x0ass && x1ass && x2ass) return home.ES_SUBSUMED(*this); if (x0ass != x0.assigned() || x1ass != x1.assigned() || x2ass != x2.assigned()) { return ES_NOFIX; } else { return ES_FIX; } } }
ExecStatus Mult<View>::propagate(Space& home, const ModEventDelta&) { Rounding r; if (pos(x0)) { if (pos(x1) || pos(x2)) goto rewrite_ppp; if (neg(x1) || neg(x2)) goto rewrite_pnn; goto prop_pxx; } if (neg(x0)) { if (neg(x1) || pos(x2)) goto rewrite_nnp; if (pos(x1) || neg(x2)) goto rewrite_npn; goto prop_nxx; } if (pos(x1)) { if (pos(x2)) goto rewrite_ppp; if (neg(x2)) goto rewrite_npn; goto prop_xpx; } if (neg(x1)) { if (pos(x2)) goto rewrite_nnp; if (neg(x2)) goto rewrite_pnn; goto prop_xnx; } assert(any(x0) && any(x1)); GECODE_ME_CHECK(x2.lq(home,std::max(r.mul_up(x0.max(),x1.max()), r.mul_up(x0.min(),x1.min())))); GECODE_ME_CHECK(x2.gq(home,std::min(r.mul_down(x0.min(),x1.max()), r.mul_down(x0.max(),x1.min())))); if (pos(x2)) { if (r.div_up(x2.min(),x1.min()) < x0.min()) GECODE_ME_CHECK(x0.gq(home,0)); if (r.div_up(x2.min(),x0.min()) < x1.min()) GECODE_ME_CHECK(x1.gq(home,0)); } if (neg(x2)) { if (r.div_up(x2.max(),x1.max()) < x0.min()) GECODE_ME_CHECK(x0.gq(home,0)); if (r.div_up(x2.max(),x0.max()) < x1.min()) GECODE_ME_CHECK(x1.gq(home,0)); } if (x0.assigned()) { assert((x0.val() == 0.0) && (x2.val() == 0.0)); return home.ES_SUBSUMED(*this); } if (x1.assigned()) { assert((x1.val() == 0.0) && (x2.val() == 0.0)); return home.ES_SUBSUMED(*this); } return ES_NOFIX; prop_xpx: std::swap(x0,x1); prop_pxx: assert(pos(x0) && any(x1) && any(x2)); GECODE_ME_CHECK(x2.lq(home,r.mul_up(x0.max(),x1.max()))); GECODE_ME_CHECK(x2.gq(home,r.mul_down(x0.max(),x1.min()))); if (pos(x2)) goto rewrite_ppp; if (neg(x2)) goto rewrite_pnn; GECODE_ME_CHECK(x1.lq(home,r.div_up(x2.max(),x0.min()))); GECODE_ME_CHECK(x1.gq(home,r.div_down(x2.min(),x0.min()))); if (x0.assigned() && x1.assigned()) { GECODE_ME_CHECK(x2.eq(home,x0.val()*x1.val())); return home.ES_SUBSUMED(*this); } return ES_NOFIX; prop_xnx: std::swap(x0,x1); prop_nxx: assert(neg(x0) && any(x1) && any(x2)); GECODE_ME_CHECK(x2.lq(home,r.mul_up(x0.min(),x1.min()))); GECODE_ME_CHECK(x2.gq(home,r.mul_down(x0.min(),x1.max()))); if (pos(x2)) goto rewrite_nnp; if (neg(x2)) goto rewrite_npn; if (x0.max() != 0.0) { GECODE_ME_CHECK(x1.lq(home,r.div_up(x2.min(),x0.max()))); GECODE_ME_CHECK(x1.gq(home,r.div_down(x2.max(),x0.max()))); } if (x0.assigned() && x1.assigned()) { GECODE_ME_CHECK(x2.eq(home,x0.val()*x1.val())); return home.ES_SUBSUMED(*this); } return ES_NOFIX; rewrite_ppp: GECODE_REWRITE(*this,(MultPlus<FloatView,FloatView,FloatView> ::post(home(*this),x0,x1,x2))); rewrite_nnp: GECODE_REWRITE(*this,(MultPlus<MinusView,MinusView,FloatView> ::post(home(*this),MinusView(x0),MinusView(x1),x2))); rewrite_pnn: std::swap(x0,x1); rewrite_npn: GECODE_REWRITE(*this,(MultPlus<MinusView,FloatView,MinusView> ::post(home(*this),MinusView(x0),x1,MinusView(x2)))); }