void Solver::uncheckedEnqueue(Lit p, Clause* from) { #ifdef __PRINT if (from) { printClause(*from); } printf("--> "); printLit(p); printf("\n"); if (decisionLevel() == 0) { printf("Zl: "); printLit(p); printf("\n"); } #endif assigns [var(p)] = toInt(lbool(!sign(p))); // <<== abstract but not uttermost effecient level [var(p)] = decisionLevel(); reason [var(p)] = from; trail.push(p); }
void Engine::btToLevel(int level) { if (decisionLevel() == 0 && level == 0) return; assert(decisionLevel() > level); btToPos(trail_lim[level]); trail_lim.resize(level); dec_info.resize(level); }
double Solver::progressEstimate() const { double progress = 0; double F = 1.0 / nVars(); for (int i = 0; i <= decisionLevel(); i++){ int beg = i == 0 ? 0 : trail_lim[i - 1]; int end = i == decisionLevel() ? trail.size() : trail_lim[i]; progress += pow(F, i) * (end - beg); } return progress / nVars(); }
int MIP::doSimplex() { // printf("start simplex\n"); int r = SIMPLEX_IN_PROGRESS; int steps = 0; int limit = getLimit(); for ( ; steps < limit; steps++) { if ((r = simplex.simplex()) != SIMPLEX_IN_PROGRESS) break; // if (i == limit-1) printf("limit exceeded\n"); // if (i%10 == 0) printf("Optimum = %.3f, ", optimum()); } simplex.calcObjBound(); // if (MIP_DEBUG) { int bound = (int) ceil((double) simplex.optimum()); if (engine.opt_type == OPT_MAX) bound = -bound; if (steps) fprintf(stderr, "level = %d, %d simplex steps, status = %d, bound = %d\n", decisionLevel(), steps, r, bound); // fprintf(stderr, "%d simplex steps, status = %d, bound = %d\n", steps, r, bound); // fprintf(stderr, "%d %d\n", bound, engine.opt_type == OPT_MIN ? vars[0]->getMin() : -vars[0]->getMax()); // } exit(0); if (decisionLevel() == 0) simplex.saveState(simplex.root); return r; }
bool Solver::addClause(vec<Lit>& ps) { assert(decisionLevel() == 0); if (!ok) return false; else{ // Check if clause is satisfied and remove false/duplicate literals: sort(ps); Lit p; int i, j; for (i = j = 0, p = lit_Undef; i < ps.size(); i++) if (value(ps[i]) == l_True || ps[i] == ~p) return true; else if (value(ps[i]) != l_False && ps[i] != p) ps[j++] = p = ps[i]; ps.shrink(i - j); } if (ps.size() == 0) return ok = false; else if (ps.size() == 1){ assert(value(ps[0]) == l_Undef); uncheckedEnqueue(ps[0]); return ok = (propagate() == NULL); }else{ Clause* c = Clause_new(ps, false); clauses.push(c); attachClause(*c); } return true; }
bool SimpSMTSolver::asymm(Var v, Clause& c) { assert(decisionLevel() == 0); if (c.mark() || satisfied(c)) return true; trail_lim.push(trail.size()); Lit l = lit_Undef; for (int i = 0; i < c.size(); i++) if (var(c[i]) != v && value(c[i]) != l_False) { uncheckedEnqueue(~c[i]); } else l = c[i]; if (propagate() != NULL){ cancelUntil(0); asymm_lits++; if (!strengthenClause(c, l)) return false; }else cancelUntil(0); return true; }
/*_________________________________________________________________________________________________ | | analyzeFinal : (p : Lit) -> [void] | | Description: | Specialized analysis procedure to express the final conflict in terms of assumptions. | Calculates the (possibly empty) set of assumptions that led to the assignment of 'p', and | stores the result in 'out_conflict'. |________________________________________________________________________________________________@*/ void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict) { out_conflict.clear(); out_conflict.push(p); if (decisionLevel() == 0) return; seen[var(p)] = 1; for (int i = trail.size()-1; i >= trail_lim[0]; i--){ Var x = var(trail[i]); if (seen[x]){ if (reason[x] == NULL){ assert(level[x] > 0); out_conflict.push(~trail[i]); }else{ Clause& c = *reason[x]; for (int j = 1; j < c.size(); j++) if (level[var(c[j])] > 0) seen[var(c[j])] = 1; } seen[x] = 0; } } seen[var(p)] = 0; }
void SAT::addClause(Clause& c, bool one_watch) { assert(c.size() > 0); if (c.size() == 1) { assert(decisionLevel() == 0); if (DEBUG) fprintf(stderr, "warning: adding length 1 clause!\n"); if (value(c[0]) == l_False) TL_FAIL(); if (value(c[0]) == l_Undef) enqueue(c[0]); free(&c); return; } if (!c.learnt) { if (c.size() == 2) bin_clauses++; else if (c.size() == 3) tern_clauses++; else long_clauses++; } // Mark lazy lits which are used if (c.learnt) for (int i = 0; i < c.size(); i++) incVarUse(var(c[i])); if (c.size() == 2) { if (!one_watch) watches[toInt(~c[0])].push(c[1]); watches[toInt(~c[1])].push(c[0]); if (!c.learnt) free(&c); return; } if (!one_watch) watches[toInt(~c[0])].push(&c); watches[toInt(~c[1])].push(&c); if (c.learnt) learnts_literals += c.size(); else clauses_literals += c.size(); if (c.received) receiveds.push(&c); else if (c.learnt) learnts.push(&c); else clauses.push(&c); }
/*_________________________________________________________________________________________________ | | simplify : [void] -> [bool] | | Description: | Simplify the clause database according to the current top-level assigment. Currently, the only | thing done here is the removal of satisfied clauses, but more things can be put here. |________________________________________________________________________________________________@*/ bool MiniSATP::simplify() { remove_satisfied = false; assert(decisionLevel() == 0); // Modified Lines // if (!ok || propagate() != NULL) // return ok = false; if (!ok) return false; Clause * confl = propagate( ); if ( confl != NULL ) { fillExplanation( confl ); return ok = false; } if (nAssigns() == simpDB_assigns || (simpDB_props > 0)) return true; // Remove satisfied clauses: removeSatisfied(learnts); if (remove_satisfied) // Can be turned off. removeSatisfied(clauses); // Remove fixed variables from the variable heap: order_heap.filter(VarFilter(*this)); simpDB_assigns = nAssigns(); simpDB_props = clauses_literals + learnts_literals; // (shouldn't depend on stats really, but it will do for now) return true; }
inline void Engine::newDecisionLevel() { trail_inc++; trail_lim.push(trail.size()); sat.newDecisionLevel(); if (so.mip) mip->newDecisionLevel(); assert(dec_info.size() == decisionLevel()); }
void SimpSolver::remember(Var v) { assert(decisionLevel() == 0); assert(isEliminated(v)); vec<Lit> clause; // Re-activate variable: elimtable[v].order = 0; setDecisionVar(v, true); // Not good if the variable wasn't a decision variable before. Not sure how to fix this right now. if (use_simplification) updateElimHeap(v); // Reintroduce all old clauses which may implicitly remember other clauses: for (int i = 0; i < elimtable[v].eliminated.size(); i++){ Clause& c = *elimtable[v].eliminated[i]; clause.clear(); for (int j = 0; j < c.size(); j++) clause.push(c[j]); remembered_clauses++; check(addClause(clause)); free(&c); } elimtable[v].eliminated.clear(); }
// Backward subsumption + backward subsumption resolution bool SimpSolver::backwardSubsumptionCheck(bool verbose) { int cnt = 0; int subsumed = 0; int deleted_literals = 0; assert(decisionLevel() == 0); while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){ // Check top-level assignments by creating a dummy clause and placing it in the queue: if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){ Lit l = trail[bwdsub_assigns++]; (*bwdsub_tmpunit)[0] = l; bwdsub_tmpunit->calcAbstraction(); assert(bwdsub_tmpunit->mark() == 0); subsumption_queue.insert(bwdsub_tmpunit); } Clause& c = *subsumption_queue.peek(); subsumption_queue.pop(); if (c.mark()) continue; if (verbose && verbosity >= 2 && cnt++ % 1000 == 0) reportf("subsumption left: %10d (%10d subsumed, %10d deleted literals)\r", subsumption_queue.size(), subsumed, deleted_literals); assert(c.size() > 1 || value(c[0]) == l_True); // Unit-clauses should have been propagated before this point. // Find best variable to scan: Var best = var(c[0]); for (int i = 1; i < c.size(); i++) if (occurs[var(c[i])].size() < occurs[best].size()) best = var(c[i]); // Search all candidates: vec<Clause*>& _cs = getOccurs(best); Clause** cs = (Clause**)_cs; for (int j = 0; j < _cs.size(); j++) if (c.mark()) break; else if (!cs[j]->mark() && cs[j] != &c){ Lit l = c.subsumes(*cs[j]); if (l == lit_Undef) subsumed++, removeClause(*cs[j]); else if (l != lit_Error){ deleted_literals++; if (!strengthenClause(*cs[j], ~l)) return false; // Did current candidate get deleted from cs? Then check candidate at index j again: if (var(l) == best) j--; } } } return true; }
void Solver::uncheckedEnqueue(Lit p, Clause* from) { assert(value(p) == l_Undef); assigns [var(p)] = toInt(lbool(!sign(p))); // <<== abstract but not uttermost effecient level [var(p)] = decisionLevel(); reason [var(p)] = from; trail.push(p); }
// Can assume everything has been propagated! (esp. the first two literals are != l_False, unless // the clause is binary and satisfied, in which case the first literal is true) // Returns True if clause is satisfied (will be removed), False otherwise. // bool Solver::simplify(Clause* c) const { assert(decisionLevel() == 0); for (int i = 0; i < c->size(); i++){ if (value((*c)[i]) == l_True) return true; } return false; }
// Revert to the state at given level (keeping all assignment at 'level' but not beyond). // void Solver::cancelUntil(int level) { if (decisionLevel() > level){ for (int c = trail.size()-1; c >= trail_lim[level]; c--){ Var x = var(trail[c]); assigns[x] = toInt(l_Undef); insertVarOrder(x); } qhead = trail_lim[level]; trail.shrink(trail.size() - trail_lim[level]); trail_lim.shrink(trail_lim.size() - level); } }
// Revert to the state at given level. void Solver::cancelUntil(int level) { if (decisionLevel() > level){ for (int c = trail.size()-1; c >= trail_lim[level]; c--){ Var x = var(trail[c]); assigns[x] = toInt(l_Undef); reason [x] = GClause_NULL; order.undo(x); } trail.shrink(trail.size() - trail_lim[level]); trail_lim.shrink(trail_lim.size() - level); qhead = trail.size(); } }
void SAT::addClause(Lit p, Lit q) { if (value(p) == l_True || value(q) == l_True) return; if (value(p) == l_False && value(q) == l_False) { assert(false); TL_FAIL(); } if (value(p) == l_False) { assert(decisionLevel() == 0); enqueue(q); return; } if (value(q) == l_False) { assert(decisionLevel() == 0); enqueue(p); return; } bin_clauses++; watches[toInt(~p)].push(q); watches[toInt(~q)].push(p); }
void SAT::addClause(Clause& c, bool one_watch) { assert(c.size() > 0); if (c.size() == 1) { assert(decisionLevel() == 0); if (DEBUG) fprintf(stderr, "warning: adding length 1 clause!\n"); if (value(c[0]) == l_False) TL_FAIL(); if (value(c[0]) == l_Undef) enqueue(c[0]); free(&c); return; } if (!c.learnt) { if (c.size() == 2) bin_clauses++; else if (c.size() == 3) tern_clauses++; else long_clauses++; } // Mark lazy lits which are used if (c.learnt) for (int i = 0; i < c.size(); i++) incVarUse(var(c[i])); if (c.size() == 2 && ((!c.learnt) || (so.bin_clause_opt))) { if (!one_watch) watches[toInt(~c[0])].push(c[1]); watches[toInt(~c[1])].push(c[0]); if (!c.learnt) free(&c); return; } if (!one_watch) watches[toInt(~c[0])].push(&c); watches[toInt(~c[1])].push(&c); if (c.learnt) learnts_literals += c.size(); else clauses_literals += c.size(); if (c.learnt) { learnts.push(&c); if (so.learnt_stats) { std::set<int> levels; for (int i = 0 ; i < c.size() ; i++) { levels.insert(out_learnt_level[i]); } std::stringstream s; // s << "learntclause,"; s << c.clauseID() << "," << c.size() << "," << levels.size(); if (so.learnt_stats_nogood) { s << ","; for (int i = 0 ; i < c.size() ; i++) { s << (i == 0 ? "" : " ") << getLitString(toInt(c[i])); // s << " (" << out_learnt_level[i] << ")"; } } //std::cerr << "\n"; learntClauseString[c.clauseID()] = s.str(); } } else { clauses.push(&c); } }
/*_________________________________________________________________________________________________ | | enqueue : (p : Lit) (from : Clause*) -> [bool] | | Description: | Puts a new fact on the propagation queue as well as immediately updating the variable's value. | Should a conflict arise, FALSE is returned. | | Input: | p - The fact to enqueue | from - [Optional] Fact propagated from this (currently) unit clause. Stored in 'reason[]'. | Default value is NULL (no reason). | | Output: | TRUE if fact was enqueued without conflict, FALSE otherwise. |________________________________________________________________________________________________@*/ bool Solver::enqueue(Lit p, GClause from) { if (value(p) != l_Undef) return value(p) != l_False; else{ assigns[var(p)] = toInt(lbool(!sign(p))); level [var(p)] = decisionLevel(); reason [var(p)] = from; trail.push(p); return true; } }
inline void SAT::untrailToPos(vec<Lit>& t, int p) { int dl = decisionLevel(); for (int i = t.size(); i-- > p; ) { int x = var(t[i]); assigns[x] = toInt(l_Undef); #if PHASE_SAVING if (so.phase_saving >= 1 || (so.phase_saving == 1 && dl >= l0)) polarity[x] = sign(t[i]); #endif insertVarOrder(x); } t.resize(p); }
void Solver::saveState() { for (int i = 0; i < watchBackup.changed.size(); i++) { const int which = watchBackup.changed[i]; assert(watchBackup.flags[which] == true); watchBackup.flags[which] = false; } watchBackup.changed.clear(); backup.touchedClauses.clear(); backup.sublevel = trail.size(); backup.level = decisionLevel(); }
void Solver::uncheckedEnqueue(Lit p, Clause* from) { #ifdef RESTORE if (backup.stage == 0) { printf("setting lit "); printLit(p); printf(" decLevel: %d flag: %d detachedClause: %p\n", decisionLevel(), backup.stage, backup.detachedClause); } #endif assert(value(p) == l_Undef); assigns [var(p)] = toInt(lbool(!sign(p))); // <<== abstract but not uttermost effecient level [var(p)] = decisionLevel(); reason [var(p)] = from; polarity[var(p)] = sign(p); trail.push(p); }
void SAT::topLevelCleanUp() { assert(decisionLevel() == 0); for (int i = rtrail[0].size(); i-- > 0; ) free(rtrail[0][i]); rtrail[0].clear(); if (so.sat_simplify && propagations >= next_simp_db) simplifyDB(); for (int i = 0; i < trail[0].size(); i++) { seen[var(trail[0][i])] = true; trailpos[var(trail[0][i])] = -1; } trail[0].clear(); qhead[0] = 0; }
void SAT::btToLevel(int level) { if (decisionLevel() <= level) return; for (int l = trail.size(); l-- > level+1; ) { untrailToPos(trail[l], 0); for (int i = rtrail[l].size(); i--; ) { free(rtrail[l][i]); } } trail.resize(level+1); qhead.resize(level+1); rtrail.resize(level+1); engine.btToLevel(level); if (so.mip) mip->btToLevel(level); }
lbool SimpSolver::solve(const vec<Lit>& assumps, bool do_simp, bool turn_off_simp) { vec<Var> extra_frozen; lbool result = l_True; do_simp &= use_simplification; do_simp &= (decisionLevel() == 0); if (do_simp){ // Assumptions must be temporarily frozen to run variable elimination: for (int i = 0; i < assumps.size(); i++){ Var v = var(assumps[i]); // If an assumption has been eliminated, remember it. if (isEliminated(v)) remember(v); if (!frozen[v]){ // Freeze and store. setFrozen(v, true); extra_frozen.push(v); } } if(eliminate(turn_off_simp)) result = l_True; else result = l_False; } if (result == l_True) result = Solver::solve(assumps); if (result == l_True) { extendModel(); #ifndef NDEBUG verifyModel(); #endif } if (do_simp) // Unfreeze the assumptions that were frozen: for (int i = 0; i < extra_frozen.size(); i++) setFrozen(extra_frozen[i], false); return result; }
// Revert to the state at given level (keeping all assignment at 'level' but not beyond). // void Solver::cancelUntil(int level) { #ifdef RESTORE printf("------------ Canceling until level %d\n", level); #endif if (decisionLevel() > level){ for (int c = trail.size()-1; c >= trail_lim[level]; c--){ Var x = var(trail[c]); assigns[x] = toInt(l_Undef); insertVarOrder(x); #ifdef RESTORE printf("Canceling lit ");printLit(trail[c]); printf("\n"); #endif } qhead = trail_lim[level]; trail.shrink(trail.size() - trail_lim[level]); trail_lim.shrink(trail_lim.size() - level); } }
bool SimpSolver::implied(const vec<Lit>& c) { assert(decisionLevel() == 0); trail_lim.push(trail.size()); for (int i = 0; i < c.size(); i++) if (value(c[i]) == l_True){ cancelUntil(0); return false; }else if (value(c[i]) != l_False){ assert(value(c[i]) == l_Undef); uncheckedEnqueue(~c[i]); } bool result = propagate() != NULL; cancelUntil(0); return result; }
bool SimpSolver::strengthenClause(Clause& c, Lit l) { assert(decisionLevel() == 0); assert(c.mark() == 0); assert(!c.learnt()); assert(find(watches[toInt(~c[0])], &c)); assert(find(watches[toInt(~c[1])], &c)); // FIX: this is too inefficient but would be nice to have (properly implemented) // if (!find(subsumption_queue, &c)) subsumption_queue.insert(&c); // If l is watched, delete it from watcher list and watch a new literal if (c[0] == l || c[1] == l){ Lit other = c[0] == l ? c[1] : c[0]; if (c.size() == 2){ removeClause(c); c.strengthen(l); }else{ c.strengthen(l); remove(watches[toInt(~l)], &c); // Add a watch for the correct literal watches[toInt(~(c[1] == other ? c[0] : c[1]))].push(&c); // !! this version assumes that remove does not change the order !! //watches[toInt(~c[1])].push(&c); clauses_literals -= 1; } } else{ c.strengthen(l); clauses_literals -= 1; } // if subsumption-indexing is active perform the necessary updates if (use_simplification){ remove(occurs[var(l)], &c); n_occ[toInt(l)]--; updateElimHeap(var(l)); } return c.size() == 1 ? enqueue(c[0]) && propagate() == NULL : true; }
void SAT::topLevelCleanUp() { assert(decisionLevel() == 0); for (int i = rtrail[0].size(); i-- > 0; ) free(rtrail[0][i]); rtrail[0].clear(); if (so.sat_simplify && propagations >= next_simp_db) simplifyDB(); for (int i = 0; i < trail[0].size(); i++) { if (so.debug) { std::cerr << "setting true at top-level: " << getLitString(toInt(trail[0][i])) << "\n"; } seen[var(trail[0][i])] = true; trailpos[var(trail[0][i])] = -1; } trail[0].clear(); qhead[0] = 0; }
void SAT::btToLevel(int level) { #if DEBUG_VERBOSE std::cerr << "SAT::btToLevel( " << level << ")\n"; #endif if (decisionLevel() <= level) return; for (int l = trail.size(); l-- > level+1; ) { untrailToPos(trail[l], 0); for (int i = rtrail[l].size(); i--; ) { free(rtrail[l][i]); } } trail.resize(level+1); qhead.resize(level+1); rtrail.resize(level+1); engine.btToLevel(level); if (so.mip) mip->btToLevel(level); }