コード例 #1
0
void Constraint::assignCluster() {
	TreeDecomposition* td = wcsp->getTreeDec();
	if(!td) return;
	Cluster* lowest = td->getRoot();
	for(int i=0;i<arity();i++) if (getVar(i)->unassigned()) {
		Variable* x = getVar(i);
		Cluster* c = td->getCluster( x->getCluster() );
		if(lowest->isDescendant(c)) lowest = c;
	}
	cluster = lowest->getId();
}
コード例 #2
0
void BinaryConstraint::extend(EnumeratedVariable* x, Value value, Cost cost, vector<StoreCost>& deltaCostsX)
{
    assert(ToulBar2::verbose < 4 || ((cout << "extend(C" << getVar(0)->getName() << "," << getVar(1)->getName() << ", (" << x->getName() << "," << value << "), " << cost << ")" << endl), true));

    TreeDecomposition* td = wcsp->getTreeDec();
    if (td)
        td->addDelta(cluster, x, value, -cost);

    deltaCostsX[x->toIndex(value)] -= cost; // Warning! Possible overflow???
    x->extend(value, cost);
}
コード例 #3
0
void VACBinaryConstraint::VACextend(VACVariable* x, Value v, Cost c) {
  assert(ToulBar2::verbose < 4 || ((cout << "extend(C" << getVar(0)->getName() << "," << getVar(1)->getName() << ", (" << x->getName() << "," << v << "), " << c << ")" << endl), true));

  TreeDecomposition* td = wcsp->getTreeDec();
  if(td) td->addDelta(cluster,x,v,-c);

  int index = x->toIndex(v);
  // TO BE REPLACED BY A LOOP ON THE DOMAIN IN ORDER TO AVOID SUBTRACTING TOP???
  if(!getIndex(x)) deltaCostsX[index] -= c;
  else             deltaCostsY[index] -= c;
  x->VACextend(v, c);
}
コード例 #4
0
ファイル: tb2vac.cpp プロジェクト: eomahony/Numberjack
bool VACExtension::checkPass1() const
{
    VACBinaryConstraint *cij;
    VACVariable *xi, *xj;
    bool supportFound;
    TreeDecomposition *td = wcsp->getTreeDec();

    for (unsigned int i = 0; i < wcsp->numberOfVariables(); i++) {
        xi = (VACVariable *) wcsp->getVar(i);
        if (td
                && !td->isActiveAndInCurrentClusterSubTree(xi->
                        getCluster()))
            continue;
        for (ConstraintList::iterator iter = xi->getConstrs()->begin();
                iter != xj->getConstrs()->end(); ++iter) {
            Constraint *c = (*iter).constr;
            if (c->arity() == 2 && !c->isSep()) {
                cij = (VACBinaryConstraint *) c;
                xj = (VACVariable *) cij->getVarDiffFrom(xi);
                for (EnumeratedVariable::iterator iti =
                        xi->begin(); iti != xi->end(); ++iti) {
                    Value v = *iti;
                    supportFound = false;
                    for (EnumeratedVariable::iterator itj =
                            xj->begin(); itj != xj->end();
                            ++itj) {
                        Value w = *itj;
                        if ((xi->getVACCost(v) ==
                                MIN_COST)
                                && (xj->getVACCost(w) ==
                                        MIN_COST)
                                        && (cij->
                                                getVACCost(xi, xj, v,
                                                        w) ==
                                                                MIN_COST)) {
                            supportFound = true;
                            break;
                        }
                    }
                    if (!supportFound) {
                        return false;
                    }
                }
            }
        }
    }
    return true;
}
コード例 #5
0
void VACBinaryConstraint::VACproject(VACVariable* x, Value v, Cost c)
{
    assert(ToulBar2::verbose < 4 || ((cout << "project(C" << getVar(0)->getName() << "," << getVar(1)->getName() << ", (" << x->getName() << "," << v << "), " << c << ")" << endl), true));
    wcsp->revise(this);
    TreeDecomposition* td = wcsp->getTreeDec();
    if (td)
        td->addDelta(cluster, x, v, c);

    int index = x->toIndex(v);
    // TO BE REPLACED BY A LOOP ON THE DOMAIN IN ORDER TO AVOID SUBTRACTING TOP???
    if (!getIndex(x))
        deltaCostsX[index] += c;
    else
        deltaCostsY[index] += c;
    assert(getCost((EnumeratedVariable*)x, (EnumeratedVariable*)getVarDiffFrom(x), v, getVarDiffFrom(x)->getInf()) >= MIN_COST);
    assert(getCost((EnumeratedVariable*)x, (EnumeratedVariable*)getVarDiffFrom(x), v, getVarDiffFrom(x)->getSup()) >= MIN_COST);
    x->VACproject(v, c);
}
コード例 #6
0
/*
 * Propagation methods
 *
 */
