diff options
author | Christopher L. Conway <christopherleeconway@gmail.com> | 2010-08-13 17:21:24 +0000 |
---|---|---|
committer | Christopher L. Conway <christopherleeconway@gmail.com> | 2010-08-13 17:21:24 +0000 |
commit | 33de059bee5f6814615a88a7c13d819820430f25 (patch) | |
tree | c0b2cdd0ff249c3811befcd12d011dc89a5099b9 /src/prop/minisat/simp/SimpSolver.cc | |
parent | ca627b6170a0528b95b94c8de7255eb243d99264 (diff) |
Removing newer version of MiniSat for Dejan's preferred import
Diffstat (limited to 'src/prop/minisat/simp/SimpSolver.cc')
-rw-r--r-- | src/prop/minisat/simp/SimpSolver.cc | 717 |
1 files changed, 0 insertions, 717 deletions
diff --git a/src/prop/minisat/simp/SimpSolver.cc b/src/prop/minisat/simp/SimpSolver.cc deleted file mode 100644 index a1dc16d3a..000000000 --- a/src/prop/minisat/simp/SimpSolver.cc +++ /dev/null @@ -1,717 +0,0 @@ -/***********************************************************************************[SimpSolver.cc] -Copyright (c) 2006, Niklas Een, Niklas Sorensson -Copyright (c) 2007-2010, Niklas Sorensson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -**************************************************************************************************/ - -#include "mtl/Sort.h" -#include "simp/SimpSolver.h" -#include "utils/System.h" - -using namespace Minisat; - -//================================================================================================= -// Options: - - -static const char* _cat = "SIMP"; - -static BoolOption opt_use_asymm (_cat, "asymm", "Shrink clauses by asymmetric branching.", false); -static BoolOption opt_use_rcheck (_cat, "rcheck", "Check if a clause is already implied. (costly)", false); -static BoolOption opt_use_elim (_cat, "elim", "Perform variable elimination.", true); -static IntOption opt_grow (_cat, "grow", "Allow a variable elimination step to grow by a number of clauses.", 0); -static IntOption opt_clause_lim (_cat, "cl-lim", "Variables are not eliminated if it produces a resolvent with a length above this limit. -1 means no limit", 20, IntRange(-1, INT32_MAX)); -static IntOption opt_subsumption_lim (_cat, "sub-lim", "Do not check if subsumption against a clause larger than this. -1 means no limit.", 1000, IntRange(-1, INT32_MAX)); -static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered during simplification.", 0.5, DoubleRange(0, false, HUGE_VAL, false)); - - -//================================================================================================= -// Constructor/Destructor: - - -SimpSolver::SimpSolver() : - grow (opt_grow) - , clause_lim (opt_clause_lim) - , subsumption_lim (opt_subsumption_lim) - , simp_garbage_frac (opt_simp_garbage_frac) - , use_asymm (opt_use_asymm) - , use_rcheck (opt_use_rcheck) - , use_elim (opt_use_elim) - , merges (0) - , asymm_lits (0) - , eliminated_vars (0) - , elimorder (1) - , use_simplification (true) - , occurs (ClauseDeleted(ca)) - , elim_heap (ElimLt(n_occ)) - , bwdsub_assigns (0) - , n_touched (0) -{ - vec<Lit> dummy(1,lit_Undef); - ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below. - bwdsub_tmpunit = ca.alloc(dummy); - remove_satisfied = false; -} - - -SimpSolver::~SimpSolver() -{ -} - - -Var SimpSolver::newVar(bool sign, bool dvar) { - Var v = Solver::newVar(sign, dvar); - - frozen .push((char)false); - eliminated.push((char)false); - - if (use_simplification){ - n_occ .push(0); - n_occ .push(0); - occurs .init(v); - touched .push(0); - elim_heap .insert(v); - } - return v; } - - - -lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp) -{ - vec<Var> extra_frozen; - lbool result = l_True; - - do_simp &= use_simplification; - - if (do_simp){ - // Assumptions must be temporarily frozen to run variable elimination: - for (int i = 0; i < assumptions.size(); i++){ - Var v = var(assumptions[i]); - - // If an assumption has been eliminated, remember it. - assert(!isEliminated(v)); - - if (!frozen[v]){ - // Freeze and store. - setFrozen(v, true); - extra_frozen.push(v); - } } - - result = lbool(eliminate(turn_off_simp)); - } - - if (result == l_True) - result = Solver::solve_(); - else if (verbosity >= 1) - printf("===============================================================================\n"); - - if (result == l_True) - extendModel(); - - 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; -} - - - -bool SimpSolver::addClause_(vec<Lit>& ps) -{ -#ifndef NDEBUG - for (int i = 0; i < ps.size(); i++) - assert(!isEliminated(var(ps[i]))); -#endif - - int nclauses = clauses.size(); - - if (use_rcheck && implied(ps)) - return true; - - if (!Solver::addClause_(ps)) - return false; - - if (use_simplification && clauses.size() == nclauses + 1){ - CRef cr = clauses.last(); - const Clause& c = ca[cr]; - - // NOTE: the clause is added to the queue immediately and then - // again during 'gatherTouchedClauses()'. If nothing happens - // in between, it will only be checked once. Otherwise, it may - // be checked twice unnecessarily. This is an unfortunate - // consequence of how backward subsumption is used to mimic - // forward subsumption. - subsumption_queue.insert(cr); - for (int i = 0; i < c.size(); i++){ - occurs[var(c[i])].push(cr); - n_occ[toInt(c[i])]++; - touched[var(c[i])] = 1; - n_touched++; - if (elim_heap.inHeap(var(c[i]))) - elim_heap.increase(var(c[i])); - } - } - - return true; -} - - -void SimpSolver::removeClause(CRef cr) -{ - const Clause& c = ca[cr]; - - if (use_simplification) - for (int i = 0; i < c.size(); i++){ - n_occ[toInt(c[i])]--; - updateElimHeap(var(c[i])); - occurs.smudge(var(c[i])); - } - - Solver::removeClause(cr); -} - - -bool SimpSolver::strengthenClause(CRef cr, Lit l) -{ - Clause& c = ca[cr]; - assert(decisionLevel() == 0); - assert(use_simplification); - - // FIX: this is too inefficient but would be nice to have (properly implemented) - // if (!find(subsumption_queue, &c)) - subsumption_queue.insert(cr); - - if (c.size() == 2){ - removeClause(cr); - c.strengthen(l); - }else{ - detachClause(cr, true); - c.strengthen(l); - attachClause(cr); - remove(occurs[var(l)], cr); - n_occ[toInt(l)]--; - updateElimHeap(var(l)); - } - - return c.size() == 1 ? enqueue(c[0]) && propagate() == CRef_Undef : true; -} - - -// Returns FALSE if clause is always satisfied ('out_clause' should not be used). -bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause) -{ - merges++; - out_clause.clear(); - - bool ps_smallest = _ps.size() < _qs.size(); - const Clause& ps = ps_smallest ? _qs : _ps; - const Clause& qs = ps_smallest ? _ps : _qs; - - for (int i = 0; i < qs.size(); i++){ - if (var(qs[i]) != v){ - for (int j = 0; j < ps.size(); j++) - if (var(ps[j]) == var(qs[i])) - if (ps[j] == ~qs[i]) - return false; - else - goto next; - out_clause.push(qs[i]); - } - next:; - } - - for (int i = 0; i < ps.size(); i++) - if (var(ps[i]) != v) - out_clause.push(ps[i]); - - return true; -} - - -// Returns FALSE if clause is always satisfied. -bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, int& size) -{ - merges++; - - bool ps_smallest = _ps.size() < _qs.size(); - const Clause& ps = ps_smallest ? _qs : _ps; - const Clause& qs = ps_smallest ? _ps : _qs; - const Lit* __ps = (const Lit*)ps; - const Lit* __qs = (const Lit*)qs; - - size = ps.size()-1; - - for (int i = 0; i < qs.size(); i++){ - if (var(__qs[i]) != v){ - for (int j = 0; j < ps.size(); j++) - if (var(__ps[j]) == var(__qs[i])) - if (__ps[j] == ~__qs[i]) - return false; - else - goto next; - size++; - } - next:; - } - - return true; -} - - -void SimpSolver::gatherTouchedClauses() -{ - if (n_touched == 0) return; - - int i,j; - for (i = j = 0; i < subsumption_queue.size(); i++) - if (ca[subsumption_queue[i]].mark() == 0) - ca[subsumption_queue[i]].mark(2); - - for (i = 0; i < touched.size(); i++) - if (touched[i]){ - const vec<CRef>& cs = occurs.lookup(i); - for (j = 0; j < cs.size(); j++) - if (ca[cs[j]].mark() == 0){ - subsumption_queue.insert(cs[j]); - ca[cs[j]].mark(2); - } - touched[i] = 0; - } - - for (i = 0; i < subsumption_queue.size(); i++) - if (ca[subsumption_queue[i]].mark() == 2) - ca[subsumption_queue[i]].mark(0); - - n_touched = 0; -} - - -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() != CRef_Undef; - cancelUntil(0); - return result; -} - - -// 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()){ - - // Empty subsumption queue and return immediately on user-interrupt: - if (asynch_interrupt){ - subsumption_queue.clear(); - bwdsub_assigns = trail.size(); - break; } - - // 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++]; - ca[bwdsub_tmpunit][0] = l; - ca[bwdsub_tmpunit].calcAbstraction(); - subsumption_queue.insert(bwdsub_tmpunit); } - - CRef cr = subsumption_queue.peek(); subsumption_queue.pop(); - Clause& c = ca[cr]; - - if (c.mark()) continue; - - if (verbose && verbosity >= 2 && cnt++ % 1000 == 0) - printf("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<CRef>& _cs = occurs.lookup(best); - CRef* cs = (CRef*)_cs; - - for (int j = 0; j < _cs.size(); j++) - if (c.mark()) - break; - else if (!ca[cs[j]].mark() && cs[j] != cr && (subsumption_lim == -1 || ca[cs[j]].size() < subsumption_lim)){ - Lit l = c.subsumes(ca[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; -} - - -bool SimpSolver::asymm(Var v, CRef cr) -{ - Clause& c = ca[cr]; - 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() != CRef_Undef){ - cancelUntil(0); - asymm_lits++; - if (!strengthenClause(cr, l)) - return false; - }else - cancelUntil(0); - - return true; -} - - -bool SimpSolver::asymmVar(Var v) -{ - assert(use_simplification); - - const vec<CRef>& cls = occurs.lookup(v); - - if (value(v) != l_Undef || cls.size() == 0) - return true; - - for (int i = 0; i < cls.size(); i++) - if (!asymm(v, cls[i])) - return false; - - return backwardSubsumptionCheck(); -} - - -static void mkElimClause(vec<uint32_t>& elimclauses, Lit x) -{ - elimclauses.push(toInt(x)); - elimclauses.push(1); -} - - -static void mkElimClause(vec<uint32_t>& elimclauses, Var v, Clause& c) -{ - int first = elimclauses.size(); - int v_pos = -1; - - // Copy clause to elimclauses-vector. Remember position where the - // variable 'v' occurs: - for (int i = 0; i < c.size(); i++){ - elimclauses.push(toInt(c[i])); - if (var(c[i]) == v) - v_pos = i + first; - } - assert(v_pos != -1); - - // Swap the first literal with the 'v' literal, so that the literal - // containing 'v' will occur first in the clause: - uint32_t tmp = elimclauses[v_pos]; - elimclauses[v_pos] = elimclauses[first]; - elimclauses[first] = tmp; - - // Store the length of the clause last: - elimclauses.push(c.size()); -} - - - -bool SimpSolver::eliminateVar(Var v) -{ - assert(!frozen[v]); - assert(!isEliminated(v)); - assert(value(v) == l_Undef); - - // Split the occurrences into positive and negative: - // - const vec<CRef>& cls = occurs.lookup(v); - vec<CRef> pos, neg; - for (int i = 0; i < cls.size(); i++) - (find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]); - - // Check wether the increase in number of clauses stays within the allowed ('grow'). Moreover, no - // clause must exceed the limit on the maximal clause size (if it is set): - // - int cnt = 0; - int clause_size = 0; - - for (int i = 0; i < pos.size(); i++) - for (int j = 0; j < neg.size(); j++) - if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) && - (++cnt > cls.size() + grow || (clause_lim != -1 && clause_size > clause_lim))) - return true; - - // Delete and store old clauses: - eliminated[v] = true; - setDecisionVar(v, false); - eliminated_vars++; - - if (pos.size() > neg.size()){ - for (int i = 0; i < neg.size(); i++) - mkElimClause(elimclauses, v, ca[neg[i]]); - mkElimClause(elimclauses, mkLit(v)); - }else{ - for (int i = 0; i < pos.size(); i++) - mkElimClause(elimclauses, v, ca[pos[i]]); - mkElimClause(elimclauses, ~mkLit(v)); - } - - for (int i = 0; i < cls.size(); i++) - removeClause(cls[i]); - - // Produce clauses in cross product: - vec<Lit>& resolvent = add_tmp; - for (int i = 0; i < pos.size(); i++) - for (int j = 0; j < neg.size(); j++) - if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent)) - return false; - - // Free occurs list for this variable: - occurs[v].clear(true); - - // Free watchers lists for this variable, if possible: - if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true); - if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true); - - return backwardSubsumptionCheck(); -} - - -bool SimpSolver::substitute(Var v, Lit x) -{ - assert(!frozen[v]); - assert(!isEliminated(v)); - assert(value(v) == l_Undef); - - if (!ok) return false; - - eliminated[v] = true; - setDecisionVar(v, false); - const vec<CRef>& cls = occurs.lookup(v); - - vec<Lit>& subst_clause = add_tmp; - for (int i = 0; i < cls.size(); i++){ - Clause& c = ca[cls[i]]; - - subst_clause.clear(); - for (int j = 0; j < c.size(); j++){ - Lit p = c[j]; - subst_clause.push(var(p) == v ? x ^ sign(p) : p); - } - - removeClause(cls[i]); - - if (!addClause_(subst_clause)) - return ok = false; - } - - return true; -} - - -void SimpSolver::extendModel() -{ - int i, j; - Lit x; - - for (i = elimclauses.size()-1; i > 0; i -= j){ - for (j = elimclauses[i--]; j > 1; j--, i--) - if (modelValue(toLit(elimclauses[i])) != l_False) - goto next; - - x = toLit(elimclauses[i]); - model[var(x)] = lbool(!sign(x)); - next:; - } -} - - -bool SimpSolver::eliminate(bool turn_off_elim) -{ - if (!simplify()) - return false; - else if (!use_simplification) - return true; - - // Main simplification loop: - // - while (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0){ - - gatherTouchedClauses(); - // printf(" ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns); - if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) && - !backwardSubsumptionCheck(true)){ - ok = false; goto cleanup; } - - // Empty elim_heap and return immediately on user-interrupt: - if (asynch_interrupt){ - assert(bwdsub_assigns == trail.size()); - assert(subsumption_queue.size() == 0); - assert(n_touched == 0); - elim_heap.clear(); - goto cleanup; } - - // printf(" ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), elim_heap.size()); - for (int cnt = 0; !elim_heap.empty(); cnt++){ - Var elim = elim_heap.removeMin(); - - if (asynch_interrupt) break; - - if (isEliminated(elim) || value(elim) != l_Undef) continue; - - if (verbosity >= 2 && cnt % 100 == 0) - printf("elimination left: %10d\r", elim_heap.size()); - - if (use_asymm){ - // Temporarily freeze variable. Otherwise, it would immediately end up on the queue again: - bool was_frozen = frozen[elim]; - frozen[elim] = true; - if (!asymmVar(elim)){ - ok = false; goto cleanup; } - frozen[elim] = was_frozen; } - - // At this point, the variable may have been set by assymetric branching, so check it - // again. Also, don't eliminate frozen variables: - if (use_elim && value(elim) == l_Undef && !frozen[elim] && !eliminateVar(elim)){ - ok = false; goto cleanup; } - - checkGarbage(simp_garbage_frac); - } - - assert(subsumption_queue.size() == 0); - } - cleanup: - - // If no more simplification is needed, free all simplification-related data structures: - if (turn_off_elim){ - touched .clear(true); - occurs .clear(true); - n_occ .clear(true); - elim_heap.clear(true); - subsumption_queue.clear(true); - - use_simplification = false; - remove_satisfied = true; - ca.extra_clause_field = false; - - // Force full cleanup (this is safe and desirable since it only happens once): - rebuildOrderHeap(); - garbageCollect(); - }else{ - // Cheaper cleanup: - cleanUpClauses(); // TODO: can we make 'cleanUpClauses()' not be linear in the problem size somehow? - checkGarbage(); - } - - if (verbosity >= 1 && elimclauses.size() > 0) - printf("| Eliminated clauses: %10.2f Mb |\n", - double(elimclauses.size() * sizeof(uint32_t)) / (1024*1024)); - - return ok; -} - - -void SimpSolver::cleanUpClauses() -{ - occurs.cleanAll(); - int i,j; - for (i = j = 0; i < clauses.size(); i++) - if (ca[clauses[i]].mark() == 0) - clauses[j++] = clauses[i]; - clauses.shrink(i - j); -} - - -//================================================================================================= -// Garbage Collection methods: - - -void SimpSolver::relocAll(ClauseAllocator& to) -{ - if (!use_simplification) return; - - // All occurs lists: - // - for (int i = 0; i < nVars(); i++){ - vec<CRef>& cs = occurs[i]; - for (int j = 0; j < cs.size(); j++) - ca.reloc(cs[j], to); - } - - // Subsumption queue: - // - for (int i = 0; i < subsumption_queue.size(); i++) - ca.reloc(subsumption_queue[i], to); - - // Temporary clause: - // - ca.reloc(bwdsub_tmpunit, to); -} - - -void SimpSolver::garbageCollect() -{ - // Initialize the next region to a size corresponding to the estimated utilization degree. This - // is not precise but should avoid some unnecessary reallocations for the new region: - ClauseAllocator to(ca.size() - ca.wasted()); - - cleanUpClauses(); - to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields. - relocAll(to); - Solver::relocAll(to); - if (verbosity >= 2) - printf("| Garbage collection: %12d bytes => %12d bytes |\n", - ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size); - to.moveTo(ca); -} |