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; }
ExecStatus doprop_val(Space& home, int n, Info* x, Offset& ox, Info* y, Offset& oy, int& n_na, ProcessStack& xa, ProcessStack& ya) { do { int i = xa.pop(); int j = ox(x[i].view).val(); // Assign the y variable to i (or test if already assigned!) { ModEvent me = oy(y[j].view).eq(home,i); if (me_failed(me)) { return ES_FAILED; } // Record that y[j] has been assigned and must be propagated if (me_modified(me)) ya.push(j); } // Prune the value j from all x variables for (int k=i; k--; ) { ModEvent me = ox(x[k].view).nq(home,j); if (me_failed(me)) { return ES_FAILED; } if (me_modified(me)) { if (me == ME_INT_VAL) { // Record that x[k] has been assigned and must be propagated xa.push(k); } else { // One value has been removed and this removal does not need // to be propagated again: after all y[j] = i, so it holds // that y[j] != k. x[k].removed(j); } } } // The same for the other views for (int k=i+1; k<n; k++) { ModEvent me = ox(x[k].view).nq(home,j); if (me_failed(me)) { return ES_FAILED; } if (me_modified(me)) { if (me == ME_INT_VAL) { // Record that x[k] has been assigned and must be propagated xa.push(k); } else { // One value has been removed and this removal does not need // to be propagated again: after all y[j] = i, so it holds // that y[j] != k. x[k].removed(j); } } } x[i].assigned(); n_na--; } while (!xa.empty()); return ES_OK; }
ExecStatus ViewValuesBrancher<n,min>::commit(Space& home, const Choice& c, unsigned int a) { const PosValuesChoice& pvc = static_cast<const PosValuesChoice&>(c); IntView x(ViewBrancher<IntView,n>::view(pvc.pos())); unsigned int b = min ? a : (pvc.alternatives() - 1 - a); return me_failed(x.eq(home,pvc.val(b))) ? ES_FAILED : ES_OK; }
ExecStatus ViewValuesBrancher<ViewSel,View> ::commit(Space& home, const Choice& c, unsigned int a) { const PosValuesChoice<ViewSel,View>& pvc = static_cast<const PosValuesChoice<ViewSel,View>&>(c); View v(ViewBrancher<ViewSel>::view(pvc.pos()).varimp()); viewsel.commit(home, pvc.viewchoice(), a); return me_failed(v.eq(home,pvc.val(a))) ? ES_FAILED : ES_OK; }
forceinline ModEvent ManFlexTask::norun(Space& home, int e, int l) { if (e <= l) { Iter::Ranges::Singleton sr(e-_p.min()+1,l); if (me_failed(_s.minus_r(home,sr,false))) return Int::ME_INT_FAILED; Iter::Ranges::Singleton er(e+1,_p.min()+l); return _e.minus_r(home,er,false); } else { return Int::ME_INT_NONE; } }
inline bool narrow_domy(Space& home, ViewArray<View>& x, ViewArray<View>& y, int phi[], int phiprime[], bool& nofix) { for (int i=x.size(); i--; ) { ModEvent me_lb = y[i].gq(home, x[phiprime[i]].min()); if (me_failed(me_lb)) { return false; } nofix |= (me_modified(me_lb) && x[phiprime[i]].min() != y[i].min()); ModEvent me_ub = y[i].lq(home, x[phi[i]].max()); if (me_failed(me_ub)) { return false; } nofix |= (me_modified(me_ub) && x[phi[i]].max() != y[i].max()); } return true; }
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 ExcNGL::prune(Space& home) { return me_failed(x.include(home,n)) ? ES_FAILED : ES_OK; }
ExecStatus NqNGL<View>::prune(Space& home) { return me_failed(x.eq(home,n)) ? ES_FAILED : ES_OK; }
/* * Propagation proper * */ ExecStatus Pack::propagate(Space& home, const ModEventDelta& med) { // Number of items int n = bs.size(); // Number of bins int m = l.size(); { Region region(home); // Possible sizes for bins int* s = region.alloc<int>(m); for (int j=m; j--; ) s[j] = 0; // Compute sizes for bins if (OffsetView::me(med) == ME_INT_VAL) { // Also eliminate assigned items int k=0; for (int i=0; i<n; i++) if (bs[i].assigned()) { int j = bs[i].bin().val(); l[j].offset(l[j].offset() - bs[i].size()); t -= bs[i].size(); } else { for (ViewValues<IntView> j(bs[i].bin()); j(); ++j) s[j.val()] += bs[i].size(); bs[k++] = bs[i]; } n=k; bs.size(n); } else { for (int i=n; i--; ) { assert(!bs[i].assigned()); for (ViewValues<IntView> j(bs[i].bin()); j(); ++j) s[j.val()] += bs[i].size(); } } // Propagate bin loads and compute lower and upper bound int min = t, max = t; for (int j=m; j--; ) { GECODE_ME_CHECK(l[j].gq(home,0)); GECODE_ME_CHECK(l[j].lq(home,s[j])); min -= l[j].max(); max -= l[j].min(); } // Propagate that load must be equal to total size for (bool mod = true; mod; ) { mod = false; ModEvent me; for (int j=m; j--; ) { int lj_min = l[j].min(); me = l[j].gq(home, min + l[j].max()); if (me_failed(me)) return ES_FAILED; if (me_modified(me)) { max += lj_min - l[j].min(); mod = true; } int lj_max = l[j].max(); me = l[j].lq(home, max + l[j].min()); if (me_failed(me)) return ES_FAILED; if (me_modified(me)) { min += lj_max - l[j].max(); mod = true; } } } if (n == 0) { assert(l.assigned()); return home.ES_SUBSUMED(*this); } { TellCache tc(region,m); int k=0; for (int i=0; i<n; i++) { for (ViewValues<IntView> j(bs[i].bin()); j(); ++j) { if (bs[i].size() > l[j.val()].max()) tc.nq(j.val()); if (s[j.val()] - bs[i].size() < l[j.val()].min()) tc.eq(j.val()); } GECODE_ES_CHECK(tc.tell(home,bs[i].bin())); // Eliminate assigned bin if (bs[i].assigned()) { int j = bs[i].bin().val(); l[j].offset(l[j].offset() - bs[i].size()); t -= bs[i].size(); } else { bs[k++] = bs[i]; } } n=k; bs.size(n); } } // Only if the propagator is at fixpoint here, continue with the more // expensive stage for propagation. if (IntView::me(modeventdelta()) != ME_INT_NONE) return ES_NOFIX; // Now the invariant holds that no more assigned bins exist! { Region region(home); // Size of items SizeSetMinusOne* s = region.alloc<SizeSetMinusOne>(m); for (int j=m; j--; ) s[j] = SizeSetMinusOne(region,n); // Set up size information for (int i=0; i<n; i++) { assert(!bs[i].assigned()); for (ViewValues<IntView> j(bs[i].bin()); j(); ++j) s[j.val()].add(bs[i].size()); } for (int j=m; j--; ) { // Can items still be packed into bin? if (nosum(static_cast<SizeSet&>(s[j]), l[j].min(), l[j].max())) return ES_FAILED; int ap, bp; // Must there be packed more items into bin? if (nosum(static_cast<SizeSet&>(s[j]), l[j].min(), l[j].min(), ap, bp)) GECODE_ME_CHECK(l[j].gq(home,bp)); // Must there be packed less items into bin? if (nosum(static_cast<SizeSet&>(s[j]), l[j].max(), l[j].max(), ap, bp)) GECODE_ME_CHECK(l[j].lq(home,ap)); } TellCache tc(region,m); int k=0; for (int i=0; i<n; i++) { assert(!bs[i].assigned()); for (ViewValues<IntView> j(bs[i].bin()); j(); ++j) { // Items must be removed in decreasing size! s[j.val()].minus(bs[i].size()); // Can item i still be packed into bin j? if (nosum(s[j.val()], l[j.val()].min() - bs[i].size(), l[j.val()].max() - bs[i].size())) tc.nq(j.val()); // Must item i be packed into bin j? if (nosum(s[j.val()], l[j.val()].min(), l[j.val()].max())) tc.eq(j.val()); } GECODE_ES_CHECK(tc.tell(home,bs[i].bin())); if (bs[i].assigned()) { int j = bs[i].bin().val(); l[j].offset(l[j].offset() - bs[i].size()); t -= bs[i].size(); } else { bs[k++] = bs[i]; } } n=k; bs.size(n); } // Perform lower bound checking if (n > 0) { Region region(home); // Find capacity estimate (we start from bs[0] as it might be // not packable, actually (will be detected later anyway)! int c = bs[0].size(); for (int j=m; j--; ) c = std::max(c,l[j].max()); // Count how many items have a certain size (bucket sort) int* n_s = region.alloc<int>(c+1); for (int i=c+1; i--; ) n_s[i] = 0; // Count unpacked items for (int i=n; i--; ) n_s[bs[i].size()]++; // Number of items and remaining bin load int nm = n; // Only count positive remaining bin loads for (int j=m; j--; ) if (l[j].max() < 0) { return ES_FAILED; } else if (c > l[j].max()) { n_s[c - l[j].max()]++; nm++; } // Sizes of items and remaining bin loads int* s = region.alloc<int>(nm); // Setup sorted sizes { int k=0; for (int i=c+1; i--; ) for (int n=n_s[i]; n--; ) s[k++]=i; assert(k == nm); } // Items in N1 are from 0 ... n1 - 1 int n1 = 0; // Items in N2 are from n1 ... n12 - 1, we count elements in N1 and N2 int n12 = 0; // Items in N3 are from n12 ... n3 - 1 int n3 = 0; // Free space in N2 int f2 = 0; // Total size of items in N3 int s3 = 0; // Initialize n12 and f2 for (; (n12 < nm) && (s[n12] > c/2); n12++) f2 += c - s[n12]; // Initialize n3 and s3 for (n3 = n12; n3 < nm; n3++) s3 += s[n3]; // Compute lower bounds for (int k=0; k<=c/2; k++) { // Make N1 larger by adding elements and N2 smaller for (; (n1 < nm) && (s[n1] > c-k); n1++) f2 -= c - s[n1]; assert(n1 <= n12); // Make N3 smaller by removing elements for (; (s[n3-1] < k) && (n3 > n12); n3--) s3 -= s[n3-1]; // Overspill int o = (s3 > f2) ? ((s3 - f2 + c - 1) / c) : 0; if (n12 + o > m) return ES_FAILED; } } return ES_NOFIX; }
inline bool perm_bc(Space& home, int tau[], SccComponent sinfo[], int scclist[], ViewArray<View>& x, ViewArray<View>& z, bool& crossingedge, bool& nofix) { int ps = x.size(); for (int i = 1; i < ps; i++) { // if there are "crossed edges" if (x[i - 1].min() < x[i].min()) { if (z[i - 1].min() > z[i].min()) { if (z[i].min() != sinfo[scclist[i]].leftmost) { // edge does not take part in solution if (z[i].assigned()) { // vital edge do not remove it if (x[i - 1].max() < x[i].min()) { // invalid permutation // the upper bound sorting cannot fix this return false; } } else { crossingedge = true; // and the permutation can still be changed // fix the permutation, i.e. modify z ModEvent me_z = z[i].gq(home, z[i - 1].min()); if (me_failed(me_z)) { return false; } nofix |= ( me_modified(me_z) && z[i - 1].min() != z[i].min()); } } } } } // the same check as above for the upper bounds for (int i = ps - 1; i--; ) { if (x[tau[i]].max() < x[tau[i + 1]].max()) { if (z[tau[i]].max() > z[tau[i + 1]].max()) { if (z[tau[i]].max() != sinfo[scclist[tau[i]]].rightmost) { // edge does not take part in solution if (z[tau[i]].assigned()) { if (x[tau[i + 1]].min() > x[tau[i]].max()) { // invalid permutation return false; } } else { crossingedge = true; ModEvent me_z = z[tau[i]].lq(home, z[tau[i + 1]].max()); if (me_failed(me_z)) { return false; } nofix |= (me_modified(me_z) && z[tau[i + 1]].max() != z[tau[i]].max()); } } } } } return true; }
ExecStatus prop_val(Space& home, ViewArray<View>& x) { assert(x.size() > 1); int n = x.size(); Region r(home); int* stack = r.alloc<int>(n); int* c_v = &stack[0]; // c_n is the current number of values on stack int c_n = 0; // Collect all assigned variables on stack for (int i = n; i--; ) if (x[i].assigned()) { c_v[c_n++]=x[i].val(); x[i]=x[--n]; } // The number of trips int t = 0; do { t++; if (!complete && (t > 16)) { // Give up after sixteen iterations, but the values must be // propagated first // Maybe we are lucky in that this iteration does the trick... ExecStatus es = ES_FIX; while (c_n > 0) { int v = c_v[--c_n]; // Check whether value is on stack only once for (int i = c_n; i--; ) if (c_v[i] == v) goto failed; // Tell and do not collect new values for (int i = n; i--; ) { ModEvent me = x[i].nq(home,v); if (me_failed(me)) goto failed; if (me == ME_INT_VAL) es = ES_NOFIX; } } x.size(n); return es; } if (c_n > 31) { // Many values, use full domain operation IntSet d(&c_v[0],c_n); // If the size s of d is different from the number of values, // a value must have appeared multiply: failure if (d.size() != static_cast<unsigned int>(c_n)) goto failed; // We do not need the values on the stack any longer, reset c_n = 0; // Tell and collect new values for (int i = n; i--; ) if ((d.min() <= x[i].max()) && (d.max() >= x[i].min())) { IntSetRanges dr(d); ModEvent me = x[i].minus_r(home,dr,false); if (me_failed(me)) goto failed; if (me == ME_INT_VAL) { c_v[c_n++]=x[i].val(); x[i]=x[--n]; } } } else { // Values for next iteration int* n_v = &c_v[c_n]; // Stack top for the next iteration int n_n = 0; while (c_n > 0) { int v = c_v[--c_n]; // Check whether value is not on current stack for (int i = c_n; i--; ) if (c_v[i] == v) goto failed; // Check whether value is not on next stack for (int i = n_n; i--; ) if (n_v[i] == v) goto failed; // Tell and collect new values for (int i = n; i--; ) { ModEvent me = x[i].nq(home,v); if (me_failed(me)) goto failed; if (me == ME_INT_VAL) { n_v[n_n++]=x[i].val(); x[i]=x[--n]; } } } c_v = n_v; c_n = n_n; } } while (c_n > 0); x.size(n); return ES_FIX; failed: x.size(0); return ES_FAILED; }
inline bool narrow_domx(Space& home, ViewArray<View>& x, ViewArray<View>& y, ViewArray<View>& z, int tau[], int[], int scclist[], SccComponent sinfo[], bool& nofix) { int xs = x.size(); // For every x node for (int i = 0; i < xs; i++) { int xmin = x[i].min(); /* * take the scc-list for the current x node * start from the leftmost reachable y node of the scc * and check which Y node in the scc is * really the rightmost node intersecting x, i.e. * search for the greatest lower bound of x */ int start = sinfo[scclist[i]].leftmost; while (y[start].max() < xmin) { start = sinfo[start].right; } if (Perm) { // start is the leftmost-position for x_i // that denotes the lower bound on p_i ModEvent me_plb = z[i].gq(home, start); if (me_failed(me_plb)) { return false; } nofix |= (me_modified(me_plb) && start != z[i].min()); } ModEvent me_lb = x[i].gq(home, y[start].min()); if (me_failed(me_lb)) { return false; } nofix |= (me_modified(me_lb) && y[start].min() != x[i].min()); int ptau = tau[xs - 1 - i]; int xmax = x[ptau].max(); /* * take the scc-list for the current x node * start from the rightmost reachable node and check which * y node in the scc is * really the rightmost node intersecting x, i.e. * search for the smallest upper bound of x */ start = sinfo[scclist[ptau]].rightmost; while (y[start].min() > xmax) { start = sinfo[start].left; } if (Perm) { //start is the rightmost-position for x_i //that denotes the upper bound on p_i ModEvent me_pub = z[ptau].lq(home, start); if (me_failed(me_pub)) { return false; } nofix |= (me_modified(me_pub) && start != z[ptau].max()); } ModEvent me_ub = x[ptau].lq(home, y[start].max()); if (me_failed(me_ub)) { return false; } nofix |= (me_modified(me_ub) && y[start].max() != x[ptau].max()); } return true; }