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; }
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 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; }
/* * 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 ElementUnionConst<SView,RView>::propagate(Space& home, const ModEventDelta&) { Region r(home); bool* stillSelected = r.alloc<bool>(n_iv); bool loopVar; do { loopVar = false; for (int i=n_iv; i--;) stillSelected[i] = false; // Cache the upper bound iterator, as we have to // modify the upper bound while iterating LubRanges<RView> x1ub(x1); Iter::Ranges::Cache x1ubc(r,x1ub); Iter::Ranges::ToValues<Iter::Ranges::Cache> vx1ub(x1ubc); GlbRanges<RView> x1lb(x1); Iter::Ranges::Cache x1lbc(r,x1lb); Iter::Ranges::ToValues<Iter::Ranges::Cache> 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. GLBndSet sofarBefore(home); LUBndSet selectedInter(home, IntSet (Limits::min, Limits::max)); GLBndSet* before = static_cast<GLBndSet*>(r.ralloc(sizeof(GLBndSet)*n_iv)); unsigned int maxCard = 0; unsigned int minCard = Limits::card; while (vx1ub()) { int i = vx1ub.val(); IntSetRanges candCardR(iv[i]); unsigned int candidateCard = Iter::Ranges::size(candCardR); IntSetRanges candlb(iv[i]); LubRanges<SView> x0ub(x0); Iter::Ranges::Diff<IntSetRanges, LubRanges<SView> > diff(candlb, x0ub); bool selectSingleInconsistent = false; if (x1.cardMax() <= 1) { GlbRanges<SView> x0lb(x0); IntSetRanges candub(iv[i]); Iter::Ranges::Diff<GlbRanges<SView>, IntSetRanges > diff2(x0lb, candub); selectSingleInconsistent = diff2() || candidateCard < 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 || candidateCard > x0.cardMax() || diff()) { ModEvent me = (x1.exclude(home,i)); loopVar |= me_modified(me); GECODE_ME_CHECK(me); } else { stillSelected[i] = true; // if x_i is consistent, check whether we know // that its index is in x1 if (vx1() && vx1.val()==i) { // x0 >= candidate, candidate <= x0 // GlbRanges<SView> candlb(candidate); IntSetRanges candlb(iv[i]); ModEvent me = x0.includeI(home,candlb); loopVar |= me_modified(me); GECODE_ME_CHECK(me); ++vx1; } new (&before[i]) GLBndSet(home); before[i].update(home,sofarBefore); IntSetRanges cub(iv[i]); sofarBefore.includeI(home,cub); IntSetRanges clb(iv[i]); selectedInter.intersectI(home,clb); maxCard = std::max(maxCard, candidateCard); minCard = std::min(minCard, candidateCard); } ++vx1ub; } if (x1.cardMax()==0) { // Selector is empty, hence the result must be empty { GECODE_ME_CHECK(x0.cardMax(home,0)); } for (int i=n_iv; i--;) if (stillSelected[i]) before[i].dispose(home); selectedInter.dispose(home); sofarBefore.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_iv; i--;) { if (!stillSelected[i]) continue; 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,i)); loopVar |= me_modified(me); GECODE_ME_CHECK(me); // candidate != extra IntSetRanges ivi(iv[i]); if (!Iter::Ranges::subset(diff, ivi)) GECODE_ME_CHECK(ME_SET_FAILED); } IntSetRanges iviub(iv[i]); sofarAfter.includeI(home,iviub); before[i].dispose(home); } sofarAfter.dispose(home); } while (loopVar); if (x1.assigned()) { assert(x0.assigned()); return home.ES_SUBSUMED(*this); } return ES_FIX; }
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; }
ExecStatus Weights<View>::propagate(Space& home, const ModEventDelta&) { ModEvent me = ME_SET_NONE; if (!x.assigned()) { // Collect the weights of the elements in the unknown set in an array int size = elements.size(); Region r(home); int* currentWeights = r.alloc<int>(size); UnknownRanges<View> ur(x); Iter::Ranges::ToValues<UnknownRanges<View> > urv(ur); for (int i=0; i<size; i++) { if (!urv() || elements[i]<urv.val()) { currentWeights[i] = 0; } else { assert(elements[i] == urv.val()); currentWeights[i] = weights[i]; ++urv; } } // Sort the weights of the unknown elements IntLess il; Support::quicksort<int>(currentWeights, size, il); // The maximum number of elements that can still be added to x int delta = static_cast<int>(std::min(x.unknownSize(), x.cardMax() - x.glbSize())); // The weight of the elements already in x GlbRanges<View> glb(x); int glbWeight = weightI<GlbRanges<View> >(elements, weights, glb); // Compute the weight of the current lower bound of x, plus at most // delta-1 further elements with smallest negative weights. This weight // determines which elements in the upper bound cannot possibly be // added to x (those whose weight would exceed the capacity even if // all other elements are minimal) int lowWeight = glbWeight; for (int i=0; i<delta-1; i++) { if (currentWeights[i] >= 0) break; lowWeight+=currentWeights[i]; } // Compute the lowest possible weight of x. If there is another element // with negative weight left, then add its weight to lowWeight. // Otherwise lowWeight is already the lowest possible weight. int lowestWeight = lowWeight; if (delta>0 && currentWeights[delta-1]<0) lowestWeight+=currentWeights[delta-1]; // If after including the minimal number of required elements, // no more element with negative weight is available, then // a tighter lower bound can be computed. if ( (x.cardMin() - x.glbSize() > 0 && currentWeights[x.cardMin() - x.glbSize() - 1] >= 0) || currentWeights[0] >= 0 ) { int lowestPosWeight = glbWeight; for (unsigned int i=0; i<x.cardMin() - x.glbSize(); i++) { lowestPosWeight += currentWeights[i]; } lowestWeight = std::max(lowestWeight, lowestPosWeight); } // Compute the highest possible weight of x as the weight of the lower // bound plus the weight of the delta heaviest elements still in the // upper bound. int highestWeight = glbWeight; for (int i=0; i<delta; i++) { if (currentWeights[size-i-1]<=0) break; highestWeight += currentWeights[size-i-1]; } // Prune the weight using the computed bounds GECODE_ME_CHECK(y.gq(home, lowestWeight)); GECODE_ME_CHECK(y.lq(home, highestWeight)); // Exclude all elements that are too heavy from the set x. // Elements are too heavy if their weight alone already // exceeds the remaining capacity int remainingCapacity = y.max()-lowWeight; UnknownRanges<View> ur2(x); Iter::Ranges::ToValues<UnknownRanges<View> > urv2(ur2); OverweightValues<Iter::Ranges::ToValues<UnknownRanges<View> > > ov(remainingCapacity, elements, weights, urv2); Iter::Values::ToRanges<OverweightValues< Iter::Ranges::ToValues<UnknownRanges<View> > > > ovr(ov); me = x.excludeI(home, ovr); GECODE_ME_CHECK(me); } if (x.assigned()) { // If x is assigned, just compute its weight and assign y. GlbRanges<View> glb(x); int w = weightI<GlbRanges<View> >(elements, weights, glb); GECODE_ME_CHECK(y.eq(home, w)); return home.ES_SUBSUMED(*this); } return me_modified(me) ? ES_NOFIX : ES_FIX; }