inline ExecStatus NaryNq<View>::post(Home home, ViewArray<View>& x) { x.unique(home); // Try to find an assigned view int n = x.size(); if (n <= 1) return ES_FAILED; for (int i=n; i--; ) if (x[i].assigned()) { std::swap(x[0],x[i]); break; } if (x[0].assigned()) { int v = x[0].val(); // Eliminate all equal views and possibly find disequal view for (int i=n-1; i>0; i--) if (!x[i].in(v)) { return ES_OK; } else if (x[i].assigned()) { assert(x[i].val() == v); x[i]=x[--n]; } x.size(n); } if (n == 1) return ES_FAILED; if (n == 2) return Nq<View>::post(home,x[0],x[1]); (void) new (home) NaryNq(home,x); return ES_OK; }
ExecStatus EqBoolView<XV,YV>::post(Home home, ViewArray<XV>& x, YV y, int c) { if (y.assigned()) return EqBoolInt<XV>::post(home,x,y.val()+c); 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 ES_OK; if (y.min()+c == n) { assert(y.assigned()); for (int i = n; i--; ) GECODE_ME_CHECK(x[i].one_none(home)); return ES_OK; } if (y.max()+c == 0) { assert(y.assigned()); for (int i = n; i--; ) GECODE_ME_CHECK(x[i].zero_none(home)); return ES_OK; } (void) new (home) EqBoolView<XV,YV>(home,x,y,c); return ES_OK; }
inline ExecStatus Prop<View>::post(Home home, ViewArray<View>& x, View y) { if (x.size() == 0) return ES_FAILED; x.unique(home); if (x.size() == 1) return Rel::EqDom<View,View>::post(home,x[0],y); if (x.same(home,y)) return ES_OK; // Eliminate assigned views and store them into the value set ValSet vs; add(home, vs, x); if (x.size() == 0) { ValSet::Ranges vsr(vs); GECODE_ME_CHECK(y.inter_r(home,vsr,false)); return ES_OK; } (void) new (home) Prop<View>(home, vs, x, y); return ES_OK; }
ExecStatus LqInt<VX,VY>::post(Home home, ViewArray<VX>& x, VY y, int c) { // Eliminate decided views int n_x = x.size(); for (int i=n_x; i--; ) switch (holds(x[i],y)) { case RT_FALSE: x[i] = x[--n_x]; break; case RT_TRUE: x[i] = x[--n_x]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n_x); if (c < 0) return ES_FAILED; if (c >= n_x) return ES_OK; // All views must be different if (c == 0) return post_false(home,x,y); (void) new (home) LqInt<VX,VY>(home,x,n_x-c+1,y,c); return ES_OK; }
ExecStatus EqInt<VX,VY>::post(Home home, ViewArray<VX>& x, VY y, int c) { // Eliminate decided views int n_x = x.size(); for (int i=n_x; i--; ) switch (holds(x[i],y)) { case RT_FALSE: x[i] = x[--n_x]; break; case RT_TRUE: x[i] = x[--n_x]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n_x); // RHS too small or too large if ((c < 0) || (c > n_x)) return ES_FAILED; // All views must be different if (c == 0) return post_false(home,x,y); // All views must be equal if (c == n_x) return post_true(home,x,y); // Compute how many subscriptions must be created int n_s = std::max(c,n_x-c)+1; assert(n_s <= n_x); (void) new (home) EqInt<VX,VY>(home,x,n_s,y,c); return ES_OK; }
inline bool normalize(Space& home, ViewArray<View>& y, ViewArray<View>& x, bool& nofix) { int ys = y.size(); for (int i = 1; i < ys; i++) { ModEvent me_lb = y[i].gq(home, y[i - 1].min()); if (me_failed(me_lb)) return false; nofix |= (me_modified(me_lb) && y[i - 1].min() != y[i].min()); } for (int i = ys - 1; i--; ) { ModEvent me_ub = y[i].lq(home, y[i + 1].max()); if (me_failed(me_ub)) return false; nofix |= (me_modified(me_ub) && y[i + 1].max() != y[i].max()); } int xs = x.size(); for (int i = xs; i--; ) { ModEvent me = x[i].gq(home, y[0].min()); if (me_failed(me)) return false; nofix |= (me_modified(me) && x[i].min() != y[0].min()); me = x[i].lq(home, y[xs - 1].max()); if (me_failed(me)) return false; nofix |= (me_modified(me) && x[i].max() != y[xs - 1].max()); } return true; }
inline ExecStatus Single<View>::post(Home home, ViewArray<View>& x, int s, int t) { { int alpha = 0; while ((alpha < x.size()) && !x[alpha].in(s)) GECODE_ME_CHECK(x[alpha++].nq(home,t)); x.drop_fst(alpha); if (x.size() == 0) return ES_OK; } // alpha has been normalized to 0 int beta = 0, gamma = 0; GECODE_ME_CHECK(x[0].nq(home,t)); do { gamma++; } while ((gamma < x.size()) && !assigned(x[gamma],t)); do { beta++; } while ((beta < x.size()) && !x[beta].in(s)); if (beta > gamma) { GECODE_ME_CHECK(x[0].eq(home, s)); return ES_OK; } if (gamma < x.size()) x.drop_lst(gamma); (void) new (home) Single<View>(home, x, s, t, beta, gamma); return ES_OK; }
forceinline Incremental<View>::Incremental(Home home, ViewArray<View>& x, const TupleSet& t) : Base<View,false>(home,x,t), support_data(NULL), unassigned(x.size()), ac(home) { init_support(home); // Post advisors for (int i = x.size(); i--; ) if (x[i].assigned()) { --unassigned; } else { x[i].subscribe(home,*new (home) SupportAdvisor(home,*this,ac,i)); } Region r(home); // Add initial supports BitSet* dom = r.alloc<BitSet>(x.size()); init_dom(home, dom); for (int i = x.size(); i--; ) for (ViewValues<View> vv(x[i]); vv(); ++vv) find_support(home, dom, i, vv.val()); // Work to be done or subsumption if (!w_support.empty() || !w_remove.empty() || (unassigned == 0)) View::schedule(home,*this, (unassigned != x.size()) ? ME_INT_VAL : ME_INT_DOM); }
ExecStatus NaryEqv::post(Home home, ViewArray<BoolView>& x, int pm2) { int n = x.size(); for (int i=n; i--; ) if (x[i].assigned()) { pm2 ^= x[i].val(); x[i] = x[--n]; } if (n == 0) return (pm2 == 1) ? ES_OK : ES_FAILED; if (n == 1) { GECODE_ME_CHECK(x[0].eq(home,1^pm2)); return ES_OK; } if (n == 2) { if (pm2 == 1) { return Bool::Eq<BoolView,BoolView>::post(home,x[0],x[1]); } else { NegBoolView n(x[1]); return Bool::Eq<BoolView,NegBoolView>::post(home,x[0],n); } } x.size(n); (void) new (home) NaryEqv(home,x,pm2); return ES_OK; }
ExecStatus GqInt<VX,VY>::post(Home home, ViewArray<VX>& x, VY y, int c) { // Eliminate decided views int n_x = x.size(); for (int i=n_x; i--; ) switch (holds(x[i],y)) { case RT_FALSE: x[i] = x[--n_x]; break; case RT_TRUE: x[i] = x[--n_x]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n_x); // RHS too large if (n_x < c) return ES_FAILED; // Whatever the x[i] take for values, the inequality is subsumed if (c <= 0) return ES_OK; // All views must be equal if (c == n_x) return post_true(home,x,y); (void) new (home) GqInt<VX,VY>(home,x,c+1,y,c); return ES_OK; }
ExecStatus Val<View>::post(Home home, ViewArray<View>& x) { if (x.size() == 2) return Rel::Nq<View>::post(home,x[0],x[1]); if (x.size() > 2) (void) new (home) Val<View>(home,x); return ES_OK; }
forceinline ExecStatus post_true(Home home, ViewArray<VX>& x, VX y) { ViewArray<VX> z(home,x.size()+1); z[x.size()] = y; for (int i = x.size(); i--; ) z[i] = x[i]; return Rel::NaryEqDom<VX>::post(home,z); }
inline void sort_tau(ViewArray<View>& x, ViewArray<View>& z, int tau[]) { if (Perm) { TupleMaxIncExt<View> ltmax(x,z); Support::quicksort(&(*tau), x.size(), ltmax); } else { TupleMaxInc<View> ltmax(x); Support::quicksort(&(*tau), x.size(), ltmax); } }
forceinline void Prop<View>::add(Space& home, ValSet& vs, ViewArray<View>& x) { int n=x.size(); for (int i=n; i--; ) if (x[i].assigned()) { vs.add(home, x[i].val()); x[i] = x[--n]; } x.size(n); }
// Copy constructor during cloning NoOverlap(Space& home, bool share, NoOverlap& p) : Propagator(home,share,p) { x.update(home,share,p.x); y.update(home,share,p.y); // Also copy width and height arrays w = home.alloc<int>(x.size()); h = home.alloc<int>(y.size()); for (int i=x.size(); i--; ) { w[i]=p.w[i]; h[i]=p.h[i]; } }
forceinline ExecStatus prune(Space& home, ViewArray<VX>& x, VX y) { if (x.size() == 0) return ES_OK; Region r(home); ViewRanges<VX>* rx = r.alloc<ViewRanges<VX> >(x.size()); for (int i=x.size(); i--; ) rx[i] = ViewRanges<VX>(x[i]); Iter::Ranges::NaryUnion u(r, rx, x.size()); GECODE_ME_CHECK(y.inter_r(home, u, false)); return ES_OK; }
inline ExecStatus LqBool<VY>::post(Home home, ViewArray<BoolView>& x, VY y) { if (x.size() == 0) { GECODE_ME_CHECK(y.gq(home,0)); return ES_OK; } x.unique(home); GECODE_ME_CHECK(y.gq(home,1)); if (x.size() == 1) return ES_OK; if (y.max() == 1) { assert(y.assigned()); ViewArray<BoolView> xc(home,x); return Bool::NaryEq<BoolView>::post(home,xc); } if (y.min() >= 2) return ES_OK; int n = x.size(); int status = 0; for (int i=n; i--; ) if (x[i].zero()) { if (status & VS_ONE) { GECODE_ME_CHECK(y.gq(home,2)); return ES_OK; } x[i] = x[--n]; status |= VS_ZERO; } else if (x[i].one()) { if (status & VS_ZERO) { GECODE_ME_CHECK(y.gq(home,2)); return ES_OK; } x[i] = x[--n]; status |= VS_ONE; } assert(status != (VS_ZERO | VS_ONE)); if (n == 0) { assert((status != 0) && (y.min() >= 1)); return ES_OK; } x.size(n); (void) new (home) LqBool<VY>(home,status,x,y); return ES_OK; }
forceinline ExecStatus LinkMulti::post(Home home, ViewArray<BoolView>& x, IntView y, int o) { int n=x.size(); GECODE_ME_CHECK(y.gq(home,o)); GECODE_ME_CHECK(y.lq(home,o+n-1)); assert(n > 0); if (n == 1) { GECODE_ME_CHECK(x[0].one(home)); assert(y.val() == o); } else if (y.assigned()) { 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)); } else { for (int i=n; 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,o+i)); return ES_OK; } else if (x[i].zero()) { GECODE_ME_CHECK(y.nq(home,o+i)); } (void) new (home) LinkMulti(home,x,y,o); } return ES_OK; }
forceinline ExecStatus ChannelBool<View>::post(Home home, ViewArray<Gecode::Int::BoolView>& x, View y) { GECODE_ME_CHECK(y.intersect(home, 0, x.size()-1)); (void) new (home) ChannelBool(home,x,y); return ES_OK; }
ExecStatus SeqU::propagateSeqUnion(Space& home, bool& modified, ViewArray<SetView>& x, SetView& y) { Region r(home); GlbRanges<SetView>* XLBs = r.alloc<GlbRanges<SetView> >(x.size()); for (int i=x.size(); i--; ){ GlbRanges<SetView> lb(x[i]); XLBs[i]=lb; } Iter::Ranges::NaryAppend<GlbRanges<SetView> > u(XLBs,x.size()); GECODE_ME_CHECK_MODIFIED(modified, y.includeI(home,u)); GLBndSet before(home); for (int i=0; i<x.size(); i++) { LubRanges<SetView> xiub(x[i]); before.includeI(home, xiub); BndSetRanges beforeR(before); GlbRanges<SetView> ylb(y); Iter::Ranges::Diff<GlbRanges<SetView>, BndSetRanges> diff(ylb, beforeR); if (diff()) { GECODE_ME_CHECK_MODIFIED(modified, x[i].exclude(home, diff.min(), Limits::max)); } } before.dispose(home); GLBndSet after(home); for (int i=x.size(); i--; ) { LubRanges<SetView> xiub(x[i]); after.includeI(home, xiub); BndSetRanges afterR(after); GlbRanges<SetView> ylb(y); Iter::Ranges::Diff<GlbRanges<SetView>, BndSetRanges> diff(ylb, afterR); if (diff()) { int max = diff.max(); for (; diff(); ++diff) max = diff.max(); GECODE_ME_CHECK_MODIFIED(modified, x[i].exclude(home, Limits::min, max)); } } after.dispose(home); return ES_FIX; }
inline void computesccs(Space& home, ViewArray<View>& x, ViewArray<View>& y, int phi[], SccComponent sinfo[], int scclist[]) { // number of sccs is bounded by xs (number of x-nodes) int xs = x.size(); Region r(home); Support::StaticStack<int,Region> cs(r,xs); //select an y node from the graph for (int j = 0; j < xs; j++) { int yjmin = y[j].min(); // the processed min while (!cs.empty() && x[phi[sinfo[cs.top()].rightmost]].max() < yjmin) { // the topmost scc cannot "reach" y_j or a node to the right of it cs.pop(); } // a component has the form C(y-Node, matching x-Node) // C is a minimal scc in the oriented intersection graph // we only store y_j-Node, since \phi(j) gives the matching X-node int i = phi[j]; int ximin = x[i].min(); while (!cs.empty() && ximin <= y[sinfo[cs.top()].rightmost].max()) { // y_j can "reach" cs.top() , // i.e. component c can reach component cs.top() // merge c and cs.top() into new component int top = cs.top(); // connecting sinfo[sinfo[j].leftmost].left = top; sinfo[top].right = sinfo[j].leftmost; // moving leftmost sinfo[j].leftmost = sinfo[top].leftmost; // moving rightmost sinfo[sinfo[top].leftmost].rightmost = j; cs.pop(); } cs.push(j); } cs.reset(); // now we mark all components with the respective scc-number // labeling is bound by O(k) which is bound by O(n) for (int i = 0; i < xs; i++) { if (sinfo[i].left == i) { // only label variables in sccs int scc = sinfo[i].rightmost; int z = i; //bound by the size of the largest scc = k while (sinfo[z].right != z) { sinfo[z].rightmost = scc; scclist[phi[z]] = scc; z = sinfo[z].right; } sinfo[z].rightmost = scc; scclist[phi[z]] = scc; } } }
// Post no-overlap propagator static ExecStatus post(Home home, ViewArray<IntView>& x, int w[], ViewArray<IntView>& y, int h[]) { // Only if there is something to propagate if (x.size() > 1) (void) new (home) NoOverlap(home,x,w,y,h); return ES_OK; }
static ExecStatus post(Home home, ViewArray<IntView>& x, int s[], bool a[], int n, int m, int t, int sz) { if(DEBUG) { std::cerr << "p"; } // only post if there is something to propagate if(x.size() > 1) { (void) new (home) NonLinearity(home,x,s,a,n,m,t,sz); } return ES_OK; }
forceinline ExecStatus post_false(Home home, ViewArray<VX>& x, const IntSet& y) { for (int i = x.size(); i--; ) { IntSetRanges ry(y); GECODE_ME_CHECK(x[i].minus_r(home,ry,false)); } return ES_OK; }
inline ExecStatus ReProp<View,rm>::post(Home home, ViewArray<View>& x, View y, BoolView b) { if (x.size() == 0) { if (rm != RM_PMI) GECODE_ME_CHECK(b.zero(home)); return ES_OK; } x.unique(home); if (x.size() == 1) return Rel::ReEqDom<View,BoolView,rm>::post(home,x[0],y,b); if (x.same(home,y)) { if (rm != RM_IMP) GECODE_ME_CHECK(b.one(home)); return ES_OK; } // Eliminate assigned views and store them into the value set ValSet vs; add(home, vs, x); switch (vs.compare(y)) { case Iter::Ranges::CS_SUBSET: if (rm != RM_IMP) GECODE_ME_CHECK(b.one(home)); return ES_OK; case Iter::Ranges::CS_DISJOINT: if (x.size() == 0) { if (rm != RM_PMI) GECODE_ME_CHECK(b.zero(home)); return ES_OK; } break; case Iter::Ranges::CS_NONE: break; default: GECODE_NEVER; } (void) new (home) ReProp<View,rm>(home, vs, x, y, b); return ES_OK; }
inline void sort_sigma(Space& home, ViewArray<View>& x, ViewArray<View>& z) { if (Perm) { Region r(home); ViewPair<View>* xz = r.alloc<ViewPair<View> >(x.size()); for (int i=x.size(); i--; ) { xz[i].x=x[i]; xz[i].z=z[i]; } TupleMinIncExt<View> min_inc; Support::quicksort<ViewPair<View>,TupleMinIncExt<View> > (&xz[0], x.size(), min_inc); for (int i=x.size(); i--; ) { x[i]=xz[i].x; z[i]=xz[i].z; } } else { TupleMinInc<View> min_inc; Support::quicksort<View,TupleMinInc<View> >(&x[0], x.size(), min_inc); } }
forceinline ExecStatus Incremental<View>::post(Home home, ViewArray<View>& x, const TupleSet& t) { // All variables in the correct domain for (int i = x.size(); i--; ) { GECODE_ME_CHECK(x[i].gq(home, t.min())); GECODE_ME_CHECK(x[i].lq(home, t.max())); } (void) new (home) Incremental<View>(home,x,t); return ES_OK; }
forceinline bool ViewBase<VX,VY,VZ>::sharing(const ViewArray<VX>& x, const VY& y, const VZ& z) { if (shared(y,z)) return true; for (int i = x.size(); i--; ) if (shared(x[i],z)) return true; return false; }
inline ExecStatus LqInt<VY>::post(Home home, ViewArray<IntView>& x, VY y) { if (x.size() == 0) { GECODE_ME_CHECK(y.eq(home,0)); return ES_OK; } x.unique(home); GECODE_ME_CHECK(y.gq(home,1)); if (x.size() == 1) return ES_OK; if (y.max() == 1) { assert(y.assigned()); return Rel::NaryEqDom<IntView>::post(home,x); } if (y.min() >= x.size()) return ES_OK; // Eliminate assigned views and store them into the value set ValSet vs; int n = x.size(); for (int i=n; i--; ) if (x[i].assigned()) { vs.add(home, x[i].val()); x[i] = x[--n]; } GECODE_ME_CHECK(y.gq(home,vs.size())); if (n == 0) { assert(y.min() >= vs.size()); return ES_OK; } x.size(n); (void) new (home) LqInt<VY>(home, vs, x, y); return ES_OK; }
forceinline BoolBase<VY>::BoolBase(Home home, int status0, ViewArray<BoolView>& x, VY y0) : Propagator(home), status(status0), c(home), y(y0) { y.subscribe(home,*this,PC_INT_BND); for (int i=x.size(); i--; ) { assert(!x[i].assigned()); (void) new (home) ViewAdvisor<BoolView>(home, *this, c, x[i]); } }