ExecStatus Card<View>::propagate(Space& home, const ModEventDelta&) { int x1min, x1max; do { x1min = x1.min(); x1max = x1.max(); GECODE_ME_CHECK(x0.cardMin(home,static_cast<unsigned int>(x1min))); GECODE_ME_CHECK(x0.cardMax(home,static_cast<unsigned int>(x1max))); GECODE_ME_CHECK(x1.gq(home,static_cast<int>(x0.cardMin()))); GECODE_ME_CHECK(x1.lq(home,static_cast<int>(x0.cardMax()))); } while (x1.min() > x1min || x1.max() < x1max); if (x1.assigned()) return home.ES_SUBSUMED(*this); return ES_FIX; }
ExecStatus NaryEq<View>::propagate(Space& home, const ModEventDelta& med) { assert(x.size() > 2); if (View::me(med) == ME_FLOAT_VAL) { // One of the variables is assigned for (int i = 0; ; i++) if (x[i].assigned()) { FloatVal n = x[i].val(); x.move_lst(i); for (int j = x.size(); j--; ) GECODE_ME_CHECK(x[j].eq(home,n)); return home.ES_SUBSUMED(*this); } GECODE_NEVER; } FloatNum mn = x[0].min(); restart_min: for (int i = x.size(); i--; ) { GECODE_ME_CHECK(x[i].gq(home,mn)); if (mn < x[i].min()) { mn = x[i].min(); goto restart_min; } } FloatNum mx = x[0].max(); restart_max: for (int i = x.size(); i--; ) { GECODE_ME_CHECK(x[i].lq(home,mx)); if (mx > x[i].max()) { mx = x[i].max(); goto restart_max; } } return x[0].assigned() ? home.ES_SUBSUMED(*this) : ES_FIX; }
ExecStatus Seq::propagate(Space& home, const ModEventDelta&) { bool modified = false; bool assigned; do { assigned = false; modified = false; GECODE_ES_CHECK(propagateSeq(home, modified, assigned, x)); } while (assigned || modified); for (int i=x.size(); i--;) if (!x[i].assigned()) return ES_FIX; return home.ES_SUBSUMED(*this); }
ExecStatus Prop<View>::propagate(Space& home, const ModEventDelta& med) { // Add assigned views to value set if (View::me(med) == ME_INT_VAL) add(home,vs,x); // Eliminate views from x eliminate(home); if (x.size() == 0) { // y must have values in the value set ValSet::Ranges vsr(vs); GECODE_ME_CHECK(y.inter_r(home,vsr,false)); return home.ES_SUBSUMED(*this); } // Constrain y to union of x and value set Region r(home); assert(x.size() > 0); 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; } GECODE_ME_CHECK(y.inter_r(home,u,false)); // Check whether all values in y are already in the value set if (vs.subset(y)) return home.ES_SUBSUMED(*this); return ES_FIX; }
ExecStatus LqInt<VY>::propagate(Space& home, const ModEventDelta& med) { // Add assigned views to value set if (IntView::me(med) == ME_INT_VAL) add(home); GECODE_ME_CHECK(y.gq(home, vs.size())); if (x.size() == 0) return home.ES_SUBSUMED(*this); // All values must be in the value set if (y.max() == vs.size()) return all_in_valset(home); if (x.size() + vs.size() <= y.min()) return home.ES_SUBSUMED(*this); // Compute positions of disjoint views Region r(home); int* dis; int n_dis; disjoint(home,r,dis,n_dis); // Some views might have been eliminated as they are subsumed if (x.size() == 0) return home.ES_SUBSUMED(*this); // No lower bound pruning possible if (n_dis == 0) return ES_NOFIX; // Do lower bound-based pruning GECODE_ES_CHECK(prune_lower(home,dis,n_dis)); return ES_NOFIX; }
ExecStatus ChannelBool<View>::propagate(Space& home, const ModEventDelta&) { running = true; if (zeros.size() > 0) { BndSetRanges zi(zeros); GECODE_ME_CHECK(y.excludeI(home, zi)); zeros.init(home); } if (ones.size() > 0) { BndSetRanges oi(ones); GECODE_ME_CHECK(y.includeI(home, oi)); ones.init(home); } running = false; if (delta.glbMin() != 1 || delta.glbMax() != 0) { if (!delta.glbAny()) { for (int i=delta.glbMin(); i<=delta.glbMax(); i++) GECODE_ME_CHECK(x[i].one(home)); } else { GlbRanges<View> glb(y); for (Iter::Ranges::ToValues<GlbRanges<View> > gv(glb); gv(); ++gv) { GECODE_ME_CHECK(x[gv.val()].one(home)); } } } if (delta.lubMin() != 1 || delta.lubMax() != 0) { if (!delta.lubAny()) { for (int i=delta.lubMin(); i<=delta.lubMax(); i++) GECODE_ME_CHECK(x[i].zero(home)); } else { int cur = 0; for (LubRanges<View> lub(y); lub(); ++lub) { for (; cur < lub.min(); cur++) { GECODE_ME_CHECK(x[cur].zero(home)); } cur = lub.max() + 1; } for (; cur < x.size(); cur++) { GECODE_ME_CHECK(x[cur].zero(home)); } } } new (&delta) SetDelta(); return y.assigned() ? home.ES_SUBSUMED(*this) : ES_FIX; }
ExecStatus Mult<A,B,C>::propagate(Space& home, const ModEventDelta&) { GECODE_ME_CHECK(x2.eq(home,x0.domain() * x1.domain())); if ( x2.assigned() && (x2.val() == 0) ) { if (x0.zero_in() || x1.zero_in()) { return ES_FIX; } else { return ES_FAILED; } } if (!x1.assigned() || (x1.val() != 0)) GECODE_ME_CHECK(x0.eq(home,x2.domain() / x1.domain())); if (!x0.assigned() || (x0.val() != 0)) GECODE_ME_CHECK(x1.eq(home,x2.domain() / x0.domain())); return (x0.assigned() && x1.assigned()) ? home.ES_SUBSUMED(*this) : 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 purge(Space& home, Propagator& p, TaskArray<OptTask>& t, Cap c) { int n=t.size(); for (int i=n; i--; ) if (t[i].excluded()) { t[i].cancel(home,p,PL::pc); t[i]=t[--n]; } t.size(n); if (t.size() == 1) { if (t[0].mandatory()) GECODE_ME_CHECK(c.gq(home, t[0].c())); else if (c.min() < t[0].c()) return ES_OK; } return (t.size() < 2) ? home.ES_SUBSUMED(p) : ES_OK; }
ExecStatus LinkSingle::propagate(Space& home, const ModEventDelta&) { if (x0.zero()) { GECODE_ME_CHECK(x1.eq(home,0)); } else if (x0.one()) { GECODE_ME_CHECK(x1.eq(home,1)); } else { assert(x0.none() && x1.assigned()); if (x1.val() == 0) { GECODE_ME_CHECK(x0.zero_none(home)); } else { assert(x1.val() == 1); GECODE_ME_CHECK(x0.one_none(home)); } } return home.ES_SUBSUMED(*this); }
ExecStatus Eq<View0,View1>::propagate(Space& home, const ModEventDelta& med) { ModEvent me0 = View0::me(med); ModEvent me1 = View1::me(med); Region r(home); if (testSetEventLB(me0,me1)) { GlbRanges<View0> x0lb(x0); GlbRanges<View1> x1lb(x1); Iter::Ranges::Union<GlbRanges<View0>,GlbRanges<View1> > lbu(x0lb,x1lb); Iter::Ranges::Cache<Iter::Ranges::Union <GlbRanges<View0>, GlbRanges<View1> > > lbuc(r,lbu); GECODE_ME_CHECK(x0.includeI(home,lbuc)); lbuc.reset(); GECODE_ME_CHECK(x1.includeI(home,lbuc)); } if (testSetEventUB(me0,me1)) { LubRanges<View0> x0ub(x0); LubRanges<View1> x1ub(x1); Iter::Ranges::Inter<LubRanges<View0>,LubRanges<View1> > ubi(x0ub,x1ub); Iter::Ranges::Cache<Iter::Ranges::Inter <LubRanges<View0>,LubRanges<View1> > > ubic(r,ubi); GECODE_ME_CHECK(x0.intersectI(home,ubic)); ubic.reset(); GECODE_ME_CHECK(x1.intersectI(home,ubic)); } if (testSetEventCard(me0,me1) ) { unsigned int max = std::min(x0.cardMax(),x1.cardMax()); unsigned int min = std::max(x0.cardMin(),x1.cardMin()); GECODE_ME_CHECK ( x0.cardMax(home,max) ); GECODE_ME_CHECK ( x1.cardMax(home,max) ); GECODE_ME_CHECK ( x0.cardMin(home,min) ); GECODE_ME_CHECK ( x1.cardMin(home,min) ); } if (x0.assigned()) { assert (x1.assigned()); return home.ES_SUBSUMED(*this); } return shared(x0,x1) ? ES_NOFIX : ES_FIX; }
forceinline ExecStatus prop_mult_dom(Space& home, Propagator& p, View x0, View x1, View x2) { Region r(home); SupportValues<View,Region> s0(r,x0), s1(r,x1), s2(r,x2); while (s0()) { while (s1()) { if (s2.support(mll(s0.val(),s1.val()))) { s0.support(); s1.support(); } ++s1; } s1.reset(); ++s0; } GECODE_ME_CHECK(s0.tell(home)); GECODE_ME_CHECK(s1.tell(home)); GECODE_ME_CHECK(s2.tell(home)); return x0.assigned() && x1.assigned() ? home.ES_SUBSUMED(p) : ES_FIX; }
ExecStatus ChannelInt<View>::propagate(Space& home, const ModEventDelta&) { int assigned = 0; for (int v=xs.size(); v--;) { if (xs[v].assigned()) { assigned += 1; for (int i=ys.size(); i--;) { if (i==xs[v].val()) { GECODE_ME_CHECK(ys[i].include(home, v)); } else { GECODE_ME_CHECK(ys[i].exclude(home, v)); } } } else { for (int i=ys.size(); i--;) { if (ys[i].notContains(v)) { GECODE_ME_CHECK(xs[v].nq(home, i)); } if (ys[i].contains(v)) { GECODE_ME_CHECK(xs[v].eq(home, i)); } } Gecode::Int::ViewRanges<Gecode::Int::IntView> xsv(xs[v]); int min = 0; for (; xsv(); ++xsv) { for (int i=min; i<xsv.min(); i++) { GECODE_ME_CHECK(ys[i].exclude(home, v)); } min = xsv.max() + 1; } for (int i=min; i<ys.size(); i++) { GECODE_ME_CHECK(ys[i].exclude(home, v)); } } } return (assigned==xs.size()) ? home.ES_SUBSUMED(*this) : ES_NOFIX; }
ExecStatus Pow<A,B>::propagate(Space& home, const ModEventDelta&) { GECODE_ME_CHECK(x1.eq(home,pow(x0.domain(),m_n))); if ((m_n % 2) == 0) { if (x0.min() >= 0) GECODE_ME_CHECK(x0.eq(home,nth_root(x1.domain(),m_n))); else if (x0.max() <= 0) GECODE_ME_CHECK(x0.eq(home,-nth_root(x1.domain(),m_n))); else GECODE_ME_CHECK(x0.eq(home, hull( nth_root(x1.domain(),m_n), -nth_root(x1.domain(),m_n) ) )); } else GECODE_ME_CHECK(x0.eq(home,nth_root(x1.domain(),m_n))); return x0.assigned() ? home.ES_SUBSUMED(*this) : ES_FIX; }
ExecStatus Eq<View0,View1>::propagate(Space& home, const ModEventDelta&) { if (x0.assigned()) { GECODE_ME_CHECK(x1.eq(home,x0.val())); } else if (x1.assigned()) { GECODE_ME_CHECK(x0.eq(home,x1.val())); } else { do { GECODE_ME_CHECK(x0.gq(home,x1.min())); GECODE_ME_CHECK(x1.gq(home,x0.min())); } while (x0.min() != x1.min()); do { GECODE_ME_CHECK(x0.lq(home,x1.max())); GECODE_ME_CHECK(x1.lq(home,x0.max())); } while (x0.max() != x1.max()); if (!x0.assigned()) return ES_FIX; } assert(x0.assigned() && x1.assigned()); return home.ES_SUBSUMED(*this); }
forceinline ExecStatus prop_mult_plus_bnd(Space& home, Propagator& p, VA x0, VB x1, VC x2) { assert(pos(x0) && pos(x1) && pos(x2)); bool mod; do { mod = false; { ModEvent me = x2.lq(home,mll(x0.max(),x1.max())); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } { ModEvent me = x2.gq(home,mll(x0.min(),x1.min())); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } { ModEvent me = x0.lq(home,floor_div_pp(x2.max(),x1.min())); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } { ModEvent me = x0.gq(home,ceil_div_pp(x2.min(),x1.max())); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } { ModEvent me = x1.lq(home,floor_div_pp(x2.max(),x0.min())); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } { ModEvent me = x1.gq(home,ceil_div_pp(x2.min(),x0.max())); if (me_failed(me)) return ES_FAILED; mod |= me_modified(me); } } while (mod); return x0.assigned() && x1.assigned() ? home.ES_SUBSUMED(p) : ES_FIX; }
ExecStatus ReEqFloat<View,CtrlView,rm>::propagate(Space& home, const ModEventDelta&) { if (b.one()) { if (rm != RM_PMI) GECODE_ME_CHECK(x0.eq(home,c)); } else { switch (rtest_eq(x0,c)) { case RT_TRUE: if (rm != RM_IMP) GECODE_ME_CHECK(b.one(home)); break; case RT_FALSE: if (rm != RM_PMI) GECODE_ME_CHECK(b.zero(home)); break; case RT_MAYBE: return ES_FIX; default: GECODE_NEVER; } } return home.ES_SUBSUMED(*this); }
ExecStatus ChannelInt<View>::propagate(Space& home, const ModEventDelta&) { int assigned = 0; for (int v=xs.size(); v--;) { if (xs[v].assigned()) { assigned++; if (xs[v].modified()) GECODE_ME_CHECK(ys[xs[v].val()].include(home,v)); } if (xs[v].modified()) { Gecode::Int::ViewDiffRanges<Gecode::Int::IntView> d(xs[v]); Iter::Ranges::ToValues<Gecode::Int::ViewDiffRanges< Gecode::Int::IntView> > dv(d); for (; dv(); ++dv) GECODE_ME_CHECK(ys[dv.val()].exclude(home, v)); xs[v].cache(home); } } for (int i=ys.size(); i--;) { if (ys[i].glbModified()) { GlbDiffRanges<View> yilb(ys[i]); Iter::Ranges::ToValues<GlbDiffRanges<View> > dv(yilb); for (;dv();++dv) GECODE_ME_CHECK(xs[dv.val()].eq(home,i)); ys[i].cacheGlb(home); } if (ys[i].lubModified()) { LubDiffRanges<View> yiub(ys[i]); Iter::Ranges::ToValues<LubDiffRanges<View> > dv(yiub); for (;dv();++dv) GECODE_ME_CHECK(xs[dv.val()].nq(home,i)); ys[i].cacheLub(home); } } return (assigned==xs.size()) ? home.ES_SUBSUMED(*this) : ES_NOFIX; }
forceinline ExecStatus notlast(Space& home, Propagator& p, TaskViewArray<OptTaskView>& t) { sort<OptTaskView,STO_LCT,true>(t); Region r(home); OmegaTree<OptTaskView> o(r,t); ManTaskViewIter<OptTaskView,STO_LST,true> q(r,t); int* lct = r.alloc<int>(t.size()); for (int i=t.size(); i--; ) lct[i] = t[i].lct(); for (int i=0; i<t.size(); i++) { int j = -1; while (q() && (t[i].lct() > t[q.task()].lst())) { if ((j >= 0) && (o.ect() > t[q.task()].lst())) lct[q.task()] = std::min(lct[q.task()],t[j].lst()); j = q.task(); o.insert(j); ++q; } if ((j >= 0) && (o.ect(i) > t[i].lst())) lct[i] = std::min(lct[i],t[j].lst()); } int n = t.size(); for (int i=n; i--; ) if (t[i].mandatory()) { GECODE_ME_CHECK(t[i].lct(home,lct[i])); } else if (lct[i] < t[i].ect()) { // GECODE_ME_CHECK(t[i].excluded(home)); // t[i].cancel(home,p); t[i]=t[--n]; } t.size(n); return (t.size() < 2) ? home.ES_SUBSUMED(p) : ES_OK; }
ExecStatus MultZeroOne<View,pc>::propagate(Space& home, const ModEventDelta&) { switch (equal(x0,0)) { case RT_FALSE: GECODE_ME_CHECK(x1.eq(home,1)); break; case RT_TRUE: break; case RT_MAYBE: switch (equal(x1,1)) { case RT_FALSE: GECODE_ME_CHECK(x0.eq(home,0)); break; case RT_TRUE: break; case RT_MAYBE: return ES_FIX; default: GECODE_NEVER; } break; default: GECODE_NEVER; } return home.ES_SUBSUMED(*this); }
ExecStatus ATan<A,B>::propagate(Space& home, const ModEventDelta&) { GECODE_ME_CHECK(x1.eq(home,atan(x0.domain()))); GECODE_ME_CHECK(x0.eq(home,tan(x1.domain()))); return (x0.assigned() && x1.assigned()) ? home.ES_SUBSUMED(*this) : ES_FIX; }
ExecStatus GqBin<Val,A,B>::propagate(Space& home, const ModEventDelta&) { GECODE_ME_CHECK(x0.gq(home,c-x1.max())); GECODE_ME_CHECK(x1.gq(home,c-x0.max())); return (x0.min()+x1.min() >= c) ? home.ES_SUBSUMED(*this) : 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 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 Match<View>::propagate(Space& home, const ModEventDelta&) { int xs_size = xs.size(); bool loopFlag; do { loopFlag = false; // Order int vars in xs GECODE_ME_CHECK(xs[0].gq(home,x0.lubMin())); for (int i=xs_size-1; i--; ) { GECODE_ME_CHECK_MODIFIED(loopFlag, xs[i+1].gq(home,xs[i].min() + 1)); } GECODE_ME_CHECK_MODIFIED(loopFlag, xs[xs_size-1].lq(home,x0.lubMax())); for (int i=xs_size-2; i--; ) { GECODE_ME_CHECK_MODIFIED(loopFlag, xs[i].lq(home,xs[i+1].max() - 1)); } // if y from xs is assigned, add to glb(x0) for (int i=xs_size; i--; ) { if (xs[i].assigned()) { GECODE_ME_CHECK_MODIFIED(loopFlag, x0.include(home,xs[i].val())); } } // intersect every y in xs with lub(x0) for (int i=xs_size; i--; ) { LubRanges<View> ub(x0); GECODE_ME_CHECK_MODIFIED(loopFlag, xs[i].inter_r(home,ub,false)); } // remove gaps between vars in xs from lub(x0) GECODE_ME_CHECK_MODIFIED(loopFlag, x0.exclude(home,Limits::min,xs[0].min()-1)); GECODE_ME_CHECK_MODIFIED(loopFlag, x0.exclude(home,xs[xs_size-1].max()+1, Limits::max)); for (int i=xs_size-1; i--; ) { int start = xs[i].max() + 1; int end = xs[i+1].min() - 1; if (start<=end) { GECODE_ME_CHECK_MODIFIED(loopFlag, x0.exclude(home,start,end)); } } // try to assign vars in xs from glb(x0) if (x0.glbSize()>0) { LubRanges<View> ub(x0); Iter::Ranges::ToValues<LubRanges<View> > ubv(ub); GlbRanges<View> lb(x0); Iter::Ranges::ToValues<GlbRanges<View> > lbv(lb); int i=0; for (; ubv() && lbv() && ubv.val()==lbv.val(); ++ubv, ++lbv, i++) { GECODE_ME_CHECK_MODIFIED(loopFlag, xs[i].eq(home,lbv.val())); } if (i<xs_size-1 && x0.lubMax()==x0.glbMax()) { LubRanges<View> lbx0(x0); GlbRanges<View> ubx0(x0); Iter::Ranges::Inter<LubRanges<View>,GlbRanges<View> > inter(lbx0, ubx0); int to = x0.glbMax(); int from = to; while (inter()) { from = inter.min(); ++inter; } int i=xs_size-1; for (int j=to; j>=from;j--,i--) { GECODE_ME_CHECK_MODIFIED(loopFlag, xs[i].eq(home,j)); } } } } while (loopFlag); for (int i=xs_size; i--; ) if (!xs[i].assigned()) return ES_FIX; return home.ES_SUBSUMED(*this); }
ExecStatus SuperOfInter<View0,View1,View2>::propagate(Space& home, const ModEventDelta& med) { bool allassigned = x0.assigned() && x1.assigned() && x2.assigned(); ModEvent me0 = View0::me(med); ModEvent me1 = View1::me(med); ModEvent me2 = View2::me(med); bool modified = false; do { // glb(x2) >= glb(x0) ^ glb(x1) if ( modified || Rel::testSetEventLB(me0,me1)) { GlbRanges<View0> lb0(x0); GlbRanges<View1> lb1(x1); Iter::Ranges::Inter<GlbRanges<View0>,GlbRanges<View1> > is(lb0, lb1); GECODE_ME_CHECK_MODIFIED(modified,x2.includeI(home,is)); } // lub(x0) -= glb(x1)-lub(x2) // lub(x1) -= glb(x0)-lub(x2) if ( modified || Rel::testSetEventAnyB(me0,me1,me2)) { modified = false; GlbRanges<View1> lb12(x1); LubRanges<View2> ub22(x2); Iter::Ranges::Diff<GlbRanges<View1>, LubRanges<View2> > diff1(lb12, ub22); GECODE_ME_CHECK_MODIFIED(modified, x0.excludeI(home,diff1)); GlbRanges<View0> lb01(x0); LubRanges<View2> ub23(x2); Iter::Ranges::Diff<GlbRanges<View0>, LubRanges<View2> > diff2(lb01, ub23); GECODE_ME_CHECK_MODIFIED(modified, x1.excludeI(home,diff2)); } else { modified = false; } // Cardinality propagation if ( modified || Rel::testSetEventCard(me0,me1,me2) || Rel::testSetEventUB(me0,me1) ) { LubRanges<View0> ub0(x0); LubRanges<View1> ub1(x1); Iter::Ranges::Union<LubRanges<View0>, LubRanges<View1> > u(ub0,ub1); unsigned int m = Iter::Ranges::size(u); if (m < x0.cardMin() + x1.cardMin()) { GECODE_ME_CHECK_MODIFIED(modified, x2.cardMin( home, x0.cardMin()+x1.cardMin() - m ) ); } if (m + x2.cardMax() > x1.cardMin()) { GECODE_ME_CHECK_MODIFIED(modified, x0.cardMax( home, m+x2.cardMax()-x1.cardMin() ) ); } if (m + x2.cardMax() > x0.cardMin()) { GECODE_ME_CHECK_MODIFIED(modified, x1.cardMax( home, m+x2.cardMax()-x0.cardMin() ) ); } } } while (modified); if (shared(x0,x1,x2)) { if (allassigned) { return home.ES_SUBSUMED(*this); } else { return ES_NOFIX; } } else { if (x0.assigned() + x1.assigned() + x2.assigned() >= 2) { return home.ES_SUBSUMED(*this); } else { return ES_FIX; } } }
ExecStatus Eqv<BVA,BVB,BVC>::propagate(Space& home, const ModEventDelta&) { #define GECODE_INT_STATUS(S0,S1,S2) \ ((BVA::S0<<(2*BVA::BITS))|(BVB::S1<<(1*BVB::BITS))|(BVC::S2<<(0*BVC::BITS))) switch ((x0.status() << (2*BVA::BITS)) | (x1.status() << (1*BVB::BITS)) | (x2.status() << (0*BVC::BITS))) { case GECODE_INT_STATUS(NONE,NONE,NONE): GECODE_NEVER; case GECODE_INT_STATUS(NONE,NONE,ZERO): case GECODE_INT_STATUS(NONE,NONE,ONE): case GECODE_INT_STATUS(NONE,ZERO,NONE): return ES_FIX; case GECODE_INT_STATUS(NONE,ZERO,ZERO): GECODE_ME_CHECK(x0.one_none(home)); break; case GECODE_INT_STATUS(NONE,ZERO,ONE): GECODE_ME_CHECK(x0.zero_none(home)); break; case GECODE_INT_STATUS(NONE,ONE,NONE): return ES_FIX; case GECODE_INT_STATUS(NONE,ONE,ZERO): GECODE_ME_CHECK(x0.zero_none(home)); break; case GECODE_INT_STATUS(NONE,ONE,ONE): GECODE_ME_CHECK(x0.one_none(home)); break; case GECODE_INT_STATUS(ZERO,NONE,NONE): return ES_FIX; case GECODE_INT_STATUS(ZERO,NONE,ZERO): GECODE_ME_CHECK(x1.one_none(home)); break; case GECODE_INT_STATUS(ZERO,NONE,ONE): GECODE_ME_CHECK(x1.zero_none(home)); break; case GECODE_INT_STATUS(ZERO,ZERO,NONE): GECODE_ME_CHECK(x2.one_none(home)); break; case GECODE_INT_STATUS(ZERO,ZERO,ZERO): return ES_FAILED; case GECODE_INT_STATUS(ZERO,ZERO,ONE): break; case GECODE_INT_STATUS(ZERO,ONE,NONE): GECODE_ME_CHECK(x2.zero_none(home)); break; case GECODE_INT_STATUS(ZERO,ONE,ZERO): break; case GECODE_INT_STATUS(ZERO,ONE,ONE): return ES_FAILED; case GECODE_INT_STATUS(ONE,NONE,NONE): return ES_FIX; case GECODE_INT_STATUS(ONE,NONE,ZERO): GECODE_ME_CHECK(x1.zero_none(home)); break; case GECODE_INT_STATUS(ONE,NONE,ONE): GECODE_ME_CHECK(x1.one_none(home)); break; case GECODE_INT_STATUS(ONE,ZERO,NONE): GECODE_ME_CHECK(x2.zero_none(home)); break; case GECODE_INT_STATUS(ONE,ZERO,ZERO): break; case GECODE_INT_STATUS(ONE,ZERO,ONE): return ES_FAILED; case GECODE_INT_STATUS(ONE,ONE,NONE): GECODE_ME_CHECK(x2.one_none(home)); break; case GECODE_INT_STATUS(ONE,ONE,ZERO): return ES_FAILED; case GECODE_INT_STATUS(ONE,ONE,ONE): break; default: GECODE_NEVER; } return home.ES_SUBSUMED(*this); #undef GECODE_INT_STATUS }
ExecStatus DomEq<Val,View>::propagate(Space& home, const ModEventDelta& med) { if (View::me(med) != ME_INT_DOM) { ExecStatus es = prop_bnd<Val,View,View>(home,med,*this,x,y,c); GECODE_ES_CHECK(es); return home.ES_FIX_PARTIAL(*this,View::med(ME_INT_DOM)); } // Value of equation for partial assignment Val d = -c; int n = x.size(); int m = y.size(); Region r(home); // Create support-base iterators PosSupportIter<Val>* xp = r.alloc<PosSupportIter<Val> >(n); NegSupportIter<Val>* yp = r.alloc<NegSupportIter<Val> >(m); // Initialize views for assignments { Val l = 0; Val u = 0; for (int j=m; j--; ) { yp[j].init(r,-y[j].scale(),y[j].base(),l,u); l += y[j].max(); u += y[j].min(); } for (int i=n; i--; ) { xp[i].init(r,x[i].scale(),x[i].base(),l,u); l -= x[i].min(); u -= x[i].max(); } } // Collect support information by iterating assignments { // Force reset of all iterators in first round int i = 0; int j = 0; next_i: // Reset all iterators for positive views and update d while (i<n) { if (!xp[i].reset(d)) goto prev_i; i++; } next_j: // Reset all iterators for negative views and update d while (j<m) { if (!yp[j].reset(d)) goto prev_j; j++; } // Check whether current assignment is solution if (d == 0) { // Record support for (int is=n; is--; ) xp[is].support(); for (int js=m; js--; ) yp[js].support(); } prev_j: // Try iterating to next assignment: negative views while (j>0) { if (yp[j-1].adjust(d)) goto next_j; j--; } prev_i: // Try iterating to next assignment: positive views while (i>0) { if (xp[i-1].adjust(d)) goto next_i; i--; } } // Tell back new variable domains bool assigned = true; for (int i=n; i--; ) { GECODE_ME_CHECK(xp[i].tell(home)); if (!x[i].assigned()) assigned = false; } for (int j=m; j--; ) { GECODE_ME_CHECK(yp[j].tell(home)); if (!y[j].assigned()) assigned = false; } if (assigned) 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 LinkMulti::propagate(Space& home, const ModEventDelta& med) { int n = x.size(); // Always maintain the invariant that y lies inside the x-array assert((y.min()-o >= 0) && (y.max()-o < n)); if (y.assigned()) { status = S_RUN; int j=y.val()-o; GECODE_ME_CHECK(x[j].one(home)); for (int i=0; i<j; i++) GECODE_ME_CHECK(x[i].zero(home)); for (int i=j+1; i<n; i++) GECODE_ME_CHECK(x[i].zero(home)); return home.ES_SUBSUMED(*this); } // Check whether there is a one if (status == S_ONE) { status = S_RUN; for (int i=0; true; i++) if (x[i].one()) { for (int j=0; j<i; j++) GECODE_ME_CHECK(x[j].zero(home)); for (int j=i+1; j<n; j++) GECODE_ME_CHECK(x[j].zero(home)); GECODE_ME_CHECK(y.eq(home,i+o)); return home.ES_SUBSUMED(*this); } GECODE_NEVER; } status = S_RUN; redo: // Assign all Boolean views to zero that are outside bounds { int min=y.min()-o; for (int i=0; i<min; i++) GECODE_ME_CHECK(x[i].zero(home)); x.drop_fst(min); o += min; n = x.size(); int max=y.max()-o; for (int i=max+1; i<n; i++) GECODE_ME_CHECK(x[i].zero(home)); x.drop_lst(max); n = x.size(); } { // Remove zeros on the left int i=0; while ((i < n) && x[i].zero()) i++; if (i >= n) return ES_FAILED; x.drop_fst(i); o += i; n = x.size(); } { // Remove zeros on the right int i=n-1; while ((i >= 0) && x[i].zero()) i--; assert(i >= 0); x.drop_lst(i); n = x.size(); } assert(n >= 1); // Is there only one left? if (n == 1) { GECODE_ME_CHECK(x[0].one(home)); GECODE_ME_CHECK(y.eq(home,o)); return home.ES_SUBSUMED(*this); } // Update bounds GECODE_ME_CHECK(y.gq(home,o)); GECODE_ME_CHECK(y.lq(home,o+n-1)); if ((y.min() > o) || (y.max() < o+n-1)) goto redo; assert((n >= 2) && x[0].none() && x[n-1].none()); assert((y.min()-o == 0) && (y.max()-o == n-1)); // Propagate from y to Boolean views if ((IntView::me(med) == ME_INT_BND) || (IntView::me(med) == ME_INT_DOM)) { ViewValues<IntView> v(y); int i=0; do { int j = v.val()-o; if (i < j) { GECODE_ME_CHECK(x[i].zero(home)); ++i; } else if (i > j) { ++v; } else { assert(i == j); ++i; ++v; } } while (v() && (i < n)); } // Propagate from Boolean views to y if (BoolView::me(med) == ME_BOOL_VAL) { BoolIter bv(x,o); GECODE_ME_CHECK(y.minus_v(home,bv,false)); } status = S_NONE; return ES_FIX; }