bool BinaryConstraint::project(EnumeratedVariable* x, Value value, Cost cost, vector<StoreCost>& deltaCostsX)
{
    assert(ToulBar2::verbose < 4 || ((cout << "project(C" << getVar(0)->getName() << "," << getVar(1)->getName() << ", (" << x->getName() << "," << value << "), " << cost << ")" << endl), true));

    // hard binary constraint costs are not changed
    if (!CUT(cost + wcsp->getLb(), wcsp->getUb())) {
        TreeDecomposition* td = wcsp->getTreeDec();
        if (td)
            td->addDelta(cluster, x, value, cost);
        deltaCostsX[x->toIndex(value)] += cost; // Warning! Possible overflow???
        assert(getCost(x, (EnumeratedVariable*)getVarDiffFrom(x), value, getVarDiffFrom(x)->getInf()) >= MIN_COST);
        assert(getCost(x, (EnumeratedVariable*)getVarDiffFrom(x), value, getVarDiffFrom(x)->getSup()) >= MIN_COST);
    }

    Cost oldcost = x->getCost(value);
    x->project(value, cost);
#ifdef DEECOMPLETE
    getVarDiffFrom(x)->queueDEE();
#endif
    return (x->getSupport() == value || SUPPORTTEST(oldcost, cost));
}
コード例 #7
0
ファイル: compute_tw_bound.cpp プロジェクト: cernoch/sequoia
int main(int argc, char **argv) {
    if(argc < 2) {
        std::cerr << "Error:  No input file given" << std::endl;
        usage(argv[0]);
    }

    LabeledGraph g;
    try {
	GraphFactory<LabeledGraph>::load_graph(g, argv[1]);
    } catch (const std::exception &e) {
	std::cerr << "Error loading graph: " << e.what() << std::endl;
        exit(EXIT_FAILURE);
    }

    MinDegreeHeuristic<LabeledGraph> a(g);
    a.compute();
    TreeDecomposition *tdc = a.get();
    if (tdc == NULL) {
        std::cerr << "Error converting file " << argv[1] << std::endl;
        exit(EXIT_FAILURE);
    }
    std::cout << tdc->width() - 1 << std::endl;
    return EXIT_SUCCESS;
}
コード例 #8
0
BigInteger Solver::sharpBTD(Cluster* cluster)
{

    TreeDecomposition* td = wcsp->getTreeDec();
    BigInteger NbSol = 0, nb = 0;
    TCtrs totalList;
    if (ToulBar2::verbose >= 1)
        cout << "[" << Store::getDepth() << "] recursive solve     cluster: " << cluster->getId() << " **************************************************************" << endl;

    int varIndex = -1;
    if (ToulBar2::Static_variable_ordering)
        varIndex = getNextUnassignedVar(cluster);
    else if (ToulBar2::weightedDegree && ToulBar2::lastConflict)
        varIndex = ((ToulBar2::restart > 0) ? getVarMinDomainDivMaxWeightedDegreeLastConflictRandomized(cluster) : getVarMinDomainDivMaxWeightedDegreeLastConflict(cluster));
    else if (ToulBar2::lastConflict)
        varIndex = ((ToulBar2::restart > 0) ? getVarMinDomainDivMaxDegreeLastConflictRandomized(cluster) : getVarMinDomainDivMaxDegreeLastConflict(cluster));
    else if (ToulBar2::weightedDegree)
        varIndex = ((ToulBar2::restart > 0) ? getVarMinDomainDivMaxWeightedDegreeRandomized(cluster) : getVarMinDomainDivMaxWeightedDegree(cluster));
    else
        varIndex = ((ToulBar2::restart > 0) ? getVarMinDomainDivMaxDegreeRandomized(cluster) : getVarMinDomainDivMaxDegree(cluster));

    if (varIndex < 0) {
        // Current cluster is completely assigned
        Cost lb = wcsp->getLb();
        if (ToulBar2::verbose >= 1)
            cout << "[" << Store::getDepth() << "] C" << cluster->getId() << " lb= " << lb << endl;
        NbSol = 1 * cluster->getCount();

        if (ToulBar2::approximateCountingBTD && cluster->getParent() == NULL)
            totalList = cluster->getCtrsTree();

        for (TClusters::iterator iter = cluster->beginSortedEdges(); NbSol > 0 && iter != cluster->endSortedEdges(); ++iter) {
            // Solves each cluster son
            nb = 0;
            Cluster* c = *iter;
            if ((nb = c->sgoodGet()) != -1) {
                nbSGoodsUse++;
            } else {
                nb = 0;
                td->setCurrentCluster(c);
                try {
                    Store::store();
                    if (ToulBar2::approximateCountingBTD) {
                        if (c->getParent() != NULL && c->getParent()->getParent() == NULL && c->getNbVars() > 1) {
                            // for this son of root, we disconnect the constraints which isn't in intersection
                            TCtrs usefulCtrsList = c->getCtrsTree();
                            c->deconnectDiff(totalList, usefulCtrsList);
                        }
                    }
                    wcsp->propagate();
                    nb = sharpBTD(c);
                    c->sgoodRec(0, nb);
                    nbSGoods++;
                } catch (Contradiction) {
                    wcsp->whenContradiction();
                    c->sgoodRec(0, 0); // no solution
                    nbSGoods++;
                }
                Store::restore();
            }
            if (cluster->getParent() == NULL && ToulBar2::approximateCountingBTD) {
                // computation of upper bound of solutions number for each part
                if (ubSol.find(c->getPart()) == ubSol.end()) {
                    ubSol[c->getPart()] = 1;
                }
                ubSol[c->getPart()] *= nb;
            }
            NbSol *= nb;
        }
        return NbSol;
    } else {
        // Enumerates cluster proper variables
        if (wcsp->enumerated(varIndex)) {
            assert(wcsp->canbe(varIndex, wcsp->getSupport(varIndex)));
            // Reuse last solution found if available
            Value bestval = wcsp->getBestValue(varIndex);

            NbSol = binaryChoicePointSBTD(cluster, varIndex, (wcsp->canbe(varIndex, bestval)) ? bestval : wcsp->getSupport(varIndex));
        } else {
            NbSol = binaryChoicePointSBTD(cluster, varIndex, wcsp->getInf(varIndex));
        }
        if (ToulBar2::verbose >= 1)
            cout << "[" << Store::getDepth() << "] C" << cluster->getId() << " return " << NbSol << endl;
        return NbSol;
    }
}
コード例 #9
0
pair<Cost, Cost> Solver::russianDollSearch(Cluster* c, Cost cub)
{
    TreeDecomposition* td = wcsp->getTreeDec();
    pair<Cost, Cost> res = make_pair(MIN_COST, cub);

    TClusters::iterator it = c->beginSortedEdges();
    while (it != c->endSortedEdges()) {
        russianDollSearch(*it, cub);
        ++it;
    }

    try {
        Store::store();

        Cost nogoodlb = MIN_COST;
        Cost nogoodub = MAX_COST;
        if (c != td->getRoot()) {
            c->deconnectSep();
            c->nogoodGet(nogoodlb, nogoodub, &c->open); // update c->open and c->ub
            //	      if (nogoodlb == bestub) {
            //	          assert(bestub <= cub);
            //	          Store::restore();
            //	          return make_pair(bestub,bestub);
            //	      }
            assert(c->getLbRec() == MIN_COST);
            c->setLb(MIN_COST);
            wcsp->setLb(MIN_COST);
            td->setCurrentCluster(td->getRoot());
            Cost lbroot = td->getLbRecRDS();
            td->setCurrentCluster(c);
            Cost lbc = td->getLbRecRDS();
            cub = cub - lbroot + lbc;
            cub = MIN(cub, nogoodub);
        }
        wcsp->setUb(cub);
        td->setCurrentCluster(c);
        td->setRootRDS(c);
        lastConflictVar = -1;

        if (ToulBar2::verbose >= 0)
            cout << "--- Solving cluster subtree " << c->getId() << " ..." << endl;

        //	  if(c == td->getRoot()) wcsp->propagate(); // needed if there are connected components
        enforceUb();
        wcsp->propagate();
        Cost bestlb = td->getLbRecRDS();
        bestlb = MAX(bestlb, nogoodlb);
        if (bestlb >= cub)
            THROWCONTRADICTION;
        res = hybridSolve(c, bestlb, cub);
        assert(res.first >= bestlb);
        c->setLbRDS(res.first);
        //	  if (c->sepSize() == 0)  {
        c->nogoodRec(res.first, ((res.second < cub) ? res.second : MAX_COST), &c->open);
        //	  }

        if (ToulBar2::debug || ToulBar2::verbose >= 1)
            c->printStatsRec();
        if (ToulBar2::verbose >= 0)
            cout << "---  done  cost = [" << res.first << "," << res.second << "] (" << nbBacktracks << " backtracks, " << nbNodes << " nodes, depth " << Store::getDepth() << ")" << endl
                 << endl;

    } catch (Contradiction) {
        wcsp->whenContradiction();
        res.first = res.second;
        c->setLbRDS(cub);
        //	  if (c->sepSize() == 0) {
        c->nogoodRec(cub, MAX_COST, &c->open);
        //	  }
    }
    Store::restore();
    if (c == td->getRoot()) {
        c->resetLbRec();
    } else {
        if (c->open)
            *(c->open) = OpenList(); // clear current open list
        c->resetUbRec(c);
    }
    return res;
}
コード例 #10
0
pair<Cost, Cost> Solver::recursiveSolve(Cluster* cluster, Cost lbgood, Cost cub)
{
    if (ToulBar2::verbose >= 1)
        cout << "[" << Store::getDepth() << "] recursive solve     cluster: " << cluster->getId() << "     clb: " << lbgood << "     cub: " << cub << "     clb0: " << cluster->getLb() << "     wcsp->lb: " << wcsp->getLb() << "     wcsp->ub: " << wcsp->getUb() << endl;
    assert(lbgood <= cub);
    TreeDecomposition* td = wcsp->getTreeDec();
    int varIndex = -1;
    if (ToulBar2::Static_variable_ordering)
        varIndex = getNextUnassignedVar(cluster);
    else if (ToulBar2::weightedDegree && ToulBar2::lastConflict)
        varIndex = ((ToulBar2::restart > 0) ? getVarMinDomainDivMaxWeightedDegreeLastConflictRandomized(cluster) : getVarMinDomainDivMaxWeightedDegreeLastConflict(cluster));
    else if (ToulBar2::lastConflict)
        varIndex = ((ToulBar2::restart > 0) ? getVarMinDomainDivMaxDegreeLastConflictRandomized(cluster) : getVarMinDomainDivMaxDegreeLastConflict(cluster));
    else if (ToulBar2::weightedDegree)
        varIndex = ((ToulBar2::restart > 0) ? getVarMinDomainDivMaxWeightedDegreeRandomized(cluster) : getVarMinDomainDivMaxWeightedDegree(cluster));
    else
        varIndex = ((ToulBar2::restart > 0) ? getVarMinDomainDivMaxDegreeRandomized(cluster) : getVarMinDomainDivMaxDegree(cluster));

    if (varIndex < 0) {
        // Current cluster is completely assigned
        Cost clb = wcsp->getLb();
        assert(clb <= cub);
        Cost csol = clb;

        for (TClusters::iterator iter = cluster->beginSortedEdges(); clb < cub && iter != cluster->endSortedEdges();) {
            // Solves each cluster son with local lower and upper bounds
            Cluster* c = *iter;
            ++iter;
            Cost lbSon = MIN_COST;
            Cost ubSon = MAX_COST;
            bool good = false;
            if (!c->isActive()) {
                c->reactivate();
                c->nogoodGet(lbSon, ubSon, &c->open);
                good = true;
            } else {
                lbSon = c->getLbRec();
                ubSon = c->getUb();
#ifndef NDEBUG
                Cost dummylb = -MAX_COST;
                Cost tmpub = -MAX_COST;
                c->nogoodGet(dummylb, tmpub, &c->open);
                assert(tmpub == ubSon);
#endif
            }
            if (ToulBar2::verbose >= 2)
                cout << "lbson: " << lbSon << " ubson: " << ubSon << " lbgood:" << lbgood << " clb: " << clb << " csol: " << csol << " cub: " << cub << " cluster->lb: " << c->getLbRec() << endl;
            if (lbSon < ubSon) { // we do not have an optimality proof
                if (clb <= lbgood || (csol < MAX_COST && ubSon >= cub - csol + lbSon)) { // we do not know a good enough son's solution or the currently reconstructed father's solution is not working or the currently reconstructed father's lower bound is not increasing
                    bool csolution = (csol < MAX_COST && ubSon < cub - csol + lbSon);
                    assert(!csolution || ubSon < cub - clb + lbSon);
                    ubSon = MIN(ubSon, cub - clb + lbSon);
                    td->setCurrentCluster(c);
                    wcsp->setUb(ubSon);
                    wcsp->setLb((good) ? c->getLbRec() : lbSon);
                    try {
                        Store::store();
                        wcsp->enforceUb();
                        wcsp->propagate();
                        Cost bestlb = MAX(wcsp->getLb(), lbSon);
                        if (csol < MAX_COST && iter == cluster->endSortedEdges())
                            bestlb = MAX(bestlb, lbgood - csol + lbSon); // simple trick to provide a better initial lower bound for the last son
                        if (ToulBar2::btdMode >= 2) {
                            Cost rds = td->getLbRecRDS();
                            bestlb = MAX(bestlb, rds);
                            if (CUT(bestlb, ubSon))
                                THROWCONTRADICTION;
                        }
                        pair<Cost, Cost> res = hybridSolve(c, bestlb, ubSon);
                        assert(res.first >= bestlb && res.second <= ubSon);
                        c->nogoodRec(res.first, ((res.second < ubSon) ? res.second : MAX_COST), &c->open);
                        clb += res.first - lbSon;
                        if (csol < MAX_COST) {
                            if (res.second < ubSon || csolution)
                                csol += res.second - lbSon;
                            else
                                csol = MAX_COST;
                        }
                    } catch (Contradiction) {
                        wcsp->whenContradiction();
                        c->nogoodRec(ubSon, MAX_COST, &c->open);
                        clb += ubSon - lbSon;
                        if (csolution)
                            csol += ubSon - lbSon;
                        else
                            csol = MAX_COST;
                    }
                    Store::restore();
                } else {
                    if (csol < MAX_COST) {
                        assert(ubSon < MAX_COST);
                        csol += ubSon - lbSon;
                    }
                }
            }
        }
        assert(csol >= clb);
        if (csol < cub) {
            // A new solution has been found for the current cluster
            cub = csol;
            cluster->solutionRec(csol);
            if (cluster == td->getRoot() || cluster == td->getRootRDS()) {
                if (ToulBar2::verbose >= 0 || ToulBar2::showSolutions) {
                    if (!ToulBar2::bayesian)
                        cout << "New solution: " << std::setprecision(ToulBar2::decimalPoint) << wcsp->Cost2ADCost(csol) << std::setprecision(DECIMAL_POINT) << " (" << nbBacktracks << " backtracks, " << nbNodes << " nodes, depth " << Store::getDepth() << ")" << endl;
                    else
                        cout << "New solution: " << csol << " energy: " << -(wcsp->Cost2LogProb(csol) + ToulBar2::markov_log) << " prob: " << std::scientific << wcsp->Cost2Prob(csol) * Exp(ToulBar2::markov_log) << std::fixed << " (" << nbBacktracks << " backtracks, " << nbNodes << " nodes, depth " << Store::getDepth() << ")" << endl;
                }
                if (cluster == td->getRoot())
                    td->newSolution(csol);
                else {
                    assert(cluster == td->getRootRDS());
                    // Remember current solution for value ordering heuristic
                    wcsp->restoreSolution(cluster);
                    TAssign a;
                    cluster->getSolution(a);
                    if (ToulBar2::showSolutions) {
                        TAssign::iterator it = a.begin();
                        while (it != a.end()) {
                            Value v = it->second;
                            cout << it->first << ":" << v << " ";
                            ++it;
                        }
                        cout << endl;
                    }
                }
            }
        }
        Cost bestlb = MAX(lbgood, clb);
        if (ToulBar2::verbose >= 1)
            cout << "[" << Store::getDepth() << "] C" << cluster->getId() << " return " << bestlb << " " << cub << endl;
        assert(bestlb <= cub);
        if (ToulBar2::hbfs && bestlb < cub) { // keep current node in open list instead of closing it!
            if (cluster->getNbVars() > 0) {
                int varid = *cluster->getVars().begin();
                assert(wcsp->assigned(varid));
                cluster->cp->addChoicePoint(CP_ASSIGN, varid, wcsp->getValue(varid), true); // dummy additional choice point to avoid the reversal of the last effective choice point for this open node
            }
#ifndef NDEBUG
            OpenList* prevopen = cluster->open;
            Cost tmplb = MIN_COST;
            Cost tmpub = MAX_COST;
            Cost tmpclusterub = cluster->getUb();
            assert(cluster == wcsp->getTreeDec()->getRoot() || cluster->nogoodGet(tmplb, tmpub, &cluster->open)); // warning! it can destroy cluster->ub
            cluster->setUb(tmpclusterub);
            assert(prevopen == cluster->open);
#endif
            addOpenNode(*(cluster->cp), *(cluster->open), bestlb, cluster->getCurrentDelta()); // reinsert as a new open node
            cluster->hbfsLimit = cluster->nbBacktracks; // and stop current visited node
            bestlb = cub;
        }
        return make_pair(bestlb, cub);
    } else {
        // Enumerates cluster proper variables
        *((StoreCost*)searchSize) += ((Cost)(10e6 * Log(wcsp->getDomainSize(varIndex))));
        pair<Cost, Cost> res = make_pair(MIN_COST, MAX_COST);
        if (wcsp->enumerated(varIndex)) {
            assert(wcsp->canbe(varIndex, wcsp->getSupport(varIndex)));
            // Reuse last solution found if available
            Value bestval = ((ToulBar2::verifyOpt) ? (wcsp->getSup(varIndex) + 1) : wcsp->getBestValue(varIndex));
            res = binaryChoicePoint(cluster, lbgood, cub, varIndex, (wcsp->canbe(varIndex, bestval)) ? bestval : wcsp->getSupport(varIndex));
        } else {
            res = binaryChoicePoint(cluster, lbgood, cub, varIndex, wcsp->getInf(varIndex));
        }
        if (ToulBar2::verbose >= 1)
            cout << "[" << Store::getDepth() << "] C" << cluster->getId() << " return " << res.first << " " << res.second << endl;
        assert(res.first >= lbgood);
        assert(res.second <= cub);
        assert(res.first <= res.second);
        return res;
    }
}
コード例 #11
0
pair<Cost, Cost> Solver::binaryChoicePoint(Cluster* cluster, Cost lbgood, Cost cub, int varIndex, Value value)
{
    assert(lbgood < cub);
    if (ToulBar2::interrupted)
        throw TimeOut();
    Cost clb = cub;
    TreeDecomposition* td = wcsp->getTreeDec();
    assert(wcsp->unassigned(varIndex));
    assert(wcsp->canbe(varIndex, value));
    bool dichotomic = (ToulBar2::dichotomicBranching && ToulBar2::dichotomicBranchingSize < wcsp->getDomainSize(varIndex));
    Value middle = value;
    bool increasing = true;
    if (dichotomic) {
        middle = (wcsp->getInf(varIndex) + wcsp->getSup(varIndex)) / 2;
        if (value <= middle)
            increasing = true;
        else
            increasing = false;
    }
    try {
        Store::store();
        assert(td->getCurrentCluster() == cluster);
        assert(wcsp->getLb() == cluster->getLbRec());
        wcsp->setUb(cub);
        Cost bestlb = lbgood;
        if (CUT(bestlb, cub))
            THROWCONTRADICTION;
        if (ToulBar2::btdMode >= 2) {
            Cost rds = td->getLbRecRDS();
            bestlb = MAX(bestlb, rds);
            if (CUT(bestlb, cub))
                THROWCONTRADICTION;
        }
        lastConflictVar = varIndex;
        if (dichotomic) {
            if (increasing)
                decrease(varIndex, middle);
            else
                increase(varIndex, middle + 1);
        } else
            assign(varIndex, value);
        lastConflictVar = -1;
        bestlb = MAX(bestlb, wcsp->getLb());
        pair<Cost, Cost> res = recursiveSolve(cluster, bestlb, cub);
        clb = MIN(res.first, clb);
        cub = MIN(res.second, cub);
    } catch (Contradiction) {
        wcsp->whenContradiction();
    }
    Store::restore();
    nbBacktracks++;
    if (ToulBar2::restart > 0 && nbBacktracks > nbBacktracksLimit)
        throw NbBacktracksOut();
#ifdef OPENMPI
    if (ToulBar2::vnsParallel && ((nbBacktracks % 128) == 0) && MPI_interrupted())
        throw TimeOut();
#endif
    cluster->nbBacktracks++;
    try {
        Store::store();
        assert(wcsp->getTreeDec()->getCurrentCluster() == cluster);
        assert(wcsp->getLb() == cluster->getLbRec());
        wcsp->setUb(cub);
        Cost bestlb = lbgood;
        if (CUT(bestlb, cub))
            THROWCONTRADICTION;
        if (ToulBar2::btdMode >= 2) {
            Cost rds = td->getLbRecRDS();
            bestlb = MAX(bestlb, rds);
            if (CUT(bestlb, cub))
                THROWCONTRADICTION;
        }
        if (dichotomic) {
            if (increasing)
                increase(varIndex, middle + 1, cluster->nbBacktracks >= cluster->hbfsLimit || nbBacktracks >= cluster->hbfsGlobalLimit);
            else
                decrease(varIndex, middle, cluster->nbBacktracks >= cluster->hbfsLimit || nbBacktracks >= cluster->hbfsGlobalLimit);
        } else
            remove(varIndex, value, cluster->nbBacktracks >= cluster->hbfsLimit || nbBacktracks >= cluster->hbfsGlobalLimit);
        bestlb = MAX(bestlb, wcsp->getLb());
        if (!ToulBar2::hbfs && cluster == td->getRoot() && initialDepth + 1 == Store::getDepth()) {
            initialDepth++;
            showGap(bestlb, cub);
        };
        if (cluster->nbBacktracks >= cluster->hbfsLimit || nbBacktracks >= cluster->hbfsGlobalLimit) {
            addOpenNode(*(cluster->cp), *(cluster->open), bestlb, cluster->getCurrentDelta());
        } else {
            pair<Cost, Cost> res = recursiveSolve(cluster, bestlb, cub);
            clb = MIN(res.first, clb);
            cub = MIN(res.second, cub);
        }
    } catch (Contradiction) {
        wcsp->whenContradiction();
    }
    Store::restore();
    assert(lbgood <= clb);
    assert(clb <= cub);
    return make_pair(clb, cub);
}