ExecStatus Dom<View,Offset>::propagate(Space& home, const ModEventDelta& med) { if (View::me(med) == Int::ME_INT_VAL) { GECODE_ES_CHECK((Int::Distinct::prop_val<View,true>(home,y))); ExecStatus escv = connected(home); if (escv != ES_FIX) return escv; if (y.size() < 2) return home.ES_SUBSUMED(*this); return home.ES_FIX_PARTIAL(*this,View::med(Int::ME_INT_DOM)); } if (dc.available()) { GECODE_ES_CHECK(dc.sync(home)); } else { GECODE_ES_CHECK(dc.init(home,y)); } bool assigned; GECODE_ES_CHECK(dc.propagate(home,assigned)); ExecStatus esc = connected(home); if (esc != ES_FIX) return esc; // Elminiate assigned views from y, as they have been assigned // and propagated by domain consistent propagation. This is required // as we need to know how many assigned views actually exist. if (assigned) for (int i=y.size(); i--; ) if (y[i].assigned()) y.move_lst(i); return path(home); }
ExecStatus Val<View,Offset,shared>::propagate(Space& home, const ModEventDelta&) { Region r(home); ProcessStack xa(r,n); ProcessStack ya(r,n); ValInfo<View>* x = xy; ValInfo<View>* y = xy+n; // Scan x and y for assigned but not yet propagated views for (int i = n; i--; ) { if (x[i].doval()) xa.push(i); if (y[i].doval()) ya.push(i); } do { // Propagate assigned views for x GECODE_ES_CHECK((prop_val<View,Offset,ValInfo<View> > (home,n,x,ox,y,oy,n_na,xa,ya))); // Propagate assigned views for y GECODE_ES_CHECK((prop_val<View,Offset,ValInfo<View> > (home,n,y,oy,x,ox,n_na,ya,xa))); assert(ya.empty()); } while (!xa.empty()); if (n_na == 0) return home.ES_SUBSUMED(*this); return shared ? ES_NOFIX : ES_FIX; }
ExecStatus ManProp<ManTask,Cap>::propagate(Space& home, const ModEventDelta& med) { // Only bounds changes? if (Int::IntView::me(med) != Int::ME_INT_DOM) GECODE_ES_CHECK(overload(home,c.max(),t)); GECODE_ES_CHECK(edgefinding(home,c.max(),t)); bool subsumed; ExecStatus es = basic(home,subsumed,c,t); GECODE_ES_CHECK(es); if (subsumed) return home.ES_SUBSUMED(*this); if (Cap::varderived() && c.assigned() && c.val()==1) { // Check that tasks do not overload resource for (int i=t.size(); i--; ) if (t[i].c() > 1) return ES_FAILED; // Rewrite to unary resource constraint TaskArray<typename TaskTraits<ManTask>::UnaryTask> ut(home,t.size()); for (int i=t.size(); i--;) ut[i]=t[i]; GECODE_REWRITE(*this, (Unary::ManProp<typename TaskTraits<ManTask>::UnaryTask> ::post(home(*this),ut))); } else { return es; } }
ExecStatus ManProp<ManTask,Cap,PL>::propagate(Space& home, const ModEventDelta& med) { // Only bounds changes? if (IntView::me(med) != ME_INT_DOM) GECODE_ES_CHECK(overload(home,c.max(),t)); if (PL::advanced) GECODE_ES_CHECK(edgefinding(home,c.max(),t)); if (PL::basic) GECODE_ES_CHECK(timetabling(home,*this,c,t)); if (Cap::varderived() && c.assigned() && (c.val() == 1)) { // Check that tasks do not overload resource for (int i=t.size(); i--; ) if (t[i].c() > 1) return ES_FAILED; // Rewrite to unary resource constraint TaskArray<typename TaskTraits<ManTask>::UnaryTask> ut(home,t.size()); for (int i=t.size(); i--;) ut[i]=t[i]; GECODE_REWRITE(*this, (Unary::ManProp<typename TaskTraits<ManTask>::UnaryTask,PL> ::post(home(*this),ut))); } if (!PL::basic && c.assigned()) GECODE_ES_CHECK(subsumed(home,*this,c.val(),t)); return ES_NOFIX; }
ExecStatus edgefinding(Space& home, int c, TaskArray<Task>& t) { TaskViewArray<typename TaskTraits<Task>::TaskViewFwd> f(t); GECODE_ES_CHECK(edgefinding(home,c,f)); TaskViewArray<typename TaskTraits<Task>::TaskViewBwd> b(t); GECODE_ES_CHECK(edgefinding(home,c,b)); return ES_OK; }
ExecStatus ManProp<ManTask>::propagate(Space& home, const ModEventDelta&) { GECODE_ES_CHECK(overload(home,t)); GECODE_ES_CHECK(detectable(home,t)); GECODE_ES_CHECK(notfirstnotlast(home,t)); GECODE_ES_CHECK(edgefinding(home,t)); GECODE_ES_CHECK(subsumed(home,*this,t)); return ES_NOFIX; }
ExecStatus Sequence<View,Val>::post(Home home, ViewArray<View>& x, Val s, int q, int l, int u) { GECODE_ES_CHECK(check(home,x,s,q,l,u)); Sequence<View,Val>* p = new (home) Sequence<View,Val>(home,x,s,q,l,u); GECODE_ES_CHECK(p->vvsamax.propagate(home,x,s,q,l,u)); GECODE_ES_CHECK(p->vvsamin.propagate(home,x,s,q,l,u)); return ES_OK; }
forceinline ExecStatus FixDim::nooverlap(Space& home, FixDim& d) { if (d.sec() > lsc()) { // Propagate that d must be after this GECODE_ES_CHECK(lec(home,d.lsc())); GECODE_ES_CHECK(d.ssc(home,sec())); } else { nooverlap(home, d.lsc(), d.sec()-1); } return ES_OK; }
ExecStatus Sequence<View,Val>::propagate(Space& home, const ModEventDelta&) { GECODE_ES_CHECK(vvsamax.propagate(home,x,s,q,l,u)); GECODE_ES_CHECK(vvsamin.propagate(home,x,s,q,l,u)); for (int i=x.size(); i--; ) if (undecided(x[i],s)) return ES_FIX; return home.ES_SUBSUMED(*this); }
ExecStatus UnionN<View0,View1>::propagate(Space& home, const ModEventDelta& med) { ModEvent me0 = View0::me(med); ModEvent me1 = View1::me(med); bool ubevent = Rel::testSetEventUB(me0, me1); bool lbevent = Rel::testSetEventLB(me0, me1); bool anybevent = Rel::testSetEventAnyB(me0, me1); bool cardevent = Rel::testSetEventCard(me0, me1); bool modified = false; bool oldModified = false; do { do { oldModified = modified; modified = false; if (modified || oldModified || ubevent) GECODE_ES_CHECK(unionNXiUB(home, modified, x, y,unionOfDets)); if (modified || oldModified || ubevent) GECODE_ES_CHECK(partitionNYUB(home, modified, x, y,unionOfDets)); if (modified || oldModified || anybevent) GECODE_ES_CHECK(partitionNXiLB(home, modified, x, y,unionOfDets)); if (modified || oldModified || lbevent) GECODE_ES_CHECK(partitionNYLB(home, modified, x, y,unionOfDets)); if (modified || oldModified || cardevent || ubevent) { GECODE_ES_CHECK(unionNCard(home, modified, x, y, unionOfDets)); } } while (modified); for(int i=0;i<x.size();i++){ //Do not reverse! Eats away the end of the array! while (i<x.size() && x[i].assigned()) { GlbRanges<View0> det(x[i]); unionOfDets.includeI(home,det); x.move_lst(i); modified = true; } } } while (modified); // When we run out of variables, make a final check and disolve: if (x.size()==0) { BndSetRanges all1(unionOfDets); GECODE_ME_CHECK( y.intersectI(home,all1) ); BndSetRanges all2(unionOfDets); GECODE_ME_CHECK( y.includeI(home,all2) ); unionOfDets.dispose(home); return home.ES_SUBSUMED(*this); } return shared ? ES_NOFIX : ES_FIX; }
/// Return a fresh yet equal Boolean variable forceinline ExecStatus link(Home home, BoolVar** x, int n, IntConLevel) { if (n > 2) { ViewArray<BoolView> y(home,n); y[0]=*x[0]; for (int i=1; i<n; i++) y[i]=*x[i]=BoolVar(home,0,1); GECODE_ES_CHECK(Bool::NaryEq<BoolView>::post(home,y)); } else if (n == 2) { *x[1] = BoolVar(home,0,1); GECODE_ES_CHECK((Bool::Eq<BoolView,BoolView>::post(home,*x[0],*x[1]))); } return ES_OK; }
ExecStatus EqInt<VX,VY>::propagate(Space& home, const ModEventDelta&) { // Eliminate decided views from subscribed views int n_x = x.size(); for (int i=n_s; i--; ) switch (holds(x[i],y)) { case RT_FALSE: x[i].cancel(home,*this,PC_INT_DOM); x[i]=x[--n_s]; x[n_s]=x[--n_x]; break; case RT_TRUE: x[i].cancel(home,*this,PC_INT_DOM); x[i]=x[--n_s]; x[n_s]=x[--n_x]; c--; break; case RT_MAYBE: break; default: GECODE_NEVER; } x.size(n_x); if ((c < 0) || (c > n_x)) return ES_FAILED; // Eliminate decided views from unsubscribed views for (int i=n_x; i-- > n_s; ) 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) || (c > n_x)) return ES_FAILED; if (c == 0) { // All views must be different GECODE_ES_CHECK(post_false(home,x,y)); return home.ES_SUBSUMED(*this); } if (c == n_x) { // All views must be equal GECODE_ES_CHECK(post_true(home,x,y)); return home.ES_SUBSUMED(*this); } int m = std::max(c,n_x-c)+1; assert(m <= n_x); // Now, there must be new subscriptions from x[n_s] up to x[m-1] while (n_s < m) x[n_s++].subscribe(home,*this,PC_INT_DOM,false); return ES_FIX; }
ExecStatus notfirstnotlast(Space& home, TaskArray<ManTask>& t) { TaskViewArray<typename TaskTraits<ManTask>::TaskViewFwd> f(t); GECODE_ES_CHECK(notlast(home,f)); TaskViewArray<typename TaskTraits<ManTask>::TaskViewBwd> b(t); return notlast(home,b); }
ExecStatus notfirstnotlast(Space& home, Propagator& p, TaskArray<OptTask>& t) { TaskViewArray<typename TaskTraits<OptTask>::TaskViewFwd> f(t); GECODE_ES_CHECK(notlast(home,p,f)); TaskViewArray<typename TaskTraits<OptTask>::TaskViewBwd> b(t); return notlast(home,p,b); }
ExecStatus overload(Space& home, Propagator& p, TaskArray<OptTask>& t) { TaskViewArray<typename TaskTraits<OptTask>::TaskViewFwd> f(t); sort<typename TaskTraits<OptTask>::TaskViewFwd,STO_LCT,true>(f); Region r(home); OmegaLambdaTree<typename TaskTraits<OptTask>::TaskViewFwd> ol(r,f,false); bool to_purge = false; for (int i=0; i<f.size(); i++) { if (f[i].optional()) { ol.linsert(i); } else if (f[i].mandatory()) { ol.oinsert(i); if (ol.ect() > f[i].lct()) return ES_FAILED; } while (!ol.lempty() && (ol.lect() > f[i].lct())) { int j = ol.responsible(); GECODE_ME_CHECK(f[j].excluded(home)); ol.lremove(j); to_purge = true; } } if (to_purge) GECODE_ES_CHECK((purge<OptTask,Int::PC_INT_BND>(home,p,t))); return ES_OK; }
ExecStatus Distinct<View0,View1>::post(Home home, View0 x, View1 y) { if (x.assigned()) { GlbRanges<View0> xr(x); IntSet xs(xr); ConstSetView cv(home, xs); GECODE_ES_CHECK((DistinctDoit<View1>::post(home,y,cv))); } if (y.assigned()) { GlbRanges<View1> yr(y); IntSet ys(yr); ConstSetView cv(home, ys); GECODE_ES_CHECK((DistinctDoit<View0>::post(home,x,cv))); } (void) new (home) Distinct<View0,View1>(home,x,y); return ES_OK; }
ExecStatus EqInt<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())); GECODE_ME_CHECK(y.lq(home, x.size() + 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); // Compute positions of disjoint views and eliminate subsumed views Region r(home); int* dis; int n_dis; disjoint(home,r,dis,n_dis); // The number might have changed due to elimination of subsumed views GECODE_ME_CHECK(y.lq(home, x.size() + vs.size())); if (x.size() == 0) { assert(y.val() == vs.size()); return home.ES_SUBSUMED(*this); } GECODE_ES_CHECK(prune_upper(home,g)); // No lower bound pruning possible if (n_dis == 0) return ES_NOFIX; // Only if the propagator is at fixpoint here, continue with // propagating the lower bound if (IntView::me(Propagator::modeventdelta()) != ME_INT_NONE) return ES_NOFIX; // Do lower bound-based pruning GECODE_ES_CHECK(prune_lower(home,dis,n_dis)); return ES_NOFIX; }
ExecStatus Tan<A,B>::propagate(Space& home, const ModEventDelta&) { GECODE_ME_CHECK(x1.eq(home,tan(x0.domain()))); FloatVal iv = fmod(x0.domain(),FloatVal::pi()); FloatNum offSet(Round.sub_down(x0.min(),iv.min())); GECODE_ES_CHECK(aTanProject(x1,iv)); GECODE_ME_CHECK(x0.eq(home,iv + offSet)); return (x0.assigned() && x1.assigned()) ? home.ES_SUBSUMED(*this) : ES_FIX; }
ExecStatus MultPlusDom<VA,VB,VC>::propagate(Space& home, const ModEventDelta& med) { if (VA::me(med) != ME_INT_DOM) { GECODE_ES_CHECK((prop_mult_plus_bnd<VA,VB,VC>(home,*this,x0,x1,x2))); return home.ES_FIX_PARTIAL(*this,VA::med(ME_INT_DOM)); } IntView y0(x0.varimp()), y1(x1.varimp()), y2(x2.varimp()); return prop_mult_dom<IntView>(home,*this,y0,y1,y2); }
ExecStatus Int<V0,V1,Idx,Val>::post(Home home, IntSharedArray& c, V0 x0, V1 x1) { if (x0.assigned()) { GECODE_ME_CHECK(x1.eq(home,c[x0.val()])); } else if (x1.assigned()) { GECODE_ES_CHECK(assigned_val(home,c,x0,x1)); } else { (void) new (home) Int<V0,V1,Idx,Val>(home,c,x0,x1); } return ES_OK; }
ExecStatus Single<View>::propagate(Space& home, const ModEventDelta&) { int n = x.size(); if (beta > gamma) { GECODE_ME_CHECK(x[alpha].eq(home, s)); return home.ES_SUBSUMED(*this); } if ((alpha < n) && !x[alpha].in(s)) { alpha++; while (alpha < beta) GECODE_ME_CHECK(x[alpha++].nq(home, t)); GECODE_ES_CHECK(updateAlpha(home)); beta = alpha; if (alpha < n) GECODE_ES_CHECK(updateBeta(home)); } else if ((beta < n) && !x[beta].in(s)) { GECODE_ES_CHECK(updateBeta(home)); } return (c.empty()) ? home.ES_SUBSUMED(*this) : ES_FIX; }
//Enforces sequentiality and ensures y contains union of Xi lower bounds. ExecStatus SeqU::propagate(Space& home, const ModEventDelta& med) { ModEvent me0 = SetView::me(med); bool ubevent = Rel::testSetEventUB(me0); bool anybevent = Rel::testSetEventAnyB(me0); bool cardevent = Rel::testSetEventCard(me0); bool modified = false; bool assigned=false; bool oldModified = false; do { oldModified = modified; modified = false; if (oldModified || modified || anybevent || cardevent) GECODE_ES_CHECK(propagateSeq(home,modified,assigned,x)); if (oldModified || modified || anybevent) GECODE_ES_CHECK(propagateSeqUnion(home,modified,x,y)); if (oldModified || modified || ubevent) GECODE_ES_CHECK(RelOp::unionNXiUB(home,modified,x,y,unionOfDets)); if (oldModified || modified || ubevent) GECODE_ES_CHECK(RelOp::partitionNYUB(home,modified,x,y,unionOfDets)); if (oldModified || modified || anybevent) GECODE_ES_CHECK(RelOp::partitionNXiLB(home,modified,x,y,unionOfDets)); if (oldModified || modified || cardevent || ubevent) GECODE_ES_CHECK(RelOp::partitionNCard(home,modified,x,y,unionOfDets)); } while (modified); for (int i=x.size(); i--;) if (!x[i].assigned()) return ES_FIX; return home.ES_SUBSUMED(*this); }
ExecStatus EqView<VX,VY,VZ,shr,dom>::propagate(Space& home, const ModEventDelta&) { count(home); GECODE_ME_CHECK(z.gq(home,atleast())); GECODE_ME_CHECK(z.lq(home,atmost())); if (z.assigned()) { if (z.val() == atleast()) { GECODE_ES_CHECK(post_false(home,x,y)); return home.ES_SUBSUMED(*this); } if (z.val() == atmost()) { GECODE_ES_CHECK(post_true(home,x,y)); return home.ES_SUBSUMED(*this); } if (!dom || (vtd(y) != VTD_VARVIEW)) { VY yc(y); GECODE_REWRITE(*this,(EqInt<VX,VY> ::post(home(*this),x,yc,z.val()+c))); } } if (dom && (vtd(y) == VTD_VARVIEW) && (z.min() > 0)) { /* * Only if the propagator is at fixpoint here, continue * when things are shared: the reason is that prune * requires that the views in x overlap with y! */ if (shr && (VX::me(Propagator::modeventdelta()) != ME_INT_NONE)) return ES_NOFIX; GECODE_ES_CHECK(prune(home,x,y)); return ES_NOFIX; } return shr ? ES_NOFIX : ES_FIX; }
ExecStatus Val<View>::propagate(Space& home, const ModEventDelta&) { GECODE_ES_CHECK((Int::Distinct::prop_val<View,true>(home,y))); ExecStatus esc = connected(home); if (esc != ES_FIX) return esc; /* * One cannot have a single unassigned view as the views constitute * a permutation. */ if (y.size() < 2) return home.ES_SUBSUMED(*this); return path(home); }
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); }
/// Return a fresh yet equal integer variable forceinline ExecStatus link(Home home, IntVar** x, int n, IntConLevel icl) { if (n > 2) { ViewArray<IntView> y(home,n); y[0]=*x[0]; for (int i=1; i<n; i++) y[i]=*x[i]=IntVar(home,x[0]->min(),x[0]->max()); if ((icl == ICL_DOM) || (icl == ICL_DEF)) { GECODE_ES_CHECK(Rel::NaryEqDom<IntView>::post(home,y)); } else { GECODE_ES_CHECK(Rel::NaryEqBnd<IntView>::post(home,y)); } } else if (n == 2) { *x[1]=IntVar(home,x[0]->min(),x[0]->max()); if ((icl == ICL_DOM) || (icl == ICL_DEF)) { GECODE_ES_CHECK((Rel::EqDom<IntView,IntView>::post (home,*x[0],*x[1]))); } else { GECODE_ES_CHECK((Rel::EqBnd<IntView,IntView>::post (home,*x[0],*x[1]))); } } return ES_OK; }
forceinline ExecStatus Match<View>::post(Home home, View x0, ViewArray<Gecode::Int::IntView>& xs) { unsigned int xs_size = static_cast<unsigned int>(xs.size()); GECODE_ME_CHECK(x0.cardMin(home,xs_size)); GECODE_ME_CHECK(x0.cardMax(home,xs_size)); if (xs_size == 1) { SingletonView sv(xs[0]); GECODE_ES_CHECK((Rel::Eq<View, SingletonView>::post(home,x0, sv))); } else { // Sharing in xs is handled correctly in the propagator: // if two views in xs are shared, this leads to failure. (void) new (home) Match(home,x0,xs); } return ES_OK; }
ExecStatus ManProp<Box>::propagate(Space& home, const ModEventDelta&) { Region r(home); // Number of disjoint boxes int* db = r.alloc<int>(n); for (int i=n; i--; ) db[i] = n-1; // Number of boxes to be eliminated int e = 0; for (int i=n; i--; ) for (int j=i; j--; ) if (b[i].nooverlap(b[j])) { assert(db[i] > 0); assert(db[j] > 0); if (--db[i] == 0) e++; if (--db[j] == 0) e++; continue; } else { GECODE_ES_CHECK(b[i].nooverlap(home,b[j])); } if (e == n) return home.ES_SUBSUMED(*this); { int i = n-1; while (e > 0) { // Eliminate boxes that do not overlap while (db[i] > 0) i--; b[i].cancel(home, *this); b[i] = b[--n]; e--; i--; } if (n < 2) return home.ES_SUBSUMED(*this); } return ES_NOFIX; }
ExecStatus LqView<VX,VY,VZ,shr>::propagate(Space& home, const ModEventDelta&) { count(home); GECODE_ME_CHECK(z.gq(home,atleast())); if (z.max() == atleast()) { GECODE_ES_CHECK(post_false(home,x,y)); return home.ES_SUBSUMED(*this); } if (x.size() == 0) return home.ES_SUBSUMED(*this); if (z.assigned()) { VY yc(y); GECODE_REWRITE(*this,(LqInt<VX,VY>::post(home(*this),x,yc,z.val()+c))); } return shr ? ES_NOFIX : ES_FIX; }
ExecStatus GqInt<VY>::propagate(Space& home, const ModEventDelta& med) { if (IntView::me(med) == ME_INT_VAL) add(home); // Eliminate subsumed views eliminate(home); GECODE_ME_CHECK(y.lq(home, x.size() + vs.size())); if (x.size() == 0) return home.ES_SUBSUMED(*this); if (vs.size() >= y.max()) return home.ES_SUBSUMED(*this); GECODE_ES_CHECK(prune_upper(home,g)); return ES_NOFIX; }