void distinct(Home home, const IntArgs& c, const IntVarArgs& x, IntPropLevel ipl) { using namespace Int; if (x.same(home)) throw ArgumentSame("Int::distinct"); if (c.size() != x.size()) throw ArgumentSizeMismatch("Int::distinct"); GECODE_POST; ViewArray<OffsetView> cx(home,x.size()); for (int i = c.size(); i--; ) { long long int cx_min = (static_cast<long long int>(c[i]) + static_cast<long long int>(x[i].min())); long long int cx_max = (static_cast<long long int>(c[i]) + static_cast<long long int>(x[i].max())); Limits::check(c[i],"Int::distinct"); Limits::check(cx_min,"Int::distinct"); Limits::check(cx_max,"Int::distinct"); cx[i] = OffsetView(x[i],c[i]); } switch (vbd(ipl)) { case IPL_BND: GECODE_ES_FAIL(Distinct::Bnd<OffsetView>::post(home,cx)); break; case IPL_DOM: GECODE_ES_FAIL(Distinct::Dom<OffsetView>::post(home,cx)); break; default: GECODE_ES_FAIL(Distinct::Val<OffsetView>::post(home,cx)); } }
void unary(Home home, const TaskTypeArgs& t, const IntVarArgs& flex, const IntArgs& fix, IntConLevel icl) { using namespace Gecode::Int; using namespace Gecode::Int::Unary; if ((flex.size() != fix.size()) || (flex.size() != t.size())) throw Int::ArgumentSizeMismatch("Int::unary"); for (int i=fix.size(); i--; ) { if (t[i] == TT_FIXP) Int::Limits::nonnegative(fix[i],"Int::unary"); else Int::Limits::check(fix[i],"Int::unary"); Int::Limits::check(static_cast<double>(flex[i].max()) + fix[i], "Int::unary"); } if (home.failed()) return; bool fixp = true; for (int i=t.size(); i--;) if (t[i] != TT_FIXP) { fixp = false; break; } if (fixp) { unary(home, flex, fix, icl); } else { TaskArray<ManFixPSETask> tasks(home,flex.size()); for (int i=flex.size(); i--;) tasks[i].init(t[i],flex[i],fix[i]); GECODE_ES_FAIL(ManProp<ManFixPSETask>::post(home,tasks)); } }
void nooverlap(Home home, const IntVarArgs& x, const IntArgs& w, const IntVarArgs& y, const IntArgs& h, IntConLevel) { using namespace Int; using namespace NoOverlap; if (x.same(home) || y.same(home)) throw ArgumentSame("Int::nooverlap"); if ((x.size() != w.size()) || (x.size() != y.size()) || (x.size() != h.size())) throw ArgumentSizeMismatch("Int::nooverlap"); for (int i=x.size(); i--; ) { Limits::nonnegative(w[i],"Int::nooverlap"); Limits::nonnegative(h[i],"Int::nooverlap"); Limits::check(static_cast<double>(x[i].max()) + w[i], "Int::nooverlap"); Limits::check(static_cast<double>(y[i].max()) + h[i], "Int::nooverlap"); } if (home.failed()) return; ManBox<FixDim,2>* b = static_cast<Space&>(home).alloc<ManBox<FixDim,2> >(x.size()); for (int i=x.size(); i--; ) { b[i][0] = FixDim(x[i],w[i]); b[i][1] = FixDim(y[i],h[i]); } GECODE_ES_FAIL((NoOverlap::ManProp<FixDim,2>::post(home,b,x.size()))); }
void unary(Home home, const IntVarArgs& s, const IntArgs& p, const BoolVarArgs& m, IntConLevel icl) { using namespace Gecode::Int; using namespace Gecode::Int::Unary; if (s.same(home)) throw Int::ArgumentSame("Int::unary"); if ((s.size() != p.size()) || (s.size() != m.size())) throw Int::ArgumentSizeMismatch("Int::unary"); for (int i=p.size(); i--; ) { Int::Limits::nonnegative(p[i],"Int::unary"); Int::Limits::check(static_cast<double>(s[i].max()) + p[i], "Int::unary"); } bool allMandatory = true; for (int i=m.size(); i--;) { if (!m[i].one()) { allMandatory = false; break; } } if (allMandatory) { unary(home,s,p,icl); } else { if (home.failed()) return; TaskArray<OptFixPTask> t(home,s.size()); for (int i=s.size(); i--; ) t[i].init(s[i],p[i],m[i]); GECODE_ES_FAIL(OptProp<OptFixPTask>::post(home,t)); } }
void binpacking(Home home, const IntVarArgs& l, const IntVarArgs& b, const IntArgs& s, IntConLevel) { using namespace Int; if (l.same(home,b)) throw ArgumentSame("Int::binpacking"); if (b.size() != s.size()) throw ArgumentSizeMismatch("Int::binpacking"); for (int i=s.size(); i--; ) Limits::nonnegative(s[i],"Int::binpacking"); if (home.failed()) return; ViewArray<OffsetView> lv(home,l.size()); for (int i=l.size(); i--; ) lv[i] = OffsetView(l[i],0); if (b.size() == 0) { for (int i=l.size(); i--; ) GECODE_ME_FAIL(lv[i].eq(home,0)); return; } ViewArray<BinPacking::Item> bs(home,b.size()); for (int i=bs.size(); i--; ) bs[i] = BinPacking::Item(b[i],s[i]); Support::quicksort(&bs[0], bs.size()); GECODE_ES_FAIL(Int::BinPacking::Pack::post(home,lv,bs)); }
void count(Home home, const IntVarArgs& x, const IntSet& c, const IntArgs& v, IntConLevel icl) { IntSetArgs cards(v.size()); for (int i = v.size(); i--; ) cards[i] = c; count(home, x, cards, v, icl); }
void element(Home home, SetOpType op, const IntArgs& x, SetVar y, SetVar z, const IntSet& universe) { IntSetArgs xs(x.size()); for (int i=x.size(); i--;) xs[i]=IntSet(x[i],x[i]); element(home,op,xs,y,z,universe); }
void cumulative(Home home, Cap c, const TaskTypeArgs& t, const IntVarArgs& s, const IntArgs& p, const IntArgs& u, const BoolVarArgs& m, IntConLevel icl) { using namespace Gecode::Int; using namespace Gecode::Int::Cumulative; if ((s.size() != p.size()) || (s.size() != u.size()) || (s.size() != t.size()) || (s.size() != m.size())) throw Int::ArgumentSizeMismatch("Int::cumulative"); long long int w = 0; for (int i=p.size(); i--; ) { Limits::nonnegative(p[i],"Int::cumulative"); Limits::nonnegative(u[i],"Int::cumulative"); Limits::check(static_cast<long long int>(s[i].max()) + p[i], "Int::cumulative"); mul_check(p[i],u[i]); w += s[i].width(); } mul_check(c.max(),w,s.size()); if (home.failed()) return; bool allMandatory = true; for (int i=m.size(); i--;) { if (!m[i].one()) { allMandatory = false; break; } } if (allMandatory) { cumulative(home,c,t,s,p,u,icl); } else { bool fixp = true; for (int i=t.size(); i--;) if (t[i] != TT_FIXP) { fixp = false; break; } int nonOptionals = 0; for (unsigned int i=u.size(); i--;) if (u[i]>0) nonOptionals++; if (fixp) { TaskArray<OptFixPTask> tasks(home,nonOptionals); int cur = 0; for (int i=0; i<s.size(); i++) if (u[i]>0) tasks[cur++].init(s[i],p[i],u[i],m[i]); GECODE_ES_FAIL((OptProp<OptFixPTask,Cap>::post(home,c,tasks))); } else { TaskArray<OptFixPSETask> tasks(home,nonOptionals); int cur = 0; for (int i=s.size(); i--;) if (u[i]>0) tasks[cur++].init(t[i],s[i],p[i],u[i],m[i]); GECODE_ES_FAIL((OptProp<OptFixPSETask,Cap>::post(home,c,tasks))); } } }
inline void TupleSet::add(const IntArgs& tuple) { TupleSetI* imp = static_cast<TupleSetI*>(object()); if (imp == NULL) { imp = new TupleSetI; object(imp); } assert(imp->arity == -1 || imp->arity == tuple.size()); imp->arity = tuple.size(); imp->add(tuple); }
void precede(Home home, const IntVarArgs& x, const IntArgs& c, IntConLevel) { using namespace Int; for (int i=c.size(); i--; ) Limits::check(c[i],"Int::precede"); if (home.failed()) return; for (int i=c.size()-1; i--; ) { ViewArray<IntView> y(home, x); GECODE_ES_FAIL(Precede::Single<IntView>::post(home, y, c[i], c[i+1])); } }
void precede(Home home, const SetVarArgs& x, const IntArgs& c) { using namespace Set; if (c.size() < 2) return; for (int i=c.size(); i--; ) Limits::check(c[i],"Set::precede"); GECODE_POST; for (int i=c.size()-1; i--; ) { ViewArray<SetView> y(home, x); GECODE_ES_FAIL(Precede::Single<SetView>::post(home, y, c[i], c[i+1])); } }
void linear(Home home, const IntArgs& a, const IntVarArgs& x, IntRelType r, IntVar y, IntConLevel icl) { if (a.size() != x.size()) throw ArgumentSizeMismatch("Int::linear"); if (home.failed()) return; Region re(home); Linear::Term<IntView>* t = re.alloc<Linear::Term<IntView> >(x.size()+1); for (int i = x.size(); i--; ) { t[i].a=a[i]; t[i].x=x[i]; } int min, max; estimate(t,x.size(),0,min,max); IntView v(y); switch (r) { case IRT_EQ: GECODE_ME_FAIL(v.gq(home,min)); GECODE_ME_FAIL(v.lq(home,max)); break; case IRT_GQ: GECODE_ME_FAIL(v.lq(home,max)); break; case IRT_LQ: GECODE_ME_FAIL(v.gq(home,min)); break; default: ; } if (home.failed()) return; t[x.size()].a=-1; t[x.size()].x=y; Linear::post(home,t,x.size()+1,r,0,icl); }
void cumulative(Home home, Cap c, const IntVarArgs& s, const IntVarArgs& p, const IntVarArgs& e, const IntArgs& u, IntConLevel icl) { using namespace Gecode::Int; using namespace Gecode::Int::Cumulative; if ((s.size() != p.size()) || (s.size() != e.size()) || (s.size() != u.size())) throw Int::ArgumentSizeMismatch("Int::cumulative"); long long int w = 0; for (int i=p.size(); i--; ) { rel(home, p[i], IRT_GQ, 0); } for (int i=p.size(); i--; ) { Limits::nonnegative(u[i],"Int::cumulative"); Limits::check(static_cast<long long int>(s[i].max()) + p[i].max(), "Int::cumulative"); mul_check(p[i].max(),u[i]); w += s[i].width(); } mul_check(c.max(),w,s.size()); if (home.failed()) return; bool fixP = true; for (int i=p.size(); i--;) { if (!p[i].assigned()) { fixP = false; break; } } if (fixP) { IntArgs pp(p.size()); for (int i=p.size(); i--;) pp[i] = p[i].val(); cumulative(home,c,s,pp,u,icl); } else { int nonOptionals = 0; for (unsigned int i=u.size(); i--;) if (u[i]>0) nonOptionals++; TaskArray<ManFlexTask> t(home,nonOptionals); int cur = 0; for (int i=0; i<s.size(); i++) if (u[i]>0) t[cur++].init(s[i],p[i],e[i],u[i]); GECODE_ES_FAIL((ManProp<ManFlexTask,Cap>::post(home,c,t))); } }
void cumulative(Home home, Cap c, const IntVarArgs& s, const IntArgs& p, const IntArgs& u, IntConLevel icl) { using namespace Gecode::Int; using namespace Gecode::Int::Cumulative; if ((s.size() != p.size()) || (s.size() != u.size())) throw Int::ArgumentSizeMismatch("Int::cumulative"); long long int w = 0; for (int i=p.size(); i--; ) { Limits::nonnegative(p[i],"Int::cumulative"); Limits::nonnegative(u[i],"Int::cumulative"); Limits::check(static_cast<long long int>(s[i].max()) + p[i], "Int::cumulative"); mul_check(p[i],u[i]); w += s[i].width(); } mul_check(c.max(),w,s.size()); if (home.failed()) return; int minU = INT_MAX; int minU2 = INT_MAX; int maxU = INT_MIN; for (int i=u.size(); i--;) { if (u[i] < minU) { minU2 = minU; minU = u[i]; } else if (u[i] < minU2) minU2 = u[i]; if (u[i] > maxU) maxU = u[i]; } bool disjunctive = (minU > c.max()/2) || (minU2 > c.max()/2 && minU+minU2>c.max()); if (disjunctive) { GECODE_ME_FAIL(c.gq(home,maxU)); unary(home,s,p,icl); } else { int nonOptionals = 0; for (unsigned int i=u.size(); i--;) if (u[i]>0) nonOptionals++; TaskArray<ManFixPTask> t(home,nonOptionals); int cur = 0; for (int i=0; i<s.size(); i++) if (u[i]>0) t[cur++].init(s[i],p[i],u[i]); GECODE_ES_FAIL((ManProp<ManFixPTask,Cap>::post(home,c,t))); } }
void cumulative(Home home, Cap c, const IntVarArgs& s, const IntVarArgs& p, const IntVarArgs& e, const IntArgs& u, const BoolVarArgs& m, IntConLevel icl) { using namespace Gecode::Int; using namespace Gecode::Int::Cumulative; if ((s.size() != p.size()) || (s.size() != u.size()) || (s.size() != e.size()) || (s.size() != m.size())) throw Int::ArgumentSizeMismatch("Int::cumulative"); for (int i=p.size(); i--; ) { rel(home, p[i], IRT_GQ, 0); } long long int w = 0; for (int i=p.size(); i--; ) { Limits::nonnegative(u[i],"Int::cumulative"); Limits::check(static_cast<long long int>(s[i].max()) + p[i].max(), "Int::cumulative"); mul_check(p[i].max(),u[i]); w += s[i].width(); } mul_check(c.max(),w,s.size()); if (home.failed()) return; bool allMandatory = true; for (int i=m.size(); i--;) { if (!m[i].one()) { allMandatory = false; break; } } if (allMandatory) { cumulative(home,c,s,p,e,u,icl); } else { int nonOptionals = 0; for (unsigned int i=u.size(); i--;) if (u[i]>0) nonOptionals++; TaskArray<OptFlexTask> t(home,nonOptionals); int cur = 0; for (int i=s.size(); i--; ) if (u[i]>0) t[cur++].init(s[i],p[i],e[i],u[i],m[i]); GECODE_ES_FAIL((OptProp<OptFlexTask,Cap>::post(home,c,t))); } }
void unary(Home home, const TaskTypeArgs& t, const IntVarArgs& flex, const IntArgs& fix, const BoolVarArgs& m, IntPropLevel ipl) { using namespace Gecode::Int; using namespace Gecode::Int::Unary; if ((flex.size() != fix.size()) || (flex.size() != t.size()) || (flex.size() != m.size())) throw Int::ArgumentSizeMismatch("Int::unary"); bool fixp = true; for (int i=fix.size(); i--; ) { if (t[i] == TT_FIXP) { Int::Limits::nonnegative(fix[i],"Int::unary"); } else { fixp = false; Int::Limits::check(fix[i],"Int::unary"); } Int::Limits::check(static_cast<long long int>(flex[i].max()) + fix[i], "Int::unary"); } GECODE_POST; bool allMandatory = true; for (int i=m.size(); i--;) { if (!m[i].one()) { allMandatory = false; break; } } if (allMandatory) { unary(home,t,flex,fix,ipl); } else { if (fixp) { TaskArray<OptFixPTask> tasks(home,flex.size()); for (int i=flex.size(); i--; ) tasks[i].init(flex[i],fix[i],m[i]); GECODE_ES_FAIL(optpost(home,tasks,ipl)); } else { TaskArray<OptFixPSETask> tasks(home,flex.size()); for (int i=flex.size(); i--;) tasks[i].init(t[i],flex[i],fix[i],m[i]); GECODE_ES_FAIL(optpost(home,tasks,ipl)); } } }
void unary(Home home, const IntVarArgs& s, const IntArgs& p, IntConLevel icl) { using namespace Gecode::Int; using namespace Gecode::Int::Unary; if (s.same(home)) throw Int::ArgumentSame("Int::unary"); if (s.size() != p.size()) throw Int::ArgumentSizeMismatch("Int::unary"); for (int i=p.size(); i--; ) { Int::Limits::nonnegative(p[i],"Int::unary"); Int::Limits::check(static_cast<double>(s[i].max()) + p[i], "Int::unary"); } if (home.failed()) return; bool allOne = true; for (int i=p.size(); i--;) { if (p[i] != 1) { allOne = false; break; } } if (allOne) { ViewArray<IntView> xv(home,s); switch (icl) { case ICL_BND: GECODE_ES_FAIL(Distinct::Bnd<IntView>::post(home,xv)); break; case ICL_DOM: GECODE_ES_FAIL(Distinct::Dom<IntView>::post(home,xv)); break; default: GECODE_ES_FAIL(Distinct::Val<IntView>::post(home,xv)); } } else { TaskArray<ManFixPTask> t(home,s.size()); for (int i=s.size(); i--; ) t[i].init(s[i],p[i]); GECODE_ES_FAIL(ManProp<ManFixPTask>::post(home,t)); } }
/* * Post the constraint that the rectangles defined by the coordinates * x and y and width w and height h do not overlap. * * This is the function that you will call from your model. The best * is to paste the entire file into your model. */ void nooverlap(Home home, const IntVarArgs& x, const IntArgs& w, const IntVarArgs& y, const IntArgs& h) { // Check whether the arguments make sense if ((x.size() != y.size()) || (x.size() != w.size()) || (y.size() != h.size())) throw ArgumentSizeMismatch("nooverlap"); // Never post a propagator in a failed space if (home.failed()) return; // Set up array of views for the coordinates ViewArray<IntView> vx(home,x); ViewArray<IntView> vy(home,y); // Set up arrays (allocated in home) for width and height and initialize int* wc = static_cast<Space&>(home).alloc<int>(x.size()); int* hc = static_cast<Space&>(home).alloc<int>(y.size()); for (int i=x.size(); i--; ) { wc[i]=w[i]; hc[i]=h[i]; } // If posting failed, fail space if (NoOverlap::post(home,vx,wc,vy,hc) != ES_OK) home.fail(); }
void linear(Home home, const IntArgs& a, const IntVarArgs& x, IntRelType r, int c, BoolVar b, IntConLevel) { if (a.size() != x.size()) throw ArgumentSizeMismatch("Int::linear"); if (home.failed()) return; Region re(home); Linear::Term<IntView>* t = re.alloc<Linear::Term<IntView> >(x.size()); for (int i = x.size(); i--; ) { t[i].a=a[i]; t[i].x=x[i]; } Linear::post(home,t,x.size(),r,c,b); }
LinExpr::LinExpr(const IntArgs& a, const BoolVarArgs& x) : n(new Node) { if (a.size() != x.size()) throw Int::ArgumentSizeMismatch("MiniModel::LinExpr"); n->n_int = 0; n->n_bool = x.size(); n->t = NT_SUM_BOOL; n->l = n->r = NULL; if (x.size() > 0) { n->sum.tb = heap.alloc<Int::Linear::Term<Int::BoolView> >(x.size()); for (int i=x.size(); i--; ) { n->sum.tb[i].x = x[i]; n->sum.tb[i].a = a[i]; } } }
void circuit(Home home, const IntArgs& c, const IntVarArgs& x, const IntVarArgs& y, IntVar z, IntConLevel icl) { int n = x.size(); if ((y.size() != n) || (c.size() != n*n)) throw Int::ArgumentSizeMismatch("Graph::circuit"); circuit(home, x, icl); if (home.failed()) return; IntArgs cx(n); for (int i=n; i--; ) { for (int j=0; j<n; j++) cx[j] = c[i*n+j]; element(home, cx, x[i], y[i]); } linear(home, y, IRT_EQ, z); }
void linear(Home home, const IntArgs& a, const BoolVarArgs& x, IntRelType irt, IntVar y, Reify r, IntPropLevel ipl) { if (a.size() != x.size()) throw ArgumentSizeMismatch("Int::linear"); GECODE_POST; int n=x.size(); Region re(home); Linear::Term<BoolView>* t = re.alloc<Linear::Term<BoolView> >(n); for (int i=n; i--; ) { t[i].a=a[i]; t[i].x=x[i]; } Linear::post(home,t,n,irt,y,r,ipl); }
REG::REG(const IntArgs& x) { int n = x.size(); if (n < 1) throw MiniModel::TooFewArguments("REG"); Exp** a = heap.alloc<Exp*>(n); // Initialize with symbols for (int i=n; i--; ) { a[i] = new Exp(); a[i]->use_cnt = 1; a[i]->_n_pos = 1; a[i]->type = REG::Exp::ET_SYMBOL; a[i]->data.symbol = x[i]; } // Build a balanced tree of alternative nodes for (int m=n; m>1; ) { if (m & 1) { m -= 1; Exp* e1 = a[m]; Exp* e2 = a[0]; a[0] = new Exp; a[0]->use_cnt = 1; a[0]->_n_pos = e1->n_pos() + e2->n_pos(); a[0]->type = REG::Exp::ET_OR; a[0]->data.kids[0] = e1; a[0]->data.kids[1] = e2; } else { m >>= 1; for (int i=0; i<m; i++) { Exp* e1 = a[2*i]; Exp* e2 = a[2*i+1]; a[i] = new Exp; a[i]->use_cnt = 1; a[i]->_n_pos = e1->n_pos() + e2->n_pos(); a[i]->type = REG::Exp::ET_OR; a[i]->data.kids[0] = e1; a[i]->data.kids[1] = e2; } } } e = a[0]; heap.free<Exp*>(a,n); }
void linear(Home home, const IntArgs& a, const BoolVarArgs& x, IntRelType irt, IntVar y, IntPropLevel ipl) { if (a.size() != x.size()) throw ArgumentSizeMismatch("Int::linear"); GECODE_POST; int n=x.size(); Region re(home); Linear::Term<BoolView>* t = re.alloc<Linear::Term<BoolView> >(n); for (int i=n; i--; ) { t[i].a=a[i]; t[i].x=x[i]; } int min, max; estimate(t,n,0,min,max); IntView v(y); switch (irt) { case IRT_EQ: GECODE_ME_FAIL(v.gq(home,min)); GECODE_ME_FAIL(v.lq(home,max)); break; case IRT_GQ: GECODE_ME_FAIL(v.lq(home,max)); break; case IRT_LQ: GECODE_ME_FAIL(v.gq(home,min)); break; default: ; } if (home.failed()) return; Linear::post(home,t,n,irt,y,0,ipl); }
static void init(IntSet& s, const IntArgs& i) { if (i.size() > 0) s.init(&i[0],i.size()); }
IntSet binpacking(Home home, int d, const IntVarArgs& l, const IntVarArgs& b, const IntArgs& s, const IntArgs& c, IntConLevel) { using namespace Int; if (l.same(home,b)) throw ArgumentSame("Int::binpacking"); // The number of items int n = b.size(); // The number of bins int m = l.size() / d; // Check input sizes if ((n*d != s.size()) || (m*d != l.size()) || (d != c.size())) throw ArgumentSizeMismatch("Int::binpacking"); for (int i=s.size(); i--; ) Limits::nonnegative(s[i],"Int::binpacking"); for (int i=c.size(); i--; ) Limits::nonnegative(c[i],"Int::binpacking"); if (home.failed()) return IntSet::empty; // Capacity constraint for each dimension for (int k=d; k--; ) for (int j=m; j--; ) { IntView li(l[j*d+k]); if (me_failed(li.lq(home,c[k]))) { home.fail(); return IntSet::empty; } } // Post a binpacking constraint for each dimension for (int k=d; k--; ) { ViewArray<OffsetView> lv(home,m); for (int j=m; j--; ) lv[j] = OffsetView(l[j*d+k],0); ViewArray<BinPacking::Item> bv(home,n); for (int i=n; i--; ) bv[i] = BinPacking::Item(b[i],s[i*d+k]); if (Int::BinPacking::Pack::post(home,lv,bv) == ES_FAILED) { home.fail(); return IntSet::empty; } } // Clique Finding and distinct posting { // First construct the conflict graph Region r(home); BinPacking::ConflictGraph cg(home,r,b,m); for (int i=0; i<n-1; i++) { for (int j=i+1; j<n; j++) { unsigned int nl = 0; unsigned int ds = 0; IntVarValues ii(b[i]), jj(b[j]); while (ii() && jj()) { if (ii.val() < jj.val()) { ++ii; } else if (ii.val() > jj.val()) { ++jj; } else { ds++; for (int k=d; k--; ) if (s[i*d+k] + s[j*d+k] > c[k]) { nl++; break; } ++ii; ++jj; } } if (nl >= ds) cg.edge(i,j); } } if (cg.post() == ES_FAILED) home.fail(); // The clique can be computed even if home is failed return cg.maxclique(); } }