/****************************************************************************************[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 #include #include #include #include #include #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 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& ps, bool xor_clause_inverted, const uint32_t group); template XorClause* Solver::addXorClauseInt(XorClause& ps, bool xor_clause_inverted, const uint32_t group); template 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& 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 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& ps, const uint group, const uint32_t activity); template 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& ps, const uint group); template 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& 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::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& cs, vector& 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& cs, vector& 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 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::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 bool subset(const T1& A, const T2& B, vector& 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&) (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& 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& 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 & 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& 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 & 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& 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 & 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 & 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 Clause* Solver::propagateBinExcept(const Lit& exceptLit) { while (qhead < trail.size()) { Lit p = trail[qhead++]; vec & 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 (const Lit& exceptLit); template Clause* Solver::propagateBinExcept (const Lit& exceptLit); template Clause* Solver::propagateBinOneLevel() { Lit p = trail[qhead]; vec & 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 (); template Clause* Solver::propagateBinOneLevel (); template 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& 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& Solver::get_learnts() const { return learnts; } const vec& 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 Solver::get_unitary_learnts() const { vector 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& 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::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 learnt_clause; llbool ret; starts++; if (restartType == static_restart) staticStarts++; else dynStarts++; #ifdef USE_GAUSS for (vector::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::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() <= 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& 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::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()) { 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()) 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()) 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& 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 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;isize(),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& 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& 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 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; }