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; }
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; } }
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; } }