summaryrefslogtreecommitdiff
path: root/src/prop/cryptominisat/Solver/Solver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/prop/cryptominisat/Solver/Solver.cpp')
-rw-r--r--src/prop/cryptominisat/Solver/Solver.cpp2924
1 files changed, 0 insertions, 2924 deletions
diff --git a/src/prop/cryptominisat/Solver/Solver.cpp b/src/prop/cryptominisat/Solver/Solver.cpp
deleted file mode 100644
index f73d6166e..000000000
--- a/src/prop/cryptominisat/Solver/Solver.cpp
+++ /dev/null
@@ -1,2924 +0,0 @@
-/*****************************************************************************
-MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
-glucose -- Gilles Audemard, Laurent Simon (2008)
-CryptoMiniSat -- Copyright (c) 2009 Mate Soos
-
-Original code by MiniSat and glucose authors are under an MIT licence.
-Modifications for CryptoMiniSat are under GPLv3 licence.
-******************************************************************************/
-
-#include "Solver.h"
-#include <cmath>
-#include <string.h>
-#include <algorithm>
-#include <limits.h>
-#include <vector>
-#include <iomanip>
-#include <algorithm>
-
-#include "Clause.h"
-#include "time_mem.h"
-
-#include "VarReplacer.h"
-#include "XorFinder.h"
-#include "ClauseCleaner.h"
-#include "RestartTypeChooser.h"
-#include "FailedLitSearcher.h"
-#include "Subsumer.h"
-#include "XorSubsumer.h"
-#include "StateSaver.h"
-#include "SCCFinder.h"
-#include "SharedData.h"
-#include "ClauseVivifier.h"
-#include "Gaussian.h"
-#include "MatrixFinder.h"
-#include "DataSync.h"
-#include "BothCache.h"
-
-#ifdef VERBOSE_DEBUG
-#define UNWINDING_DEBUG
-#endif
-
-//#define DEBUG_UNCHECKEDENQUEUE_LEVEL0
-//#define VERBOSE_DEBUG_POLARITIES
-//#define DEBUG_DYNAMIC_RESTART
-//#define UNWINDING_DEBUG
-
-//**********************************
-// Constructor/Destructor:
-//**********************************
-
-using namespace CMSat;
-
-/**
-@brief Sets a sane default config and allocates handler classes
-*/
-Solver::Solver(const SolverConf& _conf, const GaussConf& _gaussconfig, SharedData* sharedData) :
- // Parameters: (formerly in 'SearchParams')
- conf(_conf)
- , gaussconfig(_gaussconfig)
- , needToInterrupt (false)
- #ifdef USE_GAUSS
- , sum_gauss_called (0)
- , sum_gauss_confl (0)
- , sum_gauss_prop (0)
- , sum_gauss_unit_truths (0)
- #endif //USE_GAUSS
-
- // Stats
- , starts(0), dynStarts(0), staticStarts(0), fullStarts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0)
- , clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0)
- , nbGlue2(0), numNewBin(0), lastNbBin(0), lastSearchForBinaryXor(0), nbReduceDB(0)
- , improvedClauseNo(0), improvedClauseSize(0)
- , numShrinkedClause(0), numShrinkedClauseLits(0)
- , moreRecurMinLDo(0)
- , updateTransCache(0)
- , nbClOverMaxGlue(0)
-
- , ok (true)
- , numBins (0)
- , cla_inc (1)
- , qhead (0)
- , mtrand ((unsigned long int)0)
-
- //variables
- , order_heap (VarOrderLt(activity))
- , var_inc (128)
-
- //learnts
- , numCleanedLearnts(1)
- , nbClBeforeRed (NBCLAUSESBEFOREREDUCE)
- , nbCompensateSubsumer (0)
- , libraryCNFFile (NULL)
- , restartType (static_restart)
- , lastSelectedRestartType (static_restart)
- , simplifying (false)
- , totalSimplifyTime(0.0)
- , simpDB_assigns (-1)
- , simpDB_props (0)
-{
- mtrand.seed(conf.origSeed);
- #ifdef ENABLE_UNWIND_GLUE
- assert(conf.maxGlue < MAX_THEORETICAL_GLUE);
- #endif //ENABLE_UNWIND_GLUE
- varReplacer = new VarReplacer(*this);
- clauseCleaner = new ClauseCleaner(*this);
- failedLitSearcher = new FailedLitSearcher(*this);
- subsumer = new Subsumer(*this);
- xorSubsumer = new XorSubsumer(*this);
- restartTypeChooser = new RestartTypeChooser(*this);
- sCCFinder = new SCCFinder(*this);
- clauseVivifier = new ClauseVivifier(*this);
- matrixFinder = new MatrixFinder(*this);
- dataSync = new DataSync(*this, sharedData);
-
-}
-
-/**
-@brief Frees clauses and frees all allocated hander classes
-*/
-Solver::~Solver()
-{
- clearGaussMatrixes();
- delete matrixFinder;
- delete varReplacer;
- delete clauseCleaner;
- delete failedLitSearcher;
- delete subsumer;
- delete xorSubsumer;
- delete restartTypeChooser;
-
- if (libraryCNFFile)
- fclose(libraryCNFFile);
-}
-
-//**********************************
-// Minor methods
-//**********************************
-
-/**
-@brief Creates a new SAT variable in the solver
-
-This entails making the datastructures large enough to fit the new variable
-in all internal datastructures as well as all datastructures used in
-classes used inside Solver
-
-@p dvar The new variable should be used as a decision variable?
- NOTE: this has effects on the meaning of a SATISFIABLE result
-*/
-Var Solver::newVar(bool dvar) throw (std::out_of_range)
-{
- Var v = nVars();
- if (v >= 1<<30)
- throw std::out_of_range("ERROR! Variable requested is far too large");
-
- watches .push(); // (list for positive literal)
- watches .push(); // (list for negative literal)
- reason .push(PropBy());
- assigns .push(l_Undef);
- level .push(-1);
- binPropData.push();
- activity .push(0);
- seen .push_back(0);
- seen .push_back(0);
- #ifdef ENABLE_UNWIND_GLUE
- unWindGlue.push(NULL);
- #endif //ENABLE_UNWIND_GLUE
-
- //Transitive OTF self-subsuming resolution
- seen2 .push_back(0);
- seen2 .push_back(0);
- transOTFCache.push_back(TransCache());
- transOTFCache.push_back(TransCache());
- litReachable.push_back(LitReachData());
- litReachable.push_back(LitReachData());
-
- polarity .push_back(defaultPolarity());
-
- decision_var.push_back(dvar);
- insertVarOrder(v);
-
- varReplacer->newVar();
- subsumer->newVar();
- xorSubsumer->newVar();
- dataSync->newVar();
-
- insertVarOrder(v);
-
- if (libraryCNFFile)
- fprintf(libraryCNFFile, "c Solver::newVar() called\n");
-
- return v;
-}
-
-/**
-@brief Adds an xor clause to the problem
-
-Should ONLY be called from internally. This is different from the extenal
-xor clause-adding function addXorClause() in that it assumes that the variables
-inside are decision variables, have not been replaced, eliminated, etc.
-*/
-template<class T>
-XorClause* Solver::addXorClauseInt(T& ps, bool xorEqualFalse, const bool learnt) throw (std::out_of_range)
-{
- assert(qhead == trail.size());
- assert(decisionLevel() == 0);
-
- if (ps.size() > (0x01UL << 18))
- throw std::out_of_range("Too long clause!");
- std::sort(ps.getData(), ps.getDataEnd());
- Lit p;
- uint32_t i, j;
- for (i = j = 0, p = lit_Undef; i != ps.size(); i++) {
- if (ps[i].var() == p.var()) {
- //added, but easily removed
- j--;
- p = lit_Undef;
- if (!assigns[ps[i].var()].isUndef())
- xorEqualFalse ^= assigns[ps[i].var()].getBool();
- } else if (assigns[ps[i].var()].isUndef()) { //just add
- ps[j++] = p = ps[i];
- assert(!subsumer->getVarElimed()[p.var()]);
- assert(!xorSubsumer->getVarElimed()[p.var()]);
- } else //modify xorEqualFalse instead of adding
- xorEqualFalse ^= (assigns[ps[i].var()].getBool());
- }
- ps.shrink(i - j);
-
- switch(ps.size()) {
- case 0: {
- if (!xorEqualFalse) ok = false;
- return NULL;
- }
- case 1: {
- uncheckedEnqueue(Lit(ps[0].var(), xorEqualFalse));
- ok = (propagate<false>().isNULL());
- return NULL;
- }
- case 2: {
- #ifdef VERBOSE_DEBUG
- cout << "--> xor is 2-long, replacing var " << ps[0].var()+1 << " with " << (!xorEqualFalse ? "-" : "") << ps[1].var()+1 << endl;
- #endif
-
- ps[0] = ps[0].unsign();
- ps[1] = ps[1].unsign();
- varReplacer->replace(ps, xorEqualFalse, learnt);
- return NULL;
- }
- default: {
- assert(!learnt);
- XorClause* c = clauseAllocator.XorClause_new(ps, xorEqualFalse);
- attachClause(*c);
- return c;
- }
- }
-}
-
-template XorClause* Solver::addXorClauseInt(vec<Lit>& ps, bool xorEqualFalse, const bool learnt);
-template XorClause* Solver::addXorClauseInt(XorClause& ps, bool xorEqualFalse, const bool learnt);
-
-/**
-@brief Adds an xor clause to the problem
-
-Calls addXorClauseInt() for the heavy-lifting. Basically, this does a bit
-of debug-related stuff (see "libraryCNFFile"), and then checks if any of the
-variables have been eliminated, replaced, etc. If so, it treats it correctly,
-and then calls addXorClauseInt() to actually add the xor clause.
-
-@p ps[inout] The VARIABLES in the xor clause. Beware, there must be NO signs
- here: ALL must be unsigned (.sign() == false). Values passed here
- WILL be changed, ordered, removed, etc!
-@p xorEqualFalse The xor must be equal to TRUE or false?
-*/
-template<class T>
-bool Solver::addXorClause(T& ps, bool xorEqualFalse) throw (std::out_of_range)
-{
- assert(decisionLevel() == 0);
- if (ps.size() > (0x01UL << 18))
- throw std::out_of_range("Too long clause!");
-
- if (libraryCNFFile) {
- fprintf(libraryCNFFile, "x");
- for (uint32_t i = 0; i < ps.size(); i++) ps[i].print(libraryCNFFile);
- fprintf(libraryCNFFile, "0\n");
- }
-
- if (!ok)
- return false;
- assert(qhead == trail.size());
- #ifndef NDEBUG
- for (Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) {
- assert(l->var() < nVars() && "Clause inserted, but variable inside has not been declared with newVar()!");
- }
- #endif
-
- if (varReplacer->getNumLastReplacedVars() || subsumer->getNumElimed() || xorSubsumer->getNumElimed()) {
- for (uint32_t i = 0; i != ps.size(); i++) {
- Lit otherLit = varReplacer->getReplaceTable()[ps[i].var()];
- if (otherLit.var() != ps[i].var()) {
- ps[i] = Lit(otherLit.var(), false);
- xorEqualFalse ^= otherLit.sign();
- }
- if (subsumer->getVarElimed()[ps[i].var()] && !subsumer->unEliminate(ps[i].var()))
- return false;
- else if (xorSubsumer->getVarElimed()[ps[i].var()] && !xorSubsumer->unEliminate(ps[i].var()))
- return false;
- }
- }
-
- XorClause* c = addXorClauseInt(ps, xorEqualFalse);
- if (c != NULL) xorclauses.push(c);
-
- return ok;
-}
-
-template bool Solver::addXorClause(vec<Lit>& ps, bool xorEqualFalse);
-template bool Solver::addXorClause(XorClause& ps, bool xorEqualFalse);
-
-/**
-@brief Adds a clause to the problem. Should ONLY be called internally
-
-This code is very specific in that it must NOT be called with varibles in
-"ps" that have been replaced, eliminated, etc. Also, it must not be called
-when the solver is in an UNSAT (!ok) state, for example. Use it carefully,
-and only internally
-*/
-template <class T>
-Clause* Solver::addClauseInt(T& ps
- , const bool learnt, const uint32_t glue, const float miniSatActivity
- , const bool inOriginalInput)
-{
- assert(ok);
-#ifdef VERBOSE_DEBUG
- std::cout << "Adding new clause: " << std::endl;
- for(size_t i = 0; i< ps.size(); i++) {
- printLit(ps[i]);
- std::cout << " ";
- }
- std::cout << std::endl;
-#endif //VERBOSE_DEBUG
-
- std::sort(ps.getData(), ps.getDataEnd());
- Lit p = lit_Undef;
- uint32_t i, j;
- for (i = j = 0; i != ps.size(); i++) {
- if (value(ps[i]).getBool() || ps[i] == ~p)
- return NULL;
- else if (value(ps[i]) != l_False && ps[i] != p) {
- ps[j++] = p = ps[i];
- assert(!subsumer->getVarElimed()[p.var()]);
- assert(!xorSubsumer->getVarElimed()[p.var()]);
- }
- }
- ps.shrink(i - j);
-
- if (ps.size() == 0) {
- ok = false;
- return NULL;
- } else if (ps.size() == 1) {
- uncheckedEnqueue(ps[0]);
- ok = (propagate<false>().isNULL());
- return NULL;
- }
-
- if (ps.size() > 2) {
- Clause* c = clauseAllocator.Clause_new(ps);
- if (learnt) c->makeLearnt(glue, miniSatActivity);
- attachClause(*c);
- return c;
- } else {
- attachBinClause(ps[0], ps[1], learnt);
- if (!inOriginalInput) dataSync->signalNewBinClause(ps);
- numNewBin++;
- return NULL;
- }
-}
-
-template Clause* Solver::addClauseInt(Clause& ps, const bool learnt, const uint32_t glue, const float miniSatActivity, const bool inOriginalInput);
-template Clause* Solver::addClauseInt(vec<Lit>& ps, const bool learnt, const uint32_t glue, const float miniSatActivity, const bool inOriginalInput);
-
-template<class T> bool Solver::addClauseHelper(T& ps) throw (std::out_of_range)
-{
- assert(decisionLevel() == 0);
- if (ps.size() > (0x01UL << 18))
- throw std::out_of_range("Too long clause!");
-
- if (libraryCNFFile) {
- for (uint32_t i = 0; i != ps.size(); i++) ps[i].print(libraryCNFFile);
- fprintf(libraryCNFFile, "0\n");
- }
-
- if (!ok) return false;
- assert(qhead == trail.size());
- #ifndef NDEBUG
- for (Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) {
- assert(l->var() < nVars() && "Clause inserted, but variable inside has not been declared with Solver::newVar() !");
- }
- #endif
-
- // Check if clause is satisfied and remove false/duplicate literals:
- if (varReplacer->getNumLastReplacedVars() || subsumer->getNumElimed() || xorSubsumer->getNumElimed()) {
- for (uint32_t i = 0; i != ps.size(); i++) {
- ps[i] = varReplacer->getReplaceTable()[ps[i].var()] ^ ps[i].sign();
- if (subsumer->getVarElimed()[ps[i].var()] && !subsumer->unEliminate(ps[i].var()))
- return false;
- if (xorSubsumer->getVarElimed()[ps[i].var()] && !xorSubsumer->unEliminate(ps[i].var()))
- return false;
- }
- }
-
- for (uint32_t i = 0; i < ps.size(); i++) {
- std::swap(ps[i], ps[(mtrand.randInt() % (ps.size()-i)) + i]);
- }
-
- return true;
-}
-
-
-/**
-@brief Adds a clause to the problem. Calls addClauseInt() for heavy-lifting
-
-Does some debug-related stuff (see "libraryCNFFile"), and checks whether the
-variables of the literals in "ps" have been eliminated/replaced etc. If so,
-it acts on them such that they are correct, and calls addClauseInt() to do
-the heavy-lifting
-*/
-template<class T>
-bool Solver::addClause(T& ps)
-{
- #ifdef VERBOSE_DEBUG
- std::cout << "addClause() called with new clause: " << ps << std::endl;
- #endif //VERBOSE_DEBUG
- if (!addClauseHelper(ps)) return false;
- Clause* c = addClauseInt(ps, false, 0, 0, true);
- if (c != NULL) clauses.push(c);
-
- return ok;
-}
-
-template bool Solver::addClause(vec<Lit>& ps);
-template bool Solver::addClause(Clause& ps);
-
-
-template<class T>
-bool Solver::addLearntClause(T& ps, const uint32_t glue, const float miniSatActivity)
-{
- if (!addClauseHelper(ps)) return false;
- Clause* c = addClauseInt(ps, true, glue, miniSatActivity, true);
- if (c != NULL) learnts.push(c);
-
- return ok;
-}
-
-template bool Solver::addLearntClause(vec<Lit>& ps, const uint32_t glue, const float miniSatActivity);
-template bool Solver::addLearntClause(Clause& ps, const uint32_t glue, const float miniSatActivity);
-
-
-/**
-@brief Attaches an xor clause to the watchlists
-
-The xor clause must be larger than 2, since a 2-long XOR clause is a varible
-replacement instruction, really.
-*/
-void Solver::attachClause(XorClause& c)
-{
- assert(c.size() > 2);
- #ifdef DEBUG_ATTACH
- assert(assigns[c[0].var()] == l_Undef);
- assert(assigns[c[1].var()] == l_Undef);
-
- for (uint32_t i = 0; i < c.size(); i++) {
- assert(!subsumer->getVarElimed()[c[i].var()]);
- assert(!xorSubsumer->getVarElimed()[c[i].var()]);
- }
- #endif //DEBUG_ATTACH
-
- watches[Lit(c[0].var(), false).toInt()].push(clauseAllocator.getOffset((Clause*)&c));
- watches[Lit(c[0].var(), true).toInt()].push(clauseAllocator.getOffset((Clause*)&c));
- watches[Lit(c[1].var(), false).toInt()].push(clauseAllocator.getOffset((Clause*)&c));
- watches[Lit(c[1].var(), true).toInt()].push(clauseAllocator.getOffset((Clause*)&c));
-
- clauses_literals += c.size();
-}
-
-void Solver::attachBinClause(const Lit lit1, const Lit lit2, const bool learnt)
-{
- #ifdef DEBUG_ATTACH
- assert(lit1.var() != lit2.var());
- assert(assigns[lit1.var()] == l_Undef);
- assert(value(lit2) == l_Undef || value(lit2) == l_False);
-
- assert(!subsumer->getVarElimed()[lit1.var()]);
- assert(!subsumer->getVarElimed()[lit2.var()]);
-
- assert(!xorSubsumer->getVarElimed()[lit1.var()]);
- assert(!xorSubsumer->getVarElimed()[lit2.var()]);
- #endif //DEBUG_ATTACH
-
- watches[(~lit1).toInt()].push(Watched(lit2, learnt));
- watches[(~lit2).toInt()].push(Watched(lit1, learnt));
-
- #ifdef DUMP_STATS_FULL
- if (learnt) {
- watches[(~lit1).toInt()].last().glue = 2;
- watches[(~lit2).toInt()].last().glue = 2;
- } else {
- watches[(~lit1).toInt()].last().glue = -1;
- watches[(~lit2).toInt()].last().glue = -1;
- }
- #endif
-
- numBins++;
- if (learnt) learnts_literals += 2;
- else clauses_literals += 2;
-}
-
-/**
-@brief Attach normal a clause to the watchlists
-
-Handles 2, 3 and >3 clause sizes differently and specially
-*/
-void Solver::attachClause(Clause& c)
-{
- assert(c.size() > 2);
- #ifdef DEBUG_ATTACH
- assert(c[0].var() != c[1].var());
- assert(assigns[c[0].var()] == l_Undef);
- assert(value(c[1]) == l_Undef || value(c[1]) == l_False);
-
- for (uint32_t i = 0; i < c.size(); i++) {
- assert(!subsumer->getVarElimed()[c[i].var()]);
- assert(!xorSubsumer->getVarElimed()[c[i].var()]);
- }
- #endif //DEBUG_ATTACH
-
- if (c.size() == 3) {
- watches[(~c[0]).toInt()].push(Watched(c[1], c[2]));
- watches[(~c[1]).toInt()].push(Watched(c[0], c[2]));
- watches[(~c[2]).toInt()].push(Watched(c[0], c[1]));
-
- #ifdef DUMP_STATS_FULL
- if (c.learnt()) {
- watches[(~c[0]).toInt()].last().glue = 2;
- watches[(~c[1]).toInt()].last().glue = 2;
- watches[(~c[2]).toInt()].last().glue = 2;
- } else {
- watches[(~c[0]).toInt()].last().glue = -1;
- watches[(~c[1]).toInt()].last().glue = -1;
- watches[(~c[2]).toInt()].last().glue = -1;
- }
- #endif
-
- } else {
- ClauseOffset offset = clauseAllocator.getOffset(&c);
- watches[(~c[0]).toInt()].push(Watched(offset, c[c.size()/2]));
- watches[(~c[1]).toInt()].push(Watched(offset, c[c.size()/2]));
- }
-
- if (c.learnt())
- learnts_literals += c.size();
- else
- clauses_literals += c.size();
-}
-
-/**
-@brief Calls detachModifiedClause to do the heavy-lifting
-*/
-void Solver::detachClause(const XorClause& c)
-{
- detachModifiedClause(c[0].var(), c[1].var(), c.size(), &c);
-}
-
-/**
-@brief Calls detachModifiedClause to do the heavy-lifting
-*/
-void Solver::detachClause(const Clause& c)
-{
- detachModifiedClause(c[0], c[1], (c.size() == 3) ? c[2] : lit_Undef, c.size(), &c);
-}
-
-/**
-@brief Detaches a (potentially) modified clause
-
-The first two literals might have chaned through modification, so they are
-passed along as arguments -- they are needed to find the correct place where
-the clause is
-*/
-void Solver::detachModifiedClause(const Lit lit1, const Lit lit2, const Lit lit3, const uint32_t origSize, const Clause* address)
-{
- assert(origSize > 2);
-
- ClauseOffset offset = clauseAllocator.getOffset(address);
- if (origSize == 3) {
- //The clause might have been longer, and has only recently
- //became 3-long. Check, and detach accordingly
- if (findWCl(watches[(~lit1).toInt()], offset)) goto fullClause;
-
- removeWTri(watches[(~lit1).toInt()], lit2, lit3);
- removeWTri(watches[(~lit2).toInt()], lit1, lit3);
- removeWTri(watches[(~lit3).toInt()], lit1, lit2);
-
- } else {
- fullClause:
- removeWCl(watches[(~lit1).toInt()], offset);
- removeWCl(watches[(~lit2).toInt()], offset);
-
- }
-
- if (address->learnt())
- learnts_literals -= origSize;
- else
- clauses_literals -= origSize;
-}
-
-/**
-@brief Detaches a (potentially) modified xor clause
-
-The first two vars might have chaned through modification, so they are passed
-along as arguments.
-*/
-void Solver::detachModifiedClause(const Var var1, const Var var2, const uint32_t origSize, const XorClause* address)
-{
- assert(origSize > 2);
-
- ClauseOffset offset = clauseAllocator.getOffset(address);
- assert(findWXCl(watches[Lit(var1, false).toInt()], offset));
- assert(findWXCl(watches[Lit(var1, true).toInt()], offset));
- assert(findWXCl(watches[Lit(var2, false).toInt()], offset));
- assert(findWXCl(watches[Lit(var2, true).toInt()], offset));
-
- removeWXCl(watches[Lit(var1, false).toInt()], offset);
- removeWXCl(watches[Lit(var1, true).toInt()], offset);
- removeWXCl(watches[Lit(var2, false).toInt()], offset);
- removeWXCl(watches[Lit(var2, true).toInt()], offset);
-
- assert(!address->learnt());
- clauses_literals -= origSize;
-}
-
-/**
-@brief Revert to the state at given level
-
-Also reverts all stuff in Gass-elimination
-*/
-void Solver::cancelUntil(int level)
-{
- #ifdef VERBOSE_DEBUG
- cout << "Canceling until level " << level;
- if (level > 0) cout << " sublevel: " << trail_lim[level];
- cout << endl;
- #endif
-
- if ((int)decisionLevel() > level) {
-
- #ifdef USE_GAUSS
- for (vector<Gaussian*>::iterator gauss = gauss_matrixes.begin(), end= gauss_matrixes.end(); gauss != end; gauss++)
- (*gauss)->canceling(trail_lim[level]);
- #endif //USE_GAUSS
-
- for (int sublevel = trail.size()-1; sublevel >= (int)trail_lim[level]; sublevel--) {
- Var var = trail[sublevel].var();
- #ifdef VERBOSE_DEBUG
- cout << "Canceling var " << var+1 << " sublevel: " << sublevel << endl;
- #endif
- assigns[var] = l_Undef;
- #ifdef ANIMATE3D
- fprintf(stderr, "u %u\n", var);
- #endif
- insertVarOrder(var);
- #ifdef ENABLE_UNWIND_GLUE
- if (unWindGlue[var] != NULL) {
- #ifdef UNWINDING_DEBUG
- std::cout << "unwind, var:" << var
- << " sublevel:" << sublevel
- << " coming from:" << (trail.size()-1)
- << " going until:" << (int)trail_lim[level]
- << std::endl;
- unWindGlue[var]->plainPrint();
- #endif //UNWINDING_DEBUG
-
- Clause*& clauseToFree = unWindGlue[var];
- detachClause(*clauseToFree);
- clauseAllocator.clauseFree(clauseToFree);
- clauseToFree = NULL;
- }
- #endif //ENABLE_UNWIND_GLUE
- }
- qhead = trail_lim[level];
- trail.shrink_(trail.size() - trail_lim[level]);
- trail_lim.shrink_(trail_lim.size() - level);
- }
-
- #ifdef VERBOSE_DEBUG
- cout << "Canceling finished. (now at level: " << decisionLevel() << " sublevel: " << trail.size()-1 << ")" << endl;
- #endif
-}
-
-void Solver::cancelUntilLight()
-{
- assert((int)decisionLevel() > 0);
-
- for (int sublevel = trail.size()-1; sublevel >= (int)trail_lim[0]; sublevel--) {
- Var var = trail[sublevel].var();
- assigns[var] = l_Undef;
- }
- qhead = trail_lim[0];
- trail.shrink_(trail.size() - trail_lim[0]);
- trail_lim.clear();
-}
-
-bool Solver::clearGaussMatrixes()
-{
- assert(decisionLevel() == 0);
- #ifdef USE_GAUSS
- bool ret = gauss_matrixes.size() > 0;
- for (uint32_t i = 0; i < gauss_matrixes.size(); i++)
- delete gauss_matrixes[i];
- gauss_matrixes.clear();
-
- for (uint32_t i = 0; i != freeLater.size(); i++)
- clauseAllocator.clauseFree(freeLater[i]);
- freeLater.clear();
-
- return ret;
- #endif //USE_GAUSS
- return false;
-}
-
-/**
-@brief Returns what polarity[] should be set as default based on polarity_mode
-
-since polarity is filled with Lit::sign() , "true" here means an inverted
-signed-ness, i.e. a FALSE default value. And vice-versa
-*/
-inline bool Solver::defaultPolarity()
-{
- switch(conf.polarity_mode) {
- case polarity_false:
- return true;
- case polarity_true:
- return false;
- case polarity_rnd:
- return mtrand.randInt(1);
- case polarity_auto:
- return true;
- default:
- assert(false);
- }
-
- return true;
-}
-
-/**
-@brief Tally votes for a default TRUE or FALSE value for the variable using the Jeroslow-Wang method
-
-@p votes[inout] Votes are tallied at this place for each variable
-@p cs The clause to tally votes for
-*/
-void Solver::tallyVotes(const vec<Clause*>& cs, vec<double>& votes) const
-{
- for (const Clause * const*it = cs.getData(), * const*end = it + cs.size(); it != end; it++) {
- const Clause& c = **it;
- if (c.learnt()) continue;
-
- double divider;
- if (c.size() > 63) divider = 0.0;
- else divider = 1.0/(double)((uint64_t)1<<(c.size()-1));
-
- for (const Lit *it2 = c.getData(), *end2 = c.getDataEnd(); it2 != end2; it2++) {
- if (it2->sign()) votes[it2->var()] += divider;
- else votes[it2->var()] -= divider;
- }
- }
-}
-
-void Solver::tallyVotesBin(vec<double>& votes) const
-{
- uint32_t wsLit = 0;
- for (const vec<Watched> *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) {
- Lit lit = ~Lit::toLit(wsLit);
- const vec<Watched>& ws = *it;
- for (vec<Watched>::const_iterator it2 = ws.getData(), end2 = ws.getDataEnd(); it2 != end2; it2++) {
- if (it2->isBinary() && lit.toInt() < it2->getOtherLit().toInt()) {
- if (!it2->getLearnt()) {
- if (lit.sign()) votes[lit.var()] += 0.5;
- else votes[lit.var()] -= 0.5;
-
- Lit lit2 = it2->getOtherLit();
- if (lit2.sign()) votes[lit2.var()] += 0.5;
- else votes[lit2.var()] -= 0.5;
- }
- }
- }
- }
-}
-
-/**
-@brief Tally votes a default TRUE or FALSE value for the variable using the Jeroslow-Wang method
-
-For XOR clause, we simply add some weight for a FALSE default, i.e. being in
-xor clauses makes the variabe more likely to be FALSE by default
-*/
-void Solver::tallyVotes(const vec<XorClause*>& cs, vec<double>& votes) const
-{
- for (const XorClause * const*it = cs.getData(), * const*end = it + cs.size(); it != end; it++) {
- const XorClause& c = **it;
- double divider;
- if (c.size() > 63) divider = 0.0;
- else divider = 1.0/(double)((uint64_t)1<<(c.size()-1));
-
- for (const Lit *it2 = c.getData(), *end2 = c.getDataEnd(); it2 != end2; it2++) {
- votes[it2->var()] += divider;
- }
- }
-}
-
-/**
-@brief Tallies votes for a TRUE/FALSE default polarity using Jeroslow-Wang
-
-Voting is only used if polarity_mode is "polarity_auto". This is the default.
-Uses the tallyVotes() functions to tally the votes
-*/
-void Solver::calculateDefaultPolarities()
-{
- #ifdef VERBOSE_DEBUG_POLARITIES
- std::cout << "Default polarities: " << std::endl;
- #endif
-
- assert(decisionLevel() == 0);
- if (conf.polarity_mode == polarity_auto) {
- double myTime = cpuTime();
-
- vec<double> votes(nVars(), 0.0);
-
- tallyVotes(clauses, votes);
- tallyVotesBin(votes);
- tallyVotes(xorclauses, votes);
-
- Var i = 0;
- uint32_t posPolars = 0;
- uint32_t undecidedPolars = 0;
- for (const double *it = votes.getData(), *end = votes.getDataEnd(); it != end; it++, i++) {
- polarity[i] = (*it >= 0.0);
- posPolars += (*it < 0.0);
- undecidedPolars += (*it == 0.0);
- #ifdef VERBOSE_DEBUG_POLARITIES
- std::cout << !defaultPolarities[i] << ", ";
- #endif //VERBOSE_DEBUG_POLARITIES
- }
-
- if (conf.verbosity >= 2) {
- std::cout << "c Calc default polars - "
- << " time: " << std::fixed << std::setw(6) << std::setprecision(2) << (cpuTime() - myTime) << " s"
- << " pos: " << std::setw(7) << posPolars
- << " undec: " << std::setw(7) << undecidedPolars
- << " neg: " << std::setw(7) << nVars()- undecidedPolars - posPolars
- << std:: endl;
- }
- } else {
- for (uint32_t i = 0; i < polarity.size(); i++) {
- polarity[i] = defaultPolarity();
- }
- }
-
- #ifdef VERBOSE_DEBUG_POLARITIES
- std::cout << std::endl;
- #endif //VERBOSE_DEBUG_POLARITIES
-}
-
-void Solver::calcReachability()
-{
- double myTime = cpuTime();
-
- for (uint32_t i = 0; i < nVars()*2; i++) {
- litReachable[i] = LitReachData();
- }
-
- for (uint32_t i = 0; i < order_heap.size(); i++) for (uint32_t sig1 = 0; sig1 < 2; sig1++) {
- Lit lit = Lit(order_heap[i], sig1);
- if (value(lit.var()) != l_Undef
- || subsumer->getVarElimed()[lit.var()]
- || xorSubsumer->getVarElimed()[lit.var()]
- || !decision_var[lit.var()])
- continue;
-
- vector<Lit>& cache = transOTFCache[(~lit).toInt()].lits;
- uint32_t cacheSize = cache.size();
- for (vector<Lit>::const_iterator it = cache.begin(), end = cache.end(); it != end; it++) {
- /*if (solver.value(it->var()) != l_Undef
- || solver.subsumer->getVarElimed()[it->var()]
- || solver.xorSubsumer->getVarElimed()[it->var()])
- continue;*/
- if ((*it == lit) || (*it == ~lit)) continue;
- if (litReachable[it->toInt()].lit == lit_Undef || litReachable[it->toInt()].numInCache < cacheSize) {
- litReachable[it->toInt()].lit = lit;
- litReachable[it->toInt()].numInCache = cacheSize;
- }
- }
- }
-
- /*for (uint32_t i = 0; i < nVars()*2; i++) {
- std::sort(litReachable[i].begin(), litReachable[i].end(), MySorterX(transOTFCache));
- }*/
-
- /*for (uint32_t i = 0; i < nVars()*2; i++) {
- vector<Lit>& myset = litReachable[i];
- for (uint32_t i2 = 0; i2 < myset.size(); i2++) {
- std::cout << transOTFCache[myset[i2].toInt()].lits.size() << " , ";
- }
- std::cout << std::endl;
- }*/
-
- if (conf.verbosity >= 1) {
- std::cout << "c calculated reachability. Time: " << (cpuTime() - myTime) << std::endl;
- }
-}
-
-void Solver::saveOTFData()
-{
- assert(decisionLevel() == 1);
-
- Lit lev0Lit = trail[trail_lim[0]];
- Solver::TransCache& oTFCache = transOTFCache[(~lev0Lit).toInt()];
- oTFCache.conflictLastUpdated = conflicts;
- oTFCache.lits.clear();
-
- for (int sublevel = trail.size()-1; sublevel > (int)trail_lim[0]; sublevel--) {
- Lit lit = trail[sublevel];
- oTFCache.lits.push_back(lit);
- }
-}
-
-//**********************************
-// Major methods:
-//**********************************
-
-/**
-@brief Picks a branching variable and its value (True/False)
-
-We do three things here:
--# Try to do random decision (rare, less than 2%)
--# Try acitivity-based decision
-
-Then, we pick a sign (True/False):
-\li If we are in search-burst mode ("simplifying" is set), we pick a sign
-totally randomly
-\li Otherwise, we simply take the saved polarity
-*/
-Lit Solver::pickBranchLit()
-{
- #ifdef VERBOSE_DEBUG
- cout << "decision level: " << decisionLevel() << " ";
- #endif
-
- Var next = var_Undef;
-
- /* Skip variables which have already been defined (this will usually happen
- * because of propagations/implicit assignments) */
- for (unsigned int i = decisionLevel(); i < branching_variables.size(); ++i) {
- Var v = branching_variables[i];
- if (v < nVars()
- && !subsumer->getVarElimed()[v]
- && !xorSubsumer->getVarElimed()[v]
- && assigns[v] == l_Undef) {
- next = v;
- break;
- }
- }
-
- bool random = mtrand.randDblExc() < conf.random_var_freq;
-
- // Random decision:
- if (next == var_Undef && random && !order_heap.empty()) {
- if (conf.restrictPickBranch == 0)
- next = order_heap[mtrand.randInt(order_heap.size()-1)];
- else
- next = order_heap[mtrand.randInt(std::min((uint32_t)order_heap.size()-1, conf.restrictPickBranch))];
-
- if (assigns[next] == l_Undef && decision_var[next])
- rnd_decisions++;
- }
-
- bool signSet = false;
- bool signSetTo = false;
- // Activity based decision:
- while (next == var_Undef
- || assigns[next] != l_Undef
- || !decision_var[next]) {
- if (order_heap.empty()) {
- next = var_Undef;
- break;
- }
-
- next = order_heap.removeMin();
- if (!simplifying && value(next) == l_Undef && decision_var[next]) {
- signSet = true;
- if (avgBranchDepth.isvalid())
- signSetTo = polarity[next] ^ (mtrand.randInt(avgBranchDepth.getAvgUInt() * ((lastSelectedRestartType == static_restart) ? 2 : 1) ) == 1);
- else
- signSetTo = polarity[next];
- Lit nextLit = Lit(next, signSetTo);
- Lit lit2 = litReachable[nextLit.toInt()].lit;
- if (lit2 != lit_Undef && value(lit2.var()) == l_Undef && decision_var[lit2.var()] && mtrand.randInt(1) == 1) {
- insertVarOrder(next);
- next = litReachable[nextLit.toInt()].lit.var();
- signSetTo = litReachable[nextLit.toInt()].lit.sign();
- }
- }
- }
-
- //if "simplifying" is set, i.e. if we are in a burst-search mode, then
- //randomly pick a sign. Otherwise, if RANDOM_LOOKAROUND_SEARCHSPACE is
- //defined, we check the default polarity, and we may change it a bit
- //randomly based on the average branch depth. Otherwise, we just go for the
- //polarity that has been saved
- bool sign;
- if (next != var_Undef) {
- if (signSet) {
- sign = signSetTo;
- } else {
- if (simplifying && random)
- sign = mtrand.randInt(1);
- else if (avgBranchDepth.isvalid())
- sign = polarity[next] ^ (mtrand.randInt(avgBranchDepth.getAvgUInt() * ((lastSelectedRestartType == static_restart) ? 2 : 1) ) == 1);
- else
- sign = polarity[next];
- }
- }
-
- assert(next == var_Undef || value(next) == l_Undef);
-
- if (next == var_Undef) {
- #ifdef VERBOSE_DEBUG
- cout << "SAT!" << endl;
- #endif
- return lit_Undef;
- } else {
- Lit lit(next,sign);
- #ifdef VERBOSE_DEBUG
- assert(decision_var[lit.var()]);
- cout << "decided on: " << lit.var()+1 << " to set:" << !lit.sign() << endl;
- #endif
- return lit;
- }
-}
-
-/**
-@brief Checks subsumption. Used in on-the-fly subsumption code
-
-Assumes 'seen' is cleared (will leave it cleared)
-*/
-template<class T1, class T2>
-bool subset(const T1& A, const T2& B, vector<char>& seen)
-{
- for (uint32_t i = 0; i != B.size(); i++)
- seen[B[i].toInt()] = 1;
- for (uint32_t i = 0; i != A.size(); i++) {
- if (!seen[A[i].toInt()]) {
- for (uint32_t i = 0; i != B.size(); i++)
- seen[B[i].toInt()] = 0;
- return false;
- }
- }
- for (uint32_t i = 0; i != B.size(); i++)
- seen[B[i].toInt()] = 0;
- return true;
-}
-
-
-/**
-@brief Analyze conflict and produce a reason clause.
-
-Pre-conditions:
-\li 'out_learnt' is assumed to be cleared.
-\li Current decision level must be greater than root level.
-
-Post-conditions:
-\li 'out_learnt[0]' is the asserting literal at level 'out_btlevel'.
-
-Effect: Will undo part of the trail, upto but not beyond the assumption of the
-current decision level.
-
-@return NULL if the conflict doesn't on-the-fly subsume the last clause, and
-the pointer of the clause if it does
-*/
-Clause* Solver::analyze(PropBy conflHalf, vec<Lit>& out_learnt, int& out_btlevel, uint32_t &glue, const bool update)
-{
- int pathC = 0;
- Lit p = lit_Undef;
-
- // Generate conflict clause:
- //
- out_learnt.push(); // (leave room for the asserting literal)
- int index = trail.size() - 1;
- out_btlevel = 0;
-
- PropByFull confl(conflHalf, failBinLit, clauseAllocator);
- PropByFull oldConfl;
-
- do {
- assert(!confl.isNULL()); // (otherwise should be UIP)
-
- if (update && restartType == static_restart && confl.isClause() && confl.getClause()->learnt())
- claBumpActivity(*confl.getClause());
-
- for (uint32_t j = (p == lit_Undef) ? 0 : 1, size = confl.size(); j != size; j++) {
- Lit q = confl[j];
- const Var my_var = q.var();
-
- if (!seen[my_var] && level[my_var] > 0) {
- varBumpActivity(my_var);
- seen[my_var] = 1;
- assert(level[my_var] <= (int)decisionLevel());
- if (level[my_var] >= (int)decisionLevel()) {
- pathC++;
- if (lastSelectedRestartType == dynamic_restart
- && reason[q.var()].isClause()
- && !reason[q.var()].isNULL()
- && clauseAllocator.getPointer(reason[q.var()].getClause())->learnt())
- lastDecisionLevel.push(q.var());
- } else {
- out_learnt.push(q);
- if (level[my_var] > out_btlevel)
- out_btlevel = level[my_var];
- }
- }
- }
-
- // Select next clause to look at:
- while (!seen[trail[index--].var()]);
- p = trail[index+1];
- oldConfl = confl;
- confl = PropByFull(reason[p.var()], failBinLit, clauseAllocator);
- if (confl.isClause()) __builtin_prefetch(confl.getClause());
- seen[p.var()] = 0;
- pathC--;
-
- } while (pathC > 0);
- assert(pathC == 0);
- out_learnt[0] = ~p;
-
- // Simplify conflict clause:
- //
- uint32_t i, j;
- if (conf.expensive_ccmin) {
- uint32_t abstract_level = 0;
- for (i = 1; i < out_learnt.size(); i++)
- abstract_level |= abstractLevel(out_learnt[i].var()); // (maintain an abstraction of levels involved in conflict)
-
- out_learnt.copyTo(analyze_toclear);
- for (i = j = 1; i < out_learnt.size(); i++)
- if (reason[out_learnt[i].var()].isNULL() || !litRedundant(out_learnt[i], abstract_level))
- out_learnt[j++] = out_learnt[i];
- } else {
- out_learnt.copyTo(analyze_toclear);
- for (i = j = 1; i < out_learnt.size(); i++) {
- PropByFull c(reason[out_learnt[i].var()], failBinLit, clauseAllocator);
-
- for (uint32_t k = 1, size = c.size(); k < size; k++) {
- if (!seen[c[k].var()] && level[c[k].var()] > 0) {
- out_learnt[j++] = out_learnt[i];
- break;
- }
- }
- }
- }
- max_literals += out_learnt.size();
- out_learnt.shrink(i - j);
- for (uint32_t j = 0; j != analyze_toclear.size(); j++)
- seen[analyze_toclear[j].var()] = 0; // ('seen[]' is now cleared)
-
- if (conf.doMinimLearntMore && out_learnt.size() > 1)
- minimiseLeartFurther(out_learnt, calcNBLevels(out_learnt));
-
- glue = calcNBLevels(out_learnt);
- tot_literals += out_learnt.size();
-
- // Find correct backtrack level:
- //
- if (out_learnt.size() == 1)
- out_btlevel = 0;
- else {
- uint32_t max_i = 1;
- for (uint32_t i = 2; i < out_learnt.size(); i++)
- if (level[out_learnt[i].var()] > level[out_learnt[max_i].var()])
- max_i = i;
- std::swap(out_learnt[max_i], out_learnt[1]);
- out_btlevel = level[out_learnt[1].var()];
- }
-
- if (lastSelectedRestartType == dynamic_restart) {
- #ifdef UPDATE_VAR_ACTIVITY_BASED_ON_GLUE
- for(uint32_t i = 0; i != lastDecisionLevel.size(); i++) {
- PropBy cl = reason[lastDecisionLevel[i]];
- if (cl.isClause() && clauseAllocator.getPointer(cl.getClause())->getGlue() < glue)
- varBumpActivity(lastDecisionLevel[i]);
- }
- lastDecisionLevel.clear();
- #endif
- }
-
- //We can only on-the-fly subsume clauses that are not 2- or 3-long
- //furthermore, we cannot subsume a clause that is marked for deletion
- //due to its high glue value
- if (!conf.doOTFSubsume
- || out_learnt.size() == 1
- || !oldConfl.isClause()
- || oldConfl.getClause()->isXor()
- #ifdef ENABLE_UNWIND_GLUE
- || (conf.doMaxGlueDel && oldConfl.getClause()->getGlue() > conf.maxGlue)
- #endif //ENABLE_UNWIND_GLUE
- || out_learnt.size() >= oldConfl.getClause()->size()) return NULL;
-
- if (!subset(out_learnt, *oldConfl.getClause(), seen)) return NULL;
-
- improvedClauseNo++;
- improvedClauseSize += oldConfl.getClause()->size() - out_learnt.size();
- return oldConfl.getClause();
-}
-
-/**
-@brief Performs on-the-fly self-subsuming resolution
-
-Only uses binary and tertiary clauses already in the watchlists in native
-form to carry out the forward-self-subsuming resolution
-*/
-void Solver::minimiseLeartFurther(vec<Lit>& cl, const uint32_t glue)
-{
- //80 million is kind of a hack. It seems that the longer the solving
- //the slower this operation gets. So, limiting the "time" with total
- //number of conflict literals is maybe a good way of doing this
- bool clDoMinLRec = false;
- if (conf.doCacheOTFSSR && conf.doMinimLMoreRecur) {
- switch(lastSelectedRestartType) {
- case dynamic_restart :
- clDoMinLRec |= glue < 0.6*glueHistory.getAvgAllDouble();
- //NOTE: No "break;" here on purpose
- case static_restart :
- clDoMinLRec |= cl.size() < 0.6*conflSizeHist.getAvgDouble();
- break;
- default :
- assert(false);
- }
- }
-
- if (clDoMinLRec) moreRecurMinLDo++;
- uint64_t thisUpdateTransOTFSSCache = UPDATE_TRANSOTFSSR_CACHE;
- if (tot_literals > 80000000) thisUpdateTransOTFSSCache *= 2;
-
- //To count the "amount of time" invested in doing transitive on-the-fly
- //self-subsuming resolution
- uint32_t moreRecurProp = 0;
-
- for (uint32_t i = 0; i < cl.size(); i++) seen[cl[i].toInt()] = 1;
- for (Lit *l = cl.getData(), *end = cl.getDataEnd(); l != end; l++) {
- if (seen[l->toInt()] == 0) continue;
- Lit lit = *l;
-
- if (clDoMinLRec) {
- if (moreRecurProp > 450
- || (transOTFCache[l->toInt()].conflictLastUpdated != std::numeric_limits<uint64_t>::max()
- && (transOTFCache[l->toInt()].conflictLastUpdated + thisUpdateTransOTFSSCache >= conflicts))
- ) {
- for (vector<Lit>::const_iterator it = transOTFCache[l->toInt()].lits.begin(), end2 = transOTFCache[l->toInt()].lits.end(); it != end2; it++) {
- seen[(~(*it)).toInt()] = 0;
- }
- } else {
- updateTransCache++;
- transMinimAndUpdateCache(lit, moreRecurProp);
- }
- }
-
- //watched is messed: lit is in watched[~lit]
- vec<Watched>& ws = watches[(~lit).toInt()];
- for (vec<Watched>::iterator i = ws.getData(), end = ws.getDataEnd(); i != end; i++) {
- if (i->isBinary()) {
- seen[(~i->getOtherLit()).toInt()] = 0;
- continue;
- }
-
- if (i->isTriClause()) {
- if (seen[(~i->getOtherLit()).toInt()] && seen[i->getOtherLit2().toInt()]) {
- seen[(~i->getOtherLit()).toInt()] = 0;
- }
- if (seen[(~i->getOtherLit2()).toInt()] && seen[i->getOtherLit().toInt()]) {
- seen[(~i->getOtherLit2()).toInt()] = 0;
- }
- continue;
- }
-
- //watches are mostly sorted, so it's more-or-less OK to break
- // if non-bi or non-tri is encountered
- break;
- }
- }
-
- uint32_t removedLits = 0;
- Lit *i = cl.getData();
- Lit *j= i;
- //never remove the 0th literal
- seen[cl[0].toInt()] = 1;
- for (Lit* end = cl.getDataEnd(); i != end; i++) {
- if (seen[i->toInt()]) *j++ = *i;
- else removedLits++;
- seen[i->toInt()] = 0;
- }
- numShrinkedClause += (removedLits > 0);
- numShrinkedClauseLits += removedLits;
- cl.shrink_(i-j);
-
- #ifdef VERBOSE_DEBUG
- std::cout << "c Removed further " << removedLits << " lits" << std::endl;
- #endif
-}
-
-void Solver::transMinimAndUpdateCache(const Lit lit, uint32_t& moreRecurProp)
-{
- vector<Lit>& allAddedToSeen2 = transOTFCache[lit.toInt()].lits;
- allAddedToSeen2.clear();
-
- toRecursiveProp.push(lit);
- while(!toRecursiveProp.empty()) {
- Lit thisLit = toRecursiveProp.top();
- toRecursiveProp.pop();
- //watched is messed: lit is in watched[~lit]
- vec<Watched>& ws = watches[(~thisLit).toInt()];
- moreRecurProp += ws.size() +10;
- for (vec<Watched>::iterator i = ws.getData(), end = ws.getDataEnd(); i != end; i++) {
- if (i->isBinary()) {
- moreRecurProp += 5;
- Lit otherLit = i->getOtherLit();
- //don't do indefinite recursion, and don't remove "a" when doing self-subsuming-resolution with 'a OR b'
- if (seen2[otherLit.toInt()] != 0 || otherLit == ~lit) break;
- seen2[otherLit.toInt()] = 1;
- allAddedToSeen2.push_back(otherLit);
- toRecursiveProp.push(~otherLit);
- } else {
- break;
- }
- }
- }
- assert(toRecursiveProp.empty());
-
- for (vector<Lit>::const_iterator it = allAddedToSeen2.begin(), end = allAddedToSeen2.end(); it != end; it++) {
- seen[(~(*it)).toInt()] = 0;
- seen2[it->toInt()] = 0;
- }
-
- transOTFCache[lit.toInt()].conflictLastUpdated = conflicts;
-}
-
-/**
-@brief Check if 'p' can be removed from a learnt clause
-
-'abstract_levels' is used to abort early if the algorithm is
-visiting literals at levels that cannot be removed later.
-*/
-bool Solver::litRedundant(Lit p, uint32_t abstract_levels)
-{
- analyze_stack.clear();
- analyze_stack.push(p);
- int top = analyze_toclear.size();
- while (analyze_stack.size() > 0) {
- assert(!reason[analyze_stack.last().var()].isNULL());
- PropByFull c(reason[analyze_stack.last().var()], failBinLit, clauseAllocator);
-
- analyze_stack.pop();
-
- for (uint32_t i = 1, size = c.size(); i < size; i++) {
- Lit p = c[i];
- if (!seen[p.var()] && level[p.var()] > 0) {
- if (!reason[p.var()].isNULL() && (abstractLevel(p.var()) & abstract_levels) != 0) {
- seen[p.var()] = 1;
- analyze_stack.push(p);
- analyze_toclear.push(p);
- } else {
- for (uint32_t j = top; j != analyze_toclear.size(); j++)
- seen[analyze_toclear[j].var()] = 0;
- analyze_toclear.shrink(analyze_toclear.size() - top);
- return false;
- }
- }
- }
- }
-
- 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[p.var()] = 1;
-
- for (int32_t i = (int32_t)trail.size()-1; i >= (int32_t)trail_lim[0]; i--) {
- Var x = trail[i].var();
- if (seen[x]) {
- if (reason[x].isNULL()) {
- assert(level[x] > 0);
- out_conflict.push(~trail[i]);
- } else {
- PropByFull c(reason[x], failBinLit, clauseAllocator);
- for (uint32_t j = 1, size = c.size(); j < size; j++)
- if (level[c[j].var()] > 0)
- seen[c[j].var()] = 1;
- }
- seen[x] = 0;
- }
- }
-
- seen[p.var()] = 0;
-}
-
-/*_________________________________________________________________________________________________
-|
-| propagate : [void] -> [Clause*]
-|
-| Description:
-| Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned,
-| otherwise NULL.
-|
-| Post-conditions:
-| * the propagation queue is empty, even if there was a conflict.
-|________________________________________________________________________________________________@*/
-/**
-@brief Propagates a binary clause
-
-Need to be somewhat tricky if the clause indicates that current assignement
-is incorrect (i.e. both literals evaluate to FALSE). If conflict if found,
-sets failBinLit
-*/
-template<bool full>
-inline bool Solver::propBinaryClause(vec<Watched>::iterator &i, const Lit p, PropBy& confl)
-{
- lbool val = value(i->getOtherLit());
- if (val.isUndef()) {
- if (full) uncheckedEnqueue(i->getOtherLit(), PropBy(p));
- else uncheckedEnqueueLight(i->getOtherLit());
- #ifdef DUMP_STATS_FULL
- assert(((i->glue > 0) == i->getLearnt()));
- if (full && i->glue > 0 && !simplifying) {
- std::cout << "Prop by learnt size: " << 2 << std::endl;
- std::cout << "Prop by learnt glue: " << i->glue << std::endl;
- }
- #endif //DUMP_STATS_FULL
- } else if (val == l_False) {
- confl = PropBy(p);
- failBinLit = i->getOtherLit();
- qhead = trail.size();
- #ifdef DUMP_STATS_FULL
- assert(((i->glue > 0) == i->getLearnt()));
- if (full && i->glue > 0 && !simplifying) {
- std::cout << "Confl by learnt size: " << 2 << std::endl;
- std::cout << "Confl by learnt glue: " << i->glue << std::endl;
- }
- #endif //DUMP_STATS_FULL
-
- return false;
- }
-
- return true;
-}
-
-/**
-@brief Propagates a tertiary (3-long) clause
-
-Need to be somewhat tricky if the clause indicates that current assignement
-is incorrect (i.e. all 3 literals evaluate to FALSE). If conflict is found,
-sets failBinLit
-*/
-template<bool full>
-inline bool Solver::propTriClause(vec<Watched>::iterator &i, const Lit p, PropBy& confl)
-{
- lbool val = value(i->getOtherLit());
- if (val == l_True) return true;
-
- lbool val2 = value(i->getOtherLit2());
- if (val.isUndef() && val2 == l_False) {
- if (full) uncheckedEnqueue(i->getOtherLit(), PropBy(p, i->getOtherLit2()));
- else uncheckedEnqueueLight(i->getOtherLit());
- #ifdef DUMP_STATS_FULL
- assert(conf.isPlain);
- if (full && i->glue > 0 && !simplifying) {
- std::cout << "Prop by learnt size: " << 3 << std::endl;
- std::cout << "Prop by learnt glue: " << i->glue << std::endl;
- }
- #endif //DUMP_STATS_FULL
- } else if (val == l_False && val2.isUndef()) {
- if (full) uncheckedEnqueue(i->getOtherLit2(), PropBy(p, i->getOtherLit()));
- else uncheckedEnqueueLight(i->getOtherLit2());
- #ifdef DUMP_STATS_FULL
- assert(conf.isPlain);
- if (full && i->glue > 0 && !simplifying) {
- std::cout << "Prop by learnt size: " << 3 << std::endl;
- std::cout << "Prop by learnt glue: " << i->glue << std::endl;
- }
- #endif //DUMP_STATS_FULL
- } else if (val == l_False && val2 == l_False) {
- confl = PropBy(p, i->getOtherLit2());
- failBinLit = i->getOtherLit();
- qhead = trail.size();
- #ifdef DUMP_STATS_FULL
- assert(conf.isPlain);
- if (full && i->glue > 0 && !simplifying) {
- std::cout << "Confl by learnt size: " << 3 << std::endl;
- std::cout << "Confl by learnt glue: " << i->glue << std::endl;
- }
- #endif //DUMP_STATS_FULL
-
- return false;
- }
-
- return true;
-}
-
-/**
-@brief Propagates a tertiary (3-long) clause
-
-We have blocked literals in this case in the watchlist. That must be checked
-and updated.
-*/
-template<bool full>
-inline bool Solver::propNormalClause(vec<Watched>::iterator &i, vec<Watched>::iterator &j, const Lit p, PropBy& confl, const bool update)
-{
- if (value(i->getBlockedLit()).getBool()) {
- // Clause is sat
- *j++ = *i;
- return true;
- }
- const uint32_t offset = i->getNormOffset();
- Clause& c = *clauseAllocator.getPointer(offset);
-
- // Make sure the false literal is data[1]:
- if (c[0] == ~p) {
- std::swap(c[0], c[1]);
- }
-
- assert(c[1] == ~p);
-
- // If 0th watch is true, then clause is already satisfied.
- if (value(c[0]).getBool()) {
- *j = Watched(offset, c[0]);
- j++;
- return true;
- }
- // Look for new watch:
- for (Lit *k = c.getData() + 2, *end2 = c.getDataEnd(); k != end2; k++) {
- if (value(*k) != l_False) {
- c[1] = *k;
- *k = ~p;
- watches[(~c[1]).toInt()].push(Watched(offset, c[0]));
- return true;
- }
- }
-
- // Did not find watch -- clause is unit under assignment:
- *j++ = *i;
- if (value(c[0]) == l_False) {
- #ifdef DUMP_STATS_FULL
- if (full && c.learnt() && !simplifying) {
- std::cout << "Confl by learnt size: " << c.size() << std::endl;
- std::cout << "Confl by learnt glue: " << c.getGlue() << std::endl;
- assert(!conf.isPlain || c.getGlue() > 1);
- }
- #endif //DUMP_STATS_FULL
- confl = PropBy(offset);
- qhead = trail.size();
- return false;
- } else {
- #ifdef DUMP_STATS_FULL
- if (full && c.learnt() && !simplifying) {
- std::cout << "Prop by learnt size: " << c.size() << std::endl;
- std::cout << "Prop by learnt glue: " << c.getGlue() << std::endl;
- assert(!conf.isPlain || c.getGlue() > 1);
- }
- #endif //DUMP_STATS_FULL
-
- if (full) uncheckedEnqueue(c[0], offset);
- else uncheckedEnqueueLight(c[0]);
- #ifdef DYNAMICALLY_UPDATE_GLUE
- if (update && full && c.learnt() && c.getGlue() > 2) {
- uint32_t glue = calcNBLevels(c);
- if (glue+1 < c.getGlue()) {
- //c.setGlue(std::min(nbLevels, MAX_THEORETICAL_GLUE);
- c.setGlue(glue);
- }
- }
- #endif
- }
-
- return true;
-}
-
-/**
-@brief Propagates a tertiary (3-long) clause
-
-Strangely enough, we need to have 4 literals in the wathclists:
-for the first two varialbles, BOTH negations (v and ~v). This means quite some
-pain, since we need to remove v when moving ~v and vica-versa. However, it means
-better memory-accesses since the watchlist is already in the memory...
-
-\todo maybe not worth it, and a variable-based watchlist should be used
-*/
-template<bool full>
-inline bool Solver::propXorClause(vec<Watched>::iterator &i, vec<Watched>::iterator &j, const Lit p, PropBy& confl)
-{
- ClauseOffset offset = i->getXorOffset();
- XorClause& c = *(XorClause*)clauseAllocator.getPointer(offset);
-
- // Make sure the false literal is data[1]:
- if (c[0].var() == p.var()) {
- Lit tmp(c[0]);
- c[0] = c[1];
- c[1] = tmp;
- }
- assert(c[1].var() == p.var());
-
- bool final = c.xorEqualFalse();
- for (uint32_t k = 0, size = c.size(); k != size; k++ ) {
- const lbool& val = assigns[c[k].var()];
- if (val.isUndef() && k >= 2) {
- Lit tmp(c[1]);
- c[1] = c[k];
- c[k] = tmp;
- removeWXCl(watches[(~p).toInt()], offset);
- watches[Lit(c[1].var(), false).toInt()].push(offset);
- watches[Lit(c[1].var(), true).toInt()].push(offset);
- return true;
- }
-
- c[k] = c[k].unsign() ^ val.getBool();
- final ^= val.getBool();
- }
-
- // Did not find watch -- clause is unit under assignment:
- *j++ = *i;
-
- if (assigns[c[0].var()].isUndef()) {
- c[0] = c[0].unsign()^final;
- if (full) uncheckedEnqueue(c[0], offset);
- else uncheckedEnqueueLight(c[0]);
- } else if (!final) {
- confl = PropBy(offset);
- qhead = trail.size();
- return false;
- } else {
- Lit tmp(c[0]);
- c[0] = c[1];
- c[1] = tmp;
- }
-
- return true;
-}
-
-/**
-@brief Does the propagation
-
-Basically, it goes through the watchlists recursively, and calls the appropirate
-propagaton function
-*/
-template<bool full>
-PropBy Solver::propagate(const bool update)
-{
- PropBy confl;
- uint32_t num_props = 0;
-
- #ifdef VERBOSE_DEBUG
- cout << "Propagation started" << endl;
- #endif
-
- while (qhead < trail.size()) {
- Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate.
- vec<Watched>& ws = watches[p.toInt()];
- num_props += ws.size()/2 + 2;
-
- #ifdef VERBOSE_DEBUG
- cout << "Propagating lit " << p << endl;
- cout << "ws origSize: "<< ws.size() << endl;
- #endif
-
- vec<Watched>::iterator i = ws.getData();
- vec<Watched>::iterator j = i;
-
- vec<Watched>::iterator end = ws.getDataEnd();
- for (; i != end; i++) {
- if (i->isBinary()) {
- *j++ = *i;
- if (!propBinaryClause<full>(i, p, confl)) break;
- else continue;
- } //end BINARY
-
- if (i->isTriClause()) {
- *j++ = *i;
- if (!propTriClause<full>(i, p, confl)) break;
- else continue;
- } //end TRICLAUSE
-
- if (i->isClause()) {
- num_props += 4;
- if (!propNormalClause<full>(i, j, p, confl, update)) break;
- else continue;
- } //end CLAUSE
-
- if (i->isXorClause()) {
- num_props += 10;
- if (!propXorClause<full>(i, j, p, confl)) break;
- else continue;
- } //end XORCLAUSE
- }
- if (i != end) {
- i++;
- //copy remaining watches
- vec<Watched>::iterator j2 = i;
- vec<Watched>::iterator i2 = j;
- for(i2 = i, j2 = j; i2 != end; i2++) {
- *j2++ = *i2;
- }
- //memmove(j, i, sizeof(Watched)*(end-i));
- }
- //assert(i >= j);
- ws.shrink_(i-j);
- }
- propagations += num_props;
- simpDB_props -= num_props;
-
- #ifdef VERBOSE_DEBUG
- cout << "Propagation ended." << endl;
- #endif
-
- return confl;
-}
-template PropBy Solver::propagate<true>(const bool update);
-template PropBy Solver::propagate<false>(const bool update);
-
-PropBy Solver::propagateBin(vec<Lit>& uselessBin)
-{
- #ifdef DEBUG_USELESS_LEARNT_BIN_REMOVAL
- assert(uselessBin.empty());
- #endif
-
- while (qhead < trail.size()) {
- Lit p = trail[qhead++];
-
- //setting up binPropData
- uint32_t lev = binPropData[p.var()].lev;
- Lit lev1Ancestor;
- switch (lev) {
- case 0 :
- lev1Ancestor = lit_Undef;
- break;
- case 1:
- lev1Ancestor = p;
- break;
- default:
- lev1Ancestor = binPropData[p.var()].lev1Ancestor;
- }
- lev++;
- const bool learntLeadHere = binPropData[p.var()].learntLeadHere;
- bool& hasChildren = binPropData[p.var()].hasChildren;
- hasChildren = false;
-
- //std::cout << "lev: " << lev << " ~p: " << ~p << std::endl;
- const vec<Watched> & ws = watches[p.toInt()];
- propagations += 2;
- for(vec<Watched>::const_iterator k = ws.getData(), end = ws.getDataEnd(); k != end; k++) {
- hasChildren = true;
- if (!k->isBinary()) continue;
-
- //std::cout << (~p) << ", " << k->getOtherLit() << " learnt: " << k->getLearnt() << std::endl;
- lbool val = value(k->getOtherLit());
- if (val.isUndef()) {
- uncheckedEnqueueLight2(k->getOtherLit(), lev, lev1Ancestor, learntLeadHere || k->getLearnt());
- } else if (val == l_False) {
- return PropBy(p);
- } else {
- assert(val == l_True);
- Lit lit2 = k->getOtherLit();
- if (lev > 1
- && level[lit2.var()] != 0
- && binPropData[lit2.var()].lev == 1
- && lev1Ancestor != lit2) {
- //Was propagated at level 1, and again here, original level 1 binary clause is useless
- binPropData[lit2.var()].lev = lev;
- binPropData[lit2.var()].lev1Ancestor = lev1Ancestor;
- binPropData[lit2.var()].learntLeadHere = learntLeadHere || k->getLearnt();
- uselessBin.push(lit2);
- }
- }
- }
- }
- //std::cout << " -----------" << std::endl;
-
- return PropBy();
-}
-
-/**
-@brief Only propagates binary clauses
-
-This is used in special algorithms outside the main Solver class
-*/
-PropBy Solver::propagateNonLearntBin()
-{
- multiLevelProp = false;
- uint32_t origQhead = qhead + 1;
-
- while (qhead < trail.size()) {
- Lit p = trail[qhead++];
- const vec<Watched> & ws = watches[p.toInt()];
- propagations += ws.size()/2 + 2;
- for(vec<Watched>::const_iterator k = ws.getData(), end = ws.getDataEnd(); k != end; k++) {
- if (!k->isNonLearntBinary()) break;
-
- lbool val = value(k->getOtherLit());
- if (val.isUndef()) {
- if (qhead != origQhead) multiLevelProp = true;
- uncheckedEnqueueLight(k->getOtherLit());
- } else if (val == l_False) {
- return PropBy(p);
- }
- }
- }
-
- return PropBy();
-}
-
-/**
-@brief Propagate recursively on non-learnt binaries, but do not propagate exceptLit if we reach it
-*/
-bool Solver::propagateBinExcept(const Lit exceptLit)
-{
- while (qhead < trail.size()) {
- Lit p = trail[qhead++];
- const vec<Watched> & ws = watches[p.toInt()];
- propagations += ws.size()/2 + 2;
- for(vec<Watched>::const_iterator i = ws.getData(), end = ws.getDataEnd(); i != end; i++) {
- if (!i->isNonLearntBinary()) break;
-
- lbool val = value(i->getOtherLit());
- if (val.isUndef() && i->getOtherLit() != exceptLit) {
- uncheckedEnqueueLight(i->getOtherLit());
- } else if (val == l_False) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-/**
-@brief Propagate only for one hop(=non-recursively) on non-learnt bins
-*/
-bool Solver::propagateBinOneLevel()
-{
- Lit p = trail[qhead];
- const vec<Watched> & ws = watches[p.toInt()];
- propagations += ws.size()/2 + 2;
- for(vec<Watched>::const_iterator i = ws.getData(), end = ws.getDataEnd(); i != end; i++) {
- if (!i->isNonLearntBinary()) break;
-
- lbool val = value(i->getOtherLit());
- if (val.isUndef()) {
- uncheckedEnqueueLight(i->getOtherLit());
- } else if (val == l_False) {
- return false;
- }
- }
-
- return true;
-}
-
-struct LevelSorter
-{
- LevelSorter(const vec<int32_t>& _level) :
- level(_level)
- {}
-
- bool operator()(const Lit lit1, const Lit lit2) const {
- return level[lit1.var()] < level[lit2.var()];
- }
-
- const vec<int32_t>& level;
-};
-
-/**
-@brief Calculates the glue of a clause
-
-Used to calculate the Glue of a new clause, or to update the glue of an
-existing clause. Only used if the glue-based activity heuristic is enabled,
-i.e. if we are in GLUCOSE mode (not MiniSat mode)
-*/
-template<class T>
-inline uint32_t Solver::calcNBLevels(const T& ps)
-{
- uint32_t nbLevels = 0;
- for(const Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) {
- int32_t lev = level[l->var()];
- if (!seen[lev]) {
- nbLevels++;
- seen[lev] = 1;
- }
- }
- for(const Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) {
- int32_t lev = level[l->var()];
- seen[lev] = 0;
- }
- return nbLevels;
-}
-
-/*_________________________________________________________________________________________________
-|
-| reduceDB : () -> [void]
-|
-| Description:
-| Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked
-| clauses are clauses that are reason to some assignment. Binary clauses are never removed.
-|________________________________________________________________________________________________@*/
-bool reduceDB_ltMiniSat::operator () (const Clause* x, const Clause* y) {
- const uint32_t xsize = x->size();
- const uint32_t ysize = y->size();
-
- assert(xsize > 2 && ysize > 2);
- if (x->getMiniSatAct() == y->getMiniSatAct())
- return xsize > ysize;
- else return x->getMiniSatAct() < y->getMiniSatAct();
-}
-
-bool reduceDB_ltGlucose::operator () (const Clause* x, const Clause* y) {
- const uint32_t xsize = x->size();
- const uint32_t ysize = y->size();
-
- assert(xsize > 2 && ysize > 2);
- if (x->getGlue() > y->getGlue()) return 1;
- if (x->getGlue() < y->getGlue()) return 0;
- return xsize > ysize;
-}
-
-/**
-@brief Removes learnt clauses that have been found not to be too good
-
-Either based on glue or MiniSat-style learnt clause activities, the clauses are
-sorted and then removed
-*/
-void Solver::reduceDB()
-{
- uint32_t i, j;
-
- nbReduceDB++;
- if (lastSelectedRestartType == dynamic_restart)
- std::sort(learnts.getData(), learnts.getDataEnd(), reduceDB_ltGlucose());
- else
- std::sort(learnts.getData(), learnts.getDataEnd(), reduceDB_ltMiniSat());
-
- #ifdef VERBOSE_DEBUG
- std::cout << "Cleaning clauses" << std::endl;
- for (uint32_t i = 0; i != learnts.size(); i++) {
- std::cout << "activity:" << learnts[i]->getGlue()
- << " \toldActivity:" << learnts[i]->getMiniSatAct()
- << " \tsize:" << learnts[i]->size() << std::endl;
- }
- #endif
-
-
- const uint32_t removeNum = (double)learnts.size() * (double)RATIOREMOVECLAUSES;
- uint32_t totalNumRemoved = 0;
- uint32_t totalNumNonRemoved = 0;
- uint64_t totalGlueOfRemoved = 0;
- uint64_t totalSizeOfRemoved = 0;
- uint64_t totalGlueOfNonRemoved = 0;
- uint64_t totalSizeOfNonRemoved = 0;
- for (i = j = 0; i != removeNum; i++){
- if (i+1 < removeNum) __builtin_prefetch(learnts[i+1]);
- assert(learnts[i]->size() > 2);
- if (!locked(*learnts[i])
- && (lastSelectedRestartType == static_restart || learnts[i]->getGlue() > 2)
- && learnts[i]->size() > 3) { //we cannot update activity of 3-longs because of wathclists
-
- totalGlueOfRemoved += learnts[i]->getGlue();
- totalSizeOfRemoved += learnts[i]->size();
- totalNumRemoved++;
- removeClause(*learnts[i]);
- } else {
- totalGlueOfNonRemoved += learnts[i]->getGlue();
- totalSizeOfNonRemoved += learnts[i]->size();
- totalNumNonRemoved++;
- learnts[j++] = learnts[i];
- }
- }
- for (; i < learnts.size(); i++) {
- totalGlueOfNonRemoved += learnts[i]->getGlue();
- totalSizeOfNonRemoved += learnts[i]->size();
- totalNumNonRemoved++;
- learnts[j++] = learnts[i];
- }
- learnts.shrink_(i - j);
-
- if (conf.verbosity >= 3) {
- std::cout << "c rem-learnts " << std::setw(6) << totalNumRemoved
- << " avgGlue "
- << std::fixed << std::setw(5) << std::setprecision(2) << ((double)totalGlueOfRemoved/(double)totalNumRemoved)
- << " avgSize "
- << std::fixed << std::setw(6) << std::setprecision(2) << ((double)totalSizeOfRemoved/(double)totalNumRemoved)
- << " || remain " << std::setw(6) << totalNumNonRemoved
- << " avgGlue "
- << std::fixed << std::setw(5) << std::setprecision(2) << ((double)totalGlueOfNonRemoved/(double)totalNumNonRemoved)
- << " avgSize "
- << std::fixed << std::setw(6) << std::setprecision(2) << ((double)totalSizeOfNonRemoved/(double)totalNumNonRemoved)
- << std::endl;
- }
-
- clauseAllocator.consolidate(this);
-}
-
-inline int64_t abs64(int64_t a)
-{
- if (a < 0) return -a;
- return a;
-}
-
-/**
-@brief Simplify the clause database according to the current top-level assigment.
-
-We remove satisfied clauses, clean clauses from assigned literals, find
-binary xor-clauses and replace variables with one another. Heuristics are
-used to check if we need to find binary xor clauses or not.
-*/
-bool Solver::simplify()
-{
- testAllClauseAttach();
- assert(decisionLevel() == 0);
-
- if (!ok || !propagate<false>().isNULL()) {
- ok = false;
- return false;
- }
-
- if (simpDB_props > 0) {
- return true;
- }
- double myTime = cpuTime();
-
- double slowdown = (100000.0/((double)numBins * 30000.0/((double)order_heap.size())));
- slowdown = std::min(1.5, slowdown);
- slowdown = std::max(0.01, slowdown);
-
- double speedup = 200000000.0/(double)(propagations-lastSearchForBinaryXor);
- speedup = std::min(3.5, speedup);
- speedup = std::max(0.2, speedup);
-
- /*std::cout << "new:" << nbBin - lastNbBin + becameBinary << std::endl;
- std::cout << "left:" << ((double)(nbBin - lastNbBin + becameBinary)/BINARY_TO_XOR_APPROX) * slowdown << std::endl;
- std::cout << "right:" << (double)order_heap.size() * PERCENTAGEPERFORMREPLACE * speedup << std::endl;*/
-
- if (conf.doFindEqLits && conf.doRegFindEqLits &&
- (((double)abs64((int64_t)numNewBin - (int64_t)lastNbBin)/BINARY_TO_XOR_APPROX) * slowdown) >
- ((double)order_heap.size() * PERCENTAGEPERFORMREPLACE * speedup)) {
- lastSearchForBinaryXor = propagations;
-
- clauseCleaner->cleanClauses(clauses, ClauseCleaner::clauses);
- clauseCleaner->cleanClauses(learnts, ClauseCleaner::learnts);
- clauseCleaner->removeSatisfiedBins();
- if (!ok) return false;
-
- if (!sCCFinder->find2LongXors()) return false;
-
- lastNbBin = numNewBin;
- }
-
- // Remove satisfied clauses:
- clauseCleaner->removeAndCleanAll();
- if (!ok) return false;
-
- if (conf.doReplace && !varReplacer->performReplace())
- return false;
-
- // Remove fixed variables from the variable heap:
- order_heap.filter(VarFilter(*this));
-
- #ifdef USE_GAUSS
- for (vector<Gaussian*>::iterator gauss = gauss_matrixes.begin(), end = gauss_matrixes.end(); gauss != end; gauss++) {
- if (!(*gauss)->full_init()) return false;
- }
- #endif //USE_GAUSS
-
- simpDB_assigns = nAssigns();
- simpDB_props = std::min((uint64_t)80000000, 4*clauses_literals + 4*learnts_literals); //at most 6 sec wait
- simpDB_props = std::max((int64_t)30000000, simpDB_props); //at least 2 sec wait
- totalSimplifyTime += cpuTime() - myTime;
-
- testAllClauseAttach();
- return true;
-}
-
-/**
-@brief Search for a model
-
-Limits: must be below the specified number of conflicts and must keep the
-number of learnt clauses below the provided limit
-
-Use negative value for 'nof_conflicts' or 'nof_learnts' to indicate infinity.
-
-Output: 'l_True' if a partial assigment that is consistent with respect to the
-clauseset is found. If all variables are decision variables, this means
-that the clause set is satisfiable. 'l_False' if the clause set is
-unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached.
-*/
-lbool Solver::search(const uint64_t nof_conflicts, const uint64_t nof_conflicts_fullrestart, const bool update)
-{
- assert(ok);
- uint64_t conflictC = 0;
- vec<Lit> learnt_clause;
- llbool ret;
-
- if (!simplifying && update) {
- starts++;
- if (restartType == static_restart) staticStarts++;
- else dynStarts++;
- }
- glueHistory.fastclear();
-
- #ifdef USE_GAUSS
- for (vector<Gaussian*>::iterator gauss = gauss_matrixes.begin(), end = gauss_matrixes.end(); gauss != end; gauss++) {
- if (!(*gauss)->full_init())
- return l_False;
- }
- #endif //USE_GAUSS
-
- testAllClauseAttach();
- findAllAttach();
- #ifdef VERBOSE_DEBUG
- std::cout << "c started Solver::search()" << std::endl;
- //printAllClauses();
- #endif //VERBOSE_DEBUG
- for (;;) {
- assert(ok);
- PropBy confl = propagate<true>(update);
- #ifdef VERBOSE_DEBUG
- std::cout << "c Solver::search() has finished propagation" << std::endl;
- //printAllClauses();
- #endif //VERBOSE_DEBUG
-
- if (conflicts > conf.maxConfl) {
- if (conf.verbosity >= 0) {
- std::cout << "c Interrupting: limit on number of conflicts, "
- << conf.maxConfl
- << " reached! " << std::endl;
- }
- needToInterrupt = true;
- return l_Undef;
- }
-
- if (!confl.isNULL()) {
- ret = handle_conflict(learnt_clause, confl, conflictC, update);
- if (ret != l_Nothing) return ret;
- } else {
- #ifdef USE_GAUSS
- bool at_least_one_continue = false;
- for (vector<Gaussian*>::iterator gauss = gauss_matrixes.begin(), end= gauss_matrixes.end(); gauss != end; gauss++) {
- ret = (*gauss)->find_truths(learnt_clause, conflictC);
- if (ret == l_Continue) at_least_one_continue = true;
- else if (ret != l_Nothing) return ret;
- }
- if (at_least_one_continue) continue;
- #endif //USE_GAUSS
-
- assert(ok);
- if (conf.doCacheOTFSSR && decisionLevel() == 1) saveOTFData();
- ret = new_decision(nof_conflicts, nof_conflicts_fullrestart, conflictC);
- if (ret != l_Nothing) return ret;
- }
- }
-}
-
-/**
-@brief Picks a new decision variable to branch on
-
-@returns l_Undef if it should restart instead. l_False if it reached UNSAT
- (through simplification)
-*/
-llbool Solver::new_decision(const uint64_t nof_conflicts, const uint64_t nof_conflicts_fullrestart, const uint64_t conflictC)
-{
-
- if (conflicts >= nof_conflicts_fullrestart || needToInterrupt) {
- cancelUntil(0);
- return l_Undef;
- }
-
- // Reached bound on number of conflicts?
- switch (restartType) {
- case dynamic_restart:
- if (glueHistory.isvalid() &&
- 0.95*glueHistory.getAvgDouble() > glueHistory.getAvgAllDouble()) {
-
- #ifdef DEBUG_DYNAMIC_RESTART
- if (glueHistory.isvalid()) {
- std::cout << "glueHistory.getavg():" << glueHistory.getavg() <<std::endl;
- std::cout << "totalSumOfGlue:" << totalSumOfGlue << std::endl;
- std::cout << "conflicts:" << conflicts<< std::endl;
- std::cout << "compTotSumGlue:" << compTotSumGlue << std::endl;
- std::cout << "conflicts-compTotSumGlue:" << conflicts-compTotSumGlue<< std::endl;
- }
- #endif
-
- cancelUntil(0);
- return l_Undef;
- }
- break;
- case static_restart:
- if (conflictC >= nof_conflicts) {
- cancelUntil(0);
- return l_Undef;
- }
- break;
- case auto_restart:
- assert(false);
- break;
- }
-
- // Simplify the set of problem clauses:
- if (decisionLevel() == 0) {
- if (!dataSync->syncData()) return l_False;
- if (!simplify()) return l_False;
- }
-
- // Reduce the set of learnt clauses:
- if (conflicts >= numCleanedLearnts * nbClBeforeRed + nbCompensateSubsumer) {
- numCleanedLearnts ++;
- reduceDB();
- nbClBeforeRed += 500;
- }
-
- Lit next = lit_Undef;
- while (decisionLevel() < assumptions.size()) {
- // Perform user provided assumption:
- Lit p = assumptions[decisionLevel()];
- if (value(p) == l_True) {
- // Dummy decision level:
- newDecisionLevel();
- } else if (value(p) == l_False) {
- analyzeFinal(~p, conflict);
- return l_False;
- } else {
- next = p;
- break;
- }
- }
-
- if (next == lit_Undef) {
- // New variable decision:
- decisions++;
- next = pickBranchLit();
-
- if (next == lit_Undef)
- return l_True;
- }
-
- // Increase decision level and enqueue 'next'
- assert(value(next) == l_Undef);
- newDecisionLevel();
- uncheckedEnqueue(next);
-
- return l_Nothing;
-}
-
-/**
-@brief Handles a conflict that we reached through propagation
-
-Handles on-the-fly subsumption: the OTF subsumption check is done in
-conflict analysis, but this is the code that actually replaces the original
-clause with that of the shorter one
-@returns l_False if UNSAT
-*/
-llbool Solver::handle_conflict(vec<Lit>& learnt_clause, PropBy confl, uint64_t& conflictC, const bool update)
-{
- #ifdef VERBOSE_DEBUG
- cout << "Handling conflict: ";
- for (uint32_t i = 0; i < learnt_clause.size(); i++)
- cout << learnt_clause[i].var()+1 << ",";
- cout << endl;
- #endif
-
- int backtrack_level;
- uint32_t glue;
-
- conflicts++;
- conflictC++;
- if (decisionLevel() == 0)
- return l_False;
- learnt_clause.clear();
- Clause* c = analyze(confl, learnt_clause, backtrack_level, glue, update);
- if (update) {
- avgBranchDepth.push(decisionLevel());
- if (restartType == dynamic_restart) glueHistory.push(glue);
- conflSizeHist.push(learnt_clause.size());
- }
- cancelUntil(backtrack_level);
- #ifdef DUMP_STATS
- std::cout << "Learnt clause: " << learnt_clause
- << " glue: " << glue
- << " declevel: " << decisionLevel()
- << " traillen: " << trail.size()
- << " abst: " << calcAbstraction(learnt_clause)
- << std::endl;
- assert(learnt_clause.size() == 1 || glue > 1);
- #endif //#ifdef DUMP_STATS
-
- #ifdef VERBOSE_DEBUG
- cout << "Learning:";
- for (uint32_t i = 0; i < learnt_clause.size(); i++) printLit(learnt_clause[i]), cout << " ";
- cout << endl;
- cout << "reverting var " << learnt_clause[0].var()+1 << " to " << !learnt_clause[0].sign() << endl;
- #endif
-
- assert(value(learnt_clause[0]) == l_Undef);
- //Unitary learnt
- if (learnt_clause.size() == 1) {
- uncheckedEnqueue(learnt_clause[0]);
- assert(backtrack_level == 0 && "Unit clause learnt, so must cancel until level 0, right?");
-
- #ifdef VERBOSE_DEBUG
- cout << "Unit clause learnt." << endl;
- #endif
- //Normal learnt
- } else {
- if (learnt_clause.size() == 2) {
- attachBinClause(learnt_clause[0], learnt_clause[1], true);
- numNewBin++;
- dataSync->signalNewBinClause(learnt_clause);
- uncheckedEnqueue(learnt_clause[0], PropBy(learnt_clause[1]));
- goto end;
- }
-
- if (learnt_clause.size() > 3) {
- std::sort(learnt_clause.getData()+1, learnt_clause.getDataEnd(), PolaritySorter(polarity));
- }
- if (c) { //On-the-fly subsumption
- uint32_t origSize = c->size();
- detachClause(*c);
- for (uint32_t i = 0; i != learnt_clause.size(); i++)
- (*c)[i] = learnt_clause[i];
- c->shrink(origSize - learnt_clause.size());
- if (c->learnt() && c->getGlue() > glue)
- c->setGlue(glue); // LS
- attachClause(*c);
- uncheckedEnqueue(learnt_clause[0], clauseAllocator.getOffset(c));
- } else { //no on-the-fly subsumption
- c = clauseAllocator.Clause_new(learnt_clause, true);
- #ifdef ENABLE_UNWIND_GLUE
- if (conf.doMaxGlueDel && glue > conf.maxGlue) {
- nbClOverMaxGlue++;
- nbCompensateSubsumer++;
- unWindGlue[learnt_clause[0].var()] = c;
- #ifdef UNWINDING_DEBUG
- std::cout << "unwind, var:" << learnt_clause[0].var() << std::endl;
- c->plainPrint();
- #endif //VERBOSE_DEBUG
- } else {
- #endif //ENABLE_UNWIND_GLUE
- learnts.push(c);
- #ifdef ENABLE_UNWIND_GLUE
- }
- #endif //ENABLE_UNWIND_GLUE
- c->setGlue(std::min(glue, MAX_THEORETICAL_GLUE));
- attachClause(*c);
- uncheckedEnqueue(learnt_clause[0], clauseAllocator.getOffset(c));
- }
- end:;
- }
-
- varDecayActivity();
- if (update && restartType == static_restart) claDecayActivity();
-
- return l_Nothing;
-}
-
-/**
-@brief After a full restart, determines which restar type to use
-
-Uses class RestartTypeChooser to do the heavy-lifting
-*/
-bool Solver::chooseRestartType(const uint32_t& lastFullRestart)
-{
- uint32_t relativeStart = starts - lastFullRestart;
-
- if (relativeStart > RESTART_TYPE_DECIDER_FROM && relativeStart < RESTART_TYPE_DECIDER_UNTIL) {
- if (conf.fixRestartType == auto_restart)
- restartTypeChooser->addInfo();
-
- if (relativeStart == (RESTART_TYPE_DECIDER_UNTIL-1)) {
- RestartType tmp;
- if (conf.fixRestartType == auto_restart)
- tmp = restartTypeChooser->choose();
- else
- tmp = conf.fixRestartType;
-
- if (tmp == dynamic_restart) {
- glueHistory.fastclear();
- if (conf.verbosity >= 3)
- std::cout << "c Decided on dynamic restart strategy"
- << std::endl;
- } else {
- if (conf.verbosity >= 1)
- std::cout << "c Decided on static restart strategy"
- << std::endl;
-
- if (!matrixFinder->findMatrixes()) return false;
- }
- lastSelectedRestartType = tmp;
- restartType = tmp;
- restartTypeChooser->reset();
- }
- }
-
- return true;
-}
-
-inline void Solver::setDefaultRestartType()
-{
- if (conf.fixRestartType != auto_restart) restartType = conf.fixRestartType;
- else restartType = static_restart;
-
- glueHistory.clear();
- glueHistory.initSize(MIN_GLUE_RESTART);
- conflSizeHist.clear();
- conflSizeHist.initSize(1000);
-
- lastSelectedRestartType = restartType;
-}
-
-/**
-@brief The function that brings together almost all CNF-simplifications
-
-It burst-searches for given number of conflicts, then it tries all sorts of
-things like variable elimination, subsumption, failed literal probing, etc.
-to try to simplifcy the problem at hand.
-*/
-lbool Solver::simplifyProblem(const uint32_t numConfls)
-{
- testAllClauseAttach();
- bool gaussWasCleared = clearGaussMatrixes();
-
- StateSaver savedState(*this);;
-
- #ifdef BURST_SEARCH
- if (conf.verbosity >= 3)
- std::cout << "c " << std::setw(24) << " "
- << "Simplifying problem for " << std::setw(8) << numConfls << " confls"
- << std::endl;
- conf.random_var_freq = 1;
- simplifying = true;
- uint64_t origConflicts = conflicts;
- #endif //BURST_SEARCH
-
- lbool status = l_Undef;
-
- #ifdef BURST_SEARCH
- restartType = static_restart;
-
- printRestartStat("S");
- while(status == l_Undef && conflicts-origConflicts < numConfls && needToInterrupt == false) {
- status = search(100, std::numeric_limits<uint64_t>::max(), false);
- }
- if (needToInterrupt) return l_Undef;
- printRestartStat("S");
- if (status != l_Undef) goto end;
- #endif //BURST_SEARCH
-
- if (conf.doXorSubsumption && !xorSubsumer->simplifyBySubsumption()) goto end;
-
- if (conf.doFailedLit && conf.doCacheOTFSSR) {
- BothCache both(*this);
- if (!both.tryBoth()) goto end;
- }
- if (conf.doCacheOTFSSR) cleanCache();
- if (conf.doClausVivif && !clauseVivifier->vivifyClauses()) goto end;
-
- if (conf.doCacheOTFSSRSet && order_heap.size() < 200000) {
- if (conf.doCacheOTFSSR == false && conf.verbosity > 0) {
- std::cout << "c turning cache ON because the number of active variables is lower now" << std::endl;
- }
- conf.doCacheOTFSSR = true;
- }
- if (conf.doFailedLit && !failedLitSearcher->search()) goto end;
-
- if (conf.doSatELite && !subsumer->simplifyBySubsumption()) goto end;
-
- /*if (findNormalXors && xorclauses.size() > 200 && clauses.size() < MAX_CLAUSENUM_XORFIND/8) {
- XorFinder xorFinder(*this, clauses, ClauseCleaner::clauses);
- if (!xorFinder.doNoPart(3, 7)) {
- status = l_False;
- goto end;
- }
- } else*/ if (xorclauses.size() <= 200 && xorclauses.size() > 0 && nClauses() > 10000) {
- XorFinder x(*this, clauses);
- x.addAllXorAsNorm();
- }
-
- if (conf.doClausVivif && !clauseVivifier->vivifyClauses()) goto end;
-
- //addSymmBreakClauses();
-
- if (conf.doSortWatched) sortWatched();
- if (conf.doCacheOTFSSR && conf.doCalcReach) calcReachability();
-
-end:
- #ifdef BURST_SEARCH
- if (conf.verbosity >= 3)
- std::cout << "c Simplifying finished" << std::endl;
- #endif //#ifdef BURST_SEARCH
-
- savedState.restore();
- simplifying = false;
-
- if (status == l_Undef && ok && gaussWasCleared && !matrixFinder->findMatrixes())
- status = l_False;
-
- testAllClauseAttach();
-
- if (!ok) return l_False;
- return status;
-}
-
-/**
-@brief Should we perform a full restart?
-
-If so, we also do the things to be done if the full restart is effected.
-*/
-bool Solver::checkFullRestart(uint64_t& nof_conflicts, uint64_t& nof_conflicts_fullrestart, uint32_t& lastFullRestart)
-{
- if (nof_conflicts_fullrestart > 0 && conflicts >= nof_conflicts_fullrestart) {
- #ifdef USE_GAUSS
- clearGaussMatrixes();
- #endif //USE_GAUSS
- nof_conflicts = conf.restart_first + (double)conf.restart_first*conf.restart_inc;
- nof_conflicts_fullrestart = (double)nof_conflicts_fullrestart * FULLRESTART_MULTIPLIER_MULTIPLIER;
- restartType = static_restart;
- lastFullRestart = starts;
-
- if (conf.verbosity >= 3)
- std::cout << "c Fully restarting" << std::endl;
- printRestartStat("F");
-
- /*if (findNormalXors && clauses.size() < MAX_CLAUSENUM_XORFIND) {
- XorFinder xorFinder(this, clauses, ClauseCleaner::clauses);
- if (!xorFinder.doNoPart(3, 10))
- return false;
- }*/
-
- //calculateDefaultPolarities();
- if (conf.polarity_mode != polarity_auto) {
- for (uint32_t i = 0; i < polarity.size(); i++) {
- polarity[i] = defaultPolarity();
- }
- }
-
- fullStarts++;
- }
-
- return true;
-}
-
-/**
-@brief Performs a set of pre-optimisations before the beggining of solving
-
-This is somewhat different than the set of optimisations carried out during
-solving in simplifyProblem(). For instance, binary xors are searched fully
-here, while there, no search for them is carried out. Also, the ordering
-is different.
-
-\todo experiment to use simplifyProblem() instead of this, with the only
-addition of binary clause search. Maybe it will do just as good (or better).
-*/
-void Solver::performStepsBeforeSolve()
-{
- assert(qhead == trail.size());
- testAllClauseAttach();
-
- printRestartStat();
- if (conf.doReplace && !varReplacer->performReplace()) return;
-
- order_heap.filter(Solver::VarFilter(*this));
- if (order_heap.size() > 300000) {
- if (conf.verbosity > 0) {
- std::cout << "c turning cache OFF because there are too many active variables" << std::endl;
- }
- conf.doCacheOTFSSR = false;
- }
-
- bool saveDoHyperBin = conf.doHyperBinRes;
- conf.doHyperBinRes = false;
- clauseAllocator.consolidate(this, true);
- if (conf.doFailedLit && !failedLitSearcher->search()) return;
- conf.doHyperBinRes = saveDoHyperBin;
- if (conf.doClausVivif && !conf.libraryUsage
- && !clauseVivifier->vivifyClauses()) return;
-
- #ifdef VERBOSE_DEBUG
- printAllClauses();
- #endif //VERBOSE_DEBUG
- if (conf.doSatELite
- && !conf.libraryUsage
- && clauses.size() < 4800000
- && !subsumer->simplifyBySubsumption())
- return;
-
- if (conf.doFindEqLits) {
- if (!sCCFinder->find2LongXors()) return;
- lastNbBin = numNewBin;
- if (conf.doReplace && !varReplacer->performReplace(true)) return;
- }
-
- if (conf.doFindXors && clauses.size() < MAX_CLAUSENUM_XORFIND) {
- XorFinder xorFinder(*this, clauses);
- if (!xorFinder.fullFindXors(3, 7)) return;
- }
-
- if (xorclauses.size() > 1) {
- if (conf.doXorSubsumption && !xorSubsumer->simplifyBySubsumption())
- return;
-
- if (conf.doReplace && !varReplacer->performReplace())
- return;
- }
-
- if (conf.doSortWatched) sortWatched();
- if (conf.doCacheOTFSSR && conf.doCalcReach) calcReachability();
-
- testAllClauseAttach();
-}
-
-/**
-@brief Initialises model, restarts, learnt cluause cleaning, burst-search, etc.
-*/
-void Solver::initialiseSolver()
-{
- //Clear up previous stuff like model, final conflict, matrixes
- model.clear();
- conflict.clear();
- clearGaussMatrixes();
-
- //Initialise restarts & dynamic restart datastructures
- setDefaultRestartType();
-
- //Initialise avg. branch depth
- avgBranchDepth.clear();
- avgBranchDepth.initSize(500);
-
- //Initialise number of restarts&full restarts
- starts = 0;
- fullStarts = 0;
-
- if (nClauses() * conf.learntsize_factor < nbClBeforeRed) {
- if (nClauses() * conf.learntsize_factor < nbClBeforeRed/2)
- nbClBeforeRed /= 4;
- else
- nbClBeforeRed = (nClauses() * conf.learntsize_factor)/2;
- }
-
- testAllClauseAttach();
- findAllAttach();
-}
-
-/**
-@brief The main solve loop that glues everything together
-
-We clear everything needed, pre-simplify the problem, calculate default
-polarities, and start the loop. Finally, we either report UNSAT or extend the
-found solution with all the intermediary simplifications (e.g. variable
-elimination, etc.) and output the solution.
-*/
-lbool Solver::solve(const vec<Lit>& assumps)
-{
- #ifdef VERBOSE_DEBUG
- std::cout << "Solver::solve() called" << std::endl;
- #endif
- if (!ok) return l_False;
- assert(qhead == trail.size());
- assert(subsumer->checkElimedUnassigned());
- assert(xorSubsumer->checkElimedUnassigned());
-
- if (libraryCNFFile)
- fprintf(libraryCNFFile, "c Solver::solve() called\n");
-
- assumps.copyTo(assumptions);
- initialiseSolver();
- uint64_t nof_conflicts = conf.restart_first; //Geometric restart policy, start with this many
- uint64_t nof_conflicts_fullrestart = conf.restart_first * FULLRESTART_MULTIPLIER + conflicts; //at this point, do a full restart
- uint32_t lastFullRestart = starts; //last time a full restart was made was at this number of restarts
- lbool status = l_Undef; //Current status
- uint64_t nextSimplify = conf.restart_first * conf.simpStartMult + conflicts; //Do simplifyProblem() at this number of conflicts
- if (!conf.doSchedSimp) nextSimplify = std::numeric_limits<uint64_t>::max();
-
- if (conflicts == 0) {
- if (conf.doPerformPreSimp) performStepsBeforeSolve();
- if (!ok) return l_False;
-
- calculateDefaultPolarities();
- }
-
- printStatHeader();
- printRestartStat("B");
- uint64_t lastConflPrint = conflicts;
- // Search:
- while (status == l_Undef && starts < conf.maxRestarts) {
- #ifdef DEBUG_VARELIM
- assert(subsumer->checkElimedUnassigned());
- assert(xorSubsumer->checkElimedUnassigned());
- #endif //DEBUG_VARELIM
-
- if ((conflicts - lastConflPrint) > std::min(std::max(conflicts/100*6, (uint64_t)4000), (uint64_t)20000)) {
- printRestartStat("N");
- lastConflPrint = conflicts;
- }
-
- if (conf.doSchedSimp && conflicts >= nextSimplify) {
- status = simplifyProblem(conf.simpBurstSConf);
- printRestartStat();
- lastConflPrint = conflicts;
- nextSimplify = std::min((uint64_t)((double)conflicts * conf.simpStartMMult), conflicts + MAX_CONFL_BETWEEN_SIMPLIFY);
- if (status != l_Undef) break;
- }
-
- status = search(nof_conflicts, std::min(nof_conflicts_fullrestart, nextSimplify));
- if (needToInterrupt) {
- cancelUntil(0);
- return l_Undef;
- }
-
- nof_conflicts = (double)nof_conflicts * conf.restart_inc;
- if (status != l_Undef) break;
- if (!checkFullRestart(nof_conflicts, nof_conflicts_fullrestart , lastFullRestart))
- return l_False;
- if (!chooseRestartType(lastFullRestart))
- return l_False;
- }
- printEndSearchStat();
-
- #ifdef VERBOSE_DEBUG
- if (status == l_True)
- std::cout << "Solution is SAT" << std::endl;
- else if (status == l_False)
- std::cout << "Solution is UNSAT" << std::endl;
- else
- std::cout << "Solutions is UNKNOWN" << std::endl;
- #endif //VERBOSE_DEBUG
-
- if (status == l_True) handleSATSolution();
- else if (status == l_False) handleUNSATSolution();
-
- cancelUntil(0);
- restartTypeChooser->reset();
- if (status == l_Undef) clauseCleaner->removeAndCleanAll(true);
-
- #ifdef VERBOSE_DEBUG
- std::cout << "Solver::solve() finished" << std::endl;
- #endif
- return status;
-}
-
-/**
-@brief Extends a SAT solution to the full solution
-
-variable elimination, variable replacement, sub-part solving, etc. all need to
-be handled correctly to arrive at a solution that is a solution to ALL of the
-original problem, not just of what remained of it at the end inside this class
-(i.e. we need to combine things from the helper classes)
-*/
-void Solver::handleSATSolution()
-{
-
- /*if (greedyUnbound) {
- double time = cpuTime();
- FindUndef finder(*this);
- const uint32_t unbounded = finder.unRoll();
- if (conf.verbosity >= 1)
- printf("c Greedy unbounding :%5.2lf s, unbounded: %7d vars\n", cpuTime()-time, unbounded);
- }*/
- assert(subsumer->checkElimedUnassigned());
- assert(xorSubsumer->checkElimedUnassigned());
-
- varReplacer->extendModelPossible();
- checkSolution();
-
- if (subsumer->getNumElimed() || xorSubsumer->getNumElimed()) {
- if (conf.verbosity >= 1) {
- std::cout << "c Solution needs extension. Extending." << std::endl;
- }
- Solver s;
- s.conf = conf;
- s.conf.doSatELite = false;
- s.conf.doReplace = false;
- s.conf.doFindEqLits = false;
- s.conf.doRegFindEqLits = false;
- s.conf.doFailedLit= false;
- s.conf.doConglXors = false;
- s.conf.doSubsWNonExistBins = false;
- s.conf.doRemUselessBins = false;
- s.conf.doClausVivif = false;
- s.conf.doSortWatched = false;
- s.conf.verbosity = 0;
-
- vec<Lit> tmp;
- for (Var var = 0; var < nVars(); var++) {
- s.newVar(decision_var[var]
- || subsumer->getVarElimed()[var]
- || varReplacer->varHasBeenReplaced(var)
- || xorSubsumer->getVarElimed()[var]
- );
-
- //assert(!(xorSubsumer->getVarElimed()[var] && (decision_var[var] || subsumer->getVarElimed()[var] || varReplacer->varHasBeenReplaced(var))));
-
- if (value(var) != l_Undef) {
- #ifdef VERBOSE_DEBUG
- std::cout << "Setting var " << var + 1
- << " in extend-solver to " << value(var) << std::endl;
- #endif
- tmp.clear();
- tmp.push(Lit(var, value(var) == l_False));
- s.addClause(tmp);
- }
- }
- varReplacer->extendModelImpossible(s);
- subsumer->extendModel(s);
- xorSubsumer->extendModel(s);
-
- lbool status = s.solve();
- release_assert(status == l_True && "c ERROR! Extension of model failed!");
-#ifdef VERBOSE_DEBUG
- std::cout << "Solution extending finished. Enqueuing results" << std::endl;
-#endif
- //need to start new decision level, otherwise uncheckedEnqueue will
- //enqueue to decision level 0 in certain cases :S
- newDecisionLevel();
- for (Var var = 0; var < nVars(); var++) {
- if (assigns[var] == l_Undef && s.model[var] != l_Undef)
- uncheckedEnqueue(Lit(var, s.model[var] == l_False));
- }
- ok = (propagate<false>().isNULL());
- release_assert(ok && "c ERROR! Extension of model failed!");
- }
- checkSolution();
- //Copy model:
- model.growTo(nVars());
- for (Var var = 0; var != nVars(); var++) model[var] = value(var);
-}
-
-/**
-@brief When problem is decided to be UNSAT, this is called
-
-There is basically nothing to be handled for the moment, but this could be
-made extensible
-*/
-void Solver::handleUNSATSolution()
-{
- if (conflict.size() == 0)
- ok = false;
-}
-
-void Solver::cleanCache()
-{
- for(uint32_t i = 0; i < nVars(); i++) {
- if (subsumer->getVarElimed()[i] || value(i) != l_Undef) {
- vector<Lit> tmp1;
- transOTFCache[Lit(i, false).toInt()].lits.swap(tmp1);
- vector<Lit> tmp2;
- transOTFCache[Lit(i, true).toInt()].lits.swap(tmp2);
- continue;
- }
-
- for(int which = 0; which < 2; which++) {
- cleanCachePart(Lit(i, which));
-
- }
- }
-}
-
-void Solver::cleanCachePart(const Lit vertLit)
-{
- vector<Lit>& transCache = transOTFCache[(~vertLit).toInt()].lits;
- assert(seen_vec.empty());
-
- vector<Lit>::iterator it = transCache.begin();
- vector<Lit>::iterator it2 = it;
-
- size_t newSize = 0;
- for (vector<Lit>::iterator end = transCache.end(); it != end; it++) {
- Lit lit = *it;
- lit = varReplacer->getReplaceTable()[lit.var()] ^ lit.sign();
- if (lit == vertLit
- || seen[lit.toInt()]
- || subsumer->getVarElimed()[lit.var()]
- || subsumer->getVarElimed()[lit.var()]
- ) continue;
-
- *it2++ = lit;
-
- //Don't allow the same value to be in the cache twice
- seen[lit.toInt()] = 1;
- seen_vec.push_back(lit);
-
- //Increase valid size
- newSize++;
- }
- transCache.resize(newSize);
-
- //Clear up seen
- for(vector<Lit>::const_iterator it = seen_vec.begin(), end = seen_vec.end(); it != end; it++) {
- seen[it->toInt()] = 0;
- }
- seen_vec.clear();
-}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback