bool ModelEnumerator::BacktrackFinder::doUpdate(Solver& s) { if (hasModel()) { bool ok = true; uint32 sp = (opts & ModelEnumerator::project_save_progress) != 0 ? Solver::undo_save_phases : 0; s.undoUntil(s.backtrackLevel(), sp); ClauseRep rep = ClauseCreator::prepare(s, solution, 0, Constraint_t::Conflict); if (rep.size == 0 || s.isFalse(rep.lits[0])) { // The decision stack is already ordered. ok = s.backtrack(); } else if (rep.size == 1 || s.isFalse(rep.lits[1])) { // The projection nogood is unit. Force the single remaining literal from the current DL. ok = s.force(rep.lits[0], this); } else if (!s.isTrue(rep.lits[0])) { // Shorten the projection nogood by assuming one of its literals to false. uint32 f = static_cast<uint32>(std::stable_partition(rep.lits+2, rep.lits+rep.size, std::not1(std::bind1st(std::mem_fun(&Solver::isFalse), &s))) - rep.lits); Literal x = (opts & ModelEnumerator::project_use_heuristic) != 0 ? s.heuristic()->selectRange(s, rep.lits, rep.lits+f) : rep.lits[0]; LearntConstraint* c = Clause::newContractedClause(s, rep, f, true); CLASP_FAIL_IF(!c, "Invalid constraint!"); s.assume(~x); // Remember that we must backtrack the current decision // level in order to guarantee a different projected solution. s.setProjectLevel(s.decisionLevel()); // Attach nogood to the current decision literal. // Once we backtrack to x, the then obsolete nogood is destroyed // keeping the number of projection nogoods linear in the number of (projection) atoms. s.addWatch(x, this, (uint32)projNogoods.size()); projNogoods.push_back(NogoodPair(x, c)); ok = true; } solution.clear(); return ok; } if (optimize() || s.sharedContext()->concurrency() == 1 || disjointPath()) { return true; } s.setStopConflict(); return false; }
bool BacktrackEnumerator::doBacktrack(Solver& s, uint32 bl) { // bl is the decision level on which search should proceed. // bl + 1 the minimum of: // a) the highest DL on which one of the projected vars was assigned // b) the highest DL on which one of the vars in a minimize statement was assigned // c) the current decision level assert(bl >= s.rootLevel()); ++bl; assert(bl <= s.decisionLevel()); uint32 btLevel = getHighestBacktrackLevel(s, bl); if (!projectionEnabled() || bl <= btLevel) { // If we do not project or one of the projection vars is already on the backtracking level // proceed with simple backtracking. while (!s.backtrack() || s.decisionLevel() >= bl) { if (s.decisionLevel() == s.rootLevel()) { return false; } } return true; } else if (numProjectionVars() == 1u) { Literal x = s.trueLit(projectVar(0)); s.undoUntil(0); s.force(~x, 0); // force the complement of x s.setBacktrackLevel(s.decisionLevel()); } else { // Store the current projected assignment as a nogood // and attach it to the current decision level. // Once the solver goes above that level, the nogood is automatically // destroyed. Hence, the number of projection nogoods is linear in the // number of (projection) atoms. if ( (projectOpts_ & ENABLE_PROGRESS_SAVING) != 0 ) { s.strategies().saveProgress = 1; } projAssign_.clear(); projAssign_.resize(numProjectionVars()); LitVec::size_type front = 0; LitVec::size_type back = numProjectionVars(); for (uint32 i = 0; i != numProjectionVars(); ++i) { Literal x = ~s.trueLit(projectVar(i)); // Note: complement because we store the nogood as a clause! if (s.level(x.var()) > btLevel) { projAssign_[front++] = x; } else { projAssign_[--back] = x; } } s.undoUntil( btLevel ); Literal x = projAssign_[0]; LearntConstraint* c; if (front == 1) { // The projection nogood is unit. Force the single remaining literal // from the current DL. ++back; // so that the active part of the nogood contains at least two literals c = Clause::newContractedClause(s, projAssign_, back-1, back); s.force(x, c); } else { // Shorten the projection nogood by assuming one of its literals... if ( (projectOpts_ & ENABLE_HEURISTIC_SELECT) != 0 ) { x = s.strategies().heuristic->selectRange(s, &projAssign_[0], &projAssign_[0]+back); } c = Clause::newContractedClause(s, projAssign_, back-1, back); // to false. s.assume(~x); } if (s.backtrackLevel() < s.decisionLevel()) { // Remember that we must backtrack the current decision // level in order to guarantee a different projected solution. s.setBacktrackLevel(s.decisionLevel()); } if (s.decisionLevel() != 0) { // Attach nogood to the current decision literal. // Once the solver goes above that level, the nogood (which is then satisfied) is destroyed. s.addUndoWatch(s.decisionLevel(), this); } nogoods_.push_back( NogoodPair(c, s.decisionLevel()) ); assert(s.backtrackLevel() == s.decisionLevel()); } return true; }