diff options
Diffstat (limited to 'src/prop/cryptominisat/Solver')
67 files changed, 21353 insertions, 0 deletions
diff --git a/src/prop/cryptominisat/Solver/BitArray.h b/src/prop/cryptominisat/Solver/BitArray.h new file mode 100644 index 000000000..2b67998ae --- /dev/null +++ b/src/prop/cryptominisat/Solver/BitArray.h @@ -0,0 +1,188 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#ifndef BITARRAY_H +#define BITARRAY_H + +//#define DEBUG_BITARRAY + +#include <string.h> +#include <assert.h> +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +namespace CMSat +{ + +class BitArray +{ +public: + BitArray() : + size(0) + , mp(NULL) + { + } + + BitArray(const BitArray& b) : + size(b.size) + { + mp = new uint64_t[size]; + memcpy(mp, b.mp, sizeof(uint64_t)*size); + } + + BitArray& operator=(const BitArray& b) + { + if (size != b.size) { + delete[] mp; + size = b.size; + mp = new uint64_t[size]; + } + memcpy(mp, b.mp, sizeof(uint64_t)*size); + + return *this; + } + + BitArray& operator&=(const BitArray& b) + { + assert(size == b.size); + uint64_t* t1 = mp; + uint64_t* t2 = b.mp; + for (uint64_t i = 0; i < size; i++) { + *t1 &= *t2; + t1++; + t2++; + } + + return *this; + } + + BitArray& removeThese(const BitArray& b) + { + assert(size == b.size); + uint64_t* t1 = mp; + uint64_t* t2 = b.mp; + for (uint64_t i = 0; i < size; i++) { + *t1 &= ~(*t2); + t1++; + t2++; + } + + return *this; + } + + template<class T> + BitArray& removeThese(const T& rem) + { + for (uint32_t i = 0; i < rem.size(); i++) { + clearBit(rem[i]); + } + + return *this; + } + + template<class T> + BitArray& removeTheseLit(const T& rem) + { + for (uint32_t i = 0; i < rem.size(); i++) { + clearBit(rem[i].var()); + } + + return *this; + } + + void resize(uint32_t _size, const bool fill) + { + _size = _size/64 + (bool)(_size%64); + if (size != _size) { + delete[] mp; + size = _size; + mp = new uint64_t[size]; + } + if (fill) setOne(); + else setZero(); + } + + ~BitArray() + { + delete[] mp; + } + + inline bool isZero() const + { + const uint64_t* mp2 = (const uint64_t*)mp; + + for (uint32_t i = 0; i < size; i++) { + if (mp2[i]) return false; + } + return true; + } + + inline void setZero() + { + memset(mp, 0, size*sizeof(uint64_t)); + } + + inline void setOne() + { + memset(mp, 0xff, size*sizeof(uint64_t)); + } + + inline void clearBit(const uint32_t i) + { + #ifdef DEBUG_BITARRAY + assert(size*64 > i); + #endif + + mp[i/64] &= ~((uint64_t)1 << (i%64)); + } + + inline void setBit(const uint32_t i) + { + #ifdef DEBUG_BITARRAY + assert(size*64 > i); + #endif + + mp[i/64] |= ((uint64_t)1 << (i%64)); + } + + inline bool operator[](const uint32_t& i) const + { + #ifdef DEBUG_BITARRAY + assert(size*64 > i); + #endif + + return (mp[i/64] >> (i%64)) & 1; + } + + inline uint32_t getSize() const + { + return size*64; + } + +private: + + uint32_t size; + uint64_t* mp; +}; + +} + +#endif //BITARRAY_H + diff --git a/src/prop/cryptominisat/Solver/BothCache.cpp b/src/prop/cryptominisat/Solver/BothCache.cpp new file mode 100644 index 000000000..3ffc78f7e --- /dev/null +++ b/src/prop/cryptominisat/Solver/BothCache.cpp @@ -0,0 +1,114 @@ +/*************************************************************************** +CryptoMiniSat -- Copyright (c) 2010 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "BothCache.h" +#include "time_mem.h" +#include <iomanip> +#include "VarReplacer.h" +#include "Subsumer.h" +#include "XorSubsumer.h" + +namespace CMSat { + +BothCache::BothCache(Solver& _solver) : + solver(_solver) +{} + +bool BothCache::tryBoth() +{ + vec<bool> seen(solver.nVars(), 0); + vec<bool> val(solver.nVars(), 0); + vec<Lit> tmp; + uint32_t bProp = 0; + uint32_t bXProp = 0; + double myTime = cpuTime(); + uint32_t backupTrailSize = solver.trail.size(); + + for (Var var = 0; var < solver.nVars(); var++) { + if (solver.value(var) != l_Undef + || solver.subsumer->getVarElimed()[var] + || solver.xorSubsumer->getVarElimed()[var] + || solver.varReplacer->getReplaceTable()[var].var() != var) + continue; + + Lit lit = Lit(var, false); + vector<Lit> const* cache1; + vector<Lit> const* cache2; + + bool startWithTrue; + if (solver.transOTFCache[lit.toInt()].lits.size() < solver.transOTFCache[(~lit).toInt()].lits.size()) { + cache1 = &solver.transOTFCache[lit.toInt()].lits; + cache2 = &solver.transOTFCache[(~lit).toInt()].lits; + startWithTrue = false; + } else { + cache1 = &solver.transOTFCache[(~lit).toInt()].lits; + cache2 = &solver.transOTFCache[lit.toInt()].lits; + startWithTrue = true; + } + + if (cache1->size() == 0) continue; + + for (vector<Lit>::const_iterator it = cache1->begin(), end = cache1->end(); it != end; it++) { + seen[it->var()] = true; + val[it->var()] = it->sign(); + } + + for (vector<Lit>::const_iterator it = cache2->begin(), end = cache2->end(); it != end; it++) { + if (seen[it->var()]) { + Var var2 = it->var(); + if (solver.subsumer->getVarElimed()[var2] + || solver.xorSubsumer->getVarElimed()[var2] + || solver.varReplacer->getReplaceTable()[var2].var() != var2) + continue; + + if (val[it->var()] == it->sign()) { + tmp.clear(); + tmp.push(*it); + solver.addClauseInt(tmp, true); + if (!solver.ok) goto end; + bProp++; + } else { + tmp.clear(); + tmp.push(Lit(var, false)); + tmp.push(Lit(it->var(), false)); + bool sign = true ^ startWithTrue ^ it->sign(); + solver.addXorClauseInt(tmp, sign); + if (!solver.ok) goto end; + bXProp++; + } + } + } + + for (vector<Lit>::const_iterator it = cache1->begin(), end = cache1->end(); it != end; it++) { + seen[it->var()] = false; + } + } + + end: + if (solver.conf.verbosity >= 1) { + std::cout << "c Cache " << + " BProp: " << bProp << + " Set: " << (solver.trail.size() - backupTrailSize) << + " BXProp: " << bXProp << + " T: " << (cpuTime() - myTime) << + std::endl; + } + + return solver.ok; +} + +} diff --git a/src/prop/cryptominisat/Solver/BothCache.h b/src/prop/cryptominisat/Solver/BothCache.h new file mode 100644 index 000000000..72457319d --- /dev/null +++ b/src/prop/cryptominisat/Solver/BothCache.h @@ -0,0 +1,20 @@ +#ifndef BOTHCACHE_H +#define BOTHCACHE_H + +#include "Solver.h" + +namespace CMSat { + +class BothCache +{ + public: + BothCache(Solver& solver); + bool tryBoth(); + + private: + Solver& solver; +}; + +} + +#endif //BOTHCACHE_H diff --git a/src/prop/cryptominisat/Solver/BoundedQueue.h b/src/prop/cryptominisat/Solver/BoundedQueue.h new file mode 100644 index 000000000..f7f40c158 --- /dev/null +++ b/src/prop/cryptominisat/Solver/BoundedQueue.h @@ -0,0 +1,96 @@ +/*****************************************************************************************[Queue.h] +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +2008 - Gilles Audemard, Laurent Simon +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +Original code by MiniSat and glucose authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3 licence. +**************************************************************************************************/ + +#ifndef BOUNDEDQUEUE_H +#define BOUNDEDQUEUE_H + +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#include "Vec.h" + +namespace CMSat { + +template <class T> +class bqueue { + vec<T> elems; + uint32_t first; + uint32_t last; + int64_t sumofqueue; + int64_t sumOfAllElems; + uint64_t totalNumElems; + uint32_t maxsize; + uint32_t queuesize; // Number of current elements (must be < maxsize !) + +public: + bqueue(void) : + first(0) + , last(0) + , sumofqueue(0) + , sumOfAllElems(0) + , totalNumElems(0) + , maxsize(0) + , queuesize(0) + {} + + void initSize(const uint32_t size) {growTo(size);} // Init size of bounded size queue + + void push(const T x) { + if (queuesize==maxsize) { + assert(last==first); // The queue is full, next value to enter will replace oldest one + sumofqueue -= elems[last]; + if ((++last) == maxsize) last = 0; + } else + queuesize++; + sumofqueue += x; + sumOfAllElems += x; + totalNumElems++; + elems[first] = x; + if ((++first) == maxsize) first = 0; + } + + const T peek() const { assert(queuesize>0); return elems[last]; } + void pop() {sumofqueue-=elems[last]; queuesize--; if ((++last) == maxsize) last = 0;} + + int64_t getsum() const {return sumofqueue;} + uint32_t getAvgUInt() const {return (uint64_t)sumofqueue/(uint64_t)queuesize;} + double getAvgDouble() const {return (double)sumofqueue/(double)queuesize;} + double getAvgAllDouble() const {return (double)sumOfAllElems/(double)totalNumElems;} + uint64_t getTotalNumeElems() const {return totalNumElems;} + int isvalid() const {return (queuesize==maxsize);} + + void growTo(const uint32_t size) { + elems.growTo(size); + first=0; maxsize=size; queuesize = 0; + for(uint32_t i=0;i<size;i++) elems[i]=0; + } + + void fastclear() {first = 0; last = 0; queuesize=0; sumofqueue=0;} // to be called after restarts... Discard the queue + + int size(void) { return queuesize; } + + void clear(bool dealloc = false) { + elems.clear(dealloc); + first = 0; + last = 0; + maxsize=0; + queuesize=0; + sumofqueue=0; + + totalNumElems = 0; + sumOfAllElems = 0; + } +}; + +} + +#endif //BOUNDEDQUEUE_H diff --git a/src/prop/cryptominisat/Solver/CSet.h b/src/prop/cryptominisat/Solver/CSet.h new file mode 100644 index 000000000..de06ea38f --- /dev/null +++ b/src/prop/cryptominisat/Solver/CSet.h @@ -0,0 +1,209 @@ +/************************************************************************************************** +From: Solver.C -- (C) Niklas Een, Niklas Sorensson, 2004 +**************************************************************************************************/ + +#ifndef CSET_H +#define CSET_H + +#include "Vec.h" +#include <limits> +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +namespace CMSat { + +class Clause; + +/** +@brief A class to hold a clause and a related index + +This class is used in Subsumer. Basically, the index could be added to the +Clause class, but it would take space, and that would slow down the solving. + +NOTE: On 64-bit systems, this datastructure needs 128 bits :O +*/ +class ClauseSimp +{ + public: + ClauseSimp(Clause* c, const uint32_t _index) : + clause(c) + , index(_index) + {} + + Clause* clause; ///<The clause to be stored + uint32_t index; ///<The index of the clause in Subsumer::clauses +}; + +/** +@brief Used to quicky add, remove and iterate through a clause set + +Used in Subsumer to put into a set all clauses that need to be treated +*/ +class CSet { + vec<uint32_t> where; ///<Map clause ID to position in 'which'. + vec<ClauseSimp> which; ///< List of clauses (for fast iteration). May contain 'Clause_NULL'. + vec<uint32_t> free; ///<List of positions holding 'Clause_NULL'. + + public: + //ClauseSimp& operator [] (uint32_t index) { return which[index]; } + void reserve(uint32_t size) { where.reserve(size);} + //uint32_t size(void) const { return which.size(); } + ///@brief Number of elements in the set + uint32_t nElems(void) const { return which.size() - free.size(); } + + /** + @brief Add a clause to the set + */ + bool add(const ClauseSimp& c) { + assert(c.clause != NULL); + where.growTo(c.index+1, std::numeric_limits<uint32_t>::max()); + if (where[c.index] != std::numeric_limits<uint32_t>::max()) { + return false; + } + if (free.size() > 0){ + where[c.index] = free.last(); + which[free.last()] = c; + free.pop(); + }else{ + where[c.index] = which.size(); + which.push(c); + } + return true; + } + + bool alreadyIn(const ClauseSimp& c) const { + assert(c.clause != NULL); + if (where.size() < c.index+1) return false; + if (where[c.index] != std::numeric_limits<uint32_t>::max()) + return true; + return false; + } + + /** + @brief Remove clause from set + + Handles it correctly if the clause was not in the set anyway + */ + bool exclude(const ClauseSimp& c) { + assert(c.clause != NULL); + if (c.index >= where.size() || where[c.index] == std::numeric_limits<uint32_t>::max()) { + //not inside + return false; + } + free.push(where[c.index]); + which[where[c.index]].clause = NULL; + where[c.index] = std::numeric_limits<uint32_t>::max(); + return true; + } + + /** + @brief Fully clear the set + */ + void clear(void) { + for (uint32_t i = 0; i < which.size(); i++) { + if (which[i].clause != NULL) { + where[which[i].index] = std::numeric_limits<uint32_t>::max(); + } + } + which.clear(); + free.clear(); + } + + /** + @brief A normal iterator to iterate through the set + + No other way exists of iterating correctly. + */ + class iterator + { + public: + iterator(ClauseSimp* _it) : + it(_it) + {} + + void operator++() + { + it++; + } + + bool operator!=(const iterator& iter) const + { + return (it != iter.it);; + } + + ClauseSimp& operator*() { + return *it; + } + + ClauseSimp*& operator->() { + return it; + } + private: + ClauseSimp* it; + }; + + /** + @brief A constant iterator to iterate through the set + + No other way exists of iterating correctly. + */ + class const_iterator + { + public: + const_iterator(const ClauseSimp* _it) : + it(_it) + {} + + void operator++() + { + it++; + } + + bool operator!=(const const_iterator& iter) const + { + return (it != iter.it);; + } + + const ClauseSimp& operator*() { + return *it; + } + + const ClauseSimp*& operator->() { + return it; + } + private: + const ClauseSimp* it; + }; + + ///@brief Get starting iterator + iterator begin() + { + return iterator(which.getData()); + } + + ///@brief Get ending iterator + iterator end() + { + return iterator(which.getData() + which.size()); + } + + ///@brief Get starting iterator (constant version) + const_iterator begin() const + { + return const_iterator(which.getData()); + } + + ///@brief Get ending iterator (constant version) + const_iterator end() const + { + return const_iterator(which.getData() + which.size()); + } +}; + +} + +#endif //CSET_H + diff --git a/src/prop/cryptominisat/Solver/Clause.h b/src/prop/cryptominisat/Solver/Clause.h new file mode 100644 index 000000000..e47857add --- /dev/null +++ b/src/prop/cryptominisat/Solver/Clause.h @@ -0,0 +1,344 @@ +/***************************************************************************** +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +glucose -- Gilles Audemard, Laurent Simon (2008) +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +Original code by MiniSat and glucose authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3 licence. +******************************************************************************/ + +#ifndef CLAUSE_H +#define CLAUSE_H + +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#include <cstdio> +#include <vector> +#include <sys/types.h> +#include <string.h> + +#include "SolverTypes.h" +#include "constants.h" +#include "Watched.h" +#include "Alg.h" +#include "constants.h" + +namespace CMSat { + +template <class T> +uint32_t calcAbstraction(const T& ps) { + uint32_t abstraction = 0; + for (uint32_t i = 0; i != ps.size(); i++) + abstraction |= 1 << (ps[i].var() & 31); + return abstraction; +} + +class MatrixFinder; +class ClauseAllocator; + +/** +@brief Holds a clause. Does not allocate space for literals + +Literals are allocated by an external allocator that allocates enough space +for the class that it can hold the literals as well. I.e. it malloc()-s + sizeof(Clause)+LENGHT*sizeof(Lit) +to hold the clause. +*/ +struct Clause +{ +protected: + + uint32_t isLearnt:1; ///<Is the clause a learnt clause? + uint32_t changed:1; ///<Var inside clause has been changed + /** + @brief Is the XOR equal to 1 or 0? + + i.e. "a + b" = TRUE or FALSE? -- we only have variables inside xor clauses, + so this is important to know + + NOTE: ONLY set if the clause is an xor clause. + */ + uint32_t isXorEqualFalse:1; + uint32_t isXorClause:1; ///< Is the clause an XOR clause? + uint32_t isRemoved:1; ///<Is this clause queued for removal because of usless binary removal? + uint32_t isFreed:1; ///<Has this clause been marked as freed by the ClauseAllocator ? + uint32_t glue:MAX_GLUE_BITS; ///<Clause glue -- clause activity according to GLUCOSE + uint32_t mySize:18; ///<The current size of the clause + + float miniSatAct; ///<Clause activity according to MiniSat + + uint32_t abst; //Abstraction of clause + +#ifdef _MSC_VER +public: +#endif //_MSC_VER + template<class V> + Clause(const V& ps, const bool learnt) + { + isFreed = false; + glue = 0; //To stop valgrind from complaining + isXorEqualFalse = false; //To stop valgrind from complaining + isXorClause = false; + assert(ps.size() > 2); + mySize = ps.size(); + isLearnt = learnt; + isRemoved = false; + + assert(ps.size() > 0); + memcpy(getData(), ps.getData(), ps.size()*sizeof(Lit)); + miniSatAct = 0; + setChanged(); + } + +public: + friend class ClauseAllocator; + + uint32_t size() const + { + return mySize; + } + + bool getChanged() const + { + return changed; + } + + void setChanged() + { + changed = 1; + } + + void unsetChanged() + { + changed = 0; + } + + void shrink (const uint32_t i) + { + assert(i <= size()); + mySize -= i; + if (i > 0) + setChanged(); + } + + void pop() + { + shrink(1); + } + + bool isXor() const + { + return isXorClause; + } + + bool learnt() const + { + return isLearnt; + } + + float& getMiniSatAct() + { + return miniSatAct; + } + + void setMiniSatAct(const float newMiniSatAct) + { + miniSatAct = newMiniSatAct; + } + + const float& getMiniSatAct() const + { + return miniSatAct; + } + + Lit& operator [] (const uint32_t i) + { + return *(getData() + i); + } + + const Lit& operator [] (const uint32_t i) const + { + return *(getData() + i); + } + + void setGlue(const uint32_t newGlue) + { + assert(newGlue <= MAX_THEORETICAL_GLUE); + glue = newGlue; + } + + uint32_t getGlue() const + { + return glue; + } + + void makeNonLearnt() + { + assert(isLearnt); + isLearnt = false; + } + + void makeLearnt(const uint32_t newGlue, const float newMiniSatAct) + { + glue = newGlue; + miniSatAct = newMiniSatAct; + isLearnt = true; + } + + inline void strengthen(const Lit p) + { + remove(*this, p); + setChanged(); + } + + void calcAbstractionClause() + { + abst = calcAbstraction(*this); + } + + uint32_t getAbst() const + { + return abst; + } + + const Lit* getData() const + { + return (Lit*)((char*)this + sizeof(Clause)); + } + + Lit* getData() + { + return (Lit*)((char*)this + sizeof(Clause)); + } + + const Lit* getDataEnd() const + { + return getData()+size(); + } + + Lit* getDataEnd() + { + return getData() + size(); + } + + void print(FILE* to = stdout) const + { + plainPrint(to); + fprintf(to, "c clause learnt %s glue %d miniSatAct %.3f\n", (learnt() ? "yes" : "no"), getGlue(), getMiniSatAct()); + } + + void plainPrint(FILE* to = stdout) const + { + for (uint32_t i = 0; i < size(); i++) { + if ((getData()+i)->sign()) fprintf(to, "-"); + fprintf(to, "%d ", (getData()+i)->var() + 1); + } + fprintf(to, "0\n"); + } + + void setRemoved() + { + isRemoved = true; + } + + bool getRemoved() const + { + return isRemoved; + } + + void setFreed() + { + isFreed = true; + } + + bool getFreed() const + { + return isFreed; + } + + void takeMaxOfStats(Clause& other) + { + if (other.getGlue() < getGlue()) + setGlue(other.getGlue()); + if (other.getMiniSatAct() > getMiniSatAct()) + setMiniSatAct(other.getMiniSatAct()); + } +}; + +/** +@brief Holds an xor clause. Similarly to Clause, it cannot be directly used + +The space is not allocated for the literals. See Clause for details +*/ +class XorClause : public Clause +{ +protected: + // NOTE: This constructor cannot be used directly (doesn't allocate enough memory). + template<class V> + XorClause(const V& ps, const bool xorEqualFalse) : + Clause(ps, false) + { + isXorEqualFalse = xorEqualFalse; + isXorClause = true; + } + +public: + friend class ClauseAllocator; + + inline bool xorEqualFalse() const + { + return isXorEqualFalse; + } + + inline void invert(const bool b) + { + isXorEqualFalse ^= b; + } + + void print(FILE* to = stdout) const + { + plainPrint(to); + fprintf(to, "c clause learnt %s glue %d miniSatAct %.3f\n", (learnt() ? "yes" : "no"), getGlue(), getMiniSatAct()); + } + + void plainPrint(FILE* to = stdout) const + { + fprintf(to, "x"); + if (xorEqualFalse()) + fprintf(to, "-"); + for (uint32_t i = 0; i < size(); i++) { + fprintf(to, "%d ", this->operator[](i).var() + 1); + } + fprintf(to, "0\n"); + } + + friend class MatrixFinder; +}; + +inline std::ostream& operator<<(std::ostream& cout, const Clause& cl) +{ + for (uint32_t i = 0; i < cl.size(); i++) { + cout << cl[i] << " "; + } + return cout; +} + +inline std::ostream& operator<<(std::ostream& cout, const XorClause& cl) +{ + cout << "x"; + for (uint32_t i = 0; i < cl.size(); i++) { + cout << cl[i].var() + 1 << " "; + } + if (cl.xorEqualFalse()) cout << " = false"; + else cout << " = true"; + + return cout; +} + +} + +#endif //CLAUSE_H diff --git a/src/prop/cryptominisat/Solver/ClauseAllocator.cpp b/src/prop/cryptominisat/Solver/ClauseAllocator.cpp new file mode 100644 index 000000000..f1576e7fe --- /dev/null +++ b/src/prop/cryptominisat/Solver/ClauseAllocator.cpp @@ -0,0 +1,572 @@ +/*********************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +************************************************************************/ + +#include "ClauseAllocator.h" + +#include <string.h> +#include <limits> +#include "assert.h" +#include "SolverTypes.h" +#include "Clause.h" +#include "Solver.h" +#include "time_mem.h" +#include "Subsumer.h" +#include "XorSubsumer.h" +//#include "VarReplacer.h" +#include "Gaussian.h" + +#ifndef _MSC_VER +#include <sys/mman.h> +#endif //_MSC_VER + + +//For mild debug info: +//#define DEBUG_CLAUSEALLOCATOR + +//For listing each and every clause location: +//#define DEBUG_CLAUSEALLOCATOR2 + +#define MIN_LIST_SIZE (300000 * (sizeof(Clause) + 4*sizeof(Lit))/sizeof(BASE_DATA_TYPE)) +//#define MIN_LIST_SIZE (100 * (sizeof(Clause) + 4*sizeof(Lit))/sizeof(BASE_DATA_TYPE)) +#define ALLOC_GROW_MULT 8 +//We shift stuff around in Watched, so not all of 32 bits are useable. +#define EFFECTIVELY_USEABLE_BITS 30 +#define MAXSIZE ((1 << (EFFECTIVELY_USEABLE_BITS-NUM_BITS_OUTER_OFFSET))-1) + +using namespace CMSat; + +ClauseAllocator::ClauseAllocator() +{ + assert(MIN_LIST_SIZE < MAXSIZE); + assert(sizeof(Clause) + 2*sizeof(Lit) >= sizeof(NewPointerAndOffset)); +} + +/** +@brief Frees all stacks +*/ +ClauseAllocator::~ClauseAllocator() +{ + for (uint32_t i = 0; i < dataStarts.size(); i++) { + free(dataStarts[i]); + } +} + +/** +@brief Allocates space&initializes a clause +*/ +template<class T> +Clause* ClauseAllocator::Clause_new(const T& ps, const bool learnt) +{ + assert(ps.size() > 2); + void* mem = allocEnough(ps.size()); + Clause* real= new (mem) Clause(ps, learnt); + //assert(!(ps.size() == 2 && !real->wasBin())); + + return real; +} + +template Clause* ClauseAllocator::Clause_new(const vec<Lit>& ps, const bool learnt); +template Clause* ClauseAllocator::Clause_new(const Clause& ps, const bool learnt); +template Clause* ClauseAllocator::Clause_new(const XorClause& ps, const bool learnt); + +/** +@brief Allocates space&initializes an xor clause +*/ +template<class T> +XorClause* ClauseAllocator::XorClause_new(const T& ps, const bool xorEqualFalse) +{ + assert(ps.size() > 2); + void* mem = allocEnough(ps.size()); + XorClause* real= new (mem) XorClause(ps, xorEqualFalse); + + return real; +} +template XorClause* ClauseAllocator::XorClause_new(const vec<Lit>& ps, const bool inverted); +template XorClause* ClauseAllocator::XorClause_new(const XorClause& ps, const bool inverted); + +/** +@brief Allocates space for a new clause & copies a give clause to it +*/ +Clause* ClauseAllocator::Clause_new(Clause& c) +{ + assert(c.size() > 2); + void* mem = allocEnough(c.size()); + memcpy(mem, &c, sizeof(Clause)+sizeof(Lit)*c.size()); + + return (Clause*)mem; +} + +/** +@brief Allocates enough space for a new clause + +It tries to add the clause to the end of any already created stacks +if that is impossible, it creates a new stack, and adds the clause there +*/ +void* ClauseAllocator::allocEnough(const uint32_t size) throw (std::bad_alloc) +{ + assert(sizes.size() == dataStarts.size()); + assert(maxSizes.size() == dataStarts.size()); + assert(origClauseSizes.size() == dataStarts.size()); + + assert(size > 2 && "Clause size cannot be 2 or less, those are stored natively"); + + const uint32_t needed = sizeof(Clause) + sizeof(Lit)*size; + bool found = false; + uint32_t which = std::numeric_limits<uint32_t>::max(); + for (uint32_t i = 0; i < sizes.size(); i++) { + if (sizes[i] + needed < maxSizes[i]) { + found = true; + which = i; + break; + } + } + + if (!found) { + //Checking whether we are out of memory, because the offset that we can + //store is too little + if (dataStarts.size() == (1<<NUM_BITS_OUTER_OFFSET)) + throw std::bad_alloc(); + + uint32_t nextSize; //number of BYTES to allocate + if (maxSizes.size() != 0) { + nextSize = std::min((uint32_t)(maxSizes[maxSizes.size()-1]*ALLOC_GROW_MULT), (uint32_t)MAXSIZE); + nextSize = std::max(nextSize, (uint32_t)MIN_LIST_SIZE*2); + } else { + nextSize = (uint32_t)MIN_LIST_SIZE; + } + assert(needed < nextSize); + assert(nextSize <= MAXSIZE); + + #ifdef DEBUG_CLAUSEALLOCATOR + std::cout << "c New list in ClauseAllocator. Size: " << nextSize + << " (maxSize: " << MAXSIZE + << ")" << std::endl; + #endif //DEBUG_CLAUSEALLOCATOR + + BASE_DATA_TYPE *dataStart; + dataStart = (BASE_DATA_TYPE *)malloc(sizeof(BASE_DATA_TYPE) * nextSize); + + dataStarts.push(dataStart); + sizes.push(0); + maxSizes.push(nextSize); + origClauseSizes.push(); + currentlyUsedSizes.push(0); + which = dataStarts.size()-1; + } + #ifdef DEBUG_CLAUSEALLOCATOR2 + std::cout + << "selected list = " << which + << " size = " << sizes[which] + << " maxsize = " << maxSizes[which] + << " diff = " << maxSizes[which] - sizes[which] << std::endl; + #endif //DEBUG_CLAUSEALLOCATOR + + assert(which != std::numeric_limits<uint32_t>::max()); + Clause* pointer = (Clause*)(dataStarts[which] + sizes[which]); + sizes[which] += needed; + currentlyUsedSizes[which] += needed; + origClauseSizes[which].push(needed); + + return pointer; +} + +/** +@brief Given the pointer of the clause it finds a 32-bit offset for it + +Calculates the stack frame and the position of the pointer in the stack, and +rerturns a 32-bit value that is a concatenation of these two +*/ +ClauseOffset ClauseAllocator::getOffset(const Clause* ptr) const +{ + uint32_t outerOffset = getOuterOffset(ptr); + uint32_t interOffset = getInterOffset(ptr, outerOffset); + return combineOuterInterOffsets(outerOffset, interOffset); +} + +/** +@brief Combines the stack number and the internal offset into one 32-bit number +*/ +inline ClauseOffset ClauseAllocator::combineOuterInterOffsets(const uint32_t outerOffset, const uint32_t interOffset) const +{ + return (outerOffset | (interOffset << NUM_BITS_OUTER_OFFSET)); +} + +/** +@brief Given a pointer, finds which stack it's in +*/ +inline uint32_t ClauseAllocator::getOuterOffset(const Clause* ptr) const +{ + uint32_t which = std::numeric_limits<uint32_t>::max(); + for (uint32_t i = 0; i < sizes.size(); i++) { + if ((BASE_DATA_TYPE*)ptr >= dataStarts[i] && (BASE_DATA_TYPE*)ptr < dataStarts[i] + maxSizes[i]) { + which = i; + break; + } + } + assert(which != std::numeric_limits<uint32_t>::max()); + + return which; +} + +/** +@brief Given a pointer and its stack number, returns its position inside the stack +*/ +inline uint32_t ClauseAllocator::getInterOffset(const Clause* ptr, uint32_t outerOffset) const +{ + return ((BASE_DATA_TYPE*)ptr - dataStarts[outerOffset]); +} + +/** +@brief Frees a clause + +If clause was binary, it frees it in quite a normal way. If it isn't, then it +needs to set the data in the Clause that it has been freed, and updates the +stack it belongs to such that the stack can now that its effectively used size +is smaller + +NOTE: The size of claues can change. Therefore, currentlyUsedSizes can in fact +be incorrect, since it was incremented by the ORIGINAL size of the clause, but +when the clause is "freed", it is decremented by the POTENTIALLY SMALLER size +of the clause. Therefore, the "currentlyUsedSizes" is an overestimation!! +*/ +void ClauseAllocator::clauseFree(Clause* c) +{ + assert(!c->getFreed()); + + c->setFreed(); + uint32_t outerOffset = getOuterOffset(c); + //uint32_t interOffset = getInterOffset(c, outerOffset); + currentlyUsedSizes[outerOffset] -= sizeof(Clause) + c->size()*sizeof(Lit); + //above should be + //origClauseSizes[outerOffset][interOffset] + //but it cannot be :( +} + +/** +@brief If needed, compacts stacks, removing unused clauses + +Firstly, the algorithm determines if the number of useless slots is large or +small compared to the problem size. If it is small, it does nothing. If it is +large, then it allocates new stacks, copies the non-freed clauses to these new +stacks, updates all pointers and offsets, and frees the original stacks. +*/ +void ClauseAllocator::consolidate(Solver* solver, const bool force) throw (std::bad_alloc) +{ + double myTime = cpuTime(); + #ifdef DEBUG_PROPAGATEFROM + checkGoodPropBy(solver); + #endif + + uint32_t sum = 0; + for (uint32_t i = 0; i < sizes.size(); i++) { + sum += currentlyUsedSizes[i]; + } + uint32_t sumAlloc = 0; + for (uint32_t i = 0; i < sizes.size(); i++) { + sumAlloc += sizes[i]; + } + + #ifdef DEBUG_CLAUSEALLOCATOR + std::cout << "c ratio:" << (double)sum/(double)sumAlloc << std::endl; + #endif //DEBUG_CLAUSEALLOCATOR + + //If re-allocation is not really neccessary, don't do it + //Neccesities: + //1) There is too much memory allocated. Re-allocation will save space + // Avoiding segfault (max is 16 outerOffsets, more than 10 is near) + //2) There is too much empty, unused space (>30%) + if (!force + && ((double)sum/(double)sumAlloc > 0.7 && sizes.size() < 10) + ) { + if (solver->conf.verbosity >= 3) { + std::cout << "c Not consolidating memory." << std::endl; + } + return; + } + + #ifdef DEBUG_CLAUSEALLOCATOR + std::cout << "c ------ Consolidating Memory ------------" << std::endl; + #endif //DEBUG_CLAUSEALLOCATOR + int64_t newMaxSizeNeed = (double)sum*1.2 + MIN_LIST_SIZE; + #ifdef DEBUG_CLAUSEALLOCATOR + std::cout << "c newMaxSizeNeed = " << newMaxSizeNeed << std::endl; + #endif //DEBUG_CLAUSEALLOCATOR + vec<uint32_t> newMaxSizes; + for (uint32_t i = 0; i < (1 << NUM_BITS_OUTER_OFFSET); i++) { + if (newMaxSizeNeed <= 0) break; + + uint32_t thisMaxSize = std::min(newMaxSizeNeed, (int64_t)MAXSIZE); + if (i == 0) { + thisMaxSize = std::max(thisMaxSize, (uint32_t)MIN_LIST_SIZE); + } else { + assert(i > 0); + thisMaxSize = std::max(thisMaxSize, newMaxSizes[i-1]/2); + thisMaxSize = std::max(thisMaxSize, (uint32_t)MIN_LIST_SIZE*2); + } + newMaxSizeNeed -= thisMaxSize; + assert(thisMaxSize <= MAXSIZE); + newMaxSizes.push(thisMaxSize); + //because the clauses don't always fit + //it might occur that there is enough place in total + //but the very last clause would need to be fragmented + //over multiple lists' ends :O + //So this "magic" constant could take care of that.... + //or maybe not (if _very_ large clauses are used, always + //bad chance, etc. :O ) + //NOTE: the + MIN_LIST_SIZE should take care of this above at + // newMaxSizeNeed = sum + MIN_LIST_SIZE; + #ifdef DEBUG_CLAUSEALLOCATOR + std::cout << "c NEW MaxSizes:" << newMaxSizes[i] << std::endl; + #endif //DEBUG_CLAUSEALLOCATOR + } + #ifdef DEBUG_CLAUSEALLOCATOR + std::cout << "c ------------------" << std::endl; + #endif //DEBUG_CLAUSEALLOCATOR + + if (newMaxSizeNeed > 0) + throw std::bad_alloc(); + + vec<uint32_t> newSizes; + vec<vec<uint32_t> > newOrigClauseSizes; + vec<BASE_DATA_TYPE*> newDataStartsPointers; + vec<BASE_DATA_TYPE*> newDataStarts; + for (uint32_t i = 0; i < newMaxSizes.size(); i++) { + newSizes.push(0); + newOrigClauseSizes.push(); + BASE_DATA_TYPE* pointer; + pointer = (BASE_DATA_TYPE*)malloc(newMaxSizes[i]); + newDataStartsPointers.push(pointer); + newDataStarts.push(pointer); + } + + vector<Clause*> clauses; + for (uint32_t i = 0; i < dataStarts.size(); i++) { + uint32_t currentLoc = 0; + for (uint32_t i2 = 0; i2 < origClauseSizes[i].size(); i2++) { + Clause* oldPointer = (Clause*)(dataStarts[i] + currentLoc); + if (!oldPointer->getFreed()) { + clauses.push_back(oldPointer); + } else { + (*((NewPointerAndOffset*)(oldPointer))).newOffset = std::numeric_limits<uint32_t>::max(); + } + currentLoc += origClauseSizes[i][i2]; + } + } + + putClausesIntoDatastruct(clauses); + + uint32_t outerPart = 0; + //uint64_t skippedNum = 0; + for (uint32_t i = 0; i < clauses.size(); i++) { + Clause* clause = getClause(); + + uint32_t sizeNeeded = (sizeof(Clause) + clause->size()*sizeof(Lit))/sizeof(BASE_DATA_TYPE); + + //Next line is needed, because in case of isRemoved() + //, the size of the clause could become 0, thus having less + // than enough space to carry the NewPointerAndOffset info + sizeNeeded = std::max(sizeNeeded, (uint32_t)((sizeof(Clause) + 2*sizeof(Lit))/sizeof(BASE_DATA_TYPE))); + + if (newSizes[outerPart] + sizeNeeded > newMaxSizes[outerPart]) { + outerPart++; + assert(outerPart < newMaxSizes.size()); + } + memcpy(newDataStartsPointers[outerPart], (BASE_DATA_TYPE*)clause, sizeNeeded*sizeof(BASE_DATA_TYPE)); + + NewPointerAndOffset& ptr = *((NewPointerAndOffset*)clause); + ptr.newOffset = combineOuterInterOffsets(outerPart, newSizes[outerPart]); + ptr.newPointer = (Clause*)newDataStartsPointers[outerPart]; + + newSizes[outerPart] += sizeNeeded; + newOrigClauseSizes[outerPart].push(sizeNeeded); + newDataStartsPointers[outerPart] += sizeNeeded; + } + + updateAllOffsetsAndPointers(solver); + + for (uint32_t i = 0; i < dataStarts.size(); i++) + free(dataStarts[i]); + + dataStarts.clear(); + maxSizes.clear(); + sizes.clear(); + origClauseSizes.clear(); + currentlyUsedSizes.clear(); + origClauseSizes.clear(); + + for (uint32_t i = 0; i < newMaxSizes.size(); i++) { + dataStarts.push(newDataStarts[i]); + maxSizes.push(newMaxSizes[i]); + sizes.push(newSizes[i]); + currentlyUsedSizes.push(newSizes[i]); + } + newOrigClauseSizes.moveTo(origClauseSizes); + + if (solver->conf.verbosity >= 3) { + std::cout << "c Consolidated memory. Time: " + << cpuTime() - myTime << std::endl; + } +} + +void ClauseAllocator::putClausesIntoDatastruct(std::vector<Clause*>& clauses) +{ + otherClauses.clear(); + threeLongClauses.clear(); + for (uint32_t i = 0; i < clauses.size(); i++) { + Clause* c = clauses[i]; + if (c->size() <= 3) { + threeLongClauses.push_back(c); + } else { + otherClauses.push_back(c); + } + } +} + +Clause* ClauseAllocator::getClause() +{ + if (!threeLongClauses.empty()) { + Clause* tmp = threeLongClauses[threeLongClauses.size()-1]; + threeLongClauses.pop_back(); + return tmp; + } + + assert(!otherClauses.empty()); + Clause* tmp = otherClauses[otherClauses.size()-1]; + otherClauses.pop_back(); + return tmp; +} + +void ClauseAllocator::checkGoodPropBy(const Solver* solver) +{ + const vec<PropBy>& reason = solver->reason; + Var var = 0; + for (const PropBy *it = reason.getData(), *end = reason.getDataEnd(); it != end; it++, var++) { + if ((uint32_t)solver->level[var] > solver->decisionLevel() + || solver->level[var] == 0 + || solver->value(var) == l_Undef + ) { + continue; + } + + if (it->isClause() && !it->isNULL()) { + assert(!getPointer(it->getClause())->getFreed()); + assert(!getPointer(it->getClause())->getRemoved()); + } + } +} + + +void ClauseAllocator::updateAllOffsetsAndPointers(Solver* solver) +{ + updateOffsets(solver->watches); + + updatePointers(solver->clauses); + updatePointers(solver->learnts); + updatePointers(solver->xorclauses); + updatePointers(solver->freeLater); + #ifdef ENABLE_UNWIND_GLUE + updatePointers(solver->unWindGlue); + #endif //ENABLE_UNWIND_GLUE + + //No need to update varreplacer, since it only stores binary clauses that + //must have been allocated such as to use the pool + //updatePointers(solver->varReplacer->clauses, oldToNewPointer); + + #ifdef USE_GAUSS + for (uint32_t i = 0; i < solver->gauss_matrixes.size(); i++) { + updatePointers(solver->gauss_matrixes[i]->xorclauses); + updatePointers(solver->gauss_matrixes[i]->clauses_toclear); + } + #endif //USE_GAUSS + + vec<PropBy>& reason = solver->reason; + Var var = 0; + for (PropBy *it = reason.getData(), *end = reason.getDataEnd(); it != end; it++, var++) { + if ((uint32_t)solver->level[var] > solver->decisionLevel() + || solver->level[var] == 0 + || solver->value(var) == l_Undef) { + *it = PropBy(); + continue; + } + + if (it->isClause() && !it->isNULL()) { + assert(((NewPointerAndOffset*)(getPointer(it->getClause())))->newOffset != std::numeric_limits<uint32_t>::max()); + *it = PropBy(((NewPointerAndOffset*)(getPointer(it->getClause())))->newOffset); + } + } +} + +/** +@brief A dumb helper function to update offsets +*/ +void ClauseAllocator::updateOffsets(vec<vec<Watched> >& watches) +{ + for (uint32_t i = 0; i < watches.size(); i++) { + vec<Watched>& list = watches[i]; + for (vec<Watched>::iterator it = list.getData(), end = list.getDataEnd(); it != end; it++) { + if (!it->isClause() && !it->isXorClause()) continue; + if (it->isClause()) { + it->setNormOffset(((NewPointerAndOffset*)(getPointer(it->getNormOffset())))->newOffset); + } else { + it->setXorOffset(((NewPointerAndOffset*)(getPointer(it->getXorOffset())))->newOffset); + } + } + } +} + +/** +@brief A dumb helper function to update pointers +*/ +template<class T> +void ClauseAllocator::updatePointers(vec<T*>& toUpdate) +{ + for (T **it = toUpdate.getData(), **end = toUpdate.getDataEnd(); it != end; it++) { + if (*it != NULL) { + *it = (T*)(((NewPointerAndOffset*)(*it))->newPointer); + } + } +} + +/** +@brief A dumb helper function to update pointers +*/ +void ClauseAllocator::updatePointers(vector<Clause*>& toUpdate) +{ + for (vector<Clause*>::iterator it = toUpdate.begin(), end = toUpdate.end(); it != end; it++) { + *it = (((NewPointerAndOffset*)(*it))->newPointer); + } +} + +/** +@brief A dumb helper function to update pointers +*/ +void ClauseAllocator::updatePointers(vector<XorClause*>& toUpdate) +{ + for (vector<XorClause*>::iterator it = toUpdate.begin(), end = toUpdate.end(); it != end; it++) { + *it = (XorClause*)(((NewPointerAndOffset*)(*it))->newPointer); + } +} + +/** +@brief A dumb helper function to update pointers +*/ +void ClauseAllocator::updatePointers(vector<pair<Clause*, uint32_t> >& toUpdate) +{ + for (vector<pair<Clause*, uint32_t> >::iterator it = toUpdate.begin(), end = toUpdate.end(); it != end; it++) { + it->first = (((NewPointerAndOffset*)(it->first))->newPointer); + } +} diff --git a/src/prop/cryptominisat/Solver/ClauseAllocator.h b/src/prop/cryptominisat/Solver/ClauseAllocator.h new file mode 100644 index 000000000..d20c1617b --- /dev/null +++ b/src/prop/cryptominisat/Solver/ClauseAllocator.h @@ -0,0 +1,146 @@ +/*********************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +************************************************************************/ + +#ifndef CLAUSEALLOCATOR_H +#define CLAUSEALLOCATOR_H + +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#include <stdlib.h> +#include "Vec.h" +#include <map> +#include <vector> + +#include "ClauseOffset.h" +#include "Watched.h" + +#define NUM_BITS_OUTER_OFFSET 4 +#define BASE_DATA_TYPE char + +namespace CMSat { + +using std::map; +using std::vector; + +class Clause; +class XorClause; +class Solver; + +/** +@brief Allocates memory for (xor) clauses + +This class allocates memory in large chunks, then distributes it to clauses when +needed. When instructed, it consolidates the unused space (i.e. clauses free()-ed). +Essentially, it is a stack-like allocator for clauses. It is useful to have +this, because this way, we can address clauses according to their number, +which is 32-bit, instead of their address, which might be 64-bit +*/ +class ClauseAllocator { + public: + ClauseAllocator(); + ~ClauseAllocator(); + + template<class T> + Clause* Clause_new(const T& ps, const bool learnt = false); + template<class T> + XorClause* XorClause_new(const T& ps, const bool xorEqualFalse); + Clause* Clause_new(Clause& c); + + ClauseOffset getOffset(const Clause* ptr) const; + + /** + @brief Returns the pointer of a clause given its offset + + Takes the "dataStart" of the correct stack, and adds the offset, + returning the thus created pointer. Used a LOT in propagation, thus this + is very important to be fast (therefore, it is an inlined method) + */ + inline Clause* getPointer(const uint32_t offset) const + { + return (Clause*)(dataStarts[offset&((1 << NUM_BITS_OUTER_OFFSET) - 1)] + +(offset >> NUM_BITS_OUTER_OFFSET)); + } + + void clauseFree(Clause* c); + + void consolidate(Solver* solver, const bool force = false) throw (std::bad_alloc); + + uint32_t getNewClauseNum(); + + private: + uint32_t getOuterOffset(const Clause* c) const; + uint32_t getInterOffset(const Clause* c, const uint32_t outerOffset) const; + ClauseOffset combineOuterInterOffsets(const uint32_t outerOffset, const uint32_t interOffset) const; + + void updateAllOffsetsAndPointers(Solver* solver); + template<class T> + void updatePointers(vec<T*>& toUpdate); + void updatePointers(vector<Clause*>& toUpdate); + void updatePointers(vector<XorClause*>& toUpdate); + void updatePointers(vector<std::pair<Clause*, uint32_t> >& toUpdate); + void updateOffsets(vec<vec<Watched> >& watches); + void checkGoodPropBy(const Solver* solver); + + void releaseClauseNum(const uint32_t num); + + vec<BASE_DATA_TYPE*> dataStarts; ///<Stacks start at these positions + vec<size_t> sizes; ///<The number of 32-bit datapieces currently used in each stack + /** + @brief Clauses in the stack had this size when they were allocated + This my NOT be their current size: the clauses may be shrinked during + the running of the solver. Therefore, it is imperative that their orignal + size is saved. This way, we can later move clauses around. + */ + vec<vec<uint32_t> > origClauseSizes; + vec<size_t> maxSizes; ///<The number of 32-bit datapieces allocated in each stack + /** + @brief The estimated used size of the stack + This is incremented by clauseSize each time a clause is allocated, and + decremetented by clauseSize each time a clause is deallocated. The + problem is, that clauses can shrink, and thus this value will be an + overestimation almost all the time + */ + vec<size_t> currentlyUsedSizes; + + void* allocEnough(const uint32_t size) throw (std::bad_alloc); + + /** + @brief The clause's data is replaced by this to aid updating + + We need to update the pointer or offset that points to the clause + The best way to do that is to simply fill the original place of the clause + with the pointer/offset of the new location. + */ + struct NewPointerAndOffset + { + uint32_t newOffset; ///<The new offset where the clause now resides + Clause* newPointer; ///<The new place + }; + + vector<Clause*> otherClauses; + vector<Clause*> threeLongClauses; + Clause* getClause(); + void putClausesIntoDatastruct(std::vector<Clause*>& clauses); +}; + +} + +#endif //CLAUSEALLOCATOR_H diff --git a/src/prop/cryptominisat/Solver/ClauseCleaner.cpp b/src/prop/cryptominisat/Solver/ClauseCleaner.cpp new file mode 100644 index 000000000..47dd675f4 --- /dev/null +++ b/src/prop/cryptominisat/Solver/ClauseCleaner.cpp @@ -0,0 +1,261 @@ +/*************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +****************************************************************************/ + +#include "ClauseCleaner.h" +#include "VarReplacer.h" +#include "DataSync.h" + +//#define DEBUG_CLEAN +//#define VERBOSE_DEBUG + +using namespace CMSat; + +ClauseCleaner::ClauseCleaner(Solver& _solver) : + solver(_solver) +{ + for (uint32_t i = 0; i < 6; i++) { + lastNumUnitarySat[i] = solver.get_unitary_learnts_num(); + lastNumUnitaryClean[i] = solver.get_unitary_learnts_num(); + } +} + +bool ClauseCleaner::satisfied(const Watched& watched, Lit lit) +{ + assert(watched.isBinary()); + if (solver.value(lit) == l_True) return true; + if (solver.value(watched.getOtherLit()) == l_True) return true; + return false; +} + +void ClauseCleaner::removeSatisfiedBins(const uint32_t limit) +{ + #ifdef DEBUG_CLEAN + assert(solver.decisionLevel() == 0); + #endif + + if (lastNumUnitarySat[binaryClauses] + limit >= solver.get_unitary_learnts_num()) + return; + + uint32_t numRemovedHalfNonLearnt = 0; + uint32_t numRemovedHalfLearnt = 0; + uint32_t wsLit = 0; + for (vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + vec<Watched>& ws = *it; + + vec<Watched>::iterator i = ws.getData(); + vec<Watched>::iterator j = i; + for (vec<Watched>::iterator end2 = ws.getDataEnd(); i != end2; i++) { + if (i->isBinary() && satisfied(*i, lit)) { + if (i->getLearnt()) numRemovedHalfLearnt++; + else { + numRemovedHalfNonLearnt++; + } + } else { + *j++ = *i; + } + } + ws.shrink_(i - j); + } + + //std::cout << "removedHalfLeart: " << numRemovedHalfLearnt << std::endl; + //std::cout << "removedHalfNonLeart: " << numRemovedHalfNonLearnt << std::endl; + assert(numRemovedHalfLearnt % 2 == 0); + assert(numRemovedHalfNonLearnt % 2 == 0); + solver.clauses_literals -= numRemovedHalfNonLearnt; + solver.learnts_literals -= numRemovedHalfLearnt; + solver.numBins -= (numRemovedHalfLearnt + numRemovedHalfNonLearnt)/2; + + lastNumUnitarySat[binaryClauses] = solver.get_unitary_learnts_num(); +} + +void ClauseCleaner::cleanClauses(vec<Clause*>& cs, ClauseSetType type, const uint32_t limit) +{ + assert(solver.decisionLevel() == 0); + assert(solver.qhead == solver.trail.size()); + + if (lastNumUnitaryClean[type] + limit >= solver.get_unitary_learnts_num()) + return; + + #ifdef VERBOSE_DEBUG + std::cout << "Cleaning " << (type==binaryClauses ? "binaryClauses" : "normal clauses" ) << std::endl; + #endif //VERBOSE_DEBUG + + Clause **s, **ss, **end; + for (s = ss = cs.getData(), end = s + cs.size(); s != end; s++) { + if (s+1 != end) __builtin_prefetch(*(s+1)); + + if (cleanClause(*s)) { + solver.clauseAllocator.clauseFree(*s); + } else { + *ss++ = *s; + } + } + cs.shrink(s-ss); + + lastNumUnitaryClean[type] = solver.get_unitary_learnts_num(); + + #ifdef VERBOSE_DEBUG + cout << "cleanClauses(Clause) useful ?? Removed: " << s-ss << endl; + #endif +} + +inline bool ClauseCleaner::cleanClause(Clause*& cc) +{ + Clause& c = *cc; + + Lit origLit1 = c[0]; + Lit origLit2 = c[1]; + uint32_t origSize = c.size(); + Lit origLit3 = (origSize == 3) ? c[2] : lit_Undef; + + Lit *i, *j, *end; + for (i = j = c.getData(), end = i + c.size(); i != end; i++) { + lbool val = solver.value(*i); + if (val == l_Undef) { + *j++ = *i; + continue; + } + + if (val == l_True) { + solver.detachModifiedClause(origLit1, origLit2, origLit3, origSize, &c); + return true; + } + } + c.shrink(i-j); + + assert(c.size() != 1); + if (i != j) { + if (c.size() == 2) { + solver.detachModifiedClause(origLit1, origLit2, origLit3, origSize, &c); + solver.attachBinClause(c[0], c[1], c.learnt()); + solver.numNewBin++; + solver.dataSync->signalNewBinClause(c); + return true; + } else if (c.size() == 3) { + solver.detachModifiedClause(origLit1, origLit2, origLit3, origSize, &c); + solver.attachClause(c); + } else { + if (c.learnt()) + solver.learnts_literals -= i-j; + else + solver.clauses_literals -= i-j; + } + } + + return false; +} + +void ClauseCleaner::cleanClauses(vec<XorClause*>& cs, ClauseSetType type, const uint32_t limit) +{ + assert(solver.decisionLevel() == 0); + assert(solver.qhead == solver.trail.size()); + + if (lastNumUnitaryClean[type] + limit >= solver.get_unitary_learnts_num()) + return; + + XorClause **s, **ss, **end; + for (s = ss = cs.getData(), end = s + cs.size(); s != end; s++) { + if (s+1 != end) + __builtin_prefetch(*(s+1), 1, 0); + + #ifdef DEBUG_ATTACH_FULL + XorClause& c = **s; + assert(solver.xorClauseIsAttached(c)); + if (solver.assigns[c[0].var()]!=l_Undef || solver.assigns[c[1].var()]!=l_Undef) { + satisfied(**s); + } + #endif //DEBUG_ATTACH + + if (cleanClause(**s)) { + //solver.clauseAllocator.clauseFree(*s); + solver.freeLater.push(*s); + (*s)->setRemoved(); + } else { + #ifdef DEBUG_ATTACH_FULL + assert(solver.xorClauseIsAttached(c)); + #endif //DEBUG_ATTACH + *ss++ = *s; + } + } + cs.shrink(s-ss); + + lastNumUnitaryClean[type] = solver.get_unitary_learnts_num(); + + #ifdef VERBOSE_DEBUG + cout << "cleanClauses(XorClause) useful: ?? Removed: " << s-ss << endl; + #endif +} + +inline bool ClauseCleaner::cleanClause(XorClause& c) +{ + Lit *i, *j, *end; + Var origVar1 = c[0].var(); + Var origVar2 = c[1].var(); + uint32_t origSize = c.size(); + for (i = j = c.getData(), end = i + c.size(); i != end; i++) { + const lbool& val = solver.assigns[i->var()]; + if (val.isUndef()) { + *j = *i; + j++; + } else c.invert(val.getBool()); + } + c.shrink(i-j); + + assert(c.size() != 1); + switch (c.size()) { + case 0: { + solver.detachModifiedClause(origVar1, origVar2, origSize, &c); + return true; + } + case 2: { + c[0] = c[0].unsign(); + c[1] = c[1].unsign(); + solver.varReplacer->replace(c, c.xorEqualFalse()); + solver.detachModifiedClause(origVar1, origVar2, origSize, &c); + return true; + } + default: { + if (i-j > 0) { + solver.clauses_literals -= i-j; + } + return false; + } + } + + assert(false); + return false; +} + +bool ClauseCleaner::satisfied(const Clause& c) const +{ + for (uint32_t i = 0; i != c.size(); i++) + if (solver.value(c[i]) == l_True) + return true; + return false; +} + +bool ClauseCleaner::satisfied(const XorClause& c) const +{ + bool final = c.xorEqualFalse(); + for (uint32_t k = 0; k != c.size(); k++ ) { + const lbool& val = solver.assigns[c[k].var()]; + if (val.isUndef()) return false; + final ^= val.getBool(); + } + return final; +} diff --git a/src/prop/cryptominisat/Solver/ClauseCleaner.h b/src/prop/cryptominisat/Solver/ClauseCleaner.h new file mode 100644 index 000000000..11886e430 --- /dev/null +++ b/src/prop/cryptominisat/Solver/ClauseCleaner.h @@ -0,0 +1,86 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#ifndef CLAUSECLEANER_H +#define CLAUSECLEANER_H + +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#include "Solver.h" +#include "Subsumer.h" +#include "XorSubsumer.h" + +namespace CMSat { + +/** +@brief Cleans clauses from false literals & removes satisfied clauses +*/ +class ClauseCleaner +{ + public: + ClauseCleaner(Solver& solver); + + enum ClauseSetType {clauses, binaryClauses, xorclauses, learnts}; + + void cleanClauses(vec<Clause*>& cs, ClauseSetType type, const uint32_t limit = 0); + + void cleanClauses(vec<XorClause*>& cs, ClauseSetType type, const uint32_t limit = 0); + void removeSatisfiedBins(const uint32_t limit = 0); + //void removeSatisfied(vec<Clause*>& cs, ClauseSetType type, const uint32_t limit = 0); + //void removeSatisfied(vec<XorClause*>& cs, ClauseSetType type, const uint32_t limit = 0); + void removeAndCleanAll(const bool nolimit = false); + bool satisfied(const Clause& c) const; + bool satisfied(const XorClause& c) const; + + private: + bool satisfied(const Watched& watched, Lit lit); + bool cleanClause(XorClause& c); + bool cleanClause(Clause*& c); + + uint32_t lastNumUnitarySat[6]; ///<Last time we cleaned from satisfied clauses, this many unitary clauses were known + uint32_t lastNumUnitaryClean[6]; ///<Last time we cleaned from satisfied clauses&false literals, this many unitary clauses were known + + Solver& solver; +}; + +/** +@brief Removes all satisfied clauses, and cleans false literals + +There is a heuristic in place not to try to clean all the time. However, +this limit can be overridden with "nolimit" +@p nolimit set this to force cleaning&removing. Useful if a really clean +state is needed, which is important for certain algorithms +*/ +inline void ClauseCleaner::removeAndCleanAll(const bool nolimit) +{ + //uint32_t limit = std::min((uint32_t)((double)solver.order_heap.size() * PERCENTAGECLEANCLAUSES), FIXCLEANREPLACE); + uint32_t limit = (double)solver.order_heap.size() * PERCENTAGECLEANCLAUSES; + if (nolimit) limit = 0; + + removeSatisfiedBins(limit); + cleanClauses(solver.clauses, ClauseCleaner::clauses, limit); + cleanClauses(solver.xorclauses, ClauseCleaner::xorclauses, limit); + cleanClauses(solver.learnts, ClauseCleaner::learnts, limit); +} + +} + +#endif //CLAUSECLEANER_H diff --git a/src/prop/cryptominisat/Solver/ClauseOffset.h b/src/prop/cryptominisat/Solver/ClauseOffset.h new file mode 100644 index 000000000..352cda45e --- /dev/null +++ b/src/prop/cryptominisat/Solver/ClauseOffset.h @@ -0,0 +1,16 @@ +#ifndef CLAUSEOFFSET_H +#define CLAUSEOFFSET_H + +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +namespace CMSat { + +typedef uint32_t ClauseOffset; + +} + +#endif //CLAUSEOFFSET_H diff --git a/src/prop/cryptominisat/Solver/ClauseVivifier.cpp b/src/prop/cryptominisat/Solver/ClauseVivifier.cpp new file mode 100644 index 000000000..ebe745f10 --- /dev/null +++ b/src/prop/cryptominisat/Solver/ClauseVivifier.cpp @@ -0,0 +1,342 @@ +/************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "ClauseVivifier.h" +#include "ClauseCleaner.h" +#include "time_mem.h" +#include <iomanip> + +//#define ASSYM_DEBUG + +using namespace CMSat; + +ClauseVivifier::ClauseVivifier(Solver& _solver) : + lastTimeWentUntil(0) + , numCalls(0) + , solver(_solver) +{} + + +/** +@brief Performs clause vivification (by Hamadi et al.) + +This is the only thing that does not fit under the aegis of tryBoth(), since +it is not part of failed literal probing, really. However, it is here because +it seems to be a function that fits into the idology of failed literal probing. +Maybe I am off-course and it should be in another class, or a class of its own. +*/ +bool ClauseVivifier::vivifyClauses() +{ + assert(solver.ok); + #ifdef VERBOSE_DEBUG + std::cout << "c clauseVivifier started" << std::endl; + //solver.printAllClauses(); + #endif //VERBOSE_DEBUG + + + solver.clauseCleaner->cleanClauses(solver.clauses, ClauseCleaner::clauses); + numCalls++; + + if (solver.ok) { + if (!vivifyClauses2(solver.clauses)) return false; + if (!vivifyClauses2(solver.learnts)) return false; + } + + bool failed; + uint32_t effective = 0; + uint32_t effectiveLit = 0; + double myTime = cpuTime(); + uint64_t maxNumProps = 20*1000*1000; + if (solver.clauses_literals + solver.learnts_literals < 500000) + maxNumProps *=2; + uint64_t extraDiff = 0; + uint64_t oldProps = solver.propagations; + bool needToFinish = false; + uint32_t checkedClauses = 0; + uint32_t potentialClauses = solver.clauses.size(); + if (lastTimeWentUntil + 500 > solver.clauses.size()) + lastTimeWentUntil = 0; + uint32_t thisTimeWentUntil = 0; + vec<Lit> lits; + vec<Lit> unused; + + if (solver.clauses.size() < 1000000) { + //if too many clauses, random order will do perfectly well + std::sort(solver.clauses.getData(), solver.clauses.getDataEnd(), sortBySize()); + } + + uint32_t queueByBy = 2; + if (numCalls > 8 + && (solver.clauses_literals + solver.learnts_literals < 4000000) + && (solver.clauses.size() < 50000)) + queueByBy = 1; + + Clause **i, **j; + i = j = solver.clauses.getData(); + for (Clause **end = solver.clauses.getDataEnd(); i != end; i++) { + if (needToFinish || lastTimeWentUntil > 0) { + if (!needToFinish) { + lastTimeWentUntil--; + thisTimeWentUntil++; + } + *j++ = *i; + continue; + } + + //if done enough, stop doing it + if (solver.propagations-oldProps + extraDiff > maxNumProps) { + //std::cout << "Need to finish -- ran out of prop" << std::endl; + needToFinish = true; + } + + //if bad performance, stop doing it + /*if ((i-solver.clauses.getData() > 5000 && effectiveLit < 300)) { + std::cout << "Need to finish -- not effective" << std::endl; + needToFinish = true; + }*/ + + Clause& c = **i; + extraDiff += c.size(); + checkedClauses++; + thisTimeWentUntil++; + + assert(c.size() > 2); + assert(!c.learnt()); + + unused.clear(); + lits.clear(); + lits.growTo(c.size()); + memcpy(lits.getData(), c.getData(), c.size() * sizeof(Lit)); + + failed = false; + uint32_t done = 0; + solver.newDecisionLevel(); + for (; done < lits.size();) { + uint32_t i2 = 0; + for (; (i2 < queueByBy) && ((done+i2) < lits.size()); i2++) { + lbool val = solver.value(lits[done+i2]); + if (val == l_Undef) { + solver.uncheckedEnqueueLight(~lits[done+i2]); + } else if (val == l_False) { + unused.push(lits[done+i2]); + } + } + done += i2; + failed = (!solver.propagate<false>(false).isNULL()); + if (numCalls > 3 && failed) break; + } + solver.cancelUntilLight(); + assert(solver.ok); + + if (unused.size() > 0 || (failed && done < lits.size())) { + effective++; + uint32_t origSize = lits.size(); + #ifdef ASSYM_DEBUG + std::cout << "Assym branch effective." << std::endl; + std::cout << "-- Orig clause:"; c.plainPrint(); + #endif + solver.detachClause(c); + + lits.shrink(lits.size() - done); + for (uint32_t i2 = 0; i2 < unused.size(); i2++) { + remove(lits, unused[i2]); + } + + Clause *c2 = solver.addClauseInt(lits); + #ifdef ASSYM_DEBUG + std::cout << "-- Origsize:" << origSize << " newSize:" << (c2 == NULL ? 0 : c2->size()) << " toRemove:" << c.size() - done << " unused.size():" << unused.size() << std::endl; + #endif + extraDiff += 20; + //TODO cheating here: we don't detect a NULL return that is in fact a 2-long clause + effectiveLit += origSize - (c2 == NULL ? 0 : c2->size()); + solver.clauseAllocator.clauseFree(&c); + + if (c2 != NULL) { + #ifdef ASSYM_DEBUG + std::cout << "-- New clause:"; c2->plainPrint(); + #endif + *j++ = c2; + } + + if (!solver.ok) needToFinish = true; + } else { + *j++ = *i; + } + } + solver.clauses.shrink(i-j); + + lastTimeWentUntil = thisTimeWentUntil; + + if (solver.conf.verbosity >= 1) { + std::cout << "c asymm " + << " cl-useful: " << effective << "/" << checkedClauses << "/" << potentialClauses + << " lits-rem:" << effectiveLit + << " time: " << cpuTime() - myTime + << std::endl; + } + + return solver.ok; +} + + +bool ClauseVivifier::vivifyClauses2(vec<Clause*>& clauses) +{ + assert(solver.ok); + + vec<char> seen; + seen.growTo(solver.nVars()*2, 0); + vec<char> seen_subs; + seen_subs.growTo(solver.nVars()*2, 0); + + uint32_t litsRem = 0; + uint32_t clShrinked = 0; + uint64_t countTime = 0; + uint64_t maxCountTime = 800*1000*1000; + maxCountTime *= 6; + if (solver.clauses_literals + solver.learnts_literals < 500000) + maxCountTime *= 2; + uint32_t clTried = 0; + vec<Lit> lits; + bool needToFinish = false; + double myTime = cpuTime(); + uint32_t subsumed_tri_num = 0; + uint32_t subsumed_bin_num = 0; + + Clause** i = clauses.getData(); + Clause** j = i; + for (Clause** end = clauses.getDataEnd(); i != end; i++) { + if (needToFinish) { + *j++ = *i; + continue; + } + if (countTime > maxCountTime) + needToFinish = true; + + Clause& cl = **i; + countTime += cl.size()*2; + clTried++; + + bool subsumed = false; + const bool learnt = cl.learnt(); + for (uint32_t i2 = 0; i2 < cl.size(); i2++) { + seen[cl[i2].toInt()] = 1; //for strengthening + seen_subs[cl[i2].toInt()] = 1; //for subsumption + } + + for (const Lit *l = cl.getData(), *end = cl.getDataEnd(); l != end; l++) { + const Lit *l_other = l; + l_other++; + if (l_other != end) + __builtin_prefetch(solver.watches[(~*l_other).toInt()].getData()); + + const vec<Watched>& ws = solver.watches[(~*l).toInt()]; + countTime += ws.size()*2; + for(vec<Watched>::const_iterator it = ws.getData(), end = ws.getDataEnd(); it != end; it++) { + //Handle tri clause + if (it->isTriClause() && cl.size() > 3) + { + if (learnt //we cannot decide if TRI is learnt or not + && seen_subs[it->getOtherLit().toInt()] + && seen_subs[it->getOtherLit2().toInt()] + ) { + subsumed_tri_num++; + subsumed = true; + } + + if (seen[l->toInt()]) { //we may have removed it already + //one way + if (seen[(it->getOtherLit2()).toInt()]) + seen[(~it->getOtherLit()).toInt()] = 0; + + //other way + if (seen[(it->getOtherLit()).toInt()]) + seen[(~it->getOtherLit2()).toInt()] = 0; + } + } + + //Handle Binary clause + if (it->isBinary()) { + if (seen_subs[it->getOtherLit().toInt()]) + { + if (!learnt && it->getLearnt()) + makeNonLearntBin(*l, it->getOtherLit(), it->getLearnt()); + subsumed_bin_num++; + subsumed = true; + } + + if (seen[l->toInt()]) //we may have removed it already + seen[(~it->getOtherLit()).toInt()] = 0; + + } + } + + if (seen[l->toInt()] == 0) + continue; + + countTime += solver.transOTFCache[l->toInt()].lits.size(); + for (vector<Lit>::const_iterator it2 = solver.transOTFCache[l->toInt()].lits.begin() + , end2 = solver.transOTFCache[l->toInt()].lits.end(); it2 != end2; it2++) { + seen[(~(*it2)).toInt()] = 0; + } + } + + lits.clear(); + for (const Lit *it2 = cl.getData(), *end2 = cl.getDataEnd(); it2 != end2; it2++) { + if (seen[it2->toInt()]) lits.push(*it2); + else litsRem++; + seen[it2->toInt()] = 0; + seen_subs[it2->toInt()] = 0; + } + + if (subsumed) { + solver.removeClause(cl); + } else if (lits.size() < cl.size()) { + solver.detachClause(cl); + clShrinked++; + Clause* c2 = solver.addClauseInt(lits, cl.learnt(), cl.getGlue(), cl.getMiniSatAct()); + solver.clauseAllocator.clauseFree(&cl); + + if (c2 != NULL) *j++ = c2; + if (!solver.ok) needToFinish = true; + } else { + *j++ = *i; + } + } + + clauses.shrink(i-j); + + if (solver.conf.verbosity >= 1) { + std::cout << "c vivif2 -- " + << " cl tried " << std::setw(8) << clTried + << " cl rem " << std::setw(8) << (subsumed_bin_num + subsumed_tri_num) + << " cl shrink " << std::setw(8) << clShrinked + << " lits rem " << std::setw(10) << litsRem + << " time: " << cpuTime() - myTime + << std::endl; + } + + return solver.ok; +} + +void ClauseVivifier::makeNonLearntBin(const Lit lit1, const Lit lit2, const bool learnt) +{ + assert(learnt == true); + findWatchedOfBin(solver.watches, lit1 ,lit2, learnt).setLearnt(false); + findWatchedOfBin(solver.watches, lit2 ,lit1, learnt).setLearnt(false); + solver.learnts_literals -= 2; + solver.clauses_literals += 2; +} diff --git a/src/prop/cryptominisat/Solver/ClauseVivifier.h b/src/prop/cryptominisat/Solver/ClauseVivifier.h new file mode 100644 index 000000000..51a345e59 --- /dev/null +++ b/src/prop/cryptominisat/Solver/ClauseVivifier.h @@ -0,0 +1,61 @@ +/************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef CLAUSEVIVIFIER_H +#define CLAUSEVIVIFIER_H + +#include "Solver.h" + +namespace CMSat { + +class ClauseVivifier { + public: + ClauseVivifier(Solver& solver); + bool vivifyClauses(); + bool vivifyClauses2(vec<Clause*>& clauses); + + private: + + /** + @brief Records data for asymmBranch() + + Clauses are ordered accurding to sze in asymmBranch() and then some are + checked if we could shorten them. This value records that between calls + to asymmBranch() where we stopped last time in the list + */ + uint32_t lastTimeWentUntil; + + /** + @brief Sort clauses according to size + */ + struct sortBySize + { + bool operator () (const Clause* x, const Clause* y) + { + return (x->size() > y->size()); + } + }; + + void makeNonLearntBin(const Lit lit1, const Lit lit2, const bool learnt); + + uint32_t numCalls; + Solver& solver; +}; + +} + +#endif //CLAUSEVIVIFIER_H diff --git a/src/prop/cryptominisat/Solver/CompleteDetachReattacher.cpp b/src/prop/cryptominisat/Solver/CompleteDetachReattacher.cpp new file mode 100644 index 000000000..833f13c63 --- /dev/null +++ b/src/prop/cryptominisat/Solver/CompleteDetachReattacher.cpp @@ -0,0 +1,198 @@ +/************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "CompleteDetachReattacher.h" +#include "VarReplacer.h" +#include "ClauseCleaner.h" + +using namespace CMSat; + +CompleteDetachReatacher::CompleteDetachReatacher(Solver& _solver) : + solver(_solver) +{ +} + +/** +@brief Completely detach all non-binary clauses +*/ +void CompleteDetachReatacher::detachNonBinsNonTris(const bool removeTri) +{ + uint32_t oldNumBins = solver.numBins; + ClausesStay stay; + + for (vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++) { + stay += clearWatchNotBinNotTri(*it, removeTri); + } + + solver.learnts_literals = stay.learntBins; + solver.clauses_literals = stay.nonLearntBins; + solver.numBins = (stay.learntBins + stay.nonLearntBins)/2; + release_assert(solver.numBins == oldNumBins); +} + +/** +@brief Helper function for detachPointerUsingClauses() +*/ +const CompleteDetachReatacher::ClausesStay CompleteDetachReatacher::clearWatchNotBinNotTri(vec<Watched>& ws, const bool removeTri) +{ + ClausesStay stay; + + vec<Watched>::iterator i = ws.getData(); + vec<Watched>::iterator j = i; + for (vec<Watched>::iterator end = ws.getDataEnd(); i != end; i++) { + if (i->isBinary()) { + if (i->getLearnt()) stay.learntBins++; + else stay.nonLearntBins++; + *j++ = *i; + } else if (!removeTri && i->isTriClause()) { + stay.tris++; + *j++ = *i; + } + } + ws.shrink_(i-j); + + return stay; +} + +/** +@brief Completely attach all clauses +*/ +bool CompleteDetachReatacher::reattachNonBins() +{ + assert(solver.ok); + + cleanAndAttachClauses(solver.clauses); + cleanAndAttachClauses(solver.learnts); + cleanAndAttachClauses(solver.xorclauses); + solver.clauseCleaner->removeSatisfiedBins(); + + if (solver.ok) solver.ok = (solver.propagate<false>().isNULL()); + + return solver.ok; +} + +/** +@brief Cleans clauses from failed literals/removes satisfied clauses from cs + +May change solver.ok to FALSE (!) +*/ +inline void CompleteDetachReatacher::cleanAndAttachClauses(vec<Clause*>& cs) +{ + Clause **i = cs.getData(); + Clause **j = i; + PolaritySorter sorter(solver.polarity); + for (Clause **end = cs.getDataEnd(); i != end; i++) { + std::sort((*i)->getData(), (*i)->getDataEnd(), sorter); + if (cleanClause(*i)) { + solver.attachClause(**i); + *j++ = *i; + } else { + solver.clauseAllocator.clauseFree(*i); + } + } + cs.shrink(i-j); +} + +/** +@brief Cleans clauses from failed literals/removes satisfied clauses from cs +*/ +inline void CompleteDetachReatacher::cleanAndAttachClauses(vec<XorClause*>& cs) +{ + XorClause **i = cs.getData(); + XorClause **j = i; + for (XorClause **end = cs.getDataEnd(); i != end; i++) { + if (cleanClause(**i)) { + solver.attachClause(**i); + *j++ = *i; + } else { + solver.clauseAllocator.clauseFree(*i); + } + } + cs.shrink(i-j); +} + +/** +@brief Not only cleans a clause from false literals, but if clause is satisfied, it reports it +*/ +inline bool CompleteDetachReatacher::cleanClause(Clause*& cl) +{ + Clause& ps = *cl; + assert(ps.size() > 2); + + Lit *i = ps.getData(); + Lit *j = i; + for (Lit *end = ps.getDataEnd(); i != end; i++) { + if (solver.value(*i) == l_True) return false; + if (solver.value(*i) == l_Undef) { + *j++ = *i; + } + } + ps.shrink(i-j); + + switch (ps.size()) { + case 0: + solver.ok = false; + return false; + case 1: + solver.uncheckedEnqueue(ps[0]); + return false; + + case 2: { + solver.attachBinClause(ps[0], ps[1], ps.learnt()); + return false; + } + + default:; + } + + return true; +} + +/** +@brief Not only cleans a clause from false literals, but if clause is satisfied, it reports it +*/ +inline bool CompleteDetachReatacher::cleanClause(XorClause& ps) +{ + Lit *i = ps.getData(), *j = i; + for (Lit *end = ps.getDataEnd(); i != end; i++) { + if (solver.assigns[i->var()] == l_True) ps.invert(true); + if (solver.assigns[i->var()] == l_Undef) { + *j++ = *i; + } + } + ps.shrink(i-j); + + switch (ps.size()) { + case 0: + if (ps.xorEqualFalse() == false) solver.ok = false; + return false; + case 1: + solver.uncheckedEnqueue(Lit(ps[0].var(), ps.xorEqualFalse())); + return false; + + case 2: { + ps[0] = ps[0].unsign(); + ps[1] = ps[1].unsign(); + solver.varReplacer->replace(ps, ps.xorEqualFalse()); + return false; + } + + default:; + } + + return true; +} diff --git a/src/prop/cryptominisat/Solver/CompleteDetachReattacher.h b/src/prop/cryptominisat/Solver/CompleteDetachReattacher.h new file mode 100644 index 000000000..2d9dacfa0 --- /dev/null +++ b/src/prop/cryptominisat/Solver/CompleteDetachReattacher.h @@ -0,0 +1,78 @@ +/************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "Solver.h" + +namespace CMSat { + +/** +@brief Helper class to completely detaches all(or only non-native) clauses, and then re-attach all + +Used in classes that (may) do a lot of clause-changning, in which case +detaching&reattaching of clauses would be neccessary to do +individually, which is \b very slow + +A main use-case is the following: +-# detach all clauses +-# play around with all clauses as desired. Cannot call solver.propagate() here +-# attach all clauses again + +A somewhat more complicated, but more interesting use-case is the following: +-# detach only non-natively stored clauses from watchlists +-# play around wil all clauses as desired. 2- and 3-long clauses can still +be propagated with solver.propagate() -- this is quite a nice trick, in fact +-# detach all clauses (i.e. also native ones) +-# attach all clauses +*/ +class CompleteDetachReatacher +{ + public: + CompleteDetachReatacher(Solver& solver); + bool reattachNonBins(); + void detachNonBinsNonTris(const bool removeTri); + + private: + class ClausesStay { + public: + ClausesStay() : + learntBins(0) + , nonLearntBins(0) + , tris(0) + {} + + ClausesStay& operator+=(const ClausesStay& other) { + learntBins += other.learntBins; + nonLearntBins += other.nonLearntBins; + tris += other.tris; + return *this; + } + + uint32_t learntBins; + uint32_t nonLearntBins; + uint32_t tris; + }; + const ClausesStay clearWatchNotBinNotTri(vec<Watched>& ws, const bool removeTri = false); + + void cleanAndAttachClauses(vec<Clause*>& cs); + void cleanAndAttachClauses(vec<XorClause*>& cs); + bool cleanClause(Clause*& ps); + bool cleanClause(XorClause& ps); + + Solver& solver; +}; + +} diff --git a/src/prop/cryptominisat/Solver/DataSync.cpp b/src/prop/cryptominisat/Solver/DataSync.cpp new file mode 100644 index 000000000..3e7956a19 --- /dev/null +++ b/src/prop/cryptominisat/Solver/DataSync.cpp @@ -0,0 +1,216 @@ +/***************************************************************************** +CryptoMiniSat -- Copyright (c) 2010 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +******************************************************************************/ + +#include "DataSync.h" +#include "Subsumer.h" +#include "VarReplacer.h" +#include "XorSubsumer.h" +#include <iomanip> + +using namespace CMSat; + +DataSync::DataSync(Solver& _solver, SharedData* _sharedData) : + lastSyncConf(0) + , sentUnitData(0) + , recvUnitData(0) + , sharedData(_sharedData) + , solver(_solver) +{} + +void DataSync::newVar() +{ + syncFinish.push(0); + syncFinish.push(0); + seen.push(false); + seen.push(false); +} + +bool DataSync::syncData() +{ + if (sharedData == NULL + || lastSyncConf + SYNC_EVERY_CONFL >= solver.conflicts) return true; + + assert(sharedData != NULL); + assert(solver.decisionLevel() == 0); + + bool ok; + #pragma omp critical (unitData) + ok = shareUnitData(); + if (!ok) return false; + + #pragma omp critical (binData) + ok = shareBinData(); + if (!ok) return false; + + lastSyncConf = solver.conflicts; + + return true; +} + +bool DataSync::shareBinData() +{ + uint32_t oldRecvBinData = recvBinData; + uint32_t oldSentBinData = sentBinData; + + SharedData& shared = *sharedData; + if (shared.bins.size() != solver.nVars()*2) + shared.bins.resize(solver.nVars()*2); + + for (uint32_t wsLit = 0; wsLit < solver.nVars()*2; wsLit++) { + Lit lit1 = ~Lit::toLit(wsLit); + lit1 = solver.varReplacer->getReplaceTable()[lit1.var()] ^ lit1.sign(); + if (solver.subsumer->getVarElimed()[lit1.var()] + || solver.xorSubsumer->getVarElimed()[lit1.var()] + || solver.value(lit1.var()) != l_Undef + ) continue; + + vector<Lit>& bins = shared.bins[wsLit]; + vec<Watched>& ws = solver.watches[wsLit]; + + if (bins.size() > syncFinish[wsLit] + && !syncBinFromOthers(lit1, bins, syncFinish[wsLit], ws)) return false; + } + + syncBinToOthers(); + + if (solver.conf.verbosity >= 3) { + std::cout << "c got bins " << std::setw(10) << (recvBinData - oldRecvBinData) + << std::setw(10) << " sent bins " << (sentBinData - oldSentBinData) << std::endl; + } + + return true; +} + +bool DataSync::syncBinFromOthers(const Lit lit, const vector<Lit>& bins, uint32_t& finished, vec<Watched>& ws) +{ + assert(solver.varReplacer->getReplaceTable()[lit.var()].var() == lit.var()); + assert(solver.subsumer->getVarElimed()[lit.var()] == false); + assert(solver.xorSubsumer->getVarElimed()[lit.var()] == false); + + vec<Lit> addedToSeen; + for (vec<Watched>::iterator it = ws.getData(), end = ws.getDataEnd(); it != end; it++) { + if (it->isBinary()) { + addedToSeen.push(it->getOtherLit()); + seen[it->getOtherLit().toInt()] = true; + } + } + + vec<Lit> lits(2); + for (uint32_t i = finished; i < bins.size(); i++) { + if (!seen[bins[i].toInt()]) { + Lit otherLit = bins[i]; + otherLit = solver.varReplacer->getReplaceTable()[otherLit.var()] ^ otherLit.sign(); + if (solver.subsumer->getVarElimed()[otherLit.var()] + || solver.xorSubsumer->getVarElimed()[otherLit.var()] + || solver.value(otherLit.var()) != l_Undef + ) continue; + + recvBinData++; + lits[0] = lit; + lits[1] = otherLit; + solver.addClauseInt(lits, true, 2, 0, true); + lits.clear(); + lits.growTo(2); + if (!solver.ok) goto end; + } + } + finished = bins.size(); + + end: + for (uint32_t i = 0; i < addedToSeen.size(); i++) + seen[addedToSeen[i].toInt()] = false; + + return solver.ok; +} + +void DataSync::syncBinToOthers() +{ + for(vector<std::pair<Lit, Lit> >::const_iterator it = newBinClauses.begin(), end = newBinClauses.end(); it != end; it++) { + addOneBinToOthers(it->first, it->second); + } + + newBinClauses.clear(); +} + +void DataSync::addOneBinToOthers(const Lit lit1, const Lit lit2) +{ + assert(lit1.toInt() < lit2.toInt()); + + vector<Lit>& bins = sharedData->bins[(~lit1).toInt()]; + for (vector<Lit>::const_iterator it = bins.begin(), end = bins.end(); it != end; it++) { + if (*it == lit2) return; + } + + bins.push_back(lit2); + sentBinData++; +} + +bool DataSync::shareUnitData() +{ + uint32_t thisGotUnitData = 0; + uint32_t thisSentUnitData = 0; + + SharedData& shared = *sharedData; + shared.value.growTo(solver.nVars(), l_Undef); + for (uint32_t var = 0; var < solver.nVars(); var++) { + Lit thisLit = Lit(var, false); + thisLit = solver.varReplacer->getReplaceTable()[thisLit.var()] ^ thisLit.sign(); + const lbool thisVal = solver.value(thisLit); + const lbool otherVal = shared.value[var]; + + if (thisVal == l_Undef && otherVal == l_Undef) continue; + if (thisVal != l_Undef && otherVal != l_Undef) { + if (thisVal != otherVal) { + solver.ok = false; + return false; + } else { + continue; + } + } + + if (otherVal != l_Undef) { + assert(thisVal == l_Undef); + Lit litToEnqueue = thisLit ^ (otherVal == l_False); + if (solver.subsumer->getVarElimed()[litToEnqueue.var()] + || solver.xorSubsumer->getVarElimed()[litToEnqueue.var()] + ) continue; + + solver.uncheckedEnqueue(litToEnqueue); + solver.ok = solver.propagate<false>().isNULL(); + if (!solver.ok) return false; + thisGotUnitData++; + continue; + } + + if (thisVal != l_Undef) { + assert(otherVal == l_Undef); + shared.value[var] = thisVal; + thisSentUnitData++; + continue; + } + } + + if (solver.conf.verbosity >= 3 && (thisGotUnitData > 0 || thisSentUnitData > 0)) { + std::cout << "c got units " << std::setw(8) << thisGotUnitData + << " sent units " << std::setw(8) << thisSentUnitData << std::endl; + } + + recvUnitData += thisGotUnitData; + sentUnitData += thisSentUnitData; + + return true; +} diff --git a/src/prop/cryptominisat/Solver/DataSync.h b/src/prop/cryptominisat/Solver/DataSync.h new file mode 100644 index 000000000..96ac7a355 --- /dev/null +++ b/src/prop/cryptominisat/Solver/DataSync.h @@ -0,0 +1,101 @@ +/***************************************************************************** +CryptoMiniSat -- Copyright (c) 2010 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +******************************************************************************/ + +#include "SharedData.h" +#include "Solver.h" + +namespace CMSat { + +class DataSync +{ + public: + DataSync(Solver& solver, SharedData* sharedData); + void newVar(); + bool syncData(); + + + template <class T> void signalNewBinClause(T& ps); + void signalNewBinClause(Lit lit1, Lit lit2); + + uint32_t getSentUnitData() const; + uint32_t getRecvUnitData() const; + uint32_t getSentBinData() const; + uint32_t getRecvBinData() const; + + private: + //functions + bool shareUnitData(); + bool syncBinFromOthers(const Lit lit, const vector<Lit>& bins, uint32_t& finished, vec<Watched>& ws); + void syncBinToOthers(); + void addOneBinToOthers(const Lit lit1, const Lit lit2); + bool shareBinData(); + + //stuff to sync + vector<std::pair<Lit, Lit> > newBinClauses; + + //stats + uint64_t lastSyncConf; + vec<uint32_t> syncFinish; + uint32_t sentUnitData; + uint32_t recvUnitData; + uint32_t sentBinData; + uint32_t recvBinData; + + //misc + vec<char> seen; + + //main data + SharedData* sharedData; + Solver& solver; +}; + +inline uint32_t DataSync::getSentUnitData() const +{ + return sentUnitData; +} + +inline uint32_t DataSync::getRecvUnitData() const +{ + return recvUnitData; +} + +inline uint32_t DataSync::getSentBinData() const +{ + return sentBinData; +} + +inline uint32_t DataSync::getRecvBinData() const +{ + return recvBinData; +} + +template <class T> +inline void DataSync::signalNewBinClause(T& ps) +{ + if (sharedData == NULL) return; + assert(ps.size() == 2); + signalNewBinClause(ps[0], ps[1]); +} + +inline void DataSync::signalNewBinClause(Lit lit1, Lit lit2) +{ + if (sharedData == NULL) return; + if (lit1.toInt() > lit2.toInt()) std::swap(lit1, lit2); + newBinClauses.push_back(std::make_pair(lit1, lit2)); +} + +} diff --git a/src/prop/cryptominisat/Solver/DimacsParser.cpp b/src/prop/cryptominisat/Solver/DimacsParser.cpp new file mode 100644 index 000000000..0fc4d9d74 --- /dev/null +++ b/src/prop/cryptominisat/Solver/DimacsParser.cpp @@ -0,0 +1,490 @@ +/***************************************************************************** +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +Original code by MiniSat authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3 licence. +******************************************************************************/ + +#include "DimacsParser.h" +#include <sstream> +#include <iostream> +#include <iomanip> + +#include "Solver.h" + +#ifdef VERBOSE_DEBUG +#define DEBUG_COMMENT_PARSING +#endif //VERBOSE_DEBUG + +//#define DEBUG_COMMENT_PARSING + +using namespace CMSat; + +DimacsParseError::DimacsParseError(const std::string& arg) + : std::runtime_error(arg) { } + +DimacsParseError::~DimacsParseError() throw() { } + +DimacsParser::DimacsParser(Solver* _solver, const bool _debugLib, const bool _debugNewVar, const bool _grouping, const bool _addAsLearnt): + solver(_solver) + , debugLib(_debugLib) + , debugNewVar(_debugNewVar) + , grouping(_grouping) + , addAsLearnt(_addAsLearnt) +{} + +/** +@brief Skips all whitespaces +*/ +void DimacsParser::skipWhitespace(StreamBuffer& in) +{ + while ((*in >= 9 && *in <= 13 && *in != 10) || *in == 32) + ++in; +} + +/** +@brief Skips until the end of the line +*/ +void DimacsParser::skipLine(StreamBuffer& in) +{ + for (;;) { + if (*in == EOF || *in == '\0') return; + if (*in == '\n') { + ++in; + return; + } + ++in; + } +} + +/** +@brief Returns line until the end of line +*/ +std::string DimacsParser::untilEnd(StreamBuffer& in) +{ + std::string ret; + + while(*in != EOF && *in != '\0' && *in != '\n') { + ret += *in; + ++in; + } + + return ret; +} + +/** +@brief Parses in an integer +*/ +int32_t DimacsParser::parseInt(StreamBuffer& in, uint32_t& lenParsed) throw (DimacsParseError) +{ + lenParsed = 0; + int32_t val = 0; + bool neg = false; + skipWhitespace(in); + if (*in == '-') neg = true, ++in; + else if (*in == '+') ++in; + if (*in < '0' || *in > '9') { + std::ostringstream ostr; + ostr << "Unexpected char (parseInt): " << *in; + throw DimacsParseError(ostr.str()); + } + while (*in >= '0' && *in <= '9') { + lenParsed++; + val = val*10 + (*in - '0'), + ++in; + } + return neg ? -val : val; +} + +float DimacsParser::parseFloat(StreamBuffer& in) throw (DimacsParseError) +{ + uint32_t len; + uint32_t main = parseInt(in, len); + if (*in != '.') { + std::ostringstream ostr; + ostr << "Float does not contain a dot! Instead it contains: " << *in; + throw DimacsParseError(ostr.str()); + } + ++in; + uint32_t sub = parseInt(in, len); + + uint32_t exp = 1; + for (uint32_t i = 0;i < len; i++) exp *= 10; + return (float)main + ((float)sub/exp); +} + + +std::string DimacsParser::stringify(uint32_t x) +{ + std::ostringstream o; + o << x; + return o.str(); +} + +/** +@brief Parse a continious set of characters from "in" to "str". + +\todo EOF is not checked for!! +*/ +void DimacsParser::parseString(StreamBuffer& in, std::string& str) +{ + str.clear(); + skipWhitespace(in); + while (*in != ' ' && *in != '\n') { + str += *in; + ++in; + } +} + +/** +@brief Reads in a clause and puts it in lit +@p[out] lits +*/ +void DimacsParser::readClause(StreamBuffer& in, vec<Lit>& lits) throw (DimacsParseError) +{ + int32_t parsed_lit; + Var var; + uint32_t len; + lits.clear(); + for (;;) { + parsed_lit = parseInt(in, len); + if (parsed_lit == 0) break; + var = abs(parsed_lit)-1; + if (!debugNewVar) { + if (var >= ((uint32_t)1)<<25) { + std::ostringstream ostr; + ostr << "Variable requested is far too large: " << var; + throw DimacsParseError(ostr.str()); + } + while (var >= solver->nVars()) solver->newVar(); + } + lits.push( (parsed_lit > 0) ? Lit(var, false) : Lit(var, true) ); + } +} + +/** +@brief Matches parameter "str" to content in "in" +*/ +bool DimacsParser::match(StreamBuffer& in, const char* str) +{ + for (; *str != 0; ++str, ++in) + if (*str != *in) + return false; + return true; +} + +/** +@brief Prints the data in "p cnf VARS CLAUSES" header in DIMACS + +We don't actually do \b anything with these. It's just printed for user +happyness. However, I think it's useless to print it, since it might mislead +users to think that their headers are correct, even though a lot of headers are +completely wrong, thanks to MiniSat printing the header, but not checking it. +Not checking it is \b not a problem. The problem is printing it such that +people believe it's validated +*/ +void DimacsParser::printHeader(StreamBuffer& in) throw (DimacsParseError) +{ + uint32_t len; + + if (match(in, "p cnf")) { + int vars = parseInt(in, len); + int clauses = parseInt(in, len); + if (solver->conf.verbosity >= 1) { + std::cout << "c -- header says num vars: " << std::setw(12) << vars << std::endl; + std::cout << "c -- header says num clauses:" << std::setw(12) << clauses << std::endl; + } + } else { + std::ostringstream ostr; + ostr << "Unexpected char: " << *in; + throw DimacsParseError(ostr.str()); + } +} + +/** +@brief Parse up comment lines which could contain important information + +In CryptoMiniSat we save quite a bit of information in the comment lines. +These need to be parsed up. This function achieves that. Informations that +can be given: +\li "c Solver::newVar() called" -- we execute Solver::newVar() +\li "c Solver::solve() called" -- we execute Solver::solve() and dump the +solution to debugLibPartX.out, where X is a number that starts with 1 and +increases to N, where N is the number of solve() instructions +\li variable names in the form of "c var VARNUM NAME" +*/ +void DimacsParser::parseComments(StreamBuffer& in, const std::string str) throw (DimacsParseError) +{ + uint32_t len; + #ifdef DEBUG_COMMENT_PARSING + std::cout << "Parsing comments" << std::endl; + #endif //DEBUG_COMMENT_PARSING + + if (str == "v" || str == "var") { + int var = parseInt(in, len); + skipWhitespace(in); + if (var <= 0) + throw DimacsParseError("Var number must be a positive integer"); + std::string name = untilEnd(in); + //Don't do anythint with NAME, just forget it + + #ifdef DEBUG_COMMENT_PARSING + std::cout << "Parsed 'c var'" << std::endl; + #endif //DEBUG_COMMENT_PARSING + } else if (debugLib && str == "Solver::solve()") { + lbool ret = solver->solve(); + std::string s = "debugLibPart" + stringify(debugLibPart) +".output"; + FILE* res = fopen(s.c_str(), "w"); + if (ret == l_True) { + fprintf(res, "SAT\n"); + for (Var i = 0; i != solver->nVars(); i++) { + if (solver->model[i] != l_Undef) + fprintf(res, "%s%d ", (solver->model[i]==l_True)?"":"-", i+1); + } + fprintf(res, "0\n"); + } else if (ret == l_False) { + fprintf(res, "UNSAT\n"); + } else if (ret == l_Undef) { + assert(false); + } else { + assert(false); + } + fclose(res); + debugLibPart++; + + #ifdef DEBUG_COMMENT_PARSING + std::cout << "Parsed Solver::solve()" << std::endl; + #endif //DEBUG_COMMENT_PARSING + } else if (debugNewVar && str == "Solver::newVar()") { + solver->newVar(); + + #ifdef DEBUG_COMMENT_PARSING + std::cout << "Parsed Solver::newVar()" << std::endl; + #endif //DEBUG_COMMENT_PARSING + } else { + #ifdef DEBUG_COMMENT_PARSING + std::cout << "didn't understand in CNF file: 'c " << str << std::endl; + #endif //DEBUG_COMMENT_PARSING + } + skipLine(in); +} + +/** +@brief Parses clause parameters given as e.g. "c clause learnt yes glue 4 miniSatAct 5.2" +*/ +void DimacsParser::parseClauseParameters(StreamBuffer& in, bool& learnt, uint32_t& glue, float& miniSatAct) +{ + std::string str; + uint32_t len; + + //Parse in if we are a learnt clause or not + ++in; + parseString(in, str); + if (str != "learnt") goto addTheClause; + + ++in; + parseString(in, str); + if (str == "yes") learnt = true; + else if (str == "no") { + learnt = false; + goto addTheClause; + } + else { + std::cout << "parsed in instead of yes/no: '" << str << "'" << std::endl; + goto addTheClause; + } + + //Parse in Glue value + ++in; + parseString(in, str); + if (str != "glue") goto addTheClause; + ++in; + glue = parseInt(in, len); + + //Parse in MiniSat activity + ++in; + parseString(in, str); + if (str != "miniSatAct") goto addTheClause; + ++in; + miniSatAct = parseFloat(in); + + addTheClause: + skipLine(in); + return; +} + +/** +@brief Parses in a clause and its optional attributes + +We might have lines like: +\li "c clause learnt yes glue 4 miniSatAct 5.2" which we need to parse up and +make the clause learnt. +\li Also, groupings can be given with "c group NUM NAME" after the clause. +\li Furthermore, we need to take care, since comments might mean orders like +"c Solver::newVar() called", which needs to be parsed with parseComments() +-- this, we delegate +*/ +void DimacsParser::readFullClause(StreamBuffer& in) throw (DimacsParseError) +{ + bool xor_clause = false; + bool learnt = false; + uint32_t glue = 100.0; + float miniSatAct = 10.0; + std::string name; + std::string str; + uint32_t len; + bool needToParseComments = false; + + //read in the actual clause + if ( *in == 'x') xor_clause = true, ++in; + readClause(in, lits); + skipLine(in); + + //now read in grouping information, etc. + if (grouping) { + if (*in != 'c') + throw DimacsParseError("Group must be present after each clause ('c' missing after clause line)"); + ++in; + + parseString(in, str); + if (str != "g" && str != "group") { + std::ostringstream ostr; + ostr << "Group must be present after each clause('group' missing)!" << std:: endl + << "Instead of 'group' there was: " << str; + throw DimacsParseError(ostr.str()); + } + + int groupId = parseInt(in, len); + groupId++; + //Don't do anything with grupId + + skipWhitespace(in); + name = untilEnd(in); + } + + //Parse comments or parse clause type (learnt, glue value, etc.) + if (*in == 'c') { + ++in; + parseString(in, str); + if (str == "clause") { + parseClauseParameters(in, learnt, glue, miniSatAct); + } else { + needToParseComments = true; + } + } + + if (xor_clause) { + bool xorEqualFalse = false; + for (uint32_t i = 0; i < lits.size(); i++) + xorEqualFalse ^= lits[i].sign(); + + solver->addXorClause(lits, xorEqualFalse); + numXorClauses++; + } else { + if (addAsLearnt || learnt) { + solver->addLearntClause(lits, glue, miniSatAct); + numLearntClauses++; + } else { + solver->addClause(lits); + numNormClauses++; + } + } + + if (needToParseComments) { + #ifdef DEBUG_COMMENT_PARSING + std::cout << "Need to parse comments:" << str << std::endl; + #endif //DEBUG_COMMENT_PARSING + parseComments(in, str); + } +} + +void DimacsParser::readBranchingOrder(StreamBuffer& in) +{ + skipWhitespace(in); + + while (1) { + int parsed_var; + uint32_t len; + + parsed_var = parseInt(in, len); + if (parsed_var == 0) + break; + + solver->addBranchingVariable(parsed_var - 1); + } +} + +/** +@brief The main function: parses in a full DIMACS file + +Parses in header, the clauses, and special comment lines that define clause +groups, clause group names, and variable names, plus it parses up special +comments that have to do with debugging Solver::newVar() and Solver::solve() +calls for library-debugging +*/ +void DimacsParser::parse_DIMACS_main(StreamBuffer& in) +{ + std::string str; + + for (;;) { + skipWhitespace(in); + switch (*in) { + case EOF: + return; + case 'p': + printHeader(in); + skipLine(in); + break; + case 'c': + ++in; + parseString(in, str); + parseComments(in, str); + break; + case 'b': + ++in; + readBranchingOrder(in); + break; + case '\n': + //Skipping empty line, even though empty lines are kind of out-of-spec + ++in; + break; + default: + readFullClause(in); + if (!solver->okay()) return; + break; + } + } +} + +template <class T> +void DimacsParser::parse_DIMACS(T input_stream) +{ + debugLibPart = 1; + numLearntClauses = 0; + numNormClauses = 0; + numXorClauses = 0; + uint32_t origNumVars = solver->nVars(); + + StreamBuffer in(input_stream); + parse_DIMACS_main(in); + + if (solver->conf.verbosity >= 1) { + std::cout << "c -- clauses added: " + << std::setw(12) << numLearntClauses + << " learnts, " + << std::setw(12) << numNormClauses + << " normals, " + << std::setw(12) << numXorClauses + << " xors" + << std::endl; + + std::cout << "c -- vars added " << std::setw(10) << (solver->nVars() - origNumVars) + << std::endl; + } +} + +#ifndef DISABLE_ZLIB +template void DimacsParser::parse_DIMACS(gzFile input_stream); +#endif +template void DimacsParser::parse_DIMACS(FILE* input_stream); diff --git a/src/prop/cryptominisat/Solver/DimacsParser.h b/src/prop/cryptominisat/Solver/DimacsParser.h new file mode 100644 index 000000000..c149214ba --- /dev/null +++ b/src/prop/cryptominisat/Solver/DimacsParser.h @@ -0,0 +1,84 @@ +/***************************************************************************** +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +Original code by MiniSat authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3 licence. +******************************************************************************/ + +#ifndef DIMACSPARSER_H +#define DIMACSPARSER_H + +#include <stdexcept> +#include <string> +#include "SolverTypes.h" +#include "constants.h" +#include "StreamBuffer.h" +#include "Vec.h" + +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#ifndef DISABLE_ZLIB +#include <zlib.h> +#endif // DISABLE_ZLIB + +namespace CMSat { + +class Solver; + +class DimacsParseError : public std::runtime_error +{ + public: + explicit DimacsParseError(const std::string& arg); + virtual ~DimacsParseError() throw(); +}; + +/** +@brief Parses up a DIMACS file that my be zipped +*/ +class DimacsParser +{ + public: + DimacsParser(Solver* solver, const bool debugLib, const bool debugNewVar, const bool grouping, const bool addAsLearnt = false); + + template <class T> + void parse_DIMACS(T input_stream); + + private: + void parse_DIMACS_main(StreamBuffer& in); + void skipWhitespace(StreamBuffer& in); + void skipLine(StreamBuffer& in); + std::string untilEnd(StreamBuffer& in); + int32_t parseInt(StreamBuffer& in, uint32_t& len) throw (DimacsParseError); + float parseFloat(StreamBuffer& in) throw (DimacsParseError); + void parseString(StreamBuffer& in, std::string& str); + void readClause(StreamBuffer& in, vec<Lit>& lits) throw (DimacsParseError); + void parseClauseParameters(StreamBuffer& in, bool& learnt, uint32_t& glue, float& miniSatAct); + void readFullClause(StreamBuffer& in) throw (DimacsParseError); + void readBranchingOrder(StreamBuffer& in); + bool match(StreamBuffer& in, const char* str); + void printHeader(StreamBuffer& in) throw (DimacsParseError); + void parseComments(StreamBuffer& in, const std::string str) throw (DimacsParseError); + std::string stringify(uint32_t x); + + + Solver *solver; + const bool debugLib; + const bool debugNewVar; + const bool grouping; + const bool addAsLearnt; + + uint32_t debugLibPart; ///<printing partial solutions to debugLibPart1..N.output when "debugLib" is set to TRUE + vec<Lit> lits; ///<To reduce temporary creation overhead + uint32_t numLearntClauses; ///<Number of learnt non-xor clauses added + uint32_t numNormClauses; ///<Number of non-learnt, non-xor claues added + uint32_t numXorClauses; ///<Number of non-learnt xor clauses added +}; + +} + +#endif //DIMACSPARSER_H diff --git a/src/prop/cryptominisat/Solver/DoublePackedRow.h b/src/prop/cryptominisat/Solver/DoublePackedRow.h new file mode 100644 index 000000000..cbeee2f71 --- /dev/null +++ b/src/prop/cryptominisat/Solver/DoublePackedRow.h @@ -0,0 +1,173 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#ifndef DOUBLEPACKEDROW_H +#define DOUBLEPACKEDROW_H + +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#include <stdlib.h> + +#include "SolverTypes.h" + +namespace CMSat +{ +using namespace CMSat; + +class DoublePackedRow +{ + private: + class BitIter { + public: + inline void operator=(const lbool toSet) + { + val &= ~((unsigned char)3 << offset); + val |= toSet.value << offset; + } + + inline operator lbool() const + { + return lbool((val >> offset) & 3); + } + + inline const bool isUndef() const { + return ((lbool)*this).isUndef(); + } + inline const bool isDef() const { + return ((lbool)*this).isDef(); + } + inline const bool getBool() const { + return ((lbool)*this).getBool(); + } + inline const bool operator==(lbool b) const { + return ((lbool)*this) == b; + } + inline const bool operator!=(lbool b) const { + return ((lbool)*this) != b; + } + const lbool operator^(const bool b) const { + return ((lbool)*this) ^ b; + } + + private: + friend class DoublePackedRow; + inline BitIter(unsigned char& mp, const uint32_t _offset) : + val(mp) + , offset(_offset) + {} + + unsigned char& val; + const uint32_t offset; + }; + + class BitIterConst { + public: + inline operator lbool() const + { + return lbool((val >> offset) & 3); + } + + inline const bool isUndef() const { + return ((lbool)*this).isUndef(); + } + inline const bool isDef() const { + return ((lbool)*this).isDef(); + } + inline const bool getBool() const { + return ((lbool)*this).getBool(); + } + inline const bool operator==(lbool b) const { + return ((lbool)*this) == b; + } + inline const bool operator!=(lbool b) const { + return ((lbool)*this) != b; + } + const lbool operator^(const bool b) const { + return ((lbool)*this) ^ b; + } + + + private: + friend class DoublePackedRow; + inline BitIterConst(unsigned char& mp, const uint32_t _offset) : + val(mp) + , offset(_offset) + {} + + const unsigned char& val; + const uint32_t offset; + }; + + public: + DoublePackedRow() : + numElems(0) + , mp(NULL) + {} + + uint32_t size() const + { + return numElems; + } + + void growTo(const uint32_t newNumElems) + { + uint32_t oldSize = numElems/4 + (bool)(numElems % 4); + uint32_t newSize = newNumElems/4 + (bool)(newNumElems % 4); + + if (oldSize >= newSize) { + numElems = std::max(newNumElems, numElems); + return; + } + + mp = (unsigned char*)realloc(mp, newSize*sizeof(unsigned char)); + numElems = newNumElems; + } + + inline BitIter operator[](const uint32_t at) + { + return BitIter(mp[at/4], (at%4)*2); + } + + inline const BitIterConst operator[](const uint32_t at) const + { + return BitIterConst(mp[at/4], (at%4)*2); + } + + inline void push(const lbool val) + { + growTo(numElems+1); + (*this)[numElems-1] = val; + } + + /*void clear(const uint32_t at) + { + mp[at/32] &= ~((uint64_t)3 << ((at%32)*2)); + }*/ + + private: + + Var numElems; + unsigned char *mp; +}; + +}; //NAMESPACE MINISAT + +#endif //DOUBLEPACKEDROW_H diff --git a/src/prop/cryptominisat/Solver/FailedLitSearcher.cpp b/src/prop/cryptominisat/Solver/FailedLitSearcher.cpp new file mode 100644 index 000000000..a847c5e09 --- /dev/null +++ b/src/prop/cryptominisat/Solver/FailedLitSearcher.cpp @@ -0,0 +1,768 @@ +/************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "FailedLitSearcher.h" + +#include <iomanip> +#include <utility> +#include <set> + +#include "Solver.h" +#include "ClauseCleaner.h" +#include "time_mem.h" +#include "VarReplacer.h" +#include "ClauseCleaner.h" +#include "StateSaver.h" +#include "CompleteDetachReattacher.h" + +//#define VERBOSE_DEUBUG + +using namespace CMSat; +using std::make_pair; +using std::set; + +/** +@brief Sets up variables that are used between calls to search() +*/ +FailedLitSearcher::FailedLitSearcher(Solver& _solver): + solver(_solver) + , tmpPs(2) + , totalTime(0) + , numPropsMultiplier(1.0) + , lastTimeFoundTruths(0) + , numCalls(0) +{ + lastTimeStopped = solver.mtrand.randInt(solver.nVars()); +} + +/** +@brief Initialises datastructures for 2-long xor finding by shortening longer xors +*/ +void FailedLitSearcher::addFromSolver(const vec< XorClause* >& cs) +{ + xorClauseSizes.clear(); + xorClauseSizes.growTo(cs.size()); + occur.resize(solver.nVars()); + for (Var var = 0; var < solver.nVars(); var++) { + occur[var].clear(); + } + + uint32_t i = 0; + for (XorClause * const*it = cs.getData(), * const*end = it + cs.size(); it != end; it++, i++) { + if (it+1 != end) __builtin_prefetch(*(it+1)); + + const XorClause& cl = **it; + xorClauseSizes[i] = cl.size(); + for (const Lit *l = cl.getData(), *end2 = l + cl.size(); l != end2; l++) { + occur[l->var()].push_back(i); + } + } +} + +/** +@brief Remove the assinged vars from the xors added by addFromSolver() + +The thus shortened xors are then treated if they are 2-long and if they +appear twice: by propagating "var" and by propagating "~var" +*/ +inline void FailedLitSearcher::removeVarFromXors(const Var var) +{ + vector<uint32_t>& occ = occur[var]; + if (occ.empty()) return; + + for (uint32_t *it = &occ[0], *end = it + occ.size(); it != end; it++) { + xorClauseSizes[*it]--; + if (!xorClauseTouched[*it]) { + xorClauseTouched.setBit(*it); + investigateXor.push(*it); + } + } +} + +/** +@brief Undoes what removeVarFromXors() has done +*/ +inline void FailedLitSearcher::addVarFromXors(const Var var) +{ + vector<uint32_t>& occ = occur[var]; + if (occ.empty()) return; + + for (uint32_t *it = &occ[0], *end = it + occ.size(); it != end; it++) { + xorClauseSizes[*it]++; + } +} + +/** +@brief Returns the 2-long xor clause that has been made of the longer xor-clause under current assignement + +We KNOW that the xorclause "c" passed as a parameter must be 2-long. We just +need it so that we can work with it. We KNOW it's 2-long because of the +data structures and functions in place + +@p[in] c MUST be a 2-long xor clause under current assignement +*/ +FailedLitSearcher::TwoLongXor FailedLitSearcher::getTwoLongXor(const XorClause& c) +{ + TwoLongXor tmp; + uint32_t num = 0; + tmp.inverted = c.xorEqualFalse(); + + for(const Lit *l = c.getData(), *end = l + c.size(); l != end; l++) { + if (solver.assigns[l->var()] == l_Undef) { + assert(num < 2); + tmp.var[num] = l->var(); + num++; + } else { + tmp.inverted ^= (solver.assigns[l->var()] == l_True); + } + } + + #ifdef VERBOSE_DEUBUG + if (num != 2) { + std::cout << "Num:" << num << std::endl; + c.plainPrint(); + } + #endif + + std::sort(&tmp.var[0], &tmp.var[0]+2); + assert(num == 2); + return tmp; +} + +/** +@brief The main function. Initialises data and calls tryBoth() for heavy-lifting + +It sets up the ground for tryBoth() and calls it as many times as it sees fit. +One afther the other, the different optimisations' data structures are +initialised, and their limits are set. Then tryBoth is called in two different +forms: somewhat sequentially on varaibles x...z and then on randomly picked +variables. +*/ +bool FailedLitSearcher::search() +{ + assert(solver.decisionLevel() == 0); + if (solver.nVars() == 0) return solver.ok; + + uint64_t numProps = 130 * 1000000; + uint64_t numPropsDifferent = (double)numProps*2.0; + + solver.testAllClauseAttach(); + double myTime = cpuTime(); + uint32_t origHeapSize = solver.order_heap.size(); + StateSaver savedState(solver); + Heap<Solver::VarOrderLt> order_heap_copy(solver.order_heap); //for hyperbin + + //General Stats + numFailed = 0; + goodBothSame = 0; + numCalls++; + + //If failed var searching is going good, do successively more and more of it + if ((double)lastTimeFoundTruths > (double)solver.order_heap.size() * 0.10) numPropsMultiplier = std::max(numPropsMultiplier*1.3, 2.0); + else numPropsMultiplier = 1.0; + numProps = (uint64_t) ((double)numProps * numPropsMultiplier * solver.conf.failedLitMultiplier); + + //For BothSame + propagated.resize(solver.nVars(), 0); + propValue.resize(solver.nVars(), 0); + + //For calculating how many variables have really been set + origTrailSize = solver.trail.size(); + + //For 2-long xor (rule 6 of Equivalent literal propagation in the DLL procedure by Chu-Min Li) + toReplaceBefore = solver.varReplacer->getNewToReplaceVars(); + lastTrailSize = solver.trail.size(); + binXorFind = true; + twoLongXors.clear(); + if (solver.xorclauses.size() < 5 || + solver.xorclauses.size() > 30000 || + solver.order_heap.size() > 30000 || + solver.nClauses() > 100000) + binXorFind = false; + if (binXorFind) { + solver.clauseCleaner->cleanClauses(solver.xorclauses, ClauseCleaner::xorclauses); + addFromSolver(solver.xorclauses); + } + xorClauseTouched.resize(solver.xorclauses.size(), 0); + newBinXor = 0; + + //For 2-long xor through Le Berre paper + bothInvert = 0; + + //For HyperBin + addedBin = 0; + unPropagatedBin.resize(solver.nVars(), 0); + needToVisit.resize(solver.nVars(), 0); + dontRemoveAncestor.resize(solver.nVars(), 0); + hyperbinProps = 0; + maxHyperBinProps = numProps/4; + if (solver.order_heap.size() < 20000) + maxHyperBinProps*=2; + removedUselessLearnt = 0; + removedUselessNonLearnt = 0; + + //uint32_t fromBin; + origProps = solver.propagations; + uint32_t i; + for (i = 0; i < solver.nVars(); i++) { + Var var = (lastTimeStopped + i) % solver.nVars(); + if (solver.assigns[var] != l_Undef || !solver.decision_var[var]) + continue; + if (solver.propagations >= origProps + numProps) + break; + if (!tryBoth(Lit(var, false), Lit(var, true))) + goto end; + } + lastTimeStopped = (lastTimeStopped + i) % solver.nVars(); + + origProps = solver.propagations; + while (!order_heap_copy.empty()) { + Var var = order_heap_copy.removeMin(); + if (solver.assigns[var] != l_Undef || !solver.decision_var[var]) + continue; + if (solver.propagations >= origProps + numPropsDifferent) { + break; + } + if (!tryBoth(Lit(var, false), Lit(var, true))) + goto end; + } + + if (solver.conf.verbosity >= 1) printResults(myTime); + + +end: + solver.order_heap.filter(Solver::VarFilter(solver)); + + if (solver.ok && (numFailed || goodBothSame)) { + double time = cpuTime(); + if ((int)origHeapSize - (int)solver.order_heap.size() > (int)origHeapSize/15 && solver.nClauses() + solver.learnts.size() > 500000) { + CompleteDetachReatacher reattacher(solver); + reattacher.detachNonBinsNonTris(true); + const bool ret = reattacher.reattachNonBins(); + release_assert(ret == true); + } else { + solver.clauseCleaner->removeAndCleanAll(); + } + if (solver.conf.verbosity >= 1 && numFailed + goodBothSame > 100) { + std::cout << "c Cleaning up after failed var search: " << std::setw(8) << std::fixed << std::setprecision(2) << cpuTime() - time << " s " + << std::endl; + } + } + + lastTimeFoundTruths = solver.trail.size() - origTrailSize; + totalTime += cpuTime() - myTime; + + savedState.restore(); + + solver.testAllClauseAttach(); + return solver.ok; +} + + +/** +@brief Prints results of failed litaral probing + +Printed: +1) Num failed lits +2) Num lits that have been propagated by both "var" and "~var" +3) 2-long Xor clauses that have been found because when propagating "var" and + "~var", they have been produced by normal xor-clauses shortening to this xor + clause +4) If var1 propagates var2 and ~var1 propagates ~var2, then var=var2, and this + is a 2-long XOR clause +5) Number of propagations +6) Time in seconds +*/ +void FailedLitSearcher::printResults(const double myTime) const +{ + std::cout << "c Flit: "<< std::setw(5) << numFailed << + " Blit: " << std::setw(6) << goodBothSame << + " bXBeca: " << std::setw(4) << newBinXor << + " bXProp: " << std::setw(4) << bothInvert << + " Bins:" << std::setw(7) << addedBin << + " BRemL:" << std::setw(7) << removedUselessLearnt << + " BRemN:" << std::setw(7) << removedUselessNonLearnt << + " P: " << std::setw(4) << std::fixed << std::setprecision(1) << (double)(solver.propagations - origProps)/1000000.0 << "M" + " T: " << std::setw(5) << std::fixed << std::setprecision(2) << cpuTime() - myTime + << std::endl; +} + +/** +@brief The main function of search() doing almost everything in this class + +Tries to branch on both lit1 and lit2 and then both-propagates them, fail-lits +them, and hyper-bin resolves them, etc. It is imperative that from the +SAT point of view, EITHER lit1 or lit2 MUST hold. So, if lit1 = ~lit2, it's OK. +Also, if there is a binary clause 'lit1 or lit2' it's also OK. +*/ +bool FailedLitSearcher::tryBoth(const Lit lit1, const Lit lit2) +{ + if (binXorFind) { + if (lastTrailSize < solver.trail.size()) { + for (uint32_t i = lastTrailSize; i != solver.trail.size(); i++) { + removeVarFromXors(solver.trail[i].var()); + } + } + lastTrailSize = solver.trail.size(); + xorClauseTouched.setZero(); + investigateXor.clear(); + } + + propagated.removeThese(propagatedBitSet); + #ifdef DEBUG_FAILEDLIT + assert(propagated.isZero()); + #endif + propagatedBitSet.clear(); + twoLongXors.clear(); + bothSame.clear(); + binXorToAdd.clear(); + #ifdef DEBUG_HYPERBIN + assert(propagatedVars.empty()); + assert(unPropagatedBin.isZero()); + #endif //DEBUG_HYPERBIN + #ifdef DEBUG_USELESS_LEARNT_BIN_REMOVAL + dontRemoveAncestor.isZero(); + assert(uselessBin.empty()); + #endif + + solver.newDecisionLevel(); + solver.uncheckedEnqueueLight(lit1); + failed = (!solver.propagate<false>(false).isNULL()); + if (failed) { + solver.cancelUntilLight(); + numFailed++; + solver.uncheckedEnqueue(~lit1); + solver.ok = (solver.propagate<false>(false).isNULL()); + if (!solver.ok) return false; + return true; + } + + assert(solver.decisionLevel() > 0); + Solver::TransCache& lit1OTFCache = solver.transOTFCache[(~lit1).toInt()]; + if (solver.conf.doCacheOTFSSR) { + lit1OTFCache.conflictLastUpdated = solver.conflicts; + lit1OTFCache.lits.clear(); + } + for (int c = solver.trail.size()-1; c >= (int)solver.trail_lim[0]; c--) { + Var x = solver.trail[c].var(); + propagated.setBit(x); + propagatedBitSet.push_back(x); + + if (solver.conf.doHyperBinRes) { + unPropagatedBin.setBit(x); + propagatedVars.push(x); + } + + if (solver.assigns[x].getBool()) propValue.setBit(x); + else propValue.clearBit(x); + + if (binXorFind) removeVarFromXors(x); + if (solver.conf.doCacheOTFSSR && c != (int)solver.trail_lim[0]) { + lit1OTFCache.lits.push_back(solver.trail[c]); + } + } + + if (binXorFind) { + for (uint32_t *it = investigateXor.getData(), *end = investigateXor.getDataEnd(); it != end; it++) { + if (xorClauseSizes[*it] == 2) + twoLongXors.insert(getTwoLongXor(*solver.xorclauses[*it])); + } + for (int c = solver.trail.size()-1; c >= (int)solver.trail_lim[0]; c--) { + addVarFromXors(solver.trail[c].var()); + } + xorClauseTouched.setZero(); + investigateXor.clear(); + } + + solver.cancelUntilLight(); + + //Hyper-binary resolution, and its accompanying data-structure cleaning + if (solver.conf.doHyperBinRes) { + if (hyperbinProps < maxHyperBinProps) hyperBinResolution(lit1); + unPropagatedBin.removeThese(propagatedVars); + propagatedVars.clear(); + } + + #ifdef DEBUG_HYPERBIN + assert(propagatedVars.empty()); + assert(unPropagatedBin.isZero()); + #endif //DEBUG_HYPERBIN + + solver.newDecisionLevel(); + solver.uncheckedEnqueueLight(lit2); + failed = (!solver.propagate<false>(false).isNULL()); + if (failed) { + solver.cancelUntilLight(); + numFailed++; + solver.uncheckedEnqueue(~lit2); + solver.ok = (solver.propagate<false>(false).isNULL()); + if (!solver.ok) return false; + return true; + } + + assert(solver.decisionLevel() > 0); + Solver::TransCache& lit2OTFCache = solver.transOTFCache[(~lit2).toInt()]; + if (solver.conf.doCacheOTFSSR) { + lit2OTFCache.conflictLastUpdated = solver.conflicts; + lit2OTFCache.lits.clear(); + } + for (int c = solver.trail.size()-1; c >= (int)solver.trail_lim[0]; c--) { + Var x = solver.trail[c].var(); + if (propagated[x]) { + if (propValue[x] == solver.assigns[x].getBool()) { + //they both imply the same + bothSame.push(Lit(x, !propValue[x])); + } else if (c != (int)solver.trail_lim[0]) { + bool invert; + if (lit1.var() == lit2.var()) { + assert(lit1.sign() == false && lit2.sign() == true); + tmpPs[0] = Lit(lit1.var(), false); + tmpPs[1] = Lit(x, false); + invert = propValue[x]; + } else { + tmpPs[0] = Lit(lit1.var(), false); + tmpPs[1] = Lit(lit2.var(), false); + invert = lit1.sign() ^ lit2.sign(); + } + binXorToAdd.push_back(BinXorToAdd(tmpPs[0], tmpPs[1], invert)); + bothInvert += solver.varReplacer->getNewToReplaceVars() - toReplaceBefore; + toReplaceBefore = solver.varReplacer->getNewToReplaceVars(); + } + } + + if (solver.conf.doHyperBinRes) { + unPropagatedBin.setBit(x); + propagatedVars.push(x); + } + + if (solver.assigns[x].getBool()) propValue.setBit(x); + else propValue.clearBit(x); + + if (binXorFind) removeVarFromXors(x); + if (solver.conf.doCacheOTFSSR && c != (int)solver.trail_lim[0]) { + lit2OTFCache.lits.push_back(solver.trail[c]); + } + } + + //We now add the two-long xors that have been found through longer + //xor-shortening + if (binXorFind) { + if (twoLongXors.size() > 0) { + for (uint32_t *it = investigateXor.getData(), *end = it + investigateXor.size(); it != end; it++) { + if (xorClauseSizes[*it] == 2) { + TwoLongXor tmp = getTwoLongXor(*solver.xorclauses[*it]); + if (twoLongXors.find(tmp) != twoLongXors.end()) { + tmpPs[0] = Lit(tmp.var[0], false); + tmpPs[1] = Lit(tmp.var[1], false); + binXorToAdd.push_back(BinXorToAdd(tmpPs[0], tmpPs[1], tmp.inverted)); + newBinXor += solver.varReplacer->getNewToReplaceVars() - toReplaceBefore; + toReplaceBefore = solver.varReplacer->getNewToReplaceVars(); + } + } + } + } + for (int c = solver.trail.size()-1; c >= (int)solver.trail_lim[0]; c--) { + addVarFromXors(solver.trail[c].var()); + } + } + solver.cancelUntilLight(); + + if (solver.conf.doHyperBinRes) { + if (hyperbinProps < maxHyperBinProps) hyperBinResolution(lit2); + unPropagatedBin.removeThese(propagatedVars); + propagatedVars.clear(); + } + + for(uint32_t i = 0; i != bothSame.size(); i++) { + solver.uncheckedEnqueue(bothSame[i]); + } + goodBothSame += bothSame.size(); + solver.ok = (solver.propagate<false>(false).isNULL()); + if (!solver.ok) return false; + + if (solver.conf.doBXor) { + for (uint32_t i = 0; i < binXorToAdd.size(); i++) { + tmpPs[0] = binXorToAdd[i].lit1; + tmpPs[1] = binXorToAdd[i].lit2; + solver.addXorClauseInt(tmpPs, binXorToAdd[i].isEqualFalse); + tmpPs.clear(); + tmpPs.growTo(2); + if (!solver.ok) return false; + } + } + + return true; +} + +/** +@brief Adds hyper-binary clauses + +At this point, unPropagatedBin is set, and propagatedVars is filled with lits +that have been propagated. Here, we propagate ONLY at the binary level, +and compare with propagatedVars and unPropagatedBin. If they match, it's OK. If +not, then we add the relevant binary clauses at the right point. The "right" +point is the point which has the highest in-degree. We approximated the degrees +beforehand with orderLits() +*/ +void FailedLitSearcher::hyperBinResolution(const Lit lit) +{ + #ifdef VERBOSE_DEBUG + std::cout << "Checking one BTC vs UP" << std::endl; + #endif //VERBOSE_DEBUG + + #ifdef DEBUG_HYPERBIN + assert(needToVisit.isZero()); + #endif //DEBUG_HYPERBIN + + uint64_t oldProps = solver.propagations; + vec<Lit> toVisit; + uint64_t extraTime = 0; + + solver.newDecisionLevel(); + solver.uncheckedEnqueueLight2(lit, 0, lit_Undef, false); + failed = (!solver.propagateBin(uselessBin).isNULL()); + assert(!failed); + + if (solver.conf.doRemUselessLBins && !uselessBin.empty()) { + for (const Lit *it = uselessBin.getData(), *end = uselessBin.getDataEnd(); it != end; it++) { + if (dontRemoveAncestor[it->var()]) continue; + + extraTime += solver.watches[lit.toInt()].size()/2; + extraTime += solver.watches[(~*it).toInt()].size()/2; + if (findWBin(solver.watches, ~lit, *it, true)) { + removeWBin(solver.watches[lit.toInt()], *it, true); + removeWBin(solver.watches[(~*it).toInt()], ~lit, true); + solver.learnts_literals -= 2; + solver.numBins--; + removedUselessLearnt++; + } else if (!solver.binPropData[it->var()].learntLeadHere) { + removeWBin(solver.watches[lit.toInt()], *it, false); + removeWBin(solver.watches[(~*it).toInt()], ~lit, false); + solver.clauses_literals -= 2; + solver.numBins--; + removedUselessNonLearnt++; + } else { + continue; + } + + Var ancestorVar = solver.binPropData[it->var()].lev1Ancestor.var(); + dontRemoveAncestor.setBit(ancestorVar); + toClearDontRemoveAcestor.push(ancestorVar); + } + dontRemoveAncestor.removeThese(toClearDontRemoveAcestor); + toClearDontRemoveAcestor.clear(); + } + uselessBin.clear(); + #ifdef DEBUG_USELESS_LEARNT_BIN_REMOVAL + dontRemoveAncestor.isZero(); + uint64_t backupProps; + #endif + + assert(solver.decisionLevel() > 0); + int32_t difference = propagatedVars.size() - (solver.trail.size()-solver.trail_lim[0]); + #ifdef DEBUG_USELESS_LEARNT_BIN_REMOVAL + uint32_t propagated = solver.trail.size()-solver.trail_lim[0]; + #endif + assert(difference >= 0); + if (difference == 0) { + solver.cancelUntilLight(); + goto end; + } + for (int c = solver.trail.size()-1; c >= (int)solver.trail_lim[0]; c--) { + Lit x = solver.trail[c]; + unPropagatedBin.clearBit(x.var()); + toVisit.push(x); + needToVisit.setBit(x.var()); + } + std::sort(toVisit.getData(), toVisit.getDataEnd(), LitOrder2(solver.binPropData)); + solver.cancelUntilLight(); + + #ifdef DEBUG_USELESS_LEARNT_BIN_REMOVAL + backupProps = solver.propagations; + if (solver.conf.doRemUselessLBins) { + solver.newDecisionLevel(); + solver.uncheckedEnqueueLight2(lit, 0, lit_Undef, false); + failed = (!solver.propagateBin(uselessBin).isNULL()); + uselessBin.clear(); + for (int c = solver.trail.size()-1; c >= (int)solver.trail_lim[0]; c--) { + Lit x = solver.trail[c]; + } + assert(!failed); + assert(propagated == solver.trail.size()-solver.trail_lim[0]); + solver.cancelUntilLight(); + } + solver.propagations = backupProps; + #endif + + /************************* + //To check that the ordering is the right way + // --> i.e. to avoid mistake present in Glucose's ordering*/ + /*std::cout << "--------------------" << std::endl; + for (uint32_t i = 0; i < toVisit.size(); i++) { + std::cout << "i:" << std::setw(8) << i + << " level:" << std::setw(3) << solver.binPropData[toVisit[i].var()].lev + << " lit : " << toVisit[i] + << std::endl; + } + std::cout << "difference: " << difference << std::endl; + std::cout << "--------------------" << std::endl;*/ + /***************************/ + + //difference between UP and BTC is in unPropagatedBin + for (Lit *l = toVisit.getData(), *end = toVisit.getDataEnd(); l != end; l++) { + if (!needToVisit[l->var()]) continue; + if (!solver.binPropData[l->var()].hasChildren) continue; + fillImplies(*l); + //addMyImpliesSetAsBins(*l, difference); + for (const Var *var = myImpliesSet.getData(), *end2 = myImpliesSet.getDataEnd(); var != end2; var++) { + /*Lit otherLit = Lit(*var, !propValue[*var]); + std::cout << "adding Bin:" << (~*l) << " , " << otherLit << std::endl; + std::cout << PropByFull(solver.reason[otherLit.var()], solver.failBinLit, solver.clauseAllocator) << std::endl;*/ + + addBin(~*l, Lit(*var, !propValue[*var])); + unPropagatedBin.clearBit(*var); + difference--; + } + + + assert(difference >= 0); + myImpliesSet.clear(); + + if (difference == 0) { + needToVisit.removeTheseLit(toVisit); + break; + } + } + #ifdef DEBUG_HYPERBIN + assert(unPropagatedBin.isZero()); + assert(needToVisit.isZero()); + #endif //DEBUG_HYPERBIN + + end: + hyperbinProps += solver.propagations - oldProps + extraTime; +} + +/** +@brief Fills myimplies and myimpliesSet by propagating lit at a binary level + +Used to check which variables are propagated by a certain literal when +propagating it only at the binary level +@p[in] the literal to be propagated at the binary level +*/ +void FailedLitSearcher::fillImplies(const Lit lit) +{ + solver.newDecisionLevel(); + solver.uncheckedEnqueueLight(lit); + failed = (!solver.propagate<false>(false).isNULL()); + assert(!failed); + + assert(solver.decisionLevel() > 0); + for (int sublevel = solver.trail.size()-1; sublevel >= (int)solver.trail_lim[0]; sublevel--) { + Var x = solver.trail[sublevel].var(); + needToVisit.clearBit(x); + if (unPropagatedBin[x]) { + myImpliesSet.push(x); + } + } + solver.cancelUntilLight(); +} + +/*void FailedLitSearcher::addMyImpliesSetAsBins(Lit lit, int32_t& difference) +{ + if (myImpliesSet.size() == 0) return; + if (myImpliesSet.size() == 1) { + Var var = myImpliesSet[0]; + Lit l2 = Lit(var, !propValue[var]); + addBin(~lit, l2); + unPropagatedBin.clearBit(var); + difference--; + return; + } + + uint64_t backupProps = solver.propagations; + vector<BinAddData> litsAddedEach; + uint32_t i = 0; + for (const Var *var = myImpliesSet.getData(), *end2 = myImpliesSet.getDataEnd(); var != end2; var++, i++) { + Lit l2 = Lit(*var, !propValue[*var]); + solver.newDecisionLevel(); + solver.uncheckedEnqueueLight(l2); + failed = (!solver.propagateBin(uselessBin).isNULL()); + assert(!failed); + uselessBin.clear(); + + BinAddData addData; + addData.lit = l2; + assert(solver.decisionLevel() > 0); + for (int sublevel = solver.trail.size()-1; sublevel > (int)solver.trail_lim[0]; sublevel--) { + Lit x = solver.trail[sublevel]; + addData.lits.push_back(x); + } + solver.cancelUntilLight(); + litsAddedEach.push_back(addData); + } + std::sort(litsAddedEach.begin(), litsAddedEach.end(), BinAddDataSorter()); + + while(!litsAddedEach.empty()) { + assert(!litsAddedEach.empty()); + BinAddData b = *litsAddedEach.begin(); + litsAddedEach.erase(litsAddedEach.begin()); + + addBin(~lit, b.lit); + assert(unPropagatedBin[b.lit.var()]); + unPropagatedBin.clearBit(b.lit.var()); + difference--; + for (uint32_t i = 0; i < b.lits.size(); i++) { + Lit alsoAddedLit = b.lits[i]; + if (unPropagatedBin[alsoAddedLit.var()]) { + unPropagatedBin.clearBit(alsoAddedLit.var()); + difference--; + for (vector<BinAddData>::iterator it2 = litsAddedEach.begin(); it2 != litsAddedEach.end(); it2++) { + if (it2->lit == alsoAddedLit) { + litsAddedEach.erase(it2); + break; + } + } + } + } + } + assert(litsAddedEach.empty()); + solver.propagations = backupProps; +}*/ + + +/** +@brief Adds a learnt binary clause to the solver + +Used by hyperBinResolution() to add the newly discovered clauses +*/ +void FailedLitSearcher::addBin(const Lit lit1, const Lit lit2) +{ + #ifdef VERBOSE_DEBUG + std::cout << "Adding extra bin: " << lit1 << " " << lit2 << std::endl; + #endif //VERBOSE_DEBUG + + assert(solver.value(lit1) == l_Undef); + assert(solver.value(lit2) == l_Undef); + tmpPs[0] = lit1; + tmpPs[1] = lit2; + + solver.addClauseInt(tmpPs, true); + tmpPs.clear(); + tmpPs.growTo(2); + assert(solver.ok); + addedBin++; +} diff --git a/src/prop/cryptominisat/Solver/FailedLitSearcher.h b/src/prop/cryptominisat/Solver/FailedLitSearcher.h new file mode 100644 index 000000000..e4bf5bd19 --- /dev/null +++ b/src/prop/cryptominisat/Solver/FailedLitSearcher.h @@ -0,0 +1,246 @@ +/*************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +****************************************************************************/ + +#ifndef FAILEDLITSEARCHER_H +#define FAILEDLITSEARCHER_H + +#include <set> +#include <map> +#include <vector> + +#include "SolverTypes.h" +#include "Clause.h" +#include "BitArray.h" + +namespace CMSat { + +using std::set; +using std::map; +using std::vector; + +class Solver; + +/** +@brief Responsible for doing failed var searching and related algorithms + +Performs in seach(): +1) Failed lit searching +2) Searching for lits that have been propagated by both "var" and "~var" +3) 2-long Xor clauses that have been found because when propagating "var" and + "~var", they have been produced by normal xor-clauses shortening to this xor + clause +4) If var1 propagates var2 and ~var1 propagates ~var2, then var=var2, and this + is a 2-long XOR clause, this 2-long xor is added +5) Hyper-binary resolution + +Perfoms in asymmBranch(): asymmetric branching, heuristically. Best paper +on this is 'Vivifying Propositional Clausal Formulae', though we do it much +more heuristically +*/ +class FailedLitSearcher { + public: + FailedLitSearcher(Solver& _solver); + + bool search(); + double getTotalTime() const; + + private: + //Main + bool tryBoth(const Lit lit1, const Lit lit2); + bool tryAll(const Lit* begin, const Lit* end); + void printResults(const double myTime) const; + + Solver& solver; ///<The solver we are updating&working with + + bool failed; ///<For checking that a specific propagation failed (=conflict). It is used in many places + + //bothprop finding + vector<uint32_t> propagatedBitSet; + BitArray propagated; ///<These lits have been propagated by propagating the lit picked + BitArray propValue; ///<The value (0 or 1) of the lits propagated set in "propagated" + /** + @brief Lits that have been propagated to the same value both by "var" and "~var" + + value that the literal has been propagated to is available in propValue + */ + vec<Lit> bothSame; + + //2-long xor-finding + /** + @brief used to find 2-long xor by shortening longer xors to this size + + -# We propagate "var" and record all xors that become 2-long + -# We propagate "~var" and record all xors that become 2-long + -# if (1) and (2) have something in common, we add it as a variable + replacement instruction + + We must be able to order these 2-long xors, so that we can search + for matching couples fast. This class is used for that + */ + class TwoLongXor + { + public: + bool operator==(const TwoLongXor& other) const + { + if (var[0] == other.var[0] + && var[1] == other.var[1] + && inverted == other.inverted) + return true; + return false; + } + bool operator<(const TwoLongXor& other) const + { + if (var[0] < other.var[0]) return true; + if (var[0] > other.var[0]) return false; + + if (var[1] < other.var[1]) return true; + if (var[1] > other.var[1]) return false; + + if (inverted < other.inverted) return true; + if (inverted > other.inverted) return false; + + return false; + } + + Var var[2]; + bool inverted; + }; + + class BinXorToAdd + { + public: + BinXorToAdd(const Lit _lit1, const Lit _lit2, const bool _isEqualFalse) : + lit1(_lit1) + , lit2(_lit2) + , isEqualFalse(_isEqualFalse) + {} + Lit lit1; + Lit lit2; + bool isEqualFalse; + }; + TwoLongXor getTwoLongXor(const XorClause& c); + void addFromSolver(const vec<XorClause*>& cs); + void removeVarFromXors(const Var var); + void addVarFromXors(const Var var); + + uint32_t newBinXor; + vec<uint32_t> xorClauseSizes; + vector<vector<uint32_t> > occur; ///<Occurence list for XORs. Indexed by variables + BitArray xorClauseTouched; + vec<uint32_t> investigateXor; + std::set<TwoLongXor> twoLongXors; + bool binXorFind; + uint32_t lastTrailSize; + vector<BinXorToAdd> binXorToAdd; + + /** + @brief Num. 2-long xor-found through Le Berre paper + + In case: + -# (a->b, ~a->~b) -> a=b + -# binary clause (a,c) exists: (a->g, c->~g) -> a = ~c + */ + uint32_t bothInvert; + + //finding HyperBins + struct LitOrder2 + { + LitOrder2(const vec<BinPropData>& _binPropData) : + binPropData(_binPropData) + {} + + bool operator () (const Lit x, const Lit y) const + { + return binPropData[x.var()].lev > binPropData[y.var()].lev; + } + + const vec<BinPropData>& binPropData; + }; + struct BinAddData + { + vector<Lit> lits; + Lit lit; + }; + struct BinAddDataSorter + { + bool operator() (const BinAddData& a, const BinAddData& b) const + { + return (a.lits.size() > b.lits.size()); + } + }; + //void addMyImpliesSetAsBins(Lit lit, int32_t& difference); + + uint32_t addedBin; + void hyperBinResolution(const Lit lit); + BitArray unPropagatedBin; + BitArray needToVisit; + vec<Var> propagatedVars; + void addBin(const Lit lit1, const Lit lit2); + void fillImplies(const Lit lit); + vec<Var> myImpliesSet; ///<variables set in myimplies + uint64_t hyperbinProps; ///<Number of bogoprops done by the hyper-binary resolution function hyperBinResolution() + + //bin-removal within hyper-bin-res + vec<Lit> uselessBin; + uint32_t removedUselessLearnt; + uint32_t removedUselessNonLearnt; + BitArray dontRemoveAncestor; + vec<Var> toClearDontRemoveAcestor; + /** + @brief Controls hyper-binary resolution's time-usage + + Don't do more than this many propagations within hyperBinResolution() + */ + uint64_t maxHyperBinProps; + + //Temporaries + vec<Lit> tmpPs; + + //State for this run + /** + @brief Records num. var-replacement istructions between 2-long xor findings through longer xor shortening + + Finding 2-long xor claues by shortening is fine, but sometimes we find + the same thing, or find something that is trivially a consequence of + other 2-long xors that we already know. To filter out these bogus + "findigs" from the statistics reported, we save in this value the + real var-replacement insturctions before and after the 2-long xor + finding through longer xor-shortening, and then compare the changes + made + */ + uint32_t toReplaceBefore; + uint32_t origTrailSize; ///<Records num. of 0-depth assignments at the start-up of search() + uint64_t origProps; ///<Records num. of bogoprops at the start-up of search() + uint32_t numFailed; ///<Records num. of failed literals during search() + uint32_t goodBothSame; ///<Records num. of literals that have been propagated to the same value by both "var" and "~var" + + //State between runs + double totalTime; + double numPropsMultiplier; ///<If last time we called search() all went fine, then this is incremented, so we do more searching this time + uint32_t lastTimeFoundTruths; ///<Records how many unit clauses we found last time we called search() + uint32_t numCalls; ///<Number of times search() has been called + uint32_t lastTimeStopped; +}; + +inline double FailedLitSearcher::getTotalTime() const +{ + return totalTime; +} + +} + +#endif //FAILEDVARSEARCHER_H diff --git a/src/prop/cryptominisat/Solver/Gaussian.cpp b/src/prop/cryptominisat/Solver/Gaussian.cpp new file mode 100644 index 000000000..e186d5849 --- /dev/null +++ b/src/prop/cryptominisat/Solver/Gaussian.cpp @@ -0,0 +1,1147 @@ +/*************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "Gaussian.h" + +#include <iostream> +#include <iomanip> +#include "Clause.h" +#include <algorithm> +#include "ClauseCleaner.h" +#include "VarReplacer.h" +#include "DataSync.h" + +//#define VERBOSE_DEBUG +//#define DEBUG_GAUSS + +#ifdef VERBOSE_DEBUG +#include <iterator> +#endif + +using namespace CMSat; +using std::ostream; +using std::cout; +using std::endl; + +static const uint16_t unassigned_col = std::numeric_limits<uint16_t>::max(); +static const Var unassigned_var = std::numeric_limits<Var>::max(); + +Gaussian::Gaussian(Solver& _solver, const GaussConf& _config, const uint32_t _matrix_no, const vector<XorClause*>& _xorclauses) : + solver(_solver) + , config(_config) + , matrix_no(_matrix_no) + , xorclauses(_xorclauses) + , messed_matrix_vars_since_reversal(true) + , gauss_last_level(0) + , disabled(false) + , useful_prop(0) + , useful_confl(0) + , called(0) + , unit_truths(0) +{ +} + +Gaussian::~Gaussian() +{ + for (uint32_t i = 0; i < clauses_toclear.size(); i++) + solver.clauseAllocator.clauseFree(clauses_toclear[i].first); +} + +inline void Gaussian::set_matrixset_to_cur() +{ + uint32_t level = solver.decisionLevel() / config.only_nth_gauss_save; + assert(level <= matrix_sets.size()); + + if (level == matrix_sets.size()) + matrix_sets.push_back(cur_matrixset); + else + matrix_sets[level] = cur_matrixset; +} + +bool Gaussian::full_init() +{ + assert(solver.ok); + assert(solver.decisionLevel() == 0); + + if (!should_init()) return true; + reset_stats(); + uint32_t last_trail_size = solver.trail.size(); + + bool do_again_gauss = true; + while (do_again_gauss) { + do_again_gauss = false; + solver.clauseCleaner->cleanClauses(solver.xorclauses, ClauseCleaner::xorclauses); + if (!solver.ok) return false; + init(); + PropBy confl; + gaussian_ret g = gaussian(confl); + switch (g) { + case unit_conflict: + case conflict: + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")conflict at level 0" << std::endl; + #endif + solver.ok = false; + return false; + case unit_propagation: + case propagation: + unit_truths += last_trail_size - solver.trail.size(); + do_again_gauss = true; + solver.ok = (solver.propagate<true>().isNULL()); + if (!solver.ok) return false; + break; + case nothing: + break; + } + } + + return true; +} + +void Gaussian::init() +{ + assert(solver.decisionLevel() == 0); + + fill_matrix(cur_matrixset); + if (!cur_matrixset.num_rows || !cur_matrixset.num_cols) { + disabled = true; + badlevel = 0; + return; + } + + matrix_sets.clear(); + matrix_sets.push_back(cur_matrixset); + gauss_last_level = solver.trail.size(); + messed_matrix_vars_since_reversal = false; + badlevel = UINT_MAX; + + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")Gaussian init finished." << endl; + #endif +} + +uint32_t Gaussian::select_columnorder(vector<uint16_t>& var_to_col, matrixset& origMat) +{ + var_to_col.resize(solver.nVars(), unassigned_col); + + uint32_t num_xorclauses = 0; + for (uint32_t i = 0; i != xorclauses.size(); i++) { + XorClause& c = *xorclauses[i]; + if (c.getRemoved()) continue; + num_xorclauses++; + + for (uint32_t i2 = 0; i2 < c.size(); i2++) { + assert(solver.assigns[c[i2].var()].isUndef()); + var_to_col[c[i2].var()] = unassigned_col - 1; + } + } + + uint32_t largest_used_var = 0; + for (uint32_t i = 0; i < var_to_col.size(); i++) + if (var_to_col[i] != unassigned_col) + largest_used_var = i; + var_to_col.resize(largest_used_var + 1); + + var_is_in.resize(var_to_col.size(), 0); + origMat.var_is_set.resize(var_to_col.size(), 0); + + origMat.col_to_var.clear(); + vector<Var> vars(solver.nVars()); + if (!config.orderCols) { + for (uint32_t i = 0; i < solver.nVars(); i++) { + vars.push_back(i); + } + std::random_shuffle(vars.begin(), vars.end()); + } + + Heap<Solver::VarOrderLt> order_heap(solver.order_heap); + uint32_t iterReduceIt = 0; + while ((config.orderCols && !order_heap.empty()) || (!config.orderCols && iterReduceIt < vars.size())) + { + Var v; + if (config.orderCols) v = order_heap.removeMin(); + else v = vars[iterReduceIt++]; + if (var_to_col[v] == 1) { + #ifdef DEBUG_GAUSS + vector<uint32_t>::iterator it = + std::find(origMat.col_to_var.begin(), origMat.col_to_var.end(), v); + assert(it == origMat.col_to_var.end()); + #endif + + origMat.col_to_var.push_back(v); + var_to_col[v] = origMat.col_to_var.size()-1; + var_is_in.setBit(v); + } + } + + //for the ones that were not in the order_heap, but are marked in var_to_col + for (uint32_t v = 0; v != var_to_col.size(); v++) { + if (var_to_col[v] == unassigned_col - 1) { + origMat.col_to_var.push_back(v); + var_to_col[v] = origMat.col_to_var.size() -1; + var_is_in.setBit(v); + } + } + + #ifdef VERBOSE_DEBUG_MORE + cout << "(" << matrix_no << ")col_to_var:"; + std::copy(origMat.col_to_var.begin(), origMat.col_to_var.end(), std::ostream_iterator<uint32_t>(cout, ",")); + cout << endl; + #endif + + return num_xorclauses; +} + +void Gaussian::fill_matrix(matrixset& origMat) +{ + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")Filling matrix" << endl; + #endif + + vector<uint16_t> var_to_col; + origMat.num_rows = select_columnorder(var_to_col, origMat); + origMat.num_cols = origMat.col_to_var.size(); + col_to_var_original = origMat.col_to_var; + changed_rows.resize(origMat.num_rows); + memset(&changed_rows[0], 0, sizeof(unsigned char)*changed_rows.size()); + + origMat.last_one_in_col.resize(origMat.num_cols); + std::fill(origMat.last_one_in_col.begin(), origMat.last_one_in_col.end(), origMat.num_rows); + origMat.first_one_in_row.resize(origMat.num_rows); + + origMat.removeable_cols = 0; + origMat.least_column_changed = -1; + origMat.matrix.resize(origMat.num_rows, origMat.num_cols); + + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")matrix size:" << origMat.num_rows << "," << origMat.num_cols << endl; + #endif + + uint32_t matrix_row = 0; + for (uint32_t i = 0; i != xorclauses.size(); i++) { + const XorClause& c = *xorclauses[i]; + if (c.getRemoved()) continue; + + origMat.matrix.getVarsetAt(matrix_row).set(c, var_to_col, origMat.num_cols); + origMat.matrix.getMatrixAt(matrix_row).set(c, var_to_col, origMat.num_cols); + matrix_row++; + } + assert(origMat.num_rows == matrix_row); +} + +void Gaussian::update_matrix_col(matrixset& m, const Var var, const uint32_t col) +{ + #ifdef VERBOSE_DEBUG_MORE + cout << "(" << matrix_no << ")Updating matrix var " << var+1 << " (col " << col << ", m.last_one_in_col[col]: " << m.last_one_in_col[col] << ")" << endl; + cout << "m.num_rows:" << m.num_rows << endl; + #endif + + #ifdef DEBUG_GAUSS + assert(col < m.num_cols); + #endif + + m.least_column_changed = std::min(m.least_column_changed, (int)col); + PackedMatrix::iterator this_row = m.matrix.beginMatrix(); + uint32_t row_num = 0; + + if (solver.assigns[var].getBool()) { + for (uint32_t end = m.last_one_in_col[col]; row_num != end; ++this_row, row_num++) { + if ((*this_row)[col]) { + changed_rows[row_num] = true; + (*this_row).invert_is_true(); + (*this_row).clearBit(col); + } + } + } else { + for (uint32_t end = m.last_one_in_col[col]; row_num != end; ++this_row, row_num++) { + if ((*this_row)[col]) { + changed_rows[row_num] = true; + (*this_row).clearBit(col); + } + } + } + + #ifdef DEBUG_GAUSS + bool c = false; + for(PackedMatrix::iterator r = m.matrix.beginMatrix(), end = r + m.matrix.getSize(); r != end; ++r) + c |= (*r)[col]; + assert(!c); + #endif + + m.removeable_cols++; + m.col_to_var[col] = unassigned_var; + m.var_is_set.setBit(var); +} + +void Gaussian::update_matrix_by_col_all(matrixset& m) +{ + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")Updating matrix." << endl; + #ifdef VERBOSE_DEBUG_MORE + print_matrix(m); + #endif + uint32_t num_updated = 0; + #endif + + #ifdef DEBUG_GAUSS + assert(nothing_to_propagate(cur_matrixset)); + assert(solver.decisionLevel() == 0 || check_last_one_in_cols(m)); + #endif + + memset(&changed_rows[0], 0, sizeof(unsigned char)*changed_rows.size()); + + uint32_t last = 0; + uint32_t col = 0; + for (const Var *it = &m.col_to_var[0], *end = it + m.num_cols; it != end; col++, it++) { + if (*it != unassigned_var && solver.assigns[*it].isDef()) { + update_matrix_col(m, *it, col); + last++; + #ifdef VERBOSE_DEBUG + num_updated++; + #endif + } else + last = 0; + } + m.num_cols -= last; + + #ifdef DEBUG_GAUSS + check_matrix_against_varset(m.matrix, m); + #endif + + #ifdef VERBOSE_DEBUG + cout << "Matrix update finished, updated " << num_updated << " cols" << endl; + #ifdef VERBOSE_DEBUG_MORE + print_matrix(m); + #endif + #endif + + /*cout << "num_rows:" << m.num_rows; + cout << " num_rows diff:" << origMat.num_rows - m.num_rows << endl; + cout << "num_cols:" << col_to_var_original.size(); + cout << " num_cols diff:" << col_to_var_original.size() - m.col_to_var.size() << endl; + cout << "removeable cols:" << m.removeable_cols << endl;*/ +} + +inline void Gaussian::update_last_one_in_col(matrixset& m) +{ + for (uint16_t* i = &m.last_one_in_col[0]+m.last_one_in_col.size()-1, *end = &m.last_one_in_col[0]-1; i != end && *i >= m.num_rows; i--) + *i = m.num_rows; +} + +Gaussian::gaussian_ret Gaussian::gaussian(PropBy& confl) +{ + if (solver.decisionLevel() >= badlevel) + return nothing; + + if (messed_matrix_vars_since_reversal) { + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")matrix needs copy before update" << endl; + #endif + + const uint32_t level = solver.decisionLevel() / config.only_nth_gauss_save; + assert(level < matrix_sets.size()); + cur_matrixset = matrix_sets[level]; + } + update_last_one_in_col(cur_matrixset); + update_matrix_by_col_all(cur_matrixset); + + messed_matrix_vars_since_reversal = false; + gauss_last_level = solver.trail.size(); + badlevel = UINT_MAX; + + propagatable_rows.clear(); + uint32_t last_row = eliminate(cur_matrixset); + #ifdef DEBUG_GAUSS + check_matrix_against_varset(cur_matrixset.matrix, cur_matrixset); + #endif + + gaussian_ret ret; + //There is no early abort, so this is unneeded + /*if (conflict_row != UINT_MAX) { + uint32_t maxlevel = UINT_MAX; + uint32_t size = UINT_MAX; + uint32_t best_row = UINT_MAX; + analyse_confl(cur_matrixset, conflict_row, maxlevel, size, best_row); + ret = handle_matrix_confl(confl, cur_matrixset, size, maxlevel, best_row); + } else {*/ + ret = handle_matrix_prop_and_confl(cur_matrixset, last_row, confl); + //} + #ifdef DEBUG_GAUSS + assert(ret == conflict || ret == unit_conflict || nothing_to_propagate(cur_matrixset)); + #endif + + if (!cur_matrixset.num_cols || !cur_matrixset.num_rows) { + badlevel = solver.decisionLevel(); + return ret; + } + + if (ret == nothing && + solver.decisionLevel() % config.only_nth_gauss_save == 0) + set_matrixset_to_cur(); + + #ifdef VERBOSE_DEBUG + if (ret == nothing) + cout << "(" << matrix_no << ")Useless. "; + else + cout << "(" << matrix_no << ")Useful. "; + cout << "(" << matrix_no << ")Useful prop in " << ((double)useful_prop/(double)called)*100.0 << "%" << endl; + cout << "(" << matrix_no << ")Useful confl in " << ((double)useful_confl/(double)called)*100.0 << "%" << endl; + #endif + + return ret; +} + +uint32_t Gaussian::eliminate(matrixset& m) +{ + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")"; + cout << "Starting elimination" << endl; + cout << "m.least_column_changed:" << m.least_column_changed << endl; + #ifdef VERBOSE_DEBUG_MORE + print_last_one_in_cols(m); + #endif + + uint32_t number_of_row_additions = 0; + uint32_t no_exchanged = 0; + #endif + + if (m.least_column_changed == INT_MAX) { + #ifdef VERBOSE_DEBUG + cout << "Nothing to eliminate" << endl; + #endif + + return m.num_rows; + } + + + #ifdef DEBUG_GAUSS + assert(solver.decisionLevel() == 0 || check_last_one_in_cols(m)); + #endif + + uint32_t i = 0; + uint32_t j = (config.iterativeReduce) ? m.least_column_changed + 1 : 0; + PackedMatrix::iterator beginIt = m.matrix.beginMatrix(); + PackedMatrix::iterator rowIt = m.matrix.beginMatrix(); + + #ifdef DEBUG_GAUSS + check_first_one_in_row(m, j); + #endif + + if (j) { + uint16_t until = std::min(m.last_one_in_col[m.least_column_changed] - 1, (int)m.num_rows); + if (j-1 > m.first_one_in_row[m.num_rows-1]) + until = m.num_rows; + for (;i != until; i++, ++rowIt) if (changed_rows[i] && (*rowIt).popcnt_is_one(m.first_one_in_row[i])) + propagatable_rows.push(i); + } + + #ifdef VERBOSE_DEBUG + cout << "At while() start: i,j = " << i << ", " << j << endl; + cout << "num_rows:" << m.num_rows << " num_cols:" << m.num_cols << endl; + #endif + + if (j > m.num_cols) { + #ifdef VERBOSE_DEBUG + cout << "Going straight to finish" << endl; + #endif + goto finish; + } + + #ifdef DEBUG_GAUSS + assert(i <= m.num_rows && j <= m.num_cols); + #endif + + while (i != m.num_rows && j != m.num_cols) { + //Find pivot in column j, starting in row i: + + if (m.col_to_var[j] == unassigned_var) { + j++; + continue; + } + + PackedMatrix::iterator this_matrix_row = rowIt; + PackedMatrix::iterator end = beginIt + m.last_one_in_col[j]; + for (; this_matrix_row != end; ++this_matrix_row) { + if ((*this_matrix_row)[j]) + break; + } + + if (this_matrix_row != end) { + + //swap rows i and maxi, but do not change the value of i; + if (this_matrix_row != rowIt) { + #ifdef VERBOSE_DEBUG + no_exchanged++; + #endif + + //Would early abort, but would not find the best conflict (and would be expensive) + //if (matrix_row_i.is_true() && matrix_row_i.isZero()) { + // conflict_row = i; + // return 0; + //} + (*rowIt).swapBoth(*this_matrix_row); + } + #ifdef DEBUG_GAUSS + assert(m.matrix.getMatrixAt(i).popcnt(j) == m.matrix.getMatrixAt(i).popcnt()); + assert(m.matrix.getMatrixAt(i)[j]); + #endif + + if ((*rowIt).popcnt_is_one(j)) + propagatable_rows.push(i); + + //Now A[i,j] will contain the old value of A[maxi,j]; + ++this_matrix_row; + for (; this_matrix_row != end; ++this_matrix_row) if ((*this_matrix_row)[j]) { + //subtract row i from row u; + //Now A[u,j] will be 0, since A[u,j] - A[i,j] = A[u,j] -1 = 0. + #ifdef VERBOSE_DEBUG + number_of_row_additions++; + #endif + + (*this_matrix_row).xorBoth(*rowIt); + //Would early abort, but would not find the best conflict (and would be expensive) + //if (it->is_true() &&it->isZero()) { + // conflict_row = i2; + // return 0; + //} + } + m.first_one_in_row[i] = j; + i++; + ++rowIt; + m.last_one_in_col[j] = i; + } else { + m.first_one_in_row[i] = j; + m.last_one_in_col[j] = i + 1; + } + j++; + } + + finish: + + m.least_column_changed = INT_MAX; + + #ifdef VERBOSE_DEBUG + cout << "Finished elimination" << endl; + cout << "Returning with i,j:" << i << ", " << j << "(" << m.num_rows << ", " << m.num_cols << ")" << endl; + #ifdef VERBOSE_DEBUG_MORE + print_matrix(m); + print_last_one_in_cols(m); + #endif + cout << "(" << matrix_no << ")Exchanged:" << no_exchanged << " row additions:" << number_of_row_additions << endl; + #endif + + #ifdef DEBUG_GAUSS + assert(check_last_one_in_cols(m)); + uint32_t row = 0; + uint32_t col = 0; + for (; col < m.num_cols && row < m.num_rows && row < i ; col++) { + assert(m.matrix.getMatrixAt(row).popcnt() == m.matrix.getMatrixAt(row).popcnt(col)); + assert(!(m.col_to_var[col] == unassigned_var && m.matrix.getMatrixAt(row)[col])); + if (m.col_to_var[col] == unassigned_var || !m.matrix.getMatrixAt(row)[col]) { + #ifdef VERBOSE_DEBUG_MORE + cout << "row:" << row << " col:" << col << " m.last_one_in_col[col]-1: " << m.last_one_in_col[col]-1 << endl; + #endif + assert(m.col_to_var[col] == unassigned_var || std::min((uint16_t)(m.last_one_in_col[col]-1), m.num_rows) == row); + continue; + } + row++; + } + #endif + + return i; +} + +Gaussian::gaussian_ret Gaussian::handle_matrix_confl(PropBy& confl, const matrixset& m, const uint32_t maxlevel, const uint32_t best_row) +{ + assert(best_row != UINT_MAX); + + const bool xorEqualFalse = !m.matrix.getVarsetAt(best_row).is_true(); + const bool wasUndef = m.matrix.getVarsetAt(best_row).fill(tmp_clause, solver.assigns, col_to_var_original); + release_assert(!wasUndef); + + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")matrix confl clause:" + << tmp_clause << " , " + << "xorEqualFalse:" << xorEqualFalse << std::endl; + #endif + + if (tmp_clause.size() <= 1) { + if (!tmp_clause.empty()) { + confl = PropBy(tmp_clause[0]); + } else { + confl = PropBy(); + solver.ok = false; + } + return unit_conflict; + } + + if (maxlevel != solver.decisionLevel()) { + solver.cancelUntil(maxlevel); + } + const uint32_t curr_dec_level = solver.decisionLevel(); + assert(maxlevel == curr_dec_level); + + uint32_t maxsublevel = 0; + if (tmp_clause.size() == 2) { + Lit lit1 = tmp_clause[0]; + Lit lit2 = tmp_clause[1]; + + solver.watches[(~lit1).toInt()].push(Watched(lit2, true)); + solver.watches[(~lit2).toInt()].push(Watched(lit1, true)); + solver.numBins++; + solver.learnts_literals += 2; + solver.dataSync->signalNewBinClause(lit1, lit2); + + lit1 = ~lit1; + lit2 = ~lit2; + solver.watches[(~lit2).toInt()].push(Watched(lit1, true)); + solver.watches[(~lit1).toInt()].push(Watched(lit2, true)); + solver.numBins++; + solver.learnts_literals += 2; + solver.dataSync->signalNewBinClause(lit1, lit2); + + lit1 = ~lit1; + lit2 = ~lit2; + uint32_t sublevel1 = find_sublevel(lit1.var()); + uint32_t sublevel2 = find_sublevel(lit2.var()); + if (sublevel1 > sublevel2) { + maxsublevel = sublevel1; + std::swap(lit1, lit2); + } else { + maxsublevel = sublevel2; + } + + confl = PropBy(lit1); + solver.failBinLit = lit2; + } else { + Clause* conflPtr = (Clause*)solver.clauseAllocator.XorClause_new(tmp_clause, xorEqualFalse); + confl = solver.clauseAllocator.getOffset(conflPtr); + Clause& cla = *conflPtr; + + uint32_t maxsublevel_at = UINT_MAX; + for (uint32_t i = 0, size = cla.size(); i != size; i++) if (solver.level[cla[i].var()] == (int32_t)curr_dec_level) { + uint32_t tmp = find_sublevel(cla[i].var()); + if (tmp >= maxsublevel) { + maxsublevel = tmp; + maxsublevel_at = i; + } + } + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ") || Sublevel of confl: " << maxsublevel << " (due to var:" << cla[maxsublevel_at].var()-1 << ")" << endl; + #endif + + Lit tmp(cla[maxsublevel_at]); + cla[maxsublevel_at] = cla[1]; + cla[1] = tmp; + } + + cancel_until_sublevel(maxsublevel+1); + messed_matrix_vars_since_reversal = true; + + return conflict; +} + +Gaussian::gaussian_ret Gaussian::handle_matrix_prop_and_confl(matrixset& m, uint32_t last_row, PropBy& confl) +{ + int32_t maxlevel = std::numeric_limits<int32_t>::max(); + uint32_t size = UINT_MAX; + uint32_t best_row = UINT_MAX; + + for (uint32_t row = last_row; row != m.num_rows; row++) { + #ifdef DEBUG_GAUSS + assert(m.matrix.getMatrixAt(row).isZero()); + #endif + if (m.matrix.getMatrixAt(row).is_true()) + analyse_confl(m, row, maxlevel, size, best_row); + } + + if (maxlevel != std::numeric_limits<int32_t>::max()) + return handle_matrix_confl(confl, m, maxlevel, best_row); + + #ifdef DEBUG_GAUSS + assert(check_no_conflict(m)); + assert(last_row == 0 || !m.matrix.getMatrixAt(last_row-1).isZero()); + #endif + + #ifdef VERBOSE_DEBUG + cout << "Resizing matrix to num_rows = " << last_row << endl; + #endif + m.num_rows = last_row; + m.matrix.resizeNumRows(m.num_rows); + + gaussian_ret ret = nothing; + + uint32_t num_props = 0; + for (const uint32_t* prop_row = propagatable_rows.getData(), *end = prop_row + propagatable_rows.size(); prop_row != end; prop_row++ ) { + //this is a "000..1..0000000X" row. I.e. it indicates a propagation + ret = handle_matrix_prop(m, *prop_row); + num_props++; + if (ret == unit_propagation) { + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")Unit prop! Breaking from prop examination" << endl; + #endif + return unit_propagation; + } + } + #ifdef VERBOSE_DEBUG + if (num_props > 0) cout << "(" << matrix_no << ")Number of props during gauss:" << num_props << endl; + #endif + + return ret; +} + +uint32_t Gaussian::find_sublevel(const Var v) const +{ + for (int i = solver.trail.size()-1; i >= 0; i --) + if (solver.trail[i].var() == v) return i; + + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")Oooops! Var " << v+1 << " does not have a sublevel!! (so it must be undefined)" << endl; + #endif + + assert(false); + return 0; +} + +void Gaussian::cancel_until_sublevel(const uint32_t until_sublevel) +{ + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")Canceling until sublevel " << until_sublevel << endl; + #endif + + for (vector<Gaussian*>::iterator gauss = solver.gauss_matrixes.begin(), end= solver.gauss_matrixes.end(); gauss != end; gauss++) + if (*gauss != this) (*gauss)->canceling(until_sublevel); + + for (int sublevel = solver.trail.size()-1; sublevel >= (int)until_sublevel; sublevel--) { + Var var = solver.trail[sublevel].var(); + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")Canceling var " << var+1 << endl; + #endif + + solver.assigns[var] = l_Undef; + solver.insertVarOrder(var); + } + solver.trail.shrink(solver.trail.size() - until_sublevel); + + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")Canceling sublevel finished." << endl; + #endif +} + +void Gaussian::analyse_confl(const matrixset& m, const uint32_t row, int32_t& maxlevel, uint32_t& size, uint32_t& best_row) const +{ + assert(row < m.num_rows); + + //this is a "000...00000001" row. I.e. it indicates we are on the wrong branch + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")matrix conflict found!" << endl; + cout << "(" << matrix_no << ")conflict clause's vars: "; + #ifdef VERBOSE_DEBUG_MORE + print_matrix_row_with_assigns(m.matrix.getVarsetAt(row)); + cout << endl; + + cout << "(" << matrix_no << ")corresponding matrix's row (should be empty): "; + print_matrix_row(m.matrix.getMatrixAt(row)); + cout << endl; + #endif + #endif + + int32_t this_maxlevel = 0; + unsigned long int var = 0; + uint32_t this_size = 0; + while (true) { + var = m.matrix.getVarsetAt(row).scan(var); + if (var == ULONG_MAX) break; + + const Var real_var = col_to_var_original[var]; + assert(real_var < solver.nVars()); + + if (solver.level[real_var] > this_maxlevel) + this_maxlevel = solver.level[real_var]; + var++; + this_size++; + } + + //the maximum of all lit's level must be lower than the max. level of the current best clause (or this clause must be either empty or unit clause) + if (!( + (this_maxlevel < maxlevel) + || (this_maxlevel == maxlevel && this_size < size) + || (this_size <= 1) + )) { + assert(maxlevel != std::numeric_limits<int32_t>::max()); + + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")Other found conflict just as good or better."; + cout << "(" << matrix_no << ") || Old maxlevel:" << maxlevel << " new maxlevel:" << this_maxlevel; + cout << "(" << matrix_no << ") || Old size:" << size << " new size:" << this_size << endl; + //assert(!(maxlevel != UINT_MAX && maxlevel != this_maxlevel)); //NOTE: only holds if gauss is executed at each level + #endif + + return; + } + + + #ifdef VERBOSE_DEBUG + if (maxlevel != std::numeric_limits<int32_t>::max()) + cout << "(" << matrix_no << ")Better conflict found."; + else + cout << "(" << matrix_no << ")Found a possible conflict."; + + cout << "(" << matrix_no << ") || Old maxlevel:" << maxlevel << " new maxlevel:" << this_maxlevel; + cout << "(" << matrix_no << ") || Old size:" << size << " new size:" << this_size << endl; + #endif + + maxlevel = this_maxlevel; + size = this_size; + best_row = row; +} + +Gaussian::gaussian_ret Gaussian::handle_matrix_prop(matrixset& m, const uint32_t row) +{ + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")matrix prop" << endl; + #ifdef VERBOSE_DEBUG_MORE + cout << "(" << matrix_no << ")matrix row:" << m.matrix.getMatrixAt(row) << endl; + #endif + #endif + + bool xorEqualFalse = !m.matrix.getVarsetAt(row).is_true(); + m.matrix.getVarsetAt(row).fill(tmp_clause, solver.assigns, col_to_var_original); + #ifdef VERBOSE_DEBUG + cout << "(" << matrix_no << ")matrix prop clause: " << tmp_clause << std::endl; + cout << endl; + #endif + + switch(tmp_clause.size()) { + case 0: + //This would mean nothing, empty = true, always true in xors + assert(false); + break; + case 1: + solver.cancelUntil(0); + solver.uncheckedEnqueue(tmp_clause[0]); + return unit_propagation; + case 2: { + solver.cancelUntil(0); + tmp_clause[0] = tmp_clause[0].unsign(); + tmp_clause[1] = tmp_clause[1].unsign(); + XorClause* cl = solver.addXorClauseInt(tmp_clause, xorEqualFalse); + release_assert(cl == NULL); + release_assert(solver.ok); + return unit_propagation; + } + default: + if (solver.decisionLevel() == 0) { + solver.uncheckedEnqueue(tmp_clause[0]); + return unit_propagation; + } + Clause& cla = *(Clause*)solver.clauseAllocator.XorClause_new(tmp_clause, xorEqualFalse); + assert(m.matrix.getMatrixAt(row).is_true() == !cla[0].sign()); + assert(solver.assigns[cla[0].var()].isUndef()); + + clauses_toclear.push_back(std::make_pair(&cla, solver.trail.size()-1)); + solver.uncheckedEnqueue(cla[0], solver.clauseAllocator.getOffset(&cla)); + return propagation; + } + + return propagation; +} + +void Gaussian::disable_if_necessary() +{ + if (//nof_conflicts >= 0 + //&& conflictC >= nof_conflicts/8 + !config.dontDisable + && called > 50 + && useful_confl*2+useful_prop < (uint32_t)((double)called*0.05) ) + disabled = true; +} + +llbool Gaussian::find_truths(vec<Lit>& learnt_clause, uint64_t& conflictC) +{ + PropBy confl; + + disable_if_necessary(); + if (should_check_gauss(solver.decisionLevel())) { + called++; + gaussian_ret g = gaussian(confl); + + switch (g) { + case conflict: { + useful_confl++; + llbool ret = solver.handle_conflict(learnt_clause, confl, conflictC, true); + if (confl.isClause()) + solver.clauseAllocator.clauseFree(solver.clauseAllocator.getPointer(confl.getClause())); + + if (ret != l_Nothing) return ret; + return l_Continue; + } + case unit_propagation: + unit_truths++; + case propagation: + useful_prop++; + return l_Continue; + case unit_conflict: { + unit_truths++; + useful_confl++; + if (confl.isNULL()) { + #ifdef VERBOSE_DEBUG + std::cout << "(" << matrix_no << ")zero-length conflict. UNSAT" << std::endl; + #endif + solver.ok = false; + return l_False; + } + + Lit lit = confl.getOtherLit(); + solver.cancelUntil(0); + + #ifdef VERBOSE_DEBUG + std::cout << "(" << matrix_no << ")one-length conflict" << std::endl; + #endif + if (solver.value(lit) != l_Undef) { + assert(solver.value(lit) == l_False); + #ifdef VERBOSE_DEBUG + std::cout << "(" << matrix_no << ") -> UNSAT" << std::endl; + #endif + solver.ok = false; + return l_False; + } + #ifdef VERBOSE_DEBUG + std::cout << "(" << matrix_no << ") -> setting to correct value" << std::endl; + #endif + solver.uncheckedEnqueue(lit); + return l_Continue; + } + case nothing: + break; + } + } + + return l_Nothing; +} + +template<class T> +void Gaussian::print_matrix_row(const T& row) const +{ + unsigned long int var = 0; + while (true) { + var = row.scan(var); + if (var == ULONG_MAX) break; + + else cout << col_to_var_original[var]+1 << ", "; + var++; + } + cout << "final:" << row.is_true() << endl;; +} + +template<class T> +void Gaussian::print_matrix_row_with_assigns(const T& row) const +{ + unsigned long int col = 0; + while (true) { + col = row.scan(col); + if (col == ULONG_MAX) break; + + else { + Var var = col_to_var_original[col]; + cout << var+1 << "(" << lbool_to_string(solver.assigns[var]) << ")"; + cout << ", "; + } + col++; + } + if (!row.is_true()) cout << "xorEqualFalse"; +} + +string Gaussian::lbool_to_string(const lbool toprint) +{ + if (toprint == l_True) + return "true"; + if (toprint == l_False) + return "false"; + if (toprint == l_Undef) + return "undef"; + + assert(false); + return ""; +} + + +void Gaussian::print_stats() const +{ + if (called > 0) { + cout.setf(std::ios::fixed); + std::cout << " Gauss(" << matrix_no << ") useful"; + cout << " prop: " << std::setprecision(2) << std::setw(5) << ((double)useful_prop/(double)called)*100.0 << "% "; + cout << " confl: " << std::setprecision(2) << std::setw(5) << ((double)useful_confl/(double)called)*100.0 << "% "; + if (disabled) std::cout << "disabled"; + } else + std::cout << " Gauss(" << matrix_no << ") not called."; +} + +void Gaussian::print_matrix_stats() const +{ + cout << "matrix size: " << cur_matrixset.num_rows << " x " << cur_matrixset.num_cols << endl; +} + + +void Gaussian::reset_stats() +{ + useful_prop = 0; + useful_confl = 0; + called = 0; + disabled = false; +} + +bool Gaussian::check_no_conflict(matrixset& m) const +{ + uint32_t row = 0; + for(PackedMatrix::iterator r = m.matrix.beginMatrix(), end = m.matrix.endMatrix(); r != end; ++r, ++row) { + if ((*r).is_true() && (*r).isZero()) { + cout << "Conflict at row " << row << endl; + return false; + } + } + return true; +} + +void Gaussian::print_matrix(matrixset& m) const +{ + uint32_t row = 0; + for (PackedMatrix::iterator it = m.matrix.beginMatrix(); it != m.matrix.endMatrix(); ++it, row++) { + cout << *it << " -- row:" << row; + if (row >= m.num_rows) + cout << " (considered past the end)"; + cout << endl; + } +} + +void Gaussian::print_last_one_in_cols(matrixset& m) const +{ + for (uint32_t i = 0; i < m.num_cols; i++) { + cout << "last_one_in_col[" << i << "]-1 = " << m.last_one_in_col[i]-1 << endl; + } +} + +bool Gaussian::nothing_to_propagate(matrixset& m) const +{ + for(PackedMatrix::iterator r = m.matrix.beginMatrix(), end = m.matrix.endMatrix(); r != end; ++r) { + if ((*r).popcnt_is_one() + && solver.assigns[m.col_to_var[(*r).scan(0)]].isUndef()) { + #ifdef VERBOSE_DEBUG + std::cout << "row " << (*r) << " is a propagation, but we didn't catch it" << std::endl; + #endif + return false; + } + } + for(PackedMatrix::iterator r = m.matrix.beginMatrix(), end = m.matrix.endMatrix(); r != end; ++r) { + if ((*r).isZero() && (*r).is_true()) { + #ifdef VERBOSE_DEBUG + std::cout << "row " << (*r) << " is a conflict, but we didn't catch it" << std::endl; + #endif + return false; + } + } + return true; +} + +bool Gaussian::check_last_one_in_cols(matrixset& m) const +{ + for(uint32_t i = 0; i < m.num_cols; i++) { + const uint32_t last = std::min(m.last_one_in_col[i] - 1, (int)m.num_rows); + uint32_t real_last = 0; + uint32_t i2 = 0; + for (PackedMatrix::iterator it = m.matrix.beginMatrix(); it != m.matrix.endMatrix(); ++it, i2++) { + if ((*it)[i]) + real_last = i2; + } + if (real_last > last) + return false; + } + + return true; +} + +void Gaussian::check_matrix_against_varset(PackedMatrix& matrix, const matrixset& m) const +{ + for (uint32_t i = 0; i < matrix.getSize(); i++) { + const PackedRow mat_row = matrix.getMatrixAt(i); + const PackedRow var_row = matrix.getVarsetAt(i); + + unsigned long int col = 0; + bool final = false; + while (true) { + col = var_row.scan(col); + if (col == ULONG_MAX) break; + + const Var var = col_to_var_original[col]; + assert(var < solver.nVars()); + + if (solver.assigns[var] == l_True) { + assert(!mat_row[col]); + assert(m.col_to_var[col] == unassigned_var); + assert(m.var_is_set[var]); + final = !final; + } else if (solver.assigns[var] == l_False) { + assert(!mat_row[col]); + assert(m.col_to_var[col] == unassigned_var); + assert(m.var_is_set[var]); + } else if (solver.assigns[var] == l_Undef) { + assert(m.col_to_var[col] != unassigned_var); + assert(!m.var_is_set[var]); + assert(mat_row[col]); + } else assert(false); + + col++; + } + if ((final^!mat_row.is_true()) != !var_row.is_true()) { + cout << "problem with row:"; print_matrix_row_with_assigns(var_row); cout << endl; + assert(false); + } + } +} + +void Gaussian::check_first_one_in_row(matrixset& m, const uint32_t j) +{ + if (j) { + uint16_t until2 = std::min(m.last_one_in_col[m.least_column_changed] - 1, (int)m.num_rows); + if (j-1 > m.first_one_in_row[m.num_rows-1]) { + until2 = m.num_rows; + #ifdef VERBOSE_DEBUG + cout << "j-1 > m.first_one_in_row[m.num_rows-1]" << "j:" << j << " m.first_one_in_row[m.num_rows-1]:" << m.first_one_in_row[m.num_rows-1] << endl; + #endif + } + for (uint32_t i2 = 0; i2 != until2; i2++) { + #ifdef VERBOSE_DEBUG + cout << endl << "row " << i2 << " (num rows:" << m.num_rows << ")" << endl; + cout << m.matrix.getMatrixAt(i2) << endl; + cout << " m.first_one_in_row[m.num_rows-1]:" << m.first_one_in_row[m.num_rows-1] << endl; + cout << "first_one_in_row:" << m.first_one_in_row[i2] << endl; + cout << "num_cols:" << m.num_cols << endl; + cout << "popcnt:" << m.matrix.getMatrixAt(i2).popcnt() << endl; + cout << "popcnt_is_one():" << m.matrix.getMatrixAt(i2).popcnt_is_one() << endl; + cout << "popcnt_is_one("<< m.first_one_in_row[i2] <<"): " << m.matrix.getMatrixAt(i2).popcnt_is_one(m.first_one_in_row[i2]) << endl; + #endif + + for (uint32_t i3 = 0; i3 < m.first_one_in_row[i2]; i3++) { + assert(m.matrix.getMatrixAt(i2)[i3] == 0); + } + assert(m.matrix.getMatrixAt(i2)[m.first_one_in_row[i2]]); + assert(m.matrix.getMatrixAt(i2).popcnt_is_one() == + m.matrix.getMatrixAt(i2).popcnt_is_one(m.first_one_in_row[i2])); + } + } +} diff --git a/src/prop/cryptominisat/Solver/Gaussian.h b/src/prop/cryptominisat/Solver/Gaussian.h new file mode 100644 index 000000000..6e4151811 --- /dev/null +++ b/src/prop/cryptominisat/Solver/Gaussian.h @@ -0,0 +1,243 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#ifndef GAUSSIAN_H +#define GAUSSIAN_H + +#include <vector> +#include <limits> +#include <string> +#include <utility> + +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#include "SolverTypes.h" +#include "Solver.h" +#include "GaussianConfig.h" +#include "PackedMatrix.h" +#include "BitArray.h" + +//#define VERBOSE_DEBUG +//#define DEBUG_GAUSS + +namespace CMSat { + +using std::string; +using std::pair; +using std::vector; + +class Clause; + +class Gaussian +{ +public: + Gaussian(Solver& solver, const GaussConf& config, const uint32_t matrix_no, const vector<XorClause*>& xorclauses); + ~Gaussian(); + + bool full_init(); + llbool find_truths(vec<Lit>& learnt_clause, uint64_t& conflictC); + + //statistics + void print_stats() const; + void print_matrix_stats() const; + uint32_t get_called() const; + uint32_t get_useful_prop() const; + uint32_t get_useful_confl() const; + bool get_disabled() const; + uint32_t get_unit_truths() const; + void set_disabled(const bool toset); + + //functions used throughout the Solver + void canceling(const uint32_t sublevel); + + friend class ClauseAllocator; + +protected: + Solver& solver; + + //Gauss high-level configuration + const GaussConf& config; + const uint32_t matrix_no; + vector<XorClause*> xorclauses; + + enum gaussian_ret {conflict, unit_conflict, propagation, unit_propagation, nothing}; + gaussian_ret gaussian(PropBy& confl); + + vector<Var> col_to_var_original; //Matches columns to variables + BitArray var_is_in; //variable is part of the the matrix. var_is_in's size is _minimal_ so you should check whether var_is_in.getSize() < var before issuing var_is_in[var] + uint32_t badlevel; + + class matrixset + { + public: + PackedMatrix matrix; // The matrix, updated to reflect variable assignements + BitArray var_is_set; + vector<Var> col_to_var; // col_to_var[COL] tells which variable is at a given column in the matrix. Gives unassigned_var if the COL has been zeroed (i.e. the variable assigned) + uint16_t num_rows; // number of active rows in the matrix. Unactive rows are rows that contain only zeros (and if they are conflicting, then the conflict has been treated) + uint32_t num_cols; // number of active columns in the matrix. The columns at the end that have all be zeroed are no longer active + int least_column_changed; // when updating the matrix, this value contains the smallest column number that has been updated (Gauss elim. can start from here instead of from column 0) + vector<uint16_t> last_one_in_col; //last_one_in_col[COL] tells the last row+1 that has a '1' in that column. Used to reduce the burden of Gauss elim. (it only needs to look until that row) + vector<uint16_t> first_one_in_row; + uint32_t removeable_cols; // the number of columns that have been zeroed out (i.e. assigned) + }; + + //Saved states + vector<matrixset> matrix_sets; // The matrixsets for depths 'decision_from' + 0, 'decision_from' + only_nth_gaussian_save, 'decision_from' + 2*only_nth_gaussian_save, ... 'decision_from' + 'decision_until'. + matrixset cur_matrixset; // The current matrixset, i.e. the one we are working on, or the last one we worked on + + //Varibales to keep Gauss state + bool messed_matrix_vars_since_reversal; + int gauss_last_level; + vector<pair<Clause*, uint32_t> > clauses_toclear; + bool disabled; // Gauss is disabled + + //State of current elimnation + vec<uint32_t> propagatable_rows; //used to store which rows were deemed propagatable during elimination + vector<unsigned char> changed_rows; //used to store which rows were deemed propagatable during elimination + + //Statistics + uint32_t useful_prop; //how many times Gauss gave propagation as a result + uint32_t useful_confl; //how many times Gauss gave conflict as a result + uint32_t called; //how many times called the Gauss + uint32_t unit_truths; //how many unitary (i.e. decisionLevel 0) truths have been found + + //gauss init functions + void init(); // Initalise gauss state + void fill_matrix(matrixset& origMat); // Fills the origMat matrix + uint32_t select_columnorder(vector<uint16_t>& var_to_col, matrixset& origMat); // Fills var_to_col and col_to_var of the origMat matrix. + + //Main function + uint32_t eliminate(matrixset& matrix); //does the actual gaussian elimination + + //matrix update functions + void update_matrix_col(matrixset& matrix, const Var x, const uint32_t col); // Update one matrix column + void update_matrix_by_col_all(matrixset& m); // Update all columns, column-by-column (and not row-by-row) + void set_matrixset_to_cur(); // Save the current matrixset, the cur_matrixset to matrix_sets + //void update_matrix_by_row(matrixset& matrix) const; + //void update_matrix_by_col(matrixset& matrix, const uint32_t last_level) const; + + //conflict&propagation handling + gaussian_ret handle_matrix_prop_and_confl(matrixset& m, uint32_t row, PropBy& confl); + void analyse_confl(const matrixset& m, const uint32_t row, int32_t& maxlevel, uint32_t& size, uint32_t& best_row) const; // analyse conflcit to find the best conflict. Gets & returns the best one in 'maxlevel', 'size' and 'best row' (these are all UINT_MAX when calling this function first, i.e. when there is no other possible conflict to compare to the new in 'row') + gaussian_ret handle_matrix_confl(PropBy& confl, const matrixset& m, const uint32_t maxlevel, const uint32_t best_row); + gaussian_ret handle_matrix_prop(matrixset& m, const uint32_t row); // Handle matrix propagation at row 'row' + vec<Lit> tmp_clause; + + //propagation&conflict handling + void cancel_until_sublevel(const uint32_t until_sublevel); // cancels until sublevel 'until_sublevel'. The var 'until_sublevel' must NOT go over the current level. I.e. this function is ONLY for moving inside the current level + uint32_t find_sublevel(const Var v) const; // find the sublevel (i.e. trail[X]) of a given variable + + //helper functions + bool at_first_init() const; + bool should_init() const; + bool should_check_gauss(const uint32_t decisionlevel) const; + void disable_if_necessary(); + void reset_stats(); + void update_last_one_in_col(matrixset& m); + +private: + + //debug functions + bool check_no_conflict(matrixset& m) const; // Are there any conflicts that the matrixset 'm' causes? + bool nothing_to_propagate(matrixset& m) const; // Are there any conflicts of propagations that matrixset 'm' clauses? + template<class T> + void print_matrix_row(const T& row) const; // Print matrix row 'row' + template<class T> + void print_matrix_row_with_assigns(const T& row) const; + void check_matrix_against_varset(PackedMatrix& matrix,const matrixset& m) const; + bool check_last_one_in_cols(matrixset& m) const; + void check_first_one_in_row(matrixset& m, const uint32_t j); + void print_matrix(matrixset& m) const; + void print_last_one_in_cols(matrixset& m) const; + static string lbool_to_string(const lbool toprint); +}; + +inline bool Gaussian::should_init() const +{ + return (config.decision_until > 0); +} + +inline bool Gaussian::should_check_gauss(const uint32_t decisionlevel) const +{ + return (!disabled + && decisionlevel < config.decision_until); +} + +inline void Gaussian::canceling(const uint32_t sublevel) +{ + if (disabled) + return; + uint32_t a = 0; + for (int i = clauses_toclear.size()-1; i >= 0 && clauses_toclear[i].second > sublevel; i--) { + solver.clauseAllocator.clauseFree(clauses_toclear[i].first); + a++; + } + clauses_toclear.resize(clauses_toclear.size()-a); + + if (messed_matrix_vars_since_reversal) + return; + int c = std::min((int)gauss_last_level, (int)(solver.trail.size())-1); + for (; c >= (int)sublevel; c--) { + Var var = solver.trail[c].var(); + if (var < var_is_in.getSize() + && var_is_in[var] + && cur_matrixset.var_is_set[var]) { + messed_matrix_vars_since_reversal = true; + return; + } + } +} + +inline uint32_t Gaussian::get_unit_truths() const +{ + return unit_truths; +} + +inline uint32_t Gaussian::get_called() const +{ + return called; +} + +inline uint32_t Gaussian::get_useful_prop() const +{ + return useful_prop; +} + +inline uint32_t Gaussian::get_useful_confl() const +{ + return useful_confl; +} + +inline bool Gaussian::get_disabled() const +{ + return disabled; +} + +inline void Gaussian::set_disabled(const bool toset) +{ + disabled = toset; +} + +//std::ostream& operator << (std::ostream& os, const vec<Lit>& v); + +} + +#endif //GAUSSIAN_H diff --git a/src/prop/cryptominisat/Solver/GaussianConfig.h b/src/prop/cryptominisat/Solver/GaussianConfig.h new file mode 100644 index 000000000..afcdefbf1 --- /dev/null +++ b/src/prop/cryptominisat/Solver/GaussianConfig.h @@ -0,0 +1,63 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#ifndef GAUSSIANCONFIG_H +#define GAUSSIANCONFIG_H + +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#include "PackedRow.h" + +namespace CMSat +{ + +class GaussConf +{ + public: + + GaussConf() : + only_nth_gauss_save(2) + , decision_until(0) + , dontDisable(false) + , noMatrixFind(false) + , orderCols(true) + , iterativeReduce(true) + , maxMatrixRows(1000) + , minMatrixRows(20) + , maxNumMatrixes(3) + { + } + + //tuneable gauss parameters + uint32_t only_nth_gauss_save; //save only every n-th gauss matrix + uint32_t decision_until; //do Gauss until this level + bool dontDisable; //If activated, gauss elimination is never disabled + bool noMatrixFind; //Put all xor-s into one matrix, don't find matrixes + bool orderCols; //Order columns according to activity + bool iterativeReduce; //Don't minimise matrix work + uint32_t maxMatrixRows; //The maximum matrix size -- no. of rows + uint32_t minMatrixRows; //The minimum matrix size -- no. of rows + uint32_t maxNumMatrixes; //Maximum number of matrixes +}; + +} + +#endif //GAUSSIANCONFIG_H diff --git a/src/prop/cryptominisat/Solver/Main.cpp b/src/prop/cryptominisat/Solver/Main.cpp new file mode 100644 index 000000000..111683ee8 --- /dev/null +++ b/src/prop/cryptominisat/Solver/Main.cpp @@ -0,0 +1,974 @@ +/***************************************************************************** +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +Original code by MiniSat authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3 licence. +******************************************************************************/ + +/** +@mainpage CryptoMiniSat +@author Mate Soos, and collaborators + +CryptoMiniSat is an award-winning SAT solver based on MiniSat. It brings a +number of benefits relative to MiniSat, among them XOR clauses, extensive +failed literal probing, and better random search. + +The solver basically performs the following steps: + +1) parse CNF file into clause database + +2) run Conflict-Driven Clause-Learning DPLL on the clauses + +3) regularly run simplification passes on the clause-set + +4) display solution and if not used as a library, exit + +Here is a picture of of the above process in more detail: + +\image html "main_flowgraph.png" + +*/ + +#include <ctime> +#include <cstring> +#include <errno.h> +#include <string.h> +#include <sstream> +#include <iostream> +#include <iomanip> +#include <omp.h> +#include <map> +#include <set> +#include "constants.h" + +#include <signal.h> + +#include "time_mem.h" +#include "constants.h" +#include "DimacsParser.h" + +#if defined(__linux__) +#include <fpu_control.h> +#endif + +#include "Main.h" + +using namespace CMSat; + +Main::Main(int _argc, char** _argv) : + numThreads(1) + , grouping(false) + , debugLib (false) + , debugNewVar (false) + , printResult (true) + , max_nr_of_solutions (1) + , fileNamePresent (false) + , twoFileNamesPresent (false) + , argc(_argc) + , argv(_argv) +{ +} + +std::map<uint32_t, Solver*> solversToInterrupt; +std::set<uint32_t> finished; + +void Main::readInAFile(const std::string& filename, Solver& solver) +{ + #pragma omp single + if (solver.conf.verbosity >= 1) { + std::cout << "c Reading file '" << filename << "'" << std::endl; + } + #ifdef DISABLE_ZLIB + FILE * in = fopen(filename.c_str(), "rb"); + #else + gzFile in = gzopen(filename.c_str(), "rb"); + #endif // DISABLE_ZLIB + + #pragma omp single + if (in == NULL) { + std::cout << "ERROR! Could not open file '" << filename << "' for reading" << std::endl; + exit(1); + } + + DimacsParser parser(&solver, debugLib, debugNewVar, grouping); + parser.parse_DIMACS(in); + + #ifdef DISABLE_ZLIB + fclose(in); + #else + gzclose(in); + #endif // DISABLE_ZLIB +} + +void Main::readInStandardInput(Solver& solver) +{ + if (solver.conf.verbosity >= 1) { + std::cout << "c Reading from standard input... Use '-h' or '--help' for help." << std::endl; + } + #ifdef DISABLE_ZLIB + FILE * in = stdin; + #else + gzFile in = gzdopen(fileno(stdin), "rb"); + #endif // DISABLE_ZLIB + + if (in == NULL) { + std::cout << "ERROR! Could not open standard input for reading" << std::endl; + exit(1); + } + + DimacsParser parser(&solver, debugLib, debugNewVar, grouping); + parser.parse_DIMACS(in); + + #ifndef DISABLE_ZLIB + gzclose(in); + #endif // DISABLE_ZLIB +} + + + +void Main::parseInAllFiles(Solver& solver) +{ + double myTime = cpuTime(); + + //First read normal extra files + if ((debugLib || debugNewVar) && filesToRead.size() > 0) { + std::cout << "debugNewVar and debugLib must both be OFF to parse in extra files" << std::endl; + exit(-1); + } + for (uint32_t i = 0; i < filesToRead.size(); i++) { + readInAFile(filesToRead[i].c_str(), solver); + } + + //Then read the main file or standard input + if (!fileNamePresent) { + readInStandardInput(solver); + } else { + string filename = argv[(twoFileNamesPresent ? argc-2 : argc-1)]; + readInAFile(filename, solver); + } + + if (solver.conf.verbosity >= 1) { + std::cout << "c Parsing time: " + << std::fixed << std::setw(5) << std::setprecision(2) << (cpuTime() - myTime) + << " s" << std::endl; + } +} + + +void Main::printUsage(char** argv) +{ +#ifdef DISABLE_ZLIB + printf("USAGE: %s [options] <input-file> <result-output-file>\n\n where input is plain DIMACS.\n\n", argv[0]); +#else + printf("USAGE: %s [options] <input-file> <result-output-file>\n\n where input may be either in plain or gzipped DIMACS.\n\n", argv[0]); +#endif // DISABLE_ZLIB + printf("OPTIONS:\n\n"); + printf(" --polarity-mode = {true,false,rnd,auto} [default: auto]. Selects the default\n"); + printf(" polarity mode. Auto is the Jeroslow&Wang method\n"); + //printf(" -decay = <num> [ 0 - 1 ]\n"); + printf(" --rnd-freq = <num> [ 0 - 1 ]\n"); + printf(" --verbosity = {0,1,2}\n"); + printf(" --randomize = <seed> [0 - 2^32-1] Sets random seed, used for picking\n"); + printf(" decision variables (default = 0)\n"); + printf(" --restrict = <num> [1 - varnum] when picking random variables to branch\n"); + printf(" on, pick one that in the 'num' most active vars useful\n"); + printf(" for cryptographic problems, where the question is the key,\n"); + printf(" which is usually small (e.g. 80 bits)\n"); + printf(" --gaussuntil = <num> Depth until which Gaussian elimination is active.\n"); + printf(" Giving 0 switches off Gaussian elimination\n"); + printf(" --restarts = <num> [1 - 2^32-1] No more than the given number of\n"); + printf(" restarts will be performed during search\n"); + printf(" --nonormxorfind Don't find and collect >2-long xor-clauses from\n"); + printf(" regular clauses\n"); + printf(" --nobinxorfind Don't find and collect 2-long xor-clauses from\n"); + printf(" regular clauses\n"); + printf(" --noregbxorfind Don't regularly find and collect 2-long xor-clauses\n"); + printf(" from regular clauses\n"); + printf(" --doextendedscc Do strongly conn. comp. finding using non-exist. bins\n"); + printf(" --noconglomerate Don't conglomerate 2 xor clauses when one var is dependent\n"); + printf(" --nosimplify Don't do regular simplification rounds\n"); + printf(" --greedyunbound Greedily unbound variables that are not needed for SAT\n"); + printf(" --debuglib Solve at specific 'c Solver::solve()' points in the CNF\n"); + printf(" file. Used to debug file generated by Solver's\n"); + printf(" needLibraryCNFFile() function\n"); + printf(" --debugnewvar Add new vars at specific 'c Solver::newVar()' points in \n"); + printf(" the CNF file. Used to debug file generated by Solver's\n"); + printf(" needLibraryCNFFile() function.\n"); + printf(" --novarreplace Don't perform variable replacement. Needed for programmable\n"); + printf(" solver feature\n"); + printf(" --restart = {auto, static, dynamic} Which kind of restart strategy to\n"); + printf(" follow. Default is auto\n"); + printf(" --dumplearnts = <filename> If interrupted or reached restart limit, dump\n"); + printf(" the learnt clauses to the specified file. Maximum size of\n"); + printf(" dumped clauses can be specified with next option.\n"); + printf(" --maxdumplearnts = [0 - 2^32-1] When dumping the learnts to file, what\n"); + printf(" should be maximum length of the clause dumped. Useful\n"); + printf(" to make the resulting file smaller. Default is 2^32-1\n"); + printf(" note: 2-long XOR-s are always dumped.\n"); + printf(" --dumporig = <filename> If interrupted or reached restart limit, dump\n"); + printf(" the original problem instance, simplified to the\n"); + printf(" current point.\n"); + printf(" --alsoread = <filename> Also read this file in\n"); + printf(" Can be used to re-read dumped learnts, for example\n"); + printf(" --maxsolutions Search for given amount of solutions\n"); + printf(" Can only be used in single-threaded more (\"--threads=1\")\n"); + printf(" --pavgbranch Print average branch depth\n"); + printf(" --nofailedlit Don't search for failed literals, and don't search for lits\n"); + printf(" propagated both by 'varX' and '-varX'\n"); + printf(" --noheuleprocess Don't try to minimise XORs by XOR-ing them together.\n"); + printf(" Algo. as per global/local substitution in Heule's thesis\n"); + printf(" --nosatelite Don't do clause subsumption, clause strengthening and\n"); + printf(" variable elimination (implies -novarelim and -nosubsume1).\n"); + printf(" --noxorsubs Don't try to subsume xor-clauses.\n"); + printf(" --nosolprint Don't print the satisfying assignment if the solution\n"); + printf(" is SAT\n"); + printf(" --novarelim Don't perform variable elimination as per Een and Biere\n"); + printf(" --nosubsume1 Don't perform clause contraction through resolution\n"); +#ifdef USE_GAUSS + printf(" --nomatrixfind Don't find distinct matrixes. Put all xors into one\n"); + printf(" big matrix\n"); + printf(" --noordercol Don't order variables in the columns of Gaussian\n"); + printf(" elimination. Effectively disables iterative reduction\n"); + printf(" of the matrix\n"); + printf(" --noiterreduce Don't reduce iteratively the matrix that is updated\n"); + printf(" --maxmatrixrows [0 - 2^32-1] Set maximum no. of rows for gaussian matrix.\n"); + printf(" Too large matrixes should bee discarded for\n"); + printf(" reasons of efficiency. Default: %d\n", gaussconfig.maxMatrixRows); + printf(" --minmatrixrows = [0 - 2^32-1] Set minimum no. of rows for gaussian matrix.\n"); + printf(" Normally, too small matrixes are discarded for\n"); + printf(" reasons of efficiency. Default: %d\n", gaussconfig.minMatrixRows); + printf(" --savematrix = [0 - 2^32-1] Save matrix every Nth decision level.\n"); + printf(" Default: %d\n", gaussconfig.only_nth_gauss_save); + printf(" --maxnummatrixes = [0 - 2^32-1] Maximum number of matrixes to treat.\n"); + printf(" Default: %d\n", gaussconfig.maxNumMatrixes); +#endif //USE_GAUSS + //printf(" --addoldlearnts = Readd old learnts for failed variable searching.\n"); + //printf(" These learnts are usually deleted, but may help\n"); + printf(" --nohyperbinres Don't add binary clauses when doing failed lit probing.\n"); + printf(" --noremovebins Don't remove useless binary clauses\n"); + printf(" --noremlbins Don't remove useless learnt binary clauses\n"); + printf(" --nosubswithbins Don't subsume with binary clauses\n"); + printf(" --nosubswithnbins Don't subsume with non-existent binary clauses\n"); + printf(" --noclausevivif Don't do perform clause vivification\n"); + printf(" --nosortwatched Don't sort watches according to size: bin, tri, etc.\n"); + printf(" --nolfminim Don't do on-the-fly self-subsuming resolution\n"); + printf(" (called 'strong minimisation' in PrecoSat)\n"); + printf(" --nocalcreach Don't calculate reachability and interfere with\n"); + printf(" variable decisions accordingly\n"); + printf(" --nobxor Don't find equivalent lits during failed lit search\n"); + printf(" --norecotfssr Don't perform recursive/transitive OTF self-\n"); + printf(" subsuming resolution\n"); + printf(" --nocacheotfssr Don't cache 1-level equeue. Less memory used, but\n"); + printf(" disables trans OTFSSR, adv. clause vivifier, etc.\n"); + printf(" --nootfsubsume Don't do on-the-fly subsumption after conf. gen.\n"); + #ifdef ENABLE_UNWIND_GLUE + printf(" --maxgluedel Automatically delete clauses over max glue. See '--maxglue'\n"); + printf(" --maxglue = [0 - 2^%d-1] default: %d. Glue value above which we\n", MAX_GLUE_BITS, conf.maxGlue); + #endif //ENABLE_UNWIND_GLUE + printf(" throw the clause away on backtrack.\n"); + printf(" --threads = Num threads (default is 1)\n"); + printf(" --plain Get rid of all simplification algorithms\n"); + printf(" --maxconfl = [0..2^63-1] Maximum number of conflicts to do\n"); + printf("\n"); +} + + +const char* Main::hasPrefix(const char* str, const char* prefix) +{ + int len = strlen(prefix); + if (strncmp(str, prefix, len) == 0) + return str + len; + else + return NULL; +} + +void Main::printResultFunc(const Solver& S, const lbool ret, FILE* res) +{ + if (res != NULL) { + if (ret == l_True) { + std::cout << "c SAT" << std::endl; + fprintf(res, "SAT\n"); + if (printResult) { + for (Var var = 0; var != S.nVars(); var++) + if (S.model[var] != l_Undef) + fprintf(res, "%s%d ", (S.model[var] == l_True)? "" : "-", var+1); + fprintf(res, "0\n"); + } + } else if (ret == l_False) { + std::cout << "c UNSAT" << std::endl; + fprintf(res, "UNSAT\n"); + } else { + std::cout << "c INCONCLUSIVE" << std::endl; + fprintf(res, "INCONCLUSIVE\n"); + } + fclose(res); + } else { + if (ret == l_True) { + if (!printResult) std::cout << "c SATISFIABLE" << std::endl; + else std::cout << "s SATISFIABLE" << std::endl; + } else if (ret == l_False) { + if (!printResult) std::cout << "c UNSATISFIABLE" << std::endl; + else std::cout << "s UNSATISFIABLE" << std::endl; + } + + if(ret == l_True && printResult) { + std::stringstream toPrint; + toPrint << "v "; + for (Var var = 0; var != S.nVars(); var++) + if (S.model[var] != l_Undef) + toPrint << ((S.model[var] == l_True)? "" : "-") << var+1 << " "; + toPrint << "0" << std::endl; + std::cout << toPrint.str(); + } + } +} + +void Main::parseCommandLine() +{ + const char* value; + char tmpFilename[201]; + tmpFilename[0] = '\0'; + uint32_t unparsedOptions = 0; + bool needTwoFileNames = false; + conf.verbosity = 2; + + for (int i = 0; i < argc; i++) { + if ((value = hasPrefix(argv[i], "--polarity-mode="))) { + if (strcmp(value, "true") == 0) + conf.polarity_mode = polarity_true; + else if (strcmp(value, "false") == 0) + conf.polarity_mode = polarity_false; + else if (strcmp(value, "rnd") == 0) + conf.polarity_mode = polarity_rnd; + else if (strcmp(value, "auto") == 0) + conf.polarity_mode = polarity_auto; + else { + printf("ERROR! unknown polarity-mode %s\n", value); + exit(0); + } + + } else if ((value = hasPrefix(argv[i], "--rnd-freq="))) { + double rnd; + if (sscanf(value, "%lf", &rnd) <= 0 || rnd < 0 || rnd > 1) { + printf("ERROR! illegal rnRSE ERROR!d-freq constant %s\n", value); + exit(0); + } + conf.random_var_freq = rnd; + + /*} else if ((value = hasPrefix(argv[i], "--decay="))) { + double decay; + if (sscanf(value, "%lf", &decay) <= 0 || decay <= 0 || decay > 1) { + printf("ERROR! illegal decay constant %s\n", value); + exit(0); + } + conf.var_decay = 1 / decay;*/ + + } else if ((value = hasPrefix(argv[i], "--verbosity="))) { + int verbosity = (int)strtol(value, NULL, 10); + if (verbosity == EINVAL || verbosity == ERANGE) { + printf("ERROR! illegal verbosity level %s\n", value); + exit(0); + } + conf.verbosity = verbosity; + } else if ((value = hasPrefix(argv[i], "--randomize="))) { + int seed; + if (sscanf(value, "%d", &seed) < 0) { + printf("ERROR! illegal seed %s\n", value); + exit(0); + } + conf.origSeed = seed; + } else if ((value = hasPrefix(argv[i], "--restrict="))) { + int branchTo; + if (sscanf(value, "%d", &branchTo) < 0 || branchTo < 1) { + printf("ERROR! illegal restricted pick branch number %d\n", branchTo); + exit(0); + } + conf.restrictPickBranch = branchTo; + } else if ((value = hasPrefix(argv[i], "--gaussuntil="))) { + int until; + if (sscanf(value, "%d", &until) < 0) { + printf("ERROR! until %s\n", value); + exit(0); + } + gaussconfig.decision_until = until; + } else if ((value = hasPrefix(argv[i], "--restarts="))) { + int maxrest; + if (sscanf(value, "%d", &maxrest) < 0 || maxrest == 0) { + printf("ERROR! illegal maximum restart number %d\n", maxrest); + exit(0); + } + conf.maxRestarts = maxrest; + } else if ((value = hasPrefix(argv[i], "--dumplearnts="))) { + if (sscanf(value, "%200s", tmpFilename) < 0 || strlen(tmpFilename) == 0) { + printf("ERROR! wrong filename '%s'\n", tmpFilename); + exit(0); + } + conf.learntsFilename.assign(tmpFilename); + conf.needToDumpLearnts = true; + } else if ((value = hasPrefix(argv[i], "--dumporig="))) { + if (sscanf(value, "%200s", tmpFilename) < 0 || strlen(tmpFilename) == 0) { + printf("ERROR! wrong filename '%s'\n", tmpFilename); + exit(0); + } + conf.origFilename.assign(tmpFilename); + conf.needToDumpOrig = true; + } else if ((value = hasPrefix(argv[i], "--alsoread="))) { + if (sscanf(value, "%400s", tmpFilename) < 0 || strlen(tmpFilename) == 0) { + printf("ERROR! wrong filename '%s'\n", tmpFilename); + exit(0); + } + filesToRead.push_back(tmpFilename); + } else if ((value = hasPrefix(argv[i], "--maxdumplearnts="))) { + if (!conf.needToDumpLearnts) { + printf("ERROR! -dumplearnts=<filename> must be first activated before issuing -maxdumplearnts=<size>\n"); + exit(0); + } + int tmp; + if (sscanf(value, "%d", &tmp) < 0 || tmp < 0) { + std::cout << "ERROR! wrong maximum dumped learnt clause size is illegal: " << tmp << std::endl; + exit(0); + } + conf.maxDumpLearntsSize = (uint32_t)tmp; + } else if ((value = hasPrefix(argv[i], "--maxsolutions="))) { + int tmp; + if (sscanf(value, "%d", &tmp) < 0 || tmp < 0) { + std::cout << "ERROR! wrong maximum number of solutions is illegal: " << tmp << std::endl; + exit(0); + } + max_nr_of_solutions = (uint32_t)tmp; + + } else if ((value = hasPrefix(argv[i], "--pavgbranch"))) { + conf.doPrintAvgBranch = true; + } else if ((value = hasPrefix(argv[i], "--greedyunbound"))) { + conf.greedyUnbound = true; + } else if ((value = hasPrefix(argv[i], "--nonormxorfind"))) { + conf.doFindXors = false; + } else if ((value = hasPrefix(argv[i], "--nobinxorfind"))) { + conf.doFindEqLits = false; + } else if ((value = hasPrefix(argv[i], "--noregbxorfind"))) { + conf.doRegFindEqLits = false; + } else if ((value = hasPrefix(argv[i], "--doextendedscc"))) { + conf.doExtendedSCC = true; + } else if ((value = hasPrefix(argv[i], "--noconglomerate"))) { + conf.doConglXors = false; + } else if ((value = hasPrefix(argv[i], "--nosimplify"))) { + conf.doSchedSimp = false; + } else if ((value = hasPrefix(argv[i], "--debuglib"))) { + debugLib = true; + } else if ((value = hasPrefix(argv[i], "--debugnewvar"))) { + debugNewVar = true; + } else if ((value = hasPrefix(argv[i], "--novarreplace"))) { + conf.doReplace = false; + } else if ((value = hasPrefix(argv[i], "--nofailedlit"))) { + conf.doFailedLit = false; + } else if ((value = hasPrefix(argv[i], "--nodisablegauss"))) { + gaussconfig.dontDisable = true; + } else if ((value = hasPrefix(argv[i], "--maxnummatrixes="))) { + int maxNumMatrixes; + if (sscanf(value, "%d", &maxNumMatrixes) < 0) { + printf("ERROR! maxnummatrixes: %s\n", value); + exit(0); + } + gaussconfig.maxNumMatrixes = maxNumMatrixes; + } else if ((value = hasPrefix(argv[i], "--noheuleprocess"))) { + conf.doHeuleProcess = false; + } else if ((value = hasPrefix(argv[i], "--nosatelite"))) { + conf.doSatELite = false; + } else if ((value = hasPrefix(argv[i], "--noxorsubs"))) { + conf.doXorSubsumption = false; + } else if ((value = hasPrefix(argv[i], "--nohyperbinres"))) { + conf.doHyperBinRes = false; + } else if ((value = hasPrefix(argv[i], "--novarelim"))) { + conf.doVarElim = false; + } else if ((value = hasPrefix(argv[i], "--nosubsume1"))) { + conf.doSubsume1 = false; + } else if ((value = hasPrefix(argv[i], "--nomatrixfind"))) { + gaussconfig.noMatrixFind = true; + } else if ((value = hasPrefix(argv[i], "--noiterreduce"))) { + gaussconfig.iterativeReduce = false; + } else if ((value = hasPrefix(argv[i], "--noordercol"))) { + gaussconfig.orderCols = false; + } else if ((value = hasPrefix(argv[i], "--maxmatrixrows="))) { + int rows; + if (sscanf(value, "%d", &rows) < 0 || rows < 0) { + printf("ERROR! maxmatrixrows: %s\n", value); + exit(0); + } + gaussconfig.maxMatrixRows = (uint32_t)rows; + } else if ((value = hasPrefix(argv[i], "--minmatrixrows="))) { + int rows; + if (sscanf(value, "%d", &rows) < 0 || rows < 0) { + printf("ERROR! minmatrixrows: %s\n", value); + exit(0); + } + gaussconfig.minMatrixRows = rows; + } else if ((value = hasPrefix(argv[i], "--savematrix"))) { + int every; + if (sscanf(value, "%d", &every) < 0) { + printf("ERROR! savematrix: %s\n", value); + exit(0); + } + gaussconfig.only_nth_gauss_save = every; + } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "--help") == 0) { + printUsage(argv); + exit(0); + } else if ((value = hasPrefix(argv[i], "--restart="))) { + if (strcmp(value, "auto") == 0) + conf.fixRestartType = auto_restart; + else if (strcmp(value, "static") == 0) + conf.fixRestartType = static_restart; + else if (strcmp(value, "dynamic") == 0) + conf.fixRestartType = dynamic_restart; + else { + printf("ERROR! unknown restart type %s\n", value); + exit(0); + } + } else if ((value = hasPrefix(argv[i], "--nosolprint"))) { + printResult = false; + //} else if ((value = hasPrefix(argv[i], "--addoldlearnts"))) { + // conf.readdOldLearnts = true; + } else if ((value = hasPrefix(argv[i], "--nohyperbinres"))) { + conf.doHyperBinRes= false; + } else if ((value = hasPrefix(argv[i], "--noremovebins"))) { + conf.doRemUselessBins = false; + } else if ((value = hasPrefix(argv[i], "--nosubswithnbins"))) { + conf.doSubsWNonExistBins = false; + } else if ((value = hasPrefix(argv[i], "--nosubswithbins"))) { + conf.doSubsWBins = false; + } else if ((value = hasPrefix(argv[i], "--noclausevivif"))) { + conf.doClausVivif = false; + } else if ((value = hasPrefix(argv[i], "--nosortwatched"))) { + conf.doSortWatched = false; + } else if ((value = hasPrefix(argv[i], "--nolfminim"))) { + conf.doMinimLearntMore = false; + } else if ((value = hasPrefix(argv[i], "--nocalcreach"))) { + conf.doCalcReach = false; + } else if ((value = hasPrefix(argv[i], "--norecotfssr"))) { + conf.doMinimLMoreRecur = false; + } else if ((value = hasPrefix(argv[i], "--nocacheotfssr"))) { + conf.doCacheOTFSSRSet = false; + conf.doCacheOTFSSR = false; + } else if ((value = hasPrefix(argv[i], "--nootfsubsume"))) { + conf.doOTFSubsume = false; + } else if ((value = hasPrefix(argv[i], "--noremlbins"))) { + conf.doRemUselessLBins = false; + } else if ((value = hasPrefix(argv[i], "--maxconfl="))) { + int maxconfl = 0; + if (sscanf(value, "%d", &maxconfl) < 0 || maxconfl < 2) { + printf("ERROR! max confl: %s\n", value); + exit(0); + } + conf.maxConfl = maxconfl; + } else if ((value = hasPrefix(argv[i], "--plain"))) { + conf.isPlain = true; + conf.doOTFSubsume = false; + conf.doFindXors = false; + conf.doFindEqLits = false; + conf.doRegFindEqLits = false; + conf.doExtendedSCC = false; + conf.doConglXors = false; + conf.doSchedSimp = false; + conf.doReplace = false; + conf.doFailedLit = false; + conf.doHeuleProcess = false; + conf.doSatELite = false; + conf.doXorSubsumption = false; + printResult = false; + conf.doVarElim = false; + //nomatrixfind + gaussconfig.orderCols = false; + gaussconfig.iterativeReduce = false; + conf.doHyperBinRes = false; + conf.doRemUselessBins = false; + conf.doRemUselessLBins = false; + conf.doSubsWBins = false; + conf.doSubsWNonExistBins = false; + conf.doClausVivif = false; + conf.doCalcReach = false; + conf.doBXor = false; + conf.doMinimLMoreRecur = false; + conf.doMinimLearntMore = false; + conf.doCacheOTFSSR = false; + } else if ((value = hasPrefix(argv[i], "--nobxor"))) { + conf.doBXor = false; + #ifdef ENABLE_UNWIND_GLUE + } else if ((value = hasPrefix(argv[i], "--maxglue="))) { + int glue = 0; + if (sscanf(value, "%d", &glue) < 0 || glue < 2) { + printf("ERROR! maxGlue: %s\n", value); + exit(0); + } + if (glue >= (1<< MAX_GLUE_BITS)-1) { + std::cout << "Due to memory-packing limitations, max glue cannot be more than " + << ((1<< MAX_GLUE_BITS)-2) << std::endl; + exit(-1); + } + conf.maxGlue = (uint32_t)glue; + } else if ((value = hasPrefix(argv[i], "--maxgluedel"))) { + conf.doMaxGlueDel = true; + #endif //ENABLE_UNWIND_GLUE + } else if ((value = hasPrefix(argv[i], "--threads="))) { + numThreads = 0; + if (sscanf(value, "%d", &numThreads) < 0 || numThreads < 1) { + printf("ERROR! numThreads: %s\n", value); + exit(0); + } + } else if (strncmp(argv[i], "-", 1) == 0 || strncmp(argv[i], "--", 2) == 0) { + printf("ERROR! unknown flag %s\n", argv[i]); + exit(0); + } else { + //std::std::cout << "argc:" << argc << " i:" << i << ", value:" << argv[i] << std::endl; + unparsedOptions++; + if (unparsedOptions == 2) { + if (!(argc <= i+2)) { + std::cout << "You must give the input file as either:" << std::endl; + std::cout << " -- last option if you want the output to the console" << std::endl; + std::cout << " -- or one before the last option" << std::endl; + std::cout << "It appears that you did neither. Maybe you forgot the '--' from an option?" << std::endl; + exit(-1); + } + fileNamePresent = true; + if (argc == i+2) needTwoFileNames = true; + } + if (unparsedOptions == 3) { + if (!(argc <= i+1)) { + std::cout << "You must give the output file as the last option. Exiting" << std::endl; + exit(-1); + } + twoFileNamesPresent = true; + } + if (unparsedOptions == 4) { + std::cout << "You gave more than two filenames as parameters." << std::endl; + std::cout << "The first one is interpreted as the input, the second is the output." << std::endl; + std::cout << "However, the third one I cannot do anything with. EXITING" << std::endl; + exit(-1); + } + } + } + if (conf.verbosity >= 1) { + if (twoFileNamesPresent) { + std::cout << "c Outputting solution to file: " << argv[argc-1] << std::endl; + } else { + std::cout << "c Outputting solution to console" << std::endl; + } + } + + if (unparsedOptions == 2 && needTwoFileNames == true) { + std::cout << "Command line wrong. You probably frogot to add "<< std::endl + << "the '--' in front of one of the options, or you started" << std::endl + << "your output file with a hyphen ('-'). Exiting." << std::endl; + exit(-1); + } + if (!debugLib) conf.libraryUsage = false; +} + +FILE* Main::openOutputFile() +{ + FILE* res = NULL; + if (twoFileNamesPresent) { + char* filename = argv[argc-1]; + res = fopen(filename, "wb"); + if (res == NULL) { + int backup_errno = errno; + printf("Cannot open %s for writing. Problem: %s", filename, strerror(backup_errno)); + exit(1); + } + } + + return res; +} + +void Main::setDoublePrecision(const uint32_t verbosity) +{ +#if defined(_FPU_EXTENDED) && defined(_FPU_DOUBLE) + fpu_control_t oldcw, newcw; + _FPU_GETCW(oldcw); + newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; + _FPU_SETCW(newcw); + #pragma omp single + if (verbosity >= 1) { + printf("c WARNING: for repeatability, setting FPU to use double precision\n"); + } +#endif +} + +void Main::printVersionInfo(const uint32_t verbosity) +{ +#pragma omp single + if (verbosity >= 1) { + printf("c This is CryptoMiniSat %s\n", VERSION); + #ifdef __GNUC__ + printf("c compiled with gcc version %s\n", __VERSION__); + #else + printf("c compiled with non-gcc compiler\n"); + #endif + } +} + +int Main::singleThreadSolve() +{ + Solver solver(conf, gaussconfig); + solversToInterrupt[0] = &solver; + + printVersionInfo(conf.verbosity); + setDoublePrecision(conf.verbosity); + + parseInAllFiles(solver); + FILE* res = openOutputFile(); + + unsigned long current_nr_of_solutions = 0; + lbool ret = l_True; + while(current_nr_of_solutions < max_nr_of_solutions && ret == l_True) { + ret = solver.solve(); + current_nr_of_solutions++; + + if (ret == l_True && current_nr_of_solutions < max_nr_of_solutions) { + if (conf.verbosity >= 1) std::cout << "c Prepare for next run..." << std::endl; + printResultFunc(solver, ret, res); + + vec<Lit> lits; + for (Var var = 0; var != solver.nVars(); var++) { + if (solver.model[var] != l_Undef) { + lits.push( Lit(var, (solver.model[var] == l_True)? true : false) ); + } + } + solver.addClause(lits); + } + } + + if (conf.needToDumpLearnts) { + if (solver.dumpSortedLearnts(conf.learntsFilename, conf.maxDumpLearntsSize)) + std::cout << "c Sorted learnt clauses dumped to file '" << conf.learntsFilename << "'" << std::endl; + else { + std::cout << "Error: Cannot open file '" << conf.learntsFilename << "' to write learnt clauses!" << std::endl;; + exit(-1); + } + } + if (conf.needToDumpOrig) { + if (ret == l_False && conf.origFilename == "stdout") { + std::cout << "p cnf 0 1" << std::endl; + std::cout << "0"; + } else if (ret == l_True && conf.origFilename == "stdout") { + std::cout << "p cnf " << solver.model.size() << " " << solver.model.size() << std::endl; + for (uint32_t i = 0; i < solver.model.size(); i++) { + std::cout << (solver.model[i] == l_True ? "" : "-") << i+1 << " 0" << std::endl; + } + } else { + if (!solver.dumpOrigClauses(conf.origFilename)) { + std::cout << "Error: Cannot open file '" << conf.origFilename << "' to write learnt clauses!" << std::endl; + exit(-1); + } + if (conf.verbosity >= 1) + std::cout << "c Simplified original clauses dumped to file '" + << conf.origFilename << "'" << std::endl; + } + } + if (ret == l_Undef && conf.verbosity >= 1) { + std::cout << "c Not finished running -- signal caught or maximum restart reached" << std::endl; + } + if (conf.verbosity >= 1) solver.printStats(); + + printResultFunc(solver, ret, res); + + return correctReturnValue(ret); +} + +int Main::correctReturnValue(const lbool ret) const +{ + int retval = -1; + if (ret == l_True) retval = 10; + else if (ret == l_False) retval = 20; + else if (ret == l_Undef) retval = 15; + else { + std::cerr << "Something is very wrong, output is neither l_Undef, nor l_False, nor l_True" << std::endl; + exit(-1); + } + + #ifdef NDEBUG + // (faster than "return", which will invoke the destructor for 'Solver') + exit(retval); + #endif + return retval; +} + +int Main::oneThreadSolve() +{ + int numThreads = omp_get_num_threads(); + SolverConf myConf = conf; + int num = omp_get_thread_num(); + myConf.origSeed = num; + if (num > 0) { + if (num % 4 == 3) myConf.fixRestartType = dynamic_restart; + if (num % 4 == 2) myConf.doCalcReach = false; + //else myConf.fixRestartType = static_restart; + myConf.simpBurstSConf *= 1 + num; + myConf.simpStartMult *= 1.0 + 0.2*(double)num; + myConf.simpStartMMult *= 1.0 + 0.2*(double)num; + if (num == numThreads-1) { + //myConf.doVarElim = false; + myConf.doPerformPreSimp = false; + myConf.polarity_mode = polarity_false; + } + } + if (num != 0) myConf.verbosity = 0; + + Solver solver(myConf, gaussconfig, &sharedData); + #pragma omp critical (solversToInterr) + { + solversToInterrupt[num] = &solver; + //std::cout << "Solver num " << num << " is to be interrupted " << std::endl; + } + + printVersionInfo(myConf.verbosity); + setDoublePrecision(myConf.verbosity); + + parseInAllFiles(solver); + lbool ret = solver.solve(); + #pragma omp critical (finished) + { + finished.insert(num); + } + + int retval = 0; + #pragma omp single + { + int numNeededInterrupt = 0; + while(numNeededInterrupt != numThreads-1) { + #pragma omp critical (solversToInterr) + { + for(int i = 0; i < numThreads; i++) { + if (i != num + && solversToInterrupt.find(i) != solversToInterrupt.end() + && solversToInterrupt[i]->needToInterrupt == false + ) { + solversToInterrupt[i]->needToInterrupt = true; + numNeededInterrupt++; + } + } + } + } + bool mustWait = true; + while (mustWait) { + #pragma omp critical (finished) + if (finished.size() == (unsigned)numThreads) mustWait = false; + } + if (conf.needToDumpLearnts) { + if (!solver.dumpSortedLearnts(conf.learntsFilename, conf.maxDumpLearntsSize)) { + std::cout << "Error: Cannot open file '" << conf.learntsFilename << "' to write learnt clauses!" << std::endl;; + exit(-1); + } + if (conf.verbosity >= 1) { + std::cout << "c Sorted learnt clauses dumped to file '" + << conf.learntsFilename << "'" << std::endl; + } + } + if (conf.needToDumpOrig) { + if (!solver.dumpOrigClauses(conf.origFilename)) { + std::cout << "Error: Cannot open file '" << conf.origFilename << "' to write learnt clauses!" << std::endl; + exit(-1); + } + if (conf.verbosity >= 1) + std::cout << "c Simplified original clauses dumped to file '" + << conf.origFilename << "'" << std::endl; + } + + FILE* res = openOutputFile(); + if (conf.verbosity >= 1) solver.printStats(); + printResultFunc(solver, ret, res); + + retval = correctReturnValue(ret); + exit(retval); + } + return retval; +} + +int Main::multiThreadSolve() +{ + bool exitHere = false; + if (max_nr_of_solutions > 1) { + std::cerr << "ERROR: When multi-threading, only one solution can be found" << std::endl; + exitHere = true; + } + if (debugLib) { + std::cerr << "ERROR: When multi-threading, --debuglib cannot be used" << std::endl; + exitHere = true; + } + if (exitHere) { + std::cerr << "libarary in this version of CryptoMS is not multi-threaded :(" << std::endl; + std::cerr << "Please set option '--threads=1' on the command line." << std::endl; + exit(-1); + } + + int finalRetVal; + if (numThreads != -1) { + assert(numThreads > 0); + omp_set_num_threads(numThreads); + } + #pragma omp parallel + { + #pragma omp single + { + if (conf.verbosity >= 1) + std::cout << "c Using " << omp_get_num_threads() + << " threads" << std::endl; + } + int retval = oneThreadSolve(); + + #pragma omp single + finalRetVal = retval; + } + + return finalRetVal; +} + +/** +@brief For correctly and gracefully exiting + +It can happen that the user requests a dump of the learnt clauses. In this case, +the program must wait until it gets to a state where the learnt clauses are in +a correct state, then dump these and quit normally. This interrupt hander +is used to achieve this +*/ +void SIGINT_handler(int) +{ + #pragma omp critical + { + Solver& solver = *solversToInterrupt.begin()->second; + printf("\n"); + std::cerr << "*** INTERRUPTED ***" << std::endl; + if (solver.conf.needToDumpLearnts || solver.conf.needToDumpOrig) { + solver.needToInterrupt = true; + std::cerr << "*** Please wait. We need to interrupt cleanly" << std::endl; + std::cerr << "*** This means we might need to finish some calculations" << std::endl; + } else { + if (solver.conf.verbosity >= 1) solver.printStats(); + exit(1); + } + } +} + +int main(int argc, char** argv) +{ + Main main(argc, argv); + main.parseCommandLine(); + signal(SIGINT, SIGINT_handler); + //signal(SIGHUP,SIGINT_handler); + + try { + if (main.numThreads == 1) + return main.singleThreadSolve(); + else + return main.multiThreadSolve(); + } catch (std::bad_alloc) { + std::cerr << "Memory manager cannot handle the load. Sorry. Exiting." << std::endl; + exit(-1); + } catch (std::out_of_range oor) { + std::cerr << oor.what() << std::endl; + exit(-1); + } catch (CMSat::DimacsParseError dpe) { + std::cerr << "PARSE ERROR!" << dpe.what() << std::endl; + exit(3); + } + return 0; +} diff --git a/src/prop/cryptominisat/Solver/Main.h b/src/prop/cryptominisat/Solver/Main.h new file mode 100644 index 000000000..a2af6dc34 --- /dev/null +++ b/src/prop/cryptominisat/Solver/Main.h @@ -0,0 +1,74 @@ +/***************************************************************************** +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +Original code by MiniSat authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3 licence. +******************************************************************************/ + +#ifndef MAIN_H +#define MAIN_H + +#include <string> +#include <vector> +#ifndef DISABLE_ZLIB +#include <zlib.h> +#endif // DISABLE_ZLIB + +#include "Solver.h" +#include "SharedData.h" + +namespace CMSat { + +using std::string; + +class Main +{ + public: + Main(int argc, char** argv); + + void parseCommandLine(); + + int singleThreadSolve(); + int oneThreadSolve(); + int multiThreadSolve(); + + int numThreads; + + private: + + void printUsage(char** argv); + const char* hasPrefix(const char* str, const char* prefix); + void printResultFunc(const Solver& S, const lbool ret, FILE* res); + + //File reading + void readInAFile(const std::string& filename, Solver& solver); + void readInStandardInput(Solver& solver); + void parseInAllFiles(Solver& solver); + FILE* openOutputFile(); + + void setDoublePrecision(const uint32_t verbosity); + void printVersionInfo(const uint32_t verbosity); + int correctReturnValue(const lbool ret) const; + + SolverConf conf; + GaussConf gaussconfig; + + bool grouping; + bool debugLib; + bool debugNewVar; + bool printResult; + uint32_t max_nr_of_solutions; + bool fileNamePresent; + bool twoFileNamesPresent; + std::vector<std::string> filesToRead; + + SharedData sharedData; + + int argc; + char** argv; +}; + +} + +#endif //MAIN_H diff --git a/src/prop/cryptominisat/Solver/Makefile.am b/src/prop/cryptominisat/Solver/Makefile.am new file mode 100644 index 000000000..72a0d2fab --- /dev/null +++ b/src/prop/cryptominisat/Solver/Makefile.am @@ -0,0 +1,33 @@ +#noinst_LTLIBRARIES = libcryptominisat.la +lib_LTLIBRARIES = libcryptominisat.la + +libcryptominisat_la_LDFLAGS = -release 2.9.2 -no-undefined + +AM_CXXFLAGS = -Wall $(all_includes) -I$(srcdir) -I$(srcdir)/../MTRand -I$(srcdir)/../mtl $(OPENMP_CXXFLAGS) + +pkgincludesubdir = $(includedir)/cryptominisat/Solver +pkgincludesub_HEADERS = BitArray.h Clause.h CSet.h MatrixFinder.h Solver.h Subsumer.h Watched.h \ + BoundedQueue.h ClauseOffset.h DimacsParser.h GaussianConfig.h OnlyNonLearntBins.h SolverTypes.h \ + time_mem.h XorFinder.h ClauseAllocator.h CompleteDetachReattacher.h DoublePackedRow.h Gaussian.h PackedMatrix.h \ + PropBy.h StateSaver.h UselessBinRemover.h XorSubsumer.h ClauseCleaner.h constants.h FailedLitSearcher.h \ + PackedRow.h RestartTypeChooser.h StreamBuffer.h VarReplacer.h XSet.h BothCache.h SolverConf.h \ + SCCFinder.h SharedData.h ClauseVivifier.h DataSync.h Main.h \ + msvc/stdint.h + +libcryptominisat_la_SOURCES = \ + ClauseCleaner.cpp FailedLitSearcher.cpp \ + VarReplacer.cpp \ + MatrixFinder.cpp \ + Solver.cpp XorFinder.cpp \ + PackedRow.cpp Gaussian.cpp StateSaver.cpp \ + RestartTypeChooser.cpp Subsumer.cpp XorSubsumer.cpp \ + SolverMisc.cpp SolverDebug.cpp ClauseAllocator.cpp \ + UselessBinRemover.cpp SCCFinder.cpp ClauseVivifier.cpp \ + CompleteDetachReattacher.cpp DimacsParser.cpp \ + OnlyNonLearntBins.cpp SolverConf.cpp DataSync.cpp \ + BothCache.cpp + +bin_PROGRAMS = cryptominisat +cryptominisat_LDADD = libcryptominisat.la +cryptominisat_LDFLAGS = -static -lz $(OPENMP_CXXFLAGS) +cryptominisat_SOURCES = Main.cpp diff --git a/src/prop/cryptominisat/Solver/Makefile.in b/src/prop/cryptominisat/Solver/Makefile.in new file mode 100644 index 000000000..dd524fba2 --- /dev/null +++ b/src/prop/cryptominisat/Solver/Makefile.in @@ -0,0 +1,665 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = cryptominisat$(EXEEXT) +subdir = Solver +DIST_COMMON = $(pkgincludesub_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(pkgincludesubdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libcryptominisat_la_LIBADD = +am_libcryptominisat_la_OBJECTS = ClauseCleaner.lo FailedLitSearcher.lo \ + VarReplacer.lo MatrixFinder.lo Solver.lo XorFinder.lo \ + PackedRow.lo Gaussian.lo StateSaver.lo RestartTypeChooser.lo \ + Subsumer.lo XorSubsumer.lo SolverMisc.lo SolverDebug.lo \ + ClauseAllocator.lo UselessBinRemover.lo SCCFinder.lo \ + ClauseVivifier.lo CompleteDetachReattacher.lo DimacsParser.lo \ + OnlyNonLearntBins.lo SolverConf.lo DataSync.lo BothCache.lo +libcryptominisat_la_OBJECTS = $(am_libcryptominisat_la_OBJECTS) +libcryptominisat_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(libcryptominisat_la_LDFLAGS) $(LDFLAGS) -o $@ +PROGRAMS = $(bin_PROGRAMS) +am_cryptominisat_OBJECTS = Main.$(OBJEXT) +cryptominisat_OBJECTS = $(am_cryptominisat_OBJECTS) +cryptominisat_DEPENDENCIES = libcryptominisat.la +cryptominisat_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(cryptominisat_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libcryptominisat_la_SOURCES) $(cryptominisat_SOURCES) +DIST_SOURCES = $(libcryptominisat_la_SOURCES) $(cryptominisat_SOURCES) +HEADERS = $(pkgincludesub_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENMP_CXXFLAGS = @OPENMP_CXXFLAGS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +#noinst_LTLIBRARIES = libcryptominisat.la +lib_LTLIBRARIES = libcryptominisat.la +libcryptominisat_la_LDFLAGS = -release 2.9.2 -no-undefined +AM_CXXFLAGS = -Wall $(all_includes) -I$(srcdir) -I$(srcdir)/../MTRand -I$(srcdir)/../mtl $(OPENMP_CXXFLAGS) +pkgincludesubdir = $(includedir)/cryptominisat/Solver +pkgincludesub_HEADERS = BitArray.h Clause.h CSet.h MatrixFinder.h Solver.h Subsumer.h Watched.h \ + BoundedQueue.h ClauseOffset.h DimacsParser.h GaussianConfig.h OnlyNonLearntBins.h SolverTypes.h \ + time_mem.h XorFinder.h ClauseAllocator.h CompleteDetachReattacher.h DoublePackedRow.h Gaussian.h PackedMatrix.h \ + PropBy.h StateSaver.h UselessBinRemover.h XorSubsumer.h ClauseCleaner.h constants.h FailedLitSearcher.h \ + PackedRow.h RestartTypeChooser.h StreamBuffer.h VarReplacer.h XSet.h BothCache.h SolverConf.h \ + SCCFinder.h SharedData.h ClauseVivifier.h DataSync.h Main.h \ + msvc/stdint.h + +libcryptominisat_la_SOURCES = \ + ClauseCleaner.cpp FailedLitSearcher.cpp \ + VarReplacer.cpp \ + MatrixFinder.cpp \ + Solver.cpp XorFinder.cpp \ + PackedRow.cpp Gaussian.cpp StateSaver.cpp \ + RestartTypeChooser.cpp Subsumer.cpp XorSubsumer.cpp \ + SolverMisc.cpp SolverDebug.cpp ClauseAllocator.cpp \ + UselessBinRemover.cpp SCCFinder.cpp ClauseVivifier.cpp \ + CompleteDetachReattacher.cpp DimacsParser.cpp \ + OnlyNonLearntBins.cpp SolverConf.cpp DataSync.cpp \ + BothCache.cpp + +cryptominisat_LDADD = libcryptominisat.la +cryptominisat_LDFLAGS = -static -lz $(OPENMP_CXXFLAGS) +cryptominisat_SOURCES = Main.cpp +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Solver/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu Solver/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libcryptominisat.la: $(libcryptominisat_la_OBJECTS) $(libcryptominisat_la_DEPENDENCIES) + $(libcryptominisat_la_LINK) -rpath $(libdir) $(libcryptominisat_la_OBJECTS) $(libcryptominisat_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +cryptominisat$(EXEEXT): $(cryptominisat_OBJECTS) $(cryptominisat_DEPENDENCIES) + @rm -f cryptominisat$(EXEEXT) + $(cryptominisat_LINK) $(cryptominisat_OBJECTS) $(cryptominisat_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BothCache.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClauseAllocator.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClauseCleaner.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClauseVivifier.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CompleteDetachReattacher.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DataSync.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DimacsParser.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FailedLitSearcher.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Gaussian.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MatrixFinder.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OnlyNonLearntBins.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PackedRow.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RestartTypeChooser.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SCCFinder.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Solver.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SolverConf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SolverDebug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SolverMisc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StateSaver.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Subsumer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UselessBinRemover.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VarReplacer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XorFinder.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XorSubsumer.Plo@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgincludesubHEADERS: $(pkgincludesub_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(pkgincludesubdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgincludesubdir)" + @list='$(pkgincludesub_HEADERS)'; test -n "$(pkgincludesubdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludesubdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludesubdir)" || exit $$?; \ + done + +uninstall-pkgincludesubHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkgincludesub_HEADERS)'; test -n "$(pkgincludesubdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgincludesubdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgincludesubdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgincludesubdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgincludesubHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgincludesubHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libLTLIBRARIES clean-libtool ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am \ + install-pkgincludesubHEADERS install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ + uninstall-pkgincludesubHEADERS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/prop/cryptominisat/Solver/MatrixFinder.cpp b/src/prop/cryptominisat/Solver/MatrixFinder.cpp new file mode 100644 index 000000000..4a1522d80 --- /dev/null +++ b/src/prop/cryptominisat/Solver/MatrixFinder.cpp @@ -0,0 +1,248 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#include "MatrixFinder.h" + +#include "Solver.h" +#include "Gaussian.h" +#include "GaussianConfig.h" +#include "ClauseCleaner.h" +#include "time_mem.h" + +#include <set> +#include <map> +#include <iomanip> +#include <math.h> + +//#define VERBOSE_DEBUG +//#define PART_FINDING + +using namespace CMSat; + +using std::set; +using std::map; + +MatrixFinder::MatrixFinder(Solver& _solver) : + solver(_solver) +{ +} + +inline Var MatrixFinder::fingerprint(const XorClause& c) const +{ + Var fingerprint = 0; + + for (const Lit* a = &c[0], *end = a + c.size(); a != end; a++) + fingerprint |= a->var(); + + return fingerprint; +} + +inline bool MatrixFinder::firstPartOfSecond(const XorClause& c1, const XorClause& c2) const +{ + uint32_t i1, i2; + for (i1 = 0, i2 = 0; i1 < c1.size() && i2 < c2.size();) { + if (c1[i1].var() != c2[i2].var()) + i2++; + else { + i1++; + i2++; + } + } + + return (i1 == c1.size()); +} + +bool MatrixFinder::findMatrixes() +{ + assert(solver.decisionLevel() == 0); + assert(solver.ok); + + table.clear(); + table.resize(solver.nVars(), var_Undef); + reverseTable.clear(); + matrix_no = 0; + double myTime = cpuTime(); + + if (solver.xorclauses.size() < MIN_GAUSS_XOR_CLAUSES || + solver.gaussconfig.decision_until <= 0 || + solver.xorclauses.size() > MAX_GAUSS_XOR_CLAUSES + ) { + return true; + } + + solver.clauseCleaner->cleanClauses(solver.xorclauses, ClauseCleaner::xorclauses); + if (!solver.ok) return false; + + if (solver.gaussconfig.noMatrixFind) { + if (solver.conf.verbosity >=1) + std::cout << "c Matrix finding disabled through switch. Putting all xors into matrix." << std::endl; + vector<XorClause*> xorclauses; + xorclauses.reserve(solver.xorclauses.size()); + for (uint32_t i = 0; i < solver.xorclauses.size(); i++) + xorclauses.push_back(solver.xorclauses[i]); + solver.gauss_matrixes.push_back(new Gaussian(solver, solver.gaussconfig, 0, xorclauses)); + return true; + } + + for (XorClause** c = solver.xorclauses.getData(), **end = c + solver.xorclauses.size(); c != end; c++) { + set<uint32_t> tomerge; + vector<Var> newSet; + for (Lit *l = &(**c)[0], *end2 = l + (**c).size(); l != end2; l++) { + if (table[l->var()] != var_Undef) + tomerge.insert(table[l->var()]); + else + newSet.push_back(l->var()); + } + if (tomerge.size() == 1) { + const uint32_t into = *tomerge.begin(); + map<uint32_t, vector<Var> >::iterator intoReverse = reverseTable.find(into); + for (uint32_t i = 0; i < newSet.size(); i++) { + intoReverse->second.push_back(newSet[i]); + table[newSet[i]] = into; + } + continue; + } + + for (set<uint32_t>::iterator it = tomerge.begin(); it != tomerge.end(); it++) { + newSet.insert(newSet.end(), reverseTable[*it].begin(), reverseTable[*it].end()); + reverseTable.erase(*it); + } + for (uint32_t i = 0; i < newSet.size(); i++) + table[newSet[i]] = matrix_no; + reverseTable[matrix_no] = newSet; + matrix_no++; + } + + #ifdef VERBOSE_DEBUG + for (map<uint32_t, vector<Var> >::iterator it = reverseTable.begin(), end = reverseTable.end(); it != end; it++) { + std::cout << "-- set begin --" << std::endl; + for (vector<Var>::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { + std::cout << *it2 << ", "; + } + std::cout << "-------" << std::endl; + } + #endif + + uint32_t numMatrixes = setMatrixes(); + + if (solver.conf.verbosity >=1) + std::cout << "c Finding matrixes : " << cpuTime() - myTime + << " s (found " << numMatrixes << ")" + << std::endl; + + for (vector<Gaussian*>::iterator gauss = solver.gauss_matrixes.begin(), end = solver.gauss_matrixes.end(); gauss != end; gauss++) { + if (!(*gauss)->full_init()) return false; + } + + return true; +} + +uint32_t MatrixFinder::setMatrixes() +{ + vector<pair<uint32_t, uint32_t> > numXorInMatrix; + for (uint32_t i = 0; i < matrix_no; i++) + numXorInMatrix.push_back(std::make_pair(i, 0)); + + vector<uint32_t> sumXorSizeInMatrix(matrix_no, 0); + vector<vector<uint32_t> > xorSizesInMatrix(matrix_no); + vector<vector<XorClause*> > xorsInMatrix(matrix_no); + + #ifdef PART_FINDING + vector<vector<Var> > xorFingerprintInMatrix(matrix_no); + #endif + + for (XorClause** c = solver.xorclauses.getData(), **end = c + solver.xorclauses.size(); c != end; c++) { + XorClause& x = **c; + const uint32_t matrix = table[x[0].var()]; + assert(matrix < matrix_no); + + //for stats + numXorInMatrix[matrix].second++; + sumXorSizeInMatrix[matrix] += x.size(); + xorSizesInMatrix[matrix].push_back(x.size()); + xorsInMatrix[matrix].push_back(&x); + + #ifdef PART_FINDING + xorFingerprintInMatrix[matrix].push_back(fingerprint(x)); + #endif //PART_FINDING + } + + std::sort(numXorInMatrix.begin(), numXorInMatrix.end(), mysorter()); + + #ifdef PART_FINDING + for (uint32_t i = 0; i < matrix_no; i++) + findParts(xorFingerprintInMatrix[i], xorsInMatrix[i]); + #endif //PART_FINDING + + uint32_t realMatrixNum = 0; + for (int a = matrix_no-1; a != -1; a--) { + uint32_t i = numXorInMatrix[a].first; + + if (numXorInMatrix[a].second < 3) + continue; + + const uint32_t totalSize = reverseTable[i].size()*numXorInMatrix[a].second; + const double density = (double)sumXorSizeInMatrix[i]/(double)totalSize*100.0; + double avg = (double)sumXorSizeInMatrix[i]/(double)numXorInMatrix[a].second; + double variance = 0.0; + for (uint32_t i2 = 0; i2 < xorSizesInMatrix[i].size(); i2++) + variance += pow((double)xorSizesInMatrix[i][i2]-avg, 2); + variance /= (double)xorSizesInMatrix.size(); + const double stdDeviation = sqrt(variance); + + if (numXorInMatrix[a].second >= solver.gaussconfig.minMatrixRows + && numXorInMatrix[a].second <= solver.gaussconfig.maxMatrixRows + && realMatrixNum <= solver.gaussconfig.maxNumMatrixes) + { + if (solver.conf.verbosity >=1) + std::cout << "c Matrix no " << std::setw(2) << realMatrixNum; + solver.gauss_matrixes.push_back(new Gaussian(solver, solver.gaussconfig, realMatrixNum, xorsInMatrix[i])); + realMatrixNum++; + + } else { + if (solver.conf.verbosity >=1 /*&& numXorInMatrix[a].second >= 20*/) + std::cout << "c Unused Matrix "; + } + if (solver.conf.verbosity >=1 /*&& numXorInMatrix[a].second >= 20*/) { + std::cout << std::setw(7) << numXorInMatrix[a].second << " x" << std::setw(5) << reverseTable[i].size(); + std::cout << " density:" << std::setw(5) << std::fixed << std::setprecision(1) << density << "%"; + std::cout << " xorlen avg:" << std::setw(5) << std::fixed << std::setprecision(2) << avg; + std::cout << " stdev:" << std::setw(6) << std::fixed << std::setprecision(2) << stdDeviation << std::endl; + } + } + + return realMatrixNum; +} + +void MatrixFinder::findParts(vector<Var>& xorFingerprintInMatrix, vector<XorClause*>& xorsInMatrix) +{ + uint32_t ai = 0; + for (XorClause **a = &xorsInMatrix[0], **end = a + xorsInMatrix.size(); a != end; a++, ai++) { + const Var fingerprint = xorFingerprintInMatrix[ai]; + uint32_t ai2 = 0; + for (XorClause **a2 = &xorsInMatrix[0]; a2 != end; a2++, ai2++) { + if (ai == ai2) continue; + const Var fingerprint2 = xorFingerprintInMatrix[ai2]; + if (((fingerprint & fingerprint2) == fingerprint) && firstPartOfSecond(**a, **a2)) { + std::cout << "First part of second:" << std::endl; + (*a)->plainPrint(); + (*a2)->plainPrint(); + std::cout << "END" << std::endl; + } + } + } +} diff --git a/src/prop/cryptominisat/Solver/MatrixFinder.h b/src/prop/cryptominisat/Solver/MatrixFinder.h new file mode 100644 index 000000000..21210b0f7 --- /dev/null +++ b/src/prop/cryptominisat/Solver/MatrixFinder.h @@ -0,0 +1,70 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#ifndef MATRIXFINDER_H +#define MATRIXFINDER_H + +#include <vector> +#include <map> +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#include "Clause.h" +#include "Solver.h" + +namespace CMSat { + +class Solver; + +using std::map; +using std::vector; +using std::pair; + +class MatrixFinder { + + public: + MatrixFinder(Solver& solver); + bool findMatrixes(); + + private: + uint32_t setMatrixes(); + + struct mysorter + { + bool operator () (const pair<uint32_t, uint32_t>& left, const pair<uint32_t, uint32_t>& right) + { + return left.second < right.second; + } + }; + + void findParts(vector<Var>& xorFingerprintInMatrix, vector<XorClause*>& xorsInMatrix); + inline Var fingerprint(const XorClause& c) const; + inline bool firstPartOfSecond(const XorClause& c1, const XorClause& c2) const; + + map<uint32_t, vector<Var> > reverseTable; //matrix -> vars + vector<Var> table; //var -> matrix + uint32_t matrix_no; + + Solver& solver; +}; + +} + +#endif //MATRIXFINDER_H diff --git a/src/prop/cryptominisat/Solver/OnlyNonLearntBins.cpp b/src/prop/cryptominisat/Solver/OnlyNonLearntBins.cpp new file mode 100644 index 000000000..021178b08 --- /dev/null +++ b/src/prop/cryptominisat/Solver/OnlyNonLearntBins.cpp @@ -0,0 +1,84 @@ +/*********************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +************************************************************************/ + +#include "OnlyNonLearntBins.h" + +#include <iomanip> +#include "Solver.h" +#include "Clause.h" +#include "VarReplacer.h" +#include "ClauseCleaner.h" +#include "time_mem.h" + +using namespace CMSat; + +OnlyNonLearntBins::OnlyNonLearntBins(Solver& _solver) : + solver(_solver) +{} + +/** +@brief Propagate recursively on non-learnt binaries +*/ +bool OnlyNonLearntBins::propagate() +{ + while (solver.qhead < solver.trail.size()) { + Lit p = solver.trail[solver.qhead++]; + vec<WatchedBin> & wbin = binwatches[p.toInt()]; + solver.propagations += wbin.size()/2 + 2; + for(WatchedBin *k = wbin.getData(), *end = wbin.getDataEnd(); k != end; k++) { + lbool val = solver.value(k->impliedLit); + if (val.isUndef()) { + solver.uncheckedEnqueueLight(k->impliedLit); + } else if (val == l_False) { + return false; + } + } + } + + return true; +} + +/** +@brief Fill internal watchlists with non-binary clauses +*/ +bool OnlyNonLearntBins::fill() +{ + uint32_t numBins = 0; + double myTime = cpuTime(); + binwatches.growTo(solver.nVars()*2); + + uint32_t wsLit = 0; + for (const vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + const vec<Watched>& ws = *it; + for (vec<Watched>::const_iterator it2 = ws.getData(), end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary() && !it2->getLearnt()) { + binwatches[wsLit].push(WatchedBin(it2->getOtherLit())); + numBins++; + } + } + } + + if (solver.conf.verbosity >= 3) { + std::cout << "c Time to fill non-learnt binary watchlists:" + << std::fixed << std::setprecision(2) << std::setw(5) + << cpuTime() - myTime << " s" + << " num non-learnt bins: " << std::setw(10) << numBins + << std::endl; + } + + return true; +} diff --git a/src/prop/cryptominisat/Solver/OnlyNonLearntBins.h b/src/prop/cryptominisat/Solver/OnlyNonLearntBins.h new file mode 100644 index 000000000..7092331e6 --- /dev/null +++ b/src/prop/cryptominisat/Solver/OnlyNonLearntBins.h @@ -0,0 +1,72 @@ +/*********************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +************************************************************************/ + +#ifndef ONLYNONLEARNTBINS_H +#define ONLYNONLEARNTBINS_H + +#include "Solver.h" + +namespace CMSat { + +/** +@brief Handles propagation, addition&removal of non-learnt binary clauses + +It takes a snapshot of Solver's non-learnt binary clauses, builds its own +watchlists, and does everything itself.*/ +class OnlyNonLearntBins +{ + public: + OnlyNonLearntBins(Solver& solver); + + /** + @brief For storing a binary clause + */ + class WatchedBin { + public: + WatchedBin(Lit _impliedLit) : impliedLit(_impliedLit) {}; + Lit impliedLit; + }; + + //propagation + bool propagate(); + + //Management of clauses + bool fill(); + + //helper + inline uint32_t getWatchSize(const Lit lit) const; + inline const vec<vec<WatchedBin> >& getBinWatches() const; + + private: + vec<vec<WatchedBin> > binwatches; ///<Internal wathclists for non-learnt binary clauses + + Solver& solver; +}; + +inline uint32_t OnlyNonLearntBins::getWatchSize(const Lit lit) const +{ + return binwatches[lit.toInt()].size(); +} + +inline const vec<vec<OnlyNonLearntBins::WatchedBin> >& OnlyNonLearntBins::getBinWatches() const +{ + return binwatches; +} + +} + +#endif //ONLYNONLEARNTBINS_H diff --git a/src/prop/cryptominisat/Solver/PackedMatrix.h b/src/prop/cryptominisat/Solver/PackedMatrix.h new file mode 100644 index 000000000..2879a4b45 --- /dev/null +++ b/src/prop/cryptominisat/Solver/PackedMatrix.h @@ -0,0 +1,221 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#ifndef PACKEDMATRIX_H +#define PACKEDMATRIX_H + +#include <algorithm> +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#include "PackedRow.h" + +//#define DEBUG_MATRIX + +namespace CMSat { + +class PackedMatrix +{ +public: + PackedMatrix() : + mp(NULL) + , numRows(0) + , numCols(0) + { + } + + PackedMatrix(const PackedMatrix& b) : + numRows(b.numRows) + , numCols(b.numCols) + { + #ifdef DEBUG_MATRIX + assert(b.numRows > 0 && b.numCols > 0); + #endif + + mp = new uint64_t[numRows*2*(numCols+1)]; + memcpy(mp, b.mp, sizeof(uint64_t)*numRows*2*(numCols+1)); + } + + ~PackedMatrix() + { + delete[] mp; + } + + void resize(const uint32_t num_rows, uint32_t num_cols) + { + num_cols = num_cols / 64 + (bool)(num_cols % 64); + if (numRows*2*(numCols+1) < num_rows*2*(num_cols+1)) { + delete[] mp; + mp = new uint64_t[num_rows*2*(num_cols+1)]; + } + numRows = num_rows; + numCols = num_cols; + } + + void resizeNumRows(const uint32_t num_rows) + { + #ifdef DEBUG_MATRIX + assert(num_rows <= numRows); + #endif + + numRows = num_rows; + } + + PackedMatrix& operator=(const PackedMatrix& b) + { + #ifdef DEBUG_MATRIX + //assert(b.numRows > 0 && b.numCols > 0); + #endif + + if (numRows*2*(numCols+1) < b.numRows*2*(b.numCols+1)) { + delete[] mp; + mp = new uint64_t[b.numRows*2*(b.numCols+1)]; + } + + numRows = b.numRows; + numCols = b.numCols; + memcpy(mp, b.mp, sizeof(uint64_t)*numRows*2*(numCols+1)); + + return *this; + } + + inline PackedRow getMatrixAt(const uint32_t i) + { + #ifdef DEBUG_MATRIX + assert(i <= numRows); + #endif + + return PackedRow(numCols, mp+i*2*(numCols+1)); + } + inline PackedRow getVarsetAt(const uint32_t i) + { + #ifdef DEBUG_MATRIX + assert(i <= numRows); + #endif + + return PackedRow(numCols, mp+i*2*(numCols+1)+(numCols+1)); + } + + inline PackedRow getMatrixAt(const uint32_t i) const + { + #ifdef DEBUG_MATRIX + assert(i <= numRows); + #endif + + return PackedRow(numCols, mp+i*2*(numCols+1)); + } + + inline PackedRow getVarsetAt(const uint32_t i) const + { + #ifdef DEBUG_MATRIX + assert(i <= numRows); + #endif + + return PackedRow(numCols, mp+i*2*(numCols+1)+(numCols+1)); + } + + class iterator + { + public: + friend class PackedMatrix; + + PackedRow operator*() + { + return PackedRow(numCols, mp); + } + + iterator& operator++() + { + mp += 2*(numCols+1); + return *this; + } + + iterator operator+(const uint32_t num) const + { + iterator ret(*this); + ret.mp += 2*(numCols+1)*num; + return ret; + } + + uint32_t operator-(const iterator& b) const + { + return (mp - b.mp)/(2*(numCols+1)); + } + + void operator+=(const uint32_t num) + { + mp += 2*(numCols+1)*num; + } + + bool operator!=(const iterator& it) const + { + return mp != it.mp; + } + + bool operator==(const iterator& it) const + { + return mp == it.mp; + } + + private: + iterator(uint64_t* _mp, const uint32_t _numCols) : + mp(_mp) + , numCols(_numCols) + {} + + uint64_t* mp; + const uint32_t numCols; + }; + + inline iterator beginMatrix() + { + return iterator(mp, numCols); + } + + inline iterator endMatrix() + { + return iterator(mp+numRows*2*(numCols+1), numCols); + } + + inline iterator beginVarset() + { + return iterator(mp+(numCols+1), numCols); + } + + inline iterator endVarset() + { + return iterator(mp+(numCols+1)+numRows*2*(numCols+1), numCols); + } + + inline uint32_t getSize() const + { + return numRows; + } + +private: + + uint64_t* mp; + uint32_t numRows; + uint32_t numCols; +}; + +} + +#endif //PACKEDMATRIX_H diff --git a/src/prop/cryptominisat/Solver/PackedRow.cpp b/src/prop/cryptominisat/Solver/PackedRow.cpp new file mode 100644 index 000000000..8fd72dc25 --- /dev/null +++ b/src/prop/cryptominisat/Solver/PackedRow.cpp @@ -0,0 +1,109 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#include "PackedRow.h" + +using namespace CMSat; + +bool PackedRow::operator ==(const PackedRow& b) const +{ + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(size == b.size); + #endif + + return (std::equal(b.mp-1, b.mp+size, mp-1)); +} + +bool PackedRow::operator !=(const PackedRow& b) const +{ + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(size == b.size); + #endif + + return (!std::equal(b.mp-1, b.mp+size, mp-1)); +} + +uint32_t PackedRow::popcnt() const +{ + uint32_t popcnt = 0; + for (uint32_t i = 0; i < size; i++) if (mp[i]) { + uint64_t tmp = mp[i]; + for (uint32_t i2 = 0; i2 < 64; i2++) { + popcnt += (tmp & 1); + tmp >>= 1; + } + } + return popcnt; +} + +uint32_t PackedRow::popcnt(const uint32_t from) const +{ + uint32_t popcnt = 0; + for (uint32_t i = from/64; i != size; i++) if (mp[i]) { + uint64_t tmp = mp[i]; + uint32_t i2; + if (i == from/64) { + i2 = from%64; + tmp >>= i2; + } else + i2 = 0; + for (; i2 < 64; i2++) { + popcnt += (tmp & 1); + tmp >>= 1; + } + } + return popcnt; +} + +bool PackedRow::fill(vec<Lit>& tmp_clause, const vec<lbool>& assigns, const vector<Var>& col_to_var_original) const +{ + bool final = !is_true_internal; + + tmp_clause.clear(); + uint32_t col = 0; + bool wasundef = false; + for (uint32_t i = 0; i < size; i++) for (uint32_t i2 = 0; i2 < 64; i2++) { + if ((mp[i] >> i2) &1) { + const Var& var = col_to_var_original[col]; + assert(var != std::numeric_limits<Var>::max()); + + const lbool val = assigns[var]; + const bool val_bool = val.getBool(); + tmp_clause.push(Lit(var, val_bool)); + final ^= val_bool; + if (val.isUndef()) { + assert(!wasundef); + Lit tmp(tmp_clause[0]); + tmp_clause[0] = tmp_clause.last(); + tmp_clause.last() = tmp; + wasundef = true; + } + } + col++; + } + if (wasundef) { + tmp_clause[0] ^= final; + //assert(ps != ps_first+1); + } else + assert(!final); + + return wasundef; +} diff --git a/src/prop/cryptominisat/Solver/PackedRow.h b/src/prop/cryptominisat/Solver/PackedRow.h new file mode 100644 index 000000000..a9d2d7134 --- /dev/null +++ b/src/prop/cryptominisat/Solver/PackedRow.h @@ -0,0 +1,252 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#ifndef PACKEDROW_H +#define PACKEDROW_H + +//#define DEBUG_ROW + +#include <vector> +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#include "SolverTypes.h" +#include "Vec.h" +#include <string.h> +#include <iostream> +#include <algorithm> +#include <limits> + +namespace CMSat { + +using std::vector; + +class PackedMatrix; + +class PackedRow +{ +public: + bool operator ==(const PackedRow& b) const; + bool operator !=(const PackedRow& b) const; + + PackedRow& operator=(const PackedRow& b) + { + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(size == b.size); + #endif + + memcpy(mp-1, b.mp-1, size+1); + return *this; + } + + PackedRow& operator^=(const PackedRow& b) + { + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(b.size == size); + #endif + + for (uint32_t i = 0; i != size; i++) { + *(mp + i) ^= *(b.mp + i); + } + + is_true_internal ^= b.is_true_internal; + return *this; + } + + void xorBoth(const PackedRow& b) + { + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(b.size == size); + #endif + + for (uint32_t i = 0; i != 2*size+1; i++) { + *(mp + i) ^= *(b.mp + i); + } + + is_true_internal ^= b.is_true_internal; + } + + + uint32_t popcnt() const; + uint32_t popcnt(uint32_t from) const; + + bool popcnt_is_one() const + { + #if __GNUC__ >= 4 + int ret = 0; + for (uint32_t i = 0; i != size; i++) { + ret += __builtin_popcount(mp[i]&0xffffffff); + ret += __builtin_popcount(mp[i]>>32); + if (ret > 1) return false; + } + return ret == 1; + #else + uint32_t popcount = 0; + for (uint32_t i = 0; i != size; i++) { + uint64_t tmp = mp[i]; + while(tmp) { + popcount += tmp & 1; + tmp >>= 1; + } + } + return popcount == 1; + #endif + } + + bool popcnt_is_one(uint32_t from) const + { + from++; + + uint64_t tmp = mp[from/64]; + tmp >>= from%64; + if (tmp) return false; + + for (uint32_t i = from/64+1; i != size; i++) + if (mp[i]) return false; + return true; + } + + inline const uint64_t& is_true() const + { + return is_true_internal; + } + + inline bool isZero() const + { + for (uint32_t i = 0; i != size; i++) { + if (mp[i]) return false; + } + return true; + } + + inline void setZero() + { + memset(mp, 0, sizeof(uint64_t)*size); + } + + inline void clearBit(const uint32_t i) + { + mp[i/64] &= ~((uint64_t)1 << (i%64)); + } + + inline void invert_is_true(const bool b = true) + { + is_true_internal ^= (uint64_t)b; + } + + inline void setBit(const uint32_t i) + { + mp[i/64] |= ((uint64_t)1 << (i%64)); + } + + void swapBoth(PackedRow b) + { + #ifdef DEBUG_ROW + assert(size > 0); + assert(b.size > 0); + assert(b.size == size); + #endif + + uint64_t * __restrict mp1 = mp-1; + uint64_t * __restrict mp2 = b.mp-1; + + uint32_t i = 2*(size+1); + + while(i != 0) { + std::swap(*mp1, *mp2); + mp1++; + mp2++; + i--; + } + } + + inline bool operator[](const uint32_t& i) const + { + #ifdef DEBUG_ROW + assert(size*64 > i); + #endif + + return (mp[i/64] >> (i%64)) & 1; + } + + template<class T> + void set(const T& v, const vector<uint16_t>& var_to_col, const uint32_t matrix_size) + { + assert(size == (matrix_size/64) + ((bool)(matrix_size % 64))); + //mp = new uint64_t[size]; + setZero(); + for (uint32_t i = 0; i != v.size(); i++) { + const uint32_t toset_var = var_to_col[v[i].var()]; + assert(toset_var != std::numeric_limits<uint32_t>::max()); + + setBit(toset_var); + } + + is_true_internal = !v.xorEqualFalse(); + } + + bool fill(vec<Lit>& tmp_clause, const vec<lbool>& assigns, const vector<Var>& col_to_var_original) const; + + inline unsigned long int scan(const unsigned long int var) const + { + #ifdef DEBUG_ROW + assert(size > 0); + #endif + + for(uint32_t i = var; i != size*64; i++) { + if (this->operator[](i)) return i; + } + + return std::numeric_limits<unsigned long int>::max(); + } + +private: + friend class PackedMatrix; + friend std::ostream& operator << (std::ostream& os, const PackedRow& m); + + PackedRow(const uint32_t _size, uint64_t* const _mp) : + mp(_mp+1) + , is_true_internal(*_mp) + , size(_size) + {} + + uint64_t* __restrict const mp; + uint64_t& is_true_internal; + const uint32_t size; +}; + +inline std::ostream& operator << (std::ostream& os, const PackedRow& m) +{ + for(uint32_t i = 0; i < m.size*64; i++) { + os << m[i]; + } + os << " -- xor: " << m.is_true(); + return os; +} + +} + +#endif //PACKEDROW_H diff --git a/src/prop/cryptominisat/Solver/PropBy.h b/src/prop/cryptominisat/Solver/PropBy.h new file mode 100644 index 000000000..11e35cf2d --- /dev/null +++ b/src/prop/cryptominisat/Solver/PropBy.h @@ -0,0 +1,257 @@ +/*********************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +************************************************************************/ + +#ifndef PROPBY_H +#define PROPBY_H + +#include "SolverTypes.h" +#include "Clause.h" +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER +#include <stdio.h> + +//#define DEBUG_PROPAGATEFROM + +#include "ClauseOffset.h" +#include "ClauseAllocator.h" + +namespace CMSat { + +class PropBy +{ + private: + uint64_t propType:2; + //0: clause, NULL + //1: clause, non-null + //2: binary + //3: tertiary + uint64_t data1:30; + uint64_t data2:32; + + public: + PropBy() : + propType(0) + , data1(0) + , data2(0) + {} + + PropBy(ClauseOffset offset) : + propType(1) + , data2(offset) + { + } + + PropBy(const Lit lit) : + propType(2) + , data1(lit.toInt()) + { + } + + PropBy(const Lit lit1, const Lit lit2) : + propType(3) + , data1(lit1.toInt()) + , data2(lit2.toInt()) + { + } + + bool isClause() const + { + return ((propType&2) == 0); + } + + bool isBinary() const + { + return (propType == 2); + } + + bool isTri() const + { + return (propType == 3); + } + + Lit getOtherLit() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(isBinary() || isTri()); + #endif + return Lit::toLit(data1); + } + + Lit getOtherLit2() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(isTri()); + #endif + return Lit::toLit(data2); + } + + ClauseOffset getClause() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(isClause()); + #endif + return data2; + } + + ClauseOffset getClause() + { + #ifdef DEBUG_PROPAGATEFROM + assert(isClause()); + #endif + return data2; + } + + bool isNULL() const + { + if (!isClause()) return false; + return propType == 0; + } +}; + +inline std::ostream& operator<<(std::ostream& os, const PropBy& pb) +{ + if (pb.isBinary()) { + os << " binary, other lit= " << pb.getOtherLit(); + } else if (pb.isClause()) { + os << " clause, num= " << pb.getClause(); + } else if (pb.isNULL()) { + os << " NULL"; + } else if (pb.isTri()) { + os << " tri, other 2 lits= " << pb.getOtherLit() << " , "<< pb.getOtherLit2(); + } + return os; +} + +class PropByFull +{ + private: + uint32_t type; + Clause* clause; + Lit lits[3]; + + public: + PropByFull(PropBy orig, Lit otherLit, ClauseAllocator& alloc) : + type(10) + , clause(NULL) + { + if (orig.isBinary() || orig.isTri()) { + lits[0] = otherLit; + lits[1] = orig.getOtherLit(); + if (orig.isTri()) { + lits[2] = orig.getOtherLit2(); + type = 2; + } else { + type = 1; + } + } + if (orig.isClause()) { + type = 0; + if (orig.isNULL()) { + clause = NULL; + } else { + clause = alloc.getPointer(orig.getClause()); + } + } + } + + PropByFull() : + type(10) + {} + + PropByFull(const PropByFull& other) : + type(other.type) + , clause(other.clause) + { + memcpy(lits, other.lits, sizeof(Lit)*3); + } + + uint32_t size() const + { + switch (type) { + case 0 : return clause->size(); + case 1 : return 2; + case 2 : return 3; + default: + assert(false); + return 0; + } + } + + bool isNULL() const + { + return type == 0 && clause == NULL; + } + + bool isClause() const + { + return type == 0; + } + + bool isBinary() const + { + return type == 1; + } + + bool isTri() const + { + return type == 2; + } + + const Clause* getClause() const + { + return clause; + } + + Clause* getClause() + { + return clause; + } + + Lit operator[](const uint32_t i) const + { + switch (type) { + case 0: { + assert(clause != NULL); + return (*clause)[i]; + } + default : { + return lits[i]; + } + } + } +}; + +inline std::ostream& operator<<(std::ostream& cout, const PropByFull& propByFull) +{ + + if (propByFull.isBinary()) { + cout << "binary: " << " ? , " << propByFull[1]; + } else if (propByFull.isTri()) { + cout << "tri: " << " ? , " <<propByFull[1] << " , " << propByFull[2]; + } else if (propByFull.isClause()) { + if (propByFull.isNULL()) cout << "null clause"; + else cout << "clause:" << *propByFull.getClause(); + } + return cout; +} + +} + +#endif //PROPBY_H diff --git a/src/prop/cryptominisat/Solver/RestartTypeChooser.cpp b/src/prop/cryptominisat/Solver/RestartTypeChooser.cpp new file mode 100644 index 000000000..9432c374a --- /dev/null +++ b/src/prop/cryptominisat/Solver/RestartTypeChooser.cpp @@ -0,0 +1,181 @@ +/**************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#include "RestartTypeChooser.h" + +#include <utility> +#include "Solver.h" + +//#define VERBOSE_DEBUG +//#define PRINT_VARS + +using namespace CMSat; + +using std::pair; + +RestartTypeChooser::RestartTypeChooser(const Solver& s) : + solver(s) + , topX(100) + , limit(40) +{ +} + +/** +@brief Adds info at the end of a restart to the internal datastructures + +It is called a number of times after a full restart has been done, to +accumulate data. Finally, choose() is called to choose the restart type +*/ +void RestartTypeChooser::addInfo() +{ + firstVarsOld = firstVars; + calcHeap(); + uint32_t sameIn = 0; + if (!firstVarsOld.empty()) { + uint32_t thisTopX = std::min(firstVarsOld.size(), (size_t)topX); + for (uint32_t i = 0; i != thisTopX; i++) { + if (std::find(firstVars.begin(), firstVars.end(), firstVarsOld[i]) != firstVars.end()) + sameIn++; + } + #ifdef VERBOSE_DEBUG + std::cout << " Same vars in first&second first 100: " << sameIn << std::endl; + #endif + sameIns.push_back(sameIn); + } + + #ifdef VERBOSE_DEBUG + std::cout << "Avg same vars in first&second first 100: " << avg() << " standard Deviation:" << stdDeviation(sameIns) <<std::endl; + #endif +} + +/** +@brief After accumulation of data, this function finally decides which type to choose +*/ +RestartType RestartTypeChooser::choose() +{ + pair<double, double> mypair = countVarsDegreeStDev(); + if ((mypair.second < 80 && + (avg() > (double)limit || ((avg() > (double)(limit*0.9) && stdDeviation(sameIns) < 5)))) + || + (mypair.second < 80 && (double)solver.xorclauses.size() > (double)solver.nClauses()*0.1)) + return static_restart; + else + return dynamic_restart; +} + +/** +@brief Calculates average for topx variable activity changes +*/ +double RestartTypeChooser::avg() const +{ + double sum = 0.0; + for (uint32_t i = 0; i != sameIns.size(); i++) + sum += sameIns[i]; + return (sum/(double)sameIns.size()); +} + +/** +@brief Calculates standard deviation for topx variable activity changes +*/ +double RestartTypeChooser::stdDeviation(vector<uint32_t>& measure) const +{ + double average = avg(); + double variance = 0.0; + for (uint32_t i = 0; i != measure.size(); i++) + variance += pow((double)measure[i]-average, 2); + variance /= (double)measure.size(); + + return sqrt(variance); +} + +void RestartTypeChooser::calcHeap() +{ + firstVars.clear(); + firstVars.reserve(topX); + #ifdef PRINT_VARS + std::cout << "First vars:" << std::endl; + #endif + Heap<Solver::VarOrderLt> tmp(solver.order_heap); + uint32_t thisTopX = std::min(tmp.size(), topX); + for (uint32_t i = 0; i != thisTopX; i++) { + #ifdef PRINT_VARS + std::cout << tmp.removeMin()+1 << ", "; + #endif + firstVars.push_back(tmp.removeMin()); + } + #ifdef PRINT_VARS + std::cout << std::endl; + #endif +} + +std::pair<double, double> RestartTypeChooser::countVarsDegreeStDev() const +{ + vector<uint32_t> degrees; + degrees.resize(solver.nVars(), 0); + addDegrees(solver.clauses, degrees); + addDegreesBin(degrees); + addDegrees(solver.xorclauses, degrees); + uint32_t sum = 0; + uint32_t *i = °rees[0], *j = i; + for (uint32_t *end = i + degrees.size(); i != end; i++) { + if (*i != 0) { + sum += *i; + *j++ = *i; + } + } + degrees.resize(degrees.size() - (i-j)); + + double avg = (double)sum/(double)degrees.size(); + double stdDev = stdDeviation(degrees); + + #ifdef VERBOSE_DEBUG + std::cout << "varsDegree avg:" << avg << " stdDev:" << stdDev << std::endl; + #endif + + return std::make_pair(avg, stdDev); +} + +template<class T> +void RestartTypeChooser::addDegrees(const vec<T*>& cs, vector<uint32_t>& degrees) const +{ + for (T * const*c = cs.getData(), * const*end = c + cs.size(); c != end; c++) { + T& cl = **c; + if (cl.learnt()) continue; + + for (const Lit *l = cl.getData(), *end2 = l + cl.size(); l != end2; l++) { + degrees[l->var()]++; + } + } +} + +template void RestartTypeChooser::addDegrees(const vec<Clause*>& cs, vector<uint32_t>& degrees) const; +template void RestartTypeChooser::addDegrees(const vec<XorClause*>& cs, vector<uint32_t>& degrees) const; + +void RestartTypeChooser::addDegreesBin(vector<uint32_t>& degrees) const +{ + uint32_t wsLit = 0; + for (const vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec<Watched>& ws = *it; + for (vec<Watched>::const_iterator it2 = ws.getData(), end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary() && lit.toInt() < it2->getOtherLit().toInt()) { + degrees[lit.var()]++; + degrees[it2->getOtherLit().var()]++; + } + } + } +} diff --git a/src/prop/cryptominisat/Solver/RestartTypeChooser.h b/src/prop/cryptominisat/Solver/RestartTypeChooser.h new file mode 100644 index 000000000..6279b07a5 --- /dev/null +++ b/src/prop/cryptominisat/Solver/RestartTypeChooser.h @@ -0,0 +1,81 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#ifndef RESTARTTYPECHOOSER_H +#define RESTARTTYPECHOOSER_H + +#include "Solver.h" +#include <vector> +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#include "SolverTypes.h" + +namespace CMSat { + +using std::vector; + +class Solver; + +/** +@brief Chooses between MiniSat and GLUCOSE restart types&learnt clause evaluation + +MiniSat style restart is geometric, and glucose-type is dynamic. MiniSat-type +learnt clause staistic is activity-based, glucose-type is glue-based. This +class takes as input a number of MiniSat restart's end results, computes some +statistics on them, and at the end, tells if we should use one type or the +other. Basically, it masures variable activity stability, number of xors +in the problem, and variable degrees. +*/ +class RestartTypeChooser +{ + public: + RestartTypeChooser(const Solver& s); + void addInfo(); + RestartType choose(); + void reset(); + + private: + void calcHeap(); + double avg() const; + std::pair<double, double> countVarsDegreeStDev() const; + double stdDeviation(vector<uint32_t>& measure) const; + + template<class T> + void addDegrees(const vec<T*>& cs, vector<uint32_t>& degrees) const; + void addDegreesBin(vector<uint32_t>& degrees) const; + + const Solver& solver; + uint32_t topX; ///<The how many is the top X? 100 is default + uint32_t limit; ///<If top x contains on average this many common varables, we select MiniSat-type + vector<Var> sameIns; + + vector<Var> firstVars; ///<The top x variables (in terms of var activity) + vector<Var> firstVarsOld; ///<The previous top x variables (in terms of var activity) +}; + +inline void RestartTypeChooser::reset() +{ + sameIns.clear(); +} + +} + +#endif //RESTARTTYPECHOOSER_H diff --git a/src/prop/cryptominisat/Solver/SCCFinder.cpp b/src/prop/cryptominisat/Solver/SCCFinder.cpp new file mode 100644 index 000000000..896566cad --- /dev/null +++ b/src/prop/cryptominisat/Solver/SCCFinder.cpp @@ -0,0 +1,142 @@ +/***************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +******************************************************************************/ + +#include <iostream> +#include <vector> +#include "../Solver/SolverTypes.h" +#include "SCCFinder.h" +#include "VarReplacer.h" +#include <iomanip> +#include "time_mem.h" +#include "Subsumer.h" +#include "XorSubsumer.h" + +using namespace CMSat; + +SCCFinder::SCCFinder(Solver& _solver) : + solver(_solver) + , varElimed1(_solver.subsumer->getVarElimed()) + , varElimed2(_solver.xorSubsumer->getVarElimed()) + , replaceTable(_solver.varReplacer->getReplaceTable()) + , totalTime(0.0) +{} + +bool SCCFinder::find2LongXors() +{ + double myTime = cpuTime(); + uint32_t oldNumReplace = solver.varReplacer->getNewToReplaceVars(); + + globalIndex = 0; + index.clear(); + index.resize(solver.nVars()*2, std::numeric_limits<uint32_t>::max()); + lowlink.clear(); + lowlink.resize(solver.nVars()*2, std::numeric_limits<uint32_t>::max()); + stackIndicator.clear(); + stackIndicator.growTo(solver.nVars()*2, false); + assert(stack.empty()); + + for (uint32_t vertex = 0; vertex < solver.nVars()*2; vertex++) { + //Start a DFS at each node we haven't visited yet + if (index[vertex] == std::numeric_limits<uint32_t>::max()) { + recurDepth = 0; + tarjan(vertex); + assert(stack.empty()); + } + } + + if (solver.conf.verbosity >= 3 || (solver.conflicts == 0 && solver.conf.verbosity >= 1)) { + std::cout << "c Finding binary XORs T: " + << std::fixed << std::setprecision(2) << std::setw(8) << (cpuTime() - myTime) << " s" + << " found: " << std::setw(7) << solver.varReplacer->getNewToReplaceVars() - oldNumReplace + << std::endl; + } + totalTime += (cpuTime() - myTime); + + return solver.ok; +} + +void SCCFinder::tarjan(const uint32_t vertex) +{ + recurDepth++; + index[vertex] = globalIndex; // Set the depth index for v + lowlink[vertex] = globalIndex; + globalIndex++; + stack.push(vertex); // Push v on the stack + stackIndicator[vertex] = true; + + Var vertexVar = Lit::toLit(vertex).var(); + if (!varElimed1[vertexVar] && !varElimed2[vertexVar]) { + const vec<Watched>& ws = solver.watches[vertex]; + for (vec<Watched>::const_iterator it = ws.getData(), end = ws.getDataEnd(); it != end; it++) { + if (!it->isBinary()) continue; + const Lit lit = it->getOtherLit(); + + doit(lit, vertex); + } + + if (solver.conf.doExtendedSCC) { + Lit vertLit = Lit::toLit(vertex); + vector<Lit>& transCache = solver.transOTFCache[(~Lit::toLit(vertex)).toInt()].lits; + vector<Lit>::iterator it = transCache.begin(); + vector<Lit>::iterator it2 = it; + uint32_t newSize = 0; + Lit prevLit = lit_Error; + for (vector<Lit>::iterator end = transCache.end(); it != end; it++) { + Lit lit = *it; + lit = replaceTable[lit.var()] ^ lit.sign(); + if (lit == prevLit || lit == vertLit || varElimed1[lit.var()] || varElimed2[lit.var()]) + continue; + + *it2++ = lit; + prevLit = lit; + newSize++; + + doit(lit, vertex); + } + transCache.resize(newSize); + } + } + + // Is v the root of an SCC? + if (lowlink[vertex] == index[vertex]) { + uint32_t vprime; + tmp.clear(); + do { + assert(!stack.empty()); + vprime = stack.top(); + stack.pop(); + stackIndicator[vprime] = false; + tmp.push(vprime); + } while (vprime != vertex); + if (tmp.size() >= 2) { + for (uint32_t i = 1; i < tmp.size(); i++) { + if (!solver.ok) break; + vec<Lit> lits(2); + lits[0] = Lit::toLit(tmp[0]).unsign(); + lits[1] = Lit::toLit(tmp[i]).unsign(); + const bool xorEqualsFalse = Lit::toLit(tmp[0]).sign() + ^ Lit::toLit(tmp[i]).sign() + ^ true; + if (solver.value(lits[0]) == l_Undef && solver.value(lits[1]) == l_Undef) { + //Cannot add to watchlists, because we are going THROUGH the watchlists (in a higher frame) + //so it might end up kicking the chair under ourselves + solver.varReplacer->replace(lits, xorEqualsFalse, true, false); + } + } + } + } +}
\ No newline at end of file diff --git a/src/prop/cryptominisat/Solver/SCCFinder.h b/src/prop/cryptominisat/Solver/SCCFinder.h new file mode 100644 index 000000000..c1d876e2c --- /dev/null +++ b/src/prop/cryptominisat/Solver/SCCFinder.h @@ -0,0 +1,72 @@ +/***************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +******************************************************************************/ + +#ifndef SCCFINDER_H +#define SCCFINDER_H + +#include "Vec.h" +#include "Clause.h" +#include "Solver.h" +#include <stack> + +namespace CMSat { + +class SCCFinder { + public: + SCCFinder(Solver& solver); + bool find2LongXors(); + double getTotalTime() const; + + private: + void tarjan(const uint32_t vertex); + void doit(const Lit lit, const uint32_t vertex); + + uint32_t globalIndex; + vector<uint32_t> index; + vector<uint32_t> lowlink; + std::stack<uint32_t> stack; + vec<char> stackIndicator; + vec<uint32_t> tmp; + + uint32_t recurDepth; + + Solver& solver; + const vec<char>& varElimed1; + const vec<char>& varElimed2; + const vector<Lit>& replaceTable; + double totalTime; +}; + +inline void SCCFinder::doit(const Lit lit, const uint32_t vertex) { + // Was successor v' visited? + if (index[lit.toInt()] == std::numeric_limits<uint32_t>::max()) { + tarjan(lit.toInt()); + recurDepth--; + lowlink[vertex] = std::min(lowlink[vertex], lowlink[lit.toInt()]); + } else if (stackIndicator[lit.toInt()]) { + lowlink[vertex] = std::min(lowlink[vertex], lowlink[lit.toInt()]); + } +} + +inline double SCCFinder::getTotalTime() const +{ + return totalTime; +} + +} + +#endif //SCCFINDER_H diff --git a/src/prop/cryptominisat/Solver/SharedData.h b/src/prop/cryptominisat/Solver/SharedData.h new file mode 100644 index 000000000..394b517f7 --- /dev/null +++ b/src/prop/cryptominisat/Solver/SharedData.h @@ -0,0 +1,37 @@ +/************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef SHARED_DATA_H +#define SHARED_DATA_H + +#include "Vec.h" +#include "SolverTypes.h" + +#include <vector> + +namespace CMSat { + +class SharedData +{ + public: + vec<lbool> value; + std::vector<std::vector<Lit> > bins; +}; + +} + +#endif //SHARED_DATA_H diff --git a/src/prop/cryptominisat/Solver/Solver.cpp b/src/prop/cryptominisat/Solver/Solver.cpp new file mode 100644 index 000000000..f73d6166e --- /dev/null +++ b/src/prop/cryptominisat/Solver/Solver.cpp @@ -0,0 +1,2924 @@ +/***************************************************************************** +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +glucose -- Gilles Audemard, Laurent Simon (2008) +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +Original code by MiniSat and glucose authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3 licence. +******************************************************************************/ + +#include "Solver.h" +#include <cmath> +#include <string.h> +#include <algorithm> +#include <limits.h> +#include <vector> +#include <iomanip> +#include <algorithm> + +#include "Clause.h" +#include "time_mem.h" + +#include "VarReplacer.h" +#include "XorFinder.h" +#include "ClauseCleaner.h" +#include "RestartTypeChooser.h" +#include "FailedLitSearcher.h" +#include "Subsumer.h" +#include "XorSubsumer.h" +#include "StateSaver.h" +#include "SCCFinder.h" +#include "SharedData.h" +#include "ClauseVivifier.h" +#include "Gaussian.h" +#include "MatrixFinder.h" +#include "DataSync.h" +#include "BothCache.h" + +#ifdef VERBOSE_DEBUG +#define UNWINDING_DEBUG +#endif + +//#define DEBUG_UNCHECKEDENQUEUE_LEVEL0 +//#define VERBOSE_DEBUG_POLARITIES +//#define DEBUG_DYNAMIC_RESTART +//#define UNWINDING_DEBUG + +//********************************** +// Constructor/Destructor: +//********************************** + +using namespace CMSat; + +/** +@brief Sets a sane default config and allocates handler classes +*/ +Solver::Solver(const SolverConf& _conf, const GaussConf& _gaussconfig, SharedData* sharedData) : + // Parameters: (formerly in 'SearchParams') + conf(_conf) + , gaussconfig(_gaussconfig) + , needToInterrupt (false) + #ifdef USE_GAUSS + , sum_gauss_called (0) + , sum_gauss_confl (0) + , sum_gauss_prop (0) + , sum_gauss_unit_truths (0) + #endif //USE_GAUSS + + // Stats + , starts(0), dynStarts(0), staticStarts(0), fullStarts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0) + , clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0) + , nbGlue2(0), numNewBin(0), lastNbBin(0), lastSearchForBinaryXor(0), nbReduceDB(0) + , improvedClauseNo(0), improvedClauseSize(0) + , numShrinkedClause(0), numShrinkedClauseLits(0) + , moreRecurMinLDo(0) + , updateTransCache(0) + , nbClOverMaxGlue(0) + + , ok (true) + , numBins (0) + , cla_inc (1) + , qhead (0) + , mtrand ((unsigned long int)0) + + //variables + , order_heap (VarOrderLt(activity)) + , var_inc (128) + + //learnts + , numCleanedLearnts(1) + , nbClBeforeRed (NBCLAUSESBEFOREREDUCE) + , nbCompensateSubsumer (0) + , libraryCNFFile (NULL) + , restartType (static_restart) + , lastSelectedRestartType (static_restart) + , simplifying (false) + , totalSimplifyTime(0.0) + , simpDB_assigns (-1) + , simpDB_props (0) +{ + mtrand.seed(conf.origSeed); + #ifdef ENABLE_UNWIND_GLUE + assert(conf.maxGlue < MAX_THEORETICAL_GLUE); + #endif //ENABLE_UNWIND_GLUE + varReplacer = new VarReplacer(*this); + clauseCleaner = new ClauseCleaner(*this); + failedLitSearcher = new FailedLitSearcher(*this); + subsumer = new Subsumer(*this); + xorSubsumer = new XorSubsumer(*this); + restartTypeChooser = new RestartTypeChooser(*this); + sCCFinder = new SCCFinder(*this); + clauseVivifier = new ClauseVivifier(*this); + matrixFinder = new MatrixFinder(*this); + dataSync = new DataSync(*this, sharedData); + +} + +/** +@brief Frees clauses and frees all allocated hander classes +*/ +Solver::~Solver() +{ + clearGaussMatrixes(); + delete matrixFinder; + delete varReplacer; + delete clauseCleaner; + delete failedLitSearcher; + delete subsumer; + delete xorSubsumer; + delete restartTypeChooser; + + if (libraryCNFFile) + fclose(libraryCNFFile); +} + +//********************************** +// Minor methods +//********************************** + +/** +@brief Creates a new SAT variable in the solver + +This entails making the datastructures large enough to fit the new variable +in all internal datastructures as well as all datastructures used in +classes used inside Solver + +@p dvar The new variable should be used as a decision variable? + NOTE: this has effects on the meaning of a SATISFIABLE result +*/ +Var Solver::newVar(bool dvar) throw (std::out_of_range) +{ + Var v = nVars(); + if (v >= 1<<30) + throw std::out_of_range("ERROR! Variable requested is far too large"); + + watches .push(); // (list for positive literal) + watches .push(); // (list for negative literal) + reason .push(PropBy()); + assigns .push(l_Undef); + level .push(-1); + binPropData.push(); + activity .push(0); + seen .push_back(0); + seen .push_back(0); + #ifdef ENABLE_UNWIND_GLUE + unWindGlue.push(NULL); + #endif //ENABLE_UNWIND_GLUE + + //Transitive OTF self-subsuming resolution + seen2 .push_back(0); + seen2 .push_back(0); + transOTFCache.push_back(TransCache()); + transOTFCache.push_back(TransCache()); + litReachable.push_back(LitReachData()); + litReachable.push_back(LitReachData()); + + polarity .push_back(defaultPolarity()); + + decision_var.push_back(dvar); + insertVarOrder(v); + + varReplacer->newVar(); + subsumer->newVar(); + xorSubsumer->newVar(); + dataSync->newVar(); + + insertVarOrder(v); + + if (libraryCNFFile) + fprintf(libraryCNFFile, "c Solver::newVar() called\n"); + + return v; +} + +/** +@brief Adds an xor clause to the problem + +Should ONLY be called from internally. This is different from the extenal +xor clause-adding function addXorClause() in that it assumes that the variables +inside are decision variables, have not been replaced, eliminated, etc. +*/ +template<class T> +XorClause* Solver::addXorClauseInt(T& ps, bool xorEqualFalse, const bool learnt) throw (std::out_of_range) +{ + assert(qhead == trail.size()); + assert(decisionLevel() == 0); + + if (ps.size() > (0x01UL << 18)) + throw std::out_of_range("Too long clause!"); + std::sort(ps.getData(), ps.getDataEnd()); + Lit p; + uint32_t i, j; + for (i = j = 0, p = lit_Undef; i != ps.size(); i++) { + if (ps[i].var() == p.var()) { + //added, but easily removed + j--; + p = lit_Undef; + if (!assigns[ps[i].var()].isUndef()) + xorEqualFalse ^= assigns[ps[i].var()].getBool(); + } else if (assigns[ps[i].var()].isUndef()) { //just add + ps[j++] = p = ps[i]; + assert(!subsumer->getVarElimed()[p.var()]); + assert(!xorSubsumer->getVarElimed()[p.var()]); + } else //modify xorEqualFalse instead of adding + xorEqualFalse ^= (assigns[ps[i].var()].getBool()); + } + ps.shrink(i - j); + + switch(ps.size()) { + case 0: { + if (!xorEqualFalse) ok = false; + return NULL; + } + case 1: { + uncheckedEnqueue(Lit(ps[0].var(), xorEqualFalse)); + ok = (propagate<false>().isNULL()); + return NULL; + } + case 2: { + #ifdef VERBOSE_DEBUG + cout << "--> xor is 2-long, replacing var " << ps[0].var()+1 << " with " << (!xorEqualFalse ? "-" : "") << ps[1].var()+1 << endl; + #endif + + ps[0] = ps[0].unsign(); + ps[1] = ps[1].unsign(); + varReplacer->replace(ps, xorEqualFalse, learnt); + return NULL; + } + default: { + assert(!learnt); + XorClause* c = clauseAllocator.XorClause_new(ps, xorEqualFalse); + attachClause(*c); + return c; + } + } +} + +template XorClause* Solver::addXorClauseInt(vec<Lit>& ps, bool xorEqualFalse, const bool learnt); +template XorClause* Solver::addXorClauseInt(XorClause& ps, bool xorEqualFalse, const bool learnt); + +/** +@brief Adds an xor clause to the problem + +Calls addXorClauseInt() for the heavy-lifting. Basically, this does a bit +of debug-related stuff (see "libraryCNFFile"), and then checks if any of the +variables have been eliminated, replaced, etc. If so, it treats it correctly, +and then calls addXorClauseInt() to actually add the xor clause. + +@p ps[inout] The VARIABLES in the xor clause. Beware, there must be NO signs + here: ALL must be unsigned (.sign() == false). Values passed here + WILL be changed, ordered, removed, etc! +@p xorEqualFalse The xor must be equal to TRUE or false? +*/ +template<class T> +bool Solver::addXorClause(T& ps, bool xorEqualFalse) throw (std::out_of_range) +{ + assert(decisionLevel() == 0); + if (ps.size() > (0x01UL << 18)) + throw std::out_of_range("Too long clause!"); + + if (libraryCNFFile) { + fprintf(libraryCNFFile, "x"); + for (uint32_t i = 0; i < ps.size(); i++) ps[i].print(libraryCNFFile); + fprintf(libraryCNFFile, "0\n"); + } + + if (!ok) + return false; + assert(qhead == trail.size()); + #ifndef NDEBUG + for (Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) { + assert(l->var() < nVars() && "Clause inserted, but variable inside has not been declared with newVar()!"); + } + #endif + + if (varReplacer->getNumLastReplacedVars() || subsumer->getNumElimed() || xorSubsumer->getNumElimed()) { + for (uint32_t i = 0; i != ps.size(); i++) { + Lit otherLit = varReplacer->getReplaceTable()[ps[i].var()]; + if (otherLit.var() != ps[i].var()) { + ps[i] = Lit(otherLit.var(), false); + xorEqualFalse ^= otherLit.sign(); + } + if (subsumer->getVarElimed()[ps[i].var()] && !subsumer->unEliminate(ps[i].var())) + return false; + else if (xorSubsumer->getVarElimed()[ps[i].var()] && !xorSubsumer->unEliminate(ps[i].var())) + return false; + } + } + + XorClause* c = addXorClauseInt(ps, xorEqualFalse); + if (c != NULL) xorclauses.push(c); + + return ok; +} + +template bool Solver::addXorClause(vec<Lit>& ps, bool xorEqualFalse); +template bool Solver::addXorClause(XorClause& ps, bool xorEqualFalse); + +/** +@brief Adds a clause to the problem. Should ONLY be called internally + +This code is very specific in that it must NOT be called with varibles in +"ps" that have been replaced, eliminated, etc. Also, it must not be called +when the solver is in an UNSAT (!ok) state, for example. Use it carefully, +and only internally +*/ +template <class T> +Clause* Solver::addClauseInt(T& ps + , const bool learnt, const uint32_t glue, const float miniSatActivity + , const bool inOriginalInput) +{ + assert(ok); +#ifdef VERBOSE_DEBUG + std::cout << "Adding new clause: " << std::endl; + for(size_t i = 0; i< ps.size(); i++) { + printLit(ps[i]); + std::cout << " "; + } + std::cout << std::endl; +#endif //VERBOSE_DEBUG + + std::sort(ps.getData(), ps.getDataEnd()); + Lit p = lit_Undef; + uint32_t i, j; + for (i = j = 0; i != ps.size(); i++) { + if (value(ps[i]).getBool() || ps[i] == ~p) + return NULL; + else if (value(ps[i]) != l_False && ps[i] != p) { + ps[j++] = p = ps[i]; + assert(!subsumer->getVarElimed()[p.var()]); + assert(!xorSubsumer->getVarElimed()[p.var()]); + } + } + ps.shrink(i - j); + + if (ps.size() == 0) { + ok = false; + return NULL; + } else if (ps.size() == 1) { + uncheckedEnqueue(ps[0]); + ok = (propagate<false>().isNULL()); + return NULL; + } + + if (ps.size() > 2) { + Clause* c = clauseAllocator.Clause_new(ps); + if (learnt) c->makeLearnt(glue, miniSatActivity); + attachClause(*c); + return c; + } else { + attachBinClause(ps[0], ps[1], learnt); + if (!inOriginalInput) dataSync->signalNewBinClause(ps); + numNewBin++; + return NULL; + } +} + +template Clause* Solver::addClauseInt(Clause& ps, const bool learnt, const uint32_t glue, const float miniSatActivity, const bool inOriginalInput); +template Clause* Solver::addClauseInt(vec<Lit>& ps, const bool learnt, const uint32_t glue, const float miniSatActivity, const bool inOriginalInput); + +template<class T> bool Solver::addClauseHelper(T& ps) throw (std::out_of_range) +{ + assert(decisionLevel() == 0); + if (ps.size() > (0x01UL << 18)) + throw std::out_of_range("Too long clause!"); + + if (libraryCNFFile) { + for (uint32_t i = 0; i != ps.size(); i++) ps[i].print(libraryCNFFile); + fprintf(libraryCNFFile, "0\n"); + } + + if (!ok) return false; + assert(qhead == trail.size()); + #ifndef NDEBUG + for (Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) { + assert(l->var() < nVars() && "Clause inserted, but variable inside has not been declared with Solver::newVar() !"); + } + #endif + + // Check if clause is satisfied and remove false/duplicate literals: + if (varReplacer->getNumLastReplacedVars() || subsumer->getNumElimed() || xorSubsumer->getNumElimed()) { + for (uint32_t i = 0; i != ps.size(); i++) { + ps[i] = varReplacer->getReplaceTable()[ps[i].var()] ^ ps[i].sign(); + if (subsumer->getVarElimed()[ps[i].var()] && !subsumer->unEliminate(ps[i].var())) + return false; + if (xorSubsumer->getVarElimed()[ps[i].var()] && !xorSubsumer->unEliminate(ps[i].var())) + return false; + } + } + + for (uint32_t i = 0; i < ps.size(); i++) { + std::swap(ps[i], ps[(mtrand.randInt() % (ps.size()-i)) + i]); + } + + return true; +} + + +/** +@brief Adds a clause to the problem. Calls addClauseInt() for heavy-lifting + +Does some debug-related stuff (see "libraryCNFFile"), and checks whether the +variables of the literals in "ps" have been eliminated/replaced etc. If so, +it acts on them such that they are correct, and calls addClauseInt() to do +the heavy-lifting +*/ +template<class T> +bool Solver::addClause(T& ps) +{ + #ifdef VERBOSE_DEBUG + std::cout << "addClause() called with new clause: " << ps << std::endl; + #endif //VERBOSE_DEBUG + if (!addClauseHelper(ps)) return false; + Clause* c = addClauseInt(ps, false, 0, 0, true); + if (c != NULL) clauses.push(c); + + return ok; +} + +template bool Solver::addClause(vec<Lit>& ps); +template bool Solver::addClause(Clause& ps); + + +template<class T> +bool Solver::addLearntClause(T& ps, const uint32_t glue, const float miniSatActivity) +{ + if (!addClauseHelper(ps)) return false; + Clause* c = addClauseInt(ps, true, glue, miniSatActivity, true); + if (c != NULL) learnts.push(c); + + return ok; +} + +template bool Solver::addLearntClause(vec<Lit>& ps, const uint32_t glue, const float miniSatActivity); +template bool Solver::addLearntClause(Clause& ps, const uint32_t glue, const float miniSatActivity); + + +/** +@brief Attaches an xor clause to the watchlists + +The xor clause must be larger than 2, since a 2-long XOR clause is a varible +replacement instruction, really. +*/ +void Solver::attachClause(XorClause& c) +{ + assert(c.size() > 2); + #ifdef DEBUG_ATTACH + assert(assigns[c[0].var()] == l_Undef); + assert(assigns[c[1].var()] == l_Undef); + + for (uint32_t i = 0; i < c.size(); i++) { + assert(!subsumer->getVarElimed()[c[i].var()]); + assert(!xorSubsumer->getVarElimed()[c[i].var()]); + } + #endif //DEBUG_ATTACH + + watches[Lit(c[0].var(), false).toInt()].push(clauseAllocator.getOffset((Clause*)&c)); + watches[Lit(c[0].var(), true).toInt()].push(clauseAllocator.getOffset((Clause*)&c)); + watches[Lit(c[1].var(), false).toInt()].push(clauseAllocator.getOffset((Clause*)&c)); + watches[Lit(c[1].var(), true).toInt()].push(clauseAllocator.getOffset((Clause*)&c)); + + clauses_literals += c.size(); +} + +void Solver::attachBinClause(const Lit lit1, const Lit lit2, const bool learnt) +{ + #ifdef DEBUG_ATTACH + assert(lit1.var() != lit2.var()); + assert(assigns[lit1.var()] == l_Undef); + assert(value(lit2) == l_Undef || value(lit2) == l_False); + + assert(!subsumer->getVarElimed()[lit1.var()]); + assert(!subsumer->getVarElimed()[lit2.var()]); + + assert(!xorSubsumer->getVarElimed()[lit1.var()]); + assert(!xorSubsumer->getVarElimed()[lit2.var()]); + #endif //DEBUG_ATTACH + + watches[(~lit1).toInt()].push(Watched(lit2, learnt)); + watches[(~lit2).toInt()].push(Watched(lit1, learnt)); + + #ifdef DUMP_STATS_FULL + if (learnt) { + watches[(~lit1).toInt()].last().glue = 2; + watches[(~lit2).toInt()].last().glue = 2; + } else { + watches[(~lit1).toInt()].last().glue = -1; + watches[(~lit2).toInt()].last().glue = -1; + } + #endif + + numBins++; + if (learnt) learnts_literals += 2; + else clauses_literals += 2; +} + +/** +@brief Attach normal a clause to the watchlists + +Handles 2, 3 and >3 clause sizes differently and specially +*/ +void Solver::attachClause(Clause& c) +{ + assert(c.size() > 2); + #ifdef DEBUG_ATTACH + assert(c[0].var() != c[1].var()); + assert(assigns[c[0].var()] == l_Undef); + assert(value(c[1]) == l_Undef || value(c[1]) == l_False); + + for (uint32_t i = 0; i < c.size(); i++) { + assert(!subsumer->getVarElimed()[c[i].var()]); + assert(!xorSubsumer->getVarElimed()[c[i].var()]); + } + #endif //DEBUG_ATTACH + + if (c.size() == 3) { + watches[(~c[0]).toInt()].push(Watched(c[1], c[2])); + watches[(~c[1]).toInt()].push(Watched(c[0], c[2])); + watches[(~c[2]).toInt()].push(Watched(c[0], c[1])); + + #ifdef DUMP_STATS_FULL + if (c.learnt()) { + watches[(~c[0]).toInt()].last().glue = 2; + watches[(~c[1]).toInt()].last().glue = 2; + watches[(~c[2]).toInt()].last().glue = 2; + } else { + watches[(~c[0]).toInt()].last().glue = -1; + watches[(~c[1]).toInt()].last().glue = -1; + watches[(~c[2]).toInt()].last().glue = -1; + } + #endif + + } else { + ClauseOffset offset = clauseAllocator.getOffset(&c); + watches[(~c[0]).toInt()].push(Watched(offset, c[c.size()/2])); + watches[(~c[1]).toInt()].push(Watched(offset, c[c.size()/2])); + } + + if (c.learnt()) + learnts_literals += c.size(); + else + clauses_literals += c.size(); +} + +/** +@brief Calls detachModifiedClause to do the heavy-lifting +*/ +void Solver::detachClause(const XorClause& c) +{ + detachModifiedClause(c[0].var(), c[1].var(), c.size(), &c); +} + +/** +@brief Calls detachModifiedClause to do the heavy-lifting +*/ +void Solver::detachClause(const Clause& c) +{ + detachModifiedClause(c[0], c[1], (c.size() == 3) ? c[2] : lit_Undef, c.size(), &c); +} + +/** +@brief Detaches a (potentially) modified clause + +The first two literals might have chaned through modification, so they are +passed along as arguments -- they are needed to find the correct place where +the clause is +*/ +void Solver::detachModifiedClause(const Lit lit1, const Lit lit2, const Lit lit3, const uint32_t origSize, const Clause* address) +{ + assert(origSize > 2); + + ClauseOffset offset = clauseAllocator.getOffset(address); + if (origSize == 3) { + //The clause might have been longer, and has only recently + //became 3-long. Check, and detach accordingly + if (findWCl(watches[(~lit1).toInt()], offset)) goto fullClause; + + removeWTri(watches[(~lit1).toInt()], lit2, lit3); + removeWTri(watches[(~lit2).toInt()], lit1, lit3); + removeWTri(watches[(~lit3).toInt()], lit1, lit2); + + } else { + fullClause: + removeWCl(watches[(~lit1).toInt()], offset); + removeWCl(watches[(~lit2).toInt()], offset); + + } + + if (address->learnt()) + learnts_literals -= origSize; + else + clauses_literals -= origSize; +} + +/** +@brief Detaches a (potentially) modified xor clause + +The first two vars might have chaned through modification, so they are passed +along as arguments. +*/ +void Solver::detachModifiedClause(const Var var1, const Var var2, const uint32_t origSize, const XorClause* address) +{ + assert(origSize > 2); + + ClauseOffset offset = clauseAllocator.getOffset(address); + assert(findWXCl(watches[Lit(var1, false).toInt()], offset)); + assert(findWXCl(watches[Lit(var1, true).toInt()], offset)); + assert(findWXCl(watches[Lit(var2, false).toInt()], offset)); + assert(findWXCl(watches[Lit(var2, true).toInt()], offset)); + + removeWXCl(watches[Lit(var1, false).toInt()], offset); + removeWXCl(watches[Lit(var1, true).toInt()], offset); + removeWXCl(watches[Lit(var2, false).toInt()], offset); + removeWXCl(watches[Lit(var2, true).toInt()], offset); + + assert(!address->learnt()); + clauses_literals -= origSize; +} + +/** +@brief Revert to the state at given level + +Also reverts all stuff in Gass-elimination +*/ +void Solver::cancelUntil(int level) +{ + #ifdef VERBOSE_DEBUG + cout << "Canceling until level " << level; + if (level > 0) cout << " sublevel: " << trail_lim[level]; + cout << endl; + #endif + + if ((int)decisionLevel() > level) { + + #ifdef USE_GAUSS + for (vector<Gaussian*>::iterator gauss = gauss_matrixes.begin(), end= gauss_matrixes.end(); gauss != end; gauss++) + (*gauss)->canceling(trail_lim[level]); + #endif //USE_GAUSS + + for (int sublevel = trail.size()-1; sublevel >= (int)trail_lim[level]; sublevel--) { + Var var = trail[sublevel].var(); + #ifdef VERBOSE_DEBUG + cout << "Canceling var " << var+1 << " sublevel: " << sublevel << endl; + #endif + assigns[var] = l_Undef; + #ifdef ANIMATE3D + fprintf(stderr, "u %u\n", var); + #endif + insertVarOrder(var); + #ifdef ENABLE_UNWIND_GLUE + if (unWindGlue[var] != NULL) { + #ifdef UNWINDING_DEBUG + std::cout << "unwind, var:" << var + << " sublevel:" << sublevel + << " coming from:" << (trail.size()-1) + << " going until:" << (int)trail_lim[level] + << std::endl; + unWindGlue[var]->plainPrint(); + #endif //UNWINDING_DEBUG + + Clause*& clauseToFree = unWindGlue[var]; + detachClause(*clauseToFree); + clauseAllocator.clauseFree(clauseToFree); + clauseToFree = NULL; + } + #endif //ENABLE_UNWIND_GLUE + } + qhead = trail_lim[level]; + trail.shrink_(trail.size() - trail_lim[level]); + trail_lim.shrink_(trail_lim.size() - level); + } + + #ifdef VERBOSE_DEBUG + cout << "Canceling finished. (now at level: " << decisionLevel() << " sublevel: " << trail.size()-1 << ")" << endl; + #endif +} + +void Solver::cancelUntilLight() +{ + assert((int)decisionLevel() > 0); + + for (int sublevel = trail.size()-1; sublevel >= (int)trail_lim[0]; sublevel--) { + Var var = trail[sublevel].var(); + assigns[var] = l_Undef; + } + qhead = trail_lim[0]; + trail.shrink_(trail.size() - trail_lim[0]); + trail_lim.clear(); +} + +bool Solver::clearGaussMatrixes() +{ + assert(decisionLevel() == 0); + #ifdef USE_GAUSS + bool ret = gauss_matrixes.size() > 0; + for (uint32_t i = 0; i < gauss_matrixes.size(); i++) + delete gauss_matrixes[i]; + gauss_matrixes.clear(); + + for (uint32_t i = 0; i != freeLater.size(); i++) + clauseAllocator.clauseFree(freeLater[i]); + freeLater.clear(); + + return ret; + #endif //USE_GAUSS + return false; +} + +/** +@brief Returns what polarity[] should be set as default based on polarity_mode + +since polarity is filled with Lit::sign() , "true" here means an inverted +signed-ness, i.e. a FALSE default value. And vice-versa +*/ +inline bool Solver::defaultPolarity() +{ + switch(conf.polarity_mode) { + case polarity_false: + return true; + case polarity_true: + return false; + case polarity_rnd: + return mtrand.randInt(1); + case polarity_auto: + return true; + default: + assert(false); + } + + return true; +} + +/** +@brief Tally votes for a default TRUE or FALSE value for the variable using the Jeroslow-Wang method + +@p votes[inout] Votes are tallied at this place for each variable +@p cs The clause to tally votes for +*/ +void Solver::tallyVotes(const vec<Clause*>& cs, vec<double>& votes) const +{ + for (const Clause * const*it = cs.getData(), * const*end = it + cs.size(); it != end; it++) { + const Clause& c = **it; + if (c.learnt()) continue; + + double divider; + if (c.size() > 63) divider = 0.0; + else divider = 1.0/(double)((uint64_t)1<<(c.size()-1)); + + for (const Lit *it2 = c.getData(), *end2 = c.getDataEnd(); it2 != end2; it2++) { + if (it2->sign()) votes[it2->var()] += divider; + else votes[it2->var()] -= divider; + } + } +} + +void Solver::tallyVotesBin(vec<double>& votes) const +{ + uint32_t wsLit = 0; + for (const vec<Watched> *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec<Watched>& ws = *it; + for (vec<Watched>::const_iterator it2 = ws.getData(), end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary() && lit.toInt() < it2->getOtherLit().toInt()) { + if (!it2->getLearnt()) { + if (lit.sign()) votes[lit.var()] += 0.5; + else votes[lit.var()] -= 0.5; + + Lit lit2 = it2->getOtherLit(); + if (lit2.sign()) votes[lit2.var()] += 0.5; + else votes[lit2.var()] -= 0.5; + } + } + } + } +} + +/** +@brief Tally votes a default TRUE or FALSE value for the variable using the Jeroslow-Wang method + +For XOR clause, we simply add some weight for a FALSE default, i.e. being in +xor clauses makes the variabe more likely to be FALSE by default +*/ +void Solver::tallyVotes(const vec<XorClause*>& cs, vec<double>& votes) const +{ + for (const XorClause * const*it = cs.getData(), * const*end = it + cs.size(); it != end; it++) { + const XorClause& c = **it; + double divider; + if (c.size() > 63) divider = 0.0; + else divider = 1.0/(double)((uint64_t)1<<(c.size()-1)); + + for (const Lit *it2 = c.getData(), *end2 = c.getDataEnd(); it2 != end2; it2++) { + votes[it2->var()] += divider; + } + } +} + +/** +@brief Tallies votes for a TRUE/FALSE default polarity using Jeroslow-Wang + +Voting is only used if polarity_mode is "polarity_auto". This is the default. +Uses the tallyVotes() functions to tally the votes +*/ +void Solver::calculateDefaultPolarities() +{ + #ifdef VERBOSE_DEBUG_POLARITIES + std::cout << "Default polarities: " << std::endl; + #endif + + assert(decisionLevel() == 0); + if (conf.polarity_mode == polarity_auto) { + double myTime = cpuTime(); + + vec<double> votes(nVars(), 0.0); + + tallyVotes(clauses, votes); + tallyVotesBin(votes); + tallyVotes(xorclauses, votes); + + Var i = 0; + uint32_t posPolars = 0; + uint32_t undecidedPolars = 0; + for (const double *it = votes.getData(), *end = votes.getDataEnd(); it != end; it++, i++) { + polarity[i] = (*it >= 0.0); + posPolars += (*it < 0.0); + undecidedPolars += (*it == 0.0); + #ifdef VERBOSE_DEBUG_POLARITIES + std::cout << !defaultPolarities[i] << ", "; + #endif //VERBOSE_DEBUG_POLARITIES + } + + if (conf.verbosity >= 2) { + std::cout << "c Calc default polars - " + << " time: " << std::fixed << std::setw(6) << std::setprecision(2) << (cpuTime() - myTime) << " s" + << " pos: " << std::setw(7) << posPolars + << " undec: " << std::setw(7) << undecidedPolars + << " neg: " << std::setw(7) << nVars()- undecidedPolars - posPolars + << std:: endl; + } + } else { + for (uint32_t i = 0; i < polarity.size(); i++) { + polarity[i] = defaultPolarity(); + } + } + + #ifdef VERBOSE_DEBUG_POLARITIES + std::cout << std::endl; + #endif //VERBOSE_DEBUG_POLARITIES +} + +void Solver::calcReachability() +{ + double myTime = cpuTime(); + + for (uint32_t i = 0; i < nVars()*2; i++) { + litReachable[i] = LitReachData(); + } + + for (uint32_t i = 0; i < order_heap.size(); i++) for (uint32_t sig1 = 0; sig1 < 2; sig1++) { + Lit lit = Lit(order_heap[i], sig1); + if (value(lit.var()) != l_Undef + || subsumer->getVarElimed()[lit.var()] + || xorSubsumer->getVarElimed()[lit.var()] + || !decision_var[lit.var()]) + continue; + + vector<Lit>& cache = transOTFCache[(~lit).toInt()].lits; + uint32_t cacheSize = cache.size(); + for (vector<Lit>::const_iterator it = cache.begin(), end = cache.end(); it != end; it++) { + /*if (solver.value(it->var()) != l_Undef + || solver.subsumer->getVarElimed()[it->var()] + || solver.xorSubsumer->getVarElimed()[it->var()]) + continue;*/ + if ((*it == lit) || (*it == ~lit)) continue; + if (litReachable[it->toInt()].lit == lit_Undef || litReachable[it->toInt()].numInCache < cacheSize) { + litReachable[it->toInt()].lit = lit; + litReachable[it->toInt()].numInCache = cacheSize; + } + } + } + + /*for (uint32_t i = 0; i < nVars()*2; i++) { + std::sort(litReachable[i].begin(), litReachable[i].end(), MySorterX(transOTFCache)); + }*/ + + /*for (uint32_t i = 0; i < nVars()*2; i++) { + vector<Lit>& myset = litReachable[i]; + for (uint32_t i2 = 0; i2 < myset.size(); i2++) { + std::cout << transOTFCache[myset[i2].toInt()].lits.size() << " , "; + } + std::cout << std::endl; + }*/ + + if (conf.verbosity >= 1) { + std::cout << "c calculated reachability. Time: " << (cpuTime() - myTime) << std::endl; + } +} + +void Solver::saveOTFData() +{ + assert(decisionLevel() == 1); + + Lit lev0Lit = trail[trail_lim[0]]; + Solver::TransCache& oTFCache = transOTFCache[(~lev0Lit).toInt()]; + oTFCache.conflictLastUpdated = conflicts; + oTFCache.lits.clear(); + + for (int sublevel = trail.size()-1; sublevel > (int)trail_lim[0]; sublevel--) { + Lit lit = trail[sublevel]; + oTFCache.lits.push_back(lit); + } +} + +//********************************** +// Major methods: +//********************************** + +/** +@brief Picks a branching variable and its value (True/False) + +We do three things here: +-# Try to do random decision (rare, less than 2%) +-# Try acitivity-based decision + +Then, we pick a sign (True/False): +\li If we are in search-burst mode ("simplifying" is set), we pick a sign +totally randomly +\li Otherwise, we simply take the saved polarity +*/ +Lit Solver::pickBranchLit() +{ + #ifdef VERBOSE_DEBUG + cout << "decision level: " << decisionLevel() << " "; + #endif + + Var next = var_Undef; + + /* Skip variables which have already been defined (this will usually happen + * because of propagations/implicit assignments) */ + for (unsigned int i = decisionLevel(); i < branching_variables.size(); ++i) { + Var v = branching_variables[i]; + if (v < nVars() + && !subsumer->getVarElimed()[v] + && !xorSubsumer->getVarElimed()[v] + && assigns[v] == l_Undef) { + next = v; + break; + } + } + + bool random = mtrand.randDblExc() < conf.random_var_freq; + + // Random decision: + if (next == var_Undef && random && !order_heap.empty()) { + if (conf.restrictPickBranch == 0) + next = order_heap[mtrand.randInt(order_heap.size()-1)]; + else + next = order_heap[mtrand.randInt(std::min((uint32_t)order_heap.size()-1, conf.restrictPickBranch))]; + + if (assigns[next] == l_Undef && decision_var[next]) + rnd_decisions++; + } + + bool signSet = false; + bool signSetTo = false; + // Activity based decision: + while (next == var_Undef + || assigns[next] != l_Undef + || !decision_var[next]) { + if (order_heap.empty()) { + next = var_Undef; + break; + } + + next = order_heap.removeMin(); + if (!simplifying && value(next) == l_Undef && decision_var[next]) { + signSet = true; + if (avgBranchDepth.isvalid()) + signSetTo = polarity[next] ^ (mtrand.randInt(avgBranchDepth.getAvgUInt() * ((lastSelectedRestartType == static_restart) ? 2 : 1) ) == 1); + else + signSetTo = polarity[next]; + Lit nextLit = Lit(next, signSetTo); + Lit lit2 = litReachable[nextLit.toInt()].lit; + if (lit2 != lit_Undef && value(lit2.var()) == l_Undef && decision_var[lit2.var()] && mtrand.randInt(1) == 1) { + insertVarOrder(next); + next = litReachable[nextLit.toInt()].lit.var(); + signSetTo = litReachable[nextLit.toInt()].lit.sign(); + } + } + } + + //if "simplifying" is set, i.e. if we are in a burst-search mode, then + //randomly pick a sign. Otherwise, if RANDOM_LOOKAROUND_SEARCHSPACE is + //defined, we check the default polarity, and we may change it a bit + //randomly based on the average branch depth. Otherwise, we just go for the + //polarity that has been saved + bool sign; + if (next != var_Undef) { + if (signSet) { + sign = signSetTo; + } else { + if (simplifying && random) + sign = mtrand.randInt(1); + else if (avgBranchDepth.isvalid()) + sign = polarity[next] ^ (mtrand.randInt(avgBranchDepth.getAvgUInt() * ((lastSelectedRestartType == static_restart) ? 2 : 1) ) == 1); + else + sign = polarity[next]; + } + } + + assert(next == var_Undef || value(next) == l_Undef); + + if (next == var_Undef) { + #ifdef VERBOSE_DEBUG + cout << "SAT!" << endl; + #endif + return lit_Undef; + } else { + Lit lit(next,sign); + #ifdef VERBOSE_DEBUG + assert(decision_var[lit.var()]); + cout << "decided on: " << lit.var()+1 << " to set:" << !lit.sign() << endl; + #endif + return lit; + } +} + +/** +@brief Checks subsumption. Used in on-the-fly subsumption code + +Assumes 'seen' is cleared (will leave it cleared) +*/ +template<class T1, class T2> +bool subset(const T1& A, const T2& B, vector<char>& seen) +{ + for (uint32_t i = 0; i != B.size(); i++) + seen[B[i].toInt()] = 1; + for (uint32_t i = 0; i != A.size(); i++) { + if (!seen[A[i].toInt()]) { + for (uint32_t i = 0; i != B.size(); i++) + seen[B[i].toInt()] = 0; + return false; + } + } + for (uint32_t i = 0; i != B.size(); i++) + seen[B[i].toInt()] = 0; + return true; +} + + +/** +@brief Analyze conflict and produce a reason clause. + +Pre-conditions: +\li 'out_learnt' is assumed to be cleared. +\li Current decision level must be greater than root level. + +Post-conditions: +\li 'out_learnt[0]' is the asserting literal at level 'out_btlevel'. + +Effect: Will undo part of the trail, upto but not beyond the assumption of the +current decision level. + +@return NULL if the conflict doesn't on-the-fly subsume the last clause, and +the pointer of the clause if it does +*/ +Clause* Solver::analyze(PropBy conflHalf, vec<Lit>& out_learnt, int& out_btlevel, uint32_t &glue, const bool update) +{ + int pathC = 0; + Lit p = lit_Undef; + + // Generate conflict clause: + // + out_learnt.push(); // (leave room for the asserting literal) + int index = trail.size() - 1; + out_btlevel = 0; + + PropByFull confl(conflHalf, failBinLit, clauseAllocator); + PropByFull oldConfl; + + do { + assert(!confl.isNULL()); // (otherwise should be UIP) + + if (update && restartType == static_restart && confl.isClause() && confl.getClause()->learnt()) + claBumpActivity(*confl.getClause()); + + for (uint32_t j = (p == lit_Undef) ? 0 : 1, size = confl.size(); j != size; j++) { + Lit q = confl[j]; + const Var my_var = q.var(); + + if (!seen[my_var] && level[my_var] > 0) { + varBumpActivity(my_var); + seen[my_var] = 1; + assert(level[my_var] <= (int)decisionLevel()); + if (level[my_var] >= (int)decisionLevel()) { + pathC++; + if (lastSelectedRestartType == dynamic_restart + && reason[q.var()].isClause() + && !reason[q.var()].isNULL() + && clauseAllocator.getPointer(reason[q.var()].getClause())->learnt()) + lastDecisionLevel.push(q.var()); + } else { + out_learnt.push(q); + if (level[my_var] > out_btlevel) + out_btlevel = level[my_var]; + } + } + } + + // Select next clause to look at: + while (!seen[trail[index--].var()]); + p = trail[index+1]; + oldConfl = confl; + confl = PropByFull(reason[p.var()], failBinLit, clauseAllocator); + if (confl.isClause()) __builtin_prefetch(confl.getClause()); + seen[p.var()] = 0; + pathC--; + + } while (pathC > 0); + assert(pathC == 0); + out_learnt[0] = ~p; + + // Simplify conflict clause: + // + uint32_t i, j; + if (conf.expensive_ccmin) { + uint32_t abstract_level = 0; + for (i = 1; i < out_learnt.size(); i++) + abstract_level |= abstractLevel(out_learnt[i].var()); // (maintain an abstraction of levels involved in conflict) + + out_learnt.copyTo(analyze_toclear); + for (i = j = 1; i < out_learnt.size(); i++) + if (reason[out_learnt[i].var()].isNULL() || !litRedundant(out_learnt[i], abstract_level)) + out_learnt[j++] = out_learnt[i]; + } else { + out_learnt.copyTo(analyze_toclear); + for (i = j = 1; i < out_learnt.size(); i++) { + PropByFull c(reason[out_learnt[i].var()], failBinLit, clauseAllocator); + + for (uint32_t k = 1, size = c.size(); k < size; k++) { + if (!seen[c[k].var()] && level[c[k].var()] > 0) { + out_learnt[j++] = out_learnt[i]; + break; + } + } + } + } + max_literals += out_learnt.size(); + out_learnt.shrink(i - j); + for (uint32_t j = 0; j != analyze_toclear.size(); j++) + seen[analyze_toclear[j].var()] = 0; // ('seen[]' is now cleared) + + if (conf.doMinimLearntMore && out_learnt.size() > 1) + minimiseLeartFurther(out_learnt, calcNBLevels(out_learnt)); + + glue = calcNBLevels(out_learnt); + tot_literals += out_learnt.size(); + + // Find correct backtrack level: + // + if (out_learnt.size() == 1) + out_btlevel = 0; + else { + uint32_t max_i = 1; + for (uint32_t i = 2; i < out_learnt.size(); i++) + if (level[out_learnt[i].var()] > level[out_learnt[max_i].var()]) + max_i = i; + std::swap(out_learnt[max_i], out_learnt[1]); + out_btlevel = level[out_learnt[1].var()]; + } + + if (lastSelectedRestartType == dynamic_restart) { + #ifdef UPDATE_VAR_ACTIVITY_BASED_ON_GLUE + for(uint32_t i = 0; i != lastDecisionLevel.size(); i++) { + PropBy cl = reason[lastDecisionLevel[i]]; + if (cl.isClause() && clauseAllocator.getPointer(cl.getClause())->getGlue() < glue) + varBumpActivity(lastDecisionLevel[i]); + } + lastDecisionLevel.clear(); + #endif + } + + //We can only on-the-fly subsume clauses that are not 2- or 3-long + //furthermore, we cannot subsume a clause that is marked for deletion + //due to its high glue value + if (!conf.doOTFSubsume + || out_learnt.size() == 1 + || !oldConfl.isClause() + || oldConfl.getClause()->isXor() + #ifdef ENABLE_UNWIND_GLUE + || (conf.doMaxGlueDel && oldConfl.getClause()->getGlue() > conf.maxGlue) + #endif //ENABLE_UNWIND_GLUE + || out_learnt.size() >= oldConfl.getClause()->size()) return NULL; + + if (!subset(out_learnt, *oldConfl.getClause(), seen)) return NULL; + + improvedClauseNo++; + improvedClauseSize += oldConfl.getClause()->size() - out_learnt.size(); + return oldConfl.getClause(); +} + +/** +@brief Performs on-the-fly self-subsuming resolution + +Only uses binary and tertiary clauses already in the watchlists in native +form to carry out the forward-self-subsuming resolution +*/ +void Solver::minimiseLeartFurther(vec<Lit>& cl, const uint32_t glue) +{ + //80 million is kind of a hack. It seems that the longer the solving + //the slower this operation gets. So, limiting the "time" with total + //number of conflict literals is maybe a good way of doing this + bool clDoMinLRec = false; + if (conf.doCacheOTFSSR && conf.doMinimLMoreRecur) { + switch(lastSelectedRestartType) { + case dynamic_restart : + clDoMinLRec |= glue < 0.6*glueHistory.getAvgAllDouble(); + //NOTE: No "break;" here on purpose + case static_restart : + clDoMinLRec |= cl.size() < 0.6*conflSizeHist.getAvgDouble(); + break; + default : + assert(false); + } + } + + if (clDoMinLRec) moreRecurMinLDo++; + uint64_t thisUpdateTransOTFSSCache = UPDATE_TRANSOTFSSR_CACHE; + if (tot_literals > 80000000) thisUpdateTransOTFSSCache *= 2; + + //To count the "amount of time" invested in doing transitive on-the-fly + //self-subsuming resolution + uint32_t moreRecurProp = 0; + + for (uint32_t i = 0; i < cl.size(); i++) seen[cl[i].toInt()] = 1; + for (Lit *l = cl.getData(), *end = cl.getDataEnd(); l != end; l++) { + if (seen[l->toInt()] == 0) continue; + Lit lit = *l; + + if (clDoMinLRec) { + if (moreRecurProp > 450 + || (transOTFCache[l->toInt()].conflictLastUpdated != std::numeric_limits<uint64_t>::max() + && (transOTFCache[l->toInt()].conflictLastUpdated + thisUpdateTransOTFSSCache >= conflicts)) + ) { + for (vector<Lit>::const_iterator it = transOTFCache[l->toInt()].lits.begin(), end2 = transOTFCache[l->toInt()].lits.end(); it != end2; it++) { + seen[(~(*it)).toInt()] = 0; + } + } else { + updateTransCache++; + transMinimAndUpdateCache(lit, moreRecurProp); + } + } + + //watched is messed: lit is in watched[~lit] + vec<Watched>& ws = watches[(~lit).toInt()]; + for (vec<Watched>::iterator i = ws.getData(), end = ws.getDataEnd(); i != end; i++) { + if (i->isBinary()) { + seen[(~i->getOtherLit()).toInt()] = 0; + continue; + } + + if (i->isTriClause()) { + if (seen[(~i->getOtherLit()).toInt()] && seen[i->getOtherLit2().toInt()]) { + seen[(~i->getOtherLit()).toInt()] = 0; + } + if (seen[(~i->getOtherLit2()).toInt()] && seen[i->getOtherLit().toInt()]) { + seen[(~i->getOtherLit2()).toInt()] = 0; + } + continue; + } + + //watches are mostly sorted, so it's more-or-less OK to break + // if non-bi or non-tri is encountered + break; + } + } + + uint32_t removedLits = 0; + Lit *i = cl.getData(); + Lit *j= i; + //never remove the 0th literal + seen[cl[0].toInt()] = 1; + for (Lit* end = cl.getDataEnd(); i != end; i++) { + if (seen[i->toInt()]) *j++ = *i; + else removedLits++; + seen[i->toInt()] = 0; + } + numShrinkedClause += (removedLits > 0); + numShrinkedClauseLits += removedLits; + cl.shrink_(i-j); + + #ifdef VERBOSE_DEBUG + std::cout << "c Removed further " << removedLits << " lits" << std::endl; + #endif +} + +void Solver::transMinimAndUpdateCache(const Lit lit, uint32_t& moreRecurProp) +{ + vector<Lit>& allAddedToSeen2 = transOTFCache[lit.toInt()].lits; + allAddedToSeen2.clear(); + + toRecursiveProp.push(lit); + while(!toRecursiveProp.empty()) { + Lit thisLit = toRecursiveProp.top(); + toRecursiveProp.pop(); + //watched is messed: lit is in watched[~lit] + vec<Watched>& ws = watches[(~thisLit).toInt()]; + moreRecurProp += ws.size() +10; + for (vec<Watched>::iterator i = ws.getData(), end = ws.getDataEnd(); i != end; i++) { + if (i->isBinary()) { + moreRecurProp += 5; + Lit otherLit = i->getOtherLit(); + //don't do indefinite recursion, and don't remove "a" when doing self-subsuming-resolution with 'a OR b' + if (seen2[otherLit.toInt()] != 0 || otherLit == ~lit) break; + seen2[otherLit.toInt()] = 1; + allAddedToSeen2.push_back(otherLit); + toRecursiveProp.push(~otherLit); + } else { + break; + } + } + } + assert(toRecursiveProp.empty()); + + for (vector<Lit>::const_iterator it = allAddedToSeen2.begin(), end = allAddedToSeen2.end(); it != end; it++) { + seen[(~(*it)).toInt()] = 0; + seen2[it->toInt()] = 0; + } + + transOTFCache[lit.toInt()].conflictLastUpdated = conflicts; +} + +/** +@brief Check if 'p' can be removed from a learnt clause + +'abstract_levels' is used to abort early if the algorithm is +visiting literals at levels that cannot be removed later. +*/ +bool Solver::litRedundant(Lit p, uint32_t abstract_levels) +{ + analyze_stack.clear(); + analyze_stack.push(p); + int top = analyze_toclear.size(); + while (analyze_stack.size() > 0) { + assert(!reason[analyze_stack.last().var()].isNULL()); + PropByFull c(reason[analyze_stack.last().var()], failBinLit, clauseAllocator); + + analyze_stack.pop(); + + for (uint32_t i = 1, size = c.size(); i < size; i++) { + Lit p = c[i]; + if (!seen[p.var()] && level[p.var()] > 0) { + if (!reason[p.var()].isNULL() && (abstractLevel(p.var()) & abstract_levels) != 0) { + seen[p.var()] = 1; + analyze_stack.push(p); + analyze_toclear.push(p); + } else { + for (uint32_t j = top; j != analyze_toclear.size(); j++) + seen[analyze_toclear[j].var()] = 0; + analyze_toclear.shrink(analyze_toclear.size() - top); + return false; + } + } + } + } + + return true; +} + + +/*_________________________________________________________________________________________________ +| +| analyzeFinal : (p : Lit) -> [void] +| +| Description: +| Specialized analysis procedure to express the final conflict in terms of assumptions. +| Calculates the (possibly empty) set of assumptions that led to the assignment of 'p', and +| stores the result in 'out_conflict'. +|________________________________________________________________________________________________@*/ +void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict) +{ + out_conflict.clear(); + out_conflict.push(p); + + if (decisionLevel() == 0) + return; + + seen[p.var()] = 1; + + for (int32_t i = (int32_t)trail.size()-1; i >= (int32_t)trail_lim[0]; i--) { + Var x = trail[i].var(); + if (seen[x]) { + if (reason[x].isNULL()) { + assert(level[x] > 0); + out_conflict.push(~trail[i]); + } else { + PropByFull c(reason[x], failBinLit, clauseAllocator); + for (uint32_t j = 1, size = c.size(); j < size; j++) + if (level[c[j].var()] > 0) + seen[c[j].var()] = 1; + } + seen[x] = 0; + } + } + + seen[p.var()] = 0; +} + +/*_________________________________________________________________________________________________ +| +| propagate : [void] -> [Clause*] +| +| Description: +| Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned, +| otherwise NULL. +| +| Post-conditions: +| * the propagation queue is empty, even if there was a conflict. +|________________________________________________________________________________________________@*/ +/** +@brief Propagates a binary clause + +Need to be somewhat tricky if the clause indicates that current assignement +is incorrect (i.e. both literals evaluate to FALSE). If conflict if found, +sets failBinLit +*/ +template<bool full> +inline bool Solver::propBinaryClause(vec<Watched>::iterator &i, const Lit p, PropBy& confl) +{ + lbool val = value(i->getOtherLit()); + if (val.isUndef()) { + if (full) uncheckedEnqueue(i->getOtherLit(), PropBy(p)); + else uncheckedEnqueueLight(i->getOtherLit()); + #ifdef DUMP_STATS_FULL + assert(((i->glue > 0) == i->getLearnt())); + if (full && i->glue > 0 && !simplifying) { + std::cout << "Prop by learnt size: " << 2 << std::endl; + std::cout << "Prop by learnt glue: " << i->glue << std::endl; + } + #endif //DUMP_STATS_FULL + } else if (val == l_False) { + confl = PropBy(p); + failBinLit = i->getOtherLit(); + qhead = trail.size(); + #ifdef DUMP_STATS_FULL + assert(((i->glue > 0) == i->getLearnt())); + if (full && i->glue > 0 && !simplifying) { + std::cout << "Confl by learnt size: " << 2 << std::endl; + std::cout << "Confl by learnt glue: " << i->glue << std::endl; + } + #endif //DUMP_STATS_FULL + + return false; + } + + return true; +} + +/** +@brief Propagates a tertiary (3-long) clause + +Need to be somewhat tricky if the clause indicates that current assignement +is incorrect (i.e. all 3 literals evaluate to FALSE). If conflict is found, +sets failBinLit +*/ +template<bool full> +inline bool Solver::propTriClause(vec<Watched>::iterator &i, const Lit p, PropBy& confl) +{ + lbool val = value(i->getOtherLit()); + if (val == l_True) return true; + + lbool val2 = value(i->getOtherLit2()); + if (val.isUndef() && val2 == l_False) { + if (full) uncheckedEnqueue(i->getOtherLit(), PropBy(p, i->getOtherLit2())); + else uncheckedEnqueueLight(i->getOtherLit()); + #ifdef DUMP_STATS_FULL + assert(conf.isPlain); + if (full && i->glue > 0 && !simplifying) { + std::cout << "Prop by learnt size: " << 3 << std::endl; + std::cout << "Prop by learnt glue: " << i->glue << std::endl; + } + #endif //DUMP_STATS_FULL + } else if (val == l_False && val2.isUndef()) { + if (full) uncheckedEnqueue(i->getOtherLit2(), PropBy(p, i->getOtherLit())); + else uncheckedEnqueueLight(i->getOtherLit2()); + #ifdef DUMP_STATS_FULL + assert(conf.isPlain); + if (full && i->glue > 0 && !simplifying) { + std::cout << "Prop by learnt size: " << 3 << std::endl; + std::cout << "Prop by learnt glue: " << i->glue << std::endl; + } + #endif //DUMP_STATS_FULL + } else if (val == l_False && val2 == l_False) { + confl = PropBy(p, i->getOtherLit2()); + failBinLit = i->getOtherLit(); + qhead = trail.size(); + #ifdef DUMP_STATS_FULL + assert(conf.isPlain); + if (full && i->glue > 0 && !simplifying) { + std::cout << "Confl by learnt size: " << 3 << std::endl; + std::cout << "Confl by learnt glue: " << i->glue << std::endl; + } + #endif //DUMP_STATS_FULL + + return false; + } + + return true; +} + +/** +@brief Propagates a tertiary (3-long) clause + +We have blocked literals in this case in the watchlist. That must be checked +and updated. +*/ +template<bool full> +inline bool Solver::propNormalClause(vec<Watched>::iterator &i, vec<Watched>::iterator &j, const Lit p, PropBy& confl, const bool update) +{ + if (value(i->getBlockedLit()).getBool()) { + // Clause is sat + *j++ = *i; + return true; + } + const uint32_t offset = i->getNormOffset(); + Clause& c = *clauseAllocator.getPointer(offset); + + // Make sure the false literal is data[1]: + if (c[0] == ~p) { + std::swap(c[0], c[1]); + } + + assert(c[1] == ~p); + + // If 0th watch is true, then clause is already satisfied. + if (value(c[0]).getBool()) { + *j = Watched(offset, c[0]); + j++; + return true; + } + // Look for new watch: + for (Lit *k = c.getData() + 2, *end2 = c.getDataEnd(); k != end2; k++) { + if (value(*k) != l_False) { + c[1] = *k; + *k = ~p; + watches[(~c[1]).toInt()].push(Watched(offset, c[0])); + return true; + } + } + + // Did not find watch -- clause is unit under assignment: + *j++ = *i; + if (value(c[0]) == l_False) { + #ifdef DUMP_STATS_FULL + if (full && c.learnt() && !simplifying) { + std::cout << "Confl by learnt size: " << c.size() << std::endl; + std::cout << "Confl by learnt glue: " << c.getGlue() << std::endl; + assert(!conf.isPlain || c.getGlue() > 1); + } + #endif //DUMP_STATS_FULL + confl = PropBy(offset); + qhead = trail.size(); + return false; + } else { + #ifdef DUMP_STATS_FULL + if (full && c.learnt() && !simplifying) { + std::cout << "Prop by learnt size: " << c.size() << std::endl; + std::cout << "Prop by learnt glue: " << c.getGlue() << std::endl; + assert(!conf.isPlain || c.getGlue() > 1); + } + #endif //DUMP_STATS_FULL + + if (full) uncheckedEnqueue(c[0], offset); + else uncheckedEnqueueLight(c[0]); + #ifdef DYNAMICALLY_UPDATE_GLUE + if (update && full && c.learnt() && c.getGlue() > 2) { + uint32_t glue = calcNBLevels(c); + if (glue+1 < c.getGlue()) { + //c.setGlue(std::min(nbLevels, MAX_THEORETICAL_GLUE); + c.setGlue(glue); + } + } + #endif + } + + return true; +} + +/** +@brief Propagates a tertiary (3-long) clause + +Strangely enough, we need to have 4 literals in the wathclists: +for the first two varialbles, BOTH negations (v and ~v). This means quite some +pain, since we need to remove v when moving ~v and vica-versa. However, it means +better memory-accesses since the watchlist is already in the memory... + +\todo maybe not worth it, and a variable-based watchlist should be used +*/ +template<bool full> +inline bool Solver::propXorClause(vec<Watched>::iterator &i, vec<Watched>::iterator &j, const Lit p, PropBy& confl) +{ + ClauseOffset offset = i->getXorOffset(); + XorClause& c = *(XorClause*)clauseAllocator.getPointer(offset); + + // Make sure the false literal is data[1]: + if (c[0].var() == p.var()) { + Lit tmp(c[0]); + c[0] = c[1]; + c[1] = tmp; + } + assert(c[1].var() == p.var()); + + bool final = c.xorEqualFalse(); + for (uint32_t k = 0, size = c.size(); k != size; k++ ) { + const lbool& val = assigns[c[k].var()]; + if (val.isUndef() && k >= 2) { + Lit tmp(c[1]); + c[1] = c[k]; + c[k] = tmp; + removeWXCl(watches[(~p).toInt()], offset); + watches[Lit(c[1].var(), false).toInt()].push(offset); + watches[Lit(c[1].var(), true).toInt()].push(offset); + return true; + } + + c[k] = c[k].unsign() ^ val.getBool(); + final ^= val.getBool(); + } + + // Did not find watch -- clause is unit under assignment: + *j++ = *i; + + if (assigns[c[0].var()].isUndef()) { + c[0] = c[0].unsign()^final; + if (full) uncheckedEnqueue(c[0], offset); + else uncheckedEnqueueLight(c[0]); + } else if (!final) { + confl = PropBy(offset); + qhead = trail.size(); + return false; + } else { + Lit tmp(c[0]); + c[0] = c[1]; + c[1] = tmp; + } + + return true; +} + +/** +@brief Does the propagation + +Basically, it goes through the watchlists recursively, and calls the appropirate +propagaton function +*/ +template<bool full> +PropBy Solver::propagate(const bool update) +{ + PropBy confl; + uint32_t num_props = 0; + + #ifdef VERBOSE_DEBUG + cout << "Propagation started" << endl; + #endif + + while (qhead < trail.size()) { + Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate. + vec<Watched>& ws = watches[p.toInt()]; + num_props += ws.size()/2 + 2; + + #ifdef VERBOSE_DEBUG + cout << "Propagating lit " << p << endl; + cout << "ws origSize: "<< ws.size() << endl; + #endif + + vec<Watched>::iterator i = ws.getData(); + vec<Watched>::iterator j = i; + + vec<Watched>::iterator end = ws.getDataEnd(); + for (; i != end; i++) { + if (i->isBinary()) { + *j++ = *i; + if (!propBinaryClause<full>(i, p, confl)) break; + else continue; + } //end BINARY + + if (i->isTriClause()) { + *j++ = *i; + if (!propTriClause<full>(i, p, confl)) break; + else continue; + } //end TRICLAUSE + + if (i->isClause()) { + num_props += 4; + if (!propNormalClause<full>(i, j, p, confl, update)) break; + else continue; + } //end CLAUSE + + if (i->isXorClause()) { + num_props += 10; + if (!propXorClause<full>(i, j, p, confl)) break; + else continue; + } //end XORCLAUSE + } + if (i != end) { + i++; + //copy remaining watches + vec<Watched>::iterator j2 = i; + vec<Watched>::iterator i2 = j; + for(i2 = i, j2 = j; i2 != end; i2++) { + *j2++ = *i2; + } + //memmove(j, i, sizeof(Watched)*(end-i)); + } + //assert(i >= j); + ws.shrink_(i-j); + } + propagations += num_props; + simpDB_props -= num_props; + + #ifdef VERBOSE_DEBUG + cout << "Propagation ended." << endl; + #endif + + return confl; +} +template PropBy Solver::propagate<true>(const bool update); +template PropBy Solver::propagate<false>(const bool update); + +PropBy Solver::propagateBin(vec<Lit>& uselessBin) +{ + #ifdef DEBUG_USELESS_LEARNT_BIN_REMOVAL + assert(uselessBin.empty()); + #endif + + while (qhead < trail.size()) { + Lit p = trail[qhead++]; + + //setting up binPropData + uint32_t lev = binPropData[p.var()].lev; + Lit lev1Ancestor; + switch (lev) { + case 0 : + lev1Ancestor = lit_Undef; + break; + case 1: + lev1Ancestor = p; + break; + default: + lev1Ancestor = binPropData[p.var()].lev1Ancestor; + } + lev++; + const bool learntLeadHere = binPropData[p.var()].learntLeadHere; + bool& hasChildren = binPropData[p.var()].hasChildren; + hasChildren = false; + + //std::cout << "lev: " << lev << " ~p: " << ~p << std::endl; + const vec<Watched> & ws = watches[p.toInt()]; + propagations += 2; + for(vec<Watched>::const_iterator k = ws.getData(), end = ws.getDataEnd(); k != end; k++) { + hasChildren = true; + if (!k->isBinary()) continue; + + //std::cout << (~p) << ", " << k->getOtherLit() << " learnt: " << k->getLearnt() << std::endl; + lbool val = value(k->getOtherLit()); + if (val.isUndef()) { + uncheckedEnqueueLight2(k->getOtherLit(), lev, lev1Ancestor, learntLeadHere || k->getLearnt()); + } else if (val == l_False) { + return PropBy(p); + } else { + assert(val == l_True); + Lit lit2 = k->getOtherLit(); + if (lev > 1 + && level[lit2.var()] != 0 + && binPropData[lit2.var()].lev == 1 + && lev1Ancestor != lit2) { + //Was propagated at level 1, and again here, original level 1 binary clause is useless + binPropData[lit2.var()].lev = lev; + binPropData[lit2.var()].lev1Ancestor = lev1Ancestor; + binPropData[lit2.var()].learntLeadHere = learntLeadHere || k->getLearnt(); + uselessBin.push(lit2); + } + } + } + } + //std::cout << " -----------" << std::endl; + + return PropBy(); +} + +/** +@brief Only propagates binary clauses + +This is used in special algorithms outside the main Solver class +*/ +PropBy Solver::propagateNonLearntBin() +{ + multiLevelProp = false; + uint32_t origQhead = qhead + 1; + + while (qhead < trail.size()) { + Lit p = trail[qhead++]; + const vec<Watched> & ws = watches[p.toInt()]; + propagations += ws.size()/2 + 2; + for(vec<Watched>::const_iterator k = ws.getData(), end = ws.getDataEnd(); k != end; k++) { + if (!k->isNonLearntBinary()) break; + + lbool val = value(k->getOtherLit()); + if (val.isUndef()) { + if (qhead != origQhead) multiLevelProp = true; + uncheckedEnqueueLight(k->getOtherLit()); + } else if (val == l_False) { + return PropBy(p); + } + } + } + + return PropBy(); +} + +/** +@brief Propagate recursively on non-learnt binaries, but do not propagate exceptLit if we reach it +*/ +bool Solver::propagateBinExcept(const Lit exceptLit) +{ + while (qhead < trail.size()) { + Lit p = trail[qhead++]; + const vec<Watched> & ws = watches[p.toInt()]; + propagations += ws.size()/2 + 2; + for(vec<Watched>::const_iterator i = ws.getData(), end = ws.getDataEnd(); i != end; i++) { + if (!i->isNonLearntBinary()) break; + + lbool val = value(i->getOtherLit()); + if (val.isUndef() && i->getOtherLit() != exceptLit) { + uncheckedEnqueueLight(i->getOtherLit()); + } else if (val == l_False) { + return false; + } + } + } + + return true; +} + +/** +@brief Propagate only for one hop(=non-recursively) on non-learnt bins +*/ +bool Solver::propagateBinOneLevel() +{ + Lit p = trail[qhead]; + const vec<Watched> & ws = watches[p.toInt()]; + propagations += ws.size()/2 + 2; + for(vec<Watched>::const_iterator i = ws.getData(), end = ws.getDataEnd(); i != end; i++) { + if (!i->isNonLearntBinary()) break; + + lbool val = value(i->getOtherLit()); + if (val.isUndef()) { + uncheckedEnqueueLight(i->getOtherLit()); + } else if (val == l_False) { + return false; + } + } + + return true; +} + +struct LevelSorter +{ + LevelSorter(const vec<int32_t>& _level) : + level(_level) + {} + + bool operator()(const Lit lit1, const Lit lit2) const { + return level[lit1.var()] < level[lit2.var()]; + } + + const vec<int32_t>& level; +}; + +/** +@brief Calculates the glue of a clause + +Used to calculate the Glue of a new clause, or to update the glue of an +existing clause. Only used if the glue-based activity heuristic is enabled, +i.e. if we are in GLUCOSE mode (not MiniSat mode) +*/ +template<class T> +inline uint32_t Solver::calcNBLevels(const T& ps) +{ + uint32_t nbLevels = 0; + for(const Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) { + int32_t lev = level[l->var()]; + if (!seen[lev]) { + nbLevels++; + seen[lev] = 1; + } + } + for(const Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) { + int32_t lev = level[l->var()]; + seen[lev] = 0; + } + return nbLevels; +} + +/*_________________________________________________________________________________________________ +| +| reduceDB : () -> [void] +| +| Description: +| Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked +| clauses are clauses that are reason to some assignment. Binary clauses are never removed. +|________________________________________________________________________________________________@*/ +bool reduceDB_ltMiniSat::operator () (const Clause* x, const Clause* y) { + const uint32_t xsize = x->size(); + const uint32_t ysize = y->size(); + + assert(xsize > 2 && ysize > 2); + if (x->getMiniSatAct() == y->getMiniSatAct()) + return xsize > ysize; + else return x->getMiniSatAct() < y->getMiniSatAct(); +} + +bool reduceDB_ltGlucose::operator () (const Clause* x, const Clause* y) { + const uint32_t xsize = x->size(); + const uint32_t ysize = y->size(); + + assert(xsize > 2 && ysize > 2); + if (x->getGlue() > y->getGlue()) return 1; + if (x->getGlue() < y->getGlue()) return 0; + return xsize > ysize; +} + +/** +@brief Removes learnt clauses that have been found not to be too good + +Either based on glue or MiniSat-style learnt clause activities, the clauses are +sorted and then removed +*/ +void Solver::reduceDB() +{ + uint32_t i, j; + + nbReduceDB++; + if (lastSelectedRestartType == dynamic_restart) + std::sort(learnts.getData(), learnts.getDataEnd(), reduceDB_ltGlucose()); + else + std::sort(learnts.getData(), learnts.getDataEnd(), reduceDB_ltMiniSat()); + + #ifdef VERBOSE_DEBUG + std::cout << "Cleaning clauses" << std::endl; + for (uint32_t i = 0; i != learnts.size(); i++) { + std::cout << "activity:" << learnts[i]->getGlue() + << " \toldActivity:" << learnts[i]->getMiniSatAct() + << " \tsize:" << learnts[i]->size() << std::endl; + } + #endif + + + const uint32_t removeNum = (double)learnts.size() * (double)RATIOREMOVECLAUSES; + uint32_t totalNumRemoved = 0; + uint32_t totalNumNonRemoved = 0; + uint64_t totalGlueOfRemoved = 0; + uint64_t totalSizeOfRemoved = 0; + uint64_t totalGlueOfNonRemoved = 0; + uint64_t totalSizeOfNonRemoved = 0; + for (i = j = 0; i != removeNum; i++){ + if (i+1 < removeNum) __builtin_prefetch(learnts[i+1]); + assert(learnts[i]->size() > 2); + if (!locked(*learnts[i]) + && (lastSelectedRestartType == static_restart || learnts[i]->getGlue() > 2) + && learnts[i]->size() > 3) { //we cannot update activity of 3-longs because of wathclists + + totalGlueOfRemoved += learnts[i]->getGlue(); + totalSizeOfRemoved += learnts[i]->size(); + totalNumRemoved++; + removeClause(*learnts[i]); + } else { + totalGlueOfNonRemoved += learnts[i]->getGlue(); + totalSizeOfNonRemoved += learnts[i]->size(); + totalNumNonRemoved++; + learnts[j++] = learnts[i]; + } + } + for (; i < learnts.size(); i++) { + totalGlueOfNonRemoved += learnts[i]->getGlue(); + totalSizeOfNonRemoved += learnts[i]->size(); + totalNumNonRemoved++; + learnts[j++] = learnts[i]; + } + learnts.shrink_(i - j); + + if (conf.verbosity >= 3) { + std::cout << "c rem-learnts " << std::setw(6) << totalNumRemoved + << " avgGlue " + << std::fixed << std::setw(5) << std::setprecision(2) << ((double)totalGlueOfRemoved/(double)totalNumRemoved) + << " avgSize " + << std::fixed << std::setw(6) << std::setprecision(2) << ((double)totalSizeOfRemoved/(double)totalNumRemoved) + << " || remain " << std::setw(6) << totalNumNonRemoved + << " avgGlue " + << std::fixed << std::setw(5) << std::setprecision(2) << ((double)totalGlueOfNonRemoved/(double)totalNumNonRemoved) + << " avgSize " + << std::fixed << std::setw(6) << std::setprecision(2) << ((double)totalSizeOfNonRemoved/(double)totalNumNonRemoved) + << std::endl; + } + + clauseAllocator.consolidate(this); +} + +inline int64_t abs64(int64_t a) +{ + if (a < 0) return -a; + return a; +} + +/** +@brief Simplify the clause database according to the current top-level assigment. + +We remove satisfied clauses, clean clauses from assigned literals, find +binary xor-clauses and replace variables with one another. Heuristics are +used to check if we need to find binary xor clauses or not. +*/ +bool Solver::simplify() +{ + testAllClauseAttach(); + assert(decisionLevel() == 0); + + if (!ok || !propagate<false>().isNULL()) { + ok = false; + return false; + } + + if (simpDB_props > 0) { + return true; + } + double myTime = cpuTime(); + + double slowdown = (100000.0/((double)numBins * 30000.0/((double)order_heap.size()))); + slowdown = std::min(1.5, slowdown); + slowdown = std::max(0.01, slowdown); + + double speedup = 200000000.0/(double)(propagations-lastSearchForBinaryXor); + speedup = std::min(3.5, speedup); + speedup = std::max(0.2, speedup); + + /*std::cout << "new:" << nbBin - lastNbBin + becameBinary << std::endl; + std::cout << "left:" << ((double)(nbBin - lastNbBin + becameBinary)/BINARY_TO_XOR_APPROX) * slowdown << std::endl; + std::cout << "right:" << (double)order_heap.size() * PERCENTAGEPERFORMREPLACE * speedup << std::endl;*/ + + if (conf.doFindEqLits && conf.doRegFindEqLits && + (((double)abs64((int64_t)numNewBin - (int64_t)lastNbBin)/BINARY_TO_XOR_APPROX) * slowdown) > + ((double)order_heap.size() * PERCENTAGEPERFORMREPLACE * speedup)) { + lastSearchForBinaryXor = propagations; + + clauseCleaner->cleanClauses(clauses, ClauseCleaner::clauses); + clauseCleaner->cleanClauses(learnts, ClauseCleaner::learnts); + clauseCleaner->removeSatisfiedBins(); + if (!ok) return false; + + if (!sCCFinder->find2LongXors()) return false; + + lastNbBin = numNewBin; + } + + // Remove satisfied clauses: + clauseCleaner->removeAndCleanAll(); + if (!ok) return false; + + if (conf.doReplace && !varReplacer->performReplace()) + return false; + + // Remove fixed variables from the variable heap: + order_heap.filter(VarFilter(*this)); + + #ifdef USE_GAUSS + for (vector<Gaussian*>::iterator gauss = gauss_matrixes.begin(), end = gauss_matrixes.end(); gauss != end; gauss++) { + if (!(*gauss)->full_init()) return false; + } + #endif //USE_GAUSS + + simpDB_assigns = nAssigns(); + simpDB_props = std::min((uint64_t)80000000, 4*clauses_literals + 4*learnts_literals); //at most 6 sec wait + simpDB_props = std::max((int64_t)30000000, simpDB_props); //at least 2 sec wait + totalSimplifyTime += cpuTime() - myTime; + + testAllClauseAttach(); + return true; +} + +/** +@brief Search for a model + +Limits: must be below the specified number of conflicts and must keep the +number of learnt clauses below the provided limit + +Use negative value for 'nof_conflicts' or 'nof_learnts' to indicate infinity. + +Output: 'l_True' if a partial assigment that is consistent with respect to the +clauseset is found. If all variables are decision variables, this means +that the clause set is satisfiable. 'l_False' if the clause set is +unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached. +*/ +lbool Solver::search(const uint64_t nof_conflicts, const uint64_t nof_conflicts_fullrestart, const bool update) +{ + assert(ok); + uint64_t conflictC = 0; + vec<Lit> learnt_clause; + llbool ret; + + if (!simplifying && update) { + starts++; + if (restartType == static_restart) staticStarts++; + else dynStarts++; + } + glueHistory.fastclear(); + + #ifdef USE_GAUSS + for (vector<Gaussian*>::iterator gauss = gauss_matrixes.begin(), end = gauss_matrixes.end(); gauss != end; gauss++) { + if (!(*gauss)->full_init()) + return l_False; + } + #endif //USE_GAUSS + + testAllClauseAttach(); + findAllAttach(); + #ifdef VERBOSE_DEBUG + std::cout << "c started Solver::search()" << std::endl; + //printAllClauses(); + #endif //VERBOSE_DEBUG + for (;;) { + assert(ok); + PropBy confl = propagate<true>(update); + #ifdef VERBOSE_DEBUG + std::cout << "c Solver::search() has finished propagation" << std::endl; + //printAllClauses(); + #endif //VERBOSE_DEBUG + + if (conflicts > conf.maxConfl) { + if (conf.verbosity >= 0) { + std::cout << "c Interrupting: limit on number of conflicts, " + << conf.maxConfl + << " reached! " << std::endl; + } + needToInterrupt = true; + return l_Undef; + } + + if (!confl.isNULL()) { + ret = handle_conflict(learnt_clause, confl, conflictC, update); + if (ret != l_Nothing) return ret; + } else { + #ifdef USE_GAUSS + bool at_least_one_continue = false; + for (vector<Gaussian*>::iterator gauss = gauss_matrixes.begin(), end= gauss_matrixes.end(); gauss != end; gauss++) { + ret = (*gauss)->find_truths(learnt_clause, conflictC); + if (ret == l_Continue) at_least_one_continue = true; + else if (ret != l_Nothing) return ret; + } + if (at_least_one_continue) continue; + #endif //USE_GAUSS + + assert(ok); + if (conf.doCacheOTFSSR && decisionLevel() == 1) saveOTFData(); + ret = new_decision(nof_conflicts, nof_conflicts_fullrestart, conflictC); + if (ret != l_Nothing) return ret; + } + } +} + +/** +@brief Picks a new decision variable to branch on + +@returns l_Undef if it should restart instead. l_False if it reached UNSAT + (through simplification) +*/ +llbool Solver::new_decision(const uint64_t nof_conflicts, const uint64_t nof_conflicts_fullrestart, const uint64_t conflictC) +{ + + if (conflicts >= nof_conflicts_fullrestart || needToInterrupt) { + cancelUntil(0); + return l_Undef; + } + + // Reached bound on number of conflicts? + switch (restartType) { + case dynamic_restart: + if (glueHistory.isvalid() && + 0.95*glueHistory.getAvgDouble() > glueHistory.getAvgAllDouble()) { + + #ifdef DEBUG_DYNAMIC_RESTART + if (glueHistory.isvalid()) { + std::cout << "glueHistory.getavg():" << glueHistory.getavg() <<std::endl; + std::cout << "totalSumOfGlue:" << totalSumOfGlue << std::endl; + std::cout << "conflicts:" << conflicts<< std::endl; + std::cout << "compTotSumGlue:" << compTotSumGlue << std::endl; + std::cout << "conflicts-compTotSumGlue:" << conflicts-compTotSumGlue<< std::endl; + } + #endif + + cancelUntil(0); + return l_Undef; + } + break; + case static_restart: + if (conflictC >= nof_conflicts) { + cancelUntil(0); + return l_Undef; + } + break; + case auto_restart: + assert(false); + break; + } + + // Simplify the set of problem clauses: + if (decisionLevel() == 0) { + if (!dataSync->syncData()) return l_False; + if (!simplify()) return l_False; + } + + // Reduce the set of learnt clauses: + if (conflicts >= numCleanedLearnts * nbClBeforeRed + nbCompensateSubsumer) { + numCleanedLearnts ++; + reduceDB(); + nbClBeforeRed += 500; + } + + Lit next = lit_Undef; + while (decisionLevel() < assumptions.size()) { + // Perform user provided assumption: + Lit p = assumptions[decisionLevel()]; + if (value(p) == l_True) { + // Dummy decision level: + newDecisionLevel(); + } else if (value(p) == l_False) { + analyzeFinal(~p, conflict); + return l_False; + } else { + next = p; + break; + } + } + + if (next == lit_Undef) { + // New variable decision: + decisions++; + next = pickBranchLit(); + + if (next == lit_Undef) + return l_True; + } + + // Increase decision level and enqueue 'next' + assert(value(next) == l_Undef); + newDecisionLevel(); + uncheckedEnqueue(next); + + return l_Nothing; +} + +/** +@brief Handles a conflict that we reached through propagation + +Handles on-the-fly subsumption: the OTF subsumption check is done in +conflict analysis, but this is the code that actually replaces the original +clause with that of the shorter one +@returns l_False if UNSAT +*/ +llbool Solver::handle_conflict(vec<Lit>& learnt_clause, PropBy confl, uint64_t& conflictC, const bool update) +{ + #ifdef VERBOSE_DEBUG + cout << "Handling conflict: "; + for (uint32_t i = 0; i < learnt_clause.size(); i++) + cout << learnt_clause[i].var()+1 << ","; + cout << endl; + #endif + + int backtrack_level; + uint32_t glue; + + conflicts++; + conflictC++; + if (decisionLevel() == 0) + return l_False; + learnt_clause.clear(); + Clause* c = analyze(confl, learnt_clause, backtrack_level, glue, update); + if (update) { + avgBranchDepth.push(decisionLevel()); + if (restartType == dynamic_restart) glueHistory.push(glue); + conflSizeHist.push(learnt_clause.size()); + } + cancelUntil(backtrack_level); + #ifdef DUMP_STATS + std::cout << "Learnt clause: " << learnt_clause + << " glue: " << glue + << " declevel: " << decisionLevel() + << " traillen: " << trail.size() + << " abst: " << calcAbstraction(learnt_clause) + << std::endl; + assert(learnt_clause.size() == 1 || glue > 1); + #endif //#ifdef DUMP_STATS + + #ifdef VERBOSE_DEBUG + cout << "Learning:"; + for (uint32_t i = 0; i < learnt_clause.size(); i++) printLit(learnt_clause[i]), cout << " "; + cout << endl; + cout << "reverting var " << learnt_clause[0].var()+1 << " to " << !learnt_clause[0].sign() << endl; + #endif + + assert(value(learnt_clause[0]) == l_Undef); + //Unitary learnt + if (learnt_clause.size() == 1) { + uncheckedEnqueue(learnt_clause[0]); + assert(backtrack_level == 0 && "Unit clause learnt, so must cancel until level 0, right?"); + + #ifdef VERBOSE_DEBUG + cout << "Unit clause learnt." << endl; + #endif + //Normal learnt + } else { + if (learnt_clause.size() == 2) { + attachBinClause(learnt_clause[0], learnt_clause[1], true); + numNewBin++; + dataSync->signalNewBinClause(learnt_clause); + uncheckedEnqueue(learnt_clause[0], PropBy(learnt_clause[1])); + goto end; + } + + if (learnt_clause.size() > 3) { + std::sort(learnt_clause.getData()+1, learnt_clause.getDataEnd(), PolaritySorter(polarity)); + } + if (c) { //On-the-fly subsumption + uint32_t origSize = c->size(); + detachClause(*c); + for (uint32_t i = 0; i != learnt_clause.size(); i++) + (*c)[i] = learnt_clause[i]; + c->shrink(origSize - learnt_clause.size()); + if (c->learnt() && c->getGlue() > glue) + c->setGlue(glue); // LS + attachClause(*c); + uncheckedEnqueue(learnt_clause[0], clauseAllocator.getOffset(c)); + } else { //no on-the-fly subsumption + c = clauseAllocator.Clause_new(learnt_clause, true); + #ifdef ENABLE_UNWIND_GLUE + if (conf.doMaxGlueDel && glue > conf.maxGlue) { + nbClOverMaxGlue++; + nbCompensateSubsumer++; + unWindGlue[learnt_clause[0].var()] = c; + #ifdef UNWINDING_DEBUG + std::cout << "unwind, var:" << learnt_clause[0].var() << std::endl; + c->plainPrint(); + #endif //VERBOSE_DEBUG + } else { + #endif //ENABLE_UNWIND_GLUE + learnts.push(c); + #ifdef ENABLE_UNWIND_GLUE + } + #endif //ENABLE_UNWIND_GLUE + c->setGlue(std::min(glue, MAX_THEORETICAL_GLUE)); + attachClause(*c); + uncheckedEnqueue(learnt_clause[0], clauseAllocator.getOffset(c)); + } + end:; + } + + varDecayActivity(); + if (update && restartType == static_restart) claDecayActivity(); + + return l_Nothing; +} + +/** +@brief After a full restart, determines which restar type to use + +Uses class RestartTypeChooser to do the heavy-lifting +*/ +bool Solver::chooseRestartType(const uint32_t& lastFullRestart) +{ + uint32_t relativeStart = starts - lastFullRestart; + + if (relativeStart > RESTART_TYPE_DECIDER_FROM && relativeStart < RESTART_TYPE_DECIDER_UNTIL) { + if (conf.fixRestartType == auto_restart) + restartTypeChooser->addInfo(); + + if (relativeStart == (RESTART_TYPE_DECIDER_UNTIL-1)) { + RestartType tmp; + if (conf.fixRestartType == auto_restart) + tmp = restartTypeChooser->choose(); + else + tmp = conf.fixRestartType; + + if (tmp == dynamic_restart) { + glueHistory.fastclear(); + if (conf.verbosity >= 3) + std::cout << "c Decided on dynamic restart strategy" + << std::endl; + } else { + if (conf.verbosity >= 1) + std::cout << "c Decided on static restart strategy" + << std::endl; + + if (!matrixFinder->findMatrixes()) return false; + } + lastSelectedRestartType = tmp; + restartType = tmp; + restartTypeChooser->reset(); + } + } + + return true; +} + +inline void Solver::setDefaultRestartType() +{ + if (conf.fixRestartType != auto_restart) restartType = conf.fixRestartType; + else restartType = static_restart; + + glueHistory.clear(); + glueHistory.initSize(MIN_GLUE_RESTART); + conflSizeHist.clear(); + conflSizeHist.initSize(1000); + + lastSelectedRestartType = restartType; +} + +/** +@brief The function that brings together almost all CNF-simplifications + +It burst-searches for given number of conflicts, then it tries all sorts of +things like variable elimination, subsumption, failed literal probing, etc. +to try to simplifcy the problem at hand. +*/ +lbool Solver::simplifyProblem(const uint32_t numConfls) +{ + testAllClauseAttach(); + bool gaussWasCleared = clearGaussMatrixes(); + + StateSaver savedState(*this);; + + #ifdef BURST_SEARCH + if (conf.verbosity >= 3) + std::cout << "c " << std::setw(24) << " " + << "Simplifying problem for " << std::setw(8) << numConfls << " confls" + << std::endl; + conf.random_var_freq = 1; + simplifying = true; + uint64_t origConflicts = conflicts; + #endif //BURST_SEARCH + + lbool status = l_Undef; + + #ifdef BURST_SEARCH + restartType = static_restart; + + printRestartStat("S"); + while(status == l_Undef && conflicts-origConflicts < numConfls && needToInterrupt == false) { + status = search(100, std::numeric_limits<uint64_t>::max(), false); + } + if (needToInterrupt) return l_Undef; + printRestartStat("S"); + if (status != l_Undef) goto end; + #endif //BURST_SEARCH + + if (conf.doXorSubsumption && !xorSubsumer->simplifyBySubsumption()) goto end; + + if (conf.doFailedLit && conf.doCacheOTFSSR) { + BothCache both(*this); + if (!both.tryBoth()) goto end; + } + if (conf.doCacheOTFSSR) cleanCache(); + if (conf.doClausVivif && !clauseVivifier->vivifyClauses()) goto end; + + if (conf.doCacheOTFSSRSet && order_heap.size() < 200000) { + if (conf.doCacheOTFSSR == false && conf.verbosity > 0) { + std::cout << "c turning cache ON because the number of active variables is lower now" << std::endl; + } + conf.doCacheOTFSSR = true; + } + if (conf.doFailedLit && !failedLitSearcher->search()) goto end; + + if (conf.doSatELite && !subsumer->simplifyBySubsumption()) goto end; + + /*if (findNormalXors && xorclauses.size() > 200 && clauses.size() < MAX_CLAUSENUM_XORFIND/8) { + XorFinder xorFinder(*this, clauses, ClauseCleaner::clauses); + if (!xorFinder.doNoPart(3, 7)) { + status = l_False; + goto end; + } + } else*/ if (xorclauses.size() <= 200 && xorclauses.size() > 0 && nClauses() > 10000) { + XorFinder x(*this, clauses); + x.addAllXorAsNorm(); + } + + if (conf.doClausVivif && !clauseVivifier->vivifyClauses()) goto end; + + //addSymmBreakClauses(); + + if (conf.doSortWatched) sortWatched(); + if (conf.doCacheOTFSSR && conf.doCalcReach) calcReachability(); + +end: + #ifdef BURST_SEARCH + if (conf.verbosity >= 3) + std::cout << "c Simplifying finished" << std::endl; + #endif //#ifdef BURST_SEARCH + + savedState.restore(); + simplifying = false; + + if (status == l_Undef && ok && gaussWasCleared && !matrixFinder->findMatrixes()) + status = l_False; + + testAllClauseAttach(); + + if (!ok) return l_False; + return status; +} + +/** +@brief Should we perform a full restart? + +If so, we also do the things to be done if the full restart is effected. +*/ +bool Solver::checkFullRestart(uint64_t& nof_conflicts, uint64_t& nof_conflicts_fullrestart, uint32_t& lastFullRestart) +{ + if (nof_conflicts_fullrestart > 0 && conflicts >= nof_conflicts_fullrestart) { + #ifdef USE_GAUSS + clearGaussMatrixes(); + #endif //USE_GAUSS + nof_conflicts = conf.restart_first + (double)conf.restart_first*conf.restart_inc; + nof_conflicts_fullrestart = (double)nof_conflicts_fullrestart * FULLRESTART_MULTIPLIER_MULTIPLIER; + restartType = static_restart; + lastFullRestart = starts; + + if (conf.verbosity >= 3) + std::cout << "c Fully restarting" << std::endl; + printRestartStat("F"); + + /*if (findNormalXors && clauses.size() < MAX_CLAUSENUM_XORFIND) { + XorFinder xorFinder(this, clauses, ClauseCleaner::clauses); + if (!xorFinder.doNoPart(3, 10)) + return false; + }*/ + + //calculateDefaultPolarities(); + if (conf.polarity_mode != polarity_auto) { + for (uint32_t i = 0; i < polarity.size(); i++) { + polarity[i] = defaultPolarity(); + } + } + + fullStarts++; + } + + return true; +} + +/** +@brief Performs a set of pre-optimisations before the beggining of solving + +This is somewhat different than the set of optimisations carried out during +solving in simplifyProblem(). For instance, binary xors are searched fully +here, while there, no search for them is carried out. Also, the ordering +is different. + +\todo experiment to use simplifyProblem() instead of this, with the only +addition of binary clause search. Maybe it will do just as good (or better). +*/ +void Solver::performStepsBeforeSolve() +{ + assert(qhead == trail.size()); + testAllClauseAttach(); + + printRestartStat(); + if (conf.doReplace && !varReplacer->performReplace()) return; + + order_heap.filter(Solver::VarFilter(*this)); + if (order_heap.size() > 300000) { + if (conf.verbosity > 0) { + std::cout << "c turning cache OFF because there are too many active variables" << std::endl; + } + conf.doCacheOTFSSR = false; + } + + bool saveDoHyperBin = conf.doHyperBinRes; + conf.doHyperBinRes = false; + clauseAllocator.consolidate(this, true); + if (conf.doFailedLit && !failedLitSearcher->search()) return; + conf.doHyperBinRes = saveDoHyperBin; + if (conf.doClausVivif && !conf.libraryUsage + && !clauseVivifier->vivifyClauses()) return; + + #ifdef VERBOSE_DEBUG + printAllClauses(); + #endif //VERBOSE_DEBUG + if (conf.doSatELite + && !conf.libraryUsage + && clauses.size() < 4800000 + && !subsumer->simplifyBySubsumption()) + return; + + if (conf.doFindEqLits) { + if (!sCCFinder->find2LongXors()) return; + lastNbBin = numNewBin; + if (conf.doReplace && !varReplacer->performReplace(true)) return; + } + + if (conf.doFindXors && clauses.size() < MAX_CLAUSENUM_XORFIND) { + XorFinder xorFinder(*this, clauses); + if (!xorFinder.fullFindXors(3, 7)) return; + } + + if (xorclauses.size() > 1) { + if (conf.doXorSubsumption && !xorSubsumer->simplifyBySubsumption()) + return; + + if (conf.doReplace && !varReplacer->performReplace()) + return; + } + + if (conf.doSortWatched) sortWatched(); + if (conf.doCacheOTFSSR && conf.doCalcReach) calcReachability(); + + testAllClauseAttach(); +} + +/** +@brief Initialises model, restarts, learnt cluause cleaning, burst-search, etc. +*/ +void Solver::initialiseSolver() +{ + //Clear up previous stuff like model, final conflict, matrixes + model.clear(); + conflict.clear(); + clearGaussMatrixes(); + + //Initialise restarts & dynamic restart datastructures + setDefaultRestartType(); + + //Initialise avg. branch depth + avgBranchDepth.clear(); + avgBranchDepth.initSize(500); + + //Initialise number of restarts&full restarts + starts = 0; + fullStarts = 0; + + if (nClauses() * conf.learntsize_factor < nbClBeforeRed) { + if (nClauses() * conf.learntsize_factor < nbClBeforeRed/2) + nbClBeforeRed /= 4; + else + nbClBeforeRed = (nClauses() * conf.learntsize_factor)/2; + } + + testAllClauseAttach(); + findAllAttach(); +} + +/** +@brief The main solve loop that glues everything together + +We clear everything needed, pre-simplify the problem, calculate default +polarities, and start the loop. Finally, we either report UNSAT or extend the +found solution with all the intermediary simplifications (e.g. variable +elimination, etc.) and output the solution. +*/ +lbool Solver::solve(const vec<Lit>& assumps) +{ + #ifdef VERBOSE_DEBUG + std::cout << "Solver::solve() called" << std::endl; + #endif + if (!ok) return l_False; + assert(qhead == trail.size()); + assert(subsumer->checkElimedUnassigned()); + assert(xorSubsumer->checkElimedUnassigned()); + + if (libraryCNFFile) + fprintf(libraryCNFFile, "c Solver::solve() called\n"); + + assumps.copyTo(assumptions); + initialiseSolver(); + uint64_t nof_conflicts = conf.restart_first; //Geometric restart policy, start with this many + uint64_t nof_conflicts_fullrestart = conf.restart_first * FULLRESTART_MULTIPLIER + conflicts; //at this point, do a full restart + uint32_t lastFullRestart = starts; //last time a full restart was made was at this number of restarts + lbool status = l_Undef; //Current status + uint64_t nextSimplify = conf.restart_first * conf.simpStartMult + conflicts; //Do simplifyProblem() at this number of conflicts + if (!conf.doSchedSimp) nextSimplify = std::numeric_limits<uint64_t>::max(); + + if (conflicts == 0) { + if (conf.doPerformPreSimp) performStepsBeforeSolve(); + if (!ok) return l_False; + + calculateDefaultPolarities(); + } + + printStatHeader(); + printRestartStat("B"); + uint64_t lastConflPrint = conflicts; + // Search: + while (status == l_Undef && starts < conf.maxRestarts) { + #ifdef DEBUG_VARELIM + assert(subsumer->checkElimedUnassigned()); + assert(xorSubsumer->checkElimedUnassigned()); + #endif //DEBUG_VARELIM + + if ((conflicts - lastConflPrint) > std::min(std::max(conflicts/100*6, (uint64_t)4000), (uint64_t)20000)) { + printRestartStat("N"); + lastConflPrint = conflicts; + } + + if (conf.doSchedSimp && conflicts >= nextSimplify) { + status = simplifyProblem(conf.simpBurstSConf); + printRestartStat(); + lastConflPrint = conflicts; + nextSimplify = std::min((uint64_t)((double)conflicts * conf.simpStartMMult), conflicts + MAX_CONFL_BETWEEN_SIMPLIFY); + if (status != l_Undef) break; + } + + status = search(nof_conflicts, std::min(nof_conflicts_fullrestart, nextSimplify)); + if (needToInterrupt) { + cancelUntil(0); + return l_Undef; + } + + nof_conflicts = (double)nof_conflicts * conf.restart_inc; + if (status != l_Undef) break; + if (!checkFullRestart(nof_conflicts, nof_conflicts_fullrestart , lastFullRestart)) + return l_False; + if (!chooseRestartType(lastFullRestart)) + return l_False; + } + printEndSearchStat(); + + #ifdef VERBOSE_DEBUG + if (status == l_True) + std::cout << "Solution is SAT" << std::endl; + else if (status == l_False) + std::cout << "Solution is UNSAT" << std::endl; + else + std::cout << "Solutions is UNKNOWN" << std::endl; + #endif //VERBOSE_DEBUG + + if (status == l_True) handleSATSolution(); + else if (status == l_False) handleUNSATSolution(); + + cancelUntil(0); + restartTypeChooser->reset(); + if (status == l_Undef) clauseCleaner->removeAndCleanAll(true); + + #ifdef VERBOSE_DEBUG + std::cout << "Solver::solve() finished" << std::endl; + #endif + return status; +} + +/** +@brief Extends a SAT solution to the full solution + +variable elimination, variable replacement, sub-part solving, etc. all need to +be handled correctly to arrive at a solution that is a solution to ALL of the +original problem, not just of what remained of it at the end inside this class +(i.e. we need to combine things from the helper classes) +*/ +void Solver::handleSATSolution() +{ + + /*if (greedyUnbound) { + double time = cpuTime(); + FindUndef finder(*this); + const uint32_t unbounded = finder.unRoll(); + if (conf.verbosity >= 1) + printf("c Greedy unbounding :%5.2lf s, unbounded: %7d vars\n", cpuTime()-time, unbounded); + }*/ + assert(subsumer->checkElimedUnassigned()); + assert(xorSubsumer->checkElimedUnassigned()); + + varReplacer->extendModelPossible(); + checkSolution(); + + if (subsumer->getNumElimed() || xorSubsumer->getNumElimed()) { + if (conf.verbosity >= 1) { + std::cout << "c Solution needs extension. Extending." << std::endl; + } + Solver s; + s.conf = conf; + s.conf.doSatELite = false; + s.conf.doReplace = false; + s.conf.doFindEqLits = false; + s.conf.doRegFindEqLits = false; + s.conf.doFailedLit= false; + s.conf.doConglXors = false; + s.conf.doSubsWNonExistBins = false; + s.conf.doRemUselessBins = false; + s.conf.doClausVivif = false; + s.conf.doSortWatched = false; + s.conf.verbosity = 0; + + vec<Lit> tmp; + for (Var var = 0; var < nVars(); var++) { + s.newVar(decision_var[var] + || subsumer->getVarElimed()[var] + || varReplacer->varHasBeenReplaced(var) + || xorSubsumer->getVarElimed()[var] + ); + + //assert(!(xorSubsumer->getVarElimed()[var] && (decision_var[var] || subsumer->getVarElimed()[var] || varReplacer->varHasBeenReplaced(var)))); + + if (value(var) != l_Undef) { + #ifdef VERBOSE_DEBUG + std::cout << "Setting var " << var + 1 + << " in extend-solver to " << value(var) << std::endl; + #endif + tmp.clear(); + tmp.push(Lit(var, value(var) == l_False)); + s.addClause(tmp); + } + } + varReplacer->extendModelImpossible(s); + subsumer->extendModel(s); + xorSubsumer->extendModel(s); + + lbool status = s.solve(); + release_assert(status == l_True && "c ERROR! Extension of model failed!"); +#ifdef VERBOSE_DEBUG + std::cout << "Solution extending finished. Enqueuing results" << std::endl; +#endif + //need to start new decision level, otherwise uncheckedEnqueue will + //enqueue to decision level 0 in certain cases :S + newDecisionLevel(); + for (Var var = 0; var < nVars(); var++) { + if (assigns[var] == l_Undef && s.model[var] != l_Undef) + uncheckedEnqueue(Lit(var, s.model[var] == l_False)); + } + ok = (propagate<false>().isNULL()); + release_assert(ok && "c ERROR! Extension of model failed!"); + } + checkSolution(); + //Copy model: + model.growTo(nVars()); + for (Var var = 0; var != nVars(); var++) model[var] = value(var); +} + +/** +@brief When problem is decided to be UNSAT, this is called + +There is basically nothing to be handled for the moment, but this could be +made extensible +*/ +void Solver::handleUNSATSolution() +{ + if (conflict.size() == 0) + ok = false; +} + +void Solver::cleanCache() +{ + for(uint32_t i = 0; i < nVars(); i++) { + if (subsumer->getVarElimed()[i] || value(i) != l_Undef) { + vector<Lit> tmp1; + transOTFCache[Lit(i, false).toInt()].lits.swap(tmp1); + vector<Lit> tmp2; + transOTFCache[Lit(i, true).toInt()].lits.swap(tmp2); + continue; + } + + for(int which = 0; which < 2; which++) { + cleanCachePart(Lit(i, which)); + + } + } +} + +void Solver::cleanCachePart(const Lit vertLit) +{ + vector<Lit>& transCache = transOTFCache[(~vertLit).toInt()].lits; + assert(seen_vec.empty()); + + vector<Lit>::iterator it = transCache.begin(); + vector<Lit>::iterator it2 = it; + + size_t newSize = 0; + for (vector<Lit>::iterator end = transCache.end(); it != end; it++) { + Lit lit = *it; + lit = varReplacer->getReplaceTable()[lit.var()] ^ lit.sign(); + if (lit == vertLit + || seen[lit.toInt()] + || subsumer->getVarElimed()[lit.var()] + || subsumer->getVarElimed()[lit.var()] + ) continue; + + *it2++ = lit; + + //Don't allow the same value to be in the cache twice + seen[lit.toInt()] = 1; + seen_vec.push_back(lit); + + //Increase valid size + newSize++; + } + transCache.resize(newSize); + + //Clear up seen + for(vector<Lit>::const_iterator it = seen_vec.begin(), end = seen_vec.end(); it != end; it++) { + seen[it->toInt()] = 0; + } + seen_vec.clear(); +} diff --git a/src/prop/cryptominisat/Solver/Solver.h b/src/prop/cryptominisat/Solver/Solver.h new file mode 100644 index 000000000..9276823dd --- /dev/null +++ b/src/prop/cryptominisat/Solver/Solver.h @@ -0,0 +1,859 @@ +/****************************************************************************************[Solver.h] +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. +**************************************************************************************************/ + +#ifndef SOLVER_H +#define SOLVER_H + +#include <cstdio> +#include <string.h> +#include <stdio.h> +#include <stack> +#include <stdexcept> + +//#define ANIMATE3D + +#include "PropBy.h" +#include "Vec.h" +#include "Heap.h" +#include "Alg.h" +#include "MersenneTwister.h" +#include "SolverTypes.h" +#include "Clause.h" +#include "constants.h" +#include "BoundedQueue.h" +#include "GaussianConfig.h" +#include "ClauseAllocator.h" +#include "SolverConf.h" + +namespace CMSat { + +class Gaussian; +class MatrixFinder; +class Conglomerate; +class VarReplacer; +class XorFinder; +class FindUndef; +class ClauseCleaner; +class FailedLitSearcher; +class Subsumer; +class XorSubsumer; +class RestartTypeChooser; +class StateSaver; +class UselessBinRemover; +class SCCFinder; +class ClauseVivifier; +class SharedData; +class DataSync; +class BothCache; + +#ifdef VERBOSE_DEBUG +#define DEBUG_UNCHECKEDENQUEUE_LEVEL0 +using std::cout; +using std::endl; +#endif + +struct reduceDB_ltMiniSat +{ + bool operator () (const Clause* x, const Clause* y); +}; + +struct reduceDB_ltGlucose +{ + bool operator () (const Clause* x, const Clause* y); +}; + +struct PolaritySorter +{ + PolaritySorter(vector<char>& polarity) : + pol(polarity) + {} + + bool operator()(const Lit lit1, const Lit lit2) const + { + return (((((bool)pol[lit1.var()])^(lit1.sign())) == false) + && ((((bool)pol[lit2.var()])^(lit2.sign())) == true)); + } + vector<char>& pol; +}; + +/** +@brief The main solver class + +This class creates and manages all the others. It is here that settings must +be set, and it is here that all data enter and leaves the system. The basic +use is to add normal and XOR clauses, and then solve(). The solver will then +solve the problem, and return with either a SAT solution with corresponding +variable settings, or report that the problem in UNSATisfiable. + +The prolbem-solving can be interrupted with the "interrupt" varible, and can +also be pre-set to stop after a certain number of restarts. The data until the +interruption can be dumped by previously setting parameters like +dumpSortedLearnts +*/ +class Solver +{ +public: + + // Constructor/Destructor: + // + Solver(const SolverConf& conf = SolverConf(), const GaussConf& _gaussconfig = GaussConf(), SharedData* sharedUnitData = NULL); + ~Solver(); + + // Problem specification: + // + Var newVar (bool dvar = true) throw (std::out_of_range); // Add a new variable with parameters specifying variable mode. + template<class T> + bool addClause (T& ps); // Add a clause to the solver. NOTE! 'ps' may be shrunk by this method! + template<class T> + bool addLearntClause(T& ps, const uint32_t glue = 10, const float miniSatActivity = 10.0); + template<class T> + bool addXorClause (T& ps, bool xorEqualFalse) throw (std::out_of_range); // Add a xor-clause to the solver. NOTE! 'ps' may be shrunk by this method! + + // Solving: + // + lbool solve (const vec<Lit>& assumps); ///<Search for a model that respects a given set of assumptions. + lbool solve (); ///<Search without assumptions. + void handleSATSolution(); ///<Extends model, if needed, and fills "model" + void handleUNSATSolution(); ///<If conflict really was zero-length, sets OK to false + bool okay () const; ///<FALSE means solver is in a conflicting state + + // Variable mode: + // + void setDecisionVar (Var v, bool b); ///<Declare if a variable should be eligible for selection in the decision heuristic. + void addBranchingVariable (Var v); + + // Read state: + // + lbool value (const Var x) const; ///<The current value of a variable. + lbool value (const Lit p) const; ///<The current value of a literal. + lbool modelValue (const Lit p) const; ///<The value of a literal in the last model. The last call to solve must have been satisfiable. + uint32_t nAssigns () const; ///<The current number of assigned literals. + uint32_t nClauses () const; ///<The current number of original clauses. + uint32_t nLiterals () const; ///<The current number of total literals. + uint32_t nLearnts () const; ///<The current number of learnt clauses. + uint32_t nVars () const; ///<The current number of variables. + + // Extra results: (read-only member variable) + // + vec<lbool> model; ///<If problem is satisfiable, this vector contains the model (if any). + vec<Lit> conflict; ///<If problem is unsatisfiable (possibly under assumptions), this vector represent the final conflict clause expressed in the assumptions. + + // Mode of operation: + // + SolverConf conf; + GaussConf gaussconfig; ///<Configuration for the gaussian elimination can be set here + bool needToInterrupt; ///<Used internally mostly. If set to TRUE, we will interrupt cleanly ASAP. The important thing is "cleanly", since we need to wait until a point when all datastructures are in a sane state (i.e. not in the middle of some algorithm) + + //Logging + void needStats(); // Prepares the solver to output statistics + void needProofGraph(); // Prepares the solver to output proof graphs during solving + const vec<Clause*>& get_sorted_learnts(); //return the set of learned clauses, sorted according to the logic used in MiniSat to distinguish between 'good' and 'bad' clauses + const vec<Clause*>& get_learnts() const; //Get all learnt clauses that are >1 long + vector<Lit> get_unitary_learnts() const; //return the set of unitary learnt clauses + uint32_t get_unitary_learnts_num() const; //return the number of unitary learnt clauses + bool dumpSortedLearnts(const std::string& fileName, const uint32_t maxSize); // Dumps all learnt clauses (including unitary ones) into the file; returns true for success, false for failure + bool needLibraryCNFFile(const std::string& fileName); //creates file in current directory with the filename indicated, and puts all calls from the library into the file. + bool dumpOrigClauses(const std::string& fileName) const; + void printBinClause(const Lit litP1, const Lit litP2, FILE* outfile) const; + + uint32_t get_sum_gauss_called() const; + uint32_t get_sum_gauss_confl() const; + uint32_t get_sum_gauss_prop() const; + uint32_t get_sum_gauss_unit_truths() const; + + //Printing statistics + void printStats(); + uint32_t getNumElimSubsume() const; ///<Get number of variables eliminated + uint32_t getNumElimXorSubsume() const; ///<Get number of variables eliminated with xor-magic + uint32_t getNumXorTrees() const; ///<Get the number of trees built from 2-long XOR-s. This is effectively the number of variables that replace other variables + uint32_t getNumXorTreesCrownSize() const; ///<Get the number of variables being replaced by other variables + /** + @brief Get total time spent in Subsumer. + + This includes: subsumption, self-subsuming resolution, variable elimination, + blocked clause elimination, subsumption and self-subsuming resolution + using non-existent binary clauses. + */ + double getTotalTimeSubsumer() const; + double getTotalTimeFailedLitSearcher() const; + double getTotalTimeSCC() const; + + /** + @brief Get total time spent in XorSubsumer. + + This included subsumption, variable elimination through XOR, and local + substitution (see Heule's Thesis) + */ + double getTotalTimeXorSubsumer() const; + +protected: + //gauss + bool clearGaussMatrixes(); + vector<Gaussian*> gauss_matrixes; + void print_gauss_sum_stats(); + uint32_t sum_gauss_called; + uint32_t sum_gauss_confl; + uint32_t sum_gauss_prop; + uint32_t sum_gauss_unit_truths; + + // Statistics + // + template<class T, class T2> + void printStatsLine(std::string left, T value, T2 value2, std::string extra); + template<class T> + void printStatsLine(std::string left, T value, std::string extra = ""); + uint64_t starts; ///<Num restarts + uint64_t dynStarts; ///<Num dynamic restarts + uint64_t staticStarts; ///<Num static restarts: note that after full restart, we do a couple of static restarts always + /** + @brief Num full restarts + + Full restarts are restarts that are made always, no matter what, after + a certan number of conflicts have passed. The problem will tried to be + decomposed into multiple parts, and then there will be a couple of static + restarts made. Finally, the problem will be determined to be MiniSat-type + or Glucose-type. + + NOTE: I belive there is a point in having full restarts even if the + glue-clause vs. MiniSat clause can be fully resolved + */ + uint64_t fullStarts; ///<Number of full restarts made + uint64_t decisions; ///<Number of decisions made + uint64_t rnd_decisions; ///<Numer of random decisions made + /** + @brief An approximation of accumulated propagation difficulty + + It does not hold the number of propagations made. Rather, it holds a + value that is approximate of the difficulty of the propagations made + This makes sense, since it is not at all the same difficulty to proapgate + a 2-long clause than to propagate a 20-long clause. In certain algorihtms, + there is a need to know how difficult the propagation part was. This value + can be used in these algorihms. However, the reported "statistic" will be + bogus. + */ + uint64_t propagations; + uint64_t conflicts; ///<Num conflicts + uint64_t clauses_literals, learnts_literals, max_literals, tot_literals; + uint64_t nbGlue2; ///<Num learnt clauses that had a glue of 2 when created + uint64_t numNewBin; ///<new binary clauses that have been found through some form of resolution (shrinking, conflicts, etc.) + uint64_t lastNbBin; ///<Last time we seached for SCCs, numBins was this much + uint64_t lastSearchForBinaryXor; ///<Last time we looked for binary xors, this many bogoprops(=propagations) has been done + uint64_t nbReduceDB; ///<Number of times learnt clause have been cleaned + uint64_t improvedClauseNo; ///<Num clauses improved using on-the-fly subsumption + uint64_t improvedClauseSize; ///<Num literals removed using on-the-fly subsumption + uint64_t numShrinkedClause; ///<Num clauses improved using on-the-fly self-subsuming resolution + uint64_t numShrinkedClauseLits; ///<Num literals removed by on-the-fly self-subsuming resolution + uint64_t moreRecurMinLDo; ///<Decided to carry out transitive on-the-fly self-subsuming resolution on this many clauses + uint64_t updateTransCache; ///<Number of times the transitive OTF-reduction cache has been updated + uint64_t nbClOverMaxGlue; ///<Number or clauses over maximum glue defined in maxGlue + + //Multi-threading + DataSync* dataSync; + + // Helper structures: + // + struct VarOrderLt { + const vec<uint32_t>& activity; + bool operator () (Var x, Var y) const { + return activity[x] > activity[y]; + } + VarOrderLt(const vec<uint32_t>& act) : activity(act) { } + }; + + struct VarFilter { + const Solver& s; + VarFilter(const Solver& _s) : s(_s) {} + bool operator()(Var v) const { + return s.assigns[v].isUndef() && s.decision_var[v]; + } + }; + + // Solver state: + // + bool ok; ///< If FALSE, the constraints are already unsatisfiable. No part of the solver state may be used! + ClauseAllocator clauseAllocator; ///< Handles memory allocation for claues + vec<Clause*> clauses; ///< List of problem clauses that are normally larger than 2. Sometimes, due to on-the-fly self-subsuming resoulution, clauses here become 2-long. They are never purposfully put here such that they are long + vec<XorClause*> xorclauses; ///< List of problem xor-clauses. Will be freed + vec<Clause*> learnts; ///< List of learnt clauses. + uint32_t numBins; + vec<XorClause*> freeLater; ///< xor clauses that need to be freed later (this is needed due to Gauss) \todo Get rid of this + float cla_inc; ///< Amount to bump learnt clause oldActivity with + vec<vec<Watched> > watches; ///< 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true). + vec<lbool> assigns; ///< The current assignments + vector<char> decision_var; ///< Declares if a variable is eligible for selection in the decision heuristic. + vec<Lit> trail; ///< Assignment stack; stores all assigments made in the order they were made. + vec<uint32_t> trail_lim; ///< Separator indices for different decision levels in 'trail'. + vec<PropBy> reason; ///< 'reason[var]' is the clause that implied the variables current value, or 'NULL' if none. + vec<int32_t> level; ///< 'level[var]' contains the level at which the assignment was made. + vec<BinPropData> binPropData; + uint32_t qhead; ///< Head of queue (as index into the trail) + Lit failBinLit; ///< Used to store which watches[~lit] we were looking through when conflict occured + vec<Lit> assumptions; ///< Current set of assumptions provided to solve by the user. + bqueue<uint32_t> avgBranchDepth; ///< Avg branch depth. We collect this, and use it to do random look-around in the searchspace during simplifyProblem() + MTRand mtrand; ///< random number generator + vector<Var> branching_variables; + + ///////////////// + // Variable activities + ///////////////// + Heap<VarOrderLt> order_heap; ///< A priority queue of variables ordered with respect to the variable activity. All variables here MUST be decision variables. If you changed the decision variables, you MUST filter this + vec<uint32_t> activity; ///< A heuristic measurement of the activity of a variable. + uint32_t var_inc; ///< Amount to bump next variable with. + + ///////////////// + // Learnt clause cleaning + ///////////////// + uint64_t numCleanedLearnts; ///< Number of times learnt clauses have been removed through simplify() up until now + uint32_t nbClBeforeRed; ///< Number of learnt clauses before learnt-clause cleaning + uint32_t nbCompensateSubsumer; ///< Number of learnt clauses that subsumed normal clauses last time subs. was executed (used to delay learnt clause-cleaning) + + ///////////////////////// + // For glue calculation & dynamic restarts + ///////////////////////// + //uint64_t MYFLAG; ///<For glue calculation + template<class T> + uint32_t calcNBLevels(const T& ps); + //vec<uint64_t> permDiff; ///<permDiff[var] is used to count the number of different decision level variables in learnt clause (filled with data from MYFLAG ) + vec<Var> lastDecisionLevel; + bqueue<uint32_t> glueHistory; ///< Set of last decision levels in (glue of) conflict clauses. Used for dynamic restarting + #ifdef ENABLE_UNWIND_GLUE + vec<Clause*> unWindGlue; + #endif //ENABLE_UNWIND_GLUE + + // Temporaries (to reduce allocation overhead). Each variable is prefixed by the method in which it is + // used, exept 'seen' wich is used in several places. + // + vector<char> seen; ///<Used in multiple places. Contains 2 * numVars() elements, all zeroed out + vector<Lit> seen_vec; + vec<Lit> analyze_stack; + vec<Lit> analyze_toclear; + + //////////// + // Transitive on-the-fly self-subsuming resolution + /////////// + class TransCache { + public: + TransCache() : + conflictLastUpdated(std::numeric_limits<uint64_t>::max()) + {}; + + vector<Lit> lits; + uint64_t conflictLastUpdated; + }; + class LitReachData { + public: + LitReachData() : + lit(lit_Undef) + , numInCache(0) + {} + Lit lit; + uint32_t numInCache; + }; + vector<char> seen2; ///<To reduce temoprary data creation overhead. Used in minimiseLeartFurther(). contains 2 * numVars() elements, all zeroed out + vec<Lit> allAddedToSeen2; ///<To reduce temoprary data creation overhead. Used in minimiseLeartFurther() + std::stack<Lit> toRecursiveProp; ///<To reduce temoprary data creation overhead. Used in minimiseLeartFurther() + vector<TransCache> transOTFCache; + bqueue<uint32_t> conflSizeHist; + void minimiseLeartFurther(vec<Lit>& cl, const uint32_t glue); + void transMinimAndUpdateCache(const Lit lit, uint32_t& moreRecurProp); + void saveOTFData(); + vector<LitReachData>litReachable; + void calcReachability(); + void cleanCache(); + void cleanCachePart(const Lit vertLit); + + //////////// + //Logging + /////////// + FILE *libraryCNFFile; //The file that all calls from the library are logged + + ///////////////// + // Propagating + //////////////// + Lit pickBranchLit (); // Return the next decision variable. + void newDecisionLevel (); // Begins a new decision level. + void uncheckedEnqueue (const Lit p, const PropBy& from = PropBy()); // Enqueue a literal. Assumes value of literal is undefined. + void uncheckedEnqueueLight (const Lit p); + void uncheckedEnqueueLight2(const Lit p, const uint32_t binPropDatael, const Lit lev1Ancestor, const bool learntLeadHere); + PropBy propagateBin(vec<Lit>& uselessBin); + PropBy propagateNonLearntBin(); + bool multiLevelProp; + bool propagateBinExcept(const Lit exceptLit); + bool propagateBinOneLevel(); + template<bool full> + PropBy propagate(const bool update = true); // Perform unit propagation. Returns possibly conflicting clause. + template<bool full> + bool propTriClause (vec<Watched>::iterator &i, const Lit p, PropBy& confl); + template<bool full> + bool propBinaryClause(vec<Watched>::iterator &i, const Lit p, PropBy& confl); + template<bool full> + bool propNormalClause(vec<Watched>::iterator &i, vec<Watched>::iterator &j, const Lit p, PropBy& confl, const bool update); + template<bool full> + bool propXorClause (vec<Watched>::iterator &i, vec<Watched>::iterator &j, const Lit p, PropBy& confl); + void sortWatched(); + + /////////////// + // Conflicting + /////////////// + void cancelUntil (int level); // Backtrack until a certain level. + void cancelUntilLight(); + Clause* analyze (PropBy confl, vec<Lit>& out_learnt, int& out_btlevel, uint32_t &nblevels, const bool update); + void analyzeFinal (Lit p, vec<Lit>& out_conflict); // COULD THIS BE IMPLEMENTED BY THE ORDINARIY "analyze" BY SOME REASONABLE GENERALIZATION? + bool litRedundant (Lit p, uint32_t abstract_levels); // (helper method for 'analyze()') + void insertVarOrder (Var x); // Insert a variable in the decision order priority queue. + + ///////////////// + // Searching + ///////////////// + lbool search (const uint64_t nof_conflicts, const uint64_t nof_conflicts_fullrestart, const bool update = true); // Search for a given number of conflicts. + llbool handle_conflict (vec<Lit>& learnt_clause, PropBy confl, uint64_t& conflictC, const bool update);// Handles the conflict clause + llbool new_decision (const uint64_t nof_conflicts, const uint64_t nof_conflicts_fullrestart, const uint64_t conflictC); // Handles the case when all propagations have been made, and now a decision must be made + + ///////////////// + // Maintaining Variable/Clause activity: + ///////////////// + void claBumpActivity (Clause& c); + void varDecayActivity (); // Decay all variables with the specified factor. Implemented by increasing the 'bump' value instead. + void varBumpActivity (Var v); // Increase a variable with the current 'bump' value. + void claDecayActivity (); // Decay all clauses with the specified factor. Implemented by increasing the 'bump' value instead. + + ///////////////// + // Operations on clauses: + ///////////////// + template<class T> bool addClauseHelper(T& ps) throw (std::out_of_range); + template <class T> + Clause* addClauseInt(T& ps, const bool learnt = false, const uint32_t glue = 10, const float miniSatActivity = 10.0, const bool inOriginalInput = false); + template<class T> + XorClause* addXorClauseInt(T& ps, bool xorEqualFalse, const bool learnt = false) throw (std::out_of_range); + void attachBinClause(const Lit lit1, const Lit lit2, const bool learnt); + void attachClause (XorClause& c); + void attachClause (Clause& c); // Attach a clause to watcher lists. + void detachClause (const XorClause& c); + void detachClause (const Clause& c); // Detach a clause to watcher lists. + void detachModifiedClause(const Lit lit1, const Lit lit2, const Lit lit3, const uint32_t origSize, const Clause* address); + void detachModifiedClause(const Var var1, const Var var2, const uint32_t origSize, const XorClause* address); + template<class T> + void removeClause(T& c); // Detach and free a clause. + bool locked (const Clause& c) const; // Returns TRUE if a clause is a reason for some implication in the current state. + + /////////////////////////// + // Debug clause attachment + /////////////////////////// + void testAllClauseAttach() const; + void findAllAttach() const; + bool findClause(XorClause* c) const; + bool findClause(Clause* c) const; + bool xorClauseIsAttached(const XorClause& c) const; + bool normClauseIsAttached(const Clause& c) const; + + // Misc: + // + uint32_t decisionLevel () const; // Gives the current decisionlevel. + uint32_t abstractLevel (const Var x) const; // Used to represent an abstraction of sets of decision levels. + + ///////////////////////// + //Classes that must be friends, since they accomplish things on our datastructures + ///////////////////////// + friend class VarFilter; + friend class Gaussian; + friend class FindUndef; + friend class XorFinder; + friend class Conglomerate; + friend class MatrixFinder; + friend class VarReplacer; + friend class ClauseCleaner; + friend class RestartTypeChooser; + friend class FailedLitSearcher; + friend class Subsumer; + friend class XorSubsumer; + friend class StateSaver; + friend class UselessBinRemover; + friend class OnlyNonLearntBins; + friend class ClauseAllocator; + friend class CompleteDetachReatacher; + friend class SCCFinder; + friend class ClauseVivifier; + friend class DataSync; + friend class BothCache; + Conglomerate* conglomerate; + VarReplacer* varReplacer; + ClauseCleaner* clauseCleaner; + FailedLitSearcher* failedLitSearcher; + Subsumer* subsumer; + XorSubsumer* xorSubsumer; + RestartTypeChooser* restartTypeChooser; + MatrixFinder* matrixFinder; + SCCFinder* sCCFinder; + ClauseVivifier* clauseVivifier; + + ///////////////////////// + // Restart type handling + ///////////////////////// + bool chooseRestartType(const uint32_t& lastFullRestart); + void setDefaultRestartType(); + bool checkFullRestart(uint64_t& nof_conflicts, uint64_t& nof_conflicts_fullrestart, uint32_t& lastFullRestart); + RestartType restartType; ///<Used internally to determine which restart strategy is currently in use + RestartType lastSelectedRestartType; ///<The last selected restart type. Used when we are just after a full restart, and need to know how to really act + + ////////////////////////// + // Problem simplification + ////////////////////////// + void performStepsBeforeSolve(); + lbool simplifyProblem(const uint32_t numConfls); + void reduceDB(); // Reduce the set of learnt clauses. + bool simplify(); // Removes satisfied clauses and finds binary xors + bool simplifying; ///<We are currently doing burst search + double totalSimplifyTime; + uint32_t simpDB_assigns; ///< Number of top-level assignments since last execution of 'simplify()'. + int64_t simpDB_props; ///< Remaining number of propagations that must be made before next execution of 'simplify()'. + + ///////////////////////////// + // SAT solution verification + ///////////////////////////// + void checkSolution (); + bool verifyModel () const; + bool verifyBinClauses() const; + bool verifyClauses (const vec<Clause*>& cs) const; + bool verifyXorClauses () const; + + // Debug & etc: + void printAllClauses(); + void printLit (const Lit l) const; + void checkLiteralCount(); + void printStatHeader () const; + void printRestartStat (const char* type = "N"); + void printEndSearchStat(); + void addSymmBreakClauses(); + void initialiseSolver(); + + //Misc related binary clauses + void dumpBinClauses(const bool alsoLearnt, const bool alsoNonLearnt, FILE* outfile) const; + uint32_t countNumBinClauses(const bool alsoLearnt, const bool alsoNonLearnt) const; + uint32_t getBinWatchSize(const bool alsoLearnt, const Lit lit); + void printStrangeBinLit(const Lit lit) const; + + ///////////////////// + // Polarity chooser + ///////////////////// + void calculateDefaultPolarities(); //Calculates the default polarity for each var, and fills defaultPolarities[] with it + bool defaultPolarity(); //if polarity_mode is not polarity_auto, this returns the default polarity of the variable + void tallyVotesBin(vec<double>& votes) const; + void tallyVotes(const vec<Clause*>& cs, vec<double>& votes) const; + void tallyVotes(const vec<XorClause*>& cs, vec<double>& votes) const; + void setPolarity(Var v, bool b); // Declare which polarity the decision heuristic should use for a variable. Requires mode 'polarity_user'. + vector<char> polarity; // The preferred polarity of each variable. +}; + + + +//********************************** +// Implementation of inline methods +//********************************** + +inline void Solver::insertVarOrder(Var x) +{ + if (!order_heap.inHeap(x) && decision_var[x]) order_heap.insert(x); +} + +inline void Solver::varDecayActivity() +{ + var_inc *= 11; + var_inc /= 10; +} +inline void Solver::varBumpActivity(Var v) +{ + if ( (activity[v] += var_inc) > (0x1U) << 24 ) { + //printf("RESCALE!!!!!!\n"); + //std::cout << "var_inc: " << var_inc << std::endl; + // Rescale: + for (Var var = 0; var != nVars(); var++) { + activity[var] >>= 14; + } + var_inc >>= 14; + //var_inc = 1; + //std::cout << "var_inc: " << var_inc << std::endl; + + /*Heap<VarOrderLt> copy_order_heap2(order_heap); + while(!copy_order_heap2.empty()) { + Var v = copy_order_heap2.getmin(); + if (decision_var[v]) + std::cout << "var_" << v+1 << " act: " << activity[v] << std::endl; + }*/ + } + + // Update order_heap with respect to new activity: + if (order_heap.inHeap(v)) + order_heap.decrease(v); +} + +inline void Solver::claBumpActivity (Clause& c) +{ + if ( (c.getMiniSatAct() += cla_inc) > 1e20 ) { + // Rescale: + for (uint32_t i = 0; i < learnts.size(); i++) + learnts[i]->getMiniSatAct() *= 1e-17; + cla_inc *= 1e-20; + } +} + +inline void Solver::claDecayActivity() +{ + //cla_inc *= clause_decay; +} + +inline bool Solver::locked(const Clause& c) const +{ + if (c.size() <= 3) return true; //we don't know in this case :I + PropBy from(reason[c[0].var()]); + return from.isClause() && !from.isNULL() && from.getClause() == clauseAllocator.getOffset(&c) && value(c[0]) == l_True; +} + +inline void Solver::newDecisionLevel() +{ + trail_lim.push(trail.size()); + #ifdef VERBOSE_DEBUG + cout << "New decision level: " << trail_lim.size() << endl; + #endif +} +/*inline int Solver::nbPropagated(int level) { + if (level == decisionLevel()) + return trail.size() - trail_lim[level-1] - 1; + return trail_lim[level] - trail_lim[level-1] - 1; +}*/ +inline uint32_t Solver::decisionLevel () const +{ + return trail_lim.size(); +} +inline uint32_t Solver::abstractLevel (const Var x) const +{ + return 1 << (level[x] & 31); +} +inline lbool Solver::value (const Var x) const +{ + return assigns[x]; +} +inline lbool Solver::value (const Lit p) const +{ + return assigns[p.var()] ^ p.sign(); +} +inline lbool Solver::modelValue (const Lit p) const +{ + return model[p.var()] ^ p.sign(); +} +inline uint32_t Solver::nAssigns () const +{ + return trail.size(); +} +inline uint32_t Solver::nClauses () const +{ + return clauses.size() + xorclauses.size(); +} +inline uint32_t Solver::nLiterals () const +{ + return clauses_literals + learnts_literals; +} +inline uint32_t Solver::nLearnts () const +{ + return learnts.size(); +} +inline uint32_t Solver::nVars () const +{ + return assigns.size(); +} +inline void Solver::setPolarity (Var v, bool b) +{ + polarity [v] = (char)b; +} +inline void Solver::setDecisionVar(Var v, bool b) +{ + decision_var[v] = b; + if (b) { + insertVarOrder(v); + } +} +inline void Solver::addBranchingVariable(Var v) +{ + branching_variables.push_back(v); +} +inline lbool Solver::solve () +{ + vec<Lit> tmp; + return solve(tmp); +} +inline bool Solver::okay () const +{ + return ok; +} + +inline uint32_t Solver::get_sum_gauss_unit_truths() const +{ + return sum_gauss_unit_truths; +} + +inline uint32_t Solver::get_sum_gauss_called() const +{ + return sum_gauss_called; +} + +inline uint32_t Solver::get_sum_gauss_confl() const +{ + return sum_gauss_confl; +} + +inline uint32_t Solver::get_sum_gauss_prop() const +{ + return sum_gauss_prop; +} + +inline uint32_t Solver::get_unitary_learnts_num() const +{ + if (decisionLevel() > 0) + return trail_lim[0]; + else + return trail.size(); +} + +template<class T> +inline void Solver::removeClause(T& c) +{ + detachClause(c); + clauseAllocator.clauseFree(&c); +} + +//********************************** +// Debug + etc: +//********************************** + +static inline void logLit(FILE* f, Lit l) +{ + fprintf(f, "%sx%d", l.sign() ? "~" : "", l.var()+1); +} + +static inline void logLits(FILE* f, const vec<Lit>& ls) +{ + fprintf(f, "[ "); + if (ls.size() > 0) { + logLit(f, ls[0]); + for (uint32_t i = 1; i < ls.size(); i++) { + fprintf(f, ", "); + logLit(f, ls[i]); + } + } + fprintf(f, "] "); +} + +#ifndef DEBUG_ATTACH_FULL +inline void Solver::testAllClauseAttach() const +{ + return; +} +inline void Solver::findAllAttach() const +{ + return; +} +#endif //DEBUG_ATTACH_FULL + +inline void Solver::uncheckedEnqueueLight(const Lit p) +{ + assert(value(p.var()) == l_Undef); + #if WATCHED_CACHE_NUM > 0 + __builtin_prefetch(watches.getData() + p.toInt()); + #else + if (watches[p.toInt()].size() > 0) __builtin_prefetch(watches[p.toInt()].getData()); + #endif + + assigns [p.var()] = boolToLBool(!p.sign());//lbool(!sign(p)); // <<== abstract but not uttermost effecient + trail.push(p); + if (decisionLevel() == 0) { + level[p.var()] = 0; + #ifdef ANIMATE3D + fprintf(stderr, "s %u %d\n", p.var(), p.sign()); + #endif + } +} + +inline void Solver::uncheckedEnqueueLight2(const Lit p, const uint32_t binSubLevel, const Lit lev1Ancestor, const bool learntLeadHere) +{ + assert(value(p.var()) == l_Undef); + #if WATCHED_CACHE_NUM > 0 + __builtin_prefetch(watches.getData() + p.toInt()); + #else + if (watches[p.toInt()].size() > 0) __builtin_prefetch(watches[p.toInt()].getData()); + #endif + + assigns [p.var()] = boolToLBool(!p.sign());//lbool(!sign(p)); // <<== abstract but not uttermost effecient + trail.push(p); + binPropData[p.var()].lev = binSubLevel; + binPropData[p.var()].lev1Ancestor = lev1Ancestor; + binPropData[p.var()].learntLeadHere = learntLeadHere; +} + +/** +@brief Enqueues&sets a new fact that has been found + +Call this when a fact has been found. Sets the value, enqueues it for +propagation, sets its level, sets why it was propagated, saves the polarity, +and does some logging if logging is enabled. + +@p p the fact to enqueue +@p from Why was it propagated (binary clause, tertiary clause, normal clause) +*/ +inline void Solver::uncheckedEnqueue(const Lit p, const PropBy& from) +{ + #ifdef DEBUG_UNCHECKEDENQUEUE_LEVEL0 + #ifndef VERBOSE_DEBUG + if (decisionLevel() == 0) + #endif //VERBOSE_DEBUG + + std::cout << "uncheckedEnqueue var " << p.var()+1 + << " to val " << !p.sign() + << " level: " << decisionLevel() + << " sublevel: " << trail.size() + << " by: " << from << std::endl; + + if (from.isClause() && !from.isNULL()) { + std::cout << "by clause: " << *clauseAllocator.getPointer(from.getClause()) << std::endl; + } + #endif //DEBUG_UNCHECKEDENQUEUE_LEVEL0 + + //assert(decisionLevel() == 0 || !subsumer->getVarElimed()[p.var()]); + + const Var v = p.var(); + assert(value(v).isUndef()); + #if WATCHED_CACHE_NUM > 0 + __builtin_prefetch(watches.getData() + p.toInt()); + #else + if (watches[p.toInt()].size() > 0) __builtin_prefetch(watches[p.toInt()].getData()); + #endif + + assigns [v] = boolToLBool(!p.sign()); + #ifdef ANIMATE3D + fprintf(stderr, "s %u %d\n", v, p.sign()); + #endif + level [v] = decisionLevel(); + reason [v] = from; + polarity[v] = p.sign(); + trail.push(p); +} + +} + +#endif //SOLVER_H diff --git a/src/prop/cryptominisat/Solver/SolverConf.cpp b/src/prop/cryptominisat/Solver/SolverConf.cpp new file mode 100644 index 000000000..e7a5cfafa --- /dev/null +++ b/src/prop/cryptominisat/Solver/SolverConf.cpp @@ -0,0 +1,91 @@ +/***************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +******************************************************************************/ + +#include "SolverConf.h" +#include <limits> + +using namespace CMSat; + +SolverConf::SolverConf() : + random_var_freq(0.001) + , clause_decay (1 / 0.999) + , restart_first(100) + , restart_inc(1.5) + , learntsize_factor((double)1/(double)3) + + , expensive_ccmin (true) + , polarity_mode (polarity_auto) + , verbosity (0) + , restrictPickBranch(0) + + //Simplification + , simpBurstSConf(NUM_CONFL_BURST_SEARCH) + , simpStartMult(SIMPLIFY_MULTIPLIER) + , simpStartMMult(SIMPLIFY_MULTIPLIER_MULTIPLIER) + + , doPerformPreSimp (true) + , failedLitMultiplier(2.0) + + //optimisations to do + , doFindXors (true) + , doFindEqLits (true) + , doRegFindEqLits (true) + , doReplace (true) + , doConglXors (true) + , doHeuleProcess (true) + , doSchedSimp (true) + , doSatELite (true) + , doXorSubsumption (true) + , doHyperBinRes (true) + , doBlockedClause (false) + , doVarElim (true) + , doSubsume1 (true) + , doClausVivif (true) + , doSortWatched (true) + , doMinimLearntMore(true) + , doMinimLMoreRecur(true) + , doFailedLit (true) + , doRemUselessBins (true) + , doSubsWBins (true) + , doSubsWNonExistBins(true) + , doRemUselessLBins(true) + #ifdef ENABLE_UNWIND_GLUE + , doMaxGlueDel (false) + #endif //ENABLE_UNWIND_GLUE + , doPrintAvgBranch (false) + , doCacheOTFSSR (true) + , doCacheOTFSSRSet (true) + , doExtendedSCC (false) + , doCalcReach (true) + , doBXor (true) + , doOTFSubsume (true) + , maxConfl (std::numeric_limits<uint64_t>::max()) + , isPlain (false) + + , maxRestarts (std::numeric_limits<uint32_t>::max()) + , needToDumpLearnts(false) + , needToDumpOrig (false) + , maxDumpLearntsSize(std::numeric_limits<uint32_t>::max()) + , libraryUsage (true) + , greedyUnbound (false) + #ifdef ENABLE_UNWIND_GLUE + , maxGlue (DEFAULT_MAX_GLUE) + #endif //ENABLE_UNWIND_GLUE + , fixRestartType (auto_restart) + , origSeed(0) +{ +} diff --git a/src/prop/cryptominisat/Solver/SolverConf.h b/src/prop/cryptominisat/Solver/SolverConf.h new file mode 100644 index 000000000..0edaf3745 --- /dev/null +++ b/src/prop/cryptominisat/Solver/SolverConf.h @@ -0,0 +1,102 @@ +/***************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +******************************************************************************/ + +#ifndef SOLVERCONF_H +#define SOLVERCONF_H + +#include "SolverTypes.h" +#include "constants.h" + +namespace CMSat { + +class SolverConf +{ + public: + SolverConf(); + + double random_var_freq; ///<The frequency with which the decision heuristic tries to choose a random variable. (default 0.02) NOTE: This is really strange. If the number of variables set is large, then the random chance is in fact _far_ lower than this value. This is because the algorithm tries to set one variable randomly, but if that variable is already set, then it _silently_ fails, and moves on (doing non-random flip)! + double clause_decay; ///<Inverse of the clause activity decay factor. Only applies if using MiniSat-style clause activities (default: 1 / 0.999) + int restart_first; ///<The initial restart limit. (default 100) + double restart_inc; ///<The factor with which the restart limit is multiplied in each restart. (default 1.5) + double learntsize_factor; ///<The intitial limit for learnt clauses is a factor of the original clauses. (default 1 / 3) + double learntsize_inc; ///<The limit for learnt clauses is multiplied with this factor each restart. (default 1.1) + bool expensive_ccmin; ///<Should clause minimisation by Sorensson&Biere be used? (default TRUE) + int polarity_mode; ///<Controls which polarity the decision heuristic chooses. Auto means Jeroslow-Wang (default: polarity_auto) + int verbosity; ///<Verbosity level. 0=silent, 1=some progress report, 2=lots of report, 3 = all report (default 2) + Var restrictPickBranch; ///<Pick variables to branch on preferentally from the highest [0, restrictedPickBranch]. If set to 0, preferentiality is turned off (i.e. picked randomly between [0, all]) + uint32_t simpBurstSConf; + double simpStartMult; + double simpStartMMult; + bool doPerformPreSimp; + double failedLitMultiplier; + + //Optimisations to do + bool doFindXors; ///<Automatically find non-binary xor clauses and convert them to xor clauses + bool doFindEqLits; ///<Automatically find binary xor clauses (i.e. variable equi- and antivalences) + bool doRegFindEqLits; ///<Regularly find binary xor clauses (i.e. variable equi- and antivalences) + bool doReplace; ///<Should var-replacing be performed? If set to FALSE, equi- and antivalent variables will not be replaced with one another. NOTE: This precludes using a lot of the algorithms! + bool doConglXors; ///<Do variable elimination at the XOR-level (xor-ing 2 xor clauses thereby removing a variable) + bool doHeuleProcess; ///<Perform local subsitutuion as per Heule's theis + bool doSchedSimp; ///<Should simplifyProblem() be scheduled regularly? (if set to FALSE, a lot of opmitisations are disabled) + bool doSatELite; ///<Should try to subsume & self-subsuming resolve & variable-eliminate & block-clause eliminate? + bool doXorSubsumption; ///<Should try to subsume & local-subsitute xor clauses + bool doHyperBinRes; ///<Should try carry out hyper-binary resolution + bool doBlockedClause; ///<Should try to remove blocked clauses + bool doVarElim; ///<Perform variable elimination + bool doSubsume1; ///<Perform self-subsuming resolution + bool doClausVivif; ///<Perform asymmetric branching at the beginning of the solving + bool doSortWatched; ///<Sort watchlists according to size&type: binary, tertiary, normal (>3-long), xor clauses + bool doMinimLearntMore; ///<Perform learnt-clause minimisation using watchists' binary and tertiary clauses? ("strong minimization" in PrecoSat) + bool doMinimLMoreRecur; ///<Always perform recursive/transitive on-the-fly self self-subsuming resolution --> an enhancement of "strong minimization" of PrecoSat + bool doFailedLit; ///<Carry out Failed literal probing + doubly propagated literal detection + 2-long xor clause detection during failed literal probing + hyper-binary resoolution + bool doRemUselessBins; ///<Should try to remove useless binary clauses at the beginning of solving? + bool doSubsWBins; + bool doSubsWNonExistBins; ///<Try to do subsumption and self-subsuming resolution with non-existent binary clauses (i.e. binary clauses that don't exist but COULD exists) + bool doRemUselessLBins; ///<Try to remove useless learnt binary clauses + #ifdef ENABLE_UNWIND_GLUE + bool doMaxGlueDel; + #endif //ENABLE_UNWIND_GLUE + bool doPrintAvgBranch; + bool doCacheOTFSSR; + bool doCacheOTFSSRSet; + bool doExtendedSCC; + bool doCalcReach; ///<Calculate reachability, and influence variable decisions with that + bool doBXor; + bool doOTFSubsume; ///On-the-fly subsumption + uint64_t maxConfl; + bool isPlain; ///<We are in 'plain' mode: glues can never be 1 + + //interrupting & dumping + uint32_t maxRestarts; + bool needToDumpLearnts; ///<If set to TRUE, learnt clauses will be dumped to the file speified by "learntsFilename" + bool needToDumpOrig; ///<If set to TRUE, a simplified version of the original clause-set will be dumped to the file speified by "origFilename". The solution to this file should perfectly satisfy the problem + std::string learntsFilename; ///<Dump sorted learnt clauses to this file. Only active if "needToDumpLearnts" is set to TRUE + std::string origFilename; ///<Dump simplified original problem CNF to this file. Only active if "needToDumpOrig" is set to TRUE + uint32_t maxDumpLearntsSize; ///<When dumping the learnt clauses, this is the maximum clause size that should be dumped + bool libraryUsage; ///<Set to true if not used as a library. In fact, this is TRUE by default, and Main.cpp sets it to "FALSE". Disables some simplifications at the beginning of solving (mostly performStepsBeforeSolve() ) + bool greedyUnbound; ///<If set, then variables will be greedily unbounded (set to l_Undef). This is EXPERIMENTAL + #ifdef ENABLE_UNWIND_GLUE + uint32_t maxGlue; ///< Learnt clauses (when doing dynamic restarts) with glue above this value will be removed immediately on backtracking + #endif //ENABLE_UNWIND_GLUE + RestartType fixRestartType; ///<If set, the solver will always choose the given restart strategy instead of automatically trying to guess a strategy. Note that even if set to dynamic_restart, there will be a few restarts made statically after each full restart. + + uint32_t origSeed; +}; + +} + +#endif //SOLVERCONF_H diff --git a/src/prop/cryptominisat/Solver/SolverDebug.cpp b/src/prop/cryptominisat/Solver/SolverDebug.cpp new file mode 100644 index 000000000..a831a2779 --- /dev/null +++ b/src/prop/cryptominisat/Solver/SolverDebug.cpp @@ -0,0 +1,253 @@ +/*************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +****************************************************************************/ + +#include "Solver.h" +#include "VarReplacer.h" + +using namespace CMSat; + +#ifdef DEBUG_ATTACH_FULL +void Solver::testAllClauseAttach() const +{ + for (Clause *const*it = clauses.getData(), *const*end = clauses.getDataEnd(); it != end; it++) { + const Clause& c = **it; + assert(normClauseIsAttached(c)); + } + + for (XorClause *const*it = xorclauses.getData(), *const*end = xorclauses.getDataEnd(); it != end; it++) { + const XorClause& c = **it; + assert(xorClauseIsAttached(c)); + } +} + +bool Solver::normClauseIsAttached(const Clause& c) const +{ + bool attached = true; + assert(c.size() > 2); + + ClauseOffset offset = clauseAllocator.getOffset(&c); + if (c.size() == 3) { + //The clause might have been longer, and has only recently + //became 3-long. Check, and detach accordingly + if (findWCl(watches[(~c[0]).toInt()], offset)) goto fullClause; + + Lit lit1 = c[0]; + Lit lit2 = c[1]; + Lit lit3 = c[2]; + attached &= findWTri(watches[(~lit1).toInt()], lit2, lit3); + attached &= findWTri(watches[(~lit2).toInt()], lit1, lit3); + attached &= findWTri(watches[(~lit3).toInt()], lit1, lit2); + } else { + fullClause: + attached &= findWCl(watches[(~c[0]).toInt()], offset); + attached &= findWCl(watches[(~c[1]).toInt()], offset); + } + + return attached; +} + +bool Solver::xorClauseIsAttached(const XorClause& c) const +{ + ClauseOffset offset = clauseAllocator.getOffset(&c); + bool attached = true; + attached &= findWXCl(watches[(c[0]).toInt()], offset); + attached &= findWXCl(watches[(~c[0]).toInt()], offset); + attached &= findWXCl(watches[(c[1]).toInt()], offset); + attached &= findWXCl(watches[(~c[1]).toInt()], offset); + + return attached; +} + +void Solver::findAllAttach() const +{ + for (uint32_t i = 0; i < watches.size(); i++) { + for (uint32_t i2 = 0; i2 < watches[i].size(); i2++) { + const Watched& w = watches[i][i2]; + if (w.isClause()) findClause(clauseAllocator.getPointer(w.getNormOffset())); + if (w.isXorClause()) findClause(clauseAllocator.getPointer(w.getXorOffset())); + } + } +} + +bool Solver::findClause(XorClause* c) const +{ + for (uint32_t i = 0; i < xorclauses.size(); i++) { + if (xorclauses[i] == c) return true; + } + return false; +} + +bool Solver::findClause(Clause* c) const +{ + 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; + } + + return false; +} +#endif //DEBUG_ATTACH_FULL + +void Solver::checkSolution() +{ + model.growTo(nVars()); + for (Var var = 0; var != nVars(); var++) model[var] = value(var); + release_assert(verifyModel()); + model.clear(); +} + +bool Solver::verifyXorClauses() const +{ + #ifdef VERBOSE_DEBUG + cout << "Checking xor-clauses whether they have been properly satisfied." << endl;; + #endif + + bool verificationOK = true; + + for (uint32_t i = 0; i != xorclauses.size(); i++) { + XorClause& c = *xorclauses[i]; + bool final = c.xorEqualFalse(); + + #ifdef VERBOSE_DEBUG + std::cout << "verifying xor clause: " << c << std::endl; + #endif + + for (uint32_t 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(); + verificationOK = false; + } + } + + return verificationOK; +} + +bool Solver::verifyBinClauses() const +{ + uint32_t wsLit = 0; + for (const vec<Watched> *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec<Watched>& ws = *it; + + for (vec<Watched>::const_iterator i = ws.getData(), end = ws.getDataEnd() ; i != end; i++) { + if (i->isBinary() + && value(lit) != l_True + && value(i->getOtherLit()) != l_True + ) { + std::cout << "bin clause: " << lit << " , " << i->getOtherLit() << " not satisfied!" << std::endl; + std::cout << "value of unsat bin clause: " << value(lit) << " , " << value(i->getOtherLit()) << std::endl; + return false; + } + } + } + + return true; +} + +bool Solver::verifyClauses(const vec<Clause*>& cs) const +{ + #ifdef VERBOSE_DEBUG + cout << "Checking clauses whether they have been properly satisfied." << endl;; + #endif + + bool verificationOK = true; + + for (uint32_t i = 0; i != cs.size(); i++) { + Clause& c = *cs[i]; + for (uint32_t j = 0; j < c.size(); j++) + if (modelValue(c[j]) == l_True) + goto next; + + printf("unsatisfied clause: "); + cs[i]->plainPrint(); + verificationOK = false; + next: + ; + } + + return verificationOK; +} + +bool Solver::verifyModel() const +{ + bool verificationOK = true; + verificationOK &= verifyClauses(clauses); + verificationOK &= verifyClauses(learnts); + verificationOK &= verifyBinClauses(); + verificationOK &= verifyXorClauses(); + + if (conf.verbosity >=1 && verificationOK) + printf("c Verified %d clauses.\n", clauses.size() + xorclauses.size()); + + return verificationOK; +} + + +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::printAllClauses() +{ + for (uint32_t i = 0; i < clauses.size(); i++) { + std::cout << "Normal clause num " << clauseAllocator.getOffset(clauses[i]) << " cl: " << *clauses[i] << std::endl; + } + + for (uint32_t i = 0; i < xorclauses.size(); i++) { + std::cout << "xorclause num " << *xorclauses[i] << std::endl; + } + + uint32_t wsLit = 0; + for (vec<Watched> *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec<Watched>& ws = *it; + std::cout << "watches[" << lit << "]" << std::endl; + for (vec<Watched>::const_iterator it2 = ws.getData(), end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary()) { + std::cout << "Binary clause part: " << lit << " , " << it2->getOtherLit() << std::endl; + } else if (it2->isClause()) { + std::cout << "Normal clause num " << it2->getNormOffset() << std::endl; + } else if (it2->isXorClause()) { + std::cout << "Xor clause num " << it2->getXorOffset() << std::endl; + } else if (it2->isTriClause()) { + std::cout << "Tri clause:" + << lit << " , " + << it2->getOtherLit() << " , " + << it2->getOtherLit2() << std::endl; + } + } + } + +} diff --git a/src/prop/cryptominisat/Solver/SolverMisc.cpp b/src/prop/cryptominisat/Solver/SolverMisc.cpp new file mode 100644 index 000000000..c2007af2e --- /dev/null +++ b/src/prop/cryptominisat/Solver/SolverMisc.cpp @@ -0,0 +1,713 @@ +/*************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +****************************************************************************/ + +#include "Solver.h" +#include "VarReplacer.h" +#include "Subsumer.h" +#include "XorSubsumer.h" +#include "time_mem.h" +#include "DimacsParser.h" +#include "FailedLitSearcher.h" +#include "DataSync.h" +#include "SCCFinder.h" +#include <iomanip> +#include <omp.h> + +#ifdef USE_GAUSS +#include "Gaussian.h" +#endif + +#ifndef _MSC_VER +#include <sys/time.h> +#include <sys/resource.h> +#endif + +using namespace CMSat; + +static const int space = 10; + +bool Solver::dumpSortedLearnts(const std::string& fileName, const uint32_t maxSize) +{ + FILE* outfile = fopen(fileName.c_str(), "w"); + if (!outfile) + return false; + + 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); + } + + fprintf(outfile, "c conflicts %lu\n", (unsigned long)conflicts); + if (maxSize == 1) goto end; + + fprintf(outfile, "c \nc ---------------------------------\n"); + fprintf(outfile, "c learnt binary clauses (extracted from watchlists)\n"); + fprintf(outfile, "c ---------------------------------\n"); + dumpBinClauses(true, false, 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); + } + } + 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); + } + } + + end: + + fclose(outfile); + return true; +} + +void Solver::printStrangeBinLit(const Lit lit) const +{ + const vec<Watched>& ws = watches[(~lit).toInt()]; + for (vec<Watched>::const_iterator it2 = ws.getData(), end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary()) { + std::cout << "bin: " << lit << " , " << it2->getOtherLit() << " learnt : " << (it2->getLearnt()) << std::endl; + } else if (it2->isTriClause()) { + std::cout << "tri: " << lit << " , " << it2->getOtherLit() << " , " << (it2->getOtherLit2()) << std::endl; + } else if (it2->isClause()) { + std::cout << "cla:" << it2->getNormOffset() << std::endl; + } else { + assert(it2->isXorClause()); + std::cout << "xor:" << it2->getXorOffset() << std::endl; + } + } +} + +uint32_t Solver::countNumBinClauses(const bool alsoLearnt, const bool alsoNonLearnt) const +{ + uint32_t num = 0; + + uint32_t wsLit = 0; + for (const vec<Watched> *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) { + const vec<Watched>& ws = *it; + for (vec<Watched>::const_iterator it2 = ws.getData(), end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary()) { + if (it2->getLearnt()) num += alsoLearnt; + else num+= alsoNonLearnt; + } + } + } + + assert(num % 2 == 0); + return num/2; +} + +void Solver::dumpBinClauses(const bool alsoLearnt, const bool alsoNonLearnt, FILE* outfile) const +{ + uint32_t wsLit = 0; + for (const vec<Watched> *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec<Watched>& ws = *it; + for (vec<Watched>::const_iterator it2 = ws.getData(), end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary() && lit.toInt() < it2->getOtherLit().toInt()) { + bool toDump = false; + if (it2->getLearnt() && alsoLearnt) toDump = true; + if (!it2->getLearnt() && alsoNonLearnt) toDump = true; + + if (toDump) it2->dump(outfile, lit); + } + } + } +} + +uint32_t Solver::getBinWatchSize(const bool alsoLearnt, const Lit lit) +{ + uint32_t num = 0; + const vec<Watched>& ws = watches[lit.toInt()]; + for (vec<Watched>::const_iterator it2 = ws.getData(), end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary() && (alsoLearnt || !it2->getLearnt())) { + num++; + } + } + + return num; +} + +void Solver::printBinClause(const Lit litP1, const Lit litP2, FILE* outfile) const +{ + if (value(litP1) == l_True) { + litP1.printFull(outfile); + } else if (value(litP1) == l_False) { + litP2.printFull(outfile); + } else if (value(litP2) == l_True) { + litP2.printFull(outfile); + } else if (value(litP2) == l_False) { + litP1.printFull(outfile); + } else { + litP1.print(outfile); + litP2.printFull(outfile); + } +} + +bool Solver::dumpOrigClauses(const std::string& fileName) const +{ + FILE* outfile; + if (fileName != std::string("stdout")) { + outfile = fopen(fileName.c_str(), "w"); + if (!outfile) + return false; + } else { + outfile = stdout; + } + + uint32_t numClauses = 0; + //unitary clauses + for (uint32_t i = 0, end = (trail_lim.size() > 0) ? trail_lim[0] : trail.size() ; i < end; i++) + numClauses++; + + //binary XOR clauses + const vector<Lit>& table = varReplacer->getReplaceTable(); + for (Var var = 0; var != table.size(); var++) { + Lit lit = table[var]; + if (lit.var() == var) + continue; + numClauses += 2; + } + + //binary normal clauses + numClauses += countNumBinClauses(false, true); + + //normal clauses + numClauses += clauses.size(); + + //xor clauses + numClauses += xorclauses.size(); + + //previously eliminated clauses + const map<Var, vector<vector<Lit> > >& elimedOutVar = subsumer->getElimedOutVar(); + for (map<Var, vector<vector<Lit> > >::const_iterator it = elimedOutVar.begin(); it != elimedOutVar.end(); it++) { + const vector<vector<Lit> >& cs = it->second; + numClauses += cs.size(); + } + const map<Var, vector<std::pair<Lit, Lit> > >& elimedOutVarBin = subsumer->getElimedOutVarBin(); + for (map<Var, vector<std::pair<Lit, Lit> > >::const_iterator it = elimedOutVarBin.begin(); it != elimedOutVarBin.end(); it++) { + numClauses += it->second.size(); + } + + const map<Var, vector<XorSubsumer::XorElimedClause> >& xorElimedOutVar = xorSubsumer->getElimedOutVar(); + for (map<Var, vector<XorSubsumer::XorElimedClause> >::const_iterator it = xorElimedOutVar.begin(); it != xorElimedOutVar.end(); it++) { + const vector<XorSubsumer::XorElimedClause>& cs = it->second; + numClauses += cs.size(); + } + + fprintf(outfile, "p cnf %d %d\n", nVars(), numClauses); + + //////////////////////////////////////////////////////////////////// + + 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); + } + + fprintf(outfile, "c \nc ---------------------------------------\n"); + fprintf(outfile, "c clauses representing 2-long XOR clauses\n"); + fprintf(outfile, "c ---------------------------------------\n"); + for (Var var = 0; var != table.size(); var++) { + Lit lit = table[var]; + if (lit.var() == var) + continue; + + Lit litP1 = ~lit; + Lit litP2 = Lit(var, false); + printBinClause(litP1, litP2, outfile); + printBinClause(~litP1, ~litP2, outfile); + } + + fprintf(outfile, "c \nc ------------\n"); + fprintf(outfile, "c binary clauses\n"); + fprintf(outfile, "c ---------------\n"); + dumpBinClauses(false, true, outfile); + + fprintf(outfile, "c \nc ------------\n"); + fprintf(outfile, "c normal clauses\n"); + fprintf(outfile, "c ---------------\n"); + for (Clause *const *i = clauses.getData(); i != clauses.getDataEnd(); i++) { + assert(!(*i)->learnt()); + (*i)->print(outfile); + } + + fprintf(outfile, "c \nc ------------\n"); + fprintf(outfile, "c xor clauses\n"); + fprintf(outfile, "c ---------------\n"); + for (XorClause *const *i = xorclauses.getData(); i != xorclauses.getDataEnd(); i++) { + assert(!(*i)->learnt()); + (*i)->print(outfile); + } + + fprintf(outfile, "c -------------------------------\n"); + fprintf(outfile, "c previously eliminated variables\n"); + fprintf(outfile, "c -------------------------------\n"); + for (map<Var, vector<vector<Lit> > >::const_iterator it = elimedOutVar.begin(); it != elimedOutVar.end(); it++) { + fprintf(outfile, "c ########### cls for eliminated var %d ### start\n", it->first + 1); + const vector<vector<Lit> >& cs = it->second; + for (vector<vector<Lit> >::const_iterator it2 = cs.begin(); it2 != cs.end(); it2++) { + printClause(outfile, *it2); + } + fprintf(outfile, "c ########### cls for eliminated var %d ### finish\n", it->first + 1); + } + for (map<Var, vector<std::pair<Lit, Lit> > >::const_iterator it = elimedOutVarBin.begin(); it != elimedOutVarBin.end(); it++) { + for (uint32_t i = 0; i < it->second.size(); i++) { + it->second[i].first.print(outfile); + it->second[i].second.printFull(outfile); + } + } + + fprintf(outfile, "c -------------------------------\n"); + fprintf(outfile, "c previously xor-eliminated variables\n"); + fprintf(outfile, "c -------------------------------\n"); + for (map<Var, vector<XorSubsumer::XorElimedClause> >::const_iterator it = xorElimedOutVar.begin(); it != xorElimedOutVar.end(); it++) { + for (vector<XorSubsumer::XorElimedClause>::const_iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { + it2->plainPrint(outfile); + } + } + + if (fileName != "stdout") fclose(outfile); + return true; +} + +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; +} + +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; +} + +uint32_t Solver::getNumElimSubsume() const +{ + return subsumer->getNumElimed(); +} + +uint32_t Solver::getNumElimXorSubsume() const +{ + return xorSubsumer->getNumElimed(); +} + +uint32_t Solver::getNumXorTrees() const +{ + return varReplacer->getNumTrees(); +} + +uint32_t Solver::getNumXorTreesCrownSize() const +{ + return varReplacer->getNumReplacedVars(); +} + +double Solver::getTotalTimeSubsumer() const +{ + return subsumer->getTotalTime(); +} + +double Solver::getTotalTimeFailedLitSearcher() const +{ + return failedLitSearcher->getTotalTime(); +} + +double Solver::getTotalTimeXorSubsumer() const +{ + return xorSubsumer->getTotalTime(); +} + +double Solver::getTotalTimeSCC() const +{ + return sCCFinder->getTotalTime(); +} + +void Solver::printStatHeader() const +{ + if (conf.verbosity >= 2) { + std::cout << "c " + << "=========================================================================================" + << std::endl; + std::cout << "c" + << " types(t): F = full restart, N = normal restart" << std::endl; + std::cout << "c" + << " types(t): S = simplification begin/end, E = solution found" << std::endl; + std::cout << "c" + << " restart types(rt): st = static, dy = dynamic" << std::endl; + + std::cout << "c " + << std::setw(2) << "t" + << std::setw(3) << "rt" + << std::setw(6) << "Rest" + << std::setw(space) << "Confl" + << std::setw(space) << "Vars" + << std::setw(space) << "NormCls" + << std::setw(space) << "XorCls" + << std::setw(space) << "BinCls" + << std::setw(space) << "Learnts" + << std::setw(space) << "ClLits" + << std::setw(space) << "LtLits" + << std::setw(space) << "LGlueHist" + << std::setw(space) << "SGlueHist" + << std::endl; + } +} + +void Solver::printRestartStat(const char* type) +{ + if (conf.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)); + + std::cout << "c " + << std::setw(2) << type + << std::setw(3) << ((restartType == static_restart) ? "st" : "dy") + << std::setw(6) << starts + << std::setw(space) << conflicts + << std::setw(space) << order_heap.size() + << std::setw(space) << clauses.size() + << std::setw(space) << xorclauses.size() + << std::setw(space) << numBins + << std::setw(space) << learnts.size() + << std::setw(space) << clauses_literals + << std::setw(space) << learnts_literals; + + if (glueHistory.getTotalNumeElems() > 0) { + std::cout << std::setw(space) << std::fixed << std::setprecision(2) << glueHistory.getAvgAllDouble(); + } else { + std::cout << std::setw(space) << "no data"; + } + if (glueHistory.isvalid()) { + std::cout << std::setw(space) << std::fixed << std::setprecision(2) << glueHistory.getAvgDouble(); + } else { + std::cout << std::setw(space) << "no data"; + } + + #ifdef RANDOM_LOOKAROUND_SEARCHSPACE + if (conf.doPrintAvgBranch) { + if (avgBranchDepth.isvalid()) + std::cout << std::setw(space) << avgBranchDepth.getAvgUInt(); + else + std::cout << std::setw(space) << "no data"; + } + #endif //RANDOM_LOOKAROUND_SEARCHSPACE + + #ifdef USE_GAUSS + print_gauss_sum_stats(); + #endif //USE_GAUSS + + std::cout << std::endl; + } +} + +void Solver::printEndSearchStat() +{ + if (conf.verbosity >= 1) { + printRestartStat("E"); + } +} + +#ifdef USE_GAUSS +void Solver::print_gauss_sum_stats() +{ + if (gauss_matrixes.size() == 0 && conf.verbosity >= 2) { + std::cout << " --"; + return; + } + + uint32_t called = 0; + uint32_t useful_prop = 0; + uint32_t useful_confl = 0; + uint32_t 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 (conf.verbosity >= 2) { + if (called == 0) { + std::cout << " --"; + } else { + std::cout << " " + << std::fixed << std::setprecision(1) << std::setw(5) + << ((double)useful_prop/(double)called*100.0) << "% " + << std::fixed << std::setprecision(1) << std::setw(5) + << ((double)useful_confl/(double)called*100.0) << "% " + << std::fixed << std::setprecision(1) << std::setw(5) + << (100.0-(double)disabled/(double)gauss_matrixes.size()*100.0) << "%"; + } + } +} +#endif //USE_GAUSS + +/** +@brief Sorts the watchlists' clauses as: binary, tertiary, normal, xor +*/ +void Solver::sortWatched() +{ + #ifdef VERBOSE_DEBUG + std::cout << "Sorting watchlists:" << std::endl; + #endif + double myTime = cpuTime(); + for (vec<Watched> *i = watches.getData(), *end = watches.getDataEnd(); i != end; i++) { + if (i->size() == 0) continue; + #ifdef VERBOSE_DEBUG + vec<Watched>& ws = *i; + std::cout << "Before sorting:" << std::endl; + for (uint32_t i2 = 0; i2 < ws.size(); i2++) { + if (ws[i2].isBinary()) std::cout << "Binary,"; + if (ws[i2].isTriClause()) std::cout << "Tri,"; + if (ws[i2].isClause()) std::cout << "Normal,"; + if (ws[i2].isXorClause()) std::cout << "Xor,"; + } + std::cout << std::endl; + #endif //VERBOSE_DEBUG + + std::sort(i->getData(), i->getDataEnd(), WatchedSorter()); + + #ifdef VERBOSE_DEBUG + std::cout << "After sorting:" << std::endl; + for (uint32_t i2 = 0; i2 < ws.size(); i2++) { + if (ws[i2].isBinary()) std::cout << "Binary,"; + if (ws[i2].isTriClause()) std::cout << "Tri,"; + if (ws[i2].isClause()) std::cout << "Normal,"; + if (ws[i2].isXorClause()) std::cout << "Xor,"; + } + std::cout << std::endl; + #endif //VERBOSE_DEBUG + } + + if (conf.verbosity >= 3) { + std::cout << "c watched " + << "sorting time: " << cpuTime() - myTime + << std::endl; + } +} + +void Solver::addSymmBreakClauses() +{ + if (xorclauses.size() > 0) { + std::cout << "c xor clauses present -> no saucy" << std::endl; + return; + } + double myTime = cpuTime(); + std::cout << "c Doing saucy" << std::endl; + dumpOrigClauses("origProblem.cnf"); + + int rvalue; + rvalue= system("grep -v \"^c\" origProblem.cnf > origProblem2.cnf"); + if (rvalue >= 2) { // unsuccessful grep in POSIX standard + std::cout << "c impossible to complete saucy" << std::endl; + return; + } + rvalue= system("python saucyReader.py origProblem2.cnf > output"); + if (rvalue != 0) { // unsuccessful saucyReader.py + std::cout << "c impossible to complete saucy" << std::endl; + return; + } + + + DimacsParser parser(this, false, false, false, true); + + #ifdef DISABLE_ZLIB + FILE * in = fopen("output", "rb"); + #else + gzFile in = gzopen("output", "rb"); + #endif // DISABLE_ZLIB + parser.parse_DIMACS(in); + #ifdef DISABLE_ZLIB + fclose(in); + #else + gzclose(in); + #endif // DISABLE_ZLIB + std::cout << "c Finished saucy, time: " << (cpuTime() - myTime) << std::endl; +} + +/** +@brief Pretty-prints a literal +*/ +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')); +} + +/** +@brief Sets that we need a CNF file that documents all commands + +newVar() and addClause(), addXorClause() commands are logged to this CNF +file and then can be re-read with special arguments to the main program. This +can help simulate a segfaulting library-call +*/ +bool Solver::needLibraryCNFFile(const std::string& fileName) +{ + libraryCNFFile = fopen(fileName.c_str(), "w"); + return libraryCNFFile != NULL; +} + +template<class T, class T2> +void Solver::printStatsLine(std::string left, T value, T2 value2, std::string extra) +{ + std::cout << std::fixed << std::left << std::setw(27) << left << ": " << std::setw(11) << std::setprecision(2) << value << " (" << std::left << std::setw(9) << std::setprecision(2) << value2 << " " << extra << ")" << std::endl; +} + +template<class T> +void Solver::printStatsLine(std::string left, T value, std::string extra) +{ + std::cout << std::fixed << std::left << std::setw(27) << left << ": " << std::setw(11) << std::setprecision(2) << value << extra << std::endl; +} + +/** +@brief prints the statistics line at the end of solving + +Prints all sorts of statistics, like number of restarts, time spent in +SatELite-type simplification, number of unit claues found, etc. +*/ +void Solver::printStats() +{ + double cpu_time = cpuTime(); + uint64_t mem_used = memUsed(); + + int numThreads = omp_get_num_threads(); + if (numThreads > 1) { + std::cout << "c Following stats are for *FIRST FINISHED THREAD ONLY*" << std::endl; + #if !defined(_MSC_VER) && !defined(RUSAGE_THREAD) + std::cout << "c There is no platform-independent way to measure time per thread" << std::endl; + std::cout << "c All times indicated are sum of ALL threads" << std::endl; + std::cout << "c Use a utilty provided by your platform to get total thread time, etc." << std::endl; + #endif + } + printStatsLine("c num threads" , numThreads); + + //Restarts stats + printStatsLine("c restarts", starts); + printStatsLine("c dynamic restarts", dynStarts); + printStatsLine("c static restarts", staticStarts); + printStatsLine("c full restarts", fullStarts); + printStatsLine("c total simplify time", totalSimplifyTime); + + //Learnts stats + printStatsLine("c learnts DL2", nbGlue2); + printStatsLine("c learnts size 2", numNewBin); + printStatsLine("c learnts size 1", get_unitary_learnts_num(), (double)get_unitary_learnts_num()/(double)nVars()*100.0, "% of vars"); + printStatsLine("c filedLit time", getTotalTimeFailedLitSearcher(), getTotalTimeFailedLitSearcher()/cpu_time*100.0, "% time"); + + //Subsumer stats + printStatsLine("c v-elim SatELite", getNumElimSubsume(), (double)getNumElimSubsume()/(double)nVars()*100.0, "% vars"); + printStatsLine("c SatELite time", getTotalTimeSubsumer(), getTotalTimeSubsumer()/cpu_time*100.0, "% time"); + + //XorSubsumer stats + printStatsLine("c v-elim xor", getNumElimXorSubsume(), (double)getNumElimXorSubsume()/(double)nVars()*100.0, "% vars"); + printStatsLine("c xor elim time", getTotalTimeXorSubsumer(), getTotalTimeXorSubsumer()/cpu_time*100.0, "% time"); + + //VarReplacer stats + printStatsLine("c num binary xor trees", getNumXorTrees()); + printStatsLine("c binxor trees' crown", getNumXorTreesCrownSize(), (double)getNumXorTreesCrownSize()/(double)getNumXorTrees(), "leafs/tree"); + printStatsLine("c bin xor find time", getTotalTimeSCC()); + + //OTF clause improvement stats + printStatsLine("c OTF clause improved", improvedClauseNo, (double)improvedClauseNo/(double)conflicts, "clauses/conflict"); + printStatsLine("c OTF impr. size diff", improvedClauseSize, (double)improvedClauseSize/(double)improvedClauseNo, " lits/clause"); + + //Clause-shrinking through watchlists + printStatsLine("c OTF cl watch-shrink", numShrinkedClause, (double)numShrinkedClause/(double)conflicts, "clauses/conflict"); + printStatsLine("c OTF cl watch-sh-lit", numShrinkedClauseLits, (double)numShrinkedClauseLits/(double)numShrinkedClause, " lits/clause"); + printStatsLine("c tried to recurMin cls", moreRecurMinLDo, (double)moreRecurMinLDo/(double)conflicts*100.0, " % of conflicts"); + printStatsLine("c updated cache", updateTransCache, updateTransCache/(double)moreRecurMinLDo, " lits/tried recurMin"); + + //Multi-threading + if (numThreads > 1) { + printStatsLine("c unit cls received", dataSync->getRecvUnitData(), (double)dataSync->getRecvUnitData()/(double)get_unitary_learnts_num()*100.0, "% of units"); + printStatsLine("c unit cls sent", dataSync->getSentUnitData(), (double)dataSync->getSentUnitData()/(double)get_unitary_learnts_num()*100.0, "% of units"); + printStatsLine("c bin cls received", dataSync->getRecvBinData()); + printStatsLine("c bin cls sent", dataSync->getSentBinData()); + } + + #ifdef USE_GAUSS + if (gaussconfig.decision_until > 0) { + std::cout << "c " << std::endl; + printStatsLine("c gauss unit truths ", get_sum_gauss_unit_truths()); + printStatsLine("c gauss called", get_sum_gauss_called()); + printStatsLine("c gauss conflicts ", get_sum_gauss_confl(), (double)get_sum_gauss_confl() / (double)get_sum_gauss_called() * 100.0, " %"); + printStatsLine("c gauss propagations ", get_sum_gauss_prop(), (double)get_sum_gauss_prop() / (double)get_sum_gauss_called() * 100.0, " %"); + printStatsLine("c gauss useful", ((double)get_sum_gauss_prop() + (double)get_sum_gauss_confl())/ (double)get_sum_gauss_called() * 100.0, " %"); + std::cout << "c " << std::endl; + } + #endif + + printStatsLine("c clauses over max glue", nbClOverMaxGlue, (double)nbClOverMaxGlue/(double)conflicts*100.0, "% of all clauses"); + + //Search stats + printStatsLine("c conflicts", conflicts, (double)conflicts/cpu_time, "/ sec"); + printStatsLine("c decisions", decisions, (double)rnd_decisions*100.0/(double)decisions, "% random"); + printStatsLine("c bogo-props", propagations, (double)propagations/cpu_time, "/ sec"); + printStatsLine("c conflict literals", tot_literals, (double)(max_literals - tot_literals)*100.0/ (double)max_literals, "% deleted"); + + //General stats + printStatsLine("c Memory used", (double)mem_used / 1048576.0, " MB"); + if (numThreads > 1) { + #if !defined(_MSC_VER) && defined(RUSAGE_THREAD) + printStatsLine("c single-thread CPU time", cpu_time, " s"); + printStatsLine("c all-threads sum CPU time", cpuTimeTotal(), " s"); + #else + printStatsLine("c all-threads sum CPU time", cpu_time, " s"); + #endif + } else { + printStatsLine("c CPU time", cpu_time, " s"); + } +} diff --git a/src/prop/cryptominisat/Solver/SolverTypes.h b/src/prop/cryptominisat/Solver/SolverTypes.h new file mode 100644 index 000000000..4228ba06a --- /dev/null +++ b/src/prop/cryptominisat/Solver/SolverTypes.h @@ -0,0 +1,244 @@ +/***************************************************************************** +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +glucose -- Gilles Audemard, Laurent Simon (2008) +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +Original code by MiniSat and glucose authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3 licence. +******************************************************************************/ + +#ifndef __SOLVERTYPES_H__ +#define __SOLVERTYPES_H__ + +#include <cassert> +#include <iostream> +#include <Vec.h> +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#include <stdio.h> +#include <vector> +#include "constants.h" + +//********************************** +// Variables, literals, lifted booleans, clauses: +//********************************** + +// NOTE! Variables are just integers. No abstraction here. They should be chosen from 0..N, +// so that they can be used as array indices. + +namespace CMSat { + +typedef uint32_t Var; +static const uint32_t var_Undef = 0xffffffffU >>1; +enum RestartType {dynamic_restart, static_restart, auto_restart}; + +/** +@brief A Literal, i.e. a variable with a sign +*/ +class Lit +{ + uint32_t x; + explicit Lit(uint32_t i) : x(i) { }; +public: + Lit() : x(2*var_Undef) {} // (lit_Undef) + explicit Lit(Var var, bool sign) : x((var+var) + (int)sign) { } + + const uint32_t& toInt() const { // Guarantees small, positive integers suitable for array indexing. + return x; + } + Lit operator~() const { + return Lit(x ^ 1); + } + Lit operator^(const bool b) const { + return Lit(x ^ (uint32_t)b); + } + Lit& operator^=(const bool b) { + x ^= (uint32_t)b; + return *this; + } + bool sign() const { + return x & 1; + } + Var var() const { + return x >> 1; + } + Lit unsign() const { + return Lit(x & ~1); + } + bool operator==(const Lit& p) const { + return x == p.x; + } + bool operator!= (const Lit& p) const { + return x != p.x; + } + /** + @brief ONLY to be used for ordering such as: a, b, ~b, etc. + */ + bool operator < (const Lit& p) const { + return x < p.x; // '<' guarantees that p, ~p are adjacent in the ordering. + } + inline void print(FILE* outfile = stdout) const + { + fprintf(outfile,"%s%d ", sign() ? "-" : "", var()+1); + } + inline void printFull(FILE* outfile = stdout) const + { + fprintf(outfile,"%s%d 0\n", sign() ? "-" : "", var()+1); + } + static Lit toLit(uint32_t data) + { + return Lit(data); + } +}; + +static const Lit lit_Undef(var_Undef, false); // Useful special constants. +static const Lit lit_Error(var_Undef, true ); // + +inline std::ostream& operator<<(std::ostream& cout, const Lit& lit) +{ + cout << (lit.sign() ? "-" : "") << (lit.var() + 1); + return cout; +} + +inline std::ostream& operator<<(std::ostream& cout, const vec<Lit>& lits) +{ + for (uint32_t i = 0; i < lits.size(); i++) { + cout << lits[i] << " "; + } + return cout; +} + +inline void printClause(FILE* outFile, const std::vector<Lit>& clause) +{ + for (size_t i = 0; i < clause.size(); i++) { + fprintf(outFile,"%s%d ", clause[i].sign() ? "-" : "", clause[i].var()+1); + } + fprintf(outFile, "0\n"); +} + +inline void printClause(FILE* outFile, const vec<Lit>& clause) +{ + for (uint32_t i = 0; i < clause.size(); i++) { + fprintf(outFile,"%s%d ", clause[i].sign() ? "-" : "", clause[i].var()+1); + } + fprintf(outFile, "0\n"); +} + +//********************************** +// Lifted booleans +//********************************** + +class llbool; + +class lbool +{ + char value; + explicit lbool(char v) : value(v) { } + +public: + lbool() : value(0) { }; + inline char getchar() const { + return value; + } + inline lbool(llbool b); + + inline bool isUndef() const { + return !value; + } + inline bool isDef() const { + return value; + } + inline bool getBool() const { + return value == 1; + } + inline bool operator==(lbool b) const { + return value == b.value; + } + inline bool operator!=(lbool b) const { + return value != b.value; + } + lbool operator^(const bool b) const { + return b ? lbool(-value) : lbool(value); + } + + friend lbool toLbool(const char v); + friend lbool boolToLBool(const bool b); + friend class llbool; +}; +inline lbool toLbool(const char v) +{ + return lbool(v); +} +inline lbool boolToLBool(const bool b) +{ + return lbool(2*b-1); +} + +const lbool l_True = toLbool( 1); +const lbool l_False = toLbool(-1); +const lbool l_Undef = toLbool( 0); + +inline std::ostream& operator<<(std::ostream& cout, const lbool val) +{ + if (val == l_True) cout << "l_True"; + if (val == l_False) cout << "l_False"; + if (val == l_Undef) cout << "l_Undef"; + return cout; +} + + +/** +@brief A very hackish lbool that also supports l_Nothing and l_Continue +*/ +class llbool +{ + char value; + +public: + llbool(): value(0) {}; + llbool(lbool v) : + value(v.value) {}; + llbool(char a) : + value(a) {} + + inline bool operator!=(const llbool& v) const { + return (v.value != value); + } + + inline bool operator==(const llbool& v) const { + return (v.value == value); + } + + friend class lbool; +}; +const llbool l_Nothing = toLbool(2); +const llbool l_Continue = toLbool(3); + +lbool::lbool(llbool b) : value(b.value) {} + +inline std::ostream& operator<<(std::ostream& os, const llbool val) +{ + if (val == l_True) os << "l_True"; + if (val == l_False) os << "l_False"; + if (val == l_Undef) os << "l_Undef"; + if (val == l_Nothing) os << "l_Nothing"; + if (val == l_Continue) os << "l_Continue"; + return os; +} + +enum { polarity_true = 0, polarity_false = 1, polarity_rnd = 3, polarity_auto = 4}; + +struct BinPropData { + uint32_t lev; + Lit lev1Ancestor; + bool learntLeadHere; + bool hasChildren; +}; + +} + +#endif //SOLVERTYPES_H diff --git a/src/prop/cryptominisat/Solver/StateSaver.cpp b/src/prop/cryptominisat/Solver/StateSaver.cpp new file mode 100644 index 000000000..379fec2c4 --- /dev/null +++ b/src/prop/cryptominisat/Solver/StateSaver.cpp @@ -0,0 +1,50 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#include "StateSaver.h" + +using namespace CMSat; + +StateSaver::StateSaver(Solver& _solver) : + solver(_solver) + , backup_order_heap(Solver::VarOrderLt(solver.activity)) +{ + //Saving Solver state + backup_var_inc = solver.var_inc; + backup_activity.growTo(solver.activity.size()); + std::copy(solver.activity.getData(), solver.activity.getDataEnd(), backup_activity.getData()); + backup_order_heap = solver.order_heap; + backup_polarities = solver.polarity; + backup_restartType = solver.restartType; + backup_propagations = solver.propagations; + backup_random_var_freq = solver.conf.random_var_freq; +} + +void StateSaver::restore() +{ + //Restore Solver state + solver.var_inc = backup_var_inc; + std::copy(backup_activity.getData(), backup_activity.getDataEnd(), solver.activity.getData()); + solver.order_heap = backup_order_heap; + solver.polarity = backup_polarities; + solver.restartType = backup_restartType; + solver.propagations = backup_propagations; + solver.conf.random_var_freq = backup_random_var_freq; + + //Finally, clear the order_heap from variables set/non-decisionned + solver.order_heap.filter(Solver::VarFilter(solver)); +} diff --git a/src/prop/cryptominisat/Solver/StateSaver.h b/src/prop/cryptominisat/Solver/StateSaver.h new file mode 100644 index 000000000..3450a2364 --- /dev/null +++ b/src/prop/cryptominisat/Solver/StateSaver.h @@ -0,0 +1,44 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#ifndef STATESAVER__H +#define STATESAVER__H + +#include "Solver.h" + +namespace CMSat { + +class StateSaver +{ + public: + StateSaver(Solver& _solver); + void restore(); + + private: + Solver& solver; + Heap<Solver::VarOrderLt> backup_order_heap; + vector<char> backup_polarities; + vec<uint32_t> backup_activity; + uint32_t backup_var_inc; + RestartType backup_restartType; + double backup_random_var_freq; + uint64_t backup_propagations; +}; + +} + +#endif //STATESAVER__H diff --git a/src/prop/cryptominisat/Solver/StreamBuffer.h b/src/prop/cryptominisat/Solver/StreamBuffer.h new file mode 100644 index 000000000..6dc390415 --- /dev/null +++ b/src/prop/cryptominisat/Solver/StreamBuffer.h @@ -0,0 +1,78 @@ +/******************************************************************************************[Main.C] +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef STREAMBUFFER_H +#define STREAMBUFFER_H + +#define CHUNK_LIMIT 1048576 + +#ifndef DISABLE_ZLIB +#include <zlib.h> +#endif // DISABLE_ZLIB + +namespace CMSat +{ + +class StreamBuffer +{ + #ifdef DISABLE_ZLIB + FILE * in; + #else + gzFile in; + #endif // DISABLE_ZLIB + char buf[CHUNK_LIMIT]; + int pos; + int size; + + void assureLookahead() { + if (pos >= size) { + pos = 0; + #ifdef DISABLE_ZLIB + #ifdef VERBOSE_DEBUG + printf("buf = %08X\n", buf); + printf("sizeof(buf) = %u\n", sizeof(buf)); + #endif //VERBOSE_DEBUG + size = fread(buf, 1, sizeof(buf), in); + #else + size = gzread(in, buf, sizeof(buf)); + #endif // DISABLE_ZLIB + } + } + +public: + #ifdef DISABLE_ZLIB + StreamBuffer(FILE * i) : in(i), pos(0), size(0) { + #else + StreamBuffer(gzFile i) : in(i), pos(0), size(0) { + #endif // DISABLE_ZLIB + assureLookahead(); + } + + int operator * () { + return (pos >= size) ? EOF : buf[pos]; + } + void operator ++ () { + pos++; + assureLookahead(); + } +}; + +} + +#endif //STREAMBUFFER_H diff --git a/src/prop/cryptominisat/Solver/Subsumer.cpp b/src/prop/cryptominisat/Solver/Subsumer.cpp new file mode 100644 index 000000000..4b7eb4b2d --- /dev/null +++ b/src/prop/cryptominisat/Solver/Subsumer.cpp @@ -0,0 +1,2141 @@ +/***************************************************************************** +SatELite -- (C) Niklas Een, Niklas Sorensson, 2004 +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +Original code by SatELite authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3 licence. +******************************************************************************/ + +#include "Solver.h" +#include "Subsumer.h" +#include "ClauseCleaner.h" +#include "time_mem.h" +#include "assert.h" +#include <iomanip> +#include <cmath> +#include <algorithm> +#include "VarReplacer.h" +#include "XorFinder.h" +#include "CompleteDetachReattacher.h" +#include "OnlyNonLearntBins.h" +#include "UselessBinRemover.h" +#include "DataSync.h" +#include "constants.h" +#include "ClauseVivifier.h" + +//#define VERBOSE_DEBUG +#ifdef VERBOSE_DEBUG +#define BIT_MORE_VERBOSITY +#endif + +//#define BIT_MORE_VERBOSITY + +using namespace CMSat; + +Subsumer::Subsumer(Solver& s): + solver(s) + , totalTime(0.0) + , numElimed(0) + , numCalls(1) +{ +} + +/** +@brief Extends the model to include eliminated variables + +Adds the clauses to the parameter solver2, and then relies on the +caller to call solver2.solve(). + +@p solver2 The external solver the variables' clauses are added to +*/ +void Subsumer::extendModel(Solver& solver2) +{ + #ifdef VERBOSE_DEBUG + std::cout << "Subsumer::extendModel(Solver& solver2) called" << std::endl; + #endif + + assert(checkElimedUnassigned()); + vec<Lit> tmp; + typedef map<Var, vector<vector<Lit> > > elimType; + for (elimType::iterator it = elimedOutVar.begin(), end = elimedOutVar.end(); it != end; it++) { + #ifndef NDEBUG + Var var = it->first; + #ifdef VERBOSE_DEBUG + std::cout << "Reinserting elimed var: " << var+1 << std::endl; + #endif + assert(!solver.decision_var[var]); + assert(solver.assigns[var] == l_Undef); + assert(!solver.order_heap.inHeap(var)); + #endif + + for (vector<vector<Lit> >::const_iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { + tmp.clear(); + tmp.growTo(it2->size()); + std::copy(it2->begin(), it2->end(), tmp.getData()); + + #ifdef VERBOSE_DEBUG + std::cout << "Reinserting elimed clause: " << tmp << std::endl;; + #endif + + solver2.addClause(tmp); + assert(solver2.ok); + } + } + + typedef map<Var, vector<std::pair<Lit, Lit> > > elimType2; + for (elimType2::iterator it = elimedOutVarBin.begin(), end = elimedOutVarBin.end(); it != end; it++) { + #ifndef NDEBUG + Var var = it->first; + #ifdef VERBOSE_DEBUG + std::cout << "Reinserting elimed var: " << var+1 << std::endl; + #endif + assert(!solver.decision_var[var]); + assert(solver.assigns[var] == l_Undef); + assert(!solver.order_heap.inHeap(var)); + #endif + + for (vector<std::pair<Lit, Lit> >::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { + tmp.clear(); + tmp.growTo(2); + tmp[0] = it2->first; + tmp[1] = it2->second; + + #ifdef VERBOSE_DEBUG + std::cout << "Reinserting bin clause: " << it2->first << " , " << it2->second << std::endl; + #endif + + solver2.addClause(tmp); + assert(solver2.ok); + } + } +} + +/** +@brief Adds to the solver the clauses representing variable var + +This function is useful if a variable was eliminated, but now needs to be +added back again. + +@p var The variable to be added back again +*/ +bool Subsumer::unEliminate(const Var var) +{ + assert(var_elimed[var]); + vec<Lit> tmp; + typedef map<Var, vector<vector<Lit> > > elimType; + typedef map<Var, vector<std::pair<Lit, Lit> > > elimType2; + elimType::iterator it = elimedOutVar.find(var); + elimType2::iterator it2 = elimedOutVarBin.find(var); + + //it MUST have been decision var, otherwise we would + //never have removed it + solver.setDecisionVar(var, true); + var_elimed[var] = false; + numElimed--; + #ifdef VERBOSE_DEBUG + std::cout << "Reinserting normal (non-xor) elimed var: " << var+1 << std::endl; + #endif + + //If the variable was removed because of + //pure literal removal (by blocked clause + //elimination, there are no clauses to re-insert + if (it == elimedOutVar.end() && it2 == elimedOutVarBin.end()) { + return solver.ok; + } + + FILE* backup_libraryCNFfile = solver.libraryCNFFile; + solver.libraryCNFFile = NULL; + + if (it == elimedOutVar.end()) goto next; + for (vector<vector<Lit> >::iterator itt = it->second.begin(), end2 = it->second.end(); itt != end2; itt++) { + #ifdef VERBOSE_DEBUG + std::cout << "Reinserting elimed clause: "; + for (uint32_t i = 0; i < itt->size(); i++) { + std::cout << (*itt)[i] << " , "; + } + std::cout << std::endl; + #endif + tmp.clear(); + tmp.growTo(itt->size()); + std::copy(itt->begin(), itt->end(), tmp.getData()); + solver.addClause(tmp); + } + elimedOutVar.erase(it); + + next: + if (it2 == elimedOutVarBin.end()) goto next2; + for (vector<std::pair<Lit, Lit> >::iterator itt = it2->second.begin(), end2 = it2->second.end(); itt != end2; itt++) { + tmp.clear(); + tmp.growTo(2); + tmp[0] = itt->first; + tmp[1] = itt->second; + #ifdef VERBOSE_DEBUG + std::cout << "Reinserting bin clause: " << itt->first << " , " << itt->second << std::endl; + #endif + solver.addClause(tmp); + } + elimedOutVarBin.erase(it2); + + next2: + solver.libraryCNFFile = backup_libraryCNFfile; + + return solver.ok; +} + +/** +@brief Backward-subsumption using given clause: helper function + +Checks all clauses in the occurrence lists if they are subsumed by ps or not. + +The input clause can be learnt. In that case, if it subsumes non-learnt clauses, +it will become non-learnt. + +Handles it well if the subsumed clause has a higher activity than the subsuming +clause (will take the max() of the two) + +@p ps The clause to use + +*/ +void Subsumer::subsume0(Clause& ps) +{ + #ifdef VERBOSE_DEBUG + cout << "subsume0-ing with clause: "; + ps.plainPrint(); + #endif + subsume0Happened ret = subsume0Orig(ps, ps.getAbst()); + + if (ps.learnt()) { + if (!ret.subsumedNonLearnt) { + if (ps.getGlue() > ret.glue) + ps.setGlue(ret.glue); + if (ps.getMiniSatAct() < ret.act) + ps.setMiniSatAct(ret.act); + } else { + solver.nbCompensateSubsumer++; + ps.makeNonLearnt(); + } + } +} + +/** +@brief Backward-subsumption using given clause + +@note Use helper function + +@param ps The clause to use to backward-subsume +@param[in] abs The abstraction of the clause +@return Subsumed anything? If so, what was the max activity? Was it non-learnt? +*/ +template<class T> +Subsumer::subsume0Happened Subsumer::subsume0Orig(const T& ps, uint32_t abs) +{ + subsume0Happened ret; + ret.subsumedNonLearnt = false; + ret.glue = std::numeric_limits<uint32_t>::max(); + ret.act = std::numeric_limits< float >::min(); + + vec<ClauseSimp> subs; + findSubsumed(ps, abs, subs); + for (uint32_t i = 0; i < subs.size(); i++){ + #ifdef VERBOSE_DEBUG + cout << "-> subsume0 removing:"; + subs[i].clause->plainPrint(); + #endif + + Clause* tmp = subs[i].clause; + if (tmp->learnt()) { + ret.glue = std::min(ret.glue, tmp->getGlue()); + ret.act = std::max(ret.act, tmp->getMiniSatAct()); + } else { + ret.subsumedNonLearnt = true; + } + unlinkClause(subs[i]); + } + + return ret; +} + +/** +@brief Backward subsumption and self-subsuming resolution + +Performs backward subsumption AND +self-subsuming resolution using backward-subsumption + +@param[in] ps The clause to use for backw-subsumption and self-subs. resolution +*/ +void Subsumer::subsume1(Clause& ps) +{ + vec<ClauseSimp> subs; + vec<Lit> subsLits; + #ifdef VERBOSE_DEBUG + cout << "subsume1-ing with clause:"; + ps.plainPrint(); + #endif + + findSubsumed1(ps, ps.getAbst(), subs, subsLits); + for (uint32_t j = 0; j < subs.size(); j++) { + if (subs[j].clause == NULL) continue; + ClauseSimp c = subs[j]; + if (subsLits[j] == lit_Undef) { + if (ps.learnt()) { + if (c.clause->learnt()) ps.takeMaxOfStats(*c.clause); + else { + solver.nbCompensateSubsumer++; + ps.makeNonLearnt(); + } + } + unlinkClause(c); + } else { + strenghten(c, subsLits[j]); + if (!solver.ok) return; + } + } +} + +bool Subsumer::subsume1(vec<Lit>& ps, const bool wasLearnt) +{ + vec<ClauseSimp> subs; + vec<Lit> subsLits; + bool toMakeNonLearnt = false; + + findSubsumed1(ps, calcAbstraction(ps), subs, subsLits); + for (uint32_t j = 0; j < subs.size(); j++) { + if (subs[j].clause == NULL) continue; + ClauseSimp c = subs[j]; + if (subsLits[j] == lit_Undef) { + if (wasLearnt && !c.clause->learnt()) toMakeNonLearnt = true; + unlinkClause(c); + } else { + strenghten(c, subsLits[j]); + if (!solver.ok) return false; + } + } + + return toMakeNonLearnt; +} + +/** +@brief Removes&free-s a clause from everywhere + +Removes clause from occurence lists, from Subsumer::clauses, and iter_sets. + +If clause is to be removed because the variable in it is eliminated, the clause +is saved in elimedOutVar[] before it is fully removed. + +@param[in] c The clause to remove +@param[in] elim If the clause is removed because of variable elmination, this +parameter is different from var_Undef. +*/ +void Subsumer::unlinkClause(ClauseSimp c, const Var elim) +{ + Clause& cl = *c.clause; + + for (uint32_t i = 0; i < cl.size(); i++) { + if (elim != var_Undef) numMaxElim -= occur[cl[i].toInt()].size()/2; + else { + numMaxSubsume0 -= occur[cl[i].toInt()].size()/2; + numMaxSubsume1 -= occur[cl[i].toInt()].size()/2; + } + maybeRemove(occur[cl[i].toInt()], &cl); + touchedVars.touch(cl[i], cl.learnt()); + } + + // Remove from iterator vectors/sets: + for (uint32_t i = 0; i < iter_sets.size(); i++) { + CSet& cs = *iter_sets[i]; + cs.exclude(c); + } + + // Remove clause from clause touched set: + cl_touched.exclude(c); + + //Compensate if removing learnt + if (cl.learnt()) solver.nbCompensateSubsumer++; + + if (elim != var_Undef) { + assert(!cl.learnt()); + #ifdef VERBOSE_DEBUG + std::cout << "Eliminating non-bin clause: " << *c.clause << std::endl; + std::cout << "On variable: " << elim+1 << std::endl; + #endif //VERBOSE_DEBUG + vector<Lit> lits(c.clause->size()); + std::copy(c.clause->getData(), c.clause->getDataEnd(), lits.begin()); + elimedOutVar[elim].push_back(lits); + } else { + clauses_subsumed++; + } + solver.clauseAllocator.clauseFree(c.clause); + + clauses[c.index].clause = NULL; +} + + +/** +@brief Cleans clause from false literals + +This does NOT re-implement the feature of ClauseCleaner because +here we need to remove the literals from the occurrence lists as well. Further- +more, we need propagate if needed, which is never assumed to be a need in +ClauseCleaner since there the clauses are always attached to the watch- +lists. + +@param ps Clause to be cleaned +*/ +bool Subsumer::cleanClause(Clause& ps) +{ + bool retval = false; + + Lit *i = ps.getData(); + Lit *j = i; + for (Lit *end = ps.getDataEnd(); i != end; i++) { + lbool val = solver.value(*i); + if (val == l_Undef) { + *j++ = *i; + continue; + } + if (val == l_False) { + removeW(occur[i->toInt()], &ps); + numMaxSubsume1 -= occur[i->toInt()].size()/2; + touchedVars.touch(*i, ps.learnt()); + continue; + } + if (val == l_True) { + *j++ = *i; + retval = true; + continue; + } + assert(false); + } + ps.shrink(i-j); + + return retval; +} + +bool Subsumer::cleanClause(vec<Lit>& ps) const +{ + bool retval = false; + + Lit *i = ps.getData(); + Lit *j = i; + for (Lit *end = ps.getDataEnd(); i != end; i++) { + lbool val = solver.value(*i); + if (val == l_Undef) { + *j++ = *i; + continue; + } + if (val == l_False) + continue; + if (val == l_True) { + *j++ = *i; + retval = true; + continue; + } + assert(false); + } + ps.shrink(i-j); + + return retval; +} + +/** +@brief Removes a literal from a clause + +May return with solver.ok being FALSE, and may set&propagate variable values. + +@param c Clause to be cleaned of the literal +@param[in] toRemoveLit The literal to be removed from the clause +*/ +void Subsumer::strenghten(ClauseSimp& c, const Lit toRemoveLit) +{ + #ifdef VERBOSE_DEBUG + cout << "-> Strenghtening clause :"; + c.clause->plainPrint(); + cout << " with lit: " << toRemoveLit << std::endl; + #endif + + literals_removed++; + c.clause->strengthen(toRemoveLit); + removeW(occur[toRemoveLit.toInt()], c.clause); + numMaxSubsume1 -= occur[toRemoveLit.toInt()].size()/2; + touchedVars.touch(toRemoveLit, c.clause->learnt()); + + if (cleanClause(*c.clause)) { + unlinkClause(c); + c.clause = NULL; + return; + } + + switch (c.clause->size()) { + case 0: + #ifdef VERBOSE_DEBUG + std::cout << "Strenghtened clause to 0-size -> UNSAT"<< std::endl; + #endif //VERBOSE_DEBUG + solver.ok = false; + break; + case 1: { + handleSize1Clause((*c.clause)[0]); + unlinkClause(c); + c.clause = NULL; + break; + } + case 2: { + solver.attachBinClause((*c.clause)[0], (*c.clause)[1], (*c.clause).learnt()); + solver.numNewBin++; + solver.dataSync->signalNewBinClause(*c.clause); + clBinTouched.push_back(NewBinaryClause((*c.clause)[0], (*c.clause)[1], (*c.clause).learnt())); + unlinkClause(c); + c.clause = NULL; + break; + } + default: + cl_touched.add(c); + } +} + +bool Subsumer::handleClBinTouched() +{ + assert(solver.ok); + uint32_t clauses_subsumed_before = clauses_subsumed; + uint32_t literals_removed_before = literals_removed; + uint32_t clBinSize = 0; + + vec<Lit> lits(2); + for (list<NewBinaryClause>::const_iterator it = clBinTouched.begin(); it != clBinTouched.end(); it++) { + lits[0] = it->lit1; + lits[1] = it->lit2; + const bool learnt = it->learnt; + + if (subsume1(lits, learnt)) { + //if we can't find it, that must be because it has been made non-learnt + //note: if it has been removed through elimination, it must't + //be able to subsume any non-learnt clauses, so we never enter here + if (findWBin(solver.watches, lits[0], lits[1], true)) { + findWatchedOfBin(solver.watches, lits[0], lits[1], learnt).setLearnt(false); + findWatchedOfBin(solver.watches, lits[1], lits[0], learnt).setLearnt(false); + } + } + if (!solver.ok) return false; + clBinSize++; + } + clBinTouched.clear(); + + if (solver.conf.verbosity >= 3) { + std::cout << "c subs-w-newbins " << clauses_subsumed - clauses_subsumed_before + << " lits rem " << literals_removed - literals_removed_before + << " went through: " << clBinSize << std::endl; + } + + return true; +} + +/** +@brief Handles if a clause became 1-long (unitary) + +Either sets&propagates the value, ignores the value (if already set), +or sets solver.ok = FALSE + +@param[in] lit The single literal the clause has +*/ +inline void Subsumer::handleSize1Clause(const Lit lit) +{ + if (solver.value(lit) == l_False) { + solver.ok = false; + } else if (solver.value(lit) == l_Undef) { + solver.uncheckedEnqueue(lit); + solver.ok = solver.propagate<false>().isNULL(); + } else { + assert(solver.value(lit) == l_True); + } +} + +/** +@brief Executes subsume1() recursively on all clauses + +This function requires cl_touched to have been set. Then, it manages cl_touched. +The clauses are called to perform subsume1() or subsume0() when appropriate, and +when there is enough numMaxSubume1 and numMaxSubume0 is available. +*/ +bool Subsumer::subsume0AndSubsume1() +{ + CSet s0, s1; + + uint32_t clTouchedTodo = 2000; + if (addedClauseLits > 3000000) clTouchedTodo /= 2; + if (addedClauseLits > 10000000) clTouchedTodo /= 4; + + registerIteration(s0); + registerIteration(s1); + vec<ClauseSimp> remClTouched; + + // Fixed-point for 1-subsumption: + #ifdef BIT_MORE_VERBOSITY + std::cout << "c cl_touched.nElems() = " << cl_touched.nElems() << std::endl; + #endif + while ((cl_touched.nElems() > 10) && numMaxSubsume0 > 0) { + #ifdef VERBOSE_DEBUG + std::cout << "c -- subsume0AndSubsume1() round --" << std::endl; + std::cout << "c cl_touched.nElems() = " << cl_touched.nElems() << std::endl; + std::cout << "c clauses.size() = " << clauses.size() << std::endl; + std::cout << "c numMaxSubsume0:" << numMaxSubsume0 << std::endl; + std::cout << "c numMaxSubsume1:" << numMaxSubsume1 << std::endl; + std::cout << "c numMaxElim:" << numMaxElim << std::endl; + #endif //VERBOSE_DEBUG + + uint32_t s1Added = 0; + const bool doSubs1Next = (numMaxSubsume1 > 0); + for (CSet::iterator it = cl_touched.begin(), end = cl_touched.end(); it != end; ++it) { + if (it->clause == NULL) continue; + Clause& cl = *it->clause; + + if (s1Added >= clTouchedTodo) { + break; + } + + s0.add(*it); + s1Added += s1.add(*it); + bool unset = true; + + for (uint32_t j = 0; j < cl.size(); j++) { + if (!ol_seenPos[cl[j].toInt()]) { + vec<ClauseSimp>& occs = occur[(cl[j]).toInt()]; + for (uint32_t k = 0; k < occs.size(); k++) { + if (s1Added >= clTouchedTodo) { + unset = false; + break; + } + s0.add(occs[k]); + } + } + ol_seenPos[cl[j].toInt()] = 1; + + if (s1Added >= clTouchedTodo) { + unset = false; + break; + } + + if (!ol_seenNeg[(~cl[j]).toInt()]) { + vec<ClauseSimp>& occs = occur[(~cl[j]).toInt()]; + for (uint32_t k = 0; k < occs.size(); k++) { + if (s1Added >= clTouchedTodo) { + unset = false; + break; + } + + s1Added += s1.add(occs[k]); + } + } + ol_seenNeg[(~cl[j]).toInt()] = 1; + + if (s1Added >= clTouchedTodo) { + unset = false; + break; + } + } + + remClTouched.push(*it); + if (doSubs1Next && unset) + it->clause->unsetChanged(); + } + //std::cout << "s0.nElems(): " << s0.nElems() << std::endl; + //std::cout << "s1.nElems(): " << s1.nElems() << std::endl; + + for (uint32_t i = 0; i < remClTouched.size(); i++) { + cl_touched.exclude(remClTouched[i]); + } + remClTouched.clear(); + + for (CSet::iterator it = s0.begin(), end = s0.end(); it != end; ++it) { + if (it->clause == NULL) continue; + subsume0(*it->clause); + } + s0.clear(); + + if (doSubs1Next) { + for (CSet::iterator it = s1.begin(), end = s1.end(); it != end; ++it) { + if (it->clause == NULL) continue; + subsume1(*it->clause); + if (!solver.ok) goto end; + } + s1.clear(); + } + + if (!handleClBinTouched()) goto end; + } + cl_touched.clear(); + end: + + unregisterIteration(s1); + unregisterIteration(s0); + + return solver.ok; +} + +/** +@brief Links in a clause into the occurrence lists and the clauses[] + +Increments clauseID + +@param[in] cl The clause to link in +*/ +ClauseSimp Subsumer::linkInClause(Clause& cl) +{ + ClauseSimp c(&cl, clauseID++); + clauses.push(c); + for (uint32_t i = 0; i < cl.size(); i++) { + occur[cl[i].toInt()].push(c); + touchedVars.touch(cl[i], cl.learnt()); + if (cl.getChanged()) { + ol_seenPos[cl[i].toInt()] = 0; + ol_seenNeg[(~cl[i]).toInt()] = 0; + } + } + if (cl.getChanged()) + cl_touched.add(c); + + return c; +} + +/** +@brief Adds clauses from the solver to here, and removes them from the solver + +Which clauses are needed can be controlled by the parameters + +@param[in] cs The clause-set to use, e.g. solver.binaryClauses, solver.learnts +@param[in] alsoLearnt Also add learnt clauses? +@param[in] addBinAndAddToCL If set to FALSE, binary clauses are not added, and +clauses are never added to the cl_touched set. +*/ +uint64_t Subsumer::addFromSolver(vec<Clause*>& cs) +{ + uint64_t numLitsAdded = 0; + Clause **i = cs.getData(); + Clause **j = i; + for (Clause **end = i + cs.size(); i != end; i++) { + if (i+1 != end) __builtin_prefetch(*(i+1)); + + linkInClause(**i); + numLitsAdded += (*i)->size(); + } + cs.shrink(i-j); + + return numLitsAdded; +} + +/** +@brief Frees memory occupied by occurrence lists +*/ +void Subsumer::freeMemory() +{ + for (uint32_t i = 0; i < occur.size(); i++) { + occur[i].clear(true); + } +} + +/** +@brief Adds clauses from here, back to the solver +*/ +void Subsumer::addBackToSolver() +{ + assert(solver.clauses.size() == 0); + for (uint32_t i = 0; i < clauses.size(); i++) { + if (clauses[i].clause == NULL) continue; + assert(clauses[i].clause->size() > 2); + + if (clauses[i].clause->learnt()) + solver.learnts.push(clauses[i].clause); + else + solver.clauses.push(clauses[i].clause); + } +} + +/** +@brief Remove clauses from input that contain eliminated variables + +Used to remove learnt clauses that still reference a variable that has been +eliminated. +*/ +void Subsumer::removeWrong(vec<Clause*>& cs) +{ + Clause **i = cs.getData(); + Clause **j = i; + for (Clause **end = i + cs.size(); i != end; i++) { + Clause& c = **i; + if (!c.learnt()) { + *j++ = *i; + continue; + } + bool remove = false; + for (Lit *l = c.getData(), *end2 = l+c.size(); l != end2; l++) { + if (var_elimed[l->var()]) { + remove = true; + //solver.detachClause(c); + solver.clauseAllocator.clauseFree(&c); + break; + } + } + if (!remove) + *j++ = *i; + } + cs.shrink(i-j); +} + +void Subsumer::removeWrongBinsAndAllTris() +{ + uint32_t numRemovedHalfLearnt = 0; + uint32_t wsLit = 0; + for (vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + vec<Watched>& ws = *it; + + vec<Watched>::iterator i = ws.getData(); + vec<Watched>::iterator j = i; + for (vec<Watched>::iterator end2 = ws.getDataEnd(); i != end2; i++) { + if (i->isTriClause()) continue; + + if (i->isBinary() + && (var_elimed[lit.var()] || var_elimed[i->getOtherLit().var()]) + ) { + assert(i->getLearnt()); + numRemovedHalfLearnt++; + } else { + *j++ = *i; + } + } + ws.shrink_(i - j); + } + + assert(numRemovedHalfLearnt % 2 == 0); + solver.learnts_literals -= numRemovedHalfLearnt; + solver.numBins -= numRemovedHalfLearnt/2; +} + +/** +@brief Fills the vector cannot_eliminate + +Variables that are: +* also present in XOR-clauses, or +* have been replaced +cannot be eliminated. This is enforced by the vector cannot_elimnate +*/ +void Subsumer::fillCannotEliminate() +{ + std::fill(cannot_eliminate.getData(), cannot_eliminate.getDataEnd(), false); + for (uint32_t i = 0; i < solver.xorclauses.size(); i++) { + const XorClause& c = *solver.xorclauses[i]; + for (uint32_t i2 = 0; i2 < c.size(); i2++) + cannot_eliminate[c[i2].var()] = true; + } + + for (Var var = 0; var < solver.nVars(); var++) { + cannot_eliminate[var] |= solver.varReplacer->cannot_eliminate[var]; + } + + #ifdef VERBOSE_DEBUG + uint32_t tmpNum = 0; + for (uint32_t i = 0; i < cannot_eliminate.size(); i++) + if (cannot_eliminate[i]) + tmpNum++; + std::cout << "Cannot eliminate num:" << tmpNum << std::endl; + #endif +} + +/** +@brief Subsumes&strenghtens normal clauses with (non-existing) binary clauses + +First, it backward-subsumes and performs self-subsuming resolution using binary +clauses on non-binary clauses. Then, it generates non-existing binary clauses +(that could exist, but would be redundant), and performs self-subsuming +resolution with them on the normal clauses using \function subsume0BIN(). +*/ +/*bool Subsumer::subsumeWithBinTri() +{ + assert(solver.ok); + + double mytime = cpuTime(); + uint32_t subsumed_bin = 0; + uint32_t subsumed_tri = 0; + uint32_t lit_rem_bin = 0; + uint32_t lit_rem_tri = 0; + if (!subsumeWithBinTri(solver.clauses, false, subsumed_bin, subsumed_tri, lit_rem_bin, lit_rem_tri)) + return false; + + if (!subsumeWithBinTri(solver.learnts, true, subsumed_bin, subsumed_tri, lit_rem_bin, lit_rem_tri)) + return false; + + if (solver.conf.verbosity > 0) { + std::cout + << "c subs-w-b: " << subsumed_bin + << " subs-w-t: " << subsumed_tri + << " lit-rem-w-b: " << lit_rem_bin + << " lit-rem-w-t: " << lit_rem_tri + << " T: " << std::fixed << std::setprecision(2) << (cpuTime() - mytime) + << std::endl; + } + return true; +} + +bool Subsumer::subsumeWithBinTri( + vec<Clause*>& cls + , bool learnt + , uint32_t& subsumed_bin_num + , uint32_t& subsumed_tri_num + , uint32_t& lit_rem_bin + , uint32_t& lit_rem_tri +) { + //Temporaries + vector<Lit> lits_set; + vector<char> seen_tmp2; + seen_tmp2.resize(solver.nVars()*2); + uint32_t to_remove_bin = 0; + uint32_t to_remove_tri = 0; + + Clause** cit = cls.getData(); + Clause** cit2 = cit; + Clause** cend = cls.getDataEnd(); + + for(; cit2 != cend; cit2++) { + Clause& c = **cit2; + + //Set up seen_tmp + lits_set.resize(c.size()); + for(size_t i = 0; i < c.size(); i++) { + seen_tmp[c[i].toInt()] = 1; + seen_tmp2[c[i].toInt()] = 1; + lits_set[i] = c[i]; + } + + bool subsumed = false; + + + if (subsumed) { +#ifdef VERBOSE_DEBUG + std::cout << "Removing: "; + c.plainPrint(); +#endif + solver.removeClause(c); + } else if (to_remove_bin > 0 || to_remove_tri > 0) { + lit_rem_bin += to_remove_bin; + lit_rem_tri += to_remove_tri; + solver.detachClause(c); + +#ifdef VERBOSE_DEBUG + std::cout << "Detached clause: (ptr: " << (&c) << " ) "; + c.plainPrint();; +#endif + + vec<Lit> lits; + for(size_t i = 0; i < c.size(); i++) { + if (seen_tmp2[c[i].toInt()]) + lits.push(c[i]); + } + + Clause *c2 = solver.addClauseInt(lits, c.learnt(), c.getGlue(), c.getMiniSatAct()); + solver.clauseAllocator.clauseFree(&c); + if (c2 != NULL) { + *cit++ = c2; + } + + if (!solver.ok) { + break; + } + } else { + *cit++ = *cit2; + } + + for(vector<Lit>::const_iterator it = lits_set.begin(), end = lits_set.end(); it != end; it++) { + seen_tmp[it->toInt()] = 0; + seen_tmp2[it->toInt()] = 0; + } + lits_set.clear(); + to_remove_bin = 0; + to_remove_tri = 0; + } + cls.shrink(cit2-cit); + + return solver.ok; +}*/ + +/** +@brief Clears and deletes (almost) everything in this class + +Clears touchlists, occurrance lists, clauses, and variable touched lists +*/ +void Subsumer::clearAll() +{ + touchedVars.clear(); + clauses.clear(); + cl_touched.clear(); + addedClauseLits = 0; + for (Var var = 0; var < solver.nVars(); var++) { + occur[2*var].clear(); + occur[2*var+1].clear(); + ol_seenNeg[2*var ] = 1; + ol_seenNeg[2*var + 1] = 1; + ol_seenPos[2*var ] = 1; + ol_seenPos[2*var + 1] = 1; + } +} + +bool Subsumer::eliminateVars() +{ + #ifdef BIT_MORE_VERBOSITY + std::cout << "c VARIABLE ELIMINIATION -- touchedVars size:" << touchedVars.size() << std::endl; + #endif + + uint32_t vars_elimed = 0; + + vec<Var> order; + orderVarsForElim(order); + + #ifdef VERBOSE_DEBUG + std::cout << "c #order size:" << order.size() << std::endl; + #endif + + uint32_t numtry = 0; + for (uint32_t i = 0; i < order.size() && numMaxElim > 0 && numMaxElimVars > 0; i++) { + Var var = order[i]; + if (!cannot_eliminate[var] && solver.decision_var[var]) { + numtry++; + if (maybeEliminate(order[i])) { + if (!solver.ok) return false; + vars_elimed++; + numMaxElimVars--; + } + } + } + numVarsElimed += vars_elimed; + + #ifdef BIT_MORE_VERBOSITY + std::cout << "c #try to eliminate: " << numtry << std::endl; + std::cout << "c #var-elim: " << vars_elimed << std::endl; + #endif + + return true; +} + +void Subsumer::subsumeBinsWithBins() +{ + double myTime = cpuTime(); + uint32_t numBinsBefore = solver.numBins; + + uint32_t wsLit = 0; + for (vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + vec<Watched>& ws = *it; + Lit lit = ~Lit::toLit(wsLit); + if (ws.size() < 2) continue; + + std::sort(ws.getData(), ws.getDataEnd(), BinSorter()); + + vec<Watched>::iterator i = ws.getData(); + vec<Watched>::iterator j = i; + + Lit lastLit = lit_Undef; + bool lastLearnt = false; + for (vec<Watched>::iterator end = ws.getDataEnd(); i != end; i++) { + if (!i->isBinary()) { + *j++ = *i; + continue; + } + if (i->getOtherLit() == lastLit) { + //The sorting algorithm prefers non-learnt to learnt, so it is + //impossible to have non-learnt before learnt + assert(!(i->getLearnt() == false && lastLearnt == true)); + + assert(i->getOtherLit().var() != lit.var()); + removeWBin(solver.watches[(~(i->getOtherLit())).toInt()], lit, i->getLearnt()); + if (i->getLearnt()) solver.learnts_literals -= 2; + else { + solver.clauses_literals -= 2; + touchedVars.touch(lit, i->getLearnt()); + touchedVars.touch(i->getOtherLit(), i->getLearnt()); + } + solver.numBins--; + } else { + lastLit = i->getOtherLit(); + lastLearnt = i->getLearnt(); + *j++ = *i; + } + } + ws.shrink_(i-j); + } + + if (solver.conf.verbosity >= 1) { + std::cout << "c bin-w-bin subsume rem " + << std::setw(10) << (numBinsBefore - solver.numBins) << " bins " + << " time: " + << std::fixed << std::setprecision(2) << std::setw(5) << (cpuTime() - myTime) + << " s" << std::endl; + } + totalTime += cpuTime() - myTime; + clauses_subsumed += (numBinsBefore - solver.numBins); +} + +/** +@brief Main function in this class + +Performs, recursively: +* backward-subsumption +* self-subsuming resolution +* variable elimination + +*/ +bool Subsumer::simplifyBySubsumption() +{ + if (solver.nClauses() > 50000000 + || solver.clauses_literals > 500000000) return true; + + double myTime = cpuTime(); + clauseID = 0; + clearAll(); + + //touch all variables + for (Var var = 0; var < solver.nVars(); var++) { + if (solver.decision_var[var] && solver.assigns[var] == l_Undef) touchedVars.touch(var); + } + + if (solver.conf.doReplace && !solver.varReplacer->performReplace(true)) + return false; + /*if (solver.conf.doSubsWBins && !subsumeWithBinTri()) + return false;*/ + + fillCannotEliminate(); + + uint32_t expected_size = solver.clauses.size() + solver.learnts.size(); + if (expected_size > 10000000) return solver.ok; + + clauses.reserve(expected_size); + cl_touched.reserve(expected_size); + + solver.clauseCleaner->cleanClauses(solver.clauses, ClauseCleaner::clauses); + solver.clauseCleaner->cleanClauses(solver.learnts, ClauseCleaner::learnts); + + if (solver.clauses.size() < 10000000) + std::sort(solver.clauses.getData(), solver.clauses.getDataEnd(), sortBySize()); + addedClauseLits += addFromSolver(solver.clauses); + + if (solver.learnts.size() < 300000) + std::sort(solver.learnts.getData(), solver.learnts.getDataEnd(), sortBySize()); + addedClauseLits += addFromSolver(solver.learnts); + + CompleteDetachReatacher reattacher(solver); + reattacher.detachNonBinsNonTris(false); + totalTime += myTime - cpuTime(); + + //Do stuff with binaries + subsumeBinsWithBins(); + numMaxSubsume1 = 500*1000*1000; + if ((solver.conf.doBlockedClause) + && solver.conf.doVarElim) { + numMaxBlockToVisit = (int64_t)800*1000*1000; + blockedClauseRemoval(); + } + + numMaxSubsume1 = 2*1000*1000*1000; + //if (solver.conf.doSubsWNonExistBins && !subsWNonExitsBinsFullFull()) return false; + if (!handleClBinTouched()) return false; + + if (solver.conf.doReplace && solver.conf.doRemUselessBins) { + UselessBinRemover uselessBinRemover(solver); + if (!uselessBinRemover.removeUslessBinFull()) return false; + } + + myTime = cpuTime(); + setLimits(); + clauses_subsumed = 0; + literals_removed = 0; + numVarsElimed = 0; + uint32_t origTrailSize = solver.trail.size(); + + #ifdef BIT_MORE_VERBOSITY + std::cout << "c time until pre-subsume0 clauses and subsume1 2-learnts:" << cpuTime()-myTime << std::endl; + std::cout << "c pre-subsumed:" << clauses_subsumed << std::endl; + std::cout << "c cl_touched:" << cl_touched.nElems() << std::endl; + std::cout << "c clauses:" << clauses.size() << std::endl; + std::cout << "c numMaxSubsume0:" << numMaxSubsume0 << std::endl; + std::cout << "c numMaxSubsume1:" << numMaxSubsume1 << std::endl; + std::cout << "c numMaxElim:" << numMaxElim << std::endl; + #endif + + do { + if (!subsume0AndSubsume1()) return false; + + if (!solver.conf.doVarElim) break; + + if (!eliminateVars()) return false; + + //subsumeBinsWithBins(); + solver.clauseCleaner->removeSatisfiedBins(); + } while (cl_touched.nElems() > 10); + + if (!solver.ok) return false; + + assert(verifyIntegrity()); + + removeWrong(solver.learnts); + removeWrongBinsAndAllTris(); + removeAssignedVarsFromEliminated(); + + solver.order_heap.filter(Solver::VarFilter(solver)); + + addBackToSolver(); + if (!reattacher.reattachNonBins()) return false; + + if (solver.conf.verbosity >= 1) { + std::cout << "c lits-rem: " << std::setw(9) << literals_removed + << " cl-subs: " << std::setw(8) << clauses_subsumed + << " v-elim: " << std::setw(6) << numVarsElimed + << " v-fix: " << std::setw(4) <<solver.trail.size() - origTrailSize + << " time: " << std::setprecision(2) << std::setw(5) << (cpuTime() - myTime) << " s" + //<< " blkClRem: " << std::setw(5) << numblockedClauseRemoved + << std::endl; + } + totalTime += cpuTime() - myTime; + + solver.testAllClauseAttach(); + return true; +} + +/** +@brief Calculate limits for backw-subsumption, var elim, etc. + +It is important to have limits, otherwise the time taken to perfom these tasks +could be huge. Furthermore, it seems that there is a benefit in doing these +simplifications slowly, instead of trying to use them as much as possible +from the beginning. +*/ +void Subsumer::setLimits() +{ + numMaxSubsume0 = 300*1000*1000; + numMaxSubsume1 = 30*1000*1000; + + numMaxElim = 500*1000*1000; + numMaxElim *= 6; + + #ifdef BIT_MORE_VERBOSITY + std::cout << "c addedClauseLits: " << addedClauseLits << std::endl; + #endif + + if (addedClauseLits < 5000000) { + numMaxElim *= 2; + numMaxSubsume0 *= 2; + numMaxSubsume1 *= 2; + } + + if (addedClauseLits < 1000000) { + numMaxElim *= 2; + numMaxSubsume0 *= 2; + numMaxSubsume1 *= 2; + } + + numMaxElimVars = (uint64_t) (((double)solver.order_heap.size()*0.3) * sqrt((double)numCalls)); + + if (solver.order_heap.size() > 200000) + numMaxBlockVars = (uint32_t)((double)solver.order_heap.size() / 3.5 * (0.8+(double)(numCalls)/4.0)); + else + numMaxBlockVars = (uint32_t)((double)solver.order_heap.size() / 1.5 * (0.8+(double)(numCalls)/4.0)); + + if (!solver.conf.doSubsume1) + numMaxSubsume1 = 0; + + + numCalls++; + + //For debugging + + //numMaxSubsume0 = 0; + //numMaxSubsume1 = 0; + //numMaxSubsume0 = std::numeric_limits<int64_t>::max(); + //numMaxSubsume1 = std::numeric_limits<int64_t>::max(); + //numMaxElimVars = std::numeric_limits<int32_t>::max(); + //numMaxElim = std::numeric_limits<int64_t>::max(); + + //numMaxBlockToVisit = std::numeric_limits<int64_t>::max(); + //numMaxBlockVars = std::numeric_limits<uint32_t>::max(); +} + +/*bool Subsumer::subsWNonExitsBinsFullFull() +{ + double myTime = cpuTime(); + clauses_subsumed = 0; + literals_removed = 0; + for (vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++) { + if (it->size() < 2) continue; + std::sort(it->getData(), it->getDataEnd(), BinSorter2()); + } + uint32_t oldTrailSize = solver.trail.size(); + if (!subsWNonExistBinsFull()) return false; + if (solver.conf.verbosity >= 1) { + std::cout << "c Subs w/ non-existent bins: " << std::setw(6) << clauses_subsumed + << " l-rem: " << std::setw(6) << literals_removed + << " v-fix: " << std::setw(5) << solver.trail.size() - oldTrailSize + << " done: " << std::setw(6) << doneNum + << " time: " << std::fixed << std::setprecision(2) << std::setw(5) << (cpuTime() - myTime) << " s" + << std::endl; + } + totalTime += cpuTime() - myTime; + return true; +} + +#define MAX_BINARY_PROP 60000000 + +bool Subsumer::subsWNonExistBinsFull() +{ + uint64_t oldProps = solver.propagations; + uint64_t maxProp = MAX_BINARY_PROP*7; + toVisitAll.clear(); + toVisitAll.growTo(solver.nVars()*2, false); + extraTimeNonExist = 0; + OnlyNonLearntBins* onlyNonLearntBins = NULL; + if (solver.clauses_literals < 10*1000*1000) { + onlyNonLearntBins = new OnlyNonLearntBins(solver); + onlyNonLearntBins->fill(); + solver.multiLevelProp = true; + } + + doneNum = 0; + uint32_t startFrom = solver.mtrand.randInt(solver.order_heap.size()); + for (uint32_t i = 0; i < solver.order_heap.size(); i++) { + Var var = solver.order_heap[(startFrom + i) % solver.order_heap.size()]; + if (solver.propagations + extraTimeNonExist*150 > oldProps + maxProp) break; + if (solver.assigns[var] != l_Undef || !solver.decision_var[var]) continue; + doneNum++; + extraTimeNonExist += 5; + + Lit lit(var, true); + if (onlyNonLearntBins != NULL && onlyNonLearntBins->getWatchSize(lit) == 0) goto next; + if (!subsWNonExistBins(lit, onlyNonLearntBins)) { + if (!solver.ok) return false; + solver.cancelUntilLight(); + solver.uncheckedEnqueue(~lit); + solver.ok = solver.propagate<false>().isNULL(); + if (!solver.ok) return false; + continue; + } + extraTimeNonExist += 10; + next: + + //in the meantime it could have got assigned + if (solver.assigns[var] != l_Undef) continue; + lit = ~lit; + if (onlyNonLearntBins != NULL && onlyNonLearntBins->getWatchSize(lit) == 0) continue; + if (!subsWNonExistBins(lit, onlyNonLearntBins)) { + if (!solver.ok) return false; + solver.cancelUntilLight(); + solver.uncheckedEnqueue(~lit); + solver.ok = solver.propagate<false>().isNULL(); + if (!solver.ok) return false; + continue; + } + extraTimeNonExist += 10; + } + + if (onlyNonLearntBins) delete onlyNonLearntBins; + + return true; +} + +bool Subsumer::subsWNonExistBins(const Lit& lit, OnlyNonLearntBins* onlyNonLearntBins) +{ + #ifdef VERBOSE_DEBUG + std::cout << "subsWNonExistBins called with lit " << lit << std::endl; + #endif //VERBOSE_DEBUG + toVisit.clear(); + solver.newDecisionLevel(); + solver.uncheckedEnqueueLight(lit); + bool failed; + if (onlyNonLearntBins == NULL) + failed = (!solver.propagateNonLearntBin().isNULL()); + else + failed = !onlyNonLearntBins->propagate(); + if (failed) return false; + uint32_t abst = 0; + + assert(solver.decisionLevel() > 0); + for (int sublevel = solver.trail.size()-1; sublevel > (int)solver.trail_lim[0]; sublevel--) { + Lit x = solver.trail[sublevel]; + toVisit.push(x); + abst |= 1 << (x.var() & 31); + toVisitAll[x.toInt()] = true; + } + solver.cancelUntilLight(); + subsume0BIN(~lit, toVisitAll, abst); + + for (uint32_t i = 0; i < toVisit.size(); i++) + toVisitAll[toVisit[i].toInt()] = false; + + return solver.ok; +} + +void Subsumer::subsume0BIN(const Lit lit1, const vec<char>& lits, const uint32_t abst) +{ + vec<ClauseSimp> subs; + vec<ClauseSimp> subs2; + vec<Lit> subs2Lit; + + vec<ClauseSimp>& cs = occur[lit1.toInt()]; + for (ClauseSimp *it = cs.getData(), *end = it + cs.size(); it != end; it++){ + if (it+1 != end) __builtin_prefetch((it+1)->clause); + if (it->clause == NULL) continue; + + Clause& c = *it->clause; + if ((c.getAbst() & abst) == 0) continue; + extraTimeNonExist += c.size()*2; + bool removed = false; + bool removedLit = false; + for (uint32_t i = 0; i < c.size(); i++) { + if (lits[c[i].toInt()]) { + subs.push(*it); + removed = true; + break; + } + + if (!removedLit && lits[(~c[i]).toInt()]) { + subs2.push(*it); + subs2Lit.push(c[i]); + removedLit = true; + } + } + + if (removed && removedLit) { + subs2.pop(); + subs2Lit.pop(); + } + } + + for (uint32_t i = 0; i < subs.size(); i++){ + unlinkClause(subs[i]); + } + + for (uint32_t i = 0; i < subs2.size(); i++) { + strenghten(subs2[i], subs2Lit[i]); + if (!solver.ok) break; + } + + #ifdef VERBOSE_DEBUG + if (!solver.ok) { + std::cout << "solver.ok is false when returning from subsume0BIN()" << std::endl; + } + #endif //VERBOSE_DEBUG +}*/ + + + +/** +@brief Remove variables from var_elimed if it has been set + +While doing, e.g. self-subsuming resolution, it might happen that the variable +that we JUST eliminated has been assigned a value. This could happen for example +if due to clause-cleaning some variable value got propagated that we just set. +Therefore, we must check at the very end if any variables that we eliminated +got set, and if so, the clauses linked to these variables can be fully removed +from elimedOutVar[]. +*/ +void Subsumer::removeAssignedVarsFromEliminated() +{ + for (Var var = 0; var < var_elimed.size(); var++) { + if (var_elimed[var] && solver.assigns[var] != l_Undef) { + var_elimed[var] = false; + solver.setDecisionVar(var, true); + numElimed--; + + map<Var, vector<vector<Lit> > >::iterator it = elimedOutVar.find(var); + if (it != elimedOutVar.end()) elimedOutVar.erase(it); + + map<Var, vector<std::pair<Lit, Lit> > >::iterator it2 = elimedOutVarBin.find(var); + if (it2 != elimedOutVarBin.end()) elimedOutVarBin.erase(it2); + } + } +} + +/** +@brief Finds clauses that are backward-subsumed by given clause + +Only handles backward-subsumption. Uses occurrence lists + +@param[in] ps The clause to backward-subsume with. +@param[in] abs Abstraction of the clause ps +@param[out] out_subsumed The set of clauses subsumed by this clause +*/ +template<class T> +void Subsumer::findSubsumed(const T& ps, uint32_t abs, vec<ClauseSimp>& out_subsumed) +{ + #ifdef VERBOSE_DEBUG + cout << "findSubsumed: " << ps << std::endl; + #endif + + for (uint32_t i = 0; i != ps.size(); i++) + seen_tmp[ps[i].toInt()] = 1; + + uint32_t min_i = 0; + for (uint32_t i = 1; i < ps.size(); i++){ + if (occur[ps[i].toInt()].size() < occur[ps[min_i].toInt()].size()) + min_i = i; + } + + vec<ClauseSimp>& cs = occur[ps[min_i].toInt()]; + numMaxSubsume0 -= cs.size()*10 + 5; + for (ClauseSimp *it = cs.getData(), *end = it + cs.size(); it != end; it++){ + if (it+1 != end) __builtin_prefetch((it+1)->clause); + + if (it->clause != (Clause*)&ps + && subsetAbst(abs, it->clause->getAbst()) + && ps.size() <= it->clause->size()) { + numMaxSubsume0 -= (*it).clause->size() + ps.size(); + if (subset(ps.size(), *it->clause)) { + out_subsumed.push(*it); + #ifdef VERBOSE_DEBUG + cout << "subsumed: "; + it->clause->plainPrint(); + #endif + } + } + } + + for (uint32_t i = 0; i != ps.size(); i++) + seen_tmp[ps[i].toInt()] = 0; +} + +/** +@brief Checks if clauses are subsumed or could be strenghtened with given clause + +Checks if: +* any clause is subsumed with given clause +* the given clause could perform self-subsuming resolution on any other clause + +Only takes into consideration clauses that are in the occurrence lists. + +@param[in] ps The clause to perform the above listed algos with +@param[in] abs The abstraction of clause ps +@param[out] out_subsumed The clauses that could be modified by ps +@param[out] out_lits Defines HOW these clauses could be modified. By removing +literal, or by subsumption (in this case, there is lit_Undef here) +*/ +template<class T> +void Subsumer::findSubsumed1(const T& ps, uint32_t abs, vec<ClauseSimp>& out_subsumed, vec<Lit>& out_lits) +{ + #ifdef VERBOSE_DEBUG + cout << "findSubsumed1: " << ps << std::endl; + #endif + + Var minVar = var_Undef; + uint32_t bestSize = std::numeric_limits<uint32_t>::max(); + for (uint32_t i = 0; i < ps.size(); i++){ + uint32_t newSize = occur[ps[i].toInt()].size()+ occur[(~ps[i]).toInt()].size(); + if (newSize < bestSize) { + minVar = ps[i].var(); + bestSize = newSize; + } + } + assert(minVar != var_Undef); + + numMaxSubsume1 -= bestSize*10 + 10; + fillSubs(ps, abs, out_subsumed, out_lits, Lit(minVar, true)); + fillSubs(ps, abs, out_subsumed, out_lits, Lit(minVar, false)); +} + +/** +@brief Helper function for findSubsumed1 + +Used to avoid duplication of code +*/ +template<class T> +void inline Subsumer::fillSubs(const T& ps, uint32_t abs, vec<ClauseSimp>& out_subsumed, vec<Lit>& out_lits, const Lit lit) +{ + Lit litSub; + vec<ClauseSimp>& cs = occur[lit.toInt()]; + for (ClauseSimp *it = cs.getData(), *end = it + cs.size(); it != end; it++) { + if (it+1 != end) __builtin_prefetch((it+1)->clause); + + if (it->clause != (Clause*)&ps + && subsetAbst(abs, it->clause->getAbst()) + && ps.size() <= it->clause->size()) { + numMaxSubsume1 -= (*it).clause->size() + ps.size(); + litSub = subset1(ps, *it->clause); + if (litSub != lit_Error) { + out_subsumed.push(*it); + out_lits.push(litSub); + #ifdef VERBOSE_DEBUG + if (litSub == lit_Undef) cout << "subsume0-d: "; + else cout << "subsume1-ed (lit: " << litSub << "): "; + it->clause->plainPrint(); + #endif + } + } + } +} + + +void Subsumer::removeClausesHelper(vec<ClAndBin>& todo, const Var var, std::pair<uint32_t, uint32_t>& removed) +{ + pair<uint32_t, uint32_t> tmp; + for (uint32_t i = 0; i < todo.size(); i++) { + ClAndBin& c = todo[i]; + if (!c.isBin) { + unlinkClause(c.clsimp, var); + } else { + #ifdef VERBOSE_DEBUG + std::cout << "Eliminating bin clause: " << c.lit1 << " , " << c.lit2 << std::endl; + std::cout << "On variable: " << var+1 << std::endl; + #endif + assert(var == c.lit1.var() || var == c.lit2.var()); + tmp = removeWBinAll(solver.watches[(~c.lit1).toInt()], c.lit2); + //assert(tmp.first > 0 || tmp.second > 0); + removed.first += tmp.first; + removed.second += tmp.second; + + tmp = removeWBinAll(solver.watches[(~c.lit2).toInt()], c.lit1); + //assert(tmp.first > 0 || tmp.second > 0); + removed.first += tmp.first; + removed.second += tmp.second; + + elimedOutVarBin[var].push_back(std::make_pair(c.lit1, c.lit2)); + touchedVars.touch(c.lit1, false); + touchedVars.touch(c.lit2, false); + } + } +} + +/** +@brief Used for variable elimination + +Migrates clauses in poss to ps, and negs to ns +Also unlinks ass clauses is ps and ns. This is special unlinking, since it +actually saves the clauses for later re-use when extending the model, or re- +introducing the eliminated variables. + +@param[in] poss The occurrence list of var where it is positive +@param[in] negs The occurrence list of var where it is negavite +@param[out] ps Where thre clauses from poss have been moved +@param[out] ns Where thre clauses from negs have been moved +@param[in] var The variable that is being eliminated +*/ +void Subsumer::removeClauses(vec<ClAndBin>& posAll, vec<ClAndBin>& negAll, const Var var) +{ + pair<uint32_t, uint32_t> removed; + removed.first = 0; + removed.second = 0; + + removeClausesHelper(posAll, var, removed); + removeClausesHelper(negAll, var, removed); + + solver.learnts_literals -= removed.first; + solver.clauses_literals -= removed.second; + solver.numBins -= (removed.first + removed.second)/2; +} + +uint32_t Subsumer::numNonLearntBins(const Lit lit) const +{ + uint32_t num = 0; + const vec<Watched>& ws = solver.watches[(~lit).toInt()]; + for (vec<Watched>::const_iterator it = ws.getData(), end = ws.getDataEnd(); it != end; it++) { + if (it->isBinary() && !it->getLearnt()) num++; + } + + return num; +} + +void Subsumer::fillClAndBin(vec<ClAndBin>& all, vec<ClauseSimp>& cs, const Lit lit) +{ + for (uint32_t i = 0; i < cs.size(); i++) { + if (!cs[i].clause->learnt()) all.push(ClAndBin(cs[i])); + } + + const vec<Watched>& ws = solver.watches[(~lit).toInt()]; + for (vec<Watched>::const_iterator it = ws.getData(), end = ws.getDataEnd(); it != end; it++) { + if (it->isBinary() &&!it->getLearnt()) all.push(ClAndBin(lit, it->getOtherLit())); + } +} + +/** +@brief Tries to eliminate variable + +Tries to eliminate a variable. It uses heuristics to decide whether it's a good +idea to eliminate a variable or not. + +@param[in] var The variable that is being eliminated +@return TRUE if variable was eliminated +*/ +bool Subsumer::maybeEliminate(const Var var) +{ + assert(!var_elimed[var]); + assert(!cannot_eliminate[var]); + assert(solver.decision_var[var]); + if (solver.value(var) != l_Undef) return false; + + Lit lit = Lit(var, false); + + //Only exists in binary clauses -- don't delete it then + /*if (occur[lit.toInt()].size() == 0 && occur[(~lit).toInt()].size() == 0) + return false;*/ + + vec<ClauseSimp>& poss = occur[lit.toInt()]; + vec<ClauseSimp>& negs = occur[(~lit).toInt()]; + const uint32_t numNonLearntPos = numNonLearntBins(lit); + const uint32_t numNonLearntNeg = numNonLearntBins(~lit); + uint32_t before_literals = numNonLearntNeg*2 + numNonLearntPos*2; + + uint32_t posSize = 0; + for (uint32_t i = 0; i < poss.size(); i++) + if (!poss[i].clause->learnt()) { + posSize++; + before_literals += poss[i].clause->size(); + } + posSize += numNonLearntPos; + + uint32_t negSize = 0; + for (uint32_t i = 0; i < negs.size(); i++) + if (!negs[i].clause->learnt()) { + negSize++; + before_literals += negs[i].clause->size(); + } + negSize += numNonLearntNeg; + + numMaxElim -= posSize + negSize; + + // Heuristic CUT OFF: + if (posSize >= 10 && negSize >= 10) return false; + + // Heuristic CUT OFF2: + if ((posSize >= 3 && negSize >= 3 && before_literals > 300) + && clauses.size() > 700000) + return false; + if ((posSize >= 5 && negSize >= 5 && before_literals > 400) + && clauses.size() <= 700000 && clauses.size() > 100000) + return false; + if ((posSize >= 8 && negSize >= 8 && before_literals > 700) + && clauses.size() <= 100000) + return false; + + vec<ClAndBin> posAll, negAll; + fillClAndBin(posAll, poss, lit); + fillClAndBin(negAll, negs, ~lit); + + // Count clauses/literals after elimination: + uint32_t before_clauses = posSize + negSize; + uint32_t after_clauses = 0; + vec<Lit> dummy; //to reduce temporary data allocation + for (uint32_t i = 0; i < posAll.size(); i++) for (uint32_t j = 0; j < negAll.size(); j++){ + // Merge clauses. If 'y' and '~y' exist, clause will not be created. + dummy.clear(); + const bool ok = merge(posAll[i], negAll[j], lit, ~lit, dummy); + if (ok){ + after_clauses++; + if (after_clauses > before_clauses) + return false; + } + } + + //Eliminate + //removing clauses (both non-learnt and learnt) + vec<ClauseSimp> tmp1 = poss; + poss.clear(); + for (uint32_t i = 0; i < tmp1.size(); i++) { + if (tmp1[i].clause->learnt()) unlinkClause(tmp1[i]); + } + vec<ClauseSimp> tmp2 = negs; + negs.clear(); + for (uint32_t i = 0; i < tmp2.size(); i++) { + if (tmp2[i].clause->learnt()) unlinkClause(tmp2[i]); + } + + removeClauses(posAll, negAll, var); + + //check watchlists + #ifndef NDEBUG + const vec<Watched>& ws1 = solver.watches[lit.toInt()]; + for (vec<Watched>::const_iterator i = ws1.getData(), end = ws1.getDataEnd(); i != end; i++) { + assert(i->isTriClause() || (i->isBinary() && i->getLearnt())); + } + const vec<Watched>& ws2 = solver.watches[(~lit).toInt()]; + for (vec<Watched>::const_iterator i = ws2.getData(), end = ws2.getDataEnd(); i != end; i++) { + assert(i->isTriClause() || (i->isBinary() && i->getLearnt())); + } + #endif + + for (uint32_t i = 0; i < posAll.size(); i++) for (uint32_t j = 0; j < negAll.size(); j++){ + dummy.clear(); + bool ok = merge(posAll[i], negAll[j], lit, ~lit, dummy); + if (!ok) continue; + + if (cleanClause(dummy)) + continue; + + #ifdef VERBOSE_DEBUG + std::cout << "Adding new clause due to varelim: " << dummy << std::endl; + #endif + switch (dummy.size()) { + case 0: + solver.ok = false; + break; + case 1: { + handleSize1Clause(dummy[0]); + break; + } + case 2: { + if (findWBin(solver.watches, dummy[0], dummy[1])) { + Watched& w = findWatchedOfBin(solver.watches, dummy[0], dummy[1]); + if (w.getLearnt()) { + w.setLearnt(false); + findWatchedOfBin(solver.watches, dummy[1], dummy[0], true).setLearnt(false); + solver.learnts_literals -= 2; + solver.clauses_literals += 2; + } + } else { + solver.attachBinClause(dummy[0], dummy[1], false); + solver.numNewBin++; + } + if (numMaxSubsume1 > 0) + subsume1(dummy, false); + break; + } + default: { + Clause* cl = solver.clauseAllocator.Clause_new(dummy); + ClauseSimp c = linkInClause(*cl); + if (numMaxSubsume1 > 0) subsume1(*c.clause); + else if (numMaxSubsume0) subsume0(*c.clause); + } + } + if (!solver.ok) return true; + } + + assert(occur[lit.toInt()].size() == 0 && occur[(~lit).toInt()].size() == 0); + var_elimed[var] = true; + numElimed++; + solver.setDecisionVar(var, false); + return true; +} + +/** +@brief Resolves two clauses on a variable + +Clause ps must contain without_p +Clause ps must contain without_q +And without_p = ~without_q + +@note: 'seen' is assumed to be cleared. + +@param[in] var The variable that is being eliminated +@return FALSE if clause is always satisfied ('out_clause' should not be used) +*/ +bool Subsumer::merge(const ClAndBin& ps, const ClAndBin& qs, const Lit without_p, const Lit without_q, vec<Lit>& out_clause) +{ + bool retval = true; + if (ps.isBin) { + numMaxElim -= 2; + assert(ps.lit1 == without_p); + assert(ps.lit2 != without_p); + + seen_tmp[ps.lit2.toInt()] = 1; + out_clause.push(ps.lit2); + } else { + Clause& c = *ps.clsimp.clause; + numMaxElim -= c.size()*5; + for (uint32_t i = 0; i < c.size(); i++){ + if (c[i] != without_p){ + seen_tmp[c[i].toInt()] = 1; + out_clause.push(c[i]); + } + } + } + + if (qs.isBin) { + numMaxElim -= 2; + assert(qs.lit1 == without_q); + assert(qs.lit2 != without_q); + + if (seen_tmp[(~qs.lit2).toInt()]) { + retval = false; + goto end; + } + if (!seen_tmp[qs.lit2.toInt()]) + out_clause.push(qs.lit2); + } else { + Clause& c = *qs.clsimp.clause; + numMaxElim -= c.size()*5; + for (uint32_t i = 0; i < c.size(); i++){ + if (c[i] != without_q) { + if (seen_tmp[(~c[i]).toInt()]) { + retval = false; + goto end; + } + if (!seen_tmp[c[i].toInt()]) + out_clause.push(c[i]); + } + } + } + + end: + if (ps.isBin) { + seen_tmp[ps.lit2.toInt()] = 0; + } else { + Clause& c = *ps.clsimp.clause; + for (uint32_t i = 0; i < c.size(); i++) + seen_tmp[c[i].toInt()] = 0; + } + + return retval; +} + +/** +@brief Orders variables for elimination + +Variables are ordered according to their occurrances. If a variable occurs far +less than others, it should be prioritised for elimination. The more difficult +variables are OK to try later. + +@note: Will untouch all variables. + +@param[out] order The order to try to eliminate the variables +*/ +void Subsumer::orderVarsForElim(vec<Var>& order) +{ + order.clear(); + vec<pair<int, Var> > cost_var; + for (vector<Var>::const_iterator it = touchedVars.begin(), end = touchedVars.end(); it != end ; it++){ + Lit x = Lit(*it, false); + + //Long non-learnt POS + uint32_t pos = 0; + const vec<ClauseSimp>& poss = occur[x.toInt()]; + for (uint32_t i = 0; i < poss.size(); i++) + if (!poss[i].clause->learnt()) pos++; + + //Long non-learnt NEG + uint32_t neg = 0; + const vec<ClauseSimp>& negs = occur[(~x).toInt()]; + for (uint32_t i = 0; i < negs.size(); i++) + if (!negs[i].clause->learnt()) neg++; + + //Short non-lerants + //uint32_t nNonLPos = numNonLearntBins(x); + //uint32_t nNonLNeg = numNonLearntBins(~x); + + //uint32_t cost = pos*neg/2 + nNonLPos*neg*2 + nNonLNeg*pos*2 + nNonLNeg*nNonLPos*6; + uint32_t cost = pos*neg * 2 + numNonLearntBins(x) * neg + numNonLearntBins(~x) * pos; + + cost_var.push(std::make_pair(cost, x.var())); + } + touchedVars.clear(); + + std::sort(cost_var.getData(), cost_var.getDataEnd(), myComp()); + for (uint32_t x = 0; x < cost_var.size(); x++) { + order.push(cost_var[x].second); + } +} + +/** +@brief Verifies that occurrence lists are OK + +Calculates how many occurences are of the varible in clauses[], and if that is +less than occur[var].size(), returns FALSE + +@return TRUE if they are OK +*/ +bool Subsumer::verifyIntegrity() +{ + vector<uint32_t> occurNum(solver.nVars()*2, 0); + + for (uint32_t i = 0; i < clauses.size(); i++) { + if (clauses[i].clause == NULL) continue; + Clause& c = *clauses[i].clause; + for (uint32_t i2 = 0; i2 < c.size(); i2++) + occurNum[c[i2].toInt()]++; + } + + for (uint32_t i = 0; i < occurNum.size(); i++) { + #ifdef VERBOSE_DEBUG + std::cout << "occurNum[i]:" << occurNum[i] + << " occur[i]:" << occur[i].size() + << " --- i:" << i << std::endl; + #endif //VERBOSE_DEBUG + + if (occurNum[i] != occur[i].size()) return false; + } + + return true; +} + +template<class T> +bool Subsumer::allTautology(const T& ps, const Lit lit) +{ + #ifdef VERBOSE_DEBUG + cout << "allTautology: " << ps << std::endl; + #endif + + numMaxBlockToVisit -= ps.size()*2; + for (const Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) { + if (*l != ~lit) seen_tmp[l->toInt()] = true; + } + + bool allIsTautology = true; + const vec<ClauseSimp>& cs = occur[lit.toInt()]; + const vec<Watched>& ws = solver.watches[(~lit).toInt()]; + + for (const ClauseSimp *it = cs.getData(), *end = cs.getDataEnd(); it != end; it++){ + if (it+1 != end) __builtin_prefetch((it+1)->clause); + + const Clause& c = *it->clause; + numMaxBlockToVisit -= c.size(); + for (const Lit *l = c.getData(), *end2 = c.getDataEnd(); l != end2; l++) { + if (seen_tmp[(~(*l)).toInt()]) { + goto next; + } + } + allIsTautology = false; + break; + + next:; + } + if (!allIsTautology) goto end; + + numMaxBlockToVisit -= ws.size(); + for (vec<Watched>::const_iterator it = ws.getData(), end = ws.getDataEnd(); it != end; it++) { + if (!it->isNonLearntBinary()) continue; + if (seen_tmp[(~it->getOtherLit()).toInt()]) continue; + else { + allIsTautology = false; + break; + } + } + + end: + for (const Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) { + seen_tmp[l->toInt()] = false; + } + + return allIsTautology; +} + +void Subsumer::blockedClauseRemoval() +{ + if (numMaxBlockToVisit < 0) return; + if (solver.order_heap.empty()) return; + + double myTime = cpuTime(); + numblockedClauseRemoved = 0; + uint32_t numElimedBefore = numElimed; + + touchedBlockedVars = priority_queue<VarOcc, vector<VarOcc>, MyComp>(); + touchedBlockedVarsBool.clear(); + touchedBlockedVarsBool.growTo(solver.nVars(), false); + for (uint32_t i = 0; i < solver.order_heap.size(); i++) { + //if (solver.order_heap.size() < 1) break; + //touchBlockedVar(solver.order_heap[solver.mtrand.randInt(solver.order_heap.size()-1)]); + touchBlockedVar(solver.order_heap[i]); + } + + uint32_t triedToBlock = 0; + while (numMaxBlockToVisit > 0 && !touchedBlockedVars.empty()) { + VarOcc vo = touchedBlockedVars.top(); + touchedBlockedVars.pop(); + touchedBlockedVarsBool[vo.var] = false; + + if (solver.value(vo.var) != l_Undef + || !solver.decision_var[vo.var] + || cannot_eliminate[vo.var]) + continue; + + triedToBlock++; + Lit lit = Lit(vo.var, false); + + //if (!tryOneSetting(lit)) { + tryOneSetting(lit); + // } + } + + if (solver.conf.verbosity >= 1) { + std::cout + << "c spec. var-rem cls: " << std::setw(8) << numblockedClauseRemoved + << " vars: " << std::setw(6) << numElimed - numElimedBefore + << " tried: " << std::setw(11) << triedToBlock + << " T: " << std::fixed << std::setprecision(2) << std::setw(4) << cpuTime() - myTime + << " s" << std::endl; + } +} + +bool Subsumer::tryOneSetting(const Lit lit) +{ + numMaxBlockToVisit -= occur[lit.toInt()].size(); + for(ClauseSimp *it = occur[lit.toInt()].getData(), *end = occur[lit.toInt()].getDataEnd(); it != end; it++) { + if (!allTautology(*it->clause, ~lit)) { + return false; + } + } + + vec<Lit> lits(1); + const vec<Watched>& ws = solver.watches[(~lit).toInt()]; + numMaxBlockToVisit -= ws.size(); + for (vec<Watched>::const_iterator it = ws.getData(), end = ws.getDataEnd(); it != end; it++) { + if (!it->isNonLearntBinary()) continue; + lits[0] = it->getOtherLit(); + if (!allTautology(lits, ~lit)) return false; + } + + blockedClauseElimAll(lit); + blockedClauseElimAll(~lit); + + var_elimed[lit.var()] = true; + numElimed++; + numMaxElimVars--; + solver.setDecisionVar(lit.var(), false); + + return true; +} + +void Subsumer::blockedClauseElimAll(const Lit lit) +{ + vec<ClauseSimp> toRemove(occur[lit.toInt()]); + for (ClauseSimp *it = toRemove.getData(), *end = toRemove.getDataEnd(); it != end; it++) { + #ifdef VERBOSE_DEBUG + std::cout << "Next varelim because of block clause elim" << std::endl; + #endif //VERBOSE_DEBUG + unlinkClause(*it, lit.var()); + numblockedClauseRemoved++; + } + + uint32_t removedNum = 0; + vec<Watched>& ws = solver.watches[(~lit).toInt()]; + vec<Watched>::iterator i = ws.getData(); + vec<Watched>::iterator j = i; + for (vec<Watched>::iterator end = ws.getDataEnd(); i != end; i++) { + if (!i->isNonLearntBinary()) { + *j++ = *i; + continue; + } + assert(!i->getLearnt()); + removeWBin(solver.watches[(~i->getOtherLit()).toInt()], lit, false); + elimedOutVarBin[lit.var()].push_back(std::make_pair(lit, i->getOtherLit())); + touchedVars.touch(i->getOtherLit(), false); + removedNum++; + } + ws.shrink_(i-j); + + solver.clauses_literals -= removedNum*2; + solver.numBins -= removedNum; +} + +/** +@brief Checks if eliminated variables are unassigned + +If there is a variable that has been assigned even though it's been eliminated +that means that there were clauses that contained that variable, and where some- +how inserted into the watchlists. That would be a grave bug, since that would +mean that not all clauses containing the eliminated variable were removed during +the running of this class. + +@return TRUE if they are all unassigned +*/ +bool Subsumer::checkElimedUnassigned() const +{ + uint32_t checkNumElimed = 0; + for (uint32_t i = 0; i < var_elimed.size(); i++) { + if (var_elimed[i]) { + checkNumElimed++; + assert(solver.assigns[i] == l_Undef); + if (solver.assigns[i] != l_Undef) return false; + } + } + assert(numElimed == checkNumElimed); + + return true; +} diff --git a/src/prop/cryptominisat/Solver/Subsumer.h b/src/prop/cryptominisat/Solver/Subsumer.h new file mode 100644 index 000000000..24a7da927 --- /dev/null +++ b/src/prop/cryptominisat/Solver/Subsumer.h @@ -0,0 +1,500 @@ +/***************************************************************************** +SatELite -- (C) Niklas Een, Niklas Sorensson, 2004 +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +Original code by SatELite authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3. +******************************************************************************/ + +#ifndef SIMPLIFIER_H +#define SIMPLIFIER_H + +#include "Solver.h" +#include "CSet.h" +#include "BitArray.h" +#include <map> +#include <vector> +#include <list> +#include <queue> + +namespace CMSat { + +using std::vector; +using std::list; +using std::map; +using std::priority_queue; + +class ClauseCleaner; +class OnlyNonLearntBins; + +class TouchList +{ + public: + void resize(uint32_t size) + { + touched.resize(size, 0); + } + + void addOne(Var var) + { + assert(touched.size() == var); + touched.push_back(1); + touchedList.push_back(var); + } + + void touch(Lit lit, const bool learnt) + { + if (!learnt) touch(lit.var()); + } + + void touch(Var var) + { + if (!touched[var]) { + touchedList.push_back(var); + touched[var]= 1; + } + } + + void clear() + { + touchedList.clear(); + std::fill(touched.begin(), touched.end(), 0); + } + + uint32_t size() const + { + return touchedList.size(); + } + + vector<Var>::const_iterator begin() const + { + return touchedList.begin(); + } + + vector<Var>::const_iterator end() const + { + return touchedList.end(); + } + + private: + vector<Var> touchedList; + vector<char> touched; +}; + +/** +@brief Handles subsumption, self-subsuming resolution, variable elimination, and related algorithms + +There are two main functions in this class, simplifyBySubsumption() and subsumeWithBinaries(). +The first one is the most important of the two: it performs everything, except manipuation +with non-existing binary clauses. The second does self-subsuming resolution with existing binary +clauses, and then does self-subsuming resolution and subsumption with binary clauses that don't exist +and never will exist: they are temporarily "created" (memorised), and used by subsume0BIN(). +*/ +class Subsumer +{ +public: + + //Construct-destruct + Subsumer(Solver& S2); + + //Called from main + bool simplifyBySubsumption(); + void newVar(); + + //UnElimination + void extendModel(Solver& solver2); + bool unEliminate(const Var var); + + //Get-functions + const vec<char>& getVarElimed() const; + uint32_t getNumElimed() const; + bool checkElimedUnassigned() const; + double getTotalTime() const; + const map<Var, vector<vector<Lit> > >& getElimedOutVar() const; + const map<Var, vector<std::pair<Lit, Lit> > >& getElimedOutVarBin() const; + +private: + + /*bool subsumeWithBinTri(); + bool subsumeWithBinTri( + vec<Clause*>& cls + , bool learnt + , uint32_t& subsumed_bin_num + , uint32_t& subsumed_tri_num + , uint32_t& lit_rem_bin + , uint32_t& lit_rem_tri + );*/ + + friend class ClauseCleaner; + friend class ClauseAllocator; + + //Main + /** + @brief Clauses to be treated are moved here ClauseSimp::index refers to the index of the clause here + */ + vec<ClauseSimp> clauses; + TouchList touchedVars; ///<Is set to true when a variable is part of a removed clause. Also true initially (upon variable creation). + CSet cl_touched; ///<Clauses strengthened/added + vec<vec<ClauseSimp> > occur; ///<occur[index(lit)]' is a list of constraints containing 'lit'. + vec<CSet* > iter_sets; ///<Sets currently used in iterations. + vec<char> cannot_eliminate;///<Variables that cannot be eliminated due to, e.g. XOR-clauses + vec<char> seen_tmp; ///<Used in various places to help perform algorithms + + //Global stats + Solver& solver; ///<The solver this simplifier is connected to + vec<char> var_elimed; ///<Contains TRUE if var has been eliminated + double totalTime; ///<Total time spent in this class + uint32_t numElimed; ///<Total number of variables eliminated + map<Var, vector<vector<Lit> > > elimedOutVar; ///<Contains the clauses to use to uneliminate a variable + map<Var, vector<std::pair<Lit, Lit> > > elimedOutVarBin; ///<Contains the clauses to use to uneliminate a variable + + //Limits + uint64_t addedClauseLits; + uint32_t numVarsElimed; ///<Number of variables elimed in this run + int64_t numMaxSubsume1; ///<Max. number self-subsuming resolution tries to do this run + int64_t numMaxSubsume0; ///<Max. number backward-subsumption tries to do this run + int64_t numMaxElim; ///<Max. number of variable elimination tries to do this run + int32_t numMaxElimVars; + int64_t numMaxBlockToVisit; ///<Max. number variable-blocking clauses to visit to do this run + uint32_t numMaxBlockVars; ///<Max. number variable-blocking tries to do this run + + //Start-up + uint64_t addFromSolver(vec<Clause*>& cs); + void fillCannotEliminate(); + void clearAll(); + void setLimits(); + bool subsume0AndSubsume1(); + vec<char> ol_seenPos; + vec<char> ol_seenNeg; + + //Finish-up + void freeMemory(); + void addBackToSolver(); + void removeWrong(vec<Clause*>& cs); + void removeWrongBinsAndAllTris(); + void removeAssignedVarsFromEliminated(); + + //Iterations + void registerIteration (CSet& iter_set) { iter_sets.push(&iter_set); } + void unregisterIteration(CSet& iter_set) { remove(iter_sets, &iter_set); } + + //Used by cleaner + void unlinkClause(ClauseSimp cc, const Var elim = var_Undef); + ClauseSimp linkInClause(Clause& cl); + + //Findsubsumed + template<class T> + void findSubsumed(const T& ps, const uint32_t abst, vec<ClauseSimp>& out_subsumed); + template<class T> + void findSubsumed1(const T& ps, uint32_t abs, vec<ClauseSimp>& out_subsumed, vec<Lit>& out_lits); + template<class T> + void fillSubs(const T& ps, uint32_t abs, vec<ClauseSimp>& out_subsumed, vec<Lit>& out_lits, const Lit lit); + template<class T2> + bool subset(const uint32_t aSize, const T2& B); + template<class T1, class T2> + Lit subset1(const T1& A, const T2& B); + bool subsetAbst(uint32_t A, uint32_t B); + + //binary clause-subsumption + struct BinSorter { + bool operator()(const Watched& first, const Watched& second) + { + assert(first.isBinary() || first.isTriClause()); + assert(second.isBinary() || second.isTriClause()); + + if (first.isTriClause() && second.isTriClause()) return false; + if (first.isBinary() && second.isTriClause()) return true; + if (second.isBinary() && first.isTriClause()) return false; + + assert(first.isBinary() && second.isBinary()); + if (first.getOtherLit().toInt() < second.getOtherLit().toInt()) return true; + if (first.getOtherLit().toInt() > second.getOtherLit().toInt()) return false; + if (first.getLearnt() == second.getLearnt()) return false; + if (!first.getLearnt()) return true; + return false; + }; + }; + void subsumeBinsWithBins(); + + //subsume0 + struct subsume0Happened { + bool subsumedNonLearnt; + uint32_t glue; + float act; + }; + /** + @brief Sort clauses according to size + */ + struct sortBySize + { + bool operator () (const Clause* x, const Clause* y) + { + return (x->size() < y->size()); + } + }; + void subsume0(Clause& ps); + template<class T> + subsume0Happened subsume0Orig(const T& ps, uint32_t abs); + void subsume0Touched(); + + //subsume1 + class NewBinaryClause + { + public: + NewBinaryClause(const Lit _lit1, const Lit _lit2, const bool _learnt) : + lit1(_lit1), lit2(_lit2), learnt(_learnt) + {}; + + const Lit lit1; + const Lit lit2; + const bool learnt; + }; + list<NewBinaryClause> clBinTouched; ///<Binary clauses strengthened/added + bool handleClBinTouched(); + + void subsume1(Clause& ps); + bool subsume1(vec<Lit>& ps, const bool wasLearnt); + void strenghten(ClauseSimp& c, const Lit toRemoveLit); + bool cleanClause(Clause& ps); + bool cleanClause(vec<Lit>& ps) const; + void handleSize1Clause(const Lit lit); + + /*bool subsWNonExitsBinsFullFull(); + bool subsWNonExistBinsFull(); + bool subsWNonExistBins(const Lit& lit, OnlyNonLearntBins* OnlyNonLearntBins); + uint64_t extraTimeNonExist; + bool subsNonExistentFinish; + vec<Lit> toVisit; + vec<char> toVisitAll;*/ + + //Variable elimination + /** + @brief Struct used to compare variable elimination difficulties + + Used to order variables according to their difficulty of elimination. Used by + the std::sort() function. in \function orderVarsForElim() + */ + struct myComp { + bool operator () (const std::pair<int, Var>& x, const std::pair<int, Var>& y) { + return x.first < y.first; + } + }; + class ClAndBin { + public: + ClAndBin(ClauseSimp& cl) : + clsimp(cl) + , lit1(lit_Undef) + , lit2(lit_Undef) + , isBin(false) + {} + + ClAndBin(const Lit _lit1, const Lit _lit2) : + clsimp(NULL, 0) + , lit1(_lit1) + , lit2(_lit2) + , isBin(true) + {} + + ClauseSimp clsimp; + Lit lit1; + Lit lit2; + bool isBin; + }; + void orderVarsForElim(vec<Var>& order); + uint32_t numNonLearntBins(const Lit lit) const; + bool maybeEliminate(Var x); + void removeClauses(vec<ClAndBin>& posAll, vec<ClAndBin>& negAll, const Var var); + void removeClausesHelper(vec<ClAndBin>& todo, const Var var, std::pair<uint32_t, uint32_t>& removed); + bool merge(const ClAndBin& ps, const ClAndBin& qs, const Lit without_p, const Lit without_q, vec<Lit>& out_clause); + bool eliminateVars(); + void fillClAndBin(vec<ClAndBin>& all, vec<ClauseSimp>& cs, const Lit lit); + + //Subsume with Nonexistent Bins + struct BinSorter2 { + bool operator()(const Watched& first, const Watched& second) + { + assert(first.isBinary() || first.isTriClause()); + assert(second.isBinary() || second.isTriClause()); + + if (first.isTriClause() && second.isTriClause()) return false; + if (first.isBinary() && second.isTriClause()) return true; + if (second.isBinary() && first.isTriClause()) return false; + + assert(first.isBinary() && second.isBinary()); + if (first.getLearnt() && !second.getLearnt()) return true; + if (!first.getLearnt() && second.getLearnt()) return false; + return false; + }; + }; + void subsume0BIN(const Lit lit, const vec<char>& lits, const uint32_t abst); + uint32_t doneNum; + + //Blocked clause elimination + class VarOcc { + public: + VarOcc(const Var& v, const uint32_t num) : + var(v) + , occurnum(num) + {} + Var var; + uint32_t occurnum; + }; + struct MyComp { + bool operator() (const VarOcc& l1, const VarOcc& l2) const { + return l1.occurnum > l2.occurnum; + } + }; + void blockedClauseRemoval(); + template<class T> + bool allTautology(const T& ps, const Lit lit); + uint32_t numblockedClauseRemoved; + bool tryOneSetting(const Lit lit); + priority_queue<VarOcc, vector<VarOcc>, MyComp> touchedBlockedVars; + vec<char> touchedBlockedVarsBool; + void touchBlockedVar(const Var x); + void blockedClauseElimAll(const Lit lit); + + + //validity checking + bool verifyIntegrity(); + + uint32_t clauses_subsumed; ///<Number of clauses subsumed in this run + uint32_t literals_removed; ///<Number of literals removed from clauses through self-subsuming resolution in this run + uint32_t numCalls; ///<Number of times simplifyBySubsumption() has been called + uint32_t clauseID; ///<We need to have clauseIDs since clauses don't natively have them. The ClauseID is stored by ClauseSimp, which also stores a pointer to the clause +}; + +template <class T, class T2> +void maybeRemove(vec<T>& ws, const T2& elem) +{ + if (ws.size() > 0) + removeW(ws, elem); +} + +/** +@brief Put varible in touchedBlockedVars + +call it when the number of occurrences of this variable changed. +*/ +inline void Subsumer::touchBlockedVar(const Var x) +{ + if (!touchedBlockedVarsBool[x]) { + touchedBlockedVars.push(VarOcc(x, occur[Lit(x, false).toInt()].size()*occur[Lit(x, true).toInt()].size())); + touchedBlockedVarsBool[x] = 1; + } +} + +/** +@brief Decides only using abstraction if clause A could subsume clause B + +@note: It can give false positives. Never gives false negatives. + +For A to subsume B, everything that is in A MUST be in B. So, if (A & ~B) +contains even one bit, it means that A contains something that B doesn't. So +A may be a subset of B only if (A & ~B) == 0 +*/ +inline bool Subsumer::subsetAbst(const uint32_t A, const uint32_t B) +{ + return !(A & ~B); +} + +//A subsumes B (A is <= B) +template<class T2> +bool Subsumer::subset(const uint32_t aSize, const T2& B) +{ + uint32_t num = 0; + for (uint32_t i = 0; i != B.size(); i++) { + num += seen_tmp[B[i].toInt()]; + } + return num == aSize; +} + + +/** +@brief Decides if A subsumes B, or if not, if A could strenghten B + +@note: Assumes 'seen' is cleared (will leave it cleared) + +Helper function findSubsumed1. Does two things in one go: +1) decides if clause A could subsume clause B +1) decides if clause A could be used to perform self-subsuming resoltuion on +clause B + +@return lit_Error, if neither (1) or (2) is true. Returns lit_Undef (1) is true, +and returns the literal to remove if (2) is true +*/ +template<class T1, class T2> +Lit Subsumer::subset1(const T1& A, const T2& B) +{ + Lit retLit = lit_Undef; + + for (uint32_t i = 0; i != B.size(); i++) + seen_tmp[B[i].toInt()] = 1; + for (uint32_t i = 0; i != A.size(); i++) { + if (!seen_tmp[A[i].toInt()]) { + if (retLit == lit_Undef && seen_tmp[(~A[i]).toInt()]) + retLit = ~A[i]; + else { + retLit = lit_Error; + goto end; + } + } + } + + end: + for (uint32_t i = 0; i != B.size(); i++) + seen_tmp[B[i].toInt()] = 0; + return retLit; +} + +/** +@brief New var has been added to the solver + +@note: MUST be called if a new var has been added to the solver + +Adds occurrence list places, increments seen_tmp, etc. +*/ +inline void Subsumer::newVar() +{ + occur .push(); + occur .push(); + seen_tmp .push(0); // (one for each polarity) + seen_tmp .push(0); + touchedVars .addOne(solver.nVars()-1); + var_elimed .push(0); + touchedBlockedVarsBool.push(0); + cannot_eliminate.push(0); + ol_seenPos.push(1); + ol_seenPos.push(1); + ol_seenNeg.push(1); + ol_seenNeg.push(1); +} + +inline const map<Var, vector<vector<Lit> > >& Subsumer::getElimedOutVar() const +{ + return elimedOutVar; +} + +inline const map<Var, vector<std::pair<Lit, Lit> > >& Subsumer::getElimedOutVarBin() const +{ + return elimedOutVarBin; +} + +inline const vec<char>& Subsumer::getVarElimed() const +{ + return var_elimed; +} + +inline uint32_t Subsumer::getNumElimed() const +{ + return numElimed; +} + +inline double Subsumer::getTotalTime() const +{ + return totalTime; +} + +} + +#endif //SIMPLIFIER_H diff --git a/src/prop/cryptominisat/Solver/UselessBinRemover.cpp b/src/prop/cryptominisat/Solver/UselessBinRemover.cpp new file mode 100644 index 000000000..1d848116e --- /dev/null +++ b/src/prop/cryptominisat/Solver/UselessBinRemover.cpp @@ -0,0 +1,228 @@ +/*************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +****************************************************************************/ + +#include <iomanip> +#include "UselessBinRemover.h" +#include "VarReplacer.h" +#include "ClauseCleaner.h" +#include "time_mem.h" + +//#define VERBOSE_DEBUG + +using namespace CMSat; + +UselessBinRemover::UselessBinRemover(Solver& _solver) : + solver(_solver) +{ +} + +/** +@brief Time limiting +*/ +#define MAX_REMOVE_BIN_FULL_PROPS 20000000 +/** +@brief We measure time in (bogo)propagations and "extra" time, time not accountable in (bogo)props +*/ +#define EXTRATIME_DIVIDER 3 + +/** +@brief Removes useless binary non-learnt clauses. See definiton of class for details + +We pick variables starting randomly at a place and going on until we stop: +we limit ourselves in time using (bogo)propagations and "extratime" +*/ +bool UselessBinRemover::removeUslessBinFull() +{ + double myTime = cpuTime(); + toDeleteSet.clear(); + toDeleteSet.growTo(solver.nVars()*2, 0); + uint32_t origHeapSize = solver.order_heap.size(); + uint64_t origProps = solver.propagations; + bool fixed = false; + uint32_t extraTime = 0; + uint32_t numBinsBefore = solver.numBins; + solver.sortWatched(); //VERY important + + uint32_t startFrom = solver.mtrand.randInt(solver.order_heap.size()); + for (uint32_t i = 0; i != solver.order_heap.size(); i++) { + Var var = solver.order_heap[(i+startFrom)%solver.order_heap.size()]; + if (solver.propagations - origProps + extraTime > MAX_REMOVE_BIN_FULL_PROPS) break; + if (solver.assigns[var] != l_Undef || !solver.decision_var[var]) continue; + + Lit lit(var, true); + if (!removeUselessBinaries(lit)) { + fixed = true; + solver.cancelUntilLight(); + solver.uncheckedEnqueue(~lit); + solver.ok = (solver.propagate<false>().isNULL()); + if (!solver.ok) return false; + continue; + } + + lit = ~lit; + if (!removeUselessBinaries(lit)) { + fixed = true; + solver.cancelUntilLight(); + solver.uncheckedEnqueue(~lit); + solver.ok = (solver.propagate<false>().isNULL()); + if (!solver.ok) return false; + continue; + } + } + + if (fixed) solver.order_heap.filter(Solver::VarFilter(solver)); + + if (solver.conf.verbosity >= 1) { + std::cout + << "c Removed useless bin:" << std::setw(8) << (numBinsBefore - solver.numBins) + << " fixed: " << std::setw(5) << (origHeapSize - solver.order_heap.size()) + << " props: " << std::fixed << std::setprecision(2) << std::setw(6) << (double)(solver.propagations - origProps)/1000000.0 << "M" + << " time: " << std::fixed << std::setprecision(2) << std::setw(5) << cpuTime() - myTime << " s" + << std::endl; + } + + return true; +} + +/** +@brief Removes useless binaries of the graph portion that starts with lit + +We try binary-space propagation on lit. Then, we check that we cannot reach any +of its one-hop neighboours from any of its other one-hope neighbours. If we can, +we remove the one-hop neighbour from the neightbours (i.e. remove the binary +clause). Example: + +\li a->b, a->c, b->c +\li In claues: (-a V b), (-a V c), (-b V c) + +One-hop neighbours of a: b, c. But c can be reached through b! So, we remove +a->c, the one-hop neighbour that is useless. +*/ +bool UselessBinRemover::removeUselessBinaries(const Lit lit) +{ + solver.newDecisionLevel(); + solver.uncheckedEnqueueLight(lit); + //Propagate only one hop + failed = !solver.propagateBinOneLevel(); + if (failed) return false; + bool ret = true; + + oneHopAway.clear(); + assert(solver.decisionLevel() > 0); + int c; + if (solver.trail.size()-solver.trail_lim[0] == 0) { + solver.cancelUntilLight(); + goto end; + } + //Fill oneHopAway and toDeleteSet with lits that are 1 hop away + extraTime += (solver.trail.size() - solver.trail_lim[0]) / EXTRATIME_DIVIDER; + for (c = solver.trail.size()-1; c > (int)solver.trail_lim[0]; c--) { + Lit x = solver.trail[c]; + toDeleteSet[x.toInt()] = true; + oneHopAway.push(x); + solver.assigns[x.var()] = l_Undef; + } + solver.assigns[solver.trail[c].var()] = l_Undef; + + solver.qhead = solver.trail_lim[0]; + solver.trail.shrink_(solver.trail.size() - solver.trail_lim[0]); + solver.trail_lim.clear(); + //solver.cancelUntil(0); + + wrong.clear(); + //We now try to reach the one-hop-away nodes from other one-hop-away + //nodes, but this time we propagate all the way + for(uint32_t i = 0; i < oneHopAway.size(); i++) { + //no need to visit it if it already queued for removal + //basically, we check if it's in 'wrong' + if (toDeleteSet[oneHopAway[i].toInt()]) { + if (!fillBinImpliesMinusLast(lit, oneHopAway[i], wrong)) { + ret = false; + goto end; + } + } + } + + for (uint32_t i = 0; i < wrong.size(); i++) { + removeBin(~lit, wrong[i]); + } + + end: + for(uint32_t i = 0; i < oneHopAway.size(); i++) { + toDeleteSet[oneHopAway[i].toInt()] = false; + } + + return ret; +} + +/** +@brief Removes a binary clause (lit1 V lit2) + +The binary clause might be in twice, three times, etc. Take care to remove +all instances of it. +*/ +void UselessBinRemover::removeBin(const Lit lit1, const Lit lit2) +{ + #ifdef VERBOSE_DEBUG + std::cout << "Removing useless bin: " << lit1 << " " << lit2 << std::endl; + #endif //VERBOSE_DEBUG + + std::pair<uint32_t, uint32_t> removed1 = removeWBinAll(solver.watches[(~lit1).toInt()], lit2); + std::pair<uint32_t, uint32_t> removed2 = removeWBinAll(solver.watches[(~lit2).toInt()], lit1); + assert(removed1 == removed2); + + assert((removed1.first + removed2.first) % 2 == 0); + assert((removed1.second + removed2.second) % 2 == 0); + solver.learnts_literals -= (removed1.first + removed2.first); + solver.clauses_literals -= (removed1.second + removed2.second); + solver.numBins -= (removed1.first + removed2.first + removed1.second + removed2.second)/2; +} + +/** +@brief Propagates all the way lit, but doesn't propagate origLit + +Removes adds to "wrong" the set of one-hop lits that can be reached from +lit AND are one-hop away from origLit. These later need to be removed +*/ +bool UselessBinRemover::fillBinImpliesMinusLast(const Lit origLit, const Lit lit, vec<Lit>& wrong) +{ + solver.newDecisionLevel(); + solver.uncheckedEnqueueLight(lit); + //if it's a cycle, it doesn't work, so don't propagate origLit + failed = !solver.propagateBinExcept(origLit); + if (failed) return false; + + assert(solver.decisionLevel() > 0); + int c; + extraTime += (solver.trail.size() - solver.trail_lim[0]) / EXTRATIME_DIVIDER; + for (c = solver.trail.size()-1; c > (int)solver.trail_lim[0]; c--) { + Lit x = solver.trail[c]; + if (toDeleteSet[x.toInt()]) { + wrong.push(x); + toDeleteSet[x.toInt()] = false; + }; + solver.assigns[x.var()] = l_Undef; + } + solver.assigns[solver.trail[c].var()] = l_Undef; + + solver.qhead = solver.trail_lim[0]; + solver.trail.shrink_(solver.trail.size() - solver.trail_lim[0]); + solver.trail_lim.clear(); + //solver.cancelUntil(0); + + return true; +} diff --git a/src/prop/cryptominisat/Solver/UselessBinRemover.h b/src/prop/cryptominisat/Solver/UselessBinRemover.h new file mode 100644 index 000000000..37944b431 --- /dev/null +++ b/src/prop/cryptominisat/Solver/UselessBinRemover.h @@ -0,0 +1,85 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#ifndef USELESSBINREMOVER_H +#define USELESSBINREMOVER_H + +#include "Vec.h" +#include "Solver.h" +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +namespace CMSat { + +/** +@brief Removes binary clauses that are effectively useless to have + +These binary clauses are useless, because for example clauses: +a V b +-b V c + +exist, so the binary clause: +a V c + +is useless in every possible way. Here, we remove such claues. Unfortunately, +currently we only remove useless non-learnt binary clauses. Learnt useless +binary clauses are not removed. + +\todo Extend such that it removes learnt useless binary clauses as well +*/ +class UselessBinRemover { + public: + UselessBinRemover(Solver& solver); + bool removeUslessBinFull(); + + private: + bool failed; ///<Has the previous propagation failed? (=conflict) + uint32_t extraTime; ///<Time that cannot be meausured in bogoprops (~propagation time) + + //Remove useless binaries + bool fillBinImpliesMinusLast(const Lit origLit, const Lit lit, vec<Lit>& wrong); + bool removeUselessBinaries(const Lit lit); + void removeBin(const Lit lit1, const Lit lit2); + /** + @brief Don't delete the same binary twice, and don't assume that deleted binaries still exist + + Not deleting the same binary twice is easy to understand. He hard part + is the second thought. Basically, once we set "a->b" to be deleted, for + instance, we should not check whether any one-hop neighbours of "a" can + be reached from "b", since the binary clause leading to "b" has already + been deleted (and, by the way, checked, since the place where we can + reach "b" from already checked for all places we can visit from "b") + */ + vec<char> toDeleteSet; + vec<Lit> oneHopAway; ///<Lits that are one hop away from selected lit (sometimes called origLit) + /** + @brief Binary clauses to be removed are gathered here + + We only gather the second lit, the one we can reach from selected lit + (calld origLit some places) see fillBinImpliesMinusLast() for details + */ + vec<Lit> wrong; + + Solver& solver; ///<The solver class e want to remove useless binary clauses from +}; + +} + +#endif //USELESSBINREMOVER_H diff --git a/src/prop/cryptominisat/Solver/VarReplacer.cpp b/src/prop/cryptominisat/Solver/VarReplacer.cpp new file mode 100644 index 000000000..e89e66c51 --- /dev/null +++ b/src/prop/cryptominisat/Solver/VarReplacer.cpp @@ -0,0 +1,731 @@ +/***************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +******************************************************************************/ + +#include "VarReplacer.h" +#include <iostream> +#include <iomanip> +#include <set> + +#include "ClauseCleaner.h" +#include "time_mem.h" +#include "DataSync.h" + +//#define VERBOSE_DEBUG +//#define DEBUG_REPLACER +//#define REPLACE_STATISTICS +//#define DEBUG_BIN_REPLACER + +using namespace CMSat; + +VarReplacer::VarReplacer(Solver& _solver) : + replacedLits(0) + , replacedVars(0) + , lastReplacedVars(0) + , solver(_solver) +{ +} + +VarReplacer::~VarReplacer() +{ +} + +/** +@brief Replaces variables, clears internal clauses, and reports stats + +When replacing, it is imperative not to make variables decision variables +which have been removed by other methods: +\li variable removal at the xor-sphere +\li disconnected component finding and solving +\li variable elimination + +NOTE: If any new such algoirhtms are added, this part MUST be updated such +that problems don't creep up +*/ +bool VarReplacer::performReplaceInternal() +{ + #ifdef VERBOSE_DEBUG + cout << "PerformReplacInternal started." << endl; + //solver.printAllClauses(); + #endif + double time = cpuTime(); + + #ifdef REPLACE_STATISTICS + uint32_t numRedir = 0; + for (uint32_t i = 0; i < table.size(); i++) { + if (table[i].var() != i) + numRedir++; + } + std::cout << "Number of trees:" << reverseTable.size() << std::endl; + std::cout << "Number of redirected nodes:" << numRedir << std::endl; + #endif //REPLACE_STATISTICS + + solver.clauseCleaner->removeAndCleanAll(true); + if (!solver.ok) return false; + solver.testAllClauseAttach(); + std::fill(cannot_eliminate.getData(), cannot_eliminate.getDataEnd(), false); + + #ifdef VERBOSE_DEBUG + { + uint32_t i = 0; + for (vector<Lit>::const_iterator it = table.begin(); it != table.end(); it++, i++) { + if (it->var() == i) continue; + cout << "Replacing var " << i+1 << " with Lit " << *it << endl; + } + } + #endif + + Var var = 0; + const vec<char>& removedVars = solver.xorSubsumer->getVarElimed(); + const vec<char>& removedVars3 = solver.subsumer->getVarElimed(); + for (vector<Lit>::const_iterator it = table.begin(); it != table.end(); it++, var++) { + if (it->var() == var + || removedVars[it->var()] + || removedVars3[it->var()] + ) continue; + #ifdef VERBOSE_DEBUG + cout << "Setting var " << var+1 << " to a non-decision var" << endl; + #endif + bool wasDecisionVar = solver.decision_var[var]; + solver.setDecisionVar(var, false); + //cannot_eliminate[var] = true; + solver.setDecisionVar(it->var(), true); + assert(!removedVars[var]); + assert(!removedVars3[var]); + + uint32_t& activity1 = solver.activity[var]; + uint32_t& activity2 = solver.activity[it->var()]; + if (wasDecisionVar && activity1 > activity2) { + activity2 = activity1; + solver.order_heap.update(it->var()); + solver.polarity[it->var()] = ((bool)solver.polarity[var]) ^ it->sign(); + } + + activity1 = 0.0; + solver.order_heap.update(var); + } + assert(solver.order_heap.heapProperty()); + + uint32_t thisTimeReplaced = replacedVars -lastReplacedVars; + lastReplacedVars = replacedVars; + + solver.testAllClauseAttach(); + assert(solver.qhead == solver.trail.size()); + + solver.countNumBinClauses(true, false); + solver.countNumBinClauses(false, true); + + if (!replaceBins()) goto end; + if (!replace_set(solver.clauses)) goto end; + if (!replace_set(solver.learnts)) goto end; + if (!replace_set(solver.xorclauses)) goto end; + solver.testAllClauseAttach(); + +end: + assert(solver.qhead == solver.trail.size() || !solver.ok); + + if (solver.conf.verbosity >= 3) { + std::cout << "c Replacing " + << std::setw(8) << thisTimeReplaced << " vars" + << " Replaced " << std::setw(8) << replacedLits<< " lits" + << " Time: " << std::setw(8) << std::fixed << std::setprecision(2) + << cpuTime()-time << " s " + << std::endl; + } + + replacedLits = 0; + + solver.order_heap.filter(Solver::VarFilter(solver)); + + return solver.ok; +} + +/** +@brief Replaces vars in xorclauses +*/ +bool VarReplacer::replace_set(vec<XorClause*>& cs) +{ + XorClause **a = cs.getData(); + XorClause **r = a; + for (XorClause **end = a + cs.size(); r != end; r++) { + XorClause& c = **r; + + bool changed = false; + Var origVar1 = c[0].var(); + Var origVar2 = c[1].var(); + + for (Lit *l = &c[0], *end2 = l + c.size(); l != end2; l++) { + Lit newlit = table[l->var()]; + if (newlit.var() != l->var()) { + changed = true; + *l = Lit(newlit.var(), false); + c.invert(newlit.sign()); + replacedLits++; + } + } + + if (changed && handleUpdatedClause(c, origVar1, origVar2)) { + if (!solver.ok) { + #ifdef VERBOSE_DEBUG + cout << "contradiction while replacing lits in xor clause" << std::endl; + #endif + for(;r != end; r++) solver.clauseAllocator.clauseFree(*r); + cs.shrink(r-a); + return false; + } + //solver.clauseAllocator.clauseFree(&c); + c.setRemoved(); + solver.freeLater.push(&c); + } else { + #ifdef SILENT_DEBUG + uint32_t numUndef = 0; + for (uint32_t i = 0; i < c.size(); i++) { + if (solver.value(c[i]) == l_Undef) numUndef++; + } + assert(numUndef >= 2 || numUndef == 0); + #endif + *a++ = *r; + } + } + cs.shrink(r-a); + + return solver.ok; +} + +/** +@brief Helper function for replace_set() +*/ +bool VarReplacer::handleUpdatedClause(XorClause& c, const Var origVar1, const Var origVar2) +{ + uint32_t origSize = c.size(); + std::sort(c.getData(), c.getDataEnd()); + Lit p; + uint32_t i, j; + for (i = j = 0, p = lit_Undef; i != c.size(); i++) { + if (c[i].var() == p.var()) { + //added, but easily removed + j--; + p = lit_Undef; + if (!solver.assigns[c[i].var()].isUndef()) + c.invert(solver.assigns[c[i].var()].getBool()); + } else if (solver.assigns[c[i].var()].isUndef()) //just add + c[j++] = p = c[i]; + else c.invert(solver.assigns[c[i].var()].getBool()); //modify xorEqualFalse instead of adding + } + c.shrink(i - j); + + //Even if i==j, the clause *has* changed + c.setChanged(); + + #ifdef VERBOSE_DEBUG + cout << "xor-clause after replacing: "; + c.plainPrint(); + #endif + + switch (c.size()) { + case 0: + solver.detachModifiedClause(origVar1, origVar2, origSize, &c); + if (!c.xorEqualFalse()) { + solver.ok = false; + } + return true; + case 1: + solver.detachModifiedClause(origVar1, origVar2, origSize, &c); + solver.uncheckedEnqueue(Lit(c[0].var(), c.xorEqualFalse())); + solver.ok = (solver.propagate<false>().isNULL()); + return true; + case 2: { + solver.detachModifiedClause(origVar1, origVar2, origSize, &c); + c[0] = c[0].unsign() ^ c.xorEqualFalse(); + c[1] = c[1].unsign(); + addBinaryXorClause(c[0], c[1]); + return true; + } + default: + solver.detachModifiedClause(origVar1, origVar2, origSize, &c); + solver.attachClause(c); + return false; + } + + assert(false); + return false; +} + +bool VarReplacer::replaceBins() +{ + #ifdef DEBUG_BIN_REPLACER + vec<uint32_t> removed(solver.nVars()*2, 0); + uint32_t replacedLitsBefore = replacedLits; + #endif + + uint32_t removedLearnt = 0; + uint32_t removedNonLearnt = 0; + uint32_t wsLit = 0; + for (vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit1 = ~Lit::toLit(wsLit); + vec<Watched>& ws = *it; + + vec<Watched>::iterator i = ws.getData(); + vec<Watched>::iterator j = i; + for (vec<Watched>::iterator end2 = ws.getDataEnd(); i != end2; i++) { + if (!i->isBinary()) { + *j++ = *i; + continue; + } + //std::cout << "bin: " << lit1 << " , " << i->getOtherLit() << " learnt : " << (i->isLearnt()) << std::endl; + Lit thisLit1 = lit1; + Lit lit2 = i->getOtherLit(); + assert(thisLit1.var() != lit2.var()); + + if (table[lit2.var()].var() != lit2.var()) { + lit2 = table[lit2.var()] ^ lit2.sign(); + i->setOtherLit(lit2); + replacedLits++; + } + + bool changedMain = false; + if (table[thisLit1.var()].var() != thisLit1.var()) { + thisLit1 = table[thisLit1.var()] ^ thisLit1.sign(); + replacedLits++; + changedMain = true; + } + + if (thisLit1 == lit2) { + if (solver.value(lit2) == l_Undef) { + solver.uncheckedEnqueue(lit2); + } else if (solver.value(lit2) == l_False) { + #ifdef VERBOSE_DEBUG + std::cout << "Contradiction during replacement of lits in binary clause" << std::endl; + #endif + solver.ok = false; + } + #ifdef DEBUG_BIN_REPLACER + removed[lit1.toInt()]++; + removed[origLit2.toInt()]++; + #endif + + if (i->getLearnt()) removedLearnt++; + else removedNonLearnt++; + continue; + } + + if (thisLit1 == ~lit2) { + #ifdef DEBUG_BIN_REPLACER + removed[lit1.toInt()]++; + removed[origLit2.toInt()]++; + #endif + + if (i->getLearnt()) removedLearnt++; + else removedNonLearnt++; + continue; + } + + if (changedMain) { + solver.watches[(~thisLit1).toInt()].push(*i); + } else { + *j++ = *i; + } + } + ws.shrink_(i-j); + } + + #ifdef DEBUG_BIN_REPLACER + for (uint32_t i = 0; i < removed.size(); i++) { + if (removed[i] % 2 != 0) { + std::cout << "suspicious: " << Lit::toLit(i) << std::endl; + std::cout << "num: " << removed[i] << std::endl; + } + } + std::cout << "replacedLitsdiff: " << replacedLits - replacedLitsBefore << std::endl; + std::cout << "removedLearnt: " << removedLearnt << std::endl; + std::cout << "removedNonLearnt: " << removedNonLearnt << std::endl; + #endif + + assert(removedLearnt % 2 == 0); + assert(removedNonLearnt % 2 == 0); + solver.learnts_literals -= removedLearnt; + solver.clauses_literals -= removedNonLearnt; + solver.numBins -= (removedLearnt + removedNonLearnt)/2; + + if (solver.ok) solver.ok = (solver.propagate<false>().isNULL()); + return solver.ok; +} + +/** +@brief Replaces variables in normal clauses +*/ +bool VarReplacer::replace_set(vec<Clause*>& cs) +{ + Clause **a = cs.getData(); + Clause **r = a; + for (Clause **end = a + cs.size(); r != end; r++) { + Clause& c = **r; + assert(c.size() > 2); + bool changed = false; + Lit origLit1 = c[0]; + Lit origLit2 = c[1]; + Lit origLit3 = (c.size() == 3) ? c[2] : lit_Undef; + for (Lit *l = c.getData(), *end2 = l + c.size(); l != end2; l++) { + if (table[l->var()].var() != l->var()) { + changed = true; + *l = table[l->var()] ^ l->sign(); + replacedLits++; + } + } + + if (changed && handleUpdatedClause(c, origLit1, origLit2, origLit3)) { + if (!solver.ok) { + #ifdef VERBOSE_DEBUG + cout << "contradiction while replacing lits in normal clause" << std::endl; + #endif + for(;r != end; r++) solver.clauseAllocator.clauseFree(*r); + cs.shrink(r-a); + return false; + } + } else { + *a++ = *r; + } + } + cs.shrink(r-a); + + return solver.ok; +} + +/** +@brief Helper function for replace_set() +*/ +bool VarReplacer::handleUpdatedClause(Clause& c, const Lit origLit1, const Lit origLit2, const Lit origLit3) +{ + bool satisfied = false; + std::sort(c.getData(), c.getData() + c.size()); + Lit p; + uint32_t i, j; + const uint32_t origSize = c.size(); + for (i = j = 0, p = lit_Undef; i != origSize; i++) { + if (solver.value(c[i]) == l_True || c[i] == ~p) { + satisfied = true; + break; + } + else if (solver.value(c[i]) != l_False && c[i] != p) + c[j++] = p = c[i]; + } + c.shrink(i - j); + c.setChanged(); + + solver.detachModifiedClause(origLit1, origLit2, origLit3, origSize, &c); + + #ifdef VERBOSE_DEBUG + cout << "clause after replacing: "; + c.plainPrint(); + #endif + + if (satisfied) return true; + + switch(c.size()) { + case 0: + solver.ok = false; + return true; + case 1 : + solver.uncheckedEnqueue(c[0]); + solver.ok = (solver.propagate<false>().isNULL()); + return true; + case 2: + solver.attachBinClause(c[0], c[1], c.learnt()); + solver.numNewBin++; + solver.dataSync->signalNewBinClause(c); + return true; + default: + solver.attachClause(c); + return false; + } + + assert(false); + return false; +} + +/** +@brief Returns variables that have been replaced +*/ +vector<Var> VarReplacer::getReplacingVars() const +{ + vector<Var> replacingVars; + + for(map<Var, vector<Var> >::const_iterator it = reverseTable.begin(), end = reverseTable.end(); it != end; it++) { + replacingVars.push_back(it->first); + } + + return replacingVars; +} + +/** +@brief Given a partial model, it tries to extend it to variables that have been replaced + +Cannot extend it fully, because it might be that a replaced d&f, but a was +later variable-eliminated. That's where extendModelImpossible() comes in +*/ +void VarReplacer::extendModelPossible() const +{ + #ifdef VERBOSE_DEBUG + std::cout << "extendModelPossible() called" << std::endl; + #endif //VERBOSE_DEBUG + uint32_t i = 0; + for (vector<Lit>::const_iterator it = table.begin(); it != table.end(); it++, i++) { + if (it->var() == i) continue; + + #ifdef VERBOSE_DEBUG + cout << "Extending model: var "; solver.printLit(Lit(i, false)); + cout << " to "; solver.printLit(*it); + cout << endl; + #endif + + if (solver.assigns[it->var()] != l_Undef) { + if (solver.assigns[i] == l_Undef) { + bool val = (solver.assigns[it->var()] == l_False); + solver.uncheckedEnqueue(Lit(i, val ^ it->sign())); + } else { + assert(solver.assigns[i].getBool() == (solver.assigns[it->var()].getBool() ^ it->sign())); + } + } + solver.ok = (solver.propagate<false>().isNULL()); + assert(solver.ok); + } +} + +/** +@brief Used when a variable was eliminated, but it replaced some other variables + +This function will add to solver2 clauses that represent the relationship of +the variables to their replaced cousins. Then, calling solver2.solve() should +take care of everything +*/ +void VarReplacer::extendModelImpossible(Solver& solver2) const +{ + + #ifdef VERBOSE_DEBUG + std::cout << "extendModelImpossible() called" << std::endl; + #endif //VERBOSE_DEBUG + + vec<Lit> tmpClause; + uint32_t i = 0; + for (vector<Lit>::const_iterator it = table.begin(); it != table.end(); it++, i++) { + if (it->var() == i) continue; + if (solver.assigns[it->var()] == l_Undef) { + assert(solver.assigns[it->var()] == l_Undef); + assert(solver.assigns[i] == l_Undef); + + tmpClause.clear(); + tmpClause.push(Lit(it->var(), true)); + tmpClause.push(Lit(i, it->sign())); + solver2.addClause(tmpClause); + assert(solver2.ok); + + tmpClause.clear(); + tmpClause.push(Lit(it->var(), false)); + tmpClause.push(Lit(i, it->sign()^true)); + solver2.addClause(tmpClause); + assert(solver2.ok); + } + } +} + +/** +@brief Replaces two two vars in "ps" with one another. xorEqualFalse defines anti/equivalence + +It can be tricky to do this. For example, if: + +\li a replaces: b, c +\li f replaces: f, h +\li we just realised that c = h +This is the most difficult case, but there are other cases, e.g. if we already +know that c=h, in which case we don't do anything + +@p ps must contain 2 variables(!), i.e literals with no sign +@p xorEqualFalse if True, the two variables are equivalent. Otherwise, they are antivalent +@p group of clause they have been inspired from. Sometimes makes no sense... +*/ +template<class T> +bool VarReplacer::replace(T& ps, const bool xorEqualFalse, const bool addBinAsLearnt, const bool addToWatchLists) +{ + #ifdef VERBOSE_DEBUG + std::cout << "replace() called with var " << ps[0].var()+1 << " and var " << ps[1].var()+1 << " with xorEqualFalse " << xorEqualFalse << std::endl; + #endif + + assert(solver.decisionLevel() == 0); + assert(ps.size() == 2); + assert(!ps[0].sign()); + assert(!ps[1].sign()); + #ifdef DEBUG_REPLACER + assert(solver.assigns[ps[0].var()].isUndef()); + assert(solver.assigns[ps[1].var()].isUndef()); + + assert(!solver.subsumer->getVarElimed()[ps[0].var()]); + assert(!solver.xorSubsumer->getVarElimed()[ps[0].var()]); + + assert(!solver.subsumer->getVarElimed()[ps[1].var()]); + assert(!solver.xorSubsumer->getVarElimed()[ps[1].var()]); + #endif + + //Detect circle + Lit lit1 = ps[0]; + lit1 = table[lit1.var()]; + Lit lit2 = ps[1]; + lit2 = table[lit2.var()] ^ !xorEqualFalse; + + //Already inside? + if (lit1.var() == lit2.var()) { + if (lit1.sign() != lit2.sign()) { + solver.ok = false; + return false; + } + return true; + } + + #ifdef DEBUG_REPLACER + assert(!solver.subsumer->getVarElimed()[lit1.var()]); + assert(!solver.xorSubsumer->getVarElimed()[lit1.var()]); + assert(!solver.subsumer->getVarElimed()[lit2.var()]); + assert(!solver.xorSubsumer->getVarElimed()[lit2.var()]); + #endif + + cannot_eliminate[lit1.var()] = true; + cannot_eliminate[lit2.var()] = true; + lbool val1 = solver.value(lit1); + lbool val2 = solver.value(lit2); + if (val1 != l_Undef && val2 != l_Undef) { + if (val1 != val2) { + solver.ok = false; + return false; + } + return true; + } + + if ((val1 != l_Undef && val2 == l_Undef) || (val2 != l_Undef && val1 == l_Undef)) { + //exactly one l_Undef, exectly one l_True/l_False + if (val1 != l_Undef) solver.uncheckedEnqueue(lit2 ^ (val1 == l_False)); + else solver.uncheckedEnqueue(lit1 ^ (val2 == l_False)); + + if (solver.ok) solver.ok = (solver.propagate<false>().isNULL()); + return solver.ok; + } + + #ifdef DEBUG_REPLACER + assert(val1 == l_Undef && val2 == l_Undef); + #endif //DEBUG_REPLACER + + if (addToWatchLists) + addBinaryXorClause(lit1, lit2 ^ true, addBinAsLearnt); + + if (reverseTable.find(lit1.var()) == reverseTable.end()) { + reverseTable[lit2.var()].push_back(lit1.var()); + table[lit1.var()] = lit2 ^ lit1.sign(); + replacedVars++; + return true; + } + + if (reverseTable.find(lit2.var()) == reverseTable.end()) { + reverseTable[lit1.var()].push_back(lit2.var()); + table[lit2.var()] = lit1 ^ lit2.sign(); + replacedVars++; + return true; + } + + //both have children + setAllThatPointsHereTo(lit1.var(), lit2 ^ lit1.sign()); //erases reverseTable[lit1.var()] + replacedVars++; + return true; +} + +template bool VarReplacer::replace(vec<Lit>& ps, const bool xorEqualFalse, const bool addBinAsLearnt, const bool addToWatchLists); +template bool VarReplacer::replace(XorClause& ps, const bool xorEqualFalse, const bool addBinAsLearnt, const bool addToWatchLists); + +/** +@brief Adds a binary xor to the internal/external clause set + +It is added externally ONLY if we are in the middle of replacing clauses, +and a new binary xor just came up. That is a very strange and unfortunate +experience, as we cannot change the datastructures in the middle of replacement +so we add this to the binary clauses of Solver, and we recover it next time. + +\todo Clean this messy internal/external thing using a better datastructure. +*/ +void VarReplacer::addBinaryXorClause(Lit lit1, Lit lit2, const bool addBinAsLearnt) +{ + solver.attachBinClause(lit1, lit2, addBinAsLearnt); + solver.dataSync->signalNewBinClause(lit1, lit2); + + lit1 ^= true; + lit2 ^= true; + solver.attachBinClause(lit1, lit2, addBinAsLearnt); + solver.dataSync->signalNewBinClause(lit1, lit2); +} + +/** +@brief Returns if we already know that var = lit + +Also checks if var = ~lit, in which it sets solver.ok = false +*/ +bool VarReplacer::alreadyIn(const Var var, const Lit lit) +{ + Lit lit2 = table[var]; + if (lit2.var() == lit.var()) { + if (lit2.sign() != lit.sign()) { + #ifdef VERBOSE_DEBUG + cout << "Inverted cycle in var-replacement -> UNSAT" << endl; + #endif + solver.ok = false; + } + return true; + } + + lit2 = table[lit.var()]; + if (lit2.var() == var) { + if (lit2.sign() != lit.sign()) { + #ifdef VERBOSE_DEBUG + cout << "Inverted cycle in var-replacement -> UNSAT" << endl; + #endif + solver.ok = false; + } + return true; + } + + return false; +} + +/** +@brief Changes internal graph to set everything that pointed to var to point to lit +*/ +void VarReplacer::setAllThatPointsHereTo(const Var var, const Lit lit) +{ + map<Var, vector<Var> >::iterator it = reverseTable.find(var); + if (it != reverseTable.end()) { + for(vector<Var>::const_iterator it2 = it->second.begin(), end = it->second.end(); it2 != end; it2++) { + assert(table[*it2].var() == var); + if (lit.var() != *it2) { + table[*it2] = lit ^ table[*it2].sign(); + reverseTable[lit.var()].push_back(*it2); + } + } + reverseTable.erase(it); + } + table[var] = lit; + reverseTable[lit.var()].push_back(var); +} + +void VarReplacer::newVar() +{ + table.push_back(Lit(table.size(), false)); + cannot_eliminate.push(false); +} diff --git a/src/prop/cryptominisat/Solver/VarReplacer.h b/src/prop/cryptominisat/Solver/VarReplacer.h new file mode 100644 index 000000000..db79aa3fe --- /dev/null +++ b/src/prop/cryptominisat/Solver/VarReplacer.h @@ -0,0 +1,153 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#ifndef VARREPLACER_H +#define VARREPLACER_H + +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#include <map> +#include <vector> + +#include "Solver.h" +#include "SolverTypes.h" +#include "Clause.h" +#include "Vec.h" + +namespace CMSat { + +using std::map; +using std::vector; + +/** +@brief Replaces variables with their anti/equivalents +*/ +class VarReplacer +{ + public: + VarReplacer(Solver& solver); + ~VarReplacer(); + bool performReplace(const bool always = false); + bool needsReplace(); + template<class T> + bool replace(T& ps, const bool xorEqualFalse, const bool addBinAsLearnt = false, const bool addToWatchLists = true); + + void extendModelPossible() const; + void extendModelImpossible(Solver& solver2) const; + + uint32_t getNumReplacedLits() const; + uint32_t getNumReplacedVars() const; + uint32_t getNumLastReplacedVars() const; + uint32_t getNewToReplaceVars() const; + uint32_t getNumTrees() const; + vector<Var> getReplacingVars() const; + const vector<Lit>& getReplaceTable() const; + bool varHasBeenReplaced(const Var var) const; + bool replacingVar(const Var var) const; + void newVar(); + + vec<char> cannot_eliminate; + + //No need to update, only stores binary clauses, that + //have been allocated within pool + //friend class ClauseAllocator; + + private: + bool performReplaceInternal(); + + bool replace_set(vec<Clause*>& cs); + bool replaceBins(); + bool replace_set(vec<XorClause*>& cs); + bool handleUpdatedClause(Clause& c, const Lit origLit1, const Lit origLit2, const Lit origLit3); + bool handleUpdatedClause(XorClause& c, const Var origVar1, const Var origVar2); + void addBinaryXorClause(Lit lit1, Lit lit2, const bool addBinAsLearnt = false); + + void setAllThatPointsHereTo(const Var var, const Lit lit); + bool alreadyIn(const Var var, const Lit lit); + + vector<Lit> table; ///<Stores which variables have been replaced by which literals. Index by: table[VAR] + map<Var, vector<Var> > reverseTable; ///<mapping of variable to set of variables it replaces + + uint32_t replacedLits; ///<Num literals replaced during var-replacement + uint32_t replacedVars; ///<Num vars replaced during var-replacement + uint32_t lastReplacedVars; ///<Last time performReplace() was called, "replacedVars" contained this + Solver& solver; ///<The solver we are working with +}; + +inline bool VarReplacer::performReplace(const bool always) +{ + //uint32_t limit = std::min((uint32_t)((double)solver.order_heap.size()*PERCENTAGEPERFORMREPLACE), FIXCLEANREPLACE); + uint32_t limit = (uint32_t)((double)solver.order_heap.size()*PERCENTAGEPERFORMREPLACE); + if ((always && getNewToReplaceVars() > 0) || getNewToReplaceVars() > limit) + return performReplaceInternal(); + + return true; +} + +inline bool VarReplacer::needsReplace() +{ + uint32_t limit = (uint32_t)((double)solver.order_heap.size()*PERCENTAGEPERFORMREPLACE); + return (getNewToReplaceVars() > limit); +} + +inline uint32_t VarReplacer::getNumReplacedLits() const +{ + return replacedLits; +} + +inline uint32_t VarReplacer::getNumReplacedVars() const +{ + return replacedVars; +} + +inline uint32_t VarReplacer::getNumLastReplacedVars() const +{ + return lastReplacedVars; +} + +inline uint32_t VarReplacer::getNewToReplaceVars() const +{ + return replacedVars-lastReplacedVars; +} + +inline const vector<Lit>& VarReplacer::getReplaceTable() const +{ + return table; +} + +inline bool VarReplacer::varHasBeenReplaced(const Var var) const +{ + return table[var].var() != var; +} + +inline bool VarReplacer::replacingVar(const Var var) const +{ + return (reverseTable.find(var) != reverseTable.end()); +} + +inline uint32_t VarReplacer::getNumTrees() const +{ + return reverseTable.size(); +} + +} + +#endif //VARREPLACER_H diff --git a/src/prop/cryptominisat/Solver/Watched.h b/src/prop/cryptominisat/Solver/Watched.h new file mode 100644 index 000000000..72075b56a --- /dev/null +++ b/src/prop/cryptominisat/Solver/Watched.h @@ -0,0 +1,278 @@ +/*************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +#ifndef WATCHED_H +#define WATCHED_H + +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +//#define DEBUG_WATCHED + +#include "ClauseOffset.h" +#include "SolverTypes.h" +#include <stdio.h> +#include <limits> +#include "constants.h" + +namespace CMSat { + +/** +@brief An element in the watchlist. Natively contains 2- and 3-long clauses, others are referenced by pointer + +This class contains two 32-bit datapieces. They are either used as: +\li One literal, in the case of binary clauses +\li Two literals, in the case of tertiary clauses +\li One blocking literal (i.e. an example literal from the clause) and a clause +offset (as per ClauseAllocator ), in the case of normal clauses +\li A clause offset (as per ClauseAllocator) for xor clauses +*/ +class Watched { + public: + /** + @brief Constructor for a long normal clause + */ + Watched(const ClauseOffset offset, Lit blockedLit) + { + data1 = blockedLit.toInt(); + data2 = (uint32_t)1 + ((uint32_t)offset << 2); + } + + Watched() : + data1 (std::numeric_limits<uint32_t>::max()) + , data2(std::numeric_limits<uint32_t>::max()) + {} + + /** + @brief Constructor for an xor-clause + */ + Watched(const ClauseOffset offset) + { + data1 = (uint32_t)offset; + data2 = (uint32_t)2; + } + + /** + @brief Constructor for a binary clause + */ + Watched(const Lit lit, const bool learnt) + { + data1 = lit.toInt(); + data2 = (uint32_t)0 + (((uint32_t)learnt) << 2); + } + + /** + @brief Constructor for a 3-long, non-xor clause + */ + Watched(const Lit lit1, const Lit lit2) + { + data1 = lit1.toInt(); + data2 = (uint32_t)3 + (lit2.toInt()<< 2); + } + + void setNormOffset(const ClauseOffset offset) + { + #ifdef DEBUG_WATCHED + assert(isClause()); + #endif + data2 = (uint32_t)1 + ((uint32_t)offset << 2); + } + + void setXorOffset(const ClauseOffset offset) + { + #ifdef DEBUG_WATCHED + assert(isXorClause()); + #endif + data1 = (uint32_t)offset; + } + + /** + @brief To update the example literal (blocked literal) of a >3-long normal clause + */ + void setBlockedLit(const Lit lit) + { + #ifdef DEBUG_WATCHED + assert(isClause()); + #endif + data1 = lit.toInt(); + } + + bool isBinary() const + { + return ((data2&3) == 0); + } + + bool isNonLearntBinary() const + { + return (data2 == 0); + } + + bool isClause() const + { + return ((data2&3) == 1); + } + + bool isXorClause() const + { + return ((data2&3) == 2); + } + + bool isTriClause() const + { + return ((data2&3) == 3); + } + + /** + @brief Get the sole other lit of the binary clause, or get lit2 of the tertiary clause + */ + Lit getOtherLit() const + { + #ifdef DEBUG_WATCHED + assert(isBinary() || isTriClause()); + #endif + return data1AsLit(); + } + + /** + @brief Set the sole other lit of the binary clause + */ + void setOtherLit(const Lit lit) + { + #ifdef DEBUG_WATCHED + assert(isBinary() || isTriClause()); + #endif + data1 = lit.toInt(); + } + + bool getLearnt() const + { + #ifdef DEBUG_WATCHED + assert(isBinary()); + #endif + return (bool)(data2 >> 2); + } + + void setLearnt(const bool learnt) + { + #ifdef DEBUG_WATCHED + assert(isBinary()); + assert(learnt == false); + #endif + data2 = (uint32_t)0 + (((uint32_t)learnt) << 2); + } + + /** + @brief Get the 3rd literal of a 3-long clause + */ + Lit getOtherLit2() const + { + #ifdef DEBUG_WATCHED + assert(isTriClause()); + #endif + return data2AsLit(); + } + + /** + @brief Get example literal (blocked lit) of a normal >3-long clause + */ + Lit getBlockedLit() const + { + #ifdef DEBUG_WATCHED + assert(isClause()); + #endif + return data1AsLit(); + } + + /** + @brief Get offset of a >3-long normal clause or of an xor clause (which may be 3-long) + */ + ClauseOffset getNormOffset() const + { + #ifdef DEBUG_WATCHED + assert(isClause()); + #endif + return (ClauseOffset)(data2 >> 2); + } + + ClauseOffset getXorOffset() const + { + #ifdef DEBUG_WATCHED + assert(isXorClause()); + #endif + return (ClauseOffset)(data1); + } + + void dump(FILE* outfile, const Lit lit) const + { + assert(isBinary()); + lit.print(outfile); + getOtherLit().printFull(outfile); + } + + void setNormClause() + { + data2 = 1; + } + + #ifdef DUMP_STATS_FULL + int glue; + #endif + + private: + Lit data1AsLit() const + { + return (Lit::toLit(data1)); + } + + Lit data2AsLit() const + { + return (Lit::toLit(data2>>2)); + } + + uint32_t data1; + uint32_t data2; +}; + +/** +@brief Orders the watchlists such that the order is binary, tertiary, normal, xor +*/ +struct WatchedSorter +{ + bool operator () (const Watched& x, const Watched& y); +}; + +inline bool WatchedSorter::operator () (const Watched& x, const Watched& y) +{ + if (y.isBinary()) return false; + //y is not binary, but x is, so x must be first + if (x.isBinary()) return true; + + //from now on, none is binary. + if (y.isTriClause()) return false; + if (x.isTriClause()) return true; + + //from now on, none is binary or tertiary + //don't bother sorting these + return false; +} + +} + +#endif //WATCHED_H diff --git a/src/prop/cryptominisat/Solver/XSet.h b/src/prop/cryptominisat/Solver/XSet.h new file mode 100644 index 000000000..ab1cd00d1 --- /dev/null +++ b/src/prop/cryptominisat/Solver/XSet.h @@ -0,0 +1,134 @@ +/************************************************************************************************** +From: Solver.C -- (C) Niklas Een, Niklas Sorensson, 2004 +**************************************************************************************************/ + +#ifndef XSET_H +#define XSET_H + +#include "Vec.h" +#include <limits> +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +namespace CMSat { + +class XorClause; + +template <class T> +uint32_t calcXorAbstraction(const T& ps) { + uint32_t abstraction = 0; + for (uint32_t i = 0; i != ps.size(); i++) + abstraction |= 1 << (ps[i].var() & 31); + return abstraction; +} + +//#pragma pack(push) +//#pragma pack(1) +class XorClauseSimp +{ + public: + XorClauseSimp(XorClause* c, const uint32_t _index) : + clause(c) + , index(_index) + {} + + XorClause* clause; + uint32_t index; +}; +//#pragma pack(pop) + +class XSet { + vec<uint32_t> where; // Map clause ID to position in 'which'. + vec<XorClauseSimp> which; // List of clauses (for fast iteration). May contain 'Clause_NULL'. + vec<uint32_t> free; // List of positions holding 'Clause_NULL'. + + public: + //XorClauseSimp& operator [] (uint32_t index) { return which[index]; } + void reserve(uint32_t size) { where.reserve(size);} + uint32_t size(void) const { return which.size(); } + uint32_t nElems(void) const { return which.size() - free.size(); } + + bool add(const XorClauseSimp& c) { + assert(c.clause != NULL); + where.growTo(c.index+1, std::numeric_limits<uint32_t>::max()); + if (where[c.index] != std::numeric_limits<uint32_t>::max()) { + return true; + } + if (free.size() > 0){ + where[c.index] = free.last(); + which[free.last()] = c; + free.pop(); + }else{ + where[c.index] = which.size(); + which.push(c); + } + return false; + } + + bool exclude(const XorClauseSimp& c) { + assert(c.clause != NULL); + if (c.index >= where.size() || where[c.index] == std::numeric_limits<uint32_t>::max()) { + //not inside + return false; + } + free.push(where[c.index]); + which[where[c.index]].clause = NULL; + where[c.index] = std::numeric_limits<uint32_t>::max(); + return true; + } + + void clear(void) { + for (uint32_t i = 0; i < which.size(); i++) { + if (which[i].clause != NULL) { + where[which[i].index] = std::numeric_limits<uint32_t>::max(); + } + } + which.clear(); + free.clear(); + } + + class iterator + { + public: + iterator(XorClauseSimp* _it) : + it(_it) + {} + + void operator++() + { + it++; + } + + bool operator!=(const iterator& iter) const + { + return (it != iter.it);; + } + + XorClauseSimp& operator*() { + return *it; + } + + XorClauseSimp*& operator->() { + return it; + } + private: + XorClauseSimp* it; + }; + + iterator begin() + { + return iterator(which.getData()); + } + + iterator end() + { + return iterator(which.getData() + which.size()); + } +}; + +#endif //XSET_H + +} diff --git a/src/prop/cryptominisat/Solver/XorFinder.cpp b/src/prop/cryptominisat/Solver/XorFinder.cpp new file mode 100644 index 000000000..1b82430e9 --- /dev/null +++ b/src/prop/cryptominisat/Solver/XorFinder.cpp @@ -0,0 +1,462 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#include "XorFinder.h" + +#include <algorithm> +#include <utility> +#include <iostream> +#include "Solver.h" +#include "VarReplacer.h" +#include "ClauseCleaner.h" +#include "time_mem.h" + +//#define VERBOSE_DEBUG + +using namespace CMSat; +using std::make_pair; + +XorFinder::XorFinder(Solver& _solver, vec<Clause*>& _cls) : + cls(_cls) + , solver(_solver) +{ +} + +bool XorFinder::fullFindXors(const uint32_t minSize, const uint32_t maxSize) +{ + uint32_t sumLengths = 0; + double time = cpuTime(); + foundXors = 0; + solver.clauseCleaner->cleanClauses(solver.clauses, ClauseCleaner::clauses); + if (!solver.ok) return false; + + toRemove.clear(); + toRemove.resize(cls.size(), false); + toLeaveInPlace.clear(); + toLeaveInPlace.resize(cls.size(), false); + + table.clear(); + table.reserve(cls.size()); + + for (Clause **it = cls.getData(), **end = cls.getDataEnd(); it != end; it ++) { + if (it+1 != end) __builtin_prefetch(*(it+1)); + Clause& c = (**it); + assert((*it)->size() > 2); + bool sorted = true; + for (uint32_t i = 0, size = c.size(); i+1 < size ; i++) { + sorted = (c[i].var() <= c[i+1].var()); + if (!sorted) break; + } + if (!sorted) { + solver.detachClause(c); + std::sort(c.getData(), c.getDataEnd()); + solver.attachClause(c); + } + } + + uint32_t i = 0; + for (Clause **it = cls.getData(), **end = cls.getDataEnd(); it != end; it++, i++) { + const uint32_t size = (*it)->size(); + if ( size > maxSize || size < minSize) { + toLeaveInPlace[i] = true; + continue; + } + table.push_back(make_pair(*it, i)); + } + std::sort(table.begin(), table.end(), clause_sorter_primary()); + + if (!findXors(sumLengths)) goto end; + solver.ok = (solver.propagate<true>().isNULL()); + +end: + + if (solver.conf.verbosity >= 1 || (solver.conf.verbosity >= 1 && foundXors > 0)) { + printf("c Finding non-binary XORs: %5.2f s (found: %7d, avg size: %3.1f)\n", cpuTime()-time, foundXors, (double)sumLengths/(double)foundXors); + } + + i = 0; + uint32_t j = 0; + uint32_t toSkip = 0; + for (uint32_t end = cls.size(); i != end; i++) { + if (toLeaveInPlace[i]) { + cls[j] = cls[i]; + j++; + toSkip++; + continue; + } + if (!toRemove[table[i-toSkip].second]) { + cls[j] = table[i-toSkip].first; + j++; + } + } + cls.shrink(i-j); + + return solver.ok; +} + + +/** +@brief Finds xors in clauseTable -- datastructures must already be set up + +Identifies sets of clauses of the same length and variable content, and then +tries to merge them into an XOR. +*/ +bool XorFinder::findXors(uint32_t& sumLengths) +{ + #ifdef VERBOSE_DEBUG + cout << "Finding Xors started" << endl; + #endif + + sumLengths = 0; + + ClauseTable::iterator begin = table.begin(); + ClauseTable::iterator end = table.begin(); + vec<Lit> lits; + bool impair; + while (getNextXor(begin, end, impair)) { + const Clause& c = *(begin->first); + lits.clear(); + for (const Lit *it = &c[0], *cend = it+c.size() ; it != cend; it++) { + lits.push(Lit(it->var(), false)); + } + + #ifdef VERBOSE_DEBUG + cout << "- Found clauses:" << endl; + #endif + + for (ClauseTable::iterator it = begin; it != end; it++) { + //This clause belongs to the xor we found? + //(i.e. does it have the correct number of inverted literals?) + if (impairSigns(*it->first) == impair){ + #ifdef VERBOSE_DEBUG + it->first->plainPrint(); + #endif + toRemove[it->second] = true; + solver.removeClause(*it->first); + } + } + + assert(lits.size() > 2); + XorClause* x = solver.addXorClauseInt(lits, impair); + if (x != NULL) solver.xorclauses.push(x); + if (!solver.ok) return false; + + #ifdef VERBOSE_DEBUG + cout << "- Final xor-clause: " << x << std::endl;; + #endif + + foundXors++; + sumLengths += lits.size(); + } + + return solver.ok; +} + +/** +@brief Moves to the next set of begin&end pointers that contain an xor + +@p begin[inout] start searching here in XorFinder::table +@p end[inout] end iterator of XorFinder::table until which the xor spans +*/ +bool XorFinder::getNextXor(ClauseTable::iterator& begin, ClauseTable::iterator& end, bool& impair) +{ + ClauseTable::iterator tableEnd = table.end(); + + while(begin != tableEnd && end != tableEnd) { + begin = end; + end++; + uint32_t size = (end == tableEnd ? 0:1); + while(end != tableEnd && clause_vareq(begin->first, end->first)) { + size++; + end++; + } + if (size > 0 && isXor(size, begin, end, impair)) + return true; + } + + return false; +} + +/** +@brief Returns if the two clauses are equal + +NOTE: assumes that the clauses are of equal lenght AND contain the same +variables (but the invertedness of the literals might differ) +*/ +bool XorFinder::clauseEqual(const Clause& c1, const Clause& c2) const +{ + assert(c1.size() == c2.size()); + for (uint32_t i = 0, size = c1.size(); i < size; i++) + if (c1[i].sign() != c2[i].sign()) return false; + + return true; +} + +/** +@brief Returns whether the number of inverted literals in the clause is pair or impair +*/ +bool XorFinder::impairSigns(const Clause& c) const +{ + uint32_t num = 0; + for (const Lit *it = &c[0], *end = it + c.size(); it != end; it++) + num += it->sign(); + + return num % 2; +} + +/** +@brief Gets as input a set of clauses of equal size and variable content, decides if there is an XOR in them + +@param impair If there is an XOR, this tells if that XOR contains an impair +number of inverted literal or not +@return True, if ther is an XOR, and False if not +*/ +bool XorFinder::isXor(const uint32_t size, const ClauseTable::iterator& begin, const ClauseTable::iterator& end, bool& impair) +{ + const uint32_t requiredSize = 1 << (begin->first->size()-1); + + //Note: "size" can be larger than requiredSize, since there might be + //a mix of imparied and paired num. inverted literals, and furthermore, + //clauses might be repeated + if (size < requiredSize) return false; + + #ifdef DEBUG_XORFIND2 + { + vec<Var> vars; + Clause& c = *begin->first; + for (uint32_t i = 0; i < c.size(); i++) + vars.push(c[i].var()); + for (ClauseTable::iterator it = begin; it != end; it++) { + Clause& c = *it->first; + for (uint32_t i = 0; i < c.size(); i++) + assert(vars[i] == c[i].var()); + } + clause_sorter_primary sorter; + + for (ClauseTable::iterator it = begin; it != end; it++) { + ClauseTable::iterator it2 = it; + it2++; + if (it2 == end) break; + assert(!sorter(*it2, *it)); + } + } + #endif //DEBUG_XORFIND + + //We now sort them according to literal content + std::sort(begin, end, clause_sorter_secondary()); + + uint32_t numPair = 0; + uint32_t numImpair = 0; + countImpairs(begin, end, numImpair, numPair); + + //if there are two XORs with equal variable sets, but different invertedness + //that leads to direct UNSAT result. + if (numImpair == requiredSize && numPair == requiredSize) { + solver.ok = false; + impair = true; + return true; + } + + if (numImpair == requiredSize) { + impair = true; + return true; + } + + if (numPair == requiredSize) { + impair = false; + return true; + } + + return false; +} + +/** +@brief Counts number of negations in the literals in clauses between begin&end, and returns the number of clauses with pair, and impair literals +*/ +void XorFinder::countImpairs(const ClauseTable::iterator& begin, const ClauseTable::iterator& end, uint32_t& numImpair, uint32_t& numPair) const +{ + numImpair = 0; + numPair = 0; + + ClauseTable::const_iterator it = begin; + ClauseTable::const_iterator it2 = begin; + it2++; + + bool impair = impairSigns(*it->first); + numImpair += impair; + numPair += !impair; + + for (; it2 != end;) { + if (!clauseEqual(*it->first, *it2->first)) { + bool impair = impairSigns(*it2->first); + numImpair += impair; + numPair += !impair; + } + it++; + it2++; + } +} + +/** +@brief Converts all xor clauses to normal clauses + +Sometimes it's not worth the hassle of having xor clauses and normal clauses. +This function converts xor clauses to normal clauses, and removes the normal +clauses. + +\todo It currently only works for 3- and 4-long clauses. Larger clauses should +also be handled. +*/ +void XorFinder::addAllXorAsNorm() +{ + uint32_t added = 0; + XorClause **i = solver.xorclauses.getData(), **j = i; + for (XorClause **end = solver.xorclauses.getDataEnd(); i != end; i++) { + if ((*i)->size() > 3) { + *j++ = *i; + continue; + } + added++; + if ((*i)->size() == 3) addXorAsNormal3(**i); + //if ((*i)->size() == 4) addXorAsNormal4(**i); + solver.removeClause(**i); + } + solver.xorclauses.shrink(i-j); + if (solver.conf.verbosity >= 1) { + std::cout << "c Added XOR as norm:" << added << std::endl; + } +} + +/** +@brief Utility function for addAllXorAsNorm() for converting 3-long xor clauses to normal clauses + +\todo clean this up, it's ugly +*/ +void XorFinder::addXorAsNormal3(XorClause& c) +{ + assert(c.size() == 3); + Clause *tmp; + vec<Var> vars; + const bool inverted = c.xorEqualFalse(); + + for (uint32_t i = 0; i < c.size(); i++) { + vars.push(c[i].var()); + } + + vec<Lit> vars2; + vars2.growTo(3); + vars2[0] = Lit(vars[0], false ^ inverted); + vars2[1] = Lit(vars[1], false ^ inverted); + vars2[2] = Lit(vars[2], false ^ inverted); + tmp = solver.addClauseInt(vars2); + if (tmp) solver.clauses.push(tmp); + + vars2.growTo(3); + vars2[0] = Lit(vars[0], true ^ inverted); + vars2[1] = Lit(vars[1], true ^ inverted); + vars2[2] = Lit(vars[2], false ^ inverted); + tmp = solver.addClauseInt(vars2); + if (tmp) solver.clauses.push(tmp); + + vars2.growTo(3); + vars2[0] = Lit(vars[0], true ^ inverted); + vars2[1] = Lit(vars[1], false ^ inverted); + vars2[2] = Lit(vars[2], true ^ inverted); + tmp = solver.addClauseInt(vars2); + if (tmp) solver.clauses.push(tmp); + + vars2.growTo(3); + vars2[0] = Lit(vars[0], false ^ inverted); + vars2[1] = Lit(vars[1], true ^ inverted); + vars2[2] = Lit(vars[2], true ^ inverted); + tmp = solver.addClauseInt(vars2); + if (tmp) solver.clauses.push(tmp); +} + +/** +@brief Utility function for addAllXorAsNorm() for converting 4-long xor clauses to normal clauses + +\todo clean this up, it's ugly +*/ +void XorFinder::addXorAsNormal4(XorClause& c) +{ + assert(c.size() == 4); + Clause *tmp; + vec<Var> vars; + vec<Lit> vars2(c.size()); + const bool inverted = !c.xorEqualFalse(); + + for (uint32_t i = 0; i < c.size(); i++) { + vars.push(c[i].var()); + } + + vars2[0] = Lit(vars[0], false ^ inverted); + vars2[1] = Lit(vars[1], false ^ inverted); + vars2[2] = Lit(vars[2], false ^ inverted); + vars2[3] = Lit(vars[3], true ^ inverted); + tmp = solver.addClauseInt(vars2); + if (tmp) solver.clauses.push(tmp); + + vars2[0] = Lit(vars[0], false ^ inverted); + vars2[1] = Lit(vars[1], true ^ inverted); + vars2[2] = Lit(vars[2], false ^ inverted); + vars2[3] = Lit(vars[3], false ^ inverted); + tmp = solver.addClauseInt(vars2); + if (tmp) solver.clauses.push(tmp); + + vars2[0] = Lit(vars[0], false ^ inverted); + vars2[1] = Lit(vars[1], false ^ inverted); + vars2[2] = Lit(vars[2], true ^ inverted); + vars2[3] = Lit(vars[3], false ^ inverted); + tmp = solver.addClauseInt(vars2); + if (tmp) solver.clauses.push(tmp); + + vars2[0] = Lit(vars[0], false ^ inverted); + vars2[1] = Lit(vars[1], false ^ inverted); + vars2[2] = Lit(vars[2], false ^ inverted); + vars2[3] = Lit(vars[3], true ^ inverted); + tmp = solver.addClauseInt(vars2); + if (tmp) solver.clauses.push(tmp); + + vars2[0] = Lit(vars[0], false ^ inverted); + vars2[1] = Lit(vars[1], true ^ inverted); + vars2[2] = Lit(vars[2], true ^ inverted); + vars2[3] = Lit(vars[3], true ^ inverted); + tmp = solver.addClauseInt(vars2); + if (tmp) solver.clauses.push(tmp); + + vars2[0] = Lit(vars[0], true ^ inverted); + vars2[1] = Lit(vars[1], false ^ inverted); + vars2[2] = Lit(vars[2], true ^ inverted); + vars2[3] = Lit(vars[3], true ^ inverted); + tmp = solver.addClauseInt(vars2); + if (tmp) solver.clauses.push(tmp); + + vars2[0] = Lit(vars[0], true ^ inverted); + vars2[1] = Lit(vars[1], true ^ inverted); + vars2[2] = Lit(vars[2], false ^ inverted); + vars2[3] = Lit(vars[3], true ^ inverted); + tmp = solver.addClauseInt(vars2); + if (tmp) solver.clauses.push(tmp); + + vars2[0] = Lit(vars[0], true ^ inverted); + vars2[1] = Lit(vars[1], true ^ inverted); + vars2[2] = Lit(vars[2], true ^ inverted); + vars2[3] = Lit(vars[3], false ^ inverted); + tmp = solver.addClauseInt(vars2); + if (tmp) solver.clauses.push(tmp); +} diff --git a/src/prop/cryptominisat/Solver/XorFinder.h b/src/prop/cryptominisat/Solver/XorFinder.h new file mode 100644 index 000000000..418dd00e3 --- /dev/null +++ b/src/prop/cryptominisat/Solver/XorFinder.h @@ -0,0 +1,157 @@ +/*********************************************************************************** +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +**************************************************************************************************/ + +#ifndef XORFINDER_H +#define XORFINDER_H + +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#define DEBUG_XORFIND +//#define DEBUG_XORFIND2 + +#include "Clause.h" +#include "VarReplacer.h" +#include "ClauseCleaner.h" + +namespace CMSat { + +class Solver; + +using std::pair; + +/** +@brief Finds xors given a set of clauses + +It basically sorts clauses' literals, sorts clauses according to size and +variable content, then idetifies continious reagions that could be an XOR +clause, finds the xor clause by counting the number of unique negation +permutations of the literals, then removes the clauses, and inserts the xor +clause +*/ +class XorFinder +{ + public: + XorFinder(Solver& _solver, vec<Clause*>& cls); + bool fullFindXors(const uint32_t minSize, const uint32_t maxSize); + void addAllXorAsNorm(); + + private: + typedef vector<pair<Clause*, uint32_t> > ClauseTable; + + bool findXors(uint32_t& sumLengths); + bool getNextXor(ClauseTable::iterator& begin, ClauseTable::iterator& end, bool& impair); + + /** + @brief For sorting clauses according to their size&their var content. Clauses' variables must already be sorted + */ + struct clause_sorter_primary { + bool operator()(const pair<Clause*, uint32_t>& c11, const pair<Clause*, uint32_t>& c22) + { + if (c11.first->size() != c22.first->size()) + return (c11.first->size() < c22.first->size()); + + #ifdef DEBUG_XORFIND2 + Clause& c1 = *c11.first; + for (uint32_t i = 0; i+1 < c1.size(); i++) + assert(c1[i].var() <= c1[i+1].var()); + + Clause& c2 = *c22.first; + for (uint32_t i = 0; i+1 < c2.size(); i++) + assert(c2[i].var() <= c2[i+1].var()); + #endif //DEBUG_XORFIND2 + + for (a = c11.first->getData(), b = c22.first->getData(), end = c11.first->getDataEnd(); a != end; a++, b++) { + if (a->var() != b->var()) + return (a->var() > b->var()); + } + + return false; + } + + Lit const *a; + Lit const *b; + Lit const *end; + }; + + /** + @brief Sorts clauses with equal length and variable content according to their literals' signs + + NOTE: the length and variable content of c11 and c22 MUST be the same + + Used to avoid the problem of having 2 clauses with exactly the same + content being counted as two different clauses (when counting the + (im)pairedness of XOR being searched) + */ + struct clause_sorter_secondary { + bool operator()(const pair<Clause*, uint32_t>& c11, const pair<Clause*, uint32_t>& c22) const + { + const Clause& c1 = *(c11.first); + const Clause& c2 = *(c22.first); + assert(c1.size() == c2.size()); + + for (uint32_t i = 0, size = c1.size(); i < size; i++) { + assert(c1[i].var() == c2[i].var()); + if (c1[i].sign() != c2[i].sign()) + return c1[i].sign(); + } + + return false; + } + }; + + /** + @brief Returns whether vars in clauses are the same -- clauses' literals must be identically sorted + */ + bool clause_vareq(const Clause* c1, const Clause* c2) const + { + if (c1->size() != c2->size()) + return false; + + for (uint32_t i = 0, size = c1->size(); i < size; i++) + if ((*c1)[i].var() != (*c2)[i].var()) + return false; + + return true; + } + + ClauseTable table; + vector<bool> toRemove; + vector<bool> toLeaveInPlace; + void clearToRemove(); + uint32_t foundXors; + + //For adding xor clause as normal clause + void addXorAsNormal3(XorClause& c); + void addXorAsNormal4(XorClause& c); + + vec<Clause*>& cls; + + bool clauseEqual(const Clause& c1, const Clause& c2) const; + bool impairSigns(const Clause& c) const; + void countImpairs(const ClauseTable::iterator& begin, const ClauseTable::iterator& end, uint32_t& numImpair, uint32_t& numPair) const; + bool isXor(const uint32_t size, const ClauseTable::iterator& begin, const ClauseTable::iterator& end, bool& impair); + + Solver& solver; +}; + +} + +#endif //XORFINDER_H diff --git a/src/prop/cryptominisat/Solver/XorSubsumer.cpp b/src/prop/cryptominisat/Solver/XorSubsumer.cpp new file mode 100644 index 000000000..f6776428e --- /dev/null +++ b/src/prop/cryptominisat/Solver/XorSubsumer.cpp @@ -0,0 +1,622 @@ +/***************************************************************************** +SatELite -- (C) Niklas Een, Niklas Sorensson, 2004 +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +Original code by SatELite authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3. +******************************************************************************/ + +#include "Solver.h" +#include "XorSubsumer.h" +#include "ClauseCleaner.h" +#include "time_mem.h" +#include "assert.h" +#include <iomanip> +#include "VarReplacer.h" + +//#define VERBOSE_DEBUG +#ifdef VERBOSE_DEBUG +#define VERBOSE_DEBUGSUBSUME0 +#define BIT_MORE_VERBOSITY +#endif + +using namespace CMSat; + +XorSubsumer::XorSubsumer(Solver& s): + solver(s) + , totalTime(0.0) + , numElimed(0) + , localSubstituteUseful(0) +{ +} + +// Will put NULL in 'cs' if clause removed. +void XorSubsumer::subsume0(XorClauseSimp ps) +{ + #ifdef VERBOSE_DEBUGSUBSUME0 + cout << "subsume0 orig clause:"; + ps.clause->plainPrint(); + #endif + + vec<Lit> unmatchedPart; + vec<XorClauseSimp> subs; + + findSubsumed(*ps.clause, subs); + for (uint32_t i = 0; i < subs.size(); i++){ + XorClause* tmp = subs[i].clause; + findUnMatched(*ps.clause, *tmp, unmatchedPart); + if (unmatchedPart.size() == 0) { + #ifdef VERBOSE_DEBUGSUBSUME0 + cout << "subsume0 removing:"; + subs[i].clause->plainPrint(); + #endif + clauses_subsumed++; + assert(tmp->size() == ps.clause->size()); + if (ps.clause->xorEqualFalse() == tmp->xorEqualFalse()) { + unlinkClause(subs[i]); + } else { + solver.ok = false; + return; + } + } else { + assert(unmatchedPart.size() > 0); + clauses_cut++; + #ifdef VERBOSE_DEBUG + std::cout << "Cutting xor-clause:"; + subs[i].clause->plainPrint(); + #endif //VERBOSE_DEBUG + XorClause *c = solver.addXorClauseInt(unmatchedPart, tmp->xorEqualFalse() ^ !ps.clause->xorEqualFalse()); + if (c != NULL) + linkInClause(*c); + unlinkClause(subs[i]); + if (!solver.ok) return; + } + unmatchedPart.clear(); + } +} + +template<class T> +void XorSubsumer::findUnMatched(const T& A, const T& B, vec<Lit>& unmatchedPart) +{ + for (uint32_t i = 0; i != B.size(); i++) + seen_tmp[B[i].var()] = 1; + for (uint32_t i = 0; i != A.size(); i++) + seen_tmp[A[i].var()] = 0; + for (uint32_t i = 0; i != B.size(); i++) { + if (seen_tmp[B[i].var()] == 1) { + unmatchedPart.push(Lit(B[i].var(), false)); + seen_tmp[B[i].var()] = 0; + } + } +} + +void XorSubsumer::unlinkClause(XorClauseSimp c, const Var elim) +{ + XorClause& cl = *c.clause; + + for (uint32_t i = 0; i < cl.size(); i++) { + removeW(occur[cl[i].var()], &cl); + } + + if (elim != var_Undef) { + XorElimedClause data; + for (Lit *it = cl.getData(), *end = cl.getDataEnd(); it != end; it++) { + data.lits.push_back(it->unsign()); + } + data.xorEqualFalse = cl.xorEqualFalse(); + elimedOutVar[elim].push_back(data); + } + solver.detachClause(cl); + solver.clauseAllocator.clauseFree(c.clause); + + clauses[c.index].clause = NULL; +} + +void XorSubsumer::unlinkModifiedClause(vec<Lit>& origClause, XorClauseSimp c) +{ + for (uint32_t i = 0; i < origClause.size(); i++) { + removeW(occur[origClause[i].var()], c.clause); + } + + solver.detachModifiedClause(origClause[0].var(), origClause[1].var(), origClause.size(), c.clause); + + clauses[c.index].clause = NULL; +} + +void XorSubsumer::unlinkModifiedClauseNoDetachNoNULL(vec<Lit>& origClause, XorClauseSimp c) +{ + for (uint32_t i = 0; i < origClause.size(); i++) { + removeW(occur[origClause[i].var()], c.clause); + } +} + +XorClauseSimp XorSubsumer::linkInClause(XorClause& cl) +{ + XorClauseSimp c(&cl, clauseID++); + clauses.push(c); + for (uint32_t i = 0; i < cl.size(); i++) { + occur[cl[i].var()].push(c); + } + + return c; +} + +void XorSubsumer::linkInAlreadyClause(XorClauseSimp& c) +{ + XorClause& cl = *c.clause; + + for (uint32_t i = 0; i < c.clause->size(); i++) { + occur[cl[i].var()].push(c); + } +} + +void XorSubsumer::addFromSolver(vec<XorClause*>& cs) +{ + clauseID = 0; + clauses.clear(); + XorClause **i = cs.getData(); + for (XorClause **end = i + cs.size(); i != end; i++) { + if (i+1 != end) __builtin_prefetch(*(i+1)); + + linkInClause(**i); + } + cs.clear(); + cs.push(NULL); //HACK --to force xor-propagation +} + +void XorSubsumer::addBackToSolver() +{ + solver.xorclauses.pop(); //HACK --to force xor-propagation + for (uint32_t i = 0; i < clauses.size(); i++) { + if (clauses[i].clause != NULL) { + solver.xorclauses.push(clauses[i].clause); + clauses[i].clause->unsetChanged(); + } + } + for (Var var = 0; var < solver.nVars(); var++) { + occur[var].clear(); + } + clauses.clear(); + clauseID = 0; +} + +void XorSubsumer::fillCannotEliminate() +{ + std::fill(cannot_eliminate.getData(), cannot_eliminate.getDataEnd(), false); + for (uint32_t i = 0; i < solver.clauses.size(); i++) + addToCannotEliminate(solver.clauses[i]); + + uint32_t wsLit = 0; + for (const vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec<Watched>& ws = *it; + for (vec<Watched>::const_iterator it2 = ws.getData(), end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary() && !it2->getLearnt()) { + cannot_eliminate[lit.var()] = true; + cannot_eliminate[it2->getOtherLit().var()] = true; + } + } + } + + for (Var var = 0; var < solver.nVars(); var++) { + cannot_eliminate[var] |= solver.varReplacer->cannot_eliminate[var]; + } + + #ifdef VERBOSE_DEBUG + uint32_t tmpNum = 0; + for (uint32_t i = 0; i < cannot_eliminate.size(); i++) + if (cannot_eliminate[i]) + tmpNum++; + std::cout << "Cannot eliminate num:" << tmpNum << std::endl; + #endif +} + +void XorSubsumer::extendModel(Solver& solver2) +{ + #ifdef VERBOSE_DEBUG + std::cout << "XorSubsumer::extendModel(Solver& solver2) called" << std::endl; + #endif + + assert(checkElimedUnassigned()); + vec<Lit> tmp; + typedef map<Var, vector<XorElimedClause> > elimType; + for (elimType::iterator it = elimedOutVar.begin(), end = elimedOutVar.end(); it != end; it++) { + #ifdef VERBOSE_DEBUG + Var var = it->first; + std::cout << "Reinserting elimed var: " << var+1 << std::endl; + #endif + + for (vector<XorElimedClause>::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { + XorElimedClause& c = *it2; + #ifdef VERBOSE_DEBUG + std::cout << "Reinserting Clause: "; + c.plainPrint(); + #endif + tmp.clear(); + tmp.growTo(c.lits.size()); + std::copy(c.lits.begin(), c.lits.end(), tmp.getData()); + solver2.addXorClause(tmp, c.xorEqualFalse); + assert(solver2.ok); + } + } +} + +bool XorSubsumer::localSubstitute() +{ + vec<Lit> tmp; + for (Var var = 0; var < occur.size(); var++) { + vec<XorClauseSimp>& occ = occur[var]; + + if (occ.size() <= 1) continue; + for (uint32_t i = 0; i < occ.size(); i++) { + XorClause& c1 = *occ[i].clause; + for (uint32_t i2 = i+1; i2 < occ.size(); i2++) { + XorClause& c2 = *occ[i2].clause; + tmp.clear(); + xorTwoClauses(c1, c2, tmp); + if (tmp.size() <= 2) { + #ifdef VERBOSE_DEBUG + std::cout << "Local substiuting. Clause1:"; c1.plainPrint(); + std::cout << "Clause 2:"; c2.plainPrint(); + #endif //VERBOSE_DEBUG + localSubstituteUseful++; + XorClause* ret = solver.addXorClauseInt(tmp, c1.xorEqualFalse() ^ !c2.xorEqualFalse()); + release_assert(ret == NULL); + if (!solver.ok) { + #ifdef VERBOSE_DEBUG + std::cout << "solver.ok is false after local substitution" << std::endl; + #endif //VERBOSE_DEBUG + return false; + } + } + } + } + } + + return true; +} + +template<class T> +void XorSubsumer::xorTwoClauses(const T& c1, const T& c2, vec<Lit>& xored) +{ + for (uint32_t i = 0; i != c1.size(); i++) + seen_tmp[c1[i].var()] = 1; + for (uint32_t i = 0; i != c2.size(); i++) + seen_tmp[c2[i].var()] ^= 1; + + for (uint32_t i = 0; i != c1.size(); i++) { + if (seen_tmp[c1[i].var()] == 1) { + xored.push(Lit(c1[i].var(), false)); + seen_tmp[c1[i].var()] = 0; + } + } + for (uint32_t i = 0; i != c2.size(); i++) { + if (seen_tmp[c2[i].var()] == 1) { + xored.push(Lit(c2[i].var(), false)); + seen_tmp[c2[i].var()] = 0; + } + } +} + +void XorSubsumer::removeWrong(vec<Clause*>& cs) +{ + Clause **i = cs.getData(); + Clause **j = i; + for (Clause **end = i + cs.size(); i != end; i++) { + Clause& c = **i; + if (!c.learnt()) { + *j++ = *i; + continue; + } + bool remove = false; + for (Lit *l = c.getData(), *end2 = l+c.size(); l != end2; l++) { + if (var_elimed[l->var()]) { + remove = true; + solver.detachClause(c); + solver.clauseAllocator.clauseFree(&c); + break; + } + } + if (!remove) + *j++ = *i; + } + cs.shrink(i-j); +} + +void XorSubsumer::removeWrongBins() +{ + uint32_t numRemovedHalfLearnt = 0; + uint32_t wsLit = 0; + for (vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + vec<Watched>& ws = *it; + + vec<Watched>::iterator i = ws.getData(); + vec<Watched>::iterator j = i; + for (vec<Watched>::iterator end2 = ws.getDataEnd(); i != end2; i++) { + if (i->isBinary() + && i->getLearnt() + && (var_elimed[lit.var()] || var_elimed[i->getOtherLit().var()]) + ) { + numRemovedHalfLearnt++; + } else { + assert(!i->isBinary() + || (!var_elimed[lit.var()] && !var_elimed[i->getOtherLit().var()])); + *j++ = *i; + } + } + ws.shrink_(i - j); + } + + assert(numRemovedHalfLearnt % 2 == 0); + solver.learnts_literals -= numRemovedHalfLearnt; + solver.numBins -= numRemovedHalfLearnt/2; +} + + +bool XorSubsumer::removeDependent() +{ + for (Var var = 0; var < occur.size(); var++) { + if (cannot_eliminate[var] || !solver.decision_var[var] || solver.assigns[var] != l_Undef) continue; + vec<XorClauseSimp>& occ = occur[var]; + + if (occ.size() == 1) { + #ifdef VERBOSE_DEBUG + std::cout << "Eliminating dependent var " << var + 1 << std::endl; + std::cout << "-> Removing dependent clause "; occ[0].clause->plainPrint(); + #endif //VERBOSE_DEBUG + unlinkClause(occ[0], var); + solver.setDecisionVar(var, false); + var_elimed[var] = true; + numElimed++; + } else if (occ.size() == 2) { + vec<Lit> lits; + XorClause& c1 = *(occ[0].clause); + lits.growTo(c1.size()); + std::copy(c1.getData(), c1.getDataEnd(), lits.getData()); + bool inverted = c1.xorEqualFalse(); + + XorClause& c2 = *(occ[1].clause); + lits.growTo(lits.size() + c2.size()); + std::copy(c2.getData(), c2.getDataEnd(), lits.getData() + c1.size()); + inverted ^= !c2.xorEqualFalse(); + uint32_t ret = removeAll(lits, var); + release_assert(ret == 2); + + #ifdef VERBOSE_DEBUG + std::cout << "Eliminating var " << var + 1 << " present in 2 xor-clauses" << std::endl; + std::cout << "-> Removing xor clause "; occ[0].clause->plainPrint(); + std::cout << "-> Removing xor clause "; occ[1].clause->plainPrint(); + #endif //VERBOSE_DEBUG + XorClauseSimp toUnlink0 = occ[0]; + XorClauseSimp toUnlink1 = occ[1]; + unlinkClause(toUnlink0); + unlinkClause(toUnlink1, var); + solver.setDecisionVar(var, false); + var_elimed[var] = true; + numElimed++; + + for (uint32_t i = 0; i < lits.size(); i++) + cannot_eliminate[lits[i].var()] = true; + XorClause* c = solver.addXorClauseInt(lits, inverted); + #ifdef VERBOSE_DEBUG + if (c != NULL) { + std::cout << "-> Added combined xor clause:"; c->plainPrint(); + } else + std::cout << "-> Combined xor clause is NULL" << std::endl; + #endif + if (c != NULL) linkInClause(*c); + if (!solver.ok) { + #ifdef VERBOSE_DEBUG + std::cout << "solver.ok is false after var-elim through xor" << std::endl; + #endif //VERBOSE_DEBUG + return false; + } + } + } + + return true; +} + +inline void XorSubsumer::addToCannotEliminate(Clause* it) +{ + const Clause& c = *it; + for (uint32_t i2 = 0; i2 < c.size(); i2++) + cannot_eliminate[c[i2].var()] = true; +} + +bool XorSubsumer::unEliminate(const Var var) +{ + assert(var_elimed[var]); + vec<Lit> tmp; + typedef map<Var, vector<XorElimedClause> > elimType; + elimType::iterator it = elimedOutVar.find(var); + + //MUST set to decision, since it would never have been eliminated + //had it not been decision var + solver.setDecisionVar(var, true); + var_elimed[var] = false; + numElimed--; + assert(it != elimedOutVar.end()); + #ifdef VERBOSE_DEBUG + std::cout << "Reinserting xor elimed var: " << var+1 << std::endl; + #endif + + FILE* backup_libraryCNFfile = solver.libraryCNFFile; + solver.libraryCNFFile = NULL; + for (vector<XorElimedClause>::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { + XorElimedClause& c = *it2; + tmp.clear(); + tmp.growTo(c.lits.size()); + std::copy(c.lits.begin(), c.lits.end(), tmp.getData()); + #ifdef VERBOSE_DEBUG + std::cout << "Reinserting elimed clause: " << tmp << std::endl;; + #endif + solver.addXorClause(tmp, c.xorEqualFalse); + } + solver.libraryCNFFile = backup_libraryCNFfile; + elimedOutVar.erase(it); + + return solver.ok; +} + + +bool XorSubsumer::simplifyBySubsumption() +{ + double myTime = cpuTime(); + uint32_t origTrailSize = solver.trail.size(); + clauses_subsumed = 0; + clauses_cut = 0; + clauseID = 0; + uint32_t lastNumElimed = numElimed; + localSubstituteUseful = 0; + while (solver.conf.doReplace && solver.varReplacer->needsReplace()) { + if (!solver.varReplacer->performReplace()) + return false; + } + + for (Var var = 0; var < solver.nVars(); var++) { + occur[var].clear(); + } + solver.findAllAttach(); + + solver.clauseCleaner->cleanClauses(solver.xorclauses, ClauseCleaner::xorclauses); + if (!solver.ok) return false; + + clauses.clear(); + clauses.reserve(solver.xorclauses.size()); + addFromSolver(solver.xorclauses); + #ifdef BIT_MORE_VERBOSITY + std::cout << "c time to link in:" << cpuTime()-myTime << std::endl; + #endif + + origNClauses = clauses.size(); + + if (!solver.ok) return false; + #ifdef VERBOSE_DEBUG + std::cout << "c clauses:" << clauses.size() << std::endl; + #endif + + bool replaced = true; + bool propagated = false; + while (replaced || propagated) { + replaced = propagated = false; + for (uint32_t i = 0; i < clauses.size(); i++) { + if (clauses[i].clause != NULL) { + subsume0(clauses[i]); + if (!solver.ok) { + addBackToSolver(); + return false; + } + } + } + + propagated = (solver.qhead != solver.trail.size()); + solver.ok = (solver.propagate<false>().isNULL()); + if (!solver.ok) { + return false; + } + if (!solver.ok) return false; + + fillCannotEliminate(); + if (solver.conf.doConglXors && !removeDependent()) { + addBackToSolver(); + return false; + } + + if (solver.conf.doHeuleProcess && !localSubstitute()) { + addBackToSolver(); + return false; + } + + /*if (solver.doReplace && solver.varReplacer->needsReplace()) { + addBackToSolver(); + while (solver.doReplace && solver.varReplacer->needsReplace()) { + replaced = true; + if (!solver.varReplacer->performReplace()) + return false; + } + addFromSolver(solver.xorclauses); + }*/ + } + + solver.order_heap.filter(Solver::VarFilter(solver)); + + removeWrong(solver.learnts); + removeWrongBins(); + addBackToSolver(); + removeAssignedVarsFromEliminated(); + + if (solver.conf.verbosity >= 1) { + std::cout << "c x-sub: " << std::setw(5) << clauses_subsumed + << " x-cut: " << std::setw(6) << clauses_cut + << " vfix: " << std::setw(6) <<solver.trail.size() - origTrailSize + << " v-elim: " <<std::setw(6) << numElimed - lastNumElimed + << " locsubst:" << std::setw(6) << localSubstituteUseful + << " time: " << std::setw(6) << std::setprecision(2) << (cpuTime() - myTime) + << std::endl; + } + totalTime += cpuTime() - myTime; + + solver.testAllClauseAttach(); + return true; +} + +void XorSubsumer::findSubsumed(XorClause& ps, vec<XorClauseSimp>& out_subsumed) +{ + #ifdef VERBOSE_DEBUGSUBSUME0 + cout << "findSubsumed: "; + for (uint32_t i = 0; i < ps.size(); i++) { + if (ps[i].sign()) printf("-"); + printf("%d ", ps[i].var() + 1); + } + printf("0\n"); + #endif + + uint32_t min_i = 0; + for (uint32_t i = 1; i < ps.size(); i++){ + if (occur[ps[i].var()].size() < occur[ps[min_i].var()].size()) + min_i = i; + } + + vec<XorClauseSimp>& cs = occur[ps[min_i].var()]; + for (XorClauseSimp *it = cs.getData(), *end = it + cs.size(); it != end; it++){ + if (it+1 != end) __builtin_prefetch((it+1)->clause); + + if (it->clause != &ps && subsetAbst(ps.getAbst(), it->clause->getAbst()) && ps.size() <= it->clause->size() && subset(ps, *it->clause)) { + out_subsumed.push(*it); + #ifdef VERBOSE_DEBUGSUBSUME0 + cout << "subsumed: "; + it->clause->plainPrint(); + #endif + } + } +} + +bool XorSubsumer::checkElimedUnassigned() const +{ + uint32_t checkNumElimed = 0; + for (uint32_t i = 0; i < var_elimed.size(); i++) { + if (var_elimed[i]) { + checkNumElimed++; + assert(solver.assigns[i] == l_Undef); + if (solver.assigns[i] != l_Undef) return false; + } + } + assert(numElimed == checkNumElimed); + + return true; +} + +void XorSubsumer::removeAssignedVarsFromEliminated() +{ + for (Var var = 0; var < var_elimed.size(); var++) { + if (var_elimed[var] && solver.assigns[var] != l_Undef) { + var_elimed[var] = false; + solver.setDecisionVar(var, true); + numElimed--; + map<Var, vector<XorElimedClause> >::iterator it = elimedOutVar.find(var); + if (it != elimedOutVar.end()) elimedOutVar.erase(it); + } + } +} diff --git a/src/prop/cryptominisat/Solver/XorSubsumer.h b/src/prop/cryptominisat/Solver/XorSubsumer.h new file mode 100644 index 000000000..67f9c6dd4 --- /dev/null +++ b/src/prop/cryptominisat/Solver/XorSubsumer.h @@ -0,0 +1,185 @@ +/***************************************************************************** +SatELite -- (C) Niklas Een, Niklas Sorensson, 2004 +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +Original code by SatELite authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3. +******************************************************************************/ + +#ifndef XORSIMPLIFIER_H +#define XORSIMPLIFIER_H + +#include "Solver.h" +#include "Vec.h" +#include "XSet.h" + +namespace CMSat { + +class ClauseCleaner; + +/** +@brief Handles xor-subsumption and variable elimination at the XOR level + +This class achieves three things: + +1) it removes variables though XOR-ing of two xors thereby removing their common +variable. If that variable is not used anywere else, the variable is now removed +from the problem + +2) It tries to XOR clauses together to get 1-long or 2-long XOR clauses. These +force variables to certain values or replace variables with other variables, +respectively + +3) It tries to subsume XOR clauses with other XOR clauses (making 2 XOR clauses +in the process, but one of them is going to be much smaller than it was originally) +*/ +class XorSubsumer +{ +public: + + XorSubsumer(Solver& S2); + bool simplifyBySubsumption(); + void unlinkModifiedClause(vec<Lit>& origClause, XorClauseSimp c); + void unlinkModifiedClauseNoDetachNoNULL(vec<Lit>& origClause, XorClauseSimp c); + void unlinkClause(XorClauseSimp cc, Var elim = var_Undef); + XorClauseSimp linkInClause(XorClause& cl); + void linkInAlreadyClause(XorClauseSimp& c); + void newVar(); + void extendModel(Solver& solver2); + + uint32_t getNumElimed() const; + const vec<char>& getVarElimed() const; + bool unEliminate(const Var var); + bool checkElimedUnassigned() const; + double getTotalTime() const; + + struct XorElimedClause + { + vector<Lit> lits; + bool xorEqualFalse; + + void plainPrint(FILE* to = stdout) const + { + fprintf(to, "x"); + if (xorEqualFalse) fprintf(to, "-"); + for (size_t i = 0; i < lits.size(); i++) { + assert(!lits[i].sign()); + fprintf(to, "%d ", lits[i].var() + 1); + } + fprintf(to, "0\n"); + } + }; + const map<Var, vector<XorElimedClause> >& getElimedOutVar() const; + +private: + + friend class ClauseCleaner; + friend class ClauseAllocator; + + //Main + vec<XorClauseSimp> clauses; + vec<vec<XorClauseSimp> > occur; // 'occur[index(lit)]' is a list of constraints containing 'lit'. + Solver& solver; // The Solver + + // Temporaries (to reduce allocation overhead): + // + vec<char> seen_tmp; // (used in various places) + + //Start-up + void addFromSolver(vec<XorClause*>& cs); + void addBackToSolver(); + + // Subsumption: + void findSubsumed(XorClause& ps, vec<XorClauseSimp>& out_subsumed); + bool isSubsumed(XorClause& ps); + void subsume0(XorClauseSimp ps); + template<class T1, class T2> + bool subset(const T1& A, const T2& B); + bool subsetAbst(uint32_t A, uint32_t B); + template<class T> + void findUnMatched(const T& A, const T& B, vec<Lit>& unmatchedPart); + + //helper + void testAllClauseAttach() const; + + //dependent removal + bool removeDependent(); + void fillCannotEliminate(); + vec<char> cannot_eliminate; + void addToCannotEliminate(Clause* it); + void removeWrong(vec<Clause*>& cs); + void removeWrongBins(); + void removeAssignedVarsFromEliminated(); + + //Global stats + double totalTime; + map<Var, vector<XorElimedClause> > elimedOutVar; + vec<char> var_elimed; + uint32_t numElimed; + + //Heule-process + template<class T> + void xorTwoClauses(const T& c1, const T& c2, vec<Lit>& xored); + bool localSubstitute(); + uint32_t localSubstituteUseful; + + uint32_t clauses_subsumed; + uint32_t clauses_cut; + uint32_t origNClauses; + uint32_t clauseID; +}; + +inline bool XorSubsumer::subsetAbst(uint32_t A, uint32_t B) +{ + return !(A & ~B); +} + +// Assumes 'seen' is cleared (will leave it cleared) +template<class T1, class T2> +bool XorSubsumer::subset(const T1& A, const T2& B) +{ + for (uint32_t i = 0; i != B.size(); i++) + seen_tmp[B[i].var()] = 1; + for (uint32_t i = 0; i != A.size(); i++) { + if (!seen_tmp[A[i].var()]) { + for (uint32_t i = 0; i != B.size(); i++) + seen_tmp[B[i].var()] = 0; + return false; + } + } + for (uint32_t i = 0; i != B.size(); i++) + seen_tmp[B[i].var()] = 0; + return true; +} + +inline void XorSubsumer::newVar() +{ + occur .push(); + seen_tmp .push(0); + cannot_eliminate.push(0); + var_elimed.push(0); +} + +inline const vec<char>& XorSubsumer::getVarElimed() const +{ + return var_elimed; +} + +inline uint32_t XorSubsumer::getNumElimed() const +{ + return numElimed; +} + +inline double XorSubsumer::getTotalTime() const +{ + return totalTime; +} + +inline const map<Var, vector<XorSubsumer::XorElimedClause> >& XorSubsumer::getElimedOutVar() const +{ + return elimedOutVar; +} + +} + +#endif //XORSIMPLIFIER_H diff --git a/src/prop/cryptominisat/Solver/constants.h b/src/prop/cryptominisat/Solver/constants.h new file mode 100644 index 000000000..e8f63bde2 --- /dev/null +++ b/src/prop/cryptominisat/Solver/constants.h @@ -0,0 +1,137 @@ +/****************************************************************************************[Solver.h] +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +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. +**************************************************************************************************/ + +#define release_assert(a) \ + do { \ + if (!(a)) {\ + fprintf(stderr, "*** ASSERTION FAILURE in %s() [%s:%d]: %s\n", \ + __FUNCTION__, __FILE__, __LINE__, #a); \ + abort(); \ + } \ + } while (0) + +/////////////////// +// Settings (magic constants) +/////////////////// + +//#define DUMP_STATS_FULL +//#define DUMP_STATS + +//#define DEBUG_UNCHECKEDENQUEUE_LEVEL0 + +#ifdef DUMP_STATS_FULL +#define DUMP_STATS +#endif //DUMP_STATS_FULL + +//Parameters for learnt-clause cleaning +#define RATIOREMOVECLAUSES 1.0/2.0 +#define NBCLAUSESBEFOREREDUCE 20000 + +#define FIXCLEANREPLACE 30U +#define PERCENTAGEPERFORMREPLACE 0.003 +#define PERCENTAGECLEANCLAUSES 0.01 + +//Parameters for xor-finding (binary and non-binary) +#define MAX_CLAUSENUM_XORFIND 1500000 +#define BINARY_TO_XOR_APPROX 6.0 + +#define UPDATE_TRANSOTFSSR_CACHE 200000 + +//Parameters controlling simplification rounds +#define SIMPLIFY_MULTIPLIER 300 +#define SIMPLIFY_MULTIPLIER_MULTIPLIER 1.5 +#define MAX_CONFL_BETWEEN_SIMPLIFY 500000 +#define BURST_SEARCH +#define NUM_CONFL_BURST_SEARCH 500 + +//Parameters controlling full restarts +#define FULLRESTART_MULTIPLIER 250 +#define FULLRESTART_MULTIPLIER_MULTIPLIER 3.5 +#define RESTART_TYPE_DECIDER_FROM 2 +#define RESTART_TYPE_DECIDER_UNTIL 7 + +//Gaussian elimination parameters +#define MIN_GAUSS_XOR_CLAUSES 5 +#define MAX_GAUSS_XOR_CLAUSES 30000 + +//Parameters regarding glues +#define DEFAULT_MAX_GLUE 24 +#define MAX_GLUE_BITS 7 +#define MAX_THEORETICAL_GLUE ((uint32_t)((1 << MAX_GLUE_BITS)-1)) +#define MIN_GLUE_RESTART 100 + +#ifndef DUMP_STATS_FULL +#define DYNAMICALLY_UPDATE_GLUE +#endif //DUMP_STATS_FULL + +//#define ENABLE_UNWIND_GLUE + +//Parameters for syncing between threads +#define SYNC_EVERY_CONFL 6000 + +/////////////////// +// Verbose Debug +/////////////////// + +//#define VERBOSE_DEBUG_XOR +//#define VERBOSE_DEBUG +#ifdef VERBOSE_DEBUG +#define SILENT_DEBUG +#define DEBUG_USELESS_LEARNT_BIN_REMOVAL +#define DEBUG_ATTACH_FULL +#endif + + +/////////////////// +// Silent Debug +/////////////////// + +#ifndef NDEBUG +#define SILENT_DEBUG +#endif + +#ifdef SILENT_DEBUG +#define DEBUG_VARELIM +#define DEBUG_PROPAGATEFROM +#define DEBUG_WATCHED +#define DEBUG_ATTACH +#define DEBUG_REPLACER +//#define DEBUG_USELESS_LEARNT_BIN_REMOVAL +#endif + +//#define MORE_DEBUG + +#ifdef MORE_DEBUG +#define DEBUG_ATTACH_FULL +#define DEBUG_FAILEDLIT +#define DEBUG_HYPERBIN +#endif + +/////////////////// +// For Automake tools +/////////////////// + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif //HAVE_CONFIG_H + +#ifdef _MSC_VER +#define __builtin_prefetch +#endif //_MSC_VER diff --git a/src/prop/cryptominisat/Solver/msvc/stdint.h b/src/prop/cryptominisat/Solver/msvc/stdint.h new file mode 100644 index 000000000..c8399d3de --- /dev/null +++ b/src/prop/cryptominisat/Solver/msvc/stdint.h @@ -0,0 +1,246 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include <limits.h> + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include <wchar.h> +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h> +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_STDINT_H_ ] diff --git a/src/prop/cryptominisat/Solver/time_mem.h b/src/prop/cryptominisat/Solver/time_mem.h new file mode 100644 index 000000000..c615eb33a --- /dev/null +++ b/src/prop/cryptominisat/Solver/time_mem.h @@ -0,0 +1,102 @@ +/****************************************************************************************[Solver.h] +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +CryptoMiniSat -- Copyright (c) 2009 Mate Soos + +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. +**************************************************************************************************/ + +#ifndef TIME_MEM_H +#define TIME_MEM_H + +#ifdef _MSC_VER +#include <msvc/stdint.h> +#else +#include <stdint.h> +#endif //_MSC_VER + +#if defined (_MSC_VER) || defined(CROSS_COMPILE) +#include <ctime> + +static inline double cpuTime(void) +{ + return (double)clock() / CLOCKS_PER_SEC; +} +#else //_MSC_VER +#include <sys/time.h> +#include <sys/resource.h> +#include <unistd.h> + +static inline double cpuTime(void) +{ + struct rusage ru; + #ifdef RUSAGE_THREAD + getrusage(RUSAGE_THREAD, &ru); + #else + getrusage(RUSAGE_SELF, &ru); + #endif + return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000.0; +} + +static inline double cpuTimeTotal(void) +{ + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000.0; +} +#endif //CROSS_COMPILE + + +#if defined(__linux__) +#include <stdio.h> +static inline int memReadStat(int field) +{ + char name[256]; + pid_t pid = getpid(); + sprintf(name, "/proc/%d/statm", pid); + FILE* in = fopen(name, "rb"); + if (in == NULL) return 0; + int value; + + int rvalue= 1; + for (; (field >= 0) && (rvalue == 1); field--) + rvalue = fscanf(in, "%d", &value); + + fclose(in); + return value; +} +static inline uint64_t memUsed() +{ + return (uint64_t)memReadStat(0) * (uint64_t)getpagesize(); +} + + +#elif defined(__FreeBSD__) +static inline uint64_t memUsed(void) +{ + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + return ru.ru_maxrss*1024; +} + + +#else +static inline uint64_t memUsed() +{ + return 0; +} +#endif + +#endif //TIME_MEM_H |