This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/packages/bee/cryptominisat-2.5.1/Solver/Solver.cpp

2701 lines
87 KiB
C++
Executable File

/****************************************************************************************[Solver.C]
MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
CryptoMiniSat -- Copyright (c) 2009 Mate Soos
glucose -- Gilles Audemard, Laurent Simon (2008)
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 "Solver.h"
#include <cmath>
#include <string.h>
#include <algorithm>
#include <limits.h>
#include <vector>
#include <iomanip>
#include "Clause.h"
#include "time_mem.h"
#include "VarReplacer.h"
#include "FindUndef.h"
#include "XorFinder.h"
#include "ClauseCleaner.h"
#include "RestartTypeChooser.h"
#include "FailedVarSearcher.h"
#include "Subsumer.h"
#include "PartHandler.h"
#include "XorSubsumer.h"
#include "StateSaver.h"
#ifdef USE_GAUSS
#include "Gaussian.h"
#include "MatrixFinder.h"
#endif //USE_GAUSS
#ifdef _MSC_VER
#define __builtin_prefetch(a,b,c)
//#define __builtin_prefetch(a,b)
#endif //_MSC_VER
//#define DEBUG_UNCHECKEDENQUEUE_LEVEL0
//#define VERBOSE_DEBUG_POLARITIES
//#define DEBUG_DYNAMIC_RESTART
//=================================================================================================
// Constructor/Destructor:
Solver::Solver() :
// Parameters: (formerly in 'SearchParams')
random_var_freq(0.02)
, clause_decay (1 / 0.999)
, restart_first(100), restart_inc(1.5), learntsize_factor((double)1/(double)3), learntsize_inc(1)
// More parameters:
//
, expensive_ccmin (true)
, polarity_mode (polarity_auto)
, verbosity (0)
, restrictedPickBranch(0)
, findNormalXors (true)
, findBinaryXors (true)
, regularlyFindBinaryXors(true)
, performReplace (true)
, conglomerateXors (true)
, heuleProcess (true)
, schedSimplification(true)
, doSubsumption (true)
, doXorSubsumption (true)
, doPartHandler (true)
, doHyperBinRes (true)
, doBlockedClause (true)
, doVarElim (true)
, doSubsume1 (true)
, failedVarSearch (true)
, readdOldLearnts (false)
, addExtraBins (true)
, removeUselessBins(true)
, regularRemoveUselessBins(true)
, subsumeWithNonExistBinaries(true)
, regularSubsumeWithNonExistBinaries(true)
, libraryUsage (true)
, greedyUnbound (false)
, fixRestartType (auto_restart)
// Statistics: (formerly in 'SolverStats')
//
, 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)
, nbDL2(0), nbBin(0), lastNbBin(0), becameBinary(0), lastSearchForBinaryXor(0), nbReduceDB(0)
, improvedClauseNo(0), improvedClauseSize(0)
#ifdef USE_GAUSS
, sum_gauss_called (0)
, sum_gauss_confl (0)
, sum_gauss_prop (0)
, sum_gauss_unit_truths (0)
#endif //USE_GAUSS
, ok (true)
, var_inc (128)
, cla_inc (1)
, curRestart (1)
, nbclausesbeforereduce (NBCLAUSESBEFOREREDUCE)
, nbCompensateSubsumer (0)
, qhead (0)
, simpDB_assigns (-1)
, simpDB_props (0)
, order_heap (VarOrderLt(activity))
, progress_estimate(0)
, remove_satisfied (true)
, mtrand((unsigned long int)0)
, restartType (static_restart)
, lastSelectedRestartType (static_restart)
#ifdef STATS_NEEDED
, logger(verbosity)
, dynamic_behaviour_analysis(false) //do not document the proof as default
#endif
, maxRestarts(UINT_MAX)
, MYFLAG (0)
, learnt_clause_group(0)
, libraryCNFFile (NULL)
, simplifying (false)
{
varReplacer = new VarReplacer(*this);
clauseCleaner = new ClauseCleaner(*this);
failedVarSearcher = new FailedVarSearcher(*this);
partHandler = new PartHandler(*this);
subsumer = new Subsumer(*this);
xorSubsumer = new XorSubsumer(*this);
restartTypeChooser = new RestartTypeChooser(*this);
#ifdef USE_GAUSS
matrixFinder = new MatrixFinder(*this);
#endif //USE_GAUSS
#ifdef STATS_NEEDED
logger.setSolver(this);
#endif
}
Solver::~Solver()
{
for (uint32_t i = 0; i != learnts.size(); i++) clauseFree(learnts[i]);
for (uint32_t i = 0; i != clauses.size(); i++) clauseFree(clauses[i]);
for (uint32_t i = 0; i != binaryClauses.size(); i++) clauseFree(binaryClauses[i]);
for (uint32_t i = 0; i != xorclauses.size(); i++) clauseFree(xorclauses[i]);
for (uint32_t i = 0; i != removedLearnts.size(); i++) clauseFree(removedLearnts[i]);
#ifdef USE_GAUSS
clearGaussMatrixes();
delete matrixFinder;
#endif
for (uint32_t i = 0; i != freeLater.size(); i++) clauseFree(freeLater[i]);
delete varReplacer;
delete clauseCleaner;
delete failedVarSearcher;
delete partHandler;
delete subsumer;
delete xorSubsumer;
delete restartTypeChooser;
if (libraryCNFFile)
fclose(libraryCNFFile);
}
//=================================================================================================
// Minor methods:
// Creates a new SAT variable in the solver. If 'decision_var' is cleared, variable will not be
// used as a decision variable (NOTE! This has effects on the meaning of a SATISFIABLE result).
Var Solver::newVar(bool dvar)
{
Var v = nVars();
watches .push(); // (list for positive literal)
watches .push(); // (list for negative literal)
binwatches.push(); // (list for positive literal)
binwatches.push(); // (list for negative literal)
xorwatches.push(); // (list for variables in xors)
reason .push((Clause*)NULL);
assigns .push(l_Undef);
level .push(-1);
activity .push(0);
seen .push_back(0);
seen .push_back(0);
permDiff .push(0);
polarity .push_back(defaultPolarity());
#ifdef USE_OLD_POLARITIES
oldPolarity.push_back(defaultPolarity());
#endif //USE_OLD_POLARITIES
decision_var.push_back(dvar);
insertVarOrder(v);
varReplacer->newVar();
partHandler->newVar();
subsumer->newVar();
xorSubsumer->newVar();
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
logger.new_var(v);
#endif
if (libraryCNFFile)
fprintf(libraryCNFFile, "c Solver::newVar() called\n");
return v;
}
template<class T>
XorClause* Solver::addXorClauseInt(T& ps, bool xor_clause_inverted, const uint32_t group)
{
assert(qhead == trail.size());
assert(decisionLevel() == 0);
if (ps.size() > (0x01UL << 18)) {
std::cout << "Too long clause!" << std::endl;
exit(-1);
}
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())
xor_clause_inverted ^= assigns[ps[i].var()].getBool();
} else if (assigns[ps[i].var()].isUndef()) //just add
ps[j++] = p = ps[i];
else //modify xor_clause_inverted instead of adding
xor_clause_inverted ^= (assigns[ps[i].var()].getBool());
}
ps.shrink(i - j);
switch(ps.size()) {
case 0: {
if (!xor_clause_inverted) ok = false;
return NULL;
}
case 1: {
uncheckedEnqueue(Lit(ps[0].var(), xor_clause_inverted));
ok = (propagate() == NULL);
return NULL;
}
case 2: {
#ifdef VERBOSE_DEBUG
cout << "--> xor is 2-long, replacing var " << ps[0].var()+1 << " with " << (!xor_clause_inverted ? "-" : "") << ps[1].var()+1 << endl;
#endif
learnt_clause_group = std::max(group+1, learnt_clause_group);
ps[0] = ps[0].unsign();
ps[1] = ps[1].unsign();
varReplacer->replace(ps, xor_clause_inverted, group);
return NULL;
}
default: {
learnt_clause_group = std::max(group+1, learnt_clause_group);
XorClause* c = XorClause_new(ps, xor_clause_inverted, group);
attachClause(*c);
return c;
}
}
}
template XorClause* Solver::addXorClauseInt(vec<Lit>& ps, bool xor_clause_inverted, const uint32_t group);
template XorClause* Solver::addXorClauseInt(XorClause& ps, bool xor_clause_inverted, const uint32_t group);
template<class T>
bool Solver::addXorClause(T& ps, bool xor_clause_inverted, const uint group, char* group_name)
{
assert(decisionLevel() == 0);
if (ps.size() > (0x01UL << 18)) {
std::cout << "Too long clause!" << std::endl;
exit(-1);
}
if (libraryCNFFile) {
fprintf(libraryCNFFile, "x");
for (uint32_t i = 0; i < ps.size(); i++) ps[i].print(libraryCNFFile);
fprintf(libraryCNFFile, "0\n");
}
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
logger.set_group_name(group, group_name);
#endif
if (!ok)
return false;
assert(qhead == trail.size());
// 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++) {
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;
else {
Lit otherLit = varReplacer->getReplaceTable()[ps[i].var()];
if (otherLit.var() != ps[i].var()) {
ps[i] = Lit(otherLit.var(), false);
xor_clause_inverted ^= otherLit.sign();
}
}
}
}
XorClause* c = addXorClauseInt(ps, xor_clause_inverted, group);
if (c != NULL) xorclauses.push(c);
return ok;
}
template bool Solver::addXorClause(vec<Lit>& ps, bool xor_clause_inverted, const uint group, char* group_name);
template bool Solver::addXorClause(XorClause& ps, bool xor_clause_inverted, const uint group, char* group_name);
template<class T>
bool Solver::addLearntClause(T& ps, const uint group, const uint32_t activity)
{
Clause* c = addClauseInt(ps, group);
if (c == NULL) return ok;
//compensate for addClauseInt's attachClause, which doesn't know
//that this is a learnt clause.
clauses_literals -= c->size();
learnts_literals += c->size();
c->makeLearnt(activity);
if (c->size() > 2) learnts.push(c);
else {
nbBin++;
binaryClauses.push(c);
}
return ok;
}
template bool Solver::addLearntClause(Clause& ps, const uint group, const uint32_t activity);
template bool Solver::addLearntClause(vec<Lit>& ps, const uint group, const uint32_t activity);
template <class T>
Clause* Solver::addClauseInt(T& ps, uint group)
{
assert(ok);
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];
}
ps.shrink(i - j);
if (ps.size() == 0) {
ok = false;
return NULL;
} else if (ps.size() == 1) {
uncheckedEnqueue(ps[0]);
ok = (propagate() == NULL);
return NULL;
}
learnt_clause_group = std::max(group+1, learnt_clause_group);
Clause* c = Clause_new(ps, group);
attachClause(*c);
return c;
}
template Clause* Solver::addClauseInt(Clause& ps, const uint group);
template Clause* Solver::addClauseInt(vec<Lit>& ps, const uint group);
template<class T>
bool Solver::addClause(T& ps, const uint group, char* group_name)
{
assert(decisionLevel() == 0);
if (ps.size() > (0x01UL << 18)) {
std::cout << "Too long clause!" << std::endl;
exit(-1);
}
if (libraryCNFFile) {
for (uint32_t i = 0; i != ps.size(); i++) ps[i].print(libraryCNFFile);
fprintf(libraryCNFFile, "0\n");
}
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
logger.set_group_name(group, group_name);
#endif
if (!ok)
return false;
assert(qhead == trail.size());
// 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;
}
}
Clause* c = addClauseInt(ps, group);
if (c != NULL) {
if (c->size() > 2)
clauses.push(c);
else
binaryClauses.push(c);
}
return ok;
}
template bool Solver::addClause(vec<Lit>& ps, const uint group, char* group_name);
template bool Solver::addClause(Clause& ps, const uint group, char* group_name);
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);
#endif //DEBUG_ATTACH
xorwatches[c[0].var()].push(&c);
xorwatches[c[1].var()].push(&c);
clauses_literals += c.size();
}
void Solver::attachClause(Clause& c)
{
assert(c.size() > 1);
int index0 = (~c[0]).toInt();
int index1 = (~c[1]).toInt();
if (c.size() == 2) {
binwatches[index0].push(WatchedBin(&c, c[1]));
binwatches[index1].push(WatchedBin(&c, c[0]));
} else {
watches[index0].push(Watched(&c, c[c.size()/2]));
watches[index1].push(Watched(&c, c[c.size()/2]));
}
if (c.learnt()) learnts_literals += c.size();
else clauses_literals += c.size();
}
void Solver::detachClause(const XorClause& c)
{
assert(c.size() > 1);
assert(find(xorwatches[c[0].var()], &c));
assert(find(xorwatches[c[1].var()], &c));
remove(xorwatches[c[0].var()], &c);
remove(xorwatches[c[1].var()], &c);
clauses_literals -= c.size();
}
void Solver::detachClause(const Clause& c)
{
assert(c.size() > 1);
if (c.size() == 2) {
assert(findWatchedBinCl(binwatches[(~c[0]).toInt()], &c));
assert(findWatchedBinCl(binwatches[(~c[1]).toInt()], &c));
removeWatchedBinCl(binwatches[(~c[0]).toInt()], &c);
removeWatchedBinCl(binwatches[(~c[1]).toInt()], &c);
} else {
assert(findWatchedCl(watches[(~c[0]).toInt()], &c));
assert(findWatchedCl(watches[(~c[1]).toInt()], &c));
removeWatchedCl(watches[(~c[0]).toInt()], &c);
removeWatchedCl(watches[(~c[1]).toInt()], &c);
}
if (c.learnt()) learnts_literals -= c.size();
else clauses_literals -= c.size();
}
void Solver::detachModifiedClause(const Lit lit1, const Lit lit2, const uint origSize, const Clause* address)
{
assert(origSize > 1);
if (origSize == 2) {
assert(findWatchedBinCl(binwatches[(~lit1).toInt()], address));
assert(findWatchedBinCl(binwatches[(~lit2).toInt()], address));
removeWatchedBinCl(binwatches[(~lit1).toInt()], address);
removeWatchedBinCl(binwatches[(~lit2).toInt()], address);
} else {
assert(findW(watches[(~lit1).toInt()], address));
assert(findW(watches[(~lit2).toInt()], address));
removeW(watches[(~lit1).toInt()], address);
removeW(watches[(~lit2).toInt()], address);
}
if (address->learnt()) learnts_literals -= origSize;
else clauses_literals -= origSize;
}
void Solver::detachModifiedClause(const Var var1, const Var var2, const uint origSize, const XorClause* address)
{
assert(origSize > 2);
assert(find(xorwatches[var1], address));
assert(find(xorwatches[var2], address));
remove(xorwatches[var1], address);
remove(xorwatches[var2], address);
clauses_literals -= origSize;
}
// Revert to the state at given level (keeping all assignment at 'level' but not beyond).
//
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
#ifdef USE_OLD_POLARITIES
polarity[var] = oldPolarity[var];
#endif //USE_OLD_POLARITIES
assigns[var] = l_Undef;
insertVarOrder(var);
}
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::printLit(const Lit l) const
{
printf("%s%d:%c", l.sign() ? "-" : "", l.var()+1, value(l) == l_True ? '1' : (value(l) == l_False ? '0' : 'X'));
}
void Solver::needLibraryCNFFile(const char* fileName)
{
libraryCNFFile = fopen(fileName, "w");
assert(libraryCNFFile != NULL);
}
#ifdef USE_GAUSS
void Solver::clearGaussMatrixes()
{
for (uint i = 0; i < gauss_matrixes.size(); i++)
delete gauss_matrixes[i];
gauss_matrixes.clear();
}
#endif //USE_GAUSS
inline bool Solver::defaultPolarity()
{
switch(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;
}
void Solver::tallyVotes(const vec<Clause*>& cs, vector<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[0], *end2 = it2 + c.size(); it2 != end2; it2++) {
if (it2->sign()) votes[it2->var()] += divider;
else votes[it2->var()] -= divider;
}
}
}
void Solver::tallyVotes(const vec<XorClause*>& cs, vector<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[0], *end2 = it2 + c.size(); it2 != end2; it2++)
votes[it2->var()] += divider;
}
}
void Solver::calculateDefaultPolarities()
{
#ifdef VERBOSE_DEBUG_POLARITIES
std::cout << "Default polarities: " << std::endl;
#endif
assert(decisionLevel() == 0);
if (polarity_mode == polarity_auto) {
double time = cpuTime();
vector<double> votes;
votes.resize(nVars(), 0.0);
tallyVotes(clauses, votes);
tallyVotes(binaryClauses, votes);
tallyVotes(varReplacer->getClauses(), votes);
tallyVotes(xorclauses, votes);
Var i = 0;
uint32_t posPolars = 0;
uint32_t undecidedPolars = 0;
for (vector<double>::const_iterator it = votes.begin(), end = votes.end(); 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 (verbosity >= 2) {
std::cout << "c | Calc default polars - "
<< " time: " << std::fixed << std::setw(6) << std::setprecision(2) << cpuTime()-time << " s"
<< " pos: " << std::setw(7) << posPolars
<< " undec: " << std::setw(7) << undecidedPolars
<< " neg: " << std::setw(7) << nVars()- undecidedPolars - posPolars
<< std::setw(8) << " |" << std:: endl;
}
} else {
std::fill(polarity.begin(), polarity.end(), defaultPolarity());
}
#ifdef VERBOSE_DEBUG_POLARITIES
std::cout << std::endl;
#endif //VERBOSE_DEBUG_POLARITIES
}
//=================================================================================================
// Major methods:
Lit Solver::pickBranchLit()
{
#ifdef VERBOSE_DEBUG
cout << "decision level: " << decisionLevel() << " ";
#endif
Var next = var_Undef;
bool random = mtrand.randDblExc() < random_var_freq;
// Random decision:
if (random && !order_heap.empty()) {
if (restrictedPickBranch == 0)
next = order_heap[mtrand.randInt(order_heap.size()-1)];
else
next = order_heap[mtrand.randInt(std::min((uint32_t)order_heap.size()-1, restrictedPickBranch))];
if (assigns[next] == l_Undef && decision_var[next])
rnd_decisions++;
}
// Activity based decision:
while (next == var_Undef || assigns[next] != l_Undef || !decision_var[next])
if (order_heap.empty()) {
#ifdef VERBOSE_DEBUG
cout << "SAT!" << endl;
#endif
return lit_Undef;
} else {
next = order_heap.removeMin();
}
bool sign;
if (simplifying && random)
sign = mtrand.randInt(1);
#ifdef RANDOM_LOOKAROUND_SEARCHSPACE
else if (avgBranchDepth.isvalid())
sign = polarity[next] ^ (mtrand.randInt(avgBranchDepth.getavg() * ((lastSelectedRestartType == static_restart) ? 2 : 1) ) == 1);
#endif
else
sign = polarity[next];
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;
}
// Assumes 'seen' is cleared (will leave it cleared)
template<class T1, class T2>
bool subset(const T1& A, const T2& B, vector<bool>& seen)
{
for (uint i = 0; i != B.size(); i++)
seen[B[i].toInt()] = 1;
for (uint i = 0; i != A.size(); i++) {
if (!seen[A[i].toInt()]) {
for (uint i = 0; i != B.size(); i++)
seen[B[i].toInt()] = 0;
return false;
}
}
for (uint i = 0; i != B.size(); i++)
seen[B[i].toInt()] = 0;
return true;
}
/*_________________________________________________________________________________________________
|
| analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel : int&) -> [void]
|
| Description:
| Analyze conflict and produce a reason clause.
|
| Pre-conditions:
| * 'out_learnt' is assumed to be cleared.
| * Current decision level must be greater than root level.
|
| Post-conditions:
| * '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.
|________________________________________________________________________________________________@*/
Clause* Solver::analyze(Clause* confl, vec<Lit>& out_learnt, int& out_btlevel, uint32_t &nbLevels, const bool update)
{
int pathC = 0;
Lit p = lit_Undef;
Clause* oldConfl = NULL;
// Generate conflict clause:
//
out_learnt.push(); // (leave room for the asserting literal)
int index = trail.size() - 1;
out_btlevel = 0;
do {
assert(confl != NULL); // (otherwise should be UIP)
Clause& c = *confl;
if (p != lit_Undef)
reverse_binary_clause(c);
if (update && restartType == static_restart && c.learnt())
claBumpActivity(c);
for (uint j = (p == lit_Undef) ? 0 : 1; j != c.size(); j++) {
const Lit& q = c[j];
const Var my_var = q.var();
if (!seen[my_var] && level[my_var] > 0) {
varBumpActivity(my_var);
seen[my_var] = 1;
if (level[my_var] >= (int)decisionLevel()) {
pathC++;
#ifdef UPDATEVARACTIVITY
if (lastSelectedRestartType == dynamic_restart && reason[q.var()] != NULL && reason[q.var()]->learnt())
lastDecisionLevel.push(q.var());
#endif
} 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 = reason[p.var()];
__builtin_prefetch(confl, 1, 0);
seen[p.var()] = 0;
pathC--;
} while (pathC > 0);
out_learnt[0] = ~p;
// Simplify conflict clause:
//
uint32_t i, j;
if (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()] == NULL || !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++) {
Clause& c = *reason[out_learnt[i].var()];
reverse_binary_clause(c);
for (uint k = 1; k < c.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);
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;
Lit p = out_learnt[max_i];
out_learnt[max_i] = out_learnt[1];
out_learnt[1] = p;
out_btlevel = level[p.var()];
}
if (lastSelectedRestartType == dynamic_restart) {
nbLevels = calcNBLevels(out_learnt);
#ifdef UPDATEVARACTIVITY
for(uint32_t i = 0; i != lastDecisionLevel.size(); i++) {
if (reason[lastDecisionLevel[i]]->activity() < nbLevels)
varBumpActivity(lastDecisionLevel[i]);
}
lastDecisionLevel.clear();
#endif
} else {
nbLevels = 1000;
}
for (uint32_t j = 0; j != analyze_toclear.size(); j++)
seen[analyze_toclear[j].var()] = 0; // ('seen[]' is now cleared)
if (out_learnt.size() == 1)
return NULL;
if (!oldConfl->isXor() && out_learnt.size() < oldConfl->size()) {
if (!subset(out_learnt, *oldConfl, seen)) return NULL;
improvedClauseNo++;
improvedClauseSize += oldConfl->size() - out_learnt.size();
return oldConfl;
}
return NULL;
}
// Check if 'p' can be removed. '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()] != NULL);
Clause& c = *reason[analyze_stack.last().var()];
reverse_binary_clause(c);
analyze_stack.pop();
for (uint i = 1; i < c.size(); i++) {
Lit p = c[i];
if (!seen[p.var()] && level[p.var()] > 0) {
if (reason[p.var()] != NULL && (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] == NULL) {
assert(level[x] > 0);
out_conflict.push(~trail[i]);
} else {
const Clause& c = *reason[x];
for (uint j = 1; j < c.size(); j++)
if (level[c[j].var()] > 0)
seen[c[j].var()] = 1;
}
seen[x] = 0;
}
}
seen[p.var()] = 0;
}
void Solver::uncheckedEnqueue(Lit p, ClausePtr from)
{
#ifdef DEBUG_UNCHECKEDENQUEUE_LEVEL0
#ifndef VERBOSE_DEBUG
if (decisionLevel() == 0)
#endif //VERBOSE_DEBUG
std::cout << "uncheckedEnqueue var " << p.var()+1 << " to " << !p.sign() << " level: " << decisionLevel() << " sublevel: " << trail.size() << std::endl;
#endif //DEBUG_UNCHECKEDENQUEUE_LEVEL0
//assert(decisionLevel() == 0 || !subsumer->getVarElimed()[p.var()]);
assert(assigns[p.var()].isUndef());
const Var v = p.var();
assigns [v] = boolToLBool(!p.sign());//lbool(!sign(p)); // <<== abstract but not uttermost effecient
level [v] = decisionLevel();
reason [v] = from;
#ifdef USE_OLD_POLARITIES
oldPolarity[p.var()] = polarity[p.var()];
#endif //USE_OLD_POLARITIES
polarity[p.var()] = p.sign();
trail.push(p);
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
logger.propagation(p, from);
#endif
}
/*_________________________________________________________________________________________________
|
| 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.
|________________________________________________________________________________________________@*/
Clause* Solver::propagate(const bool update)
{
Clause* confl = NULL;
uint32_t num_props = 0;
#ifdef VERBOSE_DEBUG
cout << "Propagation started" << endl;
#endif
uint32_t qheadBin = qhead;
while (qhead < trail.size()) {
//First propagate binary clauses
while (qheadBin < trail.size()) {
Lit p = trail[qheadBin++];
vec<WatchedBin> & wbin = binwatches[p.toInt()];
num_props += wbin.size()/2;
for(WatchedBin *k = wbin.getData(), *end = wbin.getDataEnd(); k != end; k++) {
lbool val = value(k->impliedLit);
if (val.isUndef()) {
uncheckedEnqueue(k->impliedLit, k->clause);
} else if (val == l_False) {
confl = k->clause;
//goto EndPropagate;
}
}
}
if (confl != NULL)
goto EndPropagate;
//Next, propagate normal clauses
Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate.
vec<Watched>& ws = watches[p.toInt()];
Watched *i, *j, *end;
num_props += ws.size();
#ifdef VERBOSE_DEBUG
cout << "Propagating lit " << (p.sign() ? '-' : ' ') << p.var()+1 << endl;
#endif
for (i = j = ws.getData(), end = ws.getDataEnd(); i != end;) {
if (i+1 != end)
__builtin_prefetch((i+1)->clause, 1, 0);
if(value(i->blockedLit).getBool()) { // Clause is sat
*j++ = *i++;
continue;
}
Lit bl = i->blockedLit;
Clause& c = *(i->clause);
i++;
// Make sure the false literal is data[1]:
const Lit false_lit(~p);
if (c[0] == false_lit)
c[0] = c[1], c[1] = false_lit;
assert(c[1] == false_lit);
// If 0th watch is true, then clause is already satisfied.
const Lit& first = c[0];
if (value(first).getBool()) {
j->clause = &c;
j->blockedLit = first;
j++;
} else {
// Look for new watch:
for (Lit *k = &c[2], *end2 = c.getDataEnd(); k != end2; k++) {
if (value(*k) != l_False) {
c[1] = *k;
*k = false_lit;
watches[(~c[1]).toInt()].push(Watched(&c, c[0]));
goto FoundWatch;
}
}
// Did not find watch -- clause is unit under assignment:
j->clause = &c;
j->blockedLit = bl;
j++;
if (value(first) == l_False) {
confl = &c;
qhead = trail.size();
// Copy the remaining watches:
while (i < end)
*j++ = *i++;
} else {
uncheckedEnqueue(first, &c);
#ifdef DYNAMICNBLEVEL
if (update && c.learnt() && c.activity() > 2) { // GA
uint32_t nbLevels = calcNBLevels(c);
if (nbLevels+1 < c.activity())
c.setActivity(nbLevels);
}
#endif
}
}
FoundWatch:
;
}
ws.shrink_(i - j);
//Finally, propagate XOR-clauses
if (xorclauses.size() > 0 && !confl) confl = propagate_xors(p);
}
EndPropagate:
propagations += num_props;
simpDB_props -= num_props;
#ifdef VERBOSE_DEBUG
cout << "Propagation ended." << endl;
#endif
return confl;
}
Clause* Solver::propagateLight()
{
Clause* confl = NULL;
uint32_t num_props = 0;
uint32_t qheadBin = qhead;
while (qhead < trail.size()) {
//First propagate binary clauses
while (qheadBin < trail.size()) {
Lit p = trail[qheadBin++];
vec<WatchedBin> & wbin = binwatches[p.toInt()];
num_props += wbin.size()/2;
for(WatchedBin *k = wbin.getData(), *end = wbin.getDataEnd(); k != end; k++) {
lbool val = value(k->impliedLit);
if (val.isUndef()) {
uncheckedEnqueueLight(k->impliedLit);
} else if (val == l_False) {
confl = k->clause;
goto EndPropagate;
}
}
}
//Next, propagate normal clauses
Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate.
vec<Watched>& ws = watches[p.toInt()];
Watched *i, *j, *end;
num_props += ws.size();
for (i = j = ws.getData(), end = ws.getDataEnd(); i != end;) {
if (i+1 != end)
__builtin_prefetch((i+1)->clause, 1, 0);
if(value(i->blockedLit).getBool()) { // Clause is sat
*j++ = *i++;
continue;
}
Lit bl = i->blockedLit;
Clause& c = *(i->clause);
i++;
// Make sure the false literal is data[1]:
const Lit false_lit(~p);
if (c[0] == false_lit)
c[0] = c[1], c[1] = false_lit;
assert(c[1] == false_lit);
// If 0th watch is true, then clause is already satisfied.
const Lit& first = c[0];
if (value(first).getBool()) {
j->clause = &c;
j->blockedLit = first;
j++;
} else {
// Look for new watch:
for (Lit *k = &c[2], *end2 = c.getDataEnd(); k != end2; k++) {
if (value(*k) != l_False) {
c[1] = *k;
*k = false_lit;
watches[(~c[1]).toInt()].push(Watched(&c, c[0]));
goto FoundWatch;
}
}
// Did not find watch -- clause is unit under assignment:
j->clause = &c;
j->blockedLit = bl;
j++;
if (value(first) == l_False) {
confl = &c;
qhead = trail.size();
// Copy the remaining watches:
while (i < end)
*j++ = *i++;
} else {
uncheckedEnqueueLight(first);
}
}
FoundWatch:
;
}
ws.shrink_(i - j);
//Finally, propagate XOR-clauses
if (xorclauses.size() > 0 && !confl) confl = propagate_xors(p);
}
EndPropagate:
propagations += num_props;
simpDB_props -= num_props;
return confl;
}
Clause* Solver::propagateBin()
{
while (qhead < trail.size()) {
Lit p = trail[qhead++];
vec<WatchedBin> & wbin = binwatches[p.toInt()];
propagations += wbin.size()/2;
for(WatchedBin *k = wbin.getData(), *end = wbin.getDataEnd(); k != end; k++) {
lbool val = value(k->impliedLit);
if (val.isUndef()) {
//uncheckedEnqueue(k->impliedLit, k->clause);
uncheckedEnqueueLight(k->impliedLit);
} else if (val == l_False) {
return k->clause;
}
}
}
return NULL;
}
Clause* Solver::propagateBinNoLearnts()
{
while (qhead < trail.size()) {
Lit p = trail[qhead++];
vec<WatchedBin> & wbin = binwatches[p.toInt()];
propagations += wbin.size()/2;
for(WatchedBin *k = wbin.getData(), *end = wbin.getDataEnd(); k != end; k++) {
if (k->clause->learnt()) continue;
lbool val = value(k->impliedLit);
if (val.isUndef()) {
//uncheckedEnqueue(k->impliedLit, k->clause);
uncheckedEnqueueLight(k->impliedLit);
} else if (val == l_False) {
return k->clause;
}
}
}
return NULL;
}
template<bool dontCareLearnt>
Clause* Solver::propagateBinExcept(const Lit& exceptLit)
{
while (qhead < trail.size()) {
Lit p = trail[qhead++];
vec<WatchedBin> & wbin = binwatches[p.toInt()];
propagations += wbin.size()/2;
for(WatchedBin *k = wbin.getData(), *end = wbin.getDataEnd(); k != end; k++) {
if (!dontCareLearnt && k->clause->learnt()) continue;
lbool val = value(k->impliedLit);
if (val.isUndef() && k->impliedLit != exceptLit) {
//uncheckedEnqueue(k->impliedLit, k->clause);
uncheckedEnqueueLight(k->impliedLit);
} else if (val == l_False) {
return k->clause;
}
}
}
return NULL;
}
template Clause* Solver::propagateBinExcept <true>(const Lit& exceptLit);
template Clause* Solver::propagateBinExcept <false>(const Lit& exceptLit);
template<bool dontCareLearnt>
Clause* Solver::propagateBinOneLevel()
{
Lit p = trail[qhead];
vec<WatchedBin> & wbin = binwatches[p.toInt()];
propagations += wbin.size()/2;
for(WatchedBin *k = wbin.getData(), *end = wbin.getDataEnd(); k != end; k++) {
if (!dontCareLearnt && k->clause->learnt()) continue;
lbool val = value(k->impliedLit);
if (val.isUndef()) {
//uncheckedEnqueue(k->impliedLit, k->clause);
uncheckedEnqueueLight(k->impliedLit);
} else if (val == l_False) {
return k->clause;
}
}
return NULL;
}
template Clause* Solver::propagateBinOneLevel <true>();
template Clause* Solver::propagateBinOneLevel <false>();
template<class T>
inline const uint32_t Solver::calcNBLevels(const T& ps)
{
MYFLAG++;
uint32_t nbLevels = 0;
for(const Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) {
int32_t lev = level[l->var()];
if (permDiff[lev] != MYFLAG) {
permDiff[lev] = MYFLAG;
nbLevels++;
}
}
return nbLevels;
}
Clause* Solver::propagate_xors(const Lit& p)
{
#ifdef VERBOSE_DEBUG_XOR
cout << "Xor-Propagating variable " << p.var()+1 << endl;
#endif
Clause* confl = NULL;
vec<XorClausePtr>& ws = xorwatches[p.var()];
XorClausePtr *i, *j, *end;
for (i = j = ws.getData(), end = i + ws.size(); i != end;) {
XorClause& c = **i++;
if (i != end)
__builtin_prefetch(*i, 1, 0);
// 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());
#ifdef VERBOSE_DEBUG_XOR
cout << "--> xor thing -- " << endl;
printClause(c);
cout << endl;
#endif
bool final = c.xor_clause_inverted();
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;
#ifdef VERBOSE_DEBUG_XOR
cout << "new watch set" << endl << endl;
#endif
xorwatches[c[1].var()].push(&c);
goto FoundWatch;
}
c[k] = c[k].unsign() ^ val.getBool();
final ^= val.getBool();
}
{
// Did not find watch -- clause is unit under assignment:
*j++ = &c;
#ifdef VERBOSE_DEBUG_XOR
cout << "final: " << std::boolalpha << final << " - ";
#endif
if (assigns[c[0].var()].isUndef()) {
c[0] = c[0].unsign()^final;
#ifdef VERBOSE_DEBUG_XOR
cout << "propagating ";
printLit(c[0]);
cout << endl;
cout << "propagation clause -- ";
printClause(*(Clause*)&c);
cout << endl << endl;
#endif
uncheckedEnqueue(c[0], (Clause*)&c);
} else if (!final) {
#ifdef VERBOSE_DEBUG_XOR
printf("conflict clause -- ");
printClause(*(Clause*)&c);
cout << endl << endl;
#endif
confl = (Clause*)&c;
qhead = trail.size();
// Copy the remaining watches:
while (i < end)
*j++ = *i++;
} else {
#ifdef VERBOSE_DEBUG_XOR
printf("xor satisfied\n");
#endif
Lit tmp(c[0]);
c[0] = c[1];
c[1] = tmp;
}
}
FoundWatch:
;
}
ws.shrink_(i - j);
return confl;
}
/*_________________________________________________________________________________________________
|
| 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 uint xsize = x->size();
const uint ysize = y->size();
// First criteria
if (xsize > 2 && ysize == 2) return 1;
if (ysize > 2 && xsize == 2) return 0;
if (x->oldActivity() == y->oldActivity())
return xsize > ysize;
else return x->oldActivity() < y->oldActivity();
}
bool reduceDB_ltGlucose::operator () (const Clause* x, const Clause* y) {
const uint xsize = x->size();
const uint ysize = y->size();
// First criteria
if (xsize > 2 && ysize == 2) return 1;
if (ysize > 2 && xsize == 2) return 0;
if (x->activity() > y->activity()) return 1;
if (x->activity() < y->activity()) return 0;
return xsize > ysize;
}
void Solver::reduceDB()
{
uint32_t i, j;
nbReduceDB++;
if (lastSelectedRestartType == dynamic_restart)
std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltGlucose());
else
std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltMiniSat());
#ifdef VERBOSE_DEBUG
std::cout << "Cleaning clauses" << std::endl;
for (uint i = 0; i != learnts.size(); i++) {
std::cout << "activity:" << learnts[i]->activity()
<< " \toldActivity:" << learnts[i]->oldActivity()
<< " \tsize:" << learnts[i]->size() << std::endl;
}
#endif
const uint removeNum = (double)learnts.size() / (double)RATIOREMOVECLAUSES;
for (i = j = 0; i != removeNum; i++){
//NOTE: The next instruciton only works if removeNum < learnts.size() (strictly smaller!!)
__builtin_prefetch(learnts[i+1], 0, 0);
if (learnts[i]->size() > 2 && !locked(*learnts[i]) && learnts[i]->activity() > 2) {
if (readdOldLearnts) {
detachClause(*learnts[i]);
removedLearnts.push(learnts[i]);
} else {
removeClause(*learnts[i]);
}
} else
learnts[j++] = learnts[i];
}
for (; i < learnts.size(); i++) {
learnts[j++] = learnts[i];
}
learnts.shrink(i - j);
}
const vec<Clause*>& Solver::get_learnts() const
{
return learnts;
}
const vec<Clause*>& Solver::get_sorted_learnts()
{
if (lastSelectedRestartType == dynamic_restart)
std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltGlucose());
else
std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltMiniSat());
return learnts;
}
const vector<Lit> Solver::get_unitary_learnts() const
{
vector<Lit> unitaries;
if (decisionLevel() > 0) {
for (uint32_t i = 0; i != trail_lim[0]; i++) {
unitaries.push_back(trail[i]);
}
}
return unitaries;
}
void Solver::dumpSortedLearnts(const char* file, const uint32_t maxSize)
{
FILE* outfile = fopen(file, "w");
if (!outfile) {
printf("Error: Cannot open file '%s' to write learnt clauses!\n", file);
exit(-1);
}
fprintf(outfile, "c \nc ---------\n");
fprintf(outfile, "c unitaries\n");
fprintf(outfile, "c ---------\n");
for (uint32_t i = 0, end = (trail_lim.size() > 0) ? trail_lim[0] : trail.size() ; i < end; i++) {
trail[i].printFull(outfile);
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
fprintf(outfile, "c name of var: %s\n", logger.get_var_name(trail[i].var()).c_str());
#endif //STATS_NEEDED
}
fprintf(outfile, "c conflicts %lu\n", (long unsigned int)conflicts);
fprintf(outfile, "c \nc ---------------------------------\n");
fprintf(outfile, "c learnt clauses from binaryClauses\n");
fprintf(outfile, "c ---------------------------------\n");
if (maxSize >= 2) {
for (uint i = 0; i != binaryClauses.size(); i++) {
if (binaryClauses[i]->learnt()) {
binaryClauses[i]->print(outfile);
}
}
}
fprintf(outfile, "c \nc ---------------------------------------\n");
fprintf(outfile, "c clauses representing 2-long XOR clauses\n");
fprintf(outfile, "c ---------------------------------------\n");
const vector<Lit>& table = varReplacer->getReplaceTable();
for (Var var = 0; var != table.size(); var++) {
Lit lit = table[var];
if (lit.var() == var)
continue;
fprintf(outfile, "%s%d %d 0\n", (!lit.sign() ? "-" : ""), lit.var()+1, var+1);
fprintf(outfile, "%s%d -%d 0\n", (lit.sign() ? "-" : ""), lit.var()+1, var+1);
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
fprintf(outfile, "c name of two vars that are anti/equivalent: '%s' and '%s'\n", logger.get_var_name(lit.var()).c_str(), logger.get_var_name(var).c_str());
#endif //STATS_NEEDED
}
fprintf(outfile, "c \nc --------------------n");
fprintf(outfile, "c clauses from learnts\n");
fprintf(outfile, "c --------------------n");
if (lastSelectedRestartType == dynamic_restart)
std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltGlucose());
else
std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltMiniSat());
for (int i = learnts.size()-1; i >= 0 ; i--) {
if (learnts[i]->size() <= maxSize) {
learnts[i]->print(outfile);
}
}
fclose(outfile);
}
const uint32_t Solver::getNumElimSubsume() const
{
return subsumer->getNumElimed();
}
const uint32_t Solver::getNumElimXorSubsume() const
{
return xorSubsumer->getNumElimed();
}
const uint32_t Solver::getNumXorTrees() const
{
return varReplacer->getNumTrees();
}
const uint32_t Solver::getNumXorTreesCrownSize() const
{
return varReplacer->getNumReplacedVars();
}
const double Solver::getTotalTimeSubsumer() const
{
return subsumer->getTotalTime();
}
const double Solver::getTotalTimeXorSubsumer() const
{
return xorSubsumer->getTotalTime();
}
void Solver::setMaxRestarts(const uint num)
{
maxRestarts = num;
}
inline int64_t abs64(int64_t a)
{
if (a < 0) return -a;
return a;
}
/*_________________________________________________________________________________________________
|
| simplify : [void] -> [bool]
|
| Description:
| Simplify the clause database according to the current top-level assigment. Currently, the only
| thing done here is the removal of satisfied clauses, but more things can be put here.
|________________________________________________________________________________________________@*/
const bool Solver::simplify()
{
testAllClauseAttach();
assert(decisionLevel() == 0);
if (!ok || propagate() != NULL) {
ok = false;
return false;
}
if (simpDB_props > 0) {
return true;
}
double slowdown = (100000.0/(double)binaryClauses.size());
slowdown = std::min(3.5, slowdown);
slowdown = std::max(0.2, slowdown);
double speedup = 50000000.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 (findBinaryXors && regularlyFindBinaryXors &&
(((double)abs64((int64_t)nbBin - (int64_t)lastNbBin + (int64_t)becameBinary)/BINARY_TO_XOR_APPROX) * slowdown) >
((double)order_heap.size() * PERCENTAGEPERFORMREPLACE * speedup)) {
lastSearchForBinaryXor = propagations;
clauseCleaner->cleanClauses(clauses, ClauseCleaner::clauses);
clauseCleaner->cleanClauses(learnts, ClauseCleaner::learnts);
clauseCleaner->removeSatisfied(binaryClauses, ClauseCleaner::binaryClauses);
if (!ok) return false;
testAllClauseAttach();
XorFinder xorFinder(*this, binaryClauses, ClauseCleaner::binaryClauses);
if (!xorFinder.doNoPart(2, 2)) return false;
testAllClauseAttach();
lastNbBin = nbBin;
becameBinary = 0;
}
// Remove satisfied clauses:
clauseCleaner->removeAndCleanAll();
testAllClauseAttach();
if (!ok) return false;
if (performReplace && !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 = clauses_literals + learnts_literals; // (shouldn't depend on stats really, but it will do for now)
testAllClauseAttach();
return true;
}
/*_________________________________________________________________________________________________
|
| search : (nof_conflicts : int) (nof_learnts : int) (params : const SearchParams&) -> [lbool]
|
| Description:
| Search for a model the specified number of conflicts, keeping the number of learnt clauses
| below the provided limit. NOTE! 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(int nof_conflicts, int nof_conflicts_fullrestart, const bool update)
{
assert(ok);
int conflictC = 0;
vec<Lit> learnt_clause;
llbool ret;
starts++;
if (restartType == static_restart)
staticStarts++;
else
dynStarts++;
#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();
for (;;) {
Clause* confl = propagate(update);
if (confl != NULL) {
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
ret = new_decision(nof_conflicts, nof_conflicts_fullrestart, conflictC);
if (ret != l_Nothing) return ret;
}
}
}
llbool Solver::new_decision(const int& nof_conflicts, const int& nof_conflicts_fullrestart, int& conflictC)
{
// Reached bound on number of conflicts?
switch (restartType) {
case dynamic_restart:
if (nbDecisionLevelHistory.isvalid() &&
((nbDecisionLevelHistory.getavg()) > (totalSumOfDecisionLevel / (double)(conflicts - conflictsAtLastSolve)))) {
#ifdef DEBUG_DYNAMIC_RESTART
if (nbDecisionLevelHistory.isvalid()) {
std::cout << "nbDecisionLevelHistory.getavg():" << nbDecisionLevelHistory.getavg() <<std::endl;
//std::cout << "calculated limit:" << ((double)(nbDecisionLevelHistory.getavg())*0.9*((double)fullStarts + 20.0)/20.0) << std::endl;
std::cout << "totalSumOfDecisionLevel:" << totalSumOfDecisionLevel << std::endl;
std::cout << "conflicts:" << conflicts<< std::endl;
std::cout << "conflictsAtLastSolve:" << conflictsAtLastSolve << std::endl;
std::cout << "conflicts-conflictsAtLastSolve:" << conflicts-conflictsAtLastSolve<< std::endl;
std::cout << "fullStarts:" << fullStarts << std::endl;
}
#endif
nbDecisionLevelHistory.fastclear();
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
progress_estimate = progressEstimate();
#endif
cancelUntil(0);
return l_Undef;
}
break;
case static_restart:
if (nof_conflicts >= 0 && conflictC >= nof_conflicts) {
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
progress_estimate = progressEstimate();
#endif
cancelUntil(0);
return l_Undef;
}
break;
case auto_restart:
assert(false);
break;
}
if (nof_conflicts_fullrestart >= 0 && (int)conflicts >= nof_conflicts_fullrestart) {
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
progress_estimate = progressEstimate();
#endif
cancelUntil(0);
return l_Undef;
}
// Simplify the set of problem clauses:
if (decisionLevel() == 0 && !simplify()) {
return l_False;
}
// Reduce the set of learnt clauses:
if (conflicts >= curRestart * nbclausesbeforereduce + nbCompensateSubsumer) {
curRestart ++;
reduceDB();
nbclausesbeforereduce += 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;
}
llbool Solver::handle_conflict(vec<Lit>& learnt_clause, Clause* confl, int& conflictC, const bool update)
{
#ifdef VERBOSE_DEBUG
cout << "Handling conflict: ";
for (uint i = 0; i < learnt_clause.size(); i++)
cout << learnt_clause[i].var()+1 << ",";
cout << endl;
#endif
int backtrack_level;
uint32_t nbLevels;
conflicts++;
conflictC++;
if (decisionLevel() == 0)
return l_False;
learnt_clause.clear();
Clause* c = analyze(confl, learnt_clause, backtrack_level, nbLevels, update);
if (update) {
#ifdef RANDOM_LOOKAROUND_SEARCHSPACE
avgBranchDepth.push(decisionLevel());
#endif //RANDOM_LOOKAROUND_SEARCHSPACE
if (restartType == dynamic_restart)
nbDecisionLevelHistory.push(nbLevels);
totalSumOfDecisionLevel += nbLevels;
} else {
conflictsAtLastSolve++;
}
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
logger.conflict(Logger::simple_confl_type, backtrack_level, confl->getGroup(), learnt_clause);
#endif
cancelUntil(backtrack_level);
#ifdef VERBOSE_DEBUG
cout << "Learning:";
for (uint 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 (c) {
detachClause(*c);
for (uint32_t i = 0; i != learnt_clause.size(); i++)
(*c)[i] = learnt_clause[i];
c->resize(learnt_clause.size());
if (c->learnt()) {
if (c->activity() > nbLevels)
c->setActivity(nbLevels); // LS
if (c->size() == 2)
nbBin++;
}
c->setStrenghtened();
} else {
c = Clause_new(learnt_clause, learnt_clause_group++, true);
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
logger.set_group_name(c->getGroup(), "learnt clause");
#endif
if (c->size() > 2) {
learnts.push(c);
c->setActivity(nbLevels); // LS
} else {
binaryClauses.push(c);
nbBin++;
}
}
if (nbLevels <= 2) nbDL2++;
attachClause(*c);
uncheckedEnqueue(learnt_clause[0], c);
}
varDecayActivity();
if (update && restartType == static_restart) claDecayActivity();
return l_Nothing;
}
double Solver::progressEstimate() const
{
double progress = 0;
double F = 1.0 / nVars();
for (uint32_t i = 0; i <= decisionLevel(); i++) {
int beg = i == 0 ? 0 : trail_lim[i - 1];
int end = i == decisionLevel() ? trail.size() : trail_lim[i];
progress += pow(F, (int)i) * (end - beg);
}
return progress / nVars();
}
#ifdef USE_GAUSS
void Solver::print_gauss_sum_stats()
{
if (gauss_matrixes.size() == 0 && verbosity >= 2) {
printf(" no matrixes found |\n");
return;
}
uint called = 0;
uint useful_prop = 0;
uint useful_confl = 0;
uint disabled = 0;
for (vector<Gaussian*>::const_iterator gauss = gauss_matrixes.begin(), end= gauss_matrixes.end(); gauss != end; gauss++) {
disabled += (*gauss)->get_disabled();
called += (*gauss)->get_called();
useful_prop += (*gauss)->get_useful_prop();
useful_confl += (*gauss)->get_useful_confl();
sum_gauss_unit_truths += (*gauss)->get_unit_truths();
//gauss->print_stats();
//gauss->print_matrix_stats();
}
sum_gauss_called += called;
sum_gauss_confl += useful_confl;
sum_gauss_prop += useful_prop;
if (verbosity >= 2) {
if (called == 0) {
printf(" disabled |\n");
} else {
printf(" %3.0lf%% |", (double)useful_prop/(double)called*100.0);
printf(" %3.0lf%% |", (double)useful_confl/(double)called*100.0);
printf(" %3.0lf%% |\n", 100.0-(double)disabled/(double)gauss_matrixes.size()*100.0);
}
}
}
#endif //USE_GAUSS
const bool Solver::chooseRestartType(const uint& lastFullRestart)
{
uint relativeStart = starts - lastFullRestart;
if (relativeStart > RESTART_TYPE_DECIDER_FROM && relativeStart < RESTART_TYPE_DECIDER_UNTIL) {
if (fixRestartType == auto_restart)
restartTypeChooser->addInfo();
if (relativeStart == (RESTART_TYPE_DECIDER_UNTIL-1)) {
RestartType tmp;
if (fixRestartType == auto_restart)
tmp = restartTypeChooser->choose();
else
tmp = fixRestartType;
if (tmp == dynamic_restart) {
nbDecisionLevelHistory.fastclear();
nbDecisionLevelHistory.initSize(100);
if (verbosity >= 2)
printf("c | Decided on dynamic restart strategy |\n");
} else {
if (verbosity >= 2)
printf("c | Decided on static restart strategy |\n");
#ifdef USE_GAUSS
if (!matrixFinder->findMatrixes()) return false;
#endif //USE_GAUSS
}
lastSelectedRestartType = tmp;
restartType = tmp;
restartTypeChooser->reset();
}
}
return true;
}
inline void Solver::setDefaultRestartType()
{
if (fixRestartType != auto_restart) restartType = fixRestartType;
else restartType = static_restart;
if (restartType == dynamic_restart) {
nbDecisionLevelHistory.fastclear();
nbDecisionLevelHistory.initSize(100);
}
lastSelectedRestartType = restartType;
}
const lbool Solver::simplifyProblem(const uint32_t numConfls)
{
testAllClauseAttach();
#ifdef USE_GAUSS
bool gauss_was_cleared = (gauss_matrixes.size() == 0);
clearGaussMatrixes();
#endif //USE_GAUSS
StateSaver savedState(*this);;
#ifdef BURST_SEARCH
if (verbosity >= 2)
std::cout << "c | " << std::setw(24) << " "
<< "Simplifying problem for " << std::setw(8) << numConfls << " confls"
<< std::setw(24) << " |" << std::endl;
random_var_freq = 1;
simplifying = true;
uint64_t origConflicts = conflicts;
#endif //BURST_SEARCH
lbool status = l_Undef;
#ifdef BURST_SEARCH
restartType = static_restart;
while(status == l_Undef && conflicts-origConflicts < numConfls) {
printRestartStat();
status = search(100, -1, false);
starts--;
}
if (status != l_Undef)
goto end;
printRestartStat();
#endif //BURST_SEARCH
if (doXorSubsumption && !xorSubsumer->simplifyBySubsumption()) {
status = l_False;
goto end;
}
testAllClauseAttach();
if (failedVarSearch && !failedVarSearcher->search((nClauses() < 500000 && order_heap.size() < 50000) ? 9000000 : 3000000)) {
status = l_False;
goto end;
}
testAllClauseAttach();
if (regularRemoveUselessBins
&& !failedVarSearcher->removeUslessBinFull<false>()) {
status = l_False;
goto end;
}
if (regularSubsumeWithNonExistBinaries
&& !subsumer->subsumeWithBinaries(false)) {
status = l_False;
goto end;
}
if (doSubsumption && !subsumer->simplifyBySubsumption()) {
status = l_False;
goto end;
}
testAllClauseAttach();
/*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, ClauseCleaner::clauses);
x.addAllXorAsNorm();
}
end:
#ifdef BURST_SEARCH
if (verbosity >= 2)
printf("c Simplifying finished |\n");
#endif //#ifdef BURST_SEARCH
savedState.restore();
simplifying = false;
#ifdef USE_GAUSS
if (status == l_Undef && !gauss_was_cleared && !matrixFinder->findMatrixes())
status = l_False;
#endif //USE_GAUSS
testAllClauseAttach();
return status;
}
const bool Solver::checkFullRestart(int& nof_conflicts, int& nof_conflicts_fullrestart, uint& lastFullRestart)
{
if (nof_conflicts_fullrestart > 0 && (int)conflicts >= nof_conflicts_fullrestart) {
#ifdef USE_GAUSS
clearGaussMatrixes();
#endif //USE_GAUSS
if (verbosity >= 2)
printf("c | Fully restarting |\n");
nof_conflicts = restart_first + (double)restart_first*restart_inc;
nof_conflicts_fullrestart = (double)nof_conflicts_fullrestart * FULLRESTART_MULTIPLIER_MULTIPLIER;
restartType = static_restart;
lastFullRestart = starts;
/*if (findNormalXors && clauses.size() < MAX_CLAUSENUM_XORFIND) {
XorFinder xorFinder(this, clauses, ClauseCleaner::clauses);
if (!xorFinder.doNoPart(3, 10))
return false;
}*/
if (doPartHandler && !partHandler->handle())
return false;
//calculateDefaultPolarities();
fullStarts++;
}
return true;
}
inline void Solver::performStepsBeforeSolve()
{
assert(qhead == trail.size());
testAllClauseAttach();
if (performReplace && !varReplacer->performReplace()) return;
if (conflicts == 0 && learnts.size() == 0
&& noLearntBinaries()) {
if (subsumeWithNonExistBinaries && !subsumer->subsumeWithBinaries(true)) return;
if (removeUselessBins && !failedVarSearcher->removeUslessBinFull<true>()) return;
}
if(!ok) return;
testAllClauseAttach();
if (doSubsumption
&& !libraryUsage
&& clauses.size() + binaryClauses.size() + learnts.size() < 4800000
&& !subsumer->simplifyBySubsumption())
return;
if (conflicts == 0 && learnts.size() == 0
&& noLearntBinaries()) {
if (subsumeWithNonExistBinaries && !subsumer->subsumeWithBinaries(true)) return;
if (removeUselessBins && !failedVarSearcher->removeUslessBinFull<true>()) return;
}
if(!ok) return;
testAllClauseAttach();
if (findBinaryXors && binaryClauses.size() < MAX_CLAUSENUM_XORFIND) {
XorFinder xorFinder(*this, binaryClauses, ClauseCleaner::binaryClauses);
if (!xorFinder.doNoPart(2, 2)) return;
if (performReplace && !varReplacer->performReplace(true)) return;
}
testAllClauseAttach();
if (findNormalXors && clauses.size() < MAX_CLAUSENUM_XORFIND) {
XorFinder xorFinder(*this, clauses, ClauseCleaner::clauses);
if (!xorFinder.doNoPart(3, 7)) return;
}
if (xorclauses.size() > 1) {
testAllClauseAttach();
if (doXorSubsumption && !xorSubsumer->simplifyBySubsumption())
return;
testAllClauseAttach();
if (performReplace && !varReplacer->performReplace())
return;
}
}
void Solver::checkSolution()
{
// Extend & check:
model.growTo(nVars());
for (Var var = 0; var != nVars(); var++) model[var] = value(var);
verifyModel();
model.clear();
}
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());
if (libraryCNFFile)
fprintf(libraryCNFFile, "c Solver::solve() called\n");
model.clear();
conflict.clear();
#ifdef USE_GAUSS
clearGaussMatrixes();
#endif //USE_GAUSS
setDefaultRestartType();
totalSumOfDecisionLevel = 0;
conflictsAtLastSolve = conflicts;
#ifdef RANDOM_LOOKAROUND_SEARCHSPACE
avgBranchDepth.fastclear();
avgBranchDepth.initSize(500);
#endif //RANDOM_LOOKAROUND_SEARCHSPACE
starts = 0;
assumps.copyTo(assumptions);
if(assumptions.size()>0 && varReplacer->getNumLastReplacedVars())
for (uint32_t i = 0; i != assumptions.size(); i++)
assumptions[i] = varReplacer->getReplaceTable()[assumptions[i].var()] ^ assumptions[i].sign();
int nof_conflicts = restart_first;
int nof_conflicts_fullrestart = restart_first * FULLRESTART_MULTIPLIER + conflicts;
//nof_conflicts_fullrestart = -1;
uint lastFullRestart = starts;
lbool status = l_Undef;
uint64_t nextSimplify = restart_first * SIMPLIFY_MULTIPLIER + conflicts;
if (nClauses() * learntsize_factor < nbclausesbeforereduce) {
if (nClauses() * learntsize_factor < nbclausesbeforereduce/2)
nbclausesbeforereduce = nbclausesbeforereduce/4;
else
nbclausesbeforereduce = (nClauses() * learntsize_factor)/2;
}
testAllClauseAttach();
findAllAttach();
if (conflicts == 0) {
performStepsBeforeSolve();
if (!ok) return l_False;
printStatHeader();
}
if(assumptions.size()>0 &&
(varReplacer->getNumLastReplacedVars() || subsumer->getNumElimed() || xorSubsumer->getNumElimed())) {
for (uint32_t i = 0; i != assumptions.size(); i++) {
assumptions[i] = varReplacer->getReplaceTable()[assumptions[i].var()] ^ assumptions[i].sign();
if (subsumer->getVarElimed()[assumptions[i].var()] && !subsumer->unEliminate(assumptions[i].var())) {
ok = false;
return l_False;
}
if (xorSubsumer->getVarElimed()[assumptions[i].var()] && !xorSubsumer->unEliminate(assumptions[i].var())) {
ok = false;
return l_False;
}
}
}
calculateDefaultPolarities();
// Search:
while (status == l_Undef && starts < maxRestarts) {
#ifdef DEBUG_VARELIM
assert(subsumer->checkElimedUnassigned());
assert(xorSubsumer->checkElimedUnassigned());
#endif //DEBUG_VARELIM
if (schedSimplification && conflicts >= nextSimplify) {
status = simplifyProblem(500);
nextSimplify = conflicts * 1.5;
if (status != l_Undef) break;
}
printRestartStat();
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis) {
logger.end(Logger::restarting);
logger.begin();
}
#endif
status = search(nof_conflicts, nof_conflicts_fullrestart);
nof_conflicts = (double)nof_conflicts * restart_inc;
if (status != l_Undef) break;
if (!checkFullRestart(nof_conflicts, nof_conflicts_fullrestart, lastFullRestart))
return l_False;
if (!chooseRestartType(lastFullRestart))
return l_False;
#ifdef RANDOM_LOOKAROUND_SEARCHSPACE
//if (avgBranchDepth.isvalid())
// std::cout << "avg branch depth:" << avgBranchDepth.getavg() << std::endl;
#endif //RANDOM_LOOKAROUND_SEARCHSPACE
}
printEndSearchStat();
#ifdef USE_GAUSS
for (uint i = 0; i < gauss_matrixes.size(); i++)
delete gauss_matrixes[i];
gauss_matrixes.clear();
#endif //USE_GAUSS
#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) {
if (greedyUnbound) {
double time = cpuTime();
FindUndef finder(*this);
const uint unbounded = finder.unRoll();
if (verbosity >= 1)
printf("c Greedy unbounding :%5.2lf s, unbounded: %7d vars\n", cpuTime()-time, unbounded);
}
partHandler->addSavedState();
varReplacer->extendModelPossible();
#ifndef NDEBUG
checkSolution();
#endif
if (subsumer->getNumElimed() || xorSubsumer->getNumElimed()) {
#ifdef VERBOSE_DEBUG
std::cout << "Solution needs extension. Extending." << std::endl;
#endif //VERBOSE_DEBUG
Solver s;
s.doSubsumption = false;
s.performReplace = false;
s.findBinaryXors = false;
s.findNormalXors = false;
s.failedVarSearch = false;
s.conglomerateXors = false;
s.greedyUnbound = greedyUnbound;
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) {
vec<Lit> tmp;
tmp.push(Lit(var, value(var) == l_False));
s.addClause(tmp);
}
}
varReplacer->extendModelImpossible(s);
subsumer->extendModel(s);
xorSubsumer->extendModel(s);
status = s.solve();
if (status != l_True) {
printf("c ERROR! Extension of model failed!\n");
assert(status == l_True);
exit(-1);
}
#ifdef VERBOSE_DEBUG
std::cout << "Solution extending finished." << std::endl;
#endif
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() == NULL);
if (!ok) {
printf("c ERROR! Extension of model failed!\n");
assert(ok);
exit(-1);
}
}
#ifndef NDEBUG
checkSolution();
#endif
//Copy model:
model.growTo(nVars());
for (Var var = 0; var != nVars(); var++) model[var] = value(var);
}
if (status == l_False) {
if (conflict.size() == 0)
ok = false;
}
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis) {
if (status == l_True)
logger.end(Logger::model_found);
else if (status == l_False)
logger.end(Logger::unsat_model_found);
else if (status == l_Undef)
logger.end(Logger::restarting);
}
#endif
#ifdef LS_STATS_NBBUMP
for(int i=0;i<learnts.size();i++)
printf("## %d %d %d\n", learnts[i]->size(),learnts[i]->activity(),
(uint)learnts[i]->nbBump());
#endif
cancelUntil(0);
if (doPartHandler && status != l_False) partHandler->readdRemovedClauses();
restartTypeChooser->reset();
#ifdef VERBOSE_DEBUG
std::cout << "Solver::solve() finished" << std::endl;
#endif
return status;
}
//=================================================================================================
// Debug methods:
bool Solver::verifyXorClauses(const vec<XorClause*>& cs) const
{
#ifdef VERBOSE_DEBUG
cout << "Checking xor-clauses whether they have been properly satisfied." << endl;;
#endif
bool failed = false;
for (uint32_t i = 0; i != xorclauses.size(); i++) {
XorClause& c = *xorclauses[i];
bool final = c.xor_clause_inverted();
#ifdef VERBOSE_DEBUG
XorClause* c2 = XorClause_new(c, c.xor_clause_inverted(), c.getGroup());
std::sort(c2->getData(), c2->getData()+ c2->size());
c2->plainPrint();
clauseFree(c2);
#endif
for (uint j = 0; j < c.size(); j++) {
assert(modelValue(c[j].unsign()) != l_Undef);
final ^= (modelValue(c[j].unsign()) == l_True);
}
if (!final) {
printf("unsatisfied clause: ");
xorclauses[i]->plainPrint();
failed = true;
}
}
return failed;
}
bool Solver::verifyClauses(const vec<Clause*>& cs) const
{
#ifdef VERBOSE_DEBUG
cout << "Checking clauses whether they have been properly satisfied." << endl;;
#endif
bool failed = false;
for (uint32_t i = 0; i != cs.size(); i++) {
Clause& c = *cs[i];
for (uint j = 0; j < c.size(); j++)
if (modelValue(c[j]) == l_True)
goto next;
printf("unsatisfied clause: ");
cs[i]->plainPrint();
failed = true;
next:
;
}
return failed;
}
void Solver::verifyModel()
{
assert(!verifyClauses(clauses));
assert(!verifyClauses(binaryClauses));
assert(!verifyXorClauses(xorclauses));
if (verbosity >=1)
printf("c Verified %d clauses.\n", clauses.size() + xorclauses.size());
}
void Solver::checkLiteralCount()
{
// Check that sizes are calculated correctly:
int cnt = 0;
for (uint32_t i = 0; i != clauses.size(); i++)
cnt += clauses[i]->size();
for (uint32_t i = 0; i != xorclauses.size(); i++)
cnt += xorclauses[i]->size();
if ((int)clauses_literals != cnt) {
fprintf(stderr, "literal count: %d, real value = %d\n", (int)clauses_literals, cnt);
assert((int)clauses_literals == cnt);
}
}
void Solver::printStatHeader() const
{
#ifdef STATS_NEEDED
if (verbosity >= 1 && !(dynamic_behaviour_analysis && logger.statistics_on)) {
#else
if (verbosity >= 1) {
#endif
printf("c ============================[ Search Statistics ]========================================\n");
printf("c | Conflicts | ORIGINAL | LEARNT | GAUSS |\n");
printf("c | | Vars Clauses Literals | Limit Clauses Lit/Cl | Prop Confl On |\n");
printf("c =========================================================================================\n");
}
}
void Solver::printRestartStat()
{
if (verbosity >= 2) {
printf("c | %9d | %7d %8d %8d | %8d %8d %6.0f |", (int)conflicts, (int)order_heap.size(), (int)(nClauses()-nbBin), (int)clauses_literals, (int)(nbclausesbeforereduce*curRestart+nbCompensateSubsumer), (int)(nLearnts()+nbBin), (double)learnts_literals/(double)(nLearnts()+nbBin));
}
#ifdef USE_GAUSS
print_gauss_sum_stats();
#else //USE_GAUSS
if (verbosity >= 2) {
printf(" |\n");
}
#endif //USE_GAUSS
}
void Solver::printEndSearchStat()
{
#ifdef STATS_NEEDED
if (verbosity >= 1 && !(dynamic_behaviour_analysis && logger.statistics_on)) {
#else
if (verbosity >= 1) {
#endif //STATS_NEEDED
printf("c ====================================================================");
#ifdef USE_GAUSS
print_gauss_sum_stats();
if (verbosity == 1) printf("=====================\n");
#else //USE_GAUSS
printf("\n");
#endif //USE_GAUSS
}
}
#ifdef DEBUG_ATTACH
void Solver::testAllClauseAttach() const
{
for (Clause *const*it = clauses.getData(), *const*end = clauses.getDataEnd(); it != end; it++) {
const Clause& c = **it;
if (c.size() > 2) {
assert(findWatchedCl(watches[(~c[0]).toInt()], &c));
assert(findWatchedCl(watches[(~c[1]).toInt()], &c));
} else {
assert(findWatchedBinCl(binwatches[(~c[0]).toInt()], &c));
assert(findWatchedBinCl(binwatches[(~c[1]).toInt()], &c));
}
}
for (Clause *const*it = binaryClauses.getData(), *const*end = binaryClauses.getDataEnd(); it != end; it++) {
const Clause& c = **it;
assert(c.size() == 2);
assert(findWatchedBinCl(binwatches[(~c[0]).toInt()], &c));
assert(findWatchedBinCl(binwatches[(~c[1]).toInt()], &c));
}
for (XorClause *const*it = xorclauses.getData(), *const*end = xorclauses.getDataEnd(); it != end; it++) {
const XorClause& c = **it;
assert(find(xorwatches[c[0].var()], &c));
assert(find(xorwatches[c[1].var()], &c));
if (assigns[c[0].var()]!=l_Undef || assigns[c[1].var()]!=l_Undef) {
for (uint i = 0; i < c.size();i++) {
assert(assigns[c[i].var()] != l_Undef);
}
}
}
}
void Solver::findAllAttach() const
{
for (uint32_t i = 0; i < binwatches.size(); i++) {
for (uint32_t i2 = 0; i2 < binwatches[i].size(); i2++) {
assert(findClause(binwatches[i][i2].clause));
}
}
for (uint32_t i = 0; i < watches.size(); i++) {
for (uint32_t i2 = 0; i2 < watches[i].size(); i2++) {
assert(findClause(watches[i][i2].clause));
}
}
for (uint32_t i = 0; i < xorwatches.size(); i++) {
for (uint32_t i2 = 0; i2 < xorwatches[i].size(); i2++) {
assert(findClause(xorwatches[i][i2]));
}
}
}
const bool Solver::findClause(XorClause* c) const
{
for (uint32_t i = 0; i < xorclauses.size(); i++) {
if (xorclauses[i] == c) return true;
}
return false;
}
const bool Solver::findClause(Clause* c) const
{
for (uint32_t i = 0; i < binaryClauses.size(); i++) {
if (binaryClauses[i] == c) return true;
}
for (uint32_t i = 0; i < clauses.size(); i++) {
if (clauses[i] == c) return true;
}
for (uint32_t i = 0; i < learnts.size(); i++) {
if (learnts[i] == c) return true;
}
vec<Clause*> cs = varReplacer->getClauses();
for (uint32_t i = 0; i < cs.size(); i++) {
if (cs[i] == c) return true;
}
return false;
}
#endif //DEBUG_ATTACH
const bool Solver::noLearntBinaries() const
{
for (uint32_t i = 0; i < binaryClauses.size(); i++) {
if (binaryClauses[i]->learnt()) return false;
}
return true;
}