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 IntBase<VY>::all_in_valset(Space& home) { for (int i=x.size(); i--; ) { ValSet::Ranges vsr(vs); GECODE_ME_CHECK(x[i].inter_r(home, vsr, false)); } return home.ES_SUBSUMED(*this); }
forceinline bool ValSet::subset(View x) const { if (empty() || (x.min() < min()) || (x.max() > max())) return false; ValSet::Ranges vsr(*this); ViewRanges<View> xr(x); return Iter::Ranges::subset(xr,vsr); }
forceinline Iter::Ranges::CompareStatus ValSet::compare(View x) const { if (empty() || (x.max() < min()) || (x.min() > max())) return Iter::Ranges::CS_DISJOINT; ValSet::Ranges vsr(*this); ViewRanges<View> xr(x); return Iter::Ranges::compare(xr,vsr); }
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; }
int IntBase<VY>::size(Space& home) const { Region r(home); assert(x.size() > 0); ValSet::Ranges vsr(vs); ViewRanges<IntView> xr(x[x.size()-1]); Iter::Ranges::NaryUnion u(r,vsr,xr); for (int i=x.size()-1; i--; ) { ViewRanges<IntView> xir(x[i]); u |= xir; } unsigned int s = Iter::Ranges::size(u); // To avoid overflow if (static_cast<unsigned int>(x.size()+vs.size()) < s) return x.size() + vs.size(); else return static_cast<int>(s); }
forceinline ExecStatus IntBase<VY>::prune_upper(Space& home, Graph& g) { if (!g.initialized()) { g.init(home,vs,x); } else { g.purge(); g.sync(home); } GECODE_ME_CHECK(y.lq(home, g.size())); if (y.min() == g.size()) { // All values must be taken on if (vs.size() + x.size() == g.size()) { // This is in fact a distinct, simplify and rewrite for (int i=x.size(); i--; ) { ValSet::Ranges vsr(vs); GECODE_ME_CHECK(x[i].minus_r(home, vsr, false)); } GECODE_REWRITE(*this,Distinct::Dom<IntView>::post(home,x)); } if (g.mark(home)) GECODE_ES_CHECK(g.prune(home)); } return ES_OK; }
ExecStatus IntBase<VY>::prune_lower(Space& home, int* dis, int n_dis) { assert(n_dis > 0); // At least one more value will be needed GECODE_ME_CHECK(y.gq(home,vs.size() + 1)); Region r(home); // Only one additional value is allowed if (y.max() == vs.size() + 1) { // Compute possible values ViewRanges<IntView>* r_dis = r.alloc<ViewRanges<IntView> >(n_dis); for (int i=n_dis; i--; ) r_dis[i] = ViewRanges<IntView>(x[dis[i]]); Iter::Ranges::NaryInter iv(r, r_dis, n_dis); // Is there a common value at all? if (!iv()) return ES_FAILED; ValSet::Ranges vsr(vs); Iter::Ranges::NaryUnion pv(r,iv,vsr); // Enforce common values for (int i=x.size(); i--; ) { pv.reset(); GECODE_ME_CHECK(x[i].inter_r(home, pv, false)); } return ES_OK; } // Compute independent set for lower bound // ovl is a bit-matrix defining whether two views overlap SymBitMatrix ovl(r,x.size()); // deg[i] is the degree of x[i] int* deg = r.alloc<int>(x.size()); // ovl_i[i] is an array of indices j such that x[j] overlaps with x[i] int** ovl_i = r.alloc<int*>(x.size()); // n_ovl_i[i] defines how many integers are stored for ovl_i[i] int* n_ovl_i = r.alloc<int>(x.size()); { #ifndef NDEBUG // Initialize all to null pointers so that things crash ;-) for (int i=x.size(); i--; ) ovl_i[i] = NULL; #endif // For each i there can be at most n_dis-1 entries in ovl_i[i] int* m = r.alloc<int>(n_dis*(n_dis-1)); for (int i=n_dis; i--; ) { deg[dis[i]] = 0; ovl_i[dis[i]] = m; m += n_dis-1; } } // Initialize overlap matrix by analyzing the view ranges { // Compute how many events are needed // One event for the end marker int n_re = 1; // Two events for each range for (int i=n_dis; i--; ) for (ViewRanges<IntView> rx(x[dis[i]]); rx(); ++rx) n_re += 2; // Allocate and initialize events RangeEvent* re = r.alloc<RangeEvent>(n_re); int j=0; for (int i=n_dis; i--; ) for (ViewRanges<IntView> rx(x[dis[i]]); rx(); ++rx) { // Event when a range starts re[j].ret=RET_FST; re[j].val=rx.min(); re[j].view=dis[i]; j++; // Event when a range ends re[j].ret=RET_LST; re[j].val=rx.max(); re[j].view=dis[i]; j++; } // Make this the last event re[j].ret=RET_END; re[j].val=Int::Limits::infinity; assert(j+1 == n_re); // Sort and process events Support::quicksort(re,n_re); // Current views with a range being active Support::BitSet<Region> cur(r,static_cast<unsigned int>(x.size())); // Process all events for (int i=0; true; i++) switch (re[i].ret) { case RET_FST: // Process all overlapping views for (Iter::Values::BitSet<Support::BitSet<Region> > j(cur); j(); ++j) { int di = re[i].view, dj = j.val(); if (!ovl.get(di,dj)) { ovl.set(di,dj); ovl_i[di][deg[di]++] = dj; ovl_i[dj][deg[dj]++] = di; } } cur.set(static_cast<unsigned int>(re[i].view)); break; case RET_LST: cur.clear(static_cast<unsigned int>(re[i].view)); break; case RET_END: goto done; default: GECODE_NEVER; } done: r.free<RangeEvent>(re,n_re); } // While deg changes, n_ovl_i remains unchanged and is needed, so copy it for (int i=n_dis; i--; ) { assert(deg[dis[i]] < n_dis); n_ovl_i[dis[i]] = deg[dis[i]]; } // Views in the independent set int* ind = r.alloc<int>(n_dis); int n_ind = 0; while (n_dis > 0) { int i_min = n_dis-1; int d_min = deg[dis[i_min]]; unsigned int s_min = x[dis[i_min]].size(); // Find view with smallest (degree,size) for (int i=n_dis-1; i--; ) if ((d_min > deg[dis[i]]) || ((d_min == deg[dis[i]]) && (s_min > x[dis[i]].size()))) { i_min = i; d_min = deg[dis[i]]; s_min = x[dis[i]].size(); } // i_min refers to view with smallest (degree,size) ind[n_ind++] = dis[i_min]; dis[i_min] = dis[--n_dis]; // Filter out non disjoint views for (int i=n_dis; i--; ) if (ovl.get(dis[i],ind[n_ind-1])) { // Update degree information for (int j=n_ovl_i[dis[i]]; j--; ) deg[ovl_i[dis[i]][j]]--; // Eliminate view dis[i] = dis[--n_dis]; } } // Enforce lower bound GECODE_ME_CHECK(y.gq(home,vs.size() + n_ind)); // Prune, if possible if (vs.size() + n_ind == y.max()) { // Only values from the indepent set a can be taken ViewRanges<IntView>* r_ind = r.alloc<ViewRanges<IntView> >(n_ind); for (int i=n_ind; i--; ) r_ind[i] = ViewRanges<IntView>(x[ind[i]]); Iter::Ranges::NaryUnion v_ind(r, r_ind, n_ind); ValSet::Ranges vsr(vs); v_ind |= vsr; for (int i=x.size(); i--; ) { v_ind.reset(); GECODE_ME_CHECK(x[i].inter_r(home,v_ind,false)); } } return ES_OK; }
ExecStatus ReProp<View,rm>::propagate(Space& home, const ModEventDelta& med) { // Add assigned views to value set if (View::me(med) == ME_INT_VAL) add(home,vs,x); if (b.one()) { if (rm == RM_PMI) return home.ES_SUBSUMED(*this); ValSet vsc(vs); vs.flush(); GECODE_REWRITE(*this,Prop<View>::post(home,vsc,x,y)); } if (b.zero()) { if (rm != RM_IMP) { ValSet::Ranges vsr(vs); GECODE_ME_CHECK(y.minus_r(home,vsr,false)); for (int i=x.size(); i--; ) GECODE_ES_CHECK(Rel::Nq<View>::post(home,x[i],y)); } return home.ES_SUBSUMED(*this); } // Eliminate views from x eliminate(home); switch (vs.compare(y)) { case Iter::Ranges::CS_SUBSET: if (rm != RM_IMP) GECODE_ME_CHECK(b.one(home)); return home.ES_SUBSUMED(*this); case Iter::Ranges::CS_DISJOINT: if (x.size() == 0) { if (rm != RM_PMI) GECODE_ME_CHECK(b.zero(home)); return home.ES_SUBSUMED(*this); } break; case Iter::Ranges::CS_NONE: break; default: GECODE_NEVER; } // Check whether y is in union of x and value set if (x.size() > 0) { Region r(home); ValSet::Ranges vsr(vs); ViewRanges<View> xsr(x[x.size()-1]); Iter::Ranges::NaryUnion u(r,vsr,xsr); for (int i=x.size()-1; i--; ) { ViewRanges<View> xir(x[i]); u |= xir; } ViewRanges<View> yr(y); if (Iter::Ranges::disjoint(u,yr)) { if (rm != RM_PMI) GECODE_ME_CHECK(b.zero(home)); return home.ES_SUBSUMED(*this); } } return ES_FIX; }