From: Francis Russell Date: Tue, 19 Apr 2011 02:09:37 +0000 (+0100) Subject: Integrate CryptoMiniSat 2.9.0. X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=add1bd421f45f3fbb2d2f3189227f5b2ad2c43a1;p=francis%2Fstp.git Integrate CryptoMiniSat 2.9.0. --- diff --git a/scripts/Makefile.common b/scripts/Makefile.common index f5b0930..d5b47af 100644 --- a/scripts/Makefile.common +++ b/scripts/Makefile.common @@ -47,7 +47,7 @@ ifdef STATIC endif -LDFLAGS = $(LDFLAGS_BASE) +LDFLAGS = $(LDFLAGS_BASE) -lz -fopenmp CFLAGS = $(CFLAGS_BASE) $(CFLAGS_M32) diff --git a/src/sat/CryptoMinisat.cpp b/src/sat/CryptoMinisat.cpp index 14be064..c89339e 100644 --- a/src/sat/CryptoMinisat.cpp +++ b/src/sat/CryptoMinisat.cpp @@ -15,7 +15,7 @@ namespace BEEV CryptoMinisat::CryptoMinisat() { - s = new MINISAT::Solver(); + s = new Solver(); } CryptoMinisat::~CryptoMinisat() @@ -30,9 +30,9 @@ namespace BEEV // Cryptominisat uses a slightly different Lit class too. // VERY SLOW> - MINISAT::vec v; + vec v; for (int i =0; iaddClause(v); } @@ -63,7 +63,7 @@ namespace BEEV int CryptoMinisat::setVerbosity(int v) { - s->verbosity = v; + s->conf.verbosity = v; } int CryptoMinisat::nVars() diff --git a/src/sat/CryptoMinisat.h b/src/sat/CryptoMinisat.h index c7832e0..33c8ab6 100644 --- a/src/sat/CryptoMinisat.h +++ b/src/sat/CryptoMinisat.h @@ -6,16 +6,13 @@ #include "SATSolver.h" -namespace MINISAT -{ - class Solver; -} +class Solver; namespace BEEV { class CryptoMinisat : public SATSolver { - MINISAT::Solver* s; + Solver* s; public: CryptoMinisat(); diff --git a/src/sat/cryptominisat2/BitArray.h b/src/sat/cryptominisat2/BitArray.h index aa58b62..c9e0b37 100644 --- a/src/sat/cryptominisat2/BitArray.h +++ b/src/sat/cryptominisat2/BitArray.h @@ -28,10 +28,6 @@ along with this program. If not, see . #include #endif //_MSC_VER -namespace MINISAT -{ -using namespace MINISAT; - class BitArray { public: @@ -40,14 +36,14 @@ public: , 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) { @@ -56,10 +52,10 @@ public: mp = new uint64_t[size]; } memcpy(mp, b.mp, sizeof(uint64_t)*size); - + return *this; } - + BitArray& operator&=(const BitArray& b) { assert(size == b.size); @@ -70,22 +66,8 @@ public: t1++; t2++; } - - return *this; - } - const bool nothingInCommon(const BitArray& b) const - { - assert(size == b.size); - const uint64_t* t1 = mp; - const uint64_t* t2 = b.mp; - for (uint64_t i = 0; i < size; i++) { - if ((*t1)&(*t2)) return false; - t1++; - t2++; - } - - return true; + return *this; } BitArray& removeThese(const BitArray& b) @@ -111,8 +93,8 @@ public: return *this; } - - void resize(uint _size, const bool fill) + + void resize(uint32_t _size, const bool fill) { _size = _size/64 + (bool)(_size%64); if (size != _size) { @@ -123,7 +105,7 @@ public: if (fill) setOne(); else setZero(); } - + ~BitArray() { delete[] mp; @@ -132,8 +114,8 @@ public: inline const bool isZero() const { const uint64_t* mp2 = (const uint64_t*)mp; - - for (uint i = 0; i < size; i++) { + + for (uint32_t i = 0; i < size; i++) { if (mp2[i]) return false; } return true; @@ -143,51 +125,49 @@ public: { memset(mp, 0, size*sizeof(uint64_t)); } - + inline void setOne() { - memset(mp, 0, size*sizeof(uint64_t)); + memset(mp, 0xff, size*sizeof(uint64_t)); } - inline void clearBit(const uint i) + 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 uint i) + inline void setBit(const uint32_t i) { #ifdef DEBUG_BITARRAY assert(size*64 > i); #endif - + mp[i/64] |= ((uint64_t)1 << (i%64)); } - inline const bool operator[](const uint& i) const + inline const bool operator[](const uint32_t& i) const { #ifdef DEBUG_BITARRAY assert(size*64 > i); #endif - + return (mp[i/64] >> (i%64)) & 1; } - - inline const uint getSize() const + + inline const uint32_t getSize() const { return size*64; } private: - - uint size; + + uint32_t size; uint64_t* mp; }; -}; //NAMESPACE MINISAT - #endif //BITARRAY_H diff --git a/src/sat/cryptominisat2/BoundedQueue.h b/src/sat/cryptominisat2/BoundedQueue.h index a705a6d..83ccf00 100644 --- a/src/sat/cryptominisat2/BoundedQueue.h +++ b/src/sat/cryptominisat2/BoundedQueue.h @@ -1,25 +1,14 @@ /*****************************************************************************************[Queue.h] MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson - 2008 - Gilles Audemard, Laurent Simon - -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. +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 +#ifndef BOUNDEDQUEUE_H +#define BOUNDEDQUEUE_H #ifdef _MSC_VER #include @@ -29,60 +18,75 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include "Vec.h" -//================================================================================================= - -namespace MINISAT -{ -using namespace MINISAT; - template class bqueue { vec elems; - int first; - int last; - uint64_t sumofqueue; - int maxsize; - int queuesize; // Number of current elements (must be < maxsize !) - + 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), maxsize(0), queuesize(0) { } - - void initSize(int size) {growTo(size);} // Init size of bounded size queue - - void push(T x) { + 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 + } else queuesize++; sumofqueue += x; + sumOfAllElems += x; + totalNumElems++; elems[first] = x; if ((++first) == maxsize) first = 0; } - T peek() { assert(queuesize>0); return elems[last]; } + const T peek() const { assert(queuesize>0); return elems[last]; } void pop() {sumofqueue-=elems[last]; queuesize--; if ((++last) == maxsize) last = 0;} - - uint64_t getsum() const {return sumofqueue;} - uint32_t getavg() const {return (uint64_t)sumofqueue/(uint64_t)queuesize;} + + 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(int size) { - elems.growTo(size); + + void growTo(const uint32_t size) { + elems.growTo(size); first=0; maxsize=size; queuesize = 0; - for(int i=0;i #endif //_MSC_VER -namespace MINISAT -{ -using namespace MINISAT; - class Clause; -//#pragma pack(push) -//#pragma pack(1) + +/** +@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: @@ -28,28 +31,36 @@ class ClauseSimp clause(c) , index(_index) {} - - Clause* clause; - uint32_t index; + + Clause* clause; /// where; // Map clause ID to position in 'which'. - vec which; // List of clauses (for fast iteration). May contain 'Clause_NULL'. - vec free; // List of positions holding 'Clause_NULL'. - + vec where; /// which; ///< List of clauses (for fast iteration). May contain 'Clause_NULL'. + vec free; ///::max()); if (where[c.index] != std::numeric_limits::max()) { - return true; + return false; } if (free.size() > 0){ where[c.index] = free.last(); @@ -59,9 +70,22 @@ class CSet { where[c.index] = which.size(); which.push(c); } + return true; + } + + const 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::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::max()) { @@ -73,7 +97,10 @@ class CSet { where[c.index] = std::numeric_limits::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) { @@ -83,47 +110,97 @@ class CSet { 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++; } - + const 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++; + } + + const 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 -}; //NAMESPACE MINISAT - diff --git a/src/sat/cryptominisat2/Clause.h b/src/sat/cryptominisat2/Clause.h index 42d55d7..eb99785 100644 --- a/src/sat/cryptominisat2/Clause.h +++ b/src/sat/cryptominisat2/Clause.h @@ -1,22 +1,11 @@ -/***********************************************************************************[SolverTypes.h] +/***************************************************************************** MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +glucose -- Gilles Audemard, Laurent Simon (2008) 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. -**************************************************************************************************/ +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 @@ -30,54 +19,77 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include #include #include -#include "Vec.h" +#include + #include "SolverTypes.h" -#include "PackedRow.h" #include "constants.h" -#include "ClauseAllocator.h" +#include "Watched.h" +#include "Alg.h" +#include "constants.h" template uint32_t calcAbstraction(const T& ps) { uint32_t abstraction = 0; for (uint32_t i = 0; i != ps.size(); i++) - abstraction |= 1 << (ps[i].toInt() & 31); + abstraction |= 1 << (ps[i].var() & 31); return abstraction; } -namespace MINISAT -{ -using namespace MINISAT; - //================================================================================================= // Clause -- a simple class for representing a clause: class MatrixFinder; +class ClauseAllocator; + +/** +@brief Holds a clause. Does not allocate space for literals -class Clause +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; /// - Clause(const V& ps, const uint _group, const bool learnt) + Clause(const V& ps, const uint32_t _group, const bool learnt) { - wasBinInternal = (ps.size() == 2); isFreed = false; isXorClause = false; - strenghtened = false; - sorted = false; - varChanged = true; - subsume0Done = false; + assert(ps.size() > 2); mySize = ps.size(); isLearnt = learnt; isRemoved = false; setGroup(_group); memcpy(data, ps.getData(), ps.size()*sizeof(Lit)); - if (learnt) { - extra.act = 0; - oldActivityInter = 0; - } else - calcAbstractionClause(); + miniSatAct = 0; + setStrenghtened(); } public: friend class ClauseAllocator; - const uint size () const { + const uint32_t size() const + { return mySize; } - void resize (const uint size) { - mySize = size; - } - void shrink (const uint i) { + + void shrink (const uint32_t i) + { assert(i <= size()); mySize -= i; + if (i > 0) setStrenghtened(); } - void pop () { + + void pop() + { shrink(1); } - const bool isXor () { + + const bool isXor() + { return isXorClause; } - const bool learnt () const { + + const bool learnt() const + { return isLearnt; } - float& oldActivity () { - return oldActivityInter; + + float& getMiniSatAct() + { + return miniSatAct; } - - const float& oldActivity () const { - return oldActivityInter; + + void setMiniSatAct(const float newMiniSatAct) + { + miniSatAct = newMiniSatAct; + } + + const float& getMiniSatAct() const + { + return miniSatAct; } - - const bool getStrenghtened() const { + + const bool getStrenghtened() const + { return strenghtened; } - void setStrenghtened() { + + void setStrenghtened() + { strenghtened = true; - sorted = false; - subsume0Done = false; + calcAbstractionClause(); } - void unsetStrenghtened() { + + void unsetStrenghtened() + { strenghtened = false; } - const bool getVarChanged() const { - return varChanged; - } - void setVarChanged() { - varChanged = true; - sorted = false; - subsume0Done = false; - } - void unsetVarChanged() { - varChanged = false; - } - const bool getSorted() const { - return sorted; - } - void setSorted() { - sorted = true; - } - void setUnsorted() { - sorted = false; - } - void subsume0Finished() { - subsume0Done = 1; - } - const bool subsume0IsFinished() { - return subsume0Done; - } - Lit& operator [] (uint32_t i) { + Lit& operator [] (uint32_t i) + { return data[i]; } - const Lit& operator [] (uint32_t i) const { + + const Lit& operator [] (uint32_t i) const + { return data[i]; } - void setActivity(uint32_t i) { - extra.act = i; + void setGlue(const uint32_t newGlue) + { + assert(newGlue <= MAX_THEORETICAL_GLUE); + glue = newGlue; } - - const uint32_t& activity () const { - return extra.act; + + const uint32_t getGlue() const + { + return glue; } - - void makeNonLearnt() { + + void makeNonLearnt() + { assert(isLearnt); isLearnt = false; - calcAbstractionClause(); } - - void makeLearnt(const uint32_t newActivity) { - extra.act = newActivity; - oldActivityInter = 0; + + void makeLearnt(const uint32_t newGlue, const float newMiniSatAct) + { + glue = newGlue; + miniSatAct = newMiniSatAct; isLearnt = true; } - - inline void strengthen(const Lit p) + + inline void strengthen(const Lit p) { remove(*this, p); - sorted = false; - calcAbstractionClause(); + setStrenghtened(); } - - void calcAbstractionClause() { - assert(!learnt()); - extra.abst = calcAbstraction(*this);; + + void calcAbstractionClause() + { + abst = calcAbstraction(*this); } - + uint32_t getAbst() { - if (learnt()) - return calcAbstraction(*this); - else - return extra.abst; + return abst; } - const Lit* getData () const { + const Lit* getData() const + { return data; } - Lit* getData () { + + Lit* getData() + { return data; } - const Lit* getDataEnd () const { + + const Lit* getDataEnd() const + { return data+size(); } - Lit* getDataEnd () { + + Lit* getDataEnd() + { return data+size(); } - void print(FILE* to = stdout) { + + void print(FILE* to = stdout) const + { plainPrint(to); - fprintf(to, "c clause learnt %s group %d act %d oldAct %f\n", (learnt() ? "yes" : "no"), getGroup(), activity(), oldActivity()); + fprintf(to, "c clause learnt %s glue %d miniSatAct %.3f group %d\n", (learnt() ? "yes" : "no"), getGlue(), getMiniSatAct(), getGroup()); } - void plainPrint(FILE* to = stdout) const { - for (uint i = 0; i < size(); i++) { + + void plainPrint(FILE* to = stdout) const + { + for (uint32_t i = 0; i < size(); i++) { if (data[i].sign()) fprintf(to, "-"); fprintf(to, "%d ", data[i].var() + 1); } fprintf(to, "0\n"); } + #ifdef STATS_NEEDED const uint32_t getGroup() const { @@ -255,7 +268,7 @@ public: group = _group; } #else - const uint getGroup() const + const uint32_t getGroup() const { return 0; } @@ -264,92 +277,104 @@ public: return; } #endif //STATS_NEEDED - void setRemoved() { + void setRemoved() + { isRemoved = true; } - const bool removed() const { + const bool getRemoved() const + { return isRemoved; } - void setFreed() { + void setFreed() + { isFreed = true; } - const bool freed() const { + const bool getFreed() const + { return isFreed; } - const bool wasBin() const { - return wasBinInternal; - } - - void setWasBin(const bool toSet) { - wasBinInternal = toSet; + 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 - XorClause(const V& ps, const bool inverted, const uint _group) : + XorClause(const V& ps, const bool xorEqualFalse, const uint32_t _group) : Clause(ps, _group, false) { - invertedXor = inverted; + isXorEqualFalse = xorEqualFalse; isXorClause = true; - calcXorAbstraction(); } public: friend class ClauseAllocator; - inline bool xor_clause_inverted() const + inline const bool xorEqualFalse() const { - return invertedXor; + return isXorEqualFalse; } - inline void invert(bool b) + + inline void invert(const bool b) { - invertedXor ^= b; - } - void calcXorAbstraction() { - extra.abst = 0; - for (uint32_t i = 0; i != size(); i++) - extra.abst |= 1 << (data[i].var() & 31); + isXorEqualFalse ^= b; } - void print() { - printf("XOR Clause group: %d, size: %d, learnt:%d, lits:\"", getGroup(), size(), learnt()); - plainPrint(); + void print(FILE* to = stdout) const + { + plainPrint(to); + fprintf(to, "c clause learnt %s glue %d miniSatAct %.3f group %d\n", (learnt() ? "yes" : "no"), getGlue(), getMiniSatAct(), getGroup()); } - - void plainPrint(FILE* to = stdout) const { + + void plainPrint(FILE* to = stdout) const + { fprintf(to, "x"); - if (xor_clause_inverted()) - printf("-"); - for (uint i = 0; i < size(); i++) { + if (xorEqualFalse()) + fprintf(to, "-"); + for (uint32_t i = 0; i < size(); i++) { fprintf(to, "%d ", data[i].var() + 1); } fprintf(to, "0\n"); } - + friend class MatrixFinder; }; -class WatchedBin { - public: - WatchedBin(Lit _impliedLit) : impliedLit(_impliedLit) {}; - Lit impliedLit; -}; +inline std::ostream& operator<<(std::ostream& cout, const Clause& cl) +{ + for (uint32_t i = 0; i < cl.size(); i++) { + cout << cl[i] << " "; + } + return cout; +} -class Watched { - public: - Watched(ClauseOffset _clause, Lit _blockedLit) : clause(_clause), blockedLit(_blockedLit) {}; - ClauseOffset clause; - Lit blockedLit; -}; +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; +} -}; //NAMESPACE MINISAT #endif //CLAUSE_H diff --git a/src/sat/cryptominisat2/ClauseAllocator.cpp b/src/sat/cryptominisat2/ClauseAllocator.cpp index 99bfaed..b1d58d8 100644 --- a/src/sat/cryptominisat2/ClauseAllocator.cpp +++ b/src/sat/cryptominisat2/ClauseAllocator.cpp @@ -28,42 +28,64 @@ along with this program. If not, see . #include "XorSubsumer.h" //#include "VarReplacer.h" #include "PartHandler.h" +#include "Gaussian.h" -namespace MINISAT -{ -using namespace MINISAT; - +//For mild debug info: //#define DEBUG_CLAUSEALLOCATOR -ClauseAllocator::ClauseAllocator() : - clausePoolBin(sizeof(Clause) + 2*sizeof(Lit)) -{} +//For listing each and every clause location: +//#define DEBUG_CLAUSEALLOCATOR2 + +#define MIN_LIST_SIZE (300000 * (sizeof(Clause) + 4*sizeof(Lit))/sizeof(uint32_t)) +//#define MIN_LIST_SIZE (100 * (sizeof(Clause) + 4*sizeof(Lit))/sizeof(uint32_t)) +#define ALLOC_GROW_MULT 4 +//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) + +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]); + delete [] dataStarts[i]; } } +/** +@brief Allocates space&initializes a clause +*/ template Clause* ClauseAllocator::Clause_new(const T& ps, const unsigned int group, const bool learnt) { + assert(ps.size() > 2); void* mem = allocEnough(ps.size()); Clause* real= new (mem) Clause(ps, group, learnt); //assert(!(ps.size() == 2 && !real->wasBin())); return real; } + template Clause* ClauseAllocator::Clause_new(const vec& ps, const unsigned int group, const bool learnt); template Clause* ClauseAllocator::Clause_new(const Clause& ps, const unsigned int group, const bool learnt); template Clause* ClauseAllocator::Clause_new(const XorClause& ps, const unsigned int group, const bool learnt); +/** +@brief Allocates space&initializes an xor clause +*/ template -XorClause* ClauseAllocator::XorClause_new(const T& ps, const bool inverted, const unsigned int group) +XorClause* ClauseAllocator::XorClause_new(const T& ps, const bool xorEqualFalse, const unsigned int group) { + assert(ps.size() > 0); void* mem = allocEnough(ps.size()); - XorClause* real= new (mem) XorClause(ps, inverted, group); + XorClause* real= new (mem) XorClause(ps, xorEqualFalse, group); //assert(!(ps.size() == 2 && !real->wasBin())); return real; @@ -71,19 +93,25 @@ XorClause* ClauseAllocator::XorClause_new(const T& ps, const bool inverted, cons template XorClause* ClauseAllocator::XorClause_new(const vec& ps, const bool inverted, const unsigned int group); template XorClause* ClauseAllocator::XorClause_new(const XorClause& ps, const bool inverted, const unsigned int group); +/** +@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()); Clause& c2 = *(Clause*)mem; - c2.setWasBin(c.size() == 2); - //assert(!(c.size() == 2 && !c2.wasBin())); - + return &c2; } -#define MIN_LIST_SIZE (300000 * (sizeof(Clause) + 4*sizeof(Lit))) +/** +@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) { assert(sizes.size() == dataStarts.size()); @@ -93,11 +121,13 @@ void* ClauseAllocator::allocEnough(const uint32_t size) assert(sizeof(Clause)%sizeof(uint32_t) == 0); assert(sizeof(Lit)%sizeof(uint32_t) == 0); - if (size == 2) { - return clausePoolBin.malloc(); + if (dataStarts.size() == (1< 2); + + uint32_t needed = (sizeof(Clause)+sizeof(Lit)*size)/sizeof(uint32_t); bool found = false; uint32_t which = std::numeric_limits::max(); for (uint32_t i = 0; i < sizes.size(); i++) { @@ -109,27 +139,32 @@ void* ClauseAllocator::allocEnough(const uint32_t size) } if (!found) { - #ifdef DEBUG_CLAUSEALLOCATOR - std::cout << "c New list in ClauseAllocator" << std::endl; - #endif //DEBUG_CLAUSEALLOCATOR - uint32_t nextSize; //number of BYTES to allocate - if (maxSizes.size() != 0) - nextSize = maxSizes[maxSizes.size()-1]*3*sizeof(uint32_t); - else - nextSize = MIN_LIST_SIZE; + 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); - - uint32_t *dataStart = (uint32_t*)malloc(nextSize); + assert(nextSize <= MAXSIZE); + + #ifdef DEBUG_CLAUSEALLOCATOR + std::cout << "c New list in ClauseAllocator. Size: " << nextSize + << " (maxSize: " << MAXSIZE + << ")" << std::endl; + #endif //DEBUG_CLAUSEALLOCATOR + + uint32_t *dataStart = new uint32_t[nextSize]; assert(dataStart != NULL); dataStarts.push(dataStart); sizes.push(0); - maxSizes.push(nextSize/sizeof(uint32_t)); + maxSizes.push(nextSize); origClauseSizes.push(); - currentlyUsedSize.push(0); + currentlyUsedSizes.push(0); which = dataStarts.size()-1; } - #ifdef DEBUG_CLAUSEALLOCATOR + #ifdef DEBUG_CLAUSEALLOCATOR2 std::cout << "selected list = " << which << " size = " << sizes[which] @@ -139,13 +174,19 @@ void* ClauseAllocator::allocEnough(const uint32_t size) assert(which != std::numeric_limits::max()); Clause* pointer = (Clause*)(dataStarts[which] + sizes[which]); - sizes[which] += needed/sizeof(uint32_t); - currentlyUsedSize[which] += needed/sizeof(uint32_t); - origClauseSizes[which].push(needed/sizeof(uint32_t)); + 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 +*/ const ClauseOffset ClauseAllocator::getOffset(const Clause* ptr) const { uint32_t outerOffset = getOuterOffset(ptr); @@ -153,56 +194,80 @@ const ClauseOffset ClauseAllocator::getOffset(const Clause* ptr) const return combineOuterInterOffsets(outerOffset, interOffset); } +/** +@brief Combines the stack number and the internal offset into one 32-bit number +*/ inline const ClauseOffset ClauseAllocator::combineOuterInterOffsets(const uint32_t outerOffset, const uint32_t interOffset) const { - return (outerOffset | (interOffset<<4)); + 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::max(); for (uint32_t i = 0; i < sizes.size(); i++) { - if ((uint32_t*)ptr >= dataStarts[i] && (uint32_t*)ptr < dataStarts[i] + maxSizes[i]) + if ((uint32_t*)ptr >= dataStarts[i] && (uint32_t*)ptr < dataStarts[i] + maxSizes[i]) { which = i; + break; + } } assert(which != std::numeric_limits::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 ((uint32_t*)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) { - if (c->wasBin()) { - clausePoolBin.free(c); - } else { - c->setFreed(); - uint32_t outerOffset = getOuterOffset(c); - //uint32_t interOffset = getInterOffset(c, outerOffset); - currentlyUsedSize[outerOffset] -= (sizeof(Clause) + c->size()*sizeof(Lit))/sizeof(uint32_t); - //above should be - //origClauseSizes[outerOffset][interOffset] - //but it cannot be :( - } + assert(!c->getFreed()); + c->setFreed(); + uint32_t outerOffset = getOuterOffset(c); + //uint32_t interOffset = getInterOffset(c, outerOffset); + currentlyUsedSizes[outerOffset] -= (sizeof(Clause) + c->size()*sizeof(Lit))/sizeof(uint32_t); + //above should be + //origClauseSizes[outerOffset][interOffset] + //but it cannot be :( } -struct NewPointerAndOffset { - Clause* newPointer; - uint32_t newOffset; -}; +/** +@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) { double myTime = cpuTime(); - + //if (dataStarts.size() > 2) { uint32_t sum = 0; for (uint32_t i = 0; i < sizes.size(); i++) { - sum += currentlyUsedSize[i]; + sum += currentlyUsedSizes[i]; } uint32_t sumAlloc = 0; for (uint32_t i = 0; i < sizes.size(); i++) { @@ -212,166 +277,232 @@ void ClauseAllocator::consolidate(Solver* solver) #ifdef DEBUG_CLAUSEALLOCATOR std::cout << "c ratio:" << (double)sum/(double)sumAlloc << std::endl; #endif //DEBUG_CLAUSEALLOCATOR - - if ((double)sum/(double)sumAlloc > 0.7 /*&& sum > 10000000*/) { - if (solver->verbosity >= 2) { + + //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 ((double)sum/(double)sumAlloc > 0.7 && sizes.size() < 10) { + if (solver->conf.verbosity >= 3) { std::cout << "c Not consolidating memory." << std::endl; } return; } - - uint32_t newMaxSize = std::max(sum*2*sizeof(uint32_t), MIN_LIST_SIZE); - uint32_t* newDataStarts = (uint32_t*)malloc(newMaxSize); - newMaxSize /= sizeof(uint32_t); - uint32_t newSize = 0; - vec newOrigClauseSizes; - //} - - map oldToNewPointer; - map oldToNewOffset; - - uint32_t* newDataStartsPointer = newDataStarts; - 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->freed()) { - uint32_t sizeNeeded = sizeof(Clause) + oldPointer->size()*sizeof(Lit); - memcpy(newDataStartsPointer, dataStarts[i] + currentLoc, sizeNeeded); - - oldToNewPointer[oldPointer] = (Clause*)newDataStartsPointer; - oldToNewOffset[combineOuterInterOffsets(i, currentLoc)] = combineOuterInterOffsets(0, newSize); - - newSize += sizeNeeded/sizeof(uint32_t); - newOrigClauseSizes.push(sizeNeeded/sizeof(uint32_t)); - newDataStartsPointer += sizeNeeded/sizeof(uint32_t); - } - - currentLoc += origClauseSizes[i][i2]; + #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 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 } - assert(newSize < newMaxSize); - assert(newSize <= newMaxSize/2); - - updateOffsets(solver->watches, oldToNewOffset); - updateOffsetsXor(solver->xorwatches, oldToNewOffset); - - updatePointers(solver->clauses, oldToNewPointer); - updatePointers(solver->learnts, oldToNewPointer); - updatePointers(solver->binaryClauses, oldToNewPointer); - updatePointers(solver->xorclauses, oldToNewPointer); + #ifdef DEBUG_CLAUSEALLOCATOR + std::cout << "c ------------------" << std::endl; + #endif //DEBUG_CLAUSEALLOCATOR - //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); - updatePointers(solver->partHandler->clausesRemoved, oldToNewPointer); - updatePointers(solver->partHandler->xorClausesRemoved, oldToNewPointer); - for(map >::iterator it = solver->subsumer->elimedOutVar.begin(); it != solver->subsumer->elimedOutVar.end(); it++) { - updatePointers(it->second, oldToNewPointer); + if (newMaxSizeNeed > 0) { + std::cerr << "We cannot handle the memory need load. Exiting." << std::endl; + exit(-1); } - for(map >::iterator it = solver->xorSubsumer->elimedOutVar.begin(); it != solver->xorSubsumer->elimedOutVar.end(); it++) { - updatePointers(it->second, oldToNewPointer); + + vec newSizes; + vec > newOrigClauseSizes; + vec newDataStartsPointers; + vec newDataStarts; + for (uint32_t i = 0; i < newMaxSizes.size(); i++) { + newSizes.push(0); + newOrigClauseSizes.push(); + uint32_t* pointer; + pointer = new uint32_t[newMaxSizes[i]]; + newDataStartsPointers.push(pointer); + newDataStarts.push(pointer); } - - - vec& reason = solver->reason; - for (PropagatedFrom *it = reason.getData(), *end = reason.getDataEnd(); it != end; it++) { - if (!it->isBinary() && !it->isNULL()) { - /*if ((it == reason.getData() + (*it->getClause())[0].var()) - && (solver->value((*it->getClause())[0]) == l_True)) { - assert(oldToNewPointer.find(it->getClause()) != oldToNewPointer.end()); - *it = PropagatedFrom(oldToNewPointer[it->getClause()]); + + uint32_t outerPart = 0; + 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()) { + uint32_t sizeNeeded = (sizeof(Clause) + oldPointer->size()*sizeof(Lit))/sizeof(uint32_t); + + //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(uint32_t))); + + if (newSizes[outerPart] + sizeNeeded > newMaxSizes[outerPart]) { + outerPart++; + assert(outerPart < newMaxSizes.size()); + } + memcpy(newDataStartsPointers[outerPart], dataStarts[i] + currentLoc, sizeNeeded*sizeof(uint32_t)); + + (*((NewPointerAndOffset*)(dataStarts[i] + currentLoc))).newOffset = combineOuterInterOffsets(outerPart, newSizes[outerPart]); + (*((NewPointerAndOffset*)(dataStarts[i] + currentLoc))).newPointer = (Clause*)newDataStartsPointers[outerPart]; + + newSizes[outerPart] += sizeNeeded; + newOrigClauseSizes[outerPart].push(sizeNeeded); + newDataStartsPointers[outerPart] += sizeNeeded; } else { - *it = PropagatedFrom(); - }*/ - if (oldToNewPointer.find(it->getClause()) != oldToNewPointer.end()) { - *it = PropagatedFrom(oldToNewPointer[it->getClause()]); + (*((NewPointerAndOffset*)(dataStarts[i] + currentLoc))).newOffset = std::numeric_limits::max(); } + + currentLoc += origClauseSizes[i][i2]; } } + updateAllOffsetsAndPointers(solver); + for (uint32_t i = 0; i < dataStarts.size(); i++) - free(dataStarts[i]); + delete [] dataStarts[i]; dataStarts.clear(); maxSizes.clear(); sizes.clear(); origClauseSizes.clear(); - - dataStarts.push(newDataStarts); - maxSizes.push(newMaxSize); - sizes.push(newSize); - currentlyUsedSize.clear(); - currentlyUsedSize.push(newSize); + currentlyUsedSizes.clear(); origClauseSizes.clear(); - origClauseSizes.push(); - newOrigClauseSizes.moveTo(origClauseSizes[0]); - if (solver->verbosity >= 1) { + 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; } } -template -void ClauseAllocator::updateOffsets(vec >& watches, const map& oldToNewOffset) +void ClauseAllocator::updateAllOffsetsAndPointers(Solver* solver) { - for (uint32_t i = 0; i < watches.size(); i++) { - vec& list = watches[i]; - for (T *it = list.getData(), *end = list.getDataEnd(); it != end; it++) { - map::const_iterator it2 = oldToNewOffset.find(it->clause); - assert(it2 != oldToNewOffset.end()); - it->clause = it2->second; + updateOffsets(solver->watches); + + updatePointers(solver->clauses); + updatePointers(solver->learnts); + updatePointers(solver->xorclauses); + updatePointers(solver->freeLater); + updatePointers(solver->unWindGlue); + + //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); + updatePointers(solver->partHandler->clausesRemoved); + updatePointers(solver->partHandler->xorClausesRemoved); + + #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& 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::max()); + *it = PropBy(((NewPointerAndOffset*)(getPointer(it->getClause())))->newOffset); } } } -template -void ClauseAllocator::updateOffsetsXor(vec >& watches, const map& oldToNewOffset) +/** +@brief A dumb helper function to update offsets +*/ +void ClauseAllocator::updateOffsets(vec >& watches) { for (uint32_t i = 0; i < watches.size(); i++) { - vec& list = watches[i]; - for (T *it = list.getData(), *end = list.getDataEnd(); it != end; it++) { - map::const_iterator it2 = oldToNewOffset.find(*it); - assert(it2 != oldToNewOffset.end()); - *it = it2->second; + vec& list = watches[i]; + for (Watched *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 -void ClauseAllocator::updatePointers(vec& toUpdate, const map& oldToNewPointer) +void ClauseAllocator::updatePointers(vec& toUpdate) { for (T **it = toUpdate.getData(), **end = toUpdate.getDataEnd(); it != end; it++) { - if (!(*it)->wasBin()) { - //assert(oldToNewPointer.find((TT*)*it) != oldToNewPointer.end()); - map::const_iterator it2 = oldToNewPointer.find((Clause*)*it); - *it = (T*)it2->second; + if (*it != NULL) { + *it = (T*)(((NewPointerAndOffset*)(*it))->newPointer); } } } -void ClauseAllocator::updatePointers(vector& toUpdate, const map& oldToNewPointer) +/** +@brief A dumb helper function to update pointers +*/ +void ClauseAllocator::updatePointers(vector& toUpdate) { for (vector::iterator it = toUpdate.begin(), end = toUpdate.end(); it != end; it++) { - if (!(*it)->wasBin()) { - //assert(oldToNewPointer.find((TT*)*it) != oldToNewPointer.end()); - map::const_iterator it2 = oldToNewPointer.find((Clause*)*it); - *it = it2->second; - } + *it = (((NewPointerAndOffset*)(*it))->newPointer); } } -void ClauseAllocator::updatePointers(vector& toUpdate, const map& oldToNewPointer) +/** +@brief A dumb helper function to update pointers +*/ +void ClauseAllocator::updatePointers(vector& toUpdate) { for (vector::iterator it = toUpdate.begin(), end = toUpdate.end(); it != end; it++) { - if (!(*it)->wasBin()) { - //assert(oldToNewPointer.find((TT*)*it) != oldToNewPointer.end()); - map::const_iterator it2 = oldToNewPointer.find((Clause*)*it); - *it = (XorClause*)it2->second; - } + *it = (XorClause*)(((NewPointerAndOffset*)(*it))->newPointer); } } -}; //NAMESPACE MINISAT +/** +@brief A dumb helper function to update pointers +*/ +void ClauseAllocator::updatePointers(vector >& toUpdate) +{ + for (vector >::iterator it = toUpdate.begin(), end = toUpdate.end(); it != end; it++) { + it->first = (((NewPointerAndOffset*)(it->first))->newPointer); + } +} diff --git a/src/sat/cryptominisat2/ClauseAllocator.h b/src/sat/cryptominisat2/ClauseAllocator.h index 4bf378a..69f8f07 100644 --- a/src/sat/cryptominisat2/ClauseAllocator.h +++ b/src/sat/cryptominisat2/ClauseAllocator.h @@ -24,39 +24,57 @@ along with this program. If not, see . #include #endif //_MSC_VER +#include #include "Vec.h" -#include #include #include using std::map; using std::vector; -namespace MINISAT -{ -using namespace MINISAT; +#include "ClauseOffset.h" +#include "Watched.h" + +#define NUM_BITS_OUTER_OFFSET 4 + class Clause; class XorClause; class Solver; -typedef uint32_t ClauseOffset; +/** +@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 Clause* Clause_new(const T& ps, const uint32_t group, const bool learnt = false); template - XorClause* XorClause_new(const T& ps, const bool inverted, const uint32_t group); + XorClause* XorClause_new(const T& ps, const bool xorEqualFalse, const uint32_t group); Clause* Clause_new(Clause& c); const ClauseOffset getOffset(const Clause* ptr) const; - inline Clause* getPointer(const uint32_t offset) + /** + @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&15]+(offset>>4)); + return (Clause*)(dataStarts[offset&((1 << NUM_BITS_OUTER_OFFSET) - 1)] + +(offset >> NUM_BITS_OUTER_OFFSET)); } void clauseFree(Clause* c); @@ -68,29 +86,48 @@ class ClauseAllocator { uint32_t getInterOffset(const Clause* c, const uint32_t outerOffset) const; const ClauseOffset combineOuterInterOffsets(const uint32_t outerOffset, const uint32_t interOffset) const; + void updateAllOffsetsAndPointers(Solver* solver); template - void updatePointers(vec& toUpdate, const map& oldToNewPointer); - void updatePointers(vector& toUpdate, const map& oldToNewPointer); - void updatePointers(vector& toUpdate, const map& oldToNewPointer); - - template - void updateOffsets(vec >& watches, const map& oldToNewOffset); - template - void updateOffsetsXor(vec >& watches, const map& oldToNewOffset); - - vec dataStarts; - vec sizes; + void updatePointers(vec& toUpdate); + void updatePointers(vector& toUpdate); + void updatePointers(vector& toUpdate); + void updatePointers(vector >& toUpdate); + + void updateOffsets(vec >& watches); + + vec dataStarts; /// sizes; /// > origClauseSizes; - vec maxSizes; - vec currentlyUsedSize; - vec origSizes; - - boost::pool<> clausePoolBin; + vec maxSizes; /// currentlyUsedSizes; void* allocEnough(const uint32_t size); -}; -}; //NAMESPACE MINISAT + /** + @brief The clause's data is replaced by this to aid updating -#endif //CLAUSEALLOCATOR_H + 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; ///. -**************************************************************************************************/ +****************************************************************************/ #include "ClauseCleaner.h" #include "VarReplacer.h" +#include "DataSync.h" #ifdef _MSC_VER #define __builtin_prefetch(a,b,c) @@ -25,94 +26,91 @@ along with this program. If not, see . //#define DEBUG_CLEAN //#define VERBOSE_DEBUG -namespace MINISAT -{ -using namespace MINISAT; - ClauseCleaner::ClauseCleaner(Solver& _solver) : solver(_solver) { - for (uint i = 0; i < 6; i++) { + for (uint32_t i = 0; i < 6; i++) { lastNumUnitarySat[i] = solver.get_unitary_learnts_num(); lastNumUnitaryClean[i] = solver.get_unitary_learnts_num(); } } -void ClauseCleaner::removeSatisfied(vec& cs, ClauseSetType type, const uint limit) +const bool ClauseCleaner::satisfied(const Watched& watched, Lit lit) { - #ifdef DEBUG_CLEAN - assert(solver.decisionLevel() == 0); - #endif - - if (lastNumUnitarySat[type] + limit >= solver.get_unitary_learnts_num()) - return; - - uint32_t i,j; - for (i = j = 0; i < cs.size(); i++) { - if (satisfied(*cs[i])) - solver.removeClause(*cs[i]); - else - cs[j++] = cs[i]; - } - cs.shrink(i - j); - - lastNumUnitarySat[type] = solver.get_unitary_learnts_num(); + assert(watched.isBinary()); + if (solver.value(lit) == l_True) return true; + if (solver.value(watched.getOtherLit()) == l_True) return true; + return false; } -void ClauseCleaner::removeSatisfied(vec& cs, ClauseSetType type, const uint limit) +void ClauseCleaner::removeSatisfiedBins(const uint32_t limit) { #ifdef DEBUG_CLEAN assert(solver.decisionLevel() == 0); #endif - - if (lastNumUnitarySat[type] + limit >= solver.get_unitary_learnts_num()) + + if (lastNumUnitarySat[binaryClauses] + limit >= solver.get_unitary_learnts_num()) return; - - Clause **i,**j, **end; - for (i = j = cs.getData(), end = i + cs.size(); i != end; i++) { - if (i+1 != end) - __builtin_prefetch(*(i+1), 0, 0); - if (satisfied(**i)) - solver.removeClause(**i); - else - *j++ = *i; + + uint32_t numRemovedHalfNonLearnt = 0; + uint32_t numRemovedHalfLearnt = 0; + uint32_t wsLit = 0; + for (vec *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + vec& ws = *it; + + Watched* i = ws.getData(); + Watched* j = i; + for (Watched *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); } - cs.shrink(i - j); - - lastNumUnitarySat[type] = solver.get_unitary_learnts_num(); + + //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& cs, ClauseSetType type, const uint limit) +void ClauseCleaner::cleanClauses(vec& 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;) { + for (s = ss = cs.getData(), end = s + cs.size(); s != end; s++) { if (s+1 != end) __builtin_prefetch(*(s+1), 1, 0); if (cleanClause(*s)) { solver.clauseAllocator.clauseFree(*s); - s++; - } else if (type != ClauseCleaner::binaryClauses && (*s)->size() == 2) { - solver.binaryClauses.push(*s); - solver.becameBinary++; - s++; } else { - *ss++ = *s++; + *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 @@ -121,11 +119,12 @@ void ClauseCleaner::cleanClauses(vec& cs, ClauseSetType type, const uin inline const 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); @@ -133,9 +132,9 @@ inline const bool ClauseCleaner::cleanClause(Clause*& cc) *j++ = *i; continue; } - + if (val == l_True) { - solver.detachModifiedClause(origLit1, origLit2, origSize, &c); + solver.detachModifiedClause(origLit1, origLit2, origLit3, origSize, &c); return true; } } @@ -143,13 +142,15 @@ inline const bool ClauseCleaner::cleanClause(Clause*& cc) assert(c.size() != 1); if (i != j) { - c.setStrenghtened(); if (c.size() == 2) { - solver.detachModifiedClause(origLit1, origLit2, origSize, &c); - Clause *c2 = solver.clauseAllocator.Clause_new(c); - solver.clauseAllocator.clauseFree(&c); - cc = c2; - solver.attachClause(*c2); + 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; @@ -157,46 +158,46 @@ inline const bool ClauseCleaner::cleanClause(Clause*& cc) solver.clauses_literals -= i-j; } } - + return false; } -void ClauseCleaner::cleanClauses(vec& cs, ClauseSetType type, const uint limit) +void ClauseCleaner::cleanClauses(vec& 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 - assert(find(solver.xorwatches[(**s)[0].var()], *s)); - assert(find(solver.xorwatches[(**s)[1].var()], *s)); - if (solver.assigns[(**s)[0].var()]!=l_Undef || solver.assigns[(**s)[1].var()]!=l_Undef) { + #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 - assert(find(solver.xorwatches[(**s)[0].var()], *s)); - assert(find(solver.xorwatches[(**s)[1].var()], *s)); + #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 @@ -216,7 +217,7 @@ inline const bool ClauseCleaner::cleanClause(XorClause& c) } else c.invert(val.getBool()); } c.shrink(i-j); - + assert(c.size() != 1); switch (c.size()) { case 0: { @@ -226,13 +227,12 @@ inline const bool ClauseCleaner::cleanClause(XorClause& c) case 2: { c[0] = c[0].unsign(); c[1] = c[1].unsign(); - solver.varReplacer->replace(c, c.xor_clause_inverted(), c.getGroup()); + solver.varReplacer->replace(c, c.xorEqualFalse(), c.getGroup()); solver.detachModifiedClause(origVar1, origVar2, origSize, &c); return true; } default: { if (i-j > 0) { - c.setStrenghtened(); solver.clauses_literals -= i-j; } return false; @@ -243,141 +243,9 @@ inline const bool ClauseCleaner::cleanClause(XorClause& c) return false; } -void ClauseCleaner::cleanClausesBewareNULL(vec& cs, ClauseCleaner::ClauseSetType type, Subsumer& subs, const uint limit) -{ - assert(solver.decisionLevel() == 0); - assert(solver.qhead == solver.trail.size()); - - if (lastNumUnitaryClean[type] + limit >= solver.get_unitary_learnts_num()) - return; - - ClauseSimp *s, *end; - for (s = cs.getData(), end = s + cs.size(); s != end; s++) { - if (s+1 != end) - __builtin_prefetch((s+1)->clause, 1, 0); - if (s->clause == NULL) - continue; - - if (cleanClauseBewareNULL(*s, subs)) { - continue; - } else if (s->clause->size() == 2) - solver.becameBinary++; - } - - lastNumUnitaryClean[type] = solver.get_unitary_learnts_num(); -} - -inline const bool ClauseCleaner::cleanClauseBewareNULL(ClauseSimp cc, Subsumer& subs) -{ - Clause& c = *cc.clause; - vec origClause(c.size()); - memcpy(origClause.getData(), c.getData(), sizeof(Lit)*c.size()); - - 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) { - subs.unlinkModifiedClause(origClause, cc, true); - solver.clauseAllocator.clauseFree(cc.clause); - return true; - } - } - - if (i != j) { - c.setStrenghtened(); - if (origClause.size() > 2 && origClause.size()-(i-j) == 2) { - subs.unlinkModifiedClause(origClause, cc, true); - subs.clauses[cc.index] = cc; - c.shrink(i-j); - solver.attachClause(c); - subs.linkInAlreadyClause(cc); - } else { - c.shrink(i-j); - subs.unlinkModifiedClause(origClause, cc, false); - subs.linkInAlreadyClause(cc); - if (c.learnt()) - solver.learnts_literals -= i-j; - else - solver.clauses_literals -= i-j; - } - if (!c.learnt()) c.calcAbstractionClause(); - subs.updateClause(cc); - } - - return false; -} - -void ClauseCleaner::cleanXorClausesBewareNULL(vec& cs, ClauseCleaner::ClauseSetType type, XorSubsumer& subs, const uint limit) -{ - assert(solver.decisionLevel() == 0); - assert(solver.qhead == solver.trail.size()); - - if (lastNumUnitaryClean[type] + limit >= solver.get_unitary_learnts_num()) - return; - - XorClauseSimp *s, *end; - for (s = cs.getData(), end = s + cs.size(); s != end; s++) { - if (s+1 != end) - __builtin_prefetch((s+1)->clause, 1, 0); - if (s->clause == NULL) - continue; - - cleanXorClauseBewareNULL(*s, subs); - } - - lastNumUnitaryClean[type] = solver.get_unitary_learnts_num(); -} - -inline const bool ClauseCleaner::cleanXorClauseBewareNULL(XorClauseSimp cc, XorSubsumer& subs) -{ - XorClause& c = *cc.clause; - vec origClause(c.size()); - memcpy(origClause.getData(), c.getData(), sizeof(Lit)*c.size()); - - Lit *i, *j, *end; - 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); - - switch(c.size()) { - case 0: { - subs.unlinkModifiedClause(origClause, cc); - solver.clauseAllocator.clauseFree(cc.clause); - return true; - } - case 2: { - vec ps(2); - ps[0] = c[0].unsign(); - ps[1] = c[1].unsign(); - solver.varReplacer->replace(ps, c.xor_clause_inverted(), c.getGroup()); - subs.unlinkModifiedClause(origClause, cc); - solver.clauseAllocator.clauseFree(cc.clause); - return true; - } - default: - if (i-j > 0) { - subs.unlinkModifiedClauseNoDetachNoNULL(origClause, cc); - subs.linkInAlreadyClause(cc); - c.calcXorAbstraction(); - } - } - - return false; -} - bool ClauseCleaner::satisfied(const Clause& c) const { - for (uint i = 0; i != c.size(); i++) + for (uint32_t i = 0; i != c.size(); i++) if (solver.value(c[i]) == l_True) return true; return false; @@ -385,8 +253,8 @@ bool ClauseCleaner::satisfied(const Clause& c) const bool ClauseCleaner::satisfied(const XorClause& c) const { - bool final = c.xor_clause_inverted(); - for (uint k = 0; k != c.size(); k++ ) { + 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(); @@ -394,28 +262,48 @@ bool ClauseCleaner::satisfied(const XorClause& c) const return final; } -void ClauseCleaner::moveBinClausesToBinClauses() + + +/*void ClauseCleaner::removeSatisfied(vec& cs, ClauseSetType type, const uint32_t limit) { + #ifdef DEBUG_CLEAN assert(solver.decisionLevel() == 0); - assert(solver.qhead == solver.trail.size()); + #endif - vec& cs = solver.clauses; - Clause **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); + if (lastNumUnitarySat[type] + limit >= solver.get_unitary_learnts_num()) + return; - if ((**s).size() == 2) { - solver.detachClause(**s); - Clause *c2 = solver.clauseAllocator.Clause_new(**s); - solver.clauseAllocator.clauseFree(*s); - solver.attachClause(*c2); - solver.becameBinary++; - solver.binaryClauses.push(c2); - } else - *ss++ = *s; + uint32_t i,j; + for (i = j = 0; i < cs.size(); i++) { + if (satisfied(*cs[i])) + solver.removeClause(*cs[i]); + else + cs[j++] = cs[i]; } - cs.shrink(s-ss); -} + cs.shrink(i - j); + + lastNumUnitarySat[type] = solver.get_unitary_learnts_num(); +}*/ -}; //NAMESPACE MINISAT +/*void ClauseCleaner::removeSatisfied(vec& cs, ClauseSetType type, const uint32_t limit) +{ + #ifdef DEBUG_CLEAN + assert(solver.decisionLevel() == 0); + #endif + + if (lastNumUnitarySat[type] + limit >= solver.get_unitary_learnts_num()) + return; + + Clause **i,**j, **end; + for (i = j = cs.getData(), end = i + cs.size(); i != end; i++) { + if (i+1 != end) + __builtin_prefetch(*(i+1), 0, 0); + if (satisfied(**i)) + solver.removeClause(**i); + else + *j++ = *i; + } + cs.shrink(i - j); + + lastNumUnitarySat[type] = solver.get_unitary_learnts_num(); +}*/ diff --git a/src/sat/cryptominisat2/ClauseCleaner.h b/src/sat/cryptominisat2/ClauseCleaner.h index d4c2adf..c55496b 100644 --- a/src/sat/cryptominisat2/ClauseCleaner.h +++ b/src/sat/cryptominisat2/ClauseCleaner.h @@ -28,54 +28,55 @@ along with this program. If not, see . #include "Subsumer.h" #include "XorSubsumer.h" -namespace MINISAT -{ -using namespace MINISAT; - +/** +@brief Cleans clauses from false literals & removes satisfied clauses +*/ class ClauseCleaner { public: ClauseCleaner(Solver& solver); - - enum ClauseSetType {clauses, xorclauses, learnts, binaryClauses, simpClauses, xorSimpClauses}; - - void cleanClauses(vec& cs, ClauseSetType type, const uint limit = 0); - void cleanClausesBewareNULL(vec& cs, ClauseSetType type, Subsumer& subs, const uint limit = 0); - void cleanXorClausesBewareNULL(vec& cs, ClauseSetType type, XorSubsumer& subs, const uint limit = 0); - const bool cleanClauseBewareNULL(ClauseSimp c, Subsumer& subs); - const bool cleanXorClauseBewareNULL(XorClauseSimp c, XorSubsumer& subs); - - void cleanClauses(vec& cs, ClauseSetType type, const uint limit = 0); - void removeSatisfied(vec& cs, ClauseSetType type, const uint limit = 0); - void removeSatisfied(vec& cs, ClauseSetType type, const uint limit = 0); + + enum ClauseSetType {clauses, binaryClauses, xorclauses, learnts}; + + void cleanClauses(vec& cs, ClauseSetType type, const uint32_t limit = 0); + + void cleanClauses(vec& cs, ClauseSetType type, const uint32_t limit = 0); + void removeSatisfiedBins(const uint32_t limit = 0); + //void removeSatisfied(vec& cs, ClauseSetType type, const uint32_t limit = 0); + //void removeSatisfied(vec& 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; - void moveBinClausesToBinClauses(); - private: + const bool satisfied(const Watched& watched, Lit lit); const bool cleanClause(XorClause& c); const bool cleanClause(Clause*& c); - - uint lastNumUnitarySat[6]; - uint lastNumUnitaryClean[6]; - + + uint32_t lastNumUnitarySat[6]; /// +#else +#include +#endif //_MSC_VER + +typedef uint32_t ClauseOffset; + +#endif //CLAUSEOFFSET_H diff --git a/src/sat/cryptominisat2/ClauseVivifier.cpp b/src/sat/cryptominisat2/ClauseVivifier.cpp new file mode 100644 index 0000000..b2413e3 --- /dev/null +++ b/src/sat/cryptominisat2/ClauseVivifier.cpp @@ -0,0 +1,271 @@ +/************************************************************************** +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 . +*****************************************************************************/ + +#include "ClauseVivifier.h" +#include "ClauseCleaner.h" +#include "time_mem.h" +#include + +//#define ASSYM_DEBUG + +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. +*/ +const 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 && solver.conf.doCacheOTFSSR) { + if (!vivifyClauses2(solver.clauses)) return false; + if (/*solver.lastSelectedRestartType == static_restart &&*/ !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 lits; + vec 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).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, c.getGroup()); + #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; +} + + +const bool ClauseVivifier::vivifyClauses2(vec& clauses) +{ + assert(solver.ok); + + vec seen; + seen.growTo(solver.nVars()*2, 0); + uint32_t litsRem = 0; + uint32_t clShrinked = 0; + uint64_t countTime = 0; + uint64_t maxCountTime = 500000000; + if (solver.clauses_literals + solver.learnts_literals < 500000) + maxCountTime *= 2; + if (numCalls >= 5) maxCountTime*= 3; + uint32_t clTried = 0; + vec lits; + bool needToFinish = false; + double myTime = cpuTime(); + + if (numCalls < 3) return true; + + 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++; + + for (uint32_t i2 = 0; i2 < cl.size(); i2++) seen[cl[i2].toInt()] = 1; + for (const Lit *l = cl.getData(), *end = cl.getDataEnd(); l != end; l++) { + if (seen[l->toInt()] == 0) continue; + Lit lit = *l; + + countTime += solver.transOTFCache[l->toInt()].lits.size(); + for (vector::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; + } + if (lits.size() < cl.size()) { + countTime += cl.size()*10; + solver.detachClause(cl); + clShrinked++; + Clause* c2 = solver.addClauseInt(lits, cl.getGroup(), 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 shrink " << std::setw(8) << clShrinked + << " lits rem " << std::setw(10) << litsRem + << " time: " << cpuTime() - myTime + << std::endl; + } + + return solver.ok; +} diff --git a/src/sat/cryptominisat2/ClauseVivifier.h b/src/sat/cryptominisat2/ClauseVivifier.h new file mode 100644 index 0000000..d890e40 --- /dev/null +++ b/src/sat/cryptominisat2/ClauseVivifier.h @@ -0,0 +1,55 @@ +/************************************************************************** +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 . +*****************************************************************************/ + +#ifndef CLAUSEVIVIFIER_H +#define CLAUSEVIVIFIER_H + +#include "Solver.h" + +class ClauseVivifier { + public: + ClauseVivifier(Solver& solver); + const bool vivifyClauses(); + const bool vivifyClauses2(vec& 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 + { + const bool operator () (const Clause* x, const Clause* y) + { + return (x->size() > y->size()); + } + }; + + uint32_t numCalls; + Solver& solver; +}; + +#endif //CLAUSEVIVIFIER_H diff --git a/src/sat/cryptominisat2/CompleteDetachReattacher.cpp b/src/sat/cryptominisat2/CompleteDetachReattacher.cpp new file mode 100644 index 0000000..97a53e2 --- /dev/null +++ b/src/sat/cryptominisat2/CompleteDetachReattacher.cpp @@ -0,0 +1,194 @@ +/************************************************************************** +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 . +*****************************************************************************/ + +#include "CompleteDetachReattacher.h" +#include "VarReplacer.h" +#include "ClauseCleaner.h" + +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 *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& ws, const bool removeTri) +{ + ClausesStay stay; + + Watched* i = ws.getData(); + Watched* j = i; + for (Watched *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 +*/ +const 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().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& cs) +{ + Clause **i = cs.getData(); + Clause **j = i; + for (Clause **end = cs.getDataEnd(); i != end; i++) { + 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& 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 const 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 const 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(), ps.getGroup()); + return false; + } + + default:; + } + + return true; +} diff --git a/src/sat/cryptominisat2/CompleteDetachReattacher.h b/src/sat/cryptominisat2/CompleteDetachReattacher.h new file mode 100644 index 0000000..b45949d --- /dev/null +++ b/src/sat/cryptominisat2/CompleteDetachReattacher.h @@ -0,0 +1,74 @@ +/************************************************************************** +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 . +*****************************************************************************/ + +#include "Solver.h" + +/** +@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); + const 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& ws, const bool removeTri = false); + + void cleanAndAttachClauses(vec& cs); + void cleanAndAttachClauses(vec& cs); + const bool cleanClause(Clause*& ps); + const bool cleanClause(XorClause& ps); + + Solver& solver; +}; diff --git a/src/sat/cryptominisat2/DataSync.cpp b/src/sat/cryptominisat2/DataSync.cpp new file mode 100644 index 0000000..1c927e1 --- /dev/null +++ b/src/sat/cryptominisat2/DataSync.cpp @@ -0,0 +1,231 @@ +/***************************************************************************** +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 . +******************************************************************************/ + +#include "DataSync.h" +#include "Subsumer.h" +#include "VarReplacer.h" +#include "XorSubsumer.h" +#include + +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); +} + +const 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; +} + +const 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& bins = shared.bins[wsLit]; + vec& 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; +} + +template +void DataSync::signalNewBinClause(T& ps) +{ + assert(ps.size() == 2); + signalNewBinClause(ps[0], ps[1]); +} + +void DataSync::signalNewBinClause(Lit lit1, Lit lit2) +{ + if (lit1.toInt() > lit2.toInt()) std::swap(lit1, lit2); + newBinClauses.push_back(std::make_pair(lit1, lit2)); +} + +template void DataSync::signalNewBinClause(Clause& ps); +template void DataSync::signalNewBinClause(XorClause& ps); +template void DataSync::signalNewBinClause(vec& ps); + +const bool DataSync::syncBinFromOthers(const Lit lit, const vector& bins, uint32_t& finished, vec& 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 addedToSeen; + for (Watched *it = ws.getData(), *end = ws.getDataEnd(); it != end; it++) { + if (it->isBinary()) { + addedToSeen.push(it->getOtherLit()); + seen[it->getOtherLit().toInt()] = true; + } + } + + vec 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, 0, 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 >::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& bins = sharedData->bins[(~lit1).toInt()]; + for (vector::const_iterator it = bins.begin(), end = bins.end(); it != end; it++) { + if (*it == lit2) return; + } + + bins.push_back(lit2); + sentBinData++; +} + +const 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().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; +} \ No newline at end of file diff --git a/src/sat/cryptominisat2/DataSync.h b/src/sat/cryptominisat2/DataSync.h new file mode 100644 index 0000000..b049fc4 --- /dev/null +++ b/src/sat/cryptominisat2/DataSync.h @@ -0,0 +1,83 @@ +/***************************************************************************** +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 . +******************************************************************************/ + +#include "SharedData.h" +#include "Solver.h" + +class DataSync +{ + public: + DataSync(Solver& solver, SharedData* sharedData); + void newVar(); + const bool syncData(); + + + template void signalNewBinClause(T& ps); + void signalNewBinClause(Lit lit1, Lit lit2); + + const uint32_t getSentUnitData() const; + const uint32_t getRecvUnitData() const; + const uint32_t getSentBinData() const; + const uint32_t getRecvBinData() const; + + private: + //functions + const bool shareUnitData(); + const bool syncBinFromOthers(const Lit lit, const vector& bins, uint32_t& finished, vec& ws); + void syncBinToOthers(); + void addOneBinToOthers(const Lit lit1, const Lit lit2); + const bool shareBinData(); + + //stuff to sync + vector > newBinClauses; + + //stats + uint64_t lastSyncConf; + vec syncFinish; + uint32_t sentUnitData; + uint32_t recvUnitData; + uint32_t sentBinData; + uint32_t recvBinData; + + //misc + vec seen; + + //main data + SharedData* sharedData; + Solver& solver; +}; + +inline const uint32_t DataSync::getSentUnitData() const +{ + return sentUnitData; +} + +inline const uint32_t DataSync::getRecvUnitData() const +{ + return recvUnitData; +} + +inline const uint32_t DataSync::getSentBinData() const +{ + return sentBinData; +} + +inline const uint32_t DataSync::getRecvBinData() const +{ + return recvBinData; +} + diff --git a/src/sat/cryptominisat2/DimacsParser.cpp b/src/sat/cryptominisat2/DimacsParser.cpp new file mode 100644 index 0000000..e8c4671 --- /dev/null +++ b/src/sat/cryptominisat2/DimacsParser.cpp @@ -0,0 +1,455 @@ +/***************************************************************************** +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 +#include +#include + +#include "Solver.h" + +#ifdef VERBOSE_DEBUG +#define DEBUG_COMMENT_PARSING +#endif //VERBOSE_DEBUG + +//#define DEBUG_COMMENT_PARSING + +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) + , groupId(0) +{} + +/** +@brief Skips all whitespaces +*/ +void DimacsParser::skipWhitespace(StreamBuffer& in) +{ + while ((*in >= 9 && *in <= 13) || *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 +*/ +int DimacsParser::parseInt(StreamBuffer& in, uint32_t& lenParsed) +{ + lenParsed = 0; + int val = 0; + bool neg = false; + skipWhitespace(in); + if (*in == '-') neg = true, ++in; + else if (*in == '+') ++in; + if (*in < '0' || *in > '9') printf("PARSE ERROR! Unexpected char: %c\n", *in), exit(3); + while (*in >= '0' && *in <= '9') { + lenParsed++; + val = val*10 + (*in - '0'), + ++in; + } + return neg ? -val : val; +} + +float DimacsParser::parseFloat(StreamBuffer& in) +{ + uint32_t len; + uint32_t main = parseInt(in, len); + if (*in != '.') { + printf("PARSE ERROR! Float does not contain a dot! Instead it contains: %c\n", *in); + exit(3); + } + ++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& lits) +{ + int 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) { + 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) +{ + 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 { + printf("PARSE ERROR! Unexpected char: %c\n", *in), exit(3); + } +} + +/** +@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) +{ + 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) std::cout << "PARSE ERROR! Var number must be a positive integer" << std::endl, exit(3); + std::string name = untilEnd(in); + solver->setVariableName(var-1, name.c_str()); + + #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); + //std::cout << str<< std::endl; + if (str != "learnt") goto addTheClause; + + ++in; + parseString(in, str); + //std::cout << str<< std::endl; + 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; + //std::cout << "PARSE ERROR: line contains \"c learnt\" but is not followed by yes/no" << std::endl; + //exit(-1); + } + //std::std::cout << "Learnt? " << learnt << std::endl; + + //Parse in Glue value + ++in; + parseString(in, str); + if (str != "glue") goto addTheClause; + //std::std::cout << "read GLUE" << std::endl; + ++in; + glue = parseInt(in, len); + //std::cout << "glue: " << glue << std::endl; + + //Parse in MiniSat activity + ++in; + parseString(in, str); + if (str != "miniSatAct") goto addTheClause; + //std::cout << "read MINISATACT" << std::endl; + ++in; + miniSatAct = parseFloat(in); + //std::cout << "MiniSatAct:" << miniSatAct << std::endl; + + 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) +{ + 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) groupId++; + else { + if (*in != 'c') { + std::cout << "PARSE ERROR! Group must be present after earch clause ('c' missing after clause line)" << std::endl; + exit(3); + } + ++in; + + parseString(in, str); + if (str != "g" && str != "group") { + std::cout << "PARSE ERROR! Group must be present after each clause('group' missing)!" << std::endl; + std::cout << "Instead of 'group' there was:" << str << std::endl; + exit(3); + } + + groupId = parseInt(in, len); + if (groupId <= 0) printf("PARSE ERROR! Group number must be a positive integer\n"), exit(3); + + 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, groupId, name.c_str()); + numXorClauses++; + } else { + if (addAsLearnt || learnt) { + solver->addLearntClause(lits, groupId, NULL, glue, miniSatAct); + numLearntClauses++; + } else { + solver->addClause(lits, groupId, name.c_str()); + numNormClauses++; + } + } + + if (needToParseComments) { + #ifdef DEBUG_COMMENT_PARSING + std::cout << "Need to parse comments:" << str << std::endl; + #endif //DEBUG_COMMENT_PARSING + parseComments(in, str); + } +} + +/** +@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); + break; + case 'c': + ++in; + parseString(in, str); + parseComments(in, str); + break; + default: + readFullClause(in); + break; + } + } +} + +template +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/sat/cryptominisat2/DimacsParser.h b/src/sat/cryptominisat2/DimacsParser.h new file mode 100644 index 0000000..f264637 --- /dev/null +++ b/src/sat/cryptominisat2/DimacsParser.h @@ -0,0 +1,76 @@ +/***************************************************************************** +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 +#include "SolverTypes.h" +#include "constants.h" +#include "StreamBuffer.h" +#include "Vec.h" + +#ifdef _MSC_VER +#include +#else +#include +#endif //_MSC_VER + +#ifndef DISABLE_ZLIB +#include +#endif // DISABLE_ZLIB + +#ifdef STATS_NEEDED +#include "Logger.h" +#endif //STATS_NEEDED + +class Solver; + +/** +@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 + 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); + int parseInt(StreamBuffer& in, uint32_t& len); + float parseFloat(StreamBuffer& in); + void parseString(StreamBuffer& in, std::string& str); + void readClause(StreamBuffer& in, vec& lits); + void parseClauseParameters(StreamBuffer& in, bool& learnt, uint32_t& glue, float& miniSatAct); + void readFullClause(StreamBuffer& in); + bool match(StreamBuffer& in, const char* str); + void printHeader(StreamBuffer& in); + void parseComments(StreamBuffer& in, const std::string str); + std::string stringify(uint32_t x); + + + Solver *solver; + const bool debugLib; + const bool debugNewVar; + const bool grouping; + const bool addAsLearnt; + + uint32_t debugLibPart; /// lits; ///. +*****************************************************************************/ + +#include "FailedLitSearcher.h" + +#include +#include +#include +using std::make_pair; +using std::set; + +#include "Solver.h" +#include "ClauseCleaner.h" +#include "time_mem.h" +#include "VarReplacer.h" +#include "ClauseCleaner.h" +#include "StateSaver.h" +#include "CompleteDetachReattacher.h" + +#ifdef _MSC_VER +#define __builtin_prefetch(a,b,c) +#endif //_MSC_VER + +//#define VERBOSE_DEUBUG + +/** +@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), 0, 0); + + 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& 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& 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 +*/ +const 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. +*/ +const bool FailedLitSearcher::search() +{ + assert(solver.decisionLevel() == 0); + if (solver.nVars() == 0) return solver.ok; + + uint64_t numProps = 100 * 1000000; + uint64_t numPropsDifferent = (double)numProps*2.0; + + solver.testAllClauseAttach(); + double myTime = cpuTime(); + uint32_t origHeapSize = solver.order_heap.size(); + StateSaver savedState(solver); + Heap 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; + 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: + bool removedOldLearnts = false; + + 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); + removedOldLearnts = 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. +*/ +const 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.setZero(); + 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).isNULL()); + if (failed) { + solver.cancelUntilLight(); + numFailed++; + solver.uncheckedEnqueue(~lit1); + solver.ok = (solver.propagate(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); + + 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).isNULL()); + if (failed) { + solver.cancelUntilLight(); + numFailed++; + solver.uncheckedEnqueue(~lit2); + solver.ok = (solver.propagate(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, 0)); + 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, solver.xorclauses[*it]->getGroup())); + 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).isNULL()); + if (!solver.ok) return false; + + 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, binXorToAdd[i].group); + 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 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()].lev2Ancestor.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; + fillImplies(*l); + 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.setZero(); + goto end; + } + } + #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).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(); +} + +/** +@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, 0 , true); + tmpPs.clear(); + tmpPs.growTo(2); + assert(solver.ok); + addedBin++; +} diff --git a/src/sat/cryptominisat2/FailedLitSearcher.h b/src/sat/cryptominisat2/FailedLitSearcher.h new file mode 100644 index 0000000..b092497 --- /dev/null +++ b/src/sat/cryptominisat2/FailedLitSearcher.h @@ -0,0 +1,229 @@ +/*************************************************************************** +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 . +****************************************************************************/ + +#ifndef FAILEDLITSEARCHER_H +#define FAILEDLITSEARCHER_H + +#include +#include +#include +using std::set; +using std::map; +using std::vector; + +#include "SolverTypes.h" +#include "Clause.h" +#include "BitArray.h" +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); + + const bool search(); + const double getTotalTime() const; + + private: + //Main + const bool tryBoth(const Lit lit1, const Lit lit2); + const bool tryAll(const Lit* begin, const Lit* end); + void printResults(const double myTime) const; + + Solver& solver; /// 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: + const bool operator==(const TwoLongXor& other) const + { + if (var[0] == other.var[0] + && var[1] == other.var[1] + && inverted == other.inverted) + return true; + return false; + } + const 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, const uint32_t _group) : + lit1(_lit1) + , lit2(_lit2) + , isEqualFalse(_isEqualFalse) + , group(_group) + {} + Lit lit1; + Lit lit2; + bool isEqualFalse; + uint32_t group; + }; + const TwoLongXor getTwoLongXor(const XorClause& c); + void addFromSolver(const vec& cs); + void removeVarFromXors(const Var var); + void addVarFromXors(const Var var); + + uint32_t newBinXor; + vec xorClauseSizes; + vector > occur; /// investigateXor; + std::set twoLongXors; + bool binXorFind; + uint32_t lastTrailSize; + vector 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) + {} + + const bool operator () (const Lit x, const Lit y) const + { + return binPropData[x.var()].lev > binPropData[y.var()].lev; + } + + const vec& binPropData; + }; + uint32_t addedBin; + void hyperBinResolution(const Lit lit); + BitArray unPropagatedBin; + BitArray needToVisit; + vec propagatedVars; + void addBin(const Lit lit1, const Lit lit2); + void fillImplies(const Lit lit); + vec myImpliesSet; /// uselessBin; + uint32_t removedUselessLearnt; + uint32_t removedUselessNonLearnt; + BitArray dontRemoveAncestor; + vec toClearDontRemoveAcestor; + /** + @brief Controls hyper-binary resolution's time-usage + + Don't do more than this many propagations within hyperBinResolution() + */ + uint64_t maxHyperBinProps; + + //Temporaries + vec 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; ///. -**************************************************************************************************/ - -#include "FailedVarSearcher.h" - -#include -#include -#include -using std::make_pair; -using std::set; - -#include "Solver.h" -#include "ClauseCleaner.h" -#include "time_mem.h" -#include "VarReplacer.h" -#include "ClauseCleaner.h" -#include "StateSaver.h" - -#ifdef _MSC_VER -#define __builtin_prefetch(a,b,c) -#endif //_MSC_VER - -//#define VERBOSE_DEUBUG - -namespace MINISAT -{ -using namespace MINISAT; - -FailedVarSearcher::FailedVarSearcher(Solver& _solver): - solver(_solver) - , tmpPs(2) - , finishedLastTimeVar(true) - , lastTimeWentUntilVar(0) - , finishedLastTimeBin(true) - , lastTimeWentUntilBin(0) - , numPropsMultiplier(1.0) - , lastTimeFoundTruths(0) - , numCalls(0) -{ -} - -void FailedVarSearcher::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), 0, 0); - - 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); - } - } -} - -inline void FailedVarSearcher::removeVarFromXors(const Var var) -{ - vector& 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); - } - } -} - -inline void FailedVarSearcher::addVarFromXors(const Var var) -{ - vector& occ = occur[var]; - if (occ.empty()) return; - - for (uint32_t *it = &occ[0], *end = it + occ.size(); it != end; it++) { - xorClauseSizes[*it]++; - } -} - -const TwoLongXor FailedVarSearcher::getTwoLongXor(const XorClause& c) -{ - TwoLongXor tmp; - uint32_t num = 0; - tmp.inverted = c.xor_clause_inverted(); - - 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; -} - -const bool FailedVarSearcher::search(uint64_t numProps) -{ - assert(solver.decisionLevel() == 0); - solver.testAllClauseAttach(); - double myTime = cpuTime(); - uint32_t origHeapSize = solver.order_heap.size(); - StateSaver savedState(solver); - Heap order_heap_copy(solver.order_heap); //for hyperbin - uint64_t origBinClauses = solver.binaryClauses.size(); - - //General Stats - numFailed = 0; - goodBothSame = 0; - numCalls++; - - //If failed var searching is going good, do successively more and more of it - if (lastTimeFoundTruths > 500 || (double)lastTimeFoundTruths > (double)solver.order_heap.size() * 0.03) std::max(numPropsMultiplier*1.7, 5.0); - else numPropsMultiplier = 1.0; - numProps = (uint64_t) ((double)numProps * numPropsMultiplier *3); - - //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 - unPropagatedBin.resize(solver.nVars(), 0); - myimplies.resize(solver.nVars(), 0); - hyperbinProps = 0; - if (solver.addExtraBins && !orderLits()) return false; - maxHyperBinProps = numProps/8; - - //uint32_t fromBin; - uint32_t fromVar; - if (finishedLastTimeVar || lastTimeWentUntilVar >= solver.nVars()) - fromVar = 0; - else - fromVar = lastTimeWentUntilVar; - finishedLastTimeVar = true; - lastTimeWentUntilVar = solver.nVars(); - origProps = solver.propagations; - for (Var var = fromVar; var < solver.nVars(); var++) { - if (solver.assigns[var] != l_Undef || !solver.decision_var[var]) - continue; - if (solver.propagations - origProps >= numProps) { - finishedLastTimeVar = false; - lastTimeWentUntilVar = var; - break; - } - if (!tryBoth(Lit(var, false), Lit(var, true))) - goto end; - } - - numProps = (double)numProps * 1.2; - hyperbinProps = 0; - 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 >= numProps) { - finishedLastTimeVar = false; - lastTimeWentUntilVar = var; - break; - } - if (!tryBoth(Lit(var, false), Lit(var, true))) - goto end; - } - - /*if (solver.verbosity >= 1) printResults(myTime); - if (finishedLastTimeBin || lastTimeWentUntilBin >= solver.binaryClauses.size()) - fromBin = 0; - else - fromBin = lastTimeWentUntilBin; - finishedLastTimeBin = true; - lastTimeWentUntilBin = solver.nVars(); - for (uint32_t binCl = 0; binCl < solver.binaryClauses.size(); binCl++) { - if ((double)(solver.propagations - origProps) >= 1.1*(double)numProps) { - finishedLastTimeBin = false; - lastTimeWentUntilBin = binCl; - break; - } - - Clause& cl = *solver.binaryClauses[binCl]; - if (solver.value(cl[0]) == l_Undef && solver.value(cl[1]) == l_Undef) { - if (!tryBoth(cl[0], cl[1])) - goto end; - } - }*/ - - /*for (Clause **it = solver.clauses.getData(), **end = solver.clauses.getDataEnd(); it != end; it++) { - Clause& c = **it; - for (uint i = 0; i < c.size(); i++) { - if (solver.value(c[i]) != l_Undef) goto next; - } - if (!tryAll(c.getData(), c.getDataEnd())) - goto end; - - next:; - } - - for (Clause **it = solver.learnts.getData(), **end = solver.learnts.getDataEnd(); it != end; it++) { - Clause& c = **it; - for (uint i = 0; i < c.size(); i++) { - if (solver.value(c[i]) != l_Undef) goto next2; - } - if (!tryAll(c.getData(), c.getDataEnd())) - goto end; - - next2:; - }*/ - -end: - bool removedOldLearnts = false; - binClauseAdded = solver.binaryClauses.size() - origBinClauses; - //Print results - if (solver.verbosity >= 1) printResults(myTime); - - 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) { - completelyDetachAndReattach(); - removedOldLearnts = true; - } else { - solver.clauseCleaner->removeAndCleanAll(); - } - if (solver.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::setw(39) << " | " << std::endl; - } - } - - lastTimeFoundTruths = solver.trail.size() - origTrailSize; - - savedState.restore(); - - solver.testAllClauseAttach(); - return solver.ok; -} - -void FailedVarSearcher::completelyDetachAndReattach() -{ - solver.clauses_literals = 0; - solver.learnts_literals = 0; - for (uint32_t i = 0; i < solver.nVars(); i++) { - solver.binwatches[i*2].clear(); - solver.binwatches[i*2+1].clear(); - solver.watches[i*2].clear(); - solver.watches[i*2+1].clear(); - solver.xorwatches[i].clear(); - } - solver.varReplacer->reattachInternalClauses(); - cleanAndAttachClauses(solver.binaryClauses); - cleanAndAttachClauses(solver.clauses); - cleanAndAttachClauses(solver.learnts); - cleanAndAttachClauses(solver.xorclauses); -} - -void FailedVarSearcher::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) << binClauseAdded << - " 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::setw(5) << " |" << std::endl; -} - -const bool FailedVarSearcher::orderLits() -{ - uint64_t oldProps = solver.propagations; - double myTime = cpuTime(); - uint32_t numChecked = 0; - if (litDegrees.size() != solver.nVars()) - litDegrees.resize(solver.nVars()*2, 0); - BitArray alreadyTested; - alreadyTested.resize(solver.nVars()*2, 0); - uint32_t i; - - for (i = 0; i < 3*solver.order_heap.size(); i++) { - if (solver.propagations - oldProps > 1500000) break; - Var var = solver.order_heap[solver.mtrand.randInt(solver.order_heap.size()-1)]; - if (solver.assigns[var] != l_Undef || !solver.decision_var[var]) continue; - - Lit randLit(var, solver.mtrand.randInt(1)); - if (alreadyTested[randLit.toInt()]) continue; - alreadyTested.setBit(randLit.toInt()); - - numChecked++; - solver.newDecisionLevel(); - solver.uncheckedEnqueueLight(randLit); - failed = (!solver.propagateBin().isNULL()); - if (failed) { - solver.cancelUntil(0); - solver.uncheckedEnqueue(~randLit); - solver.ok = (solver.propagate().isNULL()); - if (!solver.ok) return false; - continue; - } - assert(solver.decisionLevel() > 0); - for (int c = solver.trail.size()-1; c > (int)solver.trail_lim[0]; c--) { - Lit x = solver.trail[c]; - litDegrees[x.toInt()]++; - } - solver.cancelUntil(0); - } - if (solver.verbosity >= 1) { - std::cout << "c binary deg approx." - << " time: " << std::fixed << std::setw(5) << std::setprecision(2) << cpuTime() - myTime << " s" - << " num checked: " << std::setw(6) << numChecked - << " i: " << std::setw(7) << i - << " props: " << std::setw(4) << (solver.propagations - oldProps)/1000 << "k" - << std::setw(13) << " |" << std::endl; - } - solver.propagations = oldProps; - - return true; -} - -const bool FailedVarSearcher::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.setZero(); - twoLongXors.clear(); - propagatedVars.clear(); - unPropagatedBin.setZero(); - bothSame.clear(); - - solver.newDecisionLevel(); - solver.uncheckedEnqueueLight(lit1); - failed = (!solver.propagate().isNULL()); - if (failed) { - solver.cancelUntil(0); - numFailed++; - solver.uncheckedEnqueue(~lit1); - solver.ok = (solver.propagate(false).isNULL()); - if (!solver.ok) return false; - return true; - } else { - assert(solver.decisionLevel() > 0); - for (int c = solver.trail.size()-1; c >= (int)solver.trail_lim[0]; c--) { - Var x = solver.trail[c].var(); - propagated.setBit(x); - if (solver.addExtraBins) { - unPropagatedBin.setBit(x); - propagatedVars.push(x); - } - if (solver.assigns[x].getBool()) propValue.setBit(x); - else propValue.clearBit(x); - - if (binXorFind) removeVarFromXors(x); - } - - 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.cancelUntil(0); - } - - if (solver.addExtraBins && hyperbinProps < maxHyperBinProps) addBinClauses(lit1); - propagatedVars.clear(); - unPropagatedBin.setZero(); - - solver.newDecisionLevel(); - solver.uncheckedEnqueueLight(lit2); - failed = (!solver.propagate().isNULL()); - if (failed) { - solver.cancelUntil(0); - numFailed++; - solver.uncheckedEnqueue(~lit2); - solver.ok = (solver.propagate(false).isNULL()); - if (!solver.ok) return false; - return true; - } else { - assert(solver.decisionLevel() > 0); - for (int c = solver.trail.size()-1; c >= (int)solver.trail_lim[0]; c--) { - Var x = solver.trail[c].var(); - if (propagated[x]) { - if (solver.addExtraBins) { - unPropagatedBin.setBit(x); - propagatedVars.push(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(); - } - if (!solver.varReplacer->replace(tmpPs, invert, 0)) - return false; - bothInvert += solver.varReplacer->getNewToReplaceVars() - toReplaceBefore; - toReplaceBefore = solver.varReplacer->getNewToReplaceVars(); - } - } - if (solver.assigns[x].getBool()) propValue.setBit(x); - else propValue.clearBit(x); - if (binXorFind) removeVarFromXors(x); - } - - 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); - if (!solver.varReplacer->replace(tmpPs, tmp.inverted, solver.xorclauses[*it]->getGroup())) - return false; - 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.cancelUntil(0); - } - - if (solver.addExtraBins && hyperbinProps < maxHyperBinProps) addBinClauses(lit2); - - for(uint32_t i = 0; i != bothSame.size(); i++) { - solver.uncheckedEnqueue(bothSame[i]); - } - goodBothSame += bothSame.size(); - solver.ok = (solver.propagate(false).isNULL()); - if (!solver.ok) return false; - - return true; -} - -struct litOrder -{ - litOrder(const vector& _litDegrees) : - litDegrees(_litDegrees) - {} - - bool operator () (const Lit& x, const Lit& y) { - return litDegrees[x.toInt()] > litDegrees[y.toInt()]; - } - - const vector& litDegrees; -}; - -void FailedVarSearcher::addBinClauses(const Lit& lit) -{ - uint64_t oldProps = solver.propagations; - #ifdef VERBOSE_DEBUG - std::cout << "Checking one BTC vs UP" << std::endl; - #endif //VERBOSE_DEBUG - vec toVisit; - - solver.newDecisionLevel(); - solver.uncheckedEnqueueLight(lit); - failed = (!solver.propagateBin().isNULL()); - assert(!failed); - - assert(solver.decisionLevel() > 0); - if (propagatedVars.size() - (solver.trail.size()-solver.trail_lim[0]) == 0) { - solver.cancelUntil(0); - 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); - } - solver.cancelUntil(0); - - std::sort(toVisit.getData(), toVisit.getDataEnd(), litOrder(litDegrees)); - /************************* - //To check that the ordering is the right way - // --> i.e. to avoid mistake present in Glucose's ordering - for (uint32_t i = 0; i < toVisit.size(); i++) { - std::cout << "i:" << std::setw(8) << i << " degree:" << litDegrees[toVisit[i].toInt()] << 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++) { - #ifdef VERBOSE_DEBUG - std::cout << "Checking visit level " << end-l-1 << std::endl; - uint32_t thisLevel = 0; - #endif //VERBOSE_DEBUG - fillImplies(*l); - if (unPropagatedBin.nothingInCommon(myimplies)) goto next; - for (const Var *var = propagatedVars.getData(), *end2 = propagatedVars.getDataEnd(); var != end2; var++) { - if (unPropagatedBin[*var] && myimplies[*var]) { - #ifdef VERBOSE_DEBUG - thisLevel++; - #endif //VERBOSE_DEBUG - addBin(~*l, Lit(*var, !propValue[*var])); - unPropagatedBin.removeThese(myImpliesSet); - if (unPropagatedBin.isZero()) { - myimplies.removeThese(myImpliesSet); - myImpliesSet.clear(); - goto end; - } - } - } - next: - myimplies.removeThese(myImpliesSet); - myImpliesSet.clear(); - #ifdef VERBOSE_DEBUG - if (thisLevel > 0) { - std::cout << "Added " << thisLevel << " level diff:" << end-l-1 << std::endl; - } - #endif //VERBOSE_DEBUG - } - assert(unPropagatedBin.isZero()); - - end: - hyperbinProps += solver.propagations - oldProps; -} - -void FailedVarSearcher::fillImplies(const Lit& lit) -{ - solver.newDecisionLevel(); - solver.uncheckedEnqueue(lit); - failed = (!solver.propagate().isNULL()); - assert(!failed); - - assert(solver.decisionLevel() > 0); - for (int c = solver.trail.size()-1; c >= (int)solver.trail_lim[0]; c--) { - Lit x = solver.trail[c]; - myimplies.setBit(x.var()); - myImpliesSet.push(x.var()); - } - solver.cancelUntil(0); -} - -void FailedVarSearcher::addBin(const Lit& lit1, const Lit& lit2) -{ - #ifdef VERBOSE_DEBUG - std::cout << "Adding extra bin: "; - lit1.print(); std::cout << " "; lit2.printFull(); - #endif //VERBOSE_DEBUG - - tmpPs[0] = lit1; - tmpPs[1] = lit2; - solver.addLearntClause(tmpPs, 0, 0); - tmpPs.growTo(2); - assert(solver.ok); -} - -template -inline void FailedVarSearcher::cleanAndAttachClauses(vec& cs) -{ - T **i = cs.getData(); - T **j = i; - for (T **end = cs.getDataEnd(); i != end; i++) { - if (cleanClause(**i)) { - solver.attachClause(**i); - *j++ = *i; - } else { - solver.clauseAllocator.clauseFree(*i); - } - } - cs.shrink(i-j); -} - -inline const bool FailedVarSearcher::cleanClause(Clause& ps) -{ - uint32_t origSize = ps.size(); - - 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); - assert(ps.size() > 1); - - if (ps.size() != origSize) ps.setStrenghtened(); - if (origSize != 2 && ps.size() == 2) - solver.becameBinary++; - - return true; -} - -inline const bool FailedVarSearcher::cleanClause(XorClause& ps) -{ - uint32_t origSize = ps.size(); - - 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); - - if (ps.size() == 0) return false; - assert(ps.size() > 1); - - if (ps.size() != origSize) ps.setStrenghtened(); - if (ps.size() == 2) { - ps[0] = ps[0].unsign(); - ps[1] = ps[1].unsign(); - solver.varReplacer->replace(ps, ps.xor_clause_inverted(), ps.getGroup()); - return false; - } - - return true; -} - -/*************** -UNTESTED CODE -***************** -const bool FailedVarSearcher::tryAll(const Lit* begin, const Lit* end) -{ - propagated.setZero(); - BitArray propagated2; - propagated2.resize(solver.nVars(), 0); - propValue.resize(solver.nVars(), 0); - bool first = true; - bool last = false; - - for (const Lit *it = begin; it != end; it++, first = false) { - if (it+1 == end) last = true; - - if (!first && !last) propagated2.setZero(); - solver.newDecisionLevel(); - solver.uncheckedEnqueue(*it); - failed = (solver.propagate(false) != NULL); - if (failed) { - solver.cancelUntil(0); - numFailed++; - solver.uncheckedEnqueue(~(*it)); - solver.ok = (solver.propagate(false) == NULL); - if (!solver.ok) return false; - return true; - } else { - assert(solver.decisionLevel() > 0); - for (int c = solver.trail.size()-1; c >= (int)solver.trail_lim[0]; c--) { - Var x = solver.trail[c].var(); - if (last) { - if (propagated[x] && propValue[x] == solver.assigns[x].getBool()) - bothSame.push_back(make_pair(x, !propValue[x])); - } else { - if (first) { - propagated.setBit(x); - if (solver.assigns[x].getBool()) - propValue.setBit(x); - else - propValue.clearBit(x); - } else if (propValue[x] == solver.assigns[x].getBool()) { - propagated2.setBit(x); - } - } - } - solver.cancelUntil(0); - } - if (!last && !first) { - propagated &= propagated2; - if (propagated.isZero()) return true; - } - } - - for(uint32_t i = 0; i != bothSame.size(); i++) { - solver.uncheckedEnqueue(Lit(bothSame[i].first, bothSame[i].second)); - } - goodBothSame += bothSame.size(); - bothSame.clear(); - solver.ok = (solver.propagate(false) == NULL); - if (!solver.ok) return false; - - return true; -} -************** -Untested code end -**************/ - -}; //NAMESPACE MINISAT diff --git a/src/sat/cryptominisat2/FailedVarSearcher.h b/src/sat/cryptominisat2/FailedVarSearcher.h deleted file mode 100644 index 5ea4c1e..0000000 --- a/src/sat/cryptominisat2/FailedVarSearcher.h +++ /dev/null @@ -1,155 +0,0 @@ -/*********************************************************************************** -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 . -**************************************************************************************************/ - -#ifndef FAILEDVARSEARCHER_H -#define FAILEDVARSEARCHER_H - -#include -#include -using std::map; - -#include "SolverTypes.h" -#include "Clause.h" -#include "BitArray.h" - -namespace MINISAT -{ -using namespace MINISAT; - -class Solver; - -class TwoLongXor -{ - public: - const bool operator==(const TwoLongXor& other) const - { - if (var[0] == other.var[0] && var[1] == other.var[1] && inverted == other.inverted) - return true; - return false; - } - const 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 FailedVarSearcher { - public: - FailedVarSearcher(Solver& _solver); - - const bool search(uint64_t numProps); - - private: - //For 2-long xor - const TwoLongXor getTwoLongXor(const XorClause& c); - void addFromSolver(const vec& cs); - uint32_t newBinXor; - - //For detach&re-attach (when lots of vars found) - template - void cleanAndAttachClauses(vec& cs); - const bool cleanClause(Clause& ps); - const bool cleanClause(XorClause& ps); - void completelyDetachAndReattach(); - - //For re-adding old removed learnt clauses - const bool readdRemovedLearnts(); - void removeOldLearnts(); - - //Main - const bool tryBoth(const Lit lit1, const Lit lit2); - const bool tryAll(const Lit* begin, const Lit* end); - void printResults(const double myTime) const; - - Solver& solver; - - //For failure - bool failed; - - //bothprop finding - BitArray propagated; - BitArray propValue; - vec bothSame; - - //2-long xor-finding - vec xorClauseSizes; - vector > occur; - void removeVarFromXors(const Var var); - void addVarFromXors(const Var var); - BitArray xorClauseTouched; - vec investigateXor; - std::set twoLongXors; - bool binXorFind; - uint32_t lastTrailSize; - - //2-long xor-finding no.2 through - // 1) (a->b, ~a->~b) -> a=b - // 2) binary clause (a,c): (a->g, c->~g) -> a = ~c - uint32_t bothInvert; - - //finding HyperBins - void addBinClauses(const Lit& lit); - BitArray unPropagatedBin; - vec propagatedVars; - void addBin(const Lit& lit1, const Lit& lit2); - void fillImplies(const Lit& lit); - BitArray myimplies; - vec myImpliesSet; - uint64_t hyperbinProps; - vector litDegrees; - const bool orderLits(); - uint64_t maxHyperBinProps; - uint64_t binClauseAdded; - - //Temporaries - vec tmpPs; - - //State for this run - uint32_t toReplaceBefore; - uint32_t origTrailSize; - uint64_t origProps; - uint32_t numFailed; - uint32_t goodBothSame; - - //State between runs - bool finishedLastTimeVar; - uint32_t lastTimeWentUntilVar; - bool finishedLastTimeBin; - uint32_t lastTimeWentUntilBin; - - double numPropsMultiplier; - uint32_t lastTimeFoundTruths; - - uint32_t numCalls; -}; - -}; //NAMESPACE MINISAT - -#endif //FAILEDVARSEARCHER_H - diff --git a/src/sat/cryptominisat2/FindUndef.cpp b/src/sat/cryptominisat2/FindUndef.cpp index 84d8a6c..95f2e4e 100644 --- a/src/sat/cryptominisat2/FindUndef.cpp +++ b/src/sat/cryptominisat2/FindUndef.cpp @@ -21,10 +21,6 @@ along with this program. If not, see . #include "VarReplacer.h" #include -namespace MINISAT -{ -using namespace MINISAT; - FindUndef::FindUndef(Solver& _solver) : solver(_solver) , isPotentialSum(0) @@ -37,7 +33,7 @@ void FindUndef::fillPotential() while(trail > 0) { assert(trail < (int)solver.trail_lim.size()); - uint at = solver.trail_lim[trail]; + uint32_t at = solver.trail_lim[trail]; assert(at > 0); Var v = solver.trail[at].var(); @@ -71,7 +67,7 @@ void FindUndef::fillPotential() void FindUndef::unboundIsPotentials() { - for (uint i = 0; i < isPotential.size(); i++) + for (uint32_t i = 0; i < isPotential.size(); i++) if (isPotential[i]) solver.assigns[i] = l_Undef; } @@ -79,19 +75,19 @@ void FindUndef::unboundIsPotentials() void FindUndef::moveBinToNormal() { binPosition = solver.clauses.size(); - for (uint i = 0; i != solver.binaryClauses.size(); i++) + for (uint32_t i = 0; i != solver.binaryClauses.size(); i++) solver.clauses.push(solver.binaryClauses[i]); solver.binaryClauses.clear(); } void FindUndef::moveBinFromNormal() { - for (uint i = binPosition; i != solver.clauses.size(); i++) + for (uint32_t i = binPosition; i != solver.clauses.size(); i++) solver.binaryClauses.push(solver.clauses[i]); solver.clauses.shrink(solver.clauses.size() - binPosition); } -const uint FindUndef::unRoll() +const uint32_t FindUndef::unRoll() { if (solver.decisionLevel() == 0) return 0; @@ -107,7 +103,7 @@ const uint FindUndef::unRoll() uint32_t maximum = 0; Var v = var_Undef; - for (uint i = 0; i < isPotential.size(); i++) { + for (uint32_t i = 0; i < isPotential.size(); i++) { if (isPotential[i] && satisfies[i] >= maximum) { maximum = satisfies[i]; v = i; @@ -131,7 +127,7 @@ bool FindUndef::updateTables() { bool allSat = true; - uint i = 0; + uint32_t i = 0; for (Clause** it = solver.clauses.getData(), **end = it + solver.clauses.size(); it != end; it++, i++) { if (dontLookAtClause[i]) continue; @@ -139,7 +135,7 @@ bool FindUndef::updateTables() Clause& c = **it; bool definitelyOK = false; Var v = var_Undef; - uint numTrue = 0; + uint32_t numTrue = 0; for (Lit *l = c.getData(), *end = l + c.size(); l != end; l++) { if (solver.value(*l) == l_True) { if (!isPotential[l->var()]) { @@ -174,4 +170,3 @@ bool FindUndef::updateTables() return allSat; } -}; //NAMESPACE MINISAT diff --git a/src/sat/cryptominisat2/FindUndef.h b/src/sat/cryptominisat2/FindUndef.h index d3612ac..e9a1bca 100644 --- a/src/sat/cryptominisat2/FindUndef.h +++ b/src/sat/cryptominisat2/FindUndef.h @@ -28,14 +28,10 @@ using std::vector; #include "Solver.h" -namespace MINISAT -{ -using namespace MINISAT; - class FindUndef { public: FindUndef(Solver& _solver); - const uint unRoll(); + const uint32_t unRoll(); private: Solver& solver; @@ -54,6 +50,4 @@ class FindUndef { }; -}; //NAMESPACE MINISAT - -#endif // \ No newline at end of file +#endif // diff --git a/src/sat/cryptominisat2/Gaussian.cpp b/src/sat/cryptominisat2/Gaussian.cpp index e5edc50..3088a0f 100644 --- a/src/sat/cryptominisat2/Gaussian.cpp +++ b/src/sat/cryptominisat2/Gaussian.cpp @@ -1,4 +1,4 @@ -/*********************************************************************************** +/*************************************************************************** CryptoMiniSat -- Copyright (c) 2009 Mate Soos This program is free software: you can redistribute it and/or modify @@ -13,7 +13,7 @@ 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 . -**************************************************************************************************/ +*****************************************************************************/ #include "Gaussian.h" @@ -22,32 +22,24 @@ along with this program. If not, see . #include "Clause.h" #include #include "ClauseCleaner.h" +#include "VarReplacer.h" +#include "DataSync.h" using std::ostream; using std::cout; using std::endl; +//#define VERBOSE_DEBUG +//#define DEBUG_GAUSS + #ifdef VERBOSE_DEBUG #include #endif -namespace MINISAT -{ -using namespace MINISAT; static const uint16_t unassigned_col = std::numeric_limits::max(); static const Var unassigned_var = std::numeric_limits::max(); -ostream& operator << (ostream& os, const vec& v) -{ - for (uint32_t i = 0; i != v.size(); i++) { - if (v[i].sign()) os << "-"; - os << v[i].var()+1 << " "; - } - - return os; -} - -Gaussian::Gaussian(Solver& _solver, const GaussianConfig& _config, const uint _matrix_no, const vector& _xorclauses) : +Gaussian::Gaussian(Solver& _solver, const GaussConf& _config, const uint32_t _matrix_no, const vector& _xorclauses) : solver(_solver) , config(_config) , matrix_no(_matrix_no) @@ -64,15 +56,15 @@ Gaussian::Gaussian(Solver& _solver, const GaussianConfig& _config, const uint _m Gaussian::~Gaussian() { - for (uint i = 0; i < clauses_toclear.size(); i++) + for (uint32_t i = 0; i < clauses_toclear.size(); i++) solver.clauseAllocator.clauseFree(clauses_toclear[i].first); } inline void Gaussian::set_matrixset_to_cur() { - uint level = solver.decisionLevel() / config.only_nth_gauss_save; + 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 @@ -82,22 +74,26 @@ inline void Gaussian::set_matrixset_to_cur() const 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(); - Clause* confl; + 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: @@ -125,7 +121,7 @@ void Gaussian::init() badlevel = 0; return; } - + matrix_sets.clear(); matrix_sets.push_back(cur_matrixset); gauss_last_level = solver.trail.size(); @@ -137,28 +133,28 @@ void Gaussian::init() #endif } -uint Gaussian::select_columnorder(vector& var_to_col, matrixset& origMat) +uint32_t Gaussian::select_columnorder(vector& var_to_col, matrixset& origMat) { var_to_col.resize(solver.nVars(), unassigned_col); - uint num_xorclauses = 0; + uint32_t num_xorclauses = 0; for (uint32_t i = 0; i != xorclauses.size(); i++) { XorClause& c = *xorclauses[i]; - if (c.removed()) continue; + if (c.getRemoved()) continue; num_xorclauses++; - - for (uint i2 = 0; i2 < c.size(); i2++) { + + 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; } } - - uint largest_used_var = 0; - for (uint i = 0; i < var_to_col.size(); i++) + + 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); @@ -180,11 +176,11 @@ uint Gaussian::select_columnorder(vector& var_to_col, matrixset& origM else v = vars[iterReduceIt++]; if (var_to_col[v] == 1) { #ifdef DEBUG_GAUSS - vector::iterator it = + vector::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); @@ -192,7 +188,7 @@ uint Gaussian::select_columnorder(vector& var_to_col, matrixset& origM } //for the ones that were not in the order_heap, but are marked in var_to_col - for (uint v = 0; v != var_to_col.size(); v++) { + 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; @@ -200,9 +196,9 @@ uint Gaussian::select_columnorder(vector& var_to_col, matrixset& origM } } - #ifdef VERBOSE_DEBUG + #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(cout, ",")); + std::copy(origMat.col_to_var.begin(), origMat.col_to_var.end(), std::ostream_iterator(cout, ",")); cout << endl; #endif @@ -220,12 +216,12 @@ void Gaussian::fill_matrix(matrixset& 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(char)*changed_rows.size()); + 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); @@ -234,10 +230,10 @@ void Gaussian::fill_matrix(matrixset& origMat) cout << "(" << matrix_no << ")matrix size:" << origMat.num_rows << "," << origMat.num_cols << endl; #endif - uint matrix_row = 0; + uint32_t matrix_row = 0; for (uint32_t i = 0; i != xorclauses.size(); i++) { const XorClause& c = *xorclauses[i]; - if (c.removed()) continue; + 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); @@ -246,23 +242,23 @@ void Gaussian::fill_matrix(matrixset& origMat) assert(origMat.num_rows == matrix_row); } -void Gaussian::update_matrix_col(matrixset& m, const Var var, const uint col) +void Gaussian::update_matrix_col(matrixset& m, const Var var, const uint32_t col) { - #ifdef VERBOSE_DEBUG + #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(); - uint row_num = 0; + uint32_t row_num = 0; if (solver.assigns[var].getBool()) { - for (uint end = m.last_one_in_col[col]; row_num != end; ++this_row, row_num++) { + 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(); @@ -270,7 +266,7 @@ void Gaussian::update_matrix_col(matrixset& m, const Var var, const uint col) } } } else { - for (uint end = m.last_one_in_col[col]; row_num != end; ++this_row, row_num++) { + 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); @@ -294,19 +290,21 @@ 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); - uint num_updated = 0; #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(char)*changed_rows.size()); - uint last = 0; - uint col = 0; + 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); @@ -318,16 +316,18 @@ void Gaussian::update_matrix_by_col_all(matrixset& m) 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(); @@ -341,7 +341,7 @@ inline void Gaussian::update_last_one_in_col(matrixset& m) *i = m.num_rows; } -Gaussian::gaussian_ret Gaussian::gaussian(Clause*& confl) +Gaussian::gaussian_ret Gaussian::gaussian(PropBy& confl) { if (solver.decisionLevel() >= badlevel) return nothing; @@ -350,8 +350,8 @@ Gaussian::gaussian_ret Gaussian::gaussian(Clause*& confl) #ifdef VERBOSE_DEBUG cout << "(" << matrix_no << ")matrix needs copy before update" << endl; #endif - - const uint level = solver.decisionLevel() / config.only_nth_gauss_save; + + const uint32_t level = solver.decisionLevel() / config.only_nth_gauss_save; assert(level < matrix_sets.size()); cur_matrixset = matrix_sets[level]; } @@ -363,32 +363,32 @@ Gaussian::gaussian_ret Gaussian::gaussian(Clause*& confl) badlevel = UINT_MAX; propagatable_rows.clear(); - uint conflict_row = UINT_MAX; - uint last_row = eliminate(cur_matrixset, conflict_row); + uint32_t conflict_row = UINT_MAX; + uint32_t last_row = eliminate(cur_matrixset, conflict_row); #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) { - uint maxlevel = UINT_MAX; - uint size = UINT_MAX; - uint best_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 || nothing_to_propagate(cur_matrixset)); + 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 nothing; + return ret; } - + if (ret == nothing && solver.decisionLevel() % config.only_nth_gauss_save == 0) set_matrixset_to_cur(); @@ -405,40 +405,42 @@ Gaussian::gaussian_ret Gaussian::gaussian(Clause*& confl) return ret; } -uint Gaussian::eliminate(matrixset& m, uint& conflict_row) +uint32_t Gaussian::eliminate(matrixset& m, uint32_t& conflict_row) { #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); - - uint number_of_row_additions = 0; - uint no_exchanged = 0; #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 - uint i = 0; - uint j = (config.iterativeReduce) ? m.least_column_changed + 1 : 0; + 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]) @@ -446,19 +448,19 @@ uint Gaussian::eliminate(matrixset& m, uint& conflict_row) 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 @@ -485,7 +487,7 @@ uint Gaussian::eliminate(matrixset& m, uint& conflict_row) #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; @@ -509,7 +511,7 @@ uint Gaussian::eliminate(matrixset& m, uint& conflict_row) #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()) { @@ -527,7 +529,7 @@ uint Gaussian::eliminate(matrixset& m, uint& conflict_row) } j++; } - + finish: m.least_column_changed = INT_MAX; @@ -535,20 +537,22 @@ uint Gaussian::eliminate(matrixset& m, uint& conflict_row) #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)); - uint row = 0; - uint col = 0; + 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 + #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); @@ -561,29 +565,28 @@ uint Gaussian::eliminate(matrixset& m, uint& conflict_row) return i; } -Gaussian::gaussian_ret Gaussian::handle_matrix_confl(Clause*& confl, const matrixset& m, const uint size, const uint maxlevel, const uint best_row) +Gaussian::gaussian_ret Gaussian::handle_matrix_confl(PropBy& confl, const matrixset& m, const uint32_t size, const uint32_t maxlevel, const uint32_t best_row) { assert(best_row != UINT_MAX); - m.matrix.getVarsetAt(best_row).fill(tmp_clause, solver.assigns, col_to_var_original); - confl = (Clause*)solver.clauseAllocator.XorClause_new(tmp_clause, false, solver.learnt_clause_group++); - Clause& cla = *confl; - #ifdef STATS_NEEDED - if (solver.dynamic_behaviour_analysis) - solver.logger.set_group_name(confl->getGroup(), "learnt gauss clause"); - #endif - - if (cla.size() <= 1) { - solver.ok = false; - return unit_conflict; - } + 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); + assert(!wasUndef); - assert(cla.size() >= 2); #ifdef VERBOSE_DEBUG - cout << "(" << matrix_no << ")Found conflict:"; - cla.plainPrint(); + 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]); + solver.ok = false; + } else confl = PropBy(); + return unit_conflict; + } + if (maxlevel != solver.decisionLevel()) { #ifdef STATS_NEEDED if (solver.dynamic_behaviour_analysis) @@ -591,38 +594,81 @@ Gaussian::gaussian_ret Gaussian::handle_matrix_confl(Clause*& confl, const matri #endif solver.cancelUntil(maxlevel); } - const uint curr_dec_level = solver.decisionLevel(); + const uint32_t curr_dec_level = solver.decisionLevel(); assert(maxlevel == curr_dec_level); - - uint maxsublevel = 0; - uint maxsublevel_at = UINT_MAX; - for (uint i = 0, size = cla.size(); i != size; i++) if (solver.level[cla[i].var()] == (int32_t)curr_dec_level) { - uint tmp = find_sublevel(cla[i].var()); - if (tmp >= maxsublevel) { - maxsublevel = tmp; - maxsublevel_at = i; + + 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, solver.learnt_clause_group++); + confl = solver.clauseAllocator.getOffset(conflPtr); + Clause& cla = *conflPtr; + + #ifdef STATS_NEEDED + if (solver.dynamic_behaviour_analysis) + solver.logger.set_group_name(cla.getGroup(), "learnt gauss clause"); + #endif + + 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; } - #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, uint last_row, Clause*& confl) +Gaussian::gaussian_ret Gaussian::handle_matrix_prop_and_confl(matrixset& m, uint32_t last_row, PropBy& confl) { int32_t maxlevel = std::numeric_limits::max(); - uint size = UINT_MAX; - uint best_row = UINT_MAX; + uint32_t size = UINT_MAX; + uint32_t best_row = UINT_MAX; - for (uint row = last_row; row != m.num_rows; row++) { + for (uint32_t row = last_row; row != m.num_rows; row++) { #ifdef DEBUG_GAUSS assert(m.matrix.getMatrixAt(row).isZero()); #endif @@ -637,7 +683,7 @@ Gaussian::gaussian_ret Gaussian::handle_matrix_prop_and_confl(matrixset& m, uint 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 @@ -646,8 +692,8 @@ Gaussian::gaussian_ret Gaussian::handle_matrix_prop_and_confl(matrixset& m, uint gaussian_ret ret = nothing; - uint num_props = 0; - for (const uint* prop_row = propagatable_rows.getData(), *end = prop_row + propagatable_rows.size(); prop_row != end; prop_row++ ) { + 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++; @@ -665,25 +711,25 @@ Gaussian::gaussian_ret Gaussian::handle_matrix_prop_and_confl(matrixset& m, uint return ret; } -uint Gaussian::find_sublevel(const Var v) const +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 uint until_sublevel) +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::iterator gauss = solver.gauss_matrixes.begin(), end= solver.gauss_matrixes.end(); gauss != end; gauss++) if (*gauss != this) (*gauss)->canceling(until_sublevel); @@ -700,13 +746,13 @@ void Gaussian::cancel_until_sublevel(const uint until_sublevel) 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 uint row, int32_t& maxlevel, uint& size, uint& best_row) const +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); @@ -714,17 +760,19 @@ void Gaussian::analyse_confl(const matrixset& m, const uint row, int32_t& maxlev #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; - uint this_size = 0; + uint32_t this_size = 0; while (true) { var = m.matrix.getVarsetAt(row).scan(var); if (var == ULONG_MAX) break; @@ -745,14 +793,14 @@ void Gaussian::analyse_confl(const matrixset& m, const uint row, int32_t& maxlev || (this_size <= 1) )) { assert(maxlevel != std::numeric_limits::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; } @@ -772,39 +820,54 @@ void Gaussian::analyse_confl(const matrixset& m, const uint row, int32_t& maxlev best_row = row; } -Gaussian::gaussian_ret Gaussian::handle_matrix_prop(matrixset& m, const uint row) +Gaussian::gaussian_ret Gaussian::handle_matrix_prop(matrixset& m, const uint32_t row) { #ifdef VERBOSE_DEBUG - cout << "(" << matrix_no << ")matrix prop found!" << endl; - cout << m.matrix.getMatrixAt(row) << endl; - cout << "(" << matrix_no << ")matrix row:"; - print_matrix_row(m.matrix.getMatrixAt(row)); - cout << endl; + 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); - Clause& cla = *(Clause*)solver.clauseAllocator.XorClause_new(tmp_clause, false, solver.learnt_clause_group++); #ifdef VERBOSE_DEBUG - cout << "(" << matrix_no << ")matrix prop clause: "; - cla.plainPrint(); + cout << "(" << matrix_no << ")matrix prop clause: " << tmp_clause << std::endl; cout << endl; #endif - - assert(m.matrix.getMatrixAt(row).is_true() == !cla[0].sign()); - assert(solver.assigns[cla[0].var()].isUndef()); - if (cla.size() == 1) { - solver.cancelUntil(0); - solver.uncheckedEnqueue(cla[0]); - solver.clauseAllocator.clauseFree(&cla); - return unit_propagation; - } - clauses_toclear.push_back(std::make_pair(&cla, solver.trail.size()-1)); - #ifdef STATS_NEEDED - if (solver.dynamic_behaviour_analysis) - solver.logger.set_group_name(cla.getGroup(), "gauss prop clause"); - #endif - solver.uncheckedEnqueue(cla[0], &cla); + 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, 0); + assert(cl == NULL); + assert(solver.ok); + return unit_propagation; + break; + } + default: + Clause& cla = *(Clause*)solver.clauseAllocator.XorClause_new(tmp_clause, xorEqualFalse, solver.learnt_clause_group++); + 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)); + #ifdef STATS_NEEDED + if (solver.dynamic_behaviour_analysis) + solver.logger.set_group_name(cla.getGroup(), "gauss prop clause"); + #endif + solver.uncheckedEnqueue(cla[0], solver.clauseAllocator.getOffset(&cla)); + return propagation; + } return propagation; } @@ -815,25 +878,26 @@ void Gaussian::disable_if_necessary() //&& conflictC >= nof_conflicts/8 !config.dontDisable && called > 50 - && useful_confl*2+useful_prop < (uint)((double)called*0.05) ) + && useful_confl*2+useful_prop < (uint32_t)((double)called*0.05) ) disabled = true; } -llbool Gaussian::find_truths(vec& learnt_clause, int& conflictC) +llbool Gaussian::find_truths(vec& learnt_clause, uint64_t& conflictC) { - Clause* confl; + PropBy confl; disable_if_necessary(); if (should_check_gauss(solver.decisionLevel(), solver.starts)) { called++; gaussian_ret g = gaussian(confl); - + switch (g) { case conflict: { useful_confl++; llbool ret = solver.handle_conflict(learnt_clause, confl, conflictC, true); - solver.clauseAllocator.clauseFree(confl); - + if (confl.isClause()) + solver.clauseAllocator.clauseFree(solver.clauseAllocator.getPointer(confl.getClause())); + if (ret != l_Nothing) return ret; return l_Continue; } @@ -845,27 +909,37 @@ llbool Gaussian::find_truths(vec& learnt_clause, int& conflictC) case unit_conflict: { unit_truths++; useful_confl++; - if (confl->size() == 0) { - solver.clauseAllocator.clauseFree(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)[0]; + Lit lit = confl.getOtherLit(); #ifdef STATS_NEEDED if (solver.dynamic_behaviour_analysis) solver.logger.conflict(Logger::gauss_confl_type, 0, confl->getGroup(), *confl); #endif - + solver.cancelUntil(0); - - if (solver.assigns[lit.var()].isDef()) { - solver.clauseAllocator.clauseFree(confl); + + #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); - - solver.clauseAllocator.clauseFree(confl); return l_Continue; } case nothing: @@ -897,7 +971,7 @@ void Gaussian::print_matrix_row_with_assigns(const T& row) const 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]) << ")"; @@ -905,7 +979,7 @@ void Gaussian::print_matrix_row_with_assigns(const T& row) const } col++; } - if (!row.is_true()) cout << "xor_clause_inverted"; + if (!row.is_true()) cout << "xorEqualFalse"; } const string Gaussian::lbool_to_string(const lbool toprint) @@ -916,7 +990,7 @@ const string Gaussian::lbool_to_string(const lbool toprint) return "false"; if (toprint == l_Undef) return "undef"; - + assert(false); return ""; } @@ -950,7 +1024,7 @@ void Gaussian::reset_stats() bool Gaussian::check_no_conflict(matrixset& m) const { - uint row = 0; + 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; @@ -962,7 +1036,7 @@ bool Gaussian::check_no_conflict(matrixset& m) const void Gaussian::print_matrix(matrixset& m) const { - uint row = 0; + 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) @@ -973,7 +1047,7 @@ void Gaussian::print_matrix(matrixset& m) const void Gaussian::print_last_one_in_cols(matrixset& m) const { - for (uint i = 0; i < m.num_cols; i++) { + 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; } } @@ -982,22 +1056,30 @@ const 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()) + && 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()) + 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; } const bool Gaussian::check_last_one_in_cols(matrixset& m) const { - for(uint i = 0; i < m.num_cols; i++) { - const uint last = std::min(m.last_one_in_col[i] - 1, (int)m.num_rows); - uint real_last = 0; - uint i2 = 0; + 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; @@ -1005,25 +1087,25 @@ const bool Gaussian::check_last_one_in_cols(matrixset& m) const if (real_last > last) return false; } - + return true; } void Gaussian::check_matrix_against_varset(PackedMatrix& matrix, const matrixset& m) const { - for (uint i = 0; i < matrix.getSize(); i++) { + 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); @@ -1038,7 +1120,7 @@ void Gaussian::check_matrix_against_varset(PackedMatrix& matrix, const matrixset assert(!m.var_is_set[var]); assert(mat_row[col]); } else assert(false); - + col++; } if ((final^!mat_row.is_true()) != !var_row.is_true()) { @@ -1048,7 +1130,7 @@ void Gaussian::check_matrix_against_varset(PackedMatrix& matrix, const matrixset } } -const void Gaussian::check_first_one_in_row(matrixset& m, const uint j) +const 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); @@ -1058,7 +1140,7 @@ const void Gaussian::check_first_one_in_row(matrixset& m, const uint j) 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 (uint i2 = 0; i2 != until2; i2++) { + 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; @@ -1069,8 +1151,8 @@ const void Gaussian::check_first_one_in_row(matrixset& m, const uint j) 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 (uint i3 = 0; i3 < m.first_one_in_row[i2]; i3++) { + + 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]]); @@ -1086,16 +1168,16 @@ const void Gaussian::check_first_one_in_row(matrixset& m, const uint j) { #ifdef VERBOSE_DEBUG cout << "Updating matrix." << endl; - uint num_updated = 0; + uint32_t num_updated = 0; #endif #ifdef DEBUG_GAUSS assert(nothing_to_propagate(cur_matrixset)); #endif mpz_class toclear, tocount; - uint last_col = 0; + uint32_t last_col = 0; - for (uint col = 0; col < m.num_cols; col ++) { + for (uint32_t col = 0; col < m.num_cols; col ++) { Var var = m.col_to_var[col]; if (var != UINT_MAX && !solver.assigns[var].isUndef()) { @@ -1120,7 +1202,7 @@ const void Gaussian::check_first_one_in_row(matrixset& m, const uint j) toclear.invert(); mpz_class tmp; mpz_class* this_row = &m.matrix[0]; - for(uint i = 0, until = std::min(m.num_rows, m.last_one_in_col[last_col]+1); i < until; i++, this_row++) { + for(uint32_t i = 0, until = std::min(m.num_rows, m.last_one_in_col[last_col]+1); i < until; i++, this_row++) { mpz_class& r = *this_row; mpz_and(tmp.get_mp(), tocount.get_mp(), r.get_mp()); r.invert_is_true(tmp.popcnt() % 2); @@ -1132,11 +1214,11 @@ const void Gaussian::check_first_one_in_row(matrixset& m, const uint j) #endif }*/ -/*void Gaussian::update_matrix_by_col(matrixset& m, const uint last_level) const +/*void Gaussian::update_matrix_by_col(matrixset& m, const uint32_t last_level) const { #ifdef VERBOSE_DEBUG cout << "Updating matrix." << endl; - uint num_updated = 0; + uint32_t num_updated = 0; #endif #ifdef DEBUG_GAUSS assert(nothing_to_propagate(cur_matrixset)); @@ -1144,7 +1226,7 @@ const void Gaussian::check_first_one_in_row(matrixset& m, const uint j) for (int level = solver.trail.size()-1; level >= last_level; level--){ Var var = solver.trail[level].var(); - const uint col = m.var_to_col[var]; + const uint32_t col = m.var_to_col[var]; if ( col < UINT_MAX-1) { update_matrix_col(m, var, col); #ifdef VERBOSE_DEBUG @@ -1157,5 +1239,3 @@ const void Gaussian::check_first_one_in_row(matrixset& m, const uint j) cout << "Updated " << num_updated << " matrix cols. Could remove " << m.removeable_cols << " cols (out of " << m.num_cols << " )" <. #include #include +#include +#include +using std::string; +using std::pair; + #ifdef _MSC_VER #include #else @@ -41,48 +46,46 @@ using std::cout; using std::endl; #endif -namespace MINISAT -{ -using namespace MINISAT; - class Clause; class Gaussian { public: - Gaussian(Solver& solver, const GaussianConfig& config, const uint matrix_no, const vector& xorclauses); + Gaussian(Solver& solver, const GaussConf& config, const uint32_t matrix_no, const vector& xorclauses); ~Gaussian(); const bool full_init(); - llbool find_truths(vec& learnt_clause, int& conflictC); + llbool find_truths(vec& learnt_clause, uint64_t& conflictC); //statistics void print_stats() const; void print_matrix_stats() const; - const uint get_called() const; - const uint get_useful_prop() const; - const uint get_useful_confl() const; + const uint32_t get_called() const; + const uint32_t get_useful_prop() const; + const uint32_t get_useful_confl() const; const bool get_disabled() const; const uint32_t get_unit_truths() const; void set_disabled(const bool toset); //functions used throughout the Solver - void canceling(const uint sublevel); + void canceling(const uint32_t sublevel); + + friend class ClauseAllocator; protected: Solver& solver; - + //Gauss high-level configuration - const GaussianConfig& config; - const uint matrix_no; + const GaussConf& config; + const uint32_t matrix_no; vector xorclauses; enum gaussian_ret {conflict, unit_conflict, propagation, unit_propagation, nothing}; - gaussian_ret gaussian(Clause*& confl); + gaussian_ret gaussian(PropBy& confl); vector 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] - uint badlevel; + uint32_t badlevel; class matrixset { @@ -91,11 +94,11 @@ protected: BitArray var_is_set; vector 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) - uint num_cols; // number of active columns in the matrix. The columns at the end that have all be zeroed are no longer active + 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 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 first_one_in_row; - uint removeable_cols; // the number of columns that have been zeroed out (i.e. assigned) + uint32_t removeable_cols; // the number of columns that have been zeroed out (i.e. assigned) }; //Saved states @@ -105,55 +108,55 @@ protected: //Varibales to keep Gauss state bool messed_matrix_vars_since_reversal; int gauss_last_level; - vector > clauses_toclear; + vector > clauses_toclear; bool disabled; // Gauss is disabled - + //State of current elimnation - vec propagatable_rows; //used to store which rows were deemed propagatable during elimination + vec propagatable_rows; //used to store which rows were deemed propagatable during elimination vector changed_rows; //used to store which rows were deemed propagatable during elimination //Statistics - uint useful_prop; //how many times Gauss gave propagation as a result - uint useful_confl; //how many times Gauss gave conflict as a result - uint called; //how many times called the Gauss + 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 - uint select_columnorder(vector& var_to_col, matrixset& origMat); // Fills var_to_col and col_to_var of the origMat matrix. + uint32_t select_columnorder(vector& var_to_col, matrixset& origMat); // Fills var_to_col and col_to_var of the origMat matrix. //Main function - uint eliminate(matrixset& matrix, uint& conflict_row); //does the actual gaussian elimination + uint32_t eliminate(matrixset& matrix, uint32_t& conflict_row); //does the actual gaussian elimination //matrix update functions - void update_matrix_col(matrixset& matrix, const Var x, const uint col); // Update one matrix column + 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 uint last_level) 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, uint row, Clause*& confl); - void analyse_confl(const matrixset& m, const uint row, int32_t& maxlevel, uint& size, uint& 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(Clause*& confl, const matrixset& m, const uint size, const uint maxlevel, const uint best_row); - gaussian_ret handle_matrix_prop(matrixset& m, const uint row); // Handle matrix propagation at row 'row' + 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 size, 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 tmp_clause; //propagation&conflict handling - void cancel_until_sublevel(const uint 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 - uint find_sublevel(const Var v) const; // find the sublevel (i.e. trail[X]) of a given variable + 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 uint decisionlevel, const uint starts) const; + bool should_check_gauss(const uint32_t decisionlevel, const uint32_t starts) 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? const bool nothing_to_propagate(matrixset& m) const; // Are there any conflicts of propagations that matrixset 'm' clauses? @@ -163,7 +166,7 @@ private: void print_matrix_row_with_assigns(const T& row) const; void check_matrix_against_varset(PackedMatrix& matrix,const matrixset& m) const; const bool check_last_one_in_cols(matrixset& m) const; - const void check_first_one_in_row(matrixset& m, const uint j); + 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 const string lbool_to_string(const lbool toprint); @@ -174,23 +177,23 @@ inline bool Gaussian::should_init() const return (config.decision_until > 0); } -inline bool Gaussian::should_check_gauss(const uint decisionlevel, const uint starts) const +inline bool Gaussian::should_check_gauss(const uint32_t decisionlevel, const uint32_t starts) const { return (!disabled && decisionlevel < config.decision_until); } -inline void Gaussian::canceling(const uint sublevel) +inline void Gaussian::canceling(const uint32_t sublevel) { if (disabled) return; - uint a = 0; + 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); @@ -210,17 +213,17 @@ inline const uint32_t Gaussian::get_unit_truths() const return unit_truths; } -inline const uint Gaussian::get_called() const +inline const uint32_t Gaussian::get_called() const { return called; } -inline const uint Gaussian::get_useful_prop() const +inline const uint32_t Gaussian::get_useful_prop() const { return useful_prop; } -inline const uint Gaussian::get_useful_confl() const +inline const uint32_t Gaussian::get_useful_confl() const { return useful_confl; } @@ -237,6 +240,4 @@ inline void Gaussian::set_disabled(const bool toset) std::ostream& operator << (std::ostream& os, const vec& v); -}; //NAMESPACE MINISAT - #endif //GAUSSIAN_H diff --git a/src/sat/cryptominisat2/GaussianConfig.h b/src/sat/cryptominisat2/GaussianConfig.h index 0806f83..40c4522 100644 --- a/src/sat/cryptominisat2/GaussianConfig.h +++ b/src/sat/cryptominisat2/GaussianConfig.h @@ -26,15 +26,11 @@ along with this program. If not, see . #include "PackedRow.h" -namespace MINISAT -{ -using namespace MINISAT; - -class GaussianConfig +class GaussConf { public: - - GaussianConfig() : + + GaussConf() : only_nth_gauss_save(2) , decision_until(0) , dontDisable(false) @@ -43,20 +39,20 @@ class GaussianConfig , iterativeReduce(true) , maxMatrixRows(1000) , minMatrixRows(20) + , maxNumMatrixes(3) { } - + //tuneable gauss parameters - uint only_nth_gauss_save; //save only every n-th gauss matrix - uint decision_until; //do Gauss until this level + 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 }; -}; //NAMESPACE MINISAT - #endif //GAUSSIANCONFIG_H diff --git a/src/sat/cryptominisat2/Logger.cpp b/src/sat/cryptominisat2/Logger.cpp index 59013e5..f76fbb7 100644 --- a/src/sat/cryptominisat2/Logger.cpp +++ b/src/sat/cryptominisat2/Logger.cpp @@ -39,10 +39,6 @@ using std::ofstream; #define SND_WIDTH 35 #define TRD_WIDTH 10 -namespace MINISAT -{ -using namespace MINISAT; - Logger::Logger(int& _verbosity) : proof_graph_on(false) , mini_proof(false) @@ -719,7 +715,6 @@ void Logger::print_general_stats() const print_line("Number of clauses", S->nClauses()); print_line("Number of literals in clauses",S->clauses_literals); print_line("Avg. literals per learnt clause",(double)S->learnts_literals/(double)S->nLearnts()); - print_line("Progress estimate (%):", S->progress_estimate*100.0); print_line("All unitary learnts until now", S->get_unitary_learnts_num()); print_footer(); } @@ -906,4 +901,3 @@ void Logger::reset_statistics() last_unitary_learnt_clauses = S->get_unitary_learnts_num(); } -}; //NAMESPACE MINISAT diff --git a/src/sat/cryptominisat2/Logger.h b/src/sat/cryptominisat2/Logger.h index 7567c7a..a7c4dc3 100644 --- a/src/sat/cryptominisat2/Logger.h +++ b/src/sat/cryptominisat2/Logger.h @@ -43,10 +43,6 @@ using std::pair; using std::string; using std::map; -namespace MINISAT -{ -using namespace MINISAT; - class Solver; class MyAvg { @@ -185,6 +181,4 @@ private: uint proofStarts; }; -}; //NAMESPACE MINISAT - #endif //LOGGER_H diff --git a/src/sat/cryptominisat2/MTRand/MersenneTwister.h b/src/sat/cryptominisat2/MTRand/MersenneTwister.h index 964ecc7..16e6458 100644 --- a/src/sat/cryptominisat2/MTRand/MersenneTwister.h +++ b/src/sat/cryptominisat2/MTRand/MersenneTwister.h @@ -57,18 +57,15 @@ #ifndef MERSENNETWISTER_H #define MERSENNETWISTER_H +// Not thread safe (unless auto-initialization is avoided and each thread has +// its own MTRand object) + #include #include #include #include #include -namespace MINISAT -{ - -// Not thread safe (unless auto-initialization is avoided and each thread has -// its own MTRand object) - class MTRand { // Data public: @@ -382,7 +379,6 @@ inline std::istream& operator>>( std::istream& is, MTRand& mtrand ) mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left]; return is; } -}; #endif // MERSENNETWISTER_H diff --git a/src/sat/cryptominisat2/Main.cpp b/src/sat/cryptominisat2/Main.cpp index 3939611..7433cae 100644 --- a/src/sat/cryptominisat2/Main.cpp +++ b/src/sat/cryptominisat2/Main.cpp @@ -1,22 +1,34 @@ -/******************************************************************************************[Main.C] +/***************************************************************************** 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: +Original code by MiniSat authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3 licence. +******************************************************************************/ -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. +/** +@mainpage CryptoMiniSat +@author Mate Soos, and collaborators -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. -**************************************************************************************************/ +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 #include @@ -25,403 +37,164 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include #include #include -#include +#include #ifdef _MSC_VER #include #else #include #endif //_MSC_VER +#include +#include #include -#ifndef DISABLE_ZLIB -#include -#endif // DISABLE_ZLIB - +#ifdef STATS_NEEDED #include "Logger.h" -#include "Solver.h" +#endif //STATS_NEEDED + #include "time_mem.h" #include "constants.h" +#include "DimacsParser.h" -using std::cout; -using std::endl; - -/*************************************************************************************/ #if defined(__linux__) #include #endif -using namespace MINISAT; - -namespace MINISAT +#include "Main.h" + +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) { +} -static bool grouping = false; -static bool debugLib = false; -static bool debugNewVar = false; -static char learnts_filename[500]; -static bool dumpLearnts = false; -static uint32_t maxLearntsSize = std::numeric_limits::max(); -static bool printResult = true; - -//================================================================================================= -// DIMACS Parser: +std::map solversToInterrupt; +std::set finished; -#define CHUNK_LIMIT 1048576 -#define MAX_NAMES_SIZE 1000 +/** +@brief For correctly and gracefully exiting -class StreamBuffer +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 signum) { -#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 + #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); } } - -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(); - } -}; - -//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -template -static void skipWhitespace(B& in) -{ - while ((*in >= 9 && *in <= 13) || *in == 32) - ++in; } -template -static void skipLine(B& in) +void Main::readInAFile(const std::string& filename, Solver& solver) { - for (;;) { - if (*in == EOF || *in == '\0') return; - if (*in == '\n') { - ++in; - return; - } - ++in; + if (solver.conf.verbosity >= 1) { + std::cout << "c Reading file '" << filename << "'" << std::endl; } -} -template -static void untilEnd(B& in, char* ret) -{ - uint32_t sizeRead = 0; - for (;sizeRead < MAX_NAMES_SIZE-1; sizeRead++) { - if (*in == EOF || *in == '\0') return; - if (*in == '\n') { - return; - } - *ret = *in; - ret++; - *ret = '\0'; - ++in; + char* fname = (char*)calloc(filename.length()+1, sizeof(char)); + assert(fname != NULL); + memcpy(fname, filename.c_str(), filename.length()); + fname[filename.length()] = '\0'; + #ifdef DISABLE_ZLIB + FILE * in = fopen(fname, "rb"); + #else + gzFile in = gzopen(fname, "rb"); + #endif // DISABLE_ZLIB + free(fname); + + 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); -template -static int parseInt(B& in) -{ - int val = 0; - bool neg = false; - skipWhitespace(in); - if (*in == '-') neg = true, ++in; - else if (*in == '+') ++in; - if (*in < '0' || *in > '9') printf("PARSE ERROR! Unexpected char: %c\n", *in), exit(3); - while (*in >= '0' && *in <= '9') - val = val*10 + (*in - '0'), - ++in; - return neg ? -val : val; + #ifdef DISABLE_ZLIB + fclose(in); + #else + gzclose(in); + #endif // DISABLE_ZLIB } -inline std::string stringify(uint x) +void Main::readInStandardInput(Solver& solver) { - std::ostringstream o; - o << x; - return o.str(); -} - -template -static void parseString(B& in, std::string& str) -{ - str.clear(); - skipWhitespace(in); - while (*in != ' ' && *in != '\n') { - str += *in; - ++in; + 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 -template -static void readClause(B& in, Solver& S, vec& lits) -{ - int parsed_lit; - Var var; - lits.clear(); - for (;;) { - parsed_lit = parseInt(in); - if (parsed_lit == 0) break; - var = abs(parsed_lit)-1; - if (!debugNewVar) { - while (var >= S.nVars()) S.newVar(); - } - lits.push( (parsed_lit > 0) ? Lit(var, false) : Lit(var, true) ); + if (in == NULL) { + std::cout << "ERROR! Could not open standard input for reading" << std::endl; + exit(1); } -} - -template -static bool match(B& in, const char* str) -{ - for (; *str != 0; ++str, ++in) - if (*str != *in) - return false; - return true; -} + DimacsParser parser(&solver, debugLib, debugNewVar, grouping); + parser.parse_DIMACS(in); -template -static void parse_DIMACS_main(B& in, Solver& S) -{ - vec lits; - int group = 0; - string str; - uint debugLibPart = 1; - char name[MAX_NAMES_SIZE]; - - - for (;;) { - skipWhitespace(in); - switch (*in) { - case EOF: - return; - case 'p': - if (match(in, "p cnf")) { - int vars = parseInt(in); - int clauses = parseInt(in); - if (S.verbosity >= 1) { - printf("c | Number of variables: %-12d |\n", vars); - printf("c | Number of clauses: %-12d |\n", clauses); - } - } else { - printf("PARSE ERROR! Unexpected char: %c\n", *in), exit(3); - } - break; - case 'c': - ++in; - parseString(in, str); - if (str == "v" || str == "var") { - int var = parseInt(in); - skipWhitespace(in); - if (var <= 0) cout << "PARSE ERROR! Var number must be a positive integer" << endl, exit(3); - name[0] = '\0'; - untilEnd(in, name); - S.setVariableName(var-1, name); - } else if (debugLib && str == "Solver::solve()") { - lbool ret = S.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 != S.nVars(); i++) - if (S.model[i] != l_Undef) - fprintf(res, "%s%s%d", (i==0)?"":" ", (S.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++; - } else if (debugNewVar && str == "Solver::newVar()") { - S.newVar(); - } else { - //printf("didn't understand in CNF file: 'c %s'\n", str.c_str()); - skipLine(in); - } - break; - default: - bool xor_clause = false; - if ( *in == 'x') xor_clause = true, ++in; - readClause(in, S, lits); - skipLine(in); - - name[0] = '\0'; - - if (!grouping) group++; - else { - if (*in != 'c') { - cout << "PARSE ERROR! Group must be present after earch clause ('c' missing after clause line)" << endl; - exit(3); - } - ++in; - - parseString(in, str); - if (str != "g" && str != "group") { - cout << "PARSE ERROR! Group must be present after each clause('group' missing)!" << endl; - cout << "Instead of 'group' there was:" << str << endl; - exit(3); - } - - group = parseInt(in); - if (group <= 0) printf("PARSE ERROR! Group number must be a positive integer\n"), exit(3); - - skipWhitespace(in); - untilEnd(in, name); - } - - if (xor_clause) { - bool xor_clause_inverted = false; - for (uint32_t i = 0; i < lits.size(); i++) { - xor_clause_inverted ^= lits[i].sign(); - } - S.addXorClause(lits, xor_clause_inverted, group, name); - } else - S.addClause(lits, group, name); - break; - } - } + #ifndef DISABLE_ZLIB + gzclose(in); + #endif // DISABLE_ZLIB } -// Inserts problem into solver. -// -#ifdef DISABLE_ZLIB -static void parse_DIMACS(FILE * input_stream, Solver& S) -#else -static void parse_DIMACS(gzFile input_stream, Solver& S) -#endif // DISABLE_ZLIB -{ - StreamBuffer in(input_stream); - parse_DIMACS_main(in, S); -} - - -//================================================================================================= -template -inline void printStatsLine(string left, T value, T2 value2, string extra) -{ - cout << std::fixed << std::left << std::setw(24) << left << ": " << std::setw(11) << std::setprecision(2) << value << " (" << std::left << std::setw(9) << std::setprecision(2) << value2 << " " << extra << ")" << std::endl; -} -template -inline void printStatsLine(string left, T value, string extra = "") +void Main::parseInAllFiles(Solver& solver) { - cout << std::fixed << std::left << std::setw(24) << left << ": " << std::setw(11) << std::setprecision(2) << value << extra << std::endl; -} + double myTime = cpuTime(); - -void printStats(Solver& solver) -{ - double cpu_time = cpuTime(); - uint64_t mem_used = memUsed(); - - //Restarts stats - printStatsLine("c restarts", solver.starts); - printStatsLine("c dynamic restarts", solver.dynStarts); - printStatsLine("c static restarts", solver.staticStarts); - printStatsLine("c full restarts", solver.fullStarts); - - //Learnts stats - printStatsLine("c learnts DL2", solver.nbDL2); - printStatsLine("c learnts size 2", solver.nbBin); - printStatsLine("c learnts size 1", solver.get_unitary_learnts_num(), (double)solver.get_unitary_learnts_num()/(double)solver.nVars()*100.0, "% of vars"); - - //Subsumer stats - printStatsLine("c v-elim SatELite", solver.getNumElimSubsume(), (double)solver.getNumElimSubsume()/(double)solver.nVars()*100.0, "% vars"); - printStatsLine("c SatELite time", solver.getTotalTimeSubsumer(), solver.getTotalTimeSubsumer()/cpu_time*100.0, "% time"); - - //XorSubsumer stats - printStatsLine("c v-elim xor", solver.getNumElimXorSubsume(), (double)solver.getNumElimXorSubsume()/(double)solver.nVars()*100.0, "% vars"); - printStatsLine("c xor elim time", solver.getTotalTimeXorSubsumer(), solver.getTotalTimeXorSubsumer()/cpu_time*100.0, "% time"); - - //VarReplacer stats - printStatsLine("c num binary xor trees", solver.getNumXorTrees()); - printStatsLine("c binxor trees' crown", solver.getNumXorTreesCrownSize(), (double)solver.getNumXorTreesCrownSize()/(double)solver.getNumXorTrees(), "leafs/tree"); - - //OTF clause improvement stats - printStatsLine("c OTF clause improved", solver.improvedClauseNo, (double)solver.improvedClauseNo/(double)solver.conflicts, "clauses/conflict"); - printStatsLine("c OTF impr. size diff", solver.improvedClauseSize, (double)solver.improvedClauseSize/(double)solver.improvedClauseNo, " lits/clause"); - - #ifdef USE_GAUSS - if (solver.gaussconfig.decision_until > 0) { - std::cout << "c " << std::endl; - printStatsLine("c gauss unit truths ", solver.get_sum_gauss_unit_truths()); - printStatsLine("c gauss called", solver.get_sum_gauss_called()); - printStatsLine("c gauss conflicts ", solver.get_sum_gauss_confl(), (double)solver.get_sum_gauss_confl() / (double)solver.get_sum_gauss_called() * 100.0, " %"); - printStatsLine("c gauss propagations ", solver.get_sum_gauss_prop(), (double)solver.get_sum_gauss_prop() / (double)solver.get_sum_gauss_called() * 100.0, " %"); - printStatsLine("c gauss useful", ((double)solver.get_sum_gauss_prop() + (double)solver.get_sum_gauss_confl())/ (double)solver.get_sum_gauss_called() * 100.0, " %"); - std::cout << "c " << std::endl; + //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); } - #endif - - //Search stats - printStatsLine("c conflicts", solver.conflicts, (double)solver.conflicts/cpu_time, "/ sec"); - printStatsLine("c decisions", solver.decisions, (double)solver.rnd_decisions*100.0/(double)solver.decisions, "% random"); - printStatsLine("c propagations", solver.propagations, (double)solver.propagations/cpu_time, "/ sec"); - printStatsLine("c conflict literals", solver.tot_literals, (double)(solver.max_literals - solver.tot_literals)*100.0/ (double)solver.max_literals, "% deleted"); - //General stats - printStatsLine("c Memory used", (double)mem_used / 1048576.0, " MB"); - printStatsLine("c CPU time", cpu_time, " s"); -} + //Then read the main file or standard input + if (!fileNamePresent) { + readInStandardInput(solver); + } else { + string filename = argv[(twoFileNamesPresent ? argc-2 : argc-1)]; + readInAFile(filename, solver); + } -Solver* solver; -static void SIGINT_handler(int signum) -{ - printf("\n"); - printf("*** INTERRUPTED ***\n"); - printStats(*solver); - if (dumpLearnts) { - solver->dumpSortedLearnts(learnts_filename, maxLearntsSize); - cout << "c Sorted learnt clauses dumped to file '" << learnts_filename << "'" << endl; + if (solver.conf.verbosity >= 1) { + std::cout << "c Parsing time: " + << std::fixed << std::setw(5) << std::setprecision(2) << (cpuTime() - myTime) + << " s" << std::endl; } - printf("\n"); - printf("*** INTERRUPTED ***\n"); - exit(1); } - //================================================================================================= // Main: -void printUsage(char** argv, Solver& S) +void Main::printUsage(char** argv) { #ifdef DISABLE_ZLIB printf("USAGE: %s [options] \n\n where input is plain DIMACS.\n\n", argv[0]); @@ -458,6 +231,7 @@ void printUsage(char** argv, Solver& S) printf(" regular clauses\n"); printf(" --noregbxorfind = Don't regularly find and collect 2-long xor-clauses\n"); printf(" from regular clauses\n"); + printf(" --noextendedscc = Don't 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"); @@ -478,20 +252,27 @@ void printUsage(char** argv, Solver& S) 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 = If interrupted or reached restart limit, dump\n"); + printf(" the original problem instance, simplified to the\n"); + printf(" current point.\n"); + printf(" --alsoread = 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(" --nofailedvar = Don't search for failed vars, and don't search for vars\n"); - printf(" doubly propagated to the same value\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(" --nohyperbinres = Don't carry out hyper-binary resolution\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"); - printf(" --noparthander = Don't find and solve subroblems with subsolvers\n"); + printf(" --noparthandler = Don't find and solve subroblems with subsolvers\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"); @@ -500,24 +281,41 @@ void printUsage(char** argv, Solver& S) 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", S.gaussconfig.maxMatrixRows); + 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", S.gaussconfig.minMatrixRows); + 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", S.gaussconfig.only_nth_gauss_save); + 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(" --noextrabins = Don't add binary clauses when doing failed lit probing.\n"); + printf(" --nohyperbinres = Don't add binary clauses when doing failed lit probing.\n"); printf(" --noremovebins = Don't remove useless binary clauses\n"); - printf(" --noregremovebins= Don't remove useless binary clauses regularly\n"); - printf(" --nosubswithbins = Don't subsume with non-existent bins\n"); - printf(" --norsubswithbins= Don't subsume regularly with non-existent bins\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(" --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(" --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); + printf(" throw the clause away on backtrack.\n"); + printf(" --threads = Num threads (default is 1)\n"); printf("\n"); } -const char* hasPrefix(const char* str, const char* prefix) +const char* Main::hasPrefix(const char* str, const char* prefix) { int len = strlen(prefix); if (strncmp(str, prefix, len) == 0) @@ -526,28 +324,63 @@ const char* hasPrefix(const char* str, const char* prefix) return NULL; } -}; //NAMESPACE MINISAT - -int main(int argc, char** argv) +void Main::printResultFunc(const Solver& S, const lbool ret, FILE* res) { - Solver S; - S.verbosity = 2; + 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) + std::cout << "s SATISFIABLE" << std::endl; + else if (ret == l_False) + 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; - int j = 0; - unsigned long max_nr_of_solutions = 1; - unsigned long current_nr_of_solutions = 1; + 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) - S.polarity_mode = Solver::polarity_true; + conf.polarity_mode = polarity_true; else if (strcmp(value, "false") == 0) - S.polarity_mode = Solver::polarity_false; + conf.polarity_mode = polarity_false; else if (strcmp(value, "rnd") == 0) - S.polarity_mode = Solver::polarity_rnd; + conf.polarity_mode = polarity_rnd; else if (strcmp(value, "auto") == 0) - S.polarity_mode = Solver::polarity_auto; + conf.polarity_mode = polarity_auto; else { printf("ERROR! unknown polarity-mode %s\n", value); exit(0); @@ -556,10 +389,10 @@ int main(int argc, char** argv) } else if ((value = hasPrefix(argv[i], "--rnd-freq="))) { double rnd; if (sscanf(value, "%lf", &rnd) <= 0 || rnd < 0 || rnd > 1) { - printf("ERROR! illegal rnd-freq constant %s\n", value); + printf("ERROR! illegal rnRSE ERROR!d-freq constant %s\n", value); exit(0); } - S.random_var_freq = rnd; + conf.random_var_freq = rnd; /*} else if ((value = hasPrefix(argv[i], "--decay="))) { double decay; @@ -567,7 +400,7 @@ int main(int argc, char** argv) printf("ERROR! illegal decay constant %s\n", value); exit(0); } - S.var_decay = 1 / decay;*/ + conf.var_decay = 1 / decay;*/ } else if ((value = hasPrefix(argv[i], "--verbosity="))) { int verbosity = (int)strtol(value, NULL, 10); @@ -575,15 +408,15 @@ int main(int argc, char** argv) printf("ERROR! illegal verbosity level %s\n", value); exit(0); } - S.verbosity = verbosity; + conf.verbosity = verbosity; #ifdef STATS_NEEDED } else if ((value = hasPrefix(argv[i], "--grouping"))) { grouping = true; } else if ((value = hasPrefix(argv[i], "--proof-log"))) { - S.needProofGraph(); + conf.needProofGraph(); } else if ((value = hasPrefix(argv[i], "--stats"))) { - S.needStats(); + conf.needStats(); #endif } else if ((value = hasPrefix(argv[i], "--randomize="))) { @@ -592,131 +425,153 @@ int main(int argc, char** argv) printf("ERROR! illegal seed %s\n", value); exit(0); } - cout << "c seed:" << seed << endl; - S.setSeed(seed); + conf.origSeed = seed; } else if ((value = hasPrefix(argv[i], "--restrict="))) { - uint branchTo; + uint32_t branchTo; if (sscanf(value, "%d", &branchTo) < 0 || branchTo < 1) { printf("ERROR! illegal restricted pick branch number %d\n", branchTo); exit(0); } - S.restrictedPickBranch = branchTo; + conf.restrictPickBranch = branchTo; } else if ((value = hasPrefix(argv[i], "--gaussuntil="))) { uint32_t until; if (sscanf(value, "%d", &until) < 0) { printf("ERROR! until %s\n", value); exit(0); } - S.gaussconfig.decision_until = until; + gaussconfig.decision_until = until; } else if ((value = hasPrefix(argv[i], "--restarts="))) { - uint maxrest; + uint32_t maxrest; if (sscanf(value, "%d", &maxrest) < 0 || maxrest == 0) { printf("ERROR! illegal maximum restart number %d\n", maxrest); exit(0); } - S.setMaxRestarts(maxrest); + conf.maxRestarts = maxrest; } else if ((value = hasPrefix(argv[i], "--dumplearnts="))) { - if (sscanf(value, "%400s", learnts_filename) < 0 || strlen(learnts_filename) == 0) { - printf("ERROR! wrong filename '%s'\n", learnts_filename); + 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); } - dumpLearnts = true; + 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 (!dumpLearnts) { + if (!conf.needToDumpLearnts) { printf("ERROR! -dumplearnts= must be first activated before issuing -maxdumplearnts=\n"); exit(0); } int tmp; if (sscanf(value, "%d", &tmp) < 0 || tmp < 0) { - cout << "ERROR! wrong maximum dumped learnt clause size is illegal: " << tmp << endl; + std::cout << "ERROR! wrong maximum dumped learnt clause size is illegal: " << tmp << std::endl; exit(0); } - maxLearntsSize = (uint32_t)tmp; + conf.maxDumpLearntsSize = (uint32_t)tmp; } else if ((value = hasPrefix(argv[i], "--maxsolutions="))) { int tmp; if (sscanf(value, "%d", &tmp) < 0 || tmp < 0) { - cout << "ERROR! wrong maximum number of solutions is illegal: " << tmp << endl; + 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"))) { - S.greedyUnbound = true; + conf.greedyUnbound = true; } else if ((value = hasPrefix(argv[i], "--nonormxorfind"))) { - S.findNormalXors = false; + conf.doFindXors = false; } else if ((value = hasPrefix(argv[i], "--nobinxorfind"))) { - S.findBinaryXors = false; + conf.doFindEqLits = false; } else if ((value = hasPrefix(argv[i], "--noregbxorfind"))) { - S.regularlyFindBinaryXors = false; + conf.doRegFindEqLits = false; + } else if ((value = hasPrefix(argv[i], "--noextendedscc"))) { + conf.doExtendedSCC = false; } else if ((value = hasPrefix(argv[i], "--noconglomerate"))) { - S.conglomerateXors = false; + conf.doConglXors = false; } else if ((value = hasPrefix(argv[i], "--nosimplify"))) { - S.schedSimplification = false; + 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"))) { - S.performReplace = false; - } else if ((value = hasPrefix(argv[i], "--nofailedvar"))) { - S.failedVarSearch = false; + conf.doReplace = false; + } else if ((value = hasPrefix(argv[i], "--nofailedlit"))) { + conf.doFailedLit = false; } else if ((value = hasPrefix(argv[i], "--nodisablegauss"))) { - S.gaussconfig.dontDisable = true; + gaussconfig.dontDisable = true; + } else if ((value = hasPrefix(argv[i], "--maxnummatrixes="))) { + uint32_t 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"))) { - S.heuleProcess = false; + conf.doHeuleProcess = false; } else if ((value = hasPrefix(argv[i], "--nosatelite"))) { - S.doSubsumption = false; + conf.doSatELite = false; } else if ((value = hasPrefix(argv[i], "--noparthandler"))) { - S.doPartHandler = false; + conf.doPartHandler = false; } else if ((value = hasPrefix(argv[i], "--noxorsubs"))) { - S.doXorSubsumption = false; + conf.doXorSubsumption = false; } else if ((value = hasPrefix(argv[i], "--nohyperbinres"))) { - S.doHyperBinRes = false; - } else if ((value = hasPrefix(argv[i], "--noblockedclause"))) { - S.doBlockedClause = false; + conf.doHyperBinRes = false; } else if ((value = hasPrefix(argv[i], "--novarelim"))) { - S.doVarElim = false; + conf.doVarElim = false; } else if ((value = hasPrefix(argv[i], "--nosubsume1"))) { - S.doSubsume1 = false; + conf.doSubsume1 = false; } else if ((value = hasPrefix(argv[i], "--nomatrixfind"))) { - S.gaussconfig.noMatrixFind = true; + gaussconfig.noMatrixFind = true; } else if ((value = hasPrefix(argv[i], "--noiterreduce"))) { - S.gaussconfig.iterativeReduce = false; + gaussconfig.iterativeReduce = false; } else if ((value = hasPrefix(argv[i], "--noiterreduce"))) { - S.gaussconfig.iterativeReduce = false; + gaussconfig.iterativeReduce = false; } else if ((value = hasPrefix(argv[i], "--noordercol"))) { - S.gaussconfig.orderCols = false; - } else if ((value = hasPrefix(argv[i], "--maxmatrixrows"))) { - uint32_t rows; - if (sscanf(value, "%d", &rows) < 0) { + 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); } - S.gaussconfig.maxMatrixRows = rows; - } else if ((value = hasPrefix(argv[i], "--minmatrixrows"))) { - uint32_t rows; - if (sscanf(value, "%d", &rows) < 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); } - S.gaussconfig.minMatrixRows = rows; + gaussconfig.minMatrixRows = rows; } else if ((value = hasPrefix(argv[i], "--savematrix"))) { uint32_t every; if (sscanf(value, "%d", &every) < 0) { printf("ERROR! savematrix: %s\n", value); exit(0); } - cout << "c Matrix saved every " << every << " decision levels" << endl; - S.gaussconfig.only_nth_gauss_save = every; + 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, S); + printUsage(argv); exit(0); } else if ((value = hasPrefix(argv[i], "--restart="))) { if (strcmp(value, "auto") == 0) - S.fixRestartType = auto_restart; + conf.fixRestartType = auto_restart; else if (strcmp(value, "static") == 0) - S.fixRestartType = static_restart; + conf.fixRestartType = static_restart; else if (strcmp(value, "dynamic") == 0) - S.fixRestartType = dynamic_restart; + conf.fixRestartType = dynamic_restart; else { printf("ERROR! unknown restart type %s\n", value); exit(0); @@ -724,159 +579,336 @@ int main(int argc, char** argv) } else if ((value = hasPrefix(argv[i], "--nosolprint"))) { printResult = false; //} else if ((value = hasPrefix(argv[i], "--addoldlearnts"))) { - // S.readdOldLearnts = true; - } else if ((value = hasPrefix(argv[i], "--noextrabins"))) { - S.addExtraBins = false; + // conf.readdOldLearnts = true; + } else if ((value = hasPrefix(argv[i], "--nohyperbinres"))) { + conf.doHyperBinRes= false; } else if ((value = hasPrefix(argv[i], "--noremovebins"))) { - S.removeUselessBins = false; - } else if ((value = hasPrefix(argv[i], "--noregremovebins"))) { - S.regularRemoveUselessBins = false; + conf.doRemUselessBins = false; + } else if ((value = hasPrefix(argv[i], "--nosubswithnbins"))) { + conf.doSubsWNonExistBins = false; } else if ((value = hasPrefix(argv[i], "--nosubswithbins"))) { - S.subsumeWithNonExistBinaries = false; - } else if ((value = hasPrefix(argv[i], "--norsubswithbins"))) { - S.regularSubsumeWithNonExistBinaries = false; + 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.doCacheOTFSSR = false; + } else if ((value = hasPrefix(argv[i], "--noremlbins"))) { + conf.doRemUselessLBins = false; + } 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; + } 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 - argv[j++] = argv[i]; + } 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; + } } - argc = j; - if (!debugLib) S.libraryUsage = false; - if (S.verbosity >= 1) - printf("c This is CryptoMiniSat %s\n", VERSION); -#if defined(__linux__) + 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(__linux__) fpu_control_t oldcw, newcw; _FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw); - if (S.verbosity >= 1) printf("c WARNING: for repeatability, setting FPU to use double precision\n"); + if (verbosity >= 1) printf("c WARNING: for repeatability, setting FPU to use double precision\n"); #endif - double cpu_time = cpuTime(); +} - solver = &S; - signal(SIGINT,SIGINT_handler); - //signal(SIGHUP,SIGINT_handler); +void Main::printVersionInfo(const uint32_t verbosity) +{ + 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 + } +} - if (argc == 1) - printf("c Reading from standard input... Use '-h' or '--help' for help.\n"); +const int Main::singleThreadSolve() +{ + Solver solver(conf, gaussconfig); + solversToInterrupt[0] = &solver; -#ifdef DISABLE_ZLIB - FILE * in = (argc == 1) ? fopen(0, "rb") : fopen(argv[1], "rb"); -#else - gzFile in = (argc == 1) ? gzdopen(0, "rb") : gzopen(argv[1], "rb"); -#endif // DISABLE_ZLIB - if (in == NULL) { - printf("ERROR! Could not open file: %s\n", argc == 1 ? "" : argv[1]); - exit(1); + 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 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 (S.verbosity >= 1) { - printf("c =================================[ Problem Statistics ]==================================\n"); - printf("c | |\n"); + if (conf.needToDumpLearnts) { + solver.dumpSortedLearnts(conf.learntsFilename, conf.maxDumpLearntsSize); + std::cout << "c Sorted learnt clauses dumped to file '" << conf.learntsFilename << "'" << std::endl; + } + if (conf.needToDumpOrig) { + solver.dumpOrigClauses(conf.origFilename); + 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); - parse_DIMACS(in, S); + return correctReturnValue(ret); +} -#ifdef DISABLE_ZLIB - fclose(in); -#else - gzclose(in); -#endif // DISABLE_ZLIB - if (argc >= 3) - printf("c Outputting solution to file: %s\n" , argv[2]); +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); + } - double parse_time = cpuTime() - cpu_time; - if (S.verbosity >= 1) - printf("c | Parsing time: %-12.2f s |\n", parse_time); + #ifdef NDEBUG + // (faster than "return", which will invoke the destructor for 'Solver') + exit(retval); + #endif + return retval; +} - lbool ret; +const 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; - while(1) + Solver solver(myConf, gaussconfig, &sharedData); + #pragma omp critical (solversToInterr) { - ret = S.solve(); - if ( ret != l_True ) break; + solversToInterrupt[num] = &solver; + //std::cout << "Solver num " << num << " is to be interrupted " << std::endl; + } - std::cout << "c " << std::setw(8) << current_nr_of_solutions++ << " solution(s) found" << std::endl; + printVersionInfo(myConf.verbosity); + setDoublePrecision(myConf.verbosity); - if (current_nr_of_solutions > max_nr_of_solutions) break; - printf("c Prepare for next run...\n"); + parseInAllFiles(solver); + lbool ret = solver.solve(); + #pragma omp critical (finished) + { + finished.insert(num); + } - vec lits; - if (printResult) printf("v "); - for (Var var = 0; var != S.nVars(); var++) { - if (S.model[var] != l_Undef) { - lits.push( Lit(var, (S.model[var] == l_True)? true : false) ); - if (printResult) printf("%s%d ", (S.model[var] == l_True)? "" : "-", var+1); + 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++; + } + } } } - if (printResult) printf("\n"); - - S.addClause(lits); - } + bool mustWait = true; + while (mustWait) { + #pragma omp critical (finished) + if (finished.size() == (unsigned)numThreads) mustWait = false; + } + if (conf.needToDumpLearnts) { + solver.dumpSortedLearnts(conf.learntsFilename, conf.maxDumpLearntsSize); + if (conf.verbosity >= 1) { + std::cout << "c Sorted learnt clauses dumped to file '" + << conf.learntsFilename << "'" << std::endl; + } + } + if (conf.needToDumpOrig) { + solver.dumpOrigClauses(conf.origFilename); + if (conf.verbosity >= 1) + std::cout << "c Simplified original clauses dumped to file '" + << conf.origFilename << "'" << std::endl; + } - printStats(S); - printf("c \n"); - if (dumpLearnts) { - S.dumpSortedLearnts(learnts_filename, maxLearntsSize); - cout << "c Sorted learnt clauses dumped to file '" << learnts_filename << "'" << endl; + FILE* res = openOutputFile(); + if (conf.verbosity >= 1) solver.printStats(); + printResultFunc(solver, ret, res); + + retval = correctReturnValue(ret); + exit(retval); } - if (ret == l_Undef) - printf("c Not finished running -- maximum restart reached\n"); + return retval; +} - FILE* res = NULL; - if (argc >= 3) { - res = fopen(argv[2], "wb"); - if (res == NULL) { - int backup_errno = errno; - printf("Cannot open %s for writing. Problem: %s", argv[2], strerror(backup_errno)); - exit(1); - } +const 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); } - if (res != NULL) { - if (ret == l_True) { - printf("c SAT\n"); - 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) { - printf("c UNSAT\n"); - fprintf(res, "UNSAT\n"); - } else { - printf("c INCONCLUSIVE\n"); - fprintf(res, "INCONCLUSIVE\n"); + 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; } - fclose(res); - } else { - if (ret == l_True) - printf("s SATISFIABLE\n"); - else if (ret == l_False) - printf("s UNSATISFIABLE\n"); + int retval = oneThreadSolve(); - if(ret == l_True && printResult) { - printf("v "); - for (Var var = 0; var != S.nVars(); var++) - if (S.model[var] != l_Undef) - printf("%s%d ", (S.model[var] == l_True)? "" : "-", var+1); - printf("0\n"); - } + #pragma omp single + finalRetVal = retval; } -#ifdef NDEBUG - exit(ret == l_True ? 10 : 20); // (faster than "return", which will invoke the destructor for 'Solver') -#endif + return finalRetVal; +} - if (ret == l_True) return 10; - if (ret == l_False) return 20; - if (ret == l_Undef) return 15; - assert(false); +int main(int argc, char** argv) +{ + Main main(argc, argv); + main.parseCommandLine(); + signal(SIGINT, SIGINT_handler); + //signal(SIGHUP,SIGINT_handler); - return 0; + if (main.numThreads == 1) + return main.singleThreadSolve(); + else + return main.multiThreadSolve(); } - diff --git a/src/sat/cryptominisat2/Main.h b/src/sat/cryptominisat2/Main.h new file mode 100644 index 0000000..f3d56a7 --- /dev/null +++ b/src/sat/cryptominisat2/Main.h @@ -0,0 +1,69 @@ +/***************************************************************************** +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 +using std::string; +#include +#ifndef DISABLE_ZLIB +#include +#endif // DISABLE_ZLIB + +#include "Solver.h" +#include "SharedData.h" + +class Main +{ + public: + Main(int argc, char** argv); + + void parseCommandLine(); + + const int singleThreadSolve(); + const int oneThreadSolve(); + const 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 filesToRead; + + SharedData sharedData; + + int argc; + char** argv; +}; + +#endif //MAIN_H diff --git a/src/sat/cryptominisat2/Makefile b/src/sat/cryptominisat2/Makefile index dbe77b4..c00c033 100644 --- a/src/sat/cryptominisat2/Makefile +++ b/src/sat/cryptominisat2/Makefile @@ -5,15 +5,20 @@ MTL = mtl MTRAND = MTRand SOURCES = Logger.cpp Solver.cpp PackedRow.cpp \ XorFinder.cpp VarReplacer.cpp \ - FindUndef.cpp ClauseCleaner.cpp RestartTypeChooser.cpp \ - FailedVarSearcher.cpp PartFinder.cpp \ + ClauseCleaner.cpp RestartTypeChooser.cpp \ + PartFinder.cpp \ Subsumer.cpp PartHandler.cpp XorSubsumer.cpp \ Gaussian.cpp MatrixFinder.cpp StateSaver.cpp \ ClauseAllocator.cpp UselessBinRemover.cpp \ - OnlyNonLearntBins.cpp + OnlyNonLearntBins.cpp DataSync.cpp \ + SolverConf.cpp FailedLitSearcher.cpp \ + CompleteDetachReattacher.cpp \ + ClauseVivifier.cpp SolverMisc.cpp \ + DimacsParser.cpp SolverDebug.cpp \ + SCCFinder.cpp OBJECTS = $(SOURCES:.cpp=.o) LIB = libminisat.a -CFLAGS += -I../.. -I$(MTL) -I$(MTRAND) -DEXT_HASH_MAP -ffloat-store $(CFLAGS_M32) -c +CFLAGS += -I../.. -I$(MTL) -I$(MTRAND) -fopenmp -DEXT_HASH_MAP -ffloat-store $(CFLAGS_M32) -c EXEC = minisat LFLAGS = -lz diff --git a/src/sat/cryptominisat2/MatrixFinder.cpp b/src/sat/cryptominisat2/MatrixFinder.cpp index 35443a7..e4cb367 100644 --- a/src/sat/cryptominisat2/MatrixFinder.cpp +++ b/src/sat/cryptominisat2/MatrixFinder.cpp @@ -35,10 +35,6 @@ using std::map; using std::cout; using std::endl; -namespace MINISAT -{ -using namespace MINISAT; - //#define PART_FINDING MatrixFinder::MatrixFinder(Solver& _solver) : @@ -49,16 +45,16 @@ MatrixFinder::MatrixFinder(Solver& _solver) : inline const 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 const bool MatrixFinder::firstPartOfSecond(const XorClause& c1, const XorClause& c2) const { - uint i1, i2; + uint32_t i1, i2; for (i1 = 0, i2 = 0; i1 < c1.size() && i2 < c2.size();) { if (c1[i1].var() != c2[i2].var()) i2++; @@ -67,7 +63,7 @@ inline const bool MatrixFinder::firstPartOfSecond(const XorClause& c1, const Xor i2++; } } - + return (i1 == c1.size()); } @@ -78,19 +74,20 @@ const bool MatrixFinder::findMatrixes() 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.verbosity >=1) - cout << "c | Matrix finding disabled through switch. Putting all xors into matrix." << endl; + if (solver.conf.verbosity >=1) + cout << "c Matrix finding disabled through switch. Putting all xors into matrix." << endl; vector xorclauses; xorclauses.reserve(solver.xorclauses.size()); for (uint32_t i = 0; i < solver.xorclauses.size(); i++) @@ -98,9 +95,9 @@ const bool MatrixFinder::findMatrixes() 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 tomerge; + set tomerge; vector newSet; for (Lit *l = &(**c)[0], *end2 = l + (**c).size(); l != end2; l++) { if (table[l->var()] != var_Undef) @@ -109,27 +106,27 @@ const bool MatrixFinder::findMatrixes() newSet.push_back(l->var()); } if (tomerge.size() == 1) { - const uint into = *tomerge.begin(); - map >::iterator intoReverse = reverseTable.find(into); - for (uint i = 0; i < newSet.size(); i++) { + const uint32_t into = *tomerge.begin(); + map >::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::iterator it = tomerge.begin(); it != tomerge.end(); it++) { + + for (set::iterator it = tomerge.begin(); it != tomerge.end(); it++) { newSet.insert(newSet.end(), reverseTable[*it].begin(), reverseTable[*it].end()); reverseTable.erase(*it); } - for (uint i = 0; i < newSet.size(); i++) + 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 >::iterator it = reverseTable.begin(), end = reverseTable.end(); it != end; it++) { + for (map >::iterator it = reverseTable.begin(), end = reverseTable.end(); it != end; it++) { cout << "-- set begin --" << endl; for (vector::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { cout << *it2 << ", "; @@ -137,11 +134,13 @@ const bool MatrixFinder::findMatrixes() cout << "-------" << endl; } #endif - + uint32_t numMatrixes = setMatrixes(); - - if (solver.verbosity >=1) - std::cout << "c | Finding matrixes : " << cpuTime() - myTime << " s (found " << numMatrixes << ") |" << endl; + + if (solver.conf.verbosity >=1) + std::cout << "c Finding matrixes : " << cpuTime() - myTime + << " s (found " << numMatrixes << ")" + << endl; for (vector::iterator gauss = solver.gauss_matrixes.begin(), end = solver.gauss_matrixes.end(); gauss != end; gauss++) { if (!(*gauss)->full_init()) return false; @@ -150,89 +149,89 @@ const bool MatrixFinder::findMatrixes() return true; } -const uint MatrixFinder::setMatrixes() +const uint32_t MatrixFinder::setMatrixes() { - vector > numXorInMatrix; - for (uint i = 0; i < matrix_no; i++) + vector > numXorInMatrix; + for (uint32_t i = 0; i < matrix_no; i++) numXorInMatrix.push_back(std::make_pair(i, 0)); - - vector sumXorSizeInMatrix(matrix_no, 0); - vector > xorSizesInMatrix(matrix_no); + + vector sumXorSizeInMatrix(matrix_no, 0); + vector > xorSizesInMatrix(matrix_no); vector > xorsInMatrix(matrix_no); - + #ifdef PART_FINDING vector > xorFingerprintInMatrix(matrix_no); #endif - + for (XorClause** c = solver.xorclauses.getData(), **end = c + solver.xorclauses.size(); c != end; c++) { XorClause& x = **c; - const uint matrix = table[x[0].var()]; + 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 (uint i = 0; i < matrix_no; i++) + for (uint32_t i = 0; i < matrix_no; i++) findParts(xorFingerprintInMatrix[i], xorsInMatrix[i]); #endif //PART_FINDING - - uint realMatrixNum = 0; + + uint32_t realMatrixNum = 0; for (int a = matrix_no-1; a != -1; a--) { - uint i = numXorInMatrix[a].first; - + uint32_t i = numXorInMatrix[a].first; + if (numXorInMatrix[a].second < 3) continue; - - const uint totalSize = reverseTable[i].size()*numXorInMatrix[a].second; + + 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 (uint i2 = 0; i2 < xorSizesInMatrix[i].size(); i2++) + 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 < 3) + && realMatrixNum <= solver.gaussconfig.maxNumMatrixes) { - if (solver.verbosity >=1) - cout << "c | Matrix no " << std::setw(2) << realMatrixNum; + if (solver.conf.verbosity >=1) + 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.verbosity >=1 /*&& numXorInMatrix[a].second >= 20*/) - cout << "c | Unused Matrix "; + if (solver.conf.verbosity >=1 /*&& numXorInMatrix[a].second >= 20*/) + cout << "c Unused Matrix "; } - if (solver.verbosity >=1 /*&& numXorInMatrix[a].second >= 20*/) { + if (solver.conf.verbosity >=1 /*&& numXorInMatrix[a].second >= 20*/) { cout << std::setw(7) << numXorInMatrix[a].second << " x" << std::setw(5) << reverseTable[i].size(); cout << " density:" << std::setw(5) << std::fixed << std::setprecision(1) << density << "%"; cout << " xorlen avg:" << std::setw(5) << std::fixed << std::setprecision(2) << avg; - cout << " stdev:" << std::setw(6) << std::fixed << std::setprecision(2) << stdDeviation << " |" << endl; + cout << " stdev:" << std::setw(6) << std::fixed << std::setprecision(2) << stdDeviation << endl; } } - + return realMatrixNum; } void MatrixFinder::findParts(vector& xorFingerprintInMatrix, vector& xorsInMatrix) { - uint ai = 0; + uint32_t ai = 0; for (XorClause **a = &xorsInMatrix[0], **end = a + xorsInMatrix.size(); a != end; a++, ai++) { const Var fingerprint = xorFingerprintInMatrix[ai]; - uint ai2 = 0; + uint32_t ai2 = 0; for (XorClause **a2 = &xorsInMatrix[0]; a2 != end; a2++, ai2++) { if (ai == ai2) continue; const Var fingerprint2 = xorFingerprintInMatrix[ai2]; @@ -245,5 +244,3 @@ void MatrixFinder::findParts(vector& xorFingerprintInMatrix, vector. #include "Clause.h" #include "Solver.h" -namespace MINISAT -{ -using namespace MINISAT; - class Solver; using std::map; @@ -46,11 +42,11 @@ class MatrixFinder { const bool findMatrixes(); private: - const uint setMatrixes(); + const uint32_t setMatrixes(); struct mysorter { - bool operator () (const pair& left, const pair& right) + bool operator () (const pair& left, const pair& right) { return left.second < right.second; } @@ -60,13 +56,12 @@ class MatrixFinder { inline const Var fingerprint(const XorClause& c) const; inline const bool firstPartOfSecond(const XorClause& c1, const XorClause& c2) const; - map > reverseTable; //matrix -> vars + map > reverseTable; //matrix -> vars vector table; //var -> matrix - uint matrix_no; + uint32_t matrix_no; Solver& solver; }; -}; //NAMESPACE MINISAT #endif //MATRIXFINDER_H diff --git a/src/sat/cryptominisat2/MersenneTwister.h b/src/sat/cryptominisat2/MersenneTwister.h deleted file mode 100644 index 964ecc7..0000000 --- a/src/sat/cryptominisat2/MersenneTwister.h +++ /dev/null @@ -1,427 +0,0 @@ -// MersenneTwister.h -// Mersenne Twister random number generator -- a C++ class MTRand -// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus -// Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com - -// The Mersenne Twister is an algorithm for generating random numbers. It -// was designed with consideration of the flaws in various other generators. -// The period, 2^19937-1, and the order of equidistribution, 623 dimensions, -// are far greater. The generator is also fast; it avoids multiplication and -// division, and it benefits from caches and pipelines. For more information -// see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html - -// Reference -// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally -// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on -// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30. - -// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, -// Copyright (C) 2000 - 2003, Richard J. Wagner -// All rights reserved. -// -// 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 names of its contributors may not be used to endorse or promote -// products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "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 COPYRIGHT OWNER OR -// CONTRIBUTORS 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. - -// The original code included the following notice: -// -// When you use this, send an email to: matumoto@math.keio.ac.jp -// with an appropriate reference to your work. -// -// It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu -// when you write. - -#ifndef MERSENNETWISTER_H -#define MERSENNETWISTER_H - -#include -#include -#include -#include -#include - -namespace MINISAT -{ - -// Not thread safe (unless auto-initialization is avoided and each thread has -// its own MTRand object) - -class MTRand { -// Data -public: - typedef unsigned long uint32; // unsigned integer type, at least 32 bits - - enum { N = 624 }; // length of state vector - enum { SAVE = N + 1 }; // length of array for save() - -protected: - enum { M = 397 }; // period parameter - - uint32 state[N]; // internal state - uint32 *pNext; // next value to get from state - int left; // number of values left before reload needed - - -//Methods -public: - MTRand( const uint32& oneSeed ); // initialize with a simple uint32 - MTRand( uint32 *const bigSeed, uint32 const seedLength = N ); // or an array - MTRand(); // auto-initialize with /dev/urandom or time() and clock() - - // Do NOT use for CRYPTOGRAPHY without securely hashing several returned - // values together, otherwise the generator state can be learned after - // reading 624 consecutive values. - - // Access to 32-bit random numbers - double rand(); // real number in [0,1] - double rand( const double& n ); // real number in [0,n] - double randExc(); // real number in [0,1) - double randExc( const double& n ); // real number in [0,n) - double randDblExc(); // real number in (0,1) - double randDblExc( const double& n ); // real number in (0,n) - uint32 randInt(); // integer in [0,2^32-1] - uint32 randInt( const uint32& n ); // integer in [0,n] for n < 2^32 - double operator()() { return rand(); } // same as rand() - - // Access to 53-bit random numbers (capacity of IEEE double precision) - double rand53(); // real number in [0,1) - - // Access to nonuniform random number distributions - double randNorm( const double& mean = 0.0, const double& variance = 0.0 ); - - // Re-seeding functions with same behavior as initializers - void seed( const uint32 oneSeed ); - void seed( uint32 *const bigSeed, const uint32 seedLength = N ); - void seed(); - - // Saving and loading generator state - void save( uint32* saveArray ) const; // to array of size SAVE - void load( uint32 *const loadArray ); // from such array - friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand ); - friend std::istream& operator>>( std::istream& is, MTRand& mtrand ); - -protected: - void initialize( const uint32 oneSeed ); - void reload(); - uint32 hiBit( const uint32& u ) const { return u & 0x80000000UL; } - uint32 loBit( const uint32& u ) const { return u & 0x00000001UL; } - uint32 loBits( const uint32& u ) const { return u & 0x7fffffffUL; } - uint32 mixBits( const uint32& u, const uint32& v ) const - { return hiBit(u) | loBits(v); } - uint32 twist( const uint32& m, const uint32& s0, const uint32& s1 ) const - { return m ^ (mixBits(s0,s1)>>1) ^ (-loBit(s1) & 0x9908b0dfUL); } - static uint32 hash( time_t t, clock_t c ); -}; - - -inline MTRand::MTRand( const uint32& oneSeed ) - { seed(oneSeed); } - -inline MTRand::MTRand( uint32 *const bigSeed, const uint32 seedLength ) - { seed(bigSeed,seedLength); } - -inline MTRand::MTRand() - { seed(); } - -inline double MTRand::rand() - { return double(randInt()) * (1.0/4294967295.0); } - -inline double MTRand::rand( const double& n ) - { return rand() * n; } - -inline double MTRand::randExc() - { return double(randInt()) * (1.0/4294967296.0); } - -inline double MTRand::randExc( const double& n ) - { return randExc() * n; } - -inline double MTRand::randDblExc() - { return ( double(randInt()) + 0.5 ) * (1.0/4294967296.0); } - -inline double MTRand::randDblExc( const double& n ) - { return randDblExc() * n; } - -inline double MTRand::rand53() -{ - uint32 a = randInt() >> 5, b = randInt() >> 6; - return ( a * 67108864.0 + b ) * (1.0/9007199254740992.0); // by Isaku Wada -} - -inline double MTRand::randNorm( const double& mean, const double& variance ) -{ - // Return a real number from a normal (Gaussian) distribution with given - // mean and variance by Box-Muller method - double r = sqrt( -2.0 * log( 1.0-randDblExc()) ) * variance; - double phi = 2.0 * 3.14159265358979323846264338328 * randExc(); - return mean + r * cos(phi); -} - -inline MTRand::uint32 MTRand::randInt() -{ - // Pull a 32-bit integer from the generator state - // Every other access function simply transforms the numbers extracted here - - if( left == 0 ) reload(); - --left; - - register uint32 s1; - s1 = *pNext++; - s1 ^= (s1 >> 11); - s1 ^= (s1 << 7) & 0x9d2c5680UL; - s1 ^= (s1 << 15) & 0xefc60000UL; - return ( s1 ^ (s1 >> 18) ); -} - -inline MTRand::uint32 MTRand::randInt( const uint32& n ) -{ - // Find which bits are used in n - // Optimized by Magnus Jonsson (magnus@smartelectronix.com) - uint32 used = n; - used |= used >> 1; - used |= used >> 2; - used |= used >> 4; - used |= used >> 8; - used |= used >> 16; - - // Draw numbers until one is found in [0,n] - uint32 i; - do - i = randInt() & used; // toss unused bits to shorten search - while( i > n ); - return i; -} - - -inline void MTRand::seed( const uint32 oneSeed ) -{ - // Seed the generator with a simple uint32 - initialize(oneSeed); - reload(); -} - - -inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength ) -{ - // Seed the generator with an array of uint32's - // There are 2^19937-1 possible initial states. This function allows - // all of those to be accessed by providing at least 19937 bits (with a - // default seed length of N = 624 uint32's). Any bits above the lower 32 - // in each element are discarded. - // Just call seed() if you want to get array from /dev/urandom - initialize(19650218UL); - register int i = 1; - register uint32 j = 0; - register int k = ( N > seedLength ? N : seedLength ); - for( ; k; --k ) - { - state[i] = - state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1664525UL ); - state[i] += ( bigSeed[j] & 0xffffffffUL ) + j; - state[i] &= 0xffffffffUL; - ++i; ++j; - if( i >= N ) { state[0] = state[N-1]; i = 1; } - if( j >= seedLength ) j = 0; - } - for( k = N - 1; k; --k ) - { - state[i] = - state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL ); - state[i] -= i; - state[i] &= 0xffffffffUL; - ++i; - if( i >= N ) { state[0] = state[N-1]; i = 1; } - } - state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array - reload(); -} - - -inline void MTRand::seed() -{ - // Seed the generator with an array from /dev/urandom if available - // Otherwise use a hash of time() and clock() values - - // First try getting an array from /dev/urandom - FILE* urandom = fopen( "/dev/urandom", "rb" ); - if( urandom ) - { - uint32 bigSeed[N]; - register uint32 *s = bigSeed; - register int i = N; - register bool success = true; - while( success && i-- ) - success = fread( s++, sizeof(uint32), 1, urandom ); - fclose(urandom); - if( success ) { seed( bigSeed, N ); return; } - } - - // Was not successful, so use time() and clock() instead - seed( hash( time(NULL), clock() ) ); -} - - -inline void MTRand::initialize( const uint32 seed ) -{ - // Initialize generator state with seed - // See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier. - // In previous versions, most significant bits (MSBs) of the seed affect - // only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto. - register uint32 *s = state; - register uint32 *r = state; - register int i = 1; - *s++ = seed & 0xffffffffUL; - for( ; i < N; ++i ) - { - *s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL; - r++; - } -} - - -inline void MTRand::reload() -{ - // Generate N new values in state - // Made clearer and faster by Matthew Bellew (matthew.bellew@home.com) - register uint32 *p = state; - register int i; - for( i = N - M; i--; ++p ) - *p = twist( p[M], p[0], p[1] ); - for( i = M; --i; ++p ) - *p = twist( p[M-N], p[0], p[1] ); - *p = twist( p[M-N], p[0], state[0] ); - - left = N, pNext = state; -} - - -inline MTRand::uint32 MTRand::hash( time_t t, clock_t c ) -{ - // Get a uint32 from t and c - // Better than uint32(x) in case x is floating point in [0,1] - // Based on code by Lawrence Kirby (fred@genesis.demon.co.uk) - - static uint32 differ = 0; // guarantee time-based seeds will change - - uint32 h1 = 0; - unsigned char *p = (unsigned char *) &t; - for( size_t i = 0; i < sizeof(t); ++i ) - { - h1 *= UCHAR_MAX + 2U; - h1 += p[i]; - } - uint32 h2 = 0; - p = (unsigned char *) &c; - for( size_t j = 0; j < sizeof(c); ++j ) - { - h2 *= UCHAR_MAX + 2U; - h2 += p[j]; - } - return ( h1 + differ++ ) ^ h2; -} - - -inline void MTRand::save( uint32* saveArray ) const -{ - register uint32 *sa = saveArray; - register const uint32 *s = state; - register int i = N; - for( ; i--; *sa++ = *s++ ) {} - *sa = left; -} - - -inline void MTRand::load( uint32 *const loadArray ) -{ - register uint32 *s = state; - register uint32 *la = loadArray; - register int i = N; - for( ; i--; *s++ = *la++ ) {} - left = *la; - pNext = &state[N-left]; -} - - -inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand ) -{ - register const MTRand::uint32 *s = mtrand.state; - register int i = mtrand.N; - for( ; i--; os << *s++ << "\t" ) {} - return os << mtrand.left; -} - - -inline std::istream& operator>>( std::istream& is, MTRand& mtrand ) -{ - register MTRand::uint32 *s = mtrand.state; - register int i = mtrand.N; - for( ; i--; is >> *s++ ) {} - is >> mtrand.left; - mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left]; - return is; -} -}; - -#endif // MERSENNETWISTER_H - -// Change log: -// -// v0.1 - First release on 15 May 2000 -// - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus -// - Translated from C to C++ -// - Made completely ANSI compliant -// - Designed convenient interface for initialization, seeding, and -// obtaining numbers in default or user-defined ranges -// - Added automatic seeding from /dev/urandom or time() and clock() -// - Provided functions for saving and loading generator state -// -// v0.2 - Fixed bug which reloaded generator one step too late -// -// v0.3 - Switched to clearer, faster reload() code from Matthew Bellew -// -// v0.4 - Removed trailing newline in saved generator format to be consistent -// with output format of built-in types -// -// v0.5 - Improved portability by replacing static const int's with enum's and -// clarifying return values in seed(); suggested by Eric Heimburg -// - Removed MAXINT constant; use 0xffffffffUL instead -// -// v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits -// - Changed integer [0,n] generator to give better uniformity -// -// v0.7 - Fixed operator precedence ambiguity in reload() -// - Added access for real numbers in (0,1) and (0,n) -// -// v0.8 - Included time.h header to properly support time_t and clock_t -// -// v1.0 - Revised seeding to match 26 Jan 2002 update of Nishimura and Matsumoto -// - Allowed for seeding with arrays of any length -// - Added access for real numbers in [0,1) with 53-bit resolution -// - Added access for real numbers from normal (Gaussian) distributions -// - Increased overall speed by optimizing twist() -// - Doubled speed of integer [0,n] generation -// - Fixed out-of-range number generation on 64-bit machines -// - Improved portability by substituting literal constants for long enum's -// - Changed license from GNU LGPL to BSD diff --git a/src/sat/cryptominisat2/OnlyNonLearntBins.cpp b/src/sat/cryptominisat2/OnlyNonLearntBins.cpp index 785d7e9..fd955d2 100644 --- a/src/sat/cryptominisat2/OnlyNonLearntBins.cpp +++ b/src/sat/cryptominisat2/OnlyNonLearntBins.cpp @@ -24,20 +24,19 @@ along with this program. If not, see . #include "ClauseCleaner.h" #include "time_mem.h" -namespace MINISAT -{ -using namespace MINISAT; - OnlyNonLearntBins::OnlyNonLearntBins(Solver& _solver) : solver(_solver) {} +/** +@brief Propagate recursively on non-learnt binaries +*/ const bool OnlyNonLearntBins::propagate() { while (solver.qhead < solver.trail.size()) { - Lit p = solver.trail[solver.qhead++]; + Lit p = solver.trail[solver.qhead++]; vec & wbin = binwatches[p.toInt()]; - solver.propagations += wbin.size()/2; + 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()) { @@ -51,105 +50,34 @@ const bool OnlyNonLearntBins::propagate() return true; } -const bool OnlyNonLearntBins::propagateBinExcept(const Lit& exceptLit) -{ - while (solver.qhead < solver.trail.size()) { - Lit p = solver.trail[solver.qhead++]; - vec & wbin = binwatches[p.toInt()]; - solver.propagations += wbin.size()/2; - for(WatchedBin *k = wbin.getData(), *end = wbin.getDataEnd(); k != end; k++) { - lbool val = solver.value(k->impliedLit); - if (val.isUndef() && k->impliedLit != exceptLit) { - solver.uncheckedEnqueueLight(k->impliedLit); - } else if (val == l_False) { - return false; - } - } - } - - return true; -} - -const bool OnlyNonLearntBins::propagateBinOneLevel() -{ - Lit p = solver.trail[solver.qhead]; - vec & wbin = binwatches[p.toInt()]; - solver.propagations += wbin.size()/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 +*/ const bool OnlyNonLearntBins::fill() { + uint32_t numBins = 0; double myTime = cpuTime(); - assert(solver.performReplace); - while (solver.performReplace && solver.varReplacer->getClauses().size() > 0) { - if (!solver.varReplacer->performReplace(true)) return false; - solver.clauseCleaner->removeAndCleanAll(true); - } - assert(solver.varReplacer->getClauses().size() == 0); - solver.clauseCleaner->moveBinClausesToBinClauses(); binwatches.growTo(solver.nVars()*2); - for(Clause **i = solver.binaryClauses.getData(), **end = solver.binaryClauses.getDataEnd(); i != end; i++) { - Clause& c = **i; - if (c.learnt()) continue; - - binwatches[(~c[0]).toInt()].push(WatchedBin(c[1])); - binwatches[(~c[1]).toInt()].push(WatchedBin(c[0])); + uint32_t wsLit = 0; + for (const vec *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec& ws = *it; + for (const Watched *it2 = ws.getData(), *end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary() && !it2->getLearnt()) { + binwatches[wsLit].push(WatchedBin(it2->getOtherLit())); + numBins++; + } + } } - if (solver.verbosity >= 2) { + 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" << std::endl; + << cpuTime() - myTime << " s" + << " num non-learnt bins: " << std::setw(10) << numBins + << std::endl; } return true; } - -void OnlyNonLearntBins::removeBin(Lit lit1, Lit lit2) -{ - uint32_t index0 = lit1.toInt(); - uint32_t index1 = lit2.toInt(); - if (index1 > index0) std::swap(index0, index1); - uint64_t final = index0; - final |= ((uint64_t)index1) << 32; - toRemove.insert(final); - - solver.removeWatchedBinClAll(binwatches[(~lit1).toInt()], lit2); - solver.removeWatchedBinClAll(binwatches[(~lit2).toInt()], lit1); -} - -const uint32_t OnlyNonLearntBins::removeBins() -{ - Clause **i, **j; - i = j = solver.binaryClauses.getData(); - uint32_t num = 0; - for (Clause **end = solver.binaryClauses.getDataEnd(); i != end; i++, num++) { - Clause& c = **i; - uint32_t index0 = c[0].toInt(); - uint32_t index1 = c[1].toInt(); - if (index1 > index0) std::swap(index0, index1); - uint64_t final = index0; - final |= ((uint64_t)index1) << 32; - - if (toRemove.find(final) == toRemove.end()) { - *j++ = *i; - } else { - solver.clauseAllocator.clauseFree(*i); - } - } - solver.binaryClauses.shrink(i-j); - return (i - j); -} - -}; //NAMESPACE MINISAT diff --git a/src/sat/cryptominisat2/OnlyNonLearntBins.h b/src/sat/cryptominisat2/OnlyNonLearntBins.h index ed73cc2..8c755b9 100644 --- a/src/sat/cryptominisat2/OnlyNonLearntBins.h +++ b/src/sat/cryptominisat2/OnlyNonLearntBins.h @@ -19,36 +19,50 @@ along with this program. If not, see . #define ONLYNONLEARNTBINS_H #include "Solver.h" -#include -using std::set; -namespace MINISAT -{ -using namespace MINISAT; +/** +@brief Handles propagation, addition&removal of non-learnt binary clauses -class OnlyNonLearntBins { +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 const bool propagate(); - const bool propagateBinExcept(const Lit& exceptLit); - const bool propagateBinOneLevel(); //Management of clauses const bool fill(); - void removeBin(Lit lit1, Lit lit2); - void removeClause(Clause& c); - const uint32_t removeBins(); + + //helper + inline const uint32_t getWatchSize(const Lit lit) const; + inline const vec >& getBinWatches() const; private: - vec > binwatches; - set toRemove; - + vec > binwatches; /// >& OnlyNonLearntBins::getBinWatches() const +{ + return binwatches; +} +#endif //ONLYNONLEARNTBINS_H diff --git a/src/sat/cryptominisat2/PackedMatrix.h b/src/sat/cryptominisat2/PackedMatrix.h index 9c7f117..a6945d2 100644 --- a/src/sat/cryptominisat2/PackedMatrix.h +++ b/src/sat/cryptominisat2/PackedMatrix.h @@ -29,10 +29,6 @@ along with this program. If not, see . //#define DEBUG_MATRIX -namespace MINISAT -{ -using namespace MINISAT; - class PackedMatrix { public: @@ -60,7 +56,7 @@ public: delete[] mp; } - void resize(const uint num_rows, uint num_cols) + 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)) { @@ -71,7 +67,7 @@ public: numCols = num_cols; } - void resizeNumRows(const uint num_rows) + void resizeNumRows(const uint32_t num_rows) { #ifdef DEBUG_MATRIX assert(num_rows <= numRows); @@ -98,7 +94,7 @@ public: return *this; } - inline PackedRow getMatrixAt(const uint i) + inline PackedRow getMatrixAt(const uint32_t i) { #ifdef DEBUG_MATRIX assert(i <= numRows); @@ -106,7 +102,7 @@ public: return PackedRow(numCols, mp+i*2*(numCols+1)); } - inline PackedRow getVarsetAt(const uint i) + inline PackedRow getVarsetAt(const uint32_t i) { #ifdef DEBUG_MATRIX assert(i <= numRows); @@ -115,7 +111,7 @@ public: return PackedRow(numCols, mp+i*2*(numCols+1)+(numCols+1)); } - inline const PackedRow getMatrixAt(const uint i) const + inline const PackedRow getMatrixAt(const uint32_t i) const { #ifdef DEBUG_MATRIX assert(i <= numRows); @@ -124,7 +120,7 @@ public: return PackedRow(numCols, mp+i*2*(numCols+1)); } - inline const PackedRow getVarsetAt(const uint i) const + inline const PackedRow getVarsetAt(const uint32_t i) const { #ifdef DEBUG_MATRIX assert(i <= numRows); @@ -147,19 +143,19 @@ public: return *this; } - iterator operator+(const uint num) const + iterator operator+(const uint32_t num) const { iterator ret(*this); ret.mp += 2*(numCols+1)*num; return ret; } - const uint operator-(const iterator& b) const + const uint32_t operator-(const iterator& b) const { return (mp - b.mp)/(2*(numCols+1)); } - void operator+=(const uint num) + void operator+=(const uint32_t num) { mp += 2*(numCols+1)*num; } @@ -177,13 +173,13 @@ public: private: friend class PackedMatrix; - iterator(uint64_t* _mp, const uint _numCols) : + iterator(uint64_t* _mp, const uint32_t _numCols) : mp(_mp) , numCols(_numCols) {} uint64_t* mp; - const uint numCols; + const uint32_t numCols; }; inline iterator beginMatrix() @@ -206,7 +202,7 @@ public: return iterator(mp+(numCols+1)+numRows*2*(numCols+1), numCols); } - inline const uint getSize() const + inline const uint32_t getSize() const { return numRows; } @@ -214,11 +210,9 @@ public: private: uint64_t* mp; - uint numRows; - uint numCols; + uint32_t numRows; + uint32_t numCols; }; -}; //NAMESPACE MINISAT - #endif //PACKEDMATRIX_H diff --git a/src/sat/cryptominisat2/PackedRow.cpp b/src/sat/cryptominisat2/PackedRow.cpp index 59a4e43..890f0e0 100644 --- a/src/sat/cryptominisat2/PackedRow.cpp +++ b/src/sat/cryptominisat2/PackedRow.cpp @@ -17,10 +17,6 @@ along with this program. If not, see . #include "PackedRow.h" -namespace MINISAT -{ -using namespace MINISAT; - std::ostream& operator << (std::ostream& os, const PackedRow& m) { for(uint32_t i = 0; i < m.size*64; i++) { @@ -37,7 +33,7 @@ bool PackedRow::operator ==(const PackedRow& b) const assert(b.size > 0); assert(size == b.size); #endif - + return (std::equal(b.mp-1, b.mp+size, mp-1)); } @@ -48,7 +44,7 @@ bool PackedRow::operator !=(const PackedRow& b) const assert(b.size > 0); assert(size == b.size); #endif - + return (!std::equal(b.mp-1, b.mp+size, mp-1)); } @@ -57,7 +53,7 @@ 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 (uint i2 = 0; i2 < 64; i2++) { + for (uint32_t i2 = 0; i2 < 64; i2++) { popcnt += (tmp & 1); tmp >>= 1; } @@ -84,10 +80,10 @@ uint32_t PackedRow::popcnt(const uint32_t from) const return popcnt; } -void PackedRow::fill(vec& tmp_clause, const vec& assigns, const vector& col_to_var_original) const +const bool PackedRow::fill(vec& tmp_clause, const vec& assigns, const vector& col_to_var_original) const { bool final = !is_true_internal; - + tmp_clause.clear(); uint32_t col = 0; bool wasundef = false; @@ -95,8 +91,8 @@ void PackedRow::fill(vec& tmp_clause, const vec& assigns, const vect if ((mp[i] >> i2) &1) { const Var& var = col_to_var_original[col]; assert(var != std::numeric_limits::max()); - - const lbool& val = assigns[var]; + + const lbool val = assigns[var]; const bool val_bool = val.getBool(); tmp_clause.push(Lit(var, val_bool)); final ^= val_bool; @@ -115,6 +111,7 @@ void PackedRow::fill(vec& tmp_clause, const vec& assigns, const vect //assert(ps != ps_first+1); } else assert(!final); + + return wasundef; } -}; //NAMESPACE MINISAT diff --git a/src/sat/cryptominisat2/PackedRow.h b/src/sat/cryptominisat2/PackedRow.h index 8760998..87a8a05 100644 --- a/src/sat/cryptominisat2/PackedRow.h +++ b/src/sat/cryptominisat2/PackedRow.h @@ -33,16 +33,9 @@ along with this program. If not, see . #include #include #include -#ifndef uint -#define uint unsigned int -#endif using std::vector; -namespace MINISAT -{ -using namespace MINISAT; - class PackedMatrix; @@ -51,7 +44,7 @@ class PackedRow public: bool operator ==(const PackedRow& b) const; bool operator !=(const PackedRow& b) const; - + PackedRow& operator=(const PackedRow& b) { #ifdef DEBUG_ROW @@ -59,11 +52,11 @@ public: 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 @@ -71,15 +64,15 @@ public: 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 @@ -87,21 +80,21 @@ public: 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 { - char popcount = 0; + uint32_t popcount = 0; for (uint32_t i = 0; i != size; i++) { uint64_t tmp = mp[i]; while(tmp) { @@ -111,15 +104,15 @@ public: } return popcount == 1; } - + 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; @@ -157,7 +150,7 @@ public: { mp[i/64] |= ((uint64_t)1 << (i%64)); } - + void swapBoth(PackedRow b) { #ifdef DEBUG_ROW @@ -165,12 +158,12 @@ public: 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++; @@ -184,7 +177,7 @@ public: #ifdef DEBUG_ROW assert(size*64 > i); #endif - + return (mp[i/64] >> (i%64)) & 1; } @@ -197,44 +190,38 @@ public: 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::max()); - + setBit(toset_var); } - - is_true_internal = !v.xor_clause_inverted(); + + is_true_internal = !v.xorEqualFalse(); } - - void fill(vec& tmp_clause, const vec& assigns, const vector& col_to_var_original) const; - + + const bool fill(vec& tmp_clause, const vec& assigns, const vector& 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++) + + for(uint32_t i = var; i != size*64; i++) { if (this->operator[](i)) return i; - return std::numeric_limits::max(); + } + + return std::numeric_limits::max(); } friend std::ostream& operator << (std::ostream& os, const PackedRow& m); -#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ == 0)) -// Workaround for GCC 4.0 which doesn't extend friendship to nested classes. See -// http://stackoverflow.com/questions/3584385/friend-access-to-protected-nested-class -// for details. -public: -#else private: friend class PackedMatrix; -#endif PackedRow(const uint32_t _size, uint64_t* const _mp) : mp(_mp+1) , is_true_internal(*_mp) , size(_size) {} -private: uint64_t* __restrict const mp; uint64_t& is_true_internal; const uint32_t size; @@ -242,7 +229,5 @@ private: std::ostream& operator << (std::ostream& os, const PackedRow& m); -}; //NAMESPACE MINISAT - #endif //PACKEDROW_H diff --git a/src/sat/cryptominisat2/PartFinder.cpp b/src/sat/cryptominisat2/PartFinder.cpp index 969afe6..325b5ec 100644 --- a/src/sat/cryptominisat2/PartFinder.cpp +++ b/src/sat/cryptominisat2/PartFinder.cpp @@ -28,7 +28,7 @@ along with this program. If not, see . #include #include #include -#include "FailedVarSearcher.h" +#include "FailedLitSearcher.h" using std::set; using std::map; @@ -39,10 +39,6 @@ using std::endl; //#define PART_FINDING -namespace MINISAT -{ -using namespace MINISAT; - PartFinder::PartFinder(Solver& _solver) : solver(_solver) { @@ -50,112 +46,134 @@ PartFinder::PartFinder(Solver& _solver) : const bool PartFinder::findParts() { - assert(solver.performReplace); - + assert(solver.conf.doReplace); + double time = cpuTime(); - + table.clear(); table.resize(solver.nVars(), std::numeric_limits::max()); reverseTable.clear(); part_no = 0; - + solver.clauseCleaner->removeAndCleanAll(true); if (!solver.ok) return false; while (solver.varReplacer->getNewToReplaceVars() > 0) { - if (solver.performReplace && !solver.varReplacer->performReplace(true)) + if (solver.conf.doReplace && !solver.varReplacer->performReplace(true)) return false; solver.clauseCleaner->removeAndCleanAll(true); if (!solver.ok) return false; } - assert(solver.varReplacer->getClauses().size() == 0); - + addToPart(solver.clauses); - addToPart(solver.binaryClauses); + addToPartBins(); addToPart(solver.xorclauses); - - const uint parts = setParts(); - + + const uint32_t parts = setParts(); + #ifndef NDEBUG - for (map >::const_iterator it = reverseTable.begin(); it != reverseTable.end(); it++) { - for (uint i2 = 0; i2 < it->second.size(); i2++) { + for (map >::const_iterator it = reverseTable.begin(); it != reverseTable.end(); it++) { + for (uint32_t i2 = 0; i2 < it->second.size(); i2++) { assert(table[(it->second)[i2]] == it->first); } } #endif - - if (solver.verbosity >= 2 || (solver.verbosity >=1 && parts > 1)) { - std::cout << "c | Found parts: " << std::setw(10) << parts + + if (solver.conf.verbosity >= 3 || (solver.conf.verbosity >=1 && parts > 1)) { + std::cout << "c Found parts: " << std::setw(10) << parts << " time: " << std::setprecision(2) << std::setw(4) << cpuTime() - time - << " s" << std::setw(51) << " |" << std::endl; + << " s" + << std::endl; } - + return true; } template void PartFinder::addToPart(const vec& cs) { - set tomerge; - vector newSet; for (T* const* c = cs.getData(), * const*end = c + cs.size(); c != end; c++) { if ((*c)->learnt()) continue; - tomerge.clear(); - newSet.clear(); - for (const Lit *l = (*c)->getData(), *end2 = l + (*c)->size(); l != end2; l++) { - if (table[l->var()] != std::numeric_limits::max()) - tomerge.insert(table[l->var()]); - else - newSet.push_back(l->var()); - } - if (tomerge.size() == 1) { - //no trees to merge, only merge the clause into one tree - - const uint into = *tomerge.begin(); - map >::iterator intoReverse = reverseTable.find(into); - for (uint i = 0; i < newSet.size(); i++) { - intoReverse->second.push_back(newSet[i]); - table[newSet[i]] = into; + addToPartClause(**c); + } +} + +void PartFinder::addToPartBins() +{ + vec lits(2); + uint32_t wsLit = 0; + for (const vec *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + lits[0] = lit; + const vec& ws = *it; + for (const Watched *it2 = ws.getData(), *end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary() && lit.toInt() < it2->getOtherLit().toInt()) { + if (it2->getLearnt()) continue; + lits[1] = it2->getOtherLit(); + addToPartClause(lits); } - continue; } - - for (set::iterator it = tomerge.begin(); it != tomerge.end(); it++) { - newSet.insert(newSet.end(), reverseTable[*it].begin(), reverseTable[*it].end()); - reverseTable.erase(*it); + } +} + +template +void PartFinder::addToPartClause(T& cl) +{ + set tomerge; + vector newSet; + for (const Lit *l = cl.getData(), *end2 = cl.getDataEnd(); l != end2; l++) { + if (table[l->var()] != std::numeric_limits::max()) + tomerge.insert(table[l->var()]); + else + newSet.push_back(l->var()); + } + if (tomerge.size() == 1) { + //no trees to merge, only merge the clause into one tree + + const uint32_t into = *tomerge.begin(); + map >::iterator intoReverse = reverseTable.find(into); + for (uint32_t i = 0; i < newSet.size(); i++) { + intoReverse->second.push_back(newSet[i]); + table[newSet[i]] = into; } - - for (uint i = 0; i < newSet.size(); i++) - table[newSet[i]] = part_no; - reverseTable[part_no] = newSet; - part_no++; + return; } + + for (set::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]] = part_no; + reverseTable[part_no] = newSet; + part_no++; } -const uint PartFinder::setParts() +const uint32_t PartFinder::setParts() { - vector numClauseInPart(part_no, 0); - vector sumLitsInPart(part_no, 0); - + vector numClauseInPart(part_no, 0); + vector sumLitsInPart(part_no, 0); + calcIn(solver.clauses, numClauseInPart, sumLitsInPart); - calcIn(solver.binaryClauses, numClauseInPart, sumLitsInPart); + calcInBins(numClauseInPart, sumLitsInPart); calcIn(solver.xorclauses, numClauseInPart, sumLitsInPart); - - uint parts = 0; - for (uint i = 0; i < numClauseInPart.size(); i++) { + + uint32_t parts = 0; + for (uint32_t i = 0; i < numClauseInPart.size(); i++) { if (sumLitsInPart[i] == 0) continue; - if (solver.verbosity >= 2 || ( solver.verbosity >= 1 && reverseTable.size() > 1) ) { - std::cout << "c | Found part " << std::setw(8) << i + if (solver.conf.verbosity >= 3 || ( solver.conf.verbosity >= 1 && reverseTable.size() > 1) ) { + std::cout << "c Found part " << std::setw(8) << i << " vars: " << std::setw(10) << reverseTable[i].size() << " clauses:" << std::setw(10) << numClauseInPart[i] << " lits size:" << std::setw(10) << sumLitsInPart[i] - << std::setw(12) << " | " << std::endl; + << std::endl; } parts++; } - + if (parts > 1) { #ifdef VERBOSE_DEBUG - for (map >::iterator it = reverseTable.begin(), end = reverseTable.end(); it != end; it++) { + for (map >::iterator it = reverseTable.begin(), end = reverseTable.end(); it != end; it++) { cout << "-- set begin --" << endl; for (vector::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { cout << *it2 << ", "; @@ -164,23 +182,41 @@ const uint PartFinder::setParts() } #endif } - + return parts; } +void PartFinder::calcInBins(vector& numClauseInPart, vector& sumLitsInPart) +{ + uint32_t wsLit = 0; + for (const vec *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec& ws = *it; + for (const Watched *it2 = ws.getData(), *end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary() && lit.toInt() < it2->getOtherLit().toInt()) { + if (it2->getLearnt()) continue; + + const uint32_t part = table[lit.var()]; + assert(part < part_no); + numClauseInPart[part]++; + sumLitsInPart[part] += 2; + } + } + } +} + template -void PartFinder::calcIn(const vec& cs, vector& numClauseInPart, vector& sumLitsInPart) +void PartFinder::calcIn(const vec& cs, vector& numClauseInPart, vector& sumLitsInPart) { for (T*const* c = cs.getData(), *const*end = c + cs.size(); c != end; c++) { if ((*c)->learnt()) continue; T& x = **c; - const uint part = table[x[0].var()]; + const uint32_t part = table[x[0].var()]; assert(part < part_no); - + //for stats numClauseInPart[part]++; sumLitsInPart[part] += x.size(); } } -}; //NAMESPACE MINISAT diff --git a/src/sat/cryptominisat2/PartFinder.h b/src/sat/cryptominisat2/PartFinder.h index a3261d7..27a7921 100644 --- a/src/sat/cryptominisat2/PartFinder.h +++ b/src/sat/cryptominisat2/PartFinder.h @@ -28,10 +28,6 @@ along with this program. If not, see . #include "Clause.h" -namespace MINISAT -{ -using namespace MINISAT; - class Solver; using std::map; @@ -39,37 +35,39 @@ using std::vector; using std::pair; class PartFinder { - + public: PartFinder(Solver& solver); const bool findParts(); - + const map >& getReverseTable() const; // part->var const uint32_t getVarPart(const Var var) const; const vector& getTable() const; //var -> part const vector& getPartVars(const uint32_t part); - + private: - const uint setParts(); - template - void addToPart(const vec& cs); - + const uint32_t setParts(); + void addToPartBins(); + template void addToPartClause(T& cl); + template void addToPart(const vec& cs); + struct mysorter { - bool operator () (const pair& left, const pair& right) + bool operator () (const pair& left, const pair& right) { return left.second < right.second; } }; - + //const bool findParts(vector& xorFingerprintInMatrix, vector& xorsInMatrix); template - void calcIn(const vec& cs, vector& numClauseInPart, vector& sumLitsInPart); - + void calcIn(const vec& cs, vector& numClauseInPart, vector& sumLitsInPart); + void calcInBins(vector& numClauseInPart, vector& sumLitsInPart); + map > reverseTable; //part -> vars vector table; //var -> part uint32_t part_no; - + Solver& solver; }; @@ -93,6 +91,4 @@ inline const vector& PartFinder::getPartVars(const uint32_t part) return reverseTable[part]; } -}; //NAMESPACE MINISAT - #endif //PARTFINDER_H diff --git a/src/sat/cryptominisat2/PartHandler.cpp b/src/sat/cryptominisat2/PartHandler.cpp index 75032fe..0bba710 100644 --- a/src/sat/cryptominisat2/PartHandler.cpp +++ b/src/sat/cryptominisat2/PartHandler.cpp @@ -1,4 +1,4 @@ -/*********************************************************************************** +/***************************************************************************** CryptoMiniSat -- Copyright (c) 2009 Mate Soos This program is free software: you can redistribute it and/or modify @@ -13,7 +13,7 @@ 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 . -**************************************************************************************************/ +******************************************************************************/ #include "PartHandler.h" #include "VarReplacer.h" @@ -23,10 +23,6 @@ along with this program. If not, see . //#define VERBOSE_DEBUG -namespace MINISAT -{ -using namespace MINISAT; - PartHandler::PartHandler(Solver& s) : solver(s) { @@ -35,9 +31,9 @@ PartHandler::PartHandler(Solver& s) : const bool PartHandler::handle() { - if (solver.performReplace == false) + if (solver.conf.doReplace == false) return true; - + PartFinder partFinder(solver); if (!partFinder.findParts()) { #ifdef VERBOSE_DEBUG @@ -45,111 +41,61 @@ const bool PartHandler::handle() #endif //VERBOSE_DEBUG return false; } - + uint32_t num_parts = partFinder.getReverseTable().size(); if (num_parts == 1) return true; - + map > reverseTable = partFinder.getReverseTable(); assert(num_parts == partFinder.getReverseTable().size()); - + vector > sizes; for (map >::iterator it = reverseTable.begin(); it != reverseTable.end(); it++) sizes.push_back(std::make_pair(it->first, (uint32_t)it->second.size())); - + std::sort(sizes.begin(), sizes.end(), sort_pred()); assert(sizes.size() > 1); - + for (uint32_t it = 0; it < sizes.size()-1; it++) { uint32_t part = sizes[it].first; vector vars = reverseTable[part]; - if (solver.verbosity >= 1) + if (solver.conf.verbosity >= 1) std::cout << "c Solving part " << part << std::endl; - + Solver newSolver; - newSolver.mtrand.seed(solver.mtrand.randInt()); - newSolver.random_var_freq = solver.random_var_freq; - newSolver.verbosity = solver.verbosity; - newSolver.restrictedPickBranch = solver.restrictedPickBranch; - newSolver.greedyUnbound = solver.greedyUnbound; - newSolver.findNormalXors = solver.findNormalXors; - newSolver.findBinaryXors = solver.findBinaryXors; - newSolver.regularlyFindBinaryXors = solver.regularlyFindBinaryXors; - newSolver.conglomerateXors = solver.conglomerateXors; - newSolver.schedSimplification = solver.schedSimplification; - newSolver.performReplace = solver.performReplace; - newSolver.failedVarSearch = solver.failedVarSearch; - newSolver.gaussconfig.dontDisable = solver.gaussconfig.dontDisable; - newSolver.heuleProcess = solver.heuleProcess; - newSolver.doSubsumption = solver.doSubsumption; - newSolver.doPartHandler = solver.doPartHandler; - newSolver.fixRestartType = solver.fixRestartType; - newSolver.var_inc = solver.var_inc; - newSolver.polarity_mode = solver.polarity_mode; - - //Memory-usage reduction - newSolver.schedSimplification = false; - newSolver.doSubsumption = false; - newSolver.doXorSubsumption = false; - newSolver.doPartHandler = false; - newSolver.subsumeWithNonExistBinaries = false; - newSolver.regularSubsumeWithNonExistBinaries = false; - - std::sort(vars.begin(), vars.end()); - uint32_t i2 = 0; - for (Var var = 0; var < solver.nVars(); var++) { - if (i2 < vars.size() && vars[i2] == var) { - #ifdef VERBOSE_DEBUG - if (!solver.decision_var[var]) { - std::cout << "var " << var + 1 << " is non-decision, but in part... strange." << std::endl; - } - #endif //VERBOSE_DEBUG - newSolver.newVar(solver.decision_var[var]); - newSolver.activity[var] = solver.activity[var]; - newSolver.order_heap.update(var); - assert(partFinder.getVarPart(var) == part); - if (solver.decision_var[var]) { - solver.setDecisionVar(var, false); - decisionVarRemoved.push(var); - } - i2++; - } else { - assert(partFinder.getVarPart(var) != part); - newSolver.newVar(false); - } - } - solver.order_heap.filter(Solver::VarFilter(solver)); - - assert(solver.varReplacer->getClauses().size() == 0); + configureNewSolver(newSolver); + moveVariablesBetweenSolvers(newSolver, vars, part, partFinder); + + moveBinClauses(newSolver, part, partFinder); moveClauses(solver.clauses, newSolver, part, partFinder); - moveClauses(solver.binaryClauses, newSolver, part, partFinder); moveClauses(solver.xorclauses, newSolver, part, partFinder); - moveLearntClauses(solver.binaryClauses, newSolver, part, partFinder); moveLearntClauses(solver.learnts, newSolver, part, partFinder); assert(checkClauseMovement(newSolver, part, partFinder)); - + lbool status = newSolver.solve(); + assert(status != l_Undef); if (status == l_False) { #ifdef VERBOSE_DEBUG std::cout << "c One of the sub-problems was UNSAT. Whole problem is unsat." << std::endl; #endif //VERBOSE_DEBUG return false; } - assert(status != l_Undef); - + + //Check that the newly found solution is really unassigned in the + //original solver for (Var var = 0; var < newSolver.nVars(); var++) { if (newSolver.model[var] != l_Undef) { assert(solver.assigns[var] == l_Undef); } } - + assert(newSolver.decisionLevel() == 0); for (uint32_t i = 0; i < newSolver.trail.size(); i++) { solver.uncheckedEnqueue(newSolver.trail[i]); } solver.ok = (solver.propagate().isNULL()); assert(solver.ok); - + for (Var var = 0; var < newSolver.nVars(); var++) { if (newSolver.model[var] != l_Undef) { //Must have been decision var in the old solver!?? @@ -161,44 +107,118 @@ const bool PartHandler::handle() } } } - - if (solver.verbosity >= 1) + + if (solver.conf.verbosity >= 1) { std::cout << "c Solved part" << std::endl; + std::cout << "c " + << "=========================================================================================" + << std::endl; + } } - if (solver.verbosity >= 1) + if (solver.conf.verbosity >= 1) { std::cout << "c Coming back to original instance" - << std::setw(57) << " |" << std::endl; - + << std::endl; + std::cout << "c " + << "=========================================================================================" + << std::endl; + } + solver.order_heap.filter(Solver::VarFilter(solver)); - - //Checking that all variables that are not in the remaining part are all non-decision vars, and none have been set + + //Checking that all variables that are not in the remaining part are all + //non-decision vars, and none have been assigned for (Var var = 0; var < solver.nVars(); var++) { if (savedState[var] != l_Undef) { assert(solver.decision_var[var] == false); assert(solver.assigns[var] == l_Undef || solver.level[var] == 0); } } - + //Checking that all remaining clauses contain only variables that are in the remaining part assert(checkClauseMovement(solver, sizes[sizes.size()-1].first, partFinder)); - + return true; } +/** +@brief Sets up the sub-solver with a specific configuration + +We need to save on memory, since there might be many subsolvers. We also +need to pass all configurations from the original solver to the sub-solver. +*/ +void PartHandler::configureNewSolver(Solver& newSolver) const +{ + newSolver.mtrand.seed(solver.mtrand.randInt()); + newSolver.conf = solver.conf; + newSolver.gaussconfig = solver.gaussconfig; + + //Memory-usage reduction + newSolver.conf.doSchedSimp = false; + newSolver.conf.doSatELite = false; + newSolver.conf.doXorSubsumption = false; + newSolver.conf.doPartHandler = false; + newSolver.conf.doSubsWNonExistBins = false; +} + +/** +@brief Moves the variables to the new solver, and removes it from the original one + +This implies making the right variables decision in the new solver, +and making it non-decision in the old solver. +*/ +void PartHandler::moveVariablesBetweenSolvers(Solver& newSolver, vector& vars, const uint32_t part, const PartFinder& partFinder) +{ + std::sort(vars.begin(), vars.end()); + uint32_t i2 = 0; + for (Var var = 0; var < solver.nVars(); var++) { + if (i2 < vars.size() && vars[i2] == var) { + #ifdef VERBOSE_DEBUG + if (!solver.decision_var[var]) { + std::cout << "var " << var + 1 << " is non-decision, but in part... strange." << std::endl; + } + #endif //VERBOSE_DEBUG + newSolver.newVar(solver.decision_var[var]); + newSolver.activity[var] = solver.activity[var]; + newSolver.order_heap.update(var); + assert(partFinder.getVarPart(var) == part); + if (solver.decision_var[var]) { + solver.setDecisionVar(var, false); + decisionVarRemoved.push(var); + } + i2++; + } else { + assert(partFinder.getVarPart(var) != part); + newSolver.newVar(false); + } + } + solver.order_heap.filter(Solver::VarFilter(solver)); +} + +/** +@brief Check that when we moved the clauses, we did a good job + +I.e. we did not move clauses into a part where they don't belong +*/ const bool PartHandler::checkClauseMovement(const Solver& thisSolver, const uint32_t part, const PartFinder& partFinder) const { if (!checkOnlyThisPart(thisSolver.clauses, part, partFinder)) return false; if (!checkOnlyThisPart(thisSolver.learnts, part, partFinder)) return false; - if (!checkOnlyThisPart(thisSolver.binaryClauses, part, partFinder)) + if (!checkOnlyThisPartBin(thisSolver, part, partFinder)) return false; if (!checkOnlyThisPart(thisSolver.xorclauses, part, partFinder)) return false; - + return true; } +/** +@brief Check that clauses only contain variables belonging to this partFinder + +@p cs The clause-list to check +@p part The part that we should check that the clauses belong to +*/ template const bool PartHandler::checkOnlyThisPart(const vec& cs, const uint32_t part, const PartFinder& partFinder) const { @@ -208,33 +228,151 @@ const bool PartHandler::checkOnlyThisPart(const vec& cs, const uint32_t part if (partFinder.getVarPart(l->var()) != part) return false; } } - + return true; } +const bool PartHandler::checkOnlyThisPartBin(const Solver& thisSolver, const uint32_t part, const PartFinder& partFinder) const +{ + bool retval = true; + uint32_t wsLit = 0; + for (const vec *it = thisSolver.watches.getData(), *end = thisSolver.watches.getDataEnd(); it != end; it++, wsLit++) { + const Lit lit = ~Lit::toLit(wsLit); + const vec& ws = *it; + for (const Watched *it2 = ws.getData(), *end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary()) { + if (partFinder.getVarPart(lit.var()) != part + || partFinder.getVarPart(it2->getOtherLit().var()) != part + ) { + std::cout << "bin incorrectly moved to this part:" << lit << " , " << it2->getOtherLit() << std::endl; + retval = false; + } + } + } + } + + return retval; +} + +/** +@brief Move clauses from original to the part + +The variables that form part of the part will determine if the clause is in the +part or not +*/ void PartHandler::moveClauses(vec& cs, Solver& newSolver, const uint32_t part, PartFinder& partFinder) { Clause **i, **j, **end; for (i = j = cs.getData(), j = i , end = i + cs.size(); i != end; i++) { - if ((**i).learnt() || partFinder.getVarPart((**i)[0].var()) != part) { - *j++ = *i; - continue; + Clause& c = **i; + if (!c.learnt()) { + if (partFinder.getVarPart(c[0].var()) != part) { + //different part, move along + *j++ = *i; + continue; + } + //later we will move it } - solver.detachClause(**i); + if (c.learnt()) { + bool thisPart = false; + bool otherPart = false; + for (Lit* l = c.getData(), *end2 = c.getDataEnd(); l != end2; l++) { + if (partFinder.getVarPart(l->var()) == part) thisPart = true; + if (partFinder.getVarPart(l->var()) != part) otherPart = true; + } + //in both parts, remove it + if (thisPart && otherPart) { + solver.detachClause(c); + solver.clauseAllocator.clauseFree(&c); + continue; + } + if (!thisPart) { + //different part, move along + *j++ = *i; + continue; + } + assert(thisPart && !otherPart); + } + + solver.detachClause(c); #ifdef VERBOSE_DEBUG std::cout << "clause in this part:"; (**i).plainPrint(); #endif - Clause& c = **i; vec tmp(c.size()); std::copy(c.getData(), c.getDataEnd(), tmp.getData()); newSolver.addClause(tmp, c.getGroup()); - //NOTE: we need the CS because otherwise, the addClause could have changed **i, which we need to re-add later! + //NOTE: we need the tmp because otherwise, the addClause could have changed "c", which we need to re-add later! clausesRemoved.push(*i); } cs.shrink(i-j); } +void PartHandler::moveBinClauses(Solver& newSolver, const uint32_t part, PartFinder& partFinder) +{ + uint32_t numRemovedHalfNonLearnt = 0; + uint32_t numRemovedHalfLearnt = 0; + + uint32_t wsLit = 0; + for (vec *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + const Lit lit = ~Lit::toLit(wsLit); + vec& ws = *it; + + Watched *i = ws.getData(); + Watched *j = i; + for (Watched *end2 = ws.getDataEnd(); i != end2; i++) { + if (i->isBinary() + && (partFinder.getVarPart(lit.var()) == part || partFinder.getVarPart(i->getOtherLit().var()) == part)) + { + const Lit lit2 = i->getOtherLit(); + assert((partFinder.getVarPart(lit2.var()) == part && partFinder.getVarPart(lit.var()) == part) || i->getLearnt()); + + //If it's learnt and the lits are in different parts, remove it. + if (partFinder.getVarPart(lit.var()) != part + || partFinder.getVarPart(lit2.var()) != part + ) { + assert(i->getLearnt()); + numRemovedHalfLearnt++; + continue; + } + + assert(lit != lit2); + if (lit < lit2) { //don't add the same clause twice + vec lits(2); + lits[0] = lit; + lits[1] = lit2; + assert(partFinder.getVarPart(lit.var()) == part); + assert(partFinder.getVarPart(lit2.var()) == part); + if (i->getLearnt()) { + newSolver.addLearntClause(lits); + binClausesRemoved.push_back(std::make_pair(lit, lit2)); + numRemovedHalfLearnt++; + } else { + newSolver.addClause(lits); + numRemovedHalfNonLearnt++; + } + } else { + if (i->getLearnt()) numRemovedHalfLearnt++; + else numRemovedHalfNonLearnt++; + } + } else { + *j++ = *i; + } + } + ws.shrink_(i-j); + } + + solver.learnts_literals -= numRemovedHalfLearnt; + solver.clauses_literals -= numRemovedHalfNonLearnt; + solver.numBins -= (numRemovedHalfLearnt + numRemovedHalfNonLearnt)/2; +} + +/** +@brief Move xor clauses from original to the part + +The variables that form part of the part will determine if the clause is in the +part or not +*/ void PartHandler::moveClauses(vec& cs, Solver& newSolver, const uint32_t part, PartFinder& partFinder) { XorClause **i, **j, **end; @@ -251,13 +389,23 @@ void PartHandler::moveClauses(vec& cs, Solver& newSolver, const uint XorClause& c = **i; vec tmp(c.size()); std::copy(c.getData(), c.getDataEnd(), tmp.getData()); - newSolver.addXorClause(tmp, c.xor_clause_inverted(), c.getGroup()); - //NOTE: we need the CS because otherwise, the addXorClause could have changed **i, which we need to re-add later! + newSolver.addXorClause(tmp, c.xorEqualFalse(), c.getGroup()); + //NOTE: we need the tmp because otherwise, the addXorClause could have changed "c", which we need to re-add later! xorClausesRemoved.push(*i); } cs.shrink(i-j); } +/** +@brief Move learnt clauses from original to the part + +The variables that form part of the part will determine if the clause is in the +part or not. + +Note that learnt clauses might be in both the orignal and the sub-part. In this +case, the learnt clause is deleted, since it unneccesarily connects two +components that otherwise would be distinct +*/ void PartHandler::moveLearntClauses(vec& cs, Solver& newSolver, const uint32_t part, PartFinder& partFinder) { Clause **i, **j, **end; @@ -266,7 +414,7 @@ void PartHandler::moveLearntClauses(vec& cs, Solver& newSolver, const u *j++ = *i; continue; } - + Clause& c = **i; assert(c.size() > 0); uint32_t clause_part = partFinder.getVarPart(c[0].var()); @@ -276,7 +424,7 @@ void PartHandler::moveLearntClauses(vec& cs, Solver& newSolver, const u #ifdef VERBOSE_DEBUG std::cout << "Learnt clause in both parts:"; c.plainPrint(); #endif - + removed = true; solver.removeClause(c); break; @@ -287,21 +435,30 @@ void PartHandler::moveLearntClauses(vec& cs, Solver& newSolver, const u #ifdef VERBOSE_DEBUG //std::cout << "Learnt clause in this part:"; c.plainPrint(); #endif - + solver.detachClause(c); - newSolver.addLearntClause(c, c.getGroup(), c.activity()); + newSolver.addLearntClause(c, c.getGroup(), NULL, c.getGlue(), c.getMiniSatAct()); solver.clauseAllocator.clauseFree(&c); } else { #ifdef VERBOSE_DEBUG std::cout << "Learnt clause in other part:"; c.plainPrint(); #endif - + *j++ = *i; } } cs.shrink(i-j); } +/** +@brief Adds the saved states to the final solutions + +It is only called if the solution of the main part was SAT, and the parts +have all been SAT. We now basically extend the main part with the solutions +of the sub-parts. + +Sets all saved states to l_Undef, i.e. unassigns them +*/ void PartHandler::addSavedState() { //Don't add these (non-0-decison-level!) solutions to the 0th decision level @@ -315,12 +472,23 @@ void PartHandler::addSavedState() solver.polarity[var] = (solver.assigns[var] == l_False); } } - + for (uint32_t i = 0; i < decisionVarRemoved.size(); i++) solver.setDecisionVar(decisionVarRemoved[i], true); decisionVarRemoved.clear(); } +/** +@brief Re-add the clauses that have been removed because they were in a part + +We remove the clauses that are are in a part. Then, at the very end of the +solving, we must re-add them, since if the program is used a library, then +solve() might be called again, at which point we would be missing our clauses! + +(Furhtermore, clauses might be added between the end of solving and the +next solve() command, so we cannot keep in memory which parts were what, because +parts might be connected through the added clauses) +*/ void PartHandler::readdRemovedClauses() { FILE* backup_libraryCNFfile = solver.libraryCNFFile; @@ -330,13 +498,22 @@ void PartHandler::readdRemovedClauses() assert(solver.ok); } clausesRemoved.clear(); - + for (XorClause **it = xorClausesRemoved.getData(), **end = xorClausesRemoved.getDataEnd(); it != end; it++) { - solver.addXorClause(**it, (**it).xor_clause_inverted(), (*it)->getGroup()); + solver.addXorClause(**it, (**it).xorEqualFalse(), (*it)->getGroup()); assert(solver.ok); } xorClausesRemoved.clear(); + + for (vector >::const_iterator it = binClausesRemoved.begin(), end = binClausesRemoved.end(); it != end; it++) { + vec lits(2); + lits[0] = it->first; + lits[1] = it->second; + solver.addClause(lits); + assert(solver.ok); + } + binClausesRemoved.clear(); + solver.libraryCNFFile = backup_libraryCNFfile; } -}; //NAMESPACE MINISAT diff --git a/src/sat/cryptominisat2/PartHandler.h b/src/sat/cryptominisat2/PartHandler.h index f73bc98..7751d2b 100644 --- a/src/sat/cryptominisat2/PartHandler.h +++ b/src/sat/cryptominisat2/PartHandler.h @@ -29,10 +29,14 @@ using std::map; using std::vector; using std::pair; -namespace MINISAT -{ -using namespace MINISAT; +/** +@brief Disconnected components are treated here +Uses PartFinder to find disconnected components and treats them using +subsolvers. The solutions (if SAT) are aggregated, and at then end, the +solution is extended with the sub-solutions, and the removed clauses are +added back to the problem. +*/ class PartHandler { public: @@ -44,41 +48,64 @@ class PartHandler void readdRemovedClauses(); friend class ClauseAllocator; - + private: struct sort_pred { bool operator()(const std::pair &left, const std::pair &right) { return left.second < right.second; } }; - + + void configureNewSolver(Solver& newSolver) const; + void moveVariablesBetweenSolvers(Solver& newSolver, vector& vars, const uint32_t part, const PartFinder& partFinder); + //For moving clauses + void moveBinClauses(Solver& newSolver, const uint32_t part, PartFinder& partFinder); void moveClauses(vec& cs, Solver& newSolver, const uint32_t part, PartFinder& partFinder); void moveClauses(vec& cs, Solver& newSolver, const uint32_t part, PartFinder& partFinder); void moveLearntClauses(vec& cs, Solver& newSolver, const uint32_t part, PartFinder& partFinder); - + //Checking moved clauses const bool checkClauseMovement(const Solver& thisSolver, const uint32_t part, const PartFinder& partFinder) const; template const bool checkOnlyThisPart(const vec& cs, const uint32_t part, const PartFinder& partFinder) const; - - Solver& solver; + const bool checkOnlyThisPartBin(const Solver& thisSolver, const uint32_t part, const PartFinder& partFinder) const; + + Solver& solver; /// savedState; - vec decisionVarRemoved; //variables whose decision-ness has been removed + vec decisionVarRemoved; /// clausesRemoved; + vector > binClausesRemoved; vec xorClausesRemoved; }; +/** +@brief Returns the saved state of a variable +*/ inline const vec& PartHandler::getSavedState() { return savedState; } +/** +@brief Creates a space in savedState + +So that the solution can eventually be saved here (if parts are used). By +default the value is l_Undef, i.e. no solution has been saved there. +*/ inline void PartHandler::newVar() { savedState.push(l_Undef); } -}; //NAMESPACE MINISAT + #endif //PARTHANDLER_H diff --git a/src/sat/cryptominisat2/PropBy.h b/src/sat/cryptominisat2/PropBy.h new file mode 100644 index 0000000..92f8464 --- /dev/null +++ b/src/sat/cryptominisat2/PropBy.h @@ -0,0 +1,288 @@ +/*********************************************************************** +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 . +************************************************************************/ + +#ifndef PROPBY_H +#define PROPBY_H + +#include "SolverTypes.h" +#include "Clause.h" +#ifdef _MSC_VER +#include +#else +#include +#endif //_MSC_VER +#include + +//#define DEBUG_PROPAGATEFROM + +#include "ClauseOffset.h" +#include "ClauseAllocator.h" + +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()) + { + } + + const bool isClause() const + { + return ((propType&2) == 0); + } + + const bool isBinary() const + { + return (propType == 2); + } + + const bool isTri() const + { + return (propType == 3); + } + + const Lit getOtherLit() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(isBinary() || isTri()); + #endif + return Lit::toLit(data1); + } + + const Lit getOtherLit2() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(isTri()); + #endif + return Lit::toLit(data2); + } + + const ClauseOffset getClause() const + { + #ifdef DEBUG_PROPAGATEFROM + assert(isClause()); + #endif + return data2; + } + + ClauseOffset getClause() + { + #ifdef DEBUG_PROPAGATEFROM + assert(isClause()); + #endif + return data2; + } + + const bool isNULL() const + { + if (!isClause()) return false; + return propType == 0; + } + + /*const uint32_t size() const + { + if (isBinary()) return 2; + if (isTri()) return 3; + + #ifdef DEBUG_PROPAGATEFROM + assert(!isNULL()); + #endif + + return getClause()->size(); + }*/ + + /*const Lit operator[](uint32_t i) const + { + if (isBinary()) { + #ifdef DEBUG_PROPAGATEFROM + assert(i == 1); + #endif + return getOtherLit(); + } + + if (isTriClause()) { + #ifdef DEBUG_PROPAGATEFROM + assert(i <= 2); + #endif + if (i == 1) return getOtherLit(); + if (i == 2) return getOtherLit2(); + } + + #ifdef DEBUG_PROPAGATEFROM + assert(!isNULL()); + #endif + return (*getClause())[i]; + }*/ +}; + +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(PropByFull& other) : + type(other.type) + , clause(other.clause) + { + memcpy(lits, other.lits, sizeof(Lit)*3); + } + + const uint32_t size() const + { + switch (type) { + case 0 : return clause->size(); + case 1 : return 2; + case 2 : return 3; + default: + assert(false); + return 0; + } + } + + const bool isNULL() const + { + return type == 0 && clause == NULL; + } + + const bool isClause() const + { + return type == 0; + } + + const bool isBinary() const + { + return type == 1; + } + + const bool isTri() const + { + return type == 2; + } + + const Clause* getClause() const + { + return clause; + } + + Clause* getClause() + { + return clause; + } + + const 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: " << " ? , " <. -**************************************************************************************************/ +*****************************************************************************/ #include "RestartTypeChooser.h" + +#include #include "Solver.h" +using std::pair; //#define VERBOSE_DEBUG //#define PRINT_VARS -namespace MINISAT -{ -using namespace MINISAT; - RestartTypeChooser::RestartTypeChooser(const Solver& s) : solver(s) , topX(100) @@ -32,14 +31,20 @@ RestartTypeChooser::RestartTypeChooser(const Solver& s) : { } +/** +@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(); - uint sameIn = 0; + uint32_t sameIn = 0; if (!firstVarsOld.empty()) { - uint thisTopX = std::min(firstVarsOld.size(), (size_t)topX); - for (uint i = 0; i != thisTopX; i++) { + 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++; } @@ -48,16 +53,19 @@ void RestartTypeChooser::addInfo() #endif sameIns.push_back(sameIn); } - + #ifdef VERBOSE_DEBUG std::cout << "Avg same vars in first&second first 100: " << avg() << " standard Deviation:" << stdDeviation(sameIns) < mypair = countVarsDegreeStDev(); - if ((mypair.second < 80 && + 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)) @@ -66,22 +74,28 @@ const RestartType RestartTypeChooser::choose() return dynamic_restart; } +/** +@brief Calculates average for topx variable activity changes +*/ const double RestartTypeChooser::avg() const { double sum = 0.0; - for (uint i = 0; i != sameIns.size(); i++) + 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 +*/ const double RestartTypeChooser::stdDeviation(vector& measure) const { double average = avg(); double variance = 0.0; - for (uint i = 0; i != measure.size(); i++) + for (uint32_t i = 0; i != measure.size(); i++) variance += pow((double)measure[i]-average, 2); variance /= (double)measure.size(); - + return sqrt(variance); } @@ -110,7 +124,7 @@ const std::pair RestartTypeChooser::countVarsDegreeStDev() const vector degrees; degrees.resize(solver.nVars(), 0); addDegrees(solver.clauses, degrees); - addDegrees(solver.binaryClauses, degrees); + addDegreesBin(degrees); addDegrees(solver.xorclauses, degrees); uint32_t sum = 0; uint32_t *i = °rees[0], *j = i; @@ -121,14 +135,14 @@ const std::pair RestartTypeChooser::countVarsDegreeStDev() const } } 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); } @@ -138,7 +152,7 @@ void RestartTypeChooser::addDegrees(const vec& cs, vector& degrees 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()]++; } @@ -148,5 +162,18 @@ void RestartTypeChooser::addDegrees(const vec& cs, vector& degrees template void RestartTypeChooser::addDegrees(const vec& cs, vector& degrees) const; template void RestartTypeChooser::addDegrees(const vec& cs, vector& degrees) const; -}; //NAMESPACE MINISAT +void RestartTypeChooser::addDegreesBin(vector& degrees) const +{ + uint32_t wsLit = 0; + for (const vec *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec& ws = *it; + for (const Watched *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/sat/cryptominisat2/RestartTypeChooser.h b/src/sat/cryptominisat2/RestartTypeChooser.h index 4c0628d..446b1e9 100644 --- a/src/sat/cryptominisat2/RestartTypeChooser.h +++ b/src/sat/cryptominisat2/RestartTypeChooser.h @@ -30,12 +30,18 @@ along with this program. If not, see . using std::vector; -namespace MINISAT -{ -using namespace MINISAT; - 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: @@ -43,22 +49,24 @@ class RestartTypeChooser void addInfo(); const RestartType choose(); void reset(); - + private: void calcHeap(); const double avg() const; const std::pair countVarsDegreeStDev() const; const double stdDeviation(vector& measure) const; - + template void addDegrees(const vec& cs, vector& degrees) const; - + void addDegreesBin(vector& degrees) const; + const Solver& solver; - const uint32_t topX; - const uint32_t limit; + const uint32_t topX; /// sameIns; - - vector firstVars, firstVarsOld; + + vector firstVars; /// firstVarsOld; ///. +******************************************************************************/ + +#include +#include +#include "SolverTypes.h" +#include "SCCFinder.h" +#include "VarReplacer.h" +#include +#include "time_mem.h" +#include "Subsumer.h" +#include "XorSubsumer.h" + +SCCFinder::SCCFinder(Solver& _solver) : + solver(_solver) + , varElimed1(_solver.subsumer->getVarElimed()) + , varElimed2(_solver.xorSubsumer->getVarElimed()) + , replaceTable(_solver.varReplacer->getReplaceTable()) + , totalTime(0.0) +{} + +const bool SCCFinder::find2LongXors() +{ + double myTime = cpuTime(); + uint32_t oldNumReplace = solver.varReplacer->getNewToReplaceVars(); + + globalIndex = 0; + index.clear(); + index.resize(solver.nVars()*2, std::numeric_limits::max()); + lowlink.clear(); + lowlink.resize(solver.nVars()*2, std::numeric_limits::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::max()) { + recurDepth = 0; + tarjan(vertex); + assert(stack.empty()); + } + } + + if (solver.conf.verbosity >= 2 || (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& ws = solver.watches[vertex]; + for (const Watched *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& transCache = solver.transOTFCache[(~Lit::toLit(vertex)).toInt()].lits; + vector::iterator it = transCache.begin(); + vector::iterator it2 = it; + uint32_t newSize = 0; + for (vector::iterator end = transCache.end(); it != end; it++) { + Lit lit = *it; + lit = replaceTable[lit.var()] ^ lit.sign(); + if (lit == vertLit || varElimed1[lit.var()] || varElimed2[lit.var()]) continue; + *it2++ = 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 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) { + solver.varReplacer->replace(lits, xorEqualsFalse, 0); + } + } + } + } +} diff --git a/src/sat/cryptominisat2/SCCFinder.h b/src/sat/cryptominisat2/SCCFinder.h new file mode 100644 index 0000000..9b60b35 --- /dev/null +++ b/src/sat/cryptominisat2/SCCFinder.h @@ -0,0 +1,68 @@ +/***************************************************************************** +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 . +******************************************************************************/ + +#ifndef SCCFINDER_H +#define SCCFINDER_H + +#include "Vec.h" +#include "Clause.h" +#include "Solver.h" +#include + +class SCCFinder { + public: + SCCFinder(Solver& solver); + const bool find2LongXors(); + const double getTotalTime() const; + + private: + void tarjan(const uint32_t vertex); + void doit(const Lit lit, const uint32_t vertex); + + uint32_t globalIndex; + vector index; + vector lowlink; + std::stack stack; + vec stackIndicator; + vec tmp; + + uint32_t recurDepth; + + Solver& solver; + const vec& varElimed1; + const vec& varElimed2; + const vector& 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::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 const double SCCFinder::getTotalTime() const +{ + return totalTime; +} + +#endif //SCCFINDER_H diff --git a/src/sat/cryptominisat2/SharedData.h b/src/sat/cryptominisat2/SharedData.h new file mode 100644 index 0000000..8688f98 --- /dev/null +++ b/src/sat/cryptominisat2/SharedData.h @@ -0,0 +1,33 @@ +/************************************************************************** +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 . +*****************************************************************************/ + +#ifndef SHARED_DATA_H +#define SHARED_DATA_H + +#include "Vec.h" +#include "SolverTypes.h" + +#include + +class SharedData +{ + public: + vec value; + std::vector > bins; +}; + +#endif //SHARED_DATA_H diff --git a/src/sat/cryptominisat2/Solver.cpp b/src/sat/cryptominisat2/Solver.cpp index d3c353f..79fe687 100644 --- a/src/sat/cryptominisat2/Solver.cpp +++ b/src/sat/cryptominisat2/Solver.cpp @@ -1,23 +1,11 @@ -/****************************************************************************************[Solver.C] +/***************************************************************************** MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson -CryptoMiniSat -- Copyright (c) 2009 Mate Soos glucose -- Gilles Audemard, Laurent Simon (2008) +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. -**************************************************************************************************/ +Original code by MiniSat and glucose authors are under an MIT licence. +Modifications for CryptoMiniSat are under GPLv3 licence. +******************************************************************************/ #include "Solver.h" #include @@ -26,6 +14,7 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include #include #include +#include #include "Clause.h" #include "time_mem.h" @@ -35,143 +24,124 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include "XorFinder.h" #include "ClauseCleaner.h" #include "RestartTypeChooser.h" -#include "FailedVarSearcher.h" +#include "FailedLitSearcher.h" #include "Subsumer.h" #include "PartHandler.h" #include "XorSubsumer.h" #include "StateSaver.h" -#include "UselessBinRemover.h" -#include "OnlyNonLearntBins.h" - -#ifdef USE_GAUSS +#include "SCCFinder.h" +#include "SharedData.h" +#include "ClauseVivifier.h" #include "Gaussian.h" #include "MatrixFinder.h" -#endif //USE_GAUSS +#include "DataSync.h" #ifdef _MSC_VER #define __builtin_prefetch(a,b,c) //#define __builtin_prefetch(a,b) #endif //_MSC_VER +#ifdef VERBOSE_DEBUG +#define UNWINDING_DEBUG +#endif + //#define DEBUG_UNCHECKEDENQUEUE_LEVEL0 //#define VERBOSE_DEBUG_POLARITIES //#define DEBUG_DYNAMIC_RESTART - -namespace MINISAT -{ -using namespace MINISAT; +//#define UNWINDING_DEBUG //================================================================================================= // Constructor/Destructor: -Solver::Solver() : +/** +@brief Sets a sane default config and allocates handler classes +*/ +Solver::Solver(const SolverConf& _conf, const GaussConf& _gaussconfig, SharedData* sharedData) : // Parameters: (formerly in 'SearchParams') - random_var_freq(0.02) - , clause_decay (1 / 0.999) - , restart_first(100), restart_inc(1.5), learntsize_factor((double)1/(double)3), learntsize_inc(1) - - // More parameters: - // - , expensive_ccmin (true) - , polarity_mode (polarity_auto) - , verbosity (0) - , restrictedPickBranch(0) - , findNormalXors (true) - , findBinaryXors (true) - , regularlyFindBinaryXors(true) - , performReplace (true) - , conglomerateXors (true) - , heuleProcess (true) - , schedSimplification(true) - , doSubsumption (true) - , doXorSubsumption (true) - , doPartHandler (true) - , doHyperBinRes (true) - , doBlockedClause (true) - , doVarElim (true) - , doSubsume1 (true) - , failedVarSearch (true) - , addExtraBins (true) - , removeUselessBins(true) - , regularRemoveUselessBins(true) - , subsumeWithNonExistBinaries(true) - , regularSubsumeWithNonExistBinaries(true) - , libraryUsage (true) - , greedyUnbound (false) - , fixRestartType (auto_restart) - - // Statistics: (formerly in 'SolverStats') - // - , starts(0), dynStarts(0), staticStarts(0), fullStarts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0) - , clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0) - , nbDL2(0), nbBin(0), lastNbBin(0), becameBinary(0), lastSearchForBinaryXor(0), nbReduceDB(0) - , improvedClauseNo(0), improvedClauseSize(0) - + 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) - , var_inc (128) + , numBins (0) , cla_inc (1) - - , curRestart (1) - , nbclausesbeforereduce (NBCLAUSESBEFOREREDUCE) - , nbCompensateSubsumer (0) - , qhead (0) - , simpDB_assigns (-1) - , simpDB_props (0) + , mtrand ((unsigned long int)0) + + //variables , order_heap (VarOrderLt(activity)) - , progress_estimate(0) - , remove_satisfied (true) - , mtrand((unsigned long int)0) - , restartType (static_restart) - , lastSelectedRestartType (static_restart) + , var_inc (128) + + //learnts + , numCleanedLearnts(1) + , nbClBeforeRed (NBCLAUSESBEFOREREDUCE) + , nbCompensateSubsumer (0) + + , MYFLAG (0) #ifdef STATS_NEEDED - , logger(verbosity) + , logger(conf.verbosity) , dynamic_behaviour_analysis(false) //do not document the proof as default #endif - , maxRestarts(UINT_MAX) - , MYFLAG (0) , learnt_clause_group(0) , libraryCNFFile (NULL) + , restartType (static_restart) + , lastSelectedRestartType (static_restart) , simplifying (false) + , totalSimplifyTime(0.0) + , simpDB_assigns (-1) + , simpDB_props (0) { + mtrand.seed(conf.origSeed); + assert(conf.maxGlue < MAX_THEORETICAL_GLUE); varReplacer = new VarReplacer(*this); clauseCleaner = new ClauseCleaner(*this); - failedVarSearcher = new FailedVarSearcher(*this); + failedLitSearcher = new FailedLitSearcher(*this); partHandler = new PartHandler(*this); subsumer = new Subsumer(*this); xorSubsumer = new XorSubsumer(*this); restartTypeChooser = new RestartTypeChooser(*this); - #ifdef USE_GAUSS + sCCFinder = new SCCFinder(*this); + clauseVivifier = new ClauseVivifier(*this); matrixFinder = new MatrixFinder(*this); - #endif //USE_GAUSS - + dataSync = new DataSync(*this, sharedData); + #ifdef STATS_NEEDED logger.setSolver(this); #endif } +/** +@brief Frees clauses and frees all allocated hander classes +*/ Solver::~Solver() { - #ifdef USE_GAUSS clearGaussMatrixes(); delete matrixFinder; - #endif - delete varReplacer; delete clauseCleaner; - delete failedVarSearcher; + delete failedLitSearcher; delete partHandler; delete subsumer; delete xorSubsumer; delete restartTypeChooser; - + if (libraryCNFFile) fclose(libraryCNFFile); } @@ -180,24 +150,39 @@ Solver::~Solver() // Minor methods: -// Creates a new SAT variable in the solver. If 'decision_var' is cleared, variable will not be -// used as a decision variable (NOTE! This has effects on the meaning of a SATISFIABLE result). +/** +@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) { Var v = nVars(); watches .push(); // (list for positive literal) watches .push(); // (list for negative literal) - binwatches.push(); // (list for positive literal) - binwatches.push(); // (list for negative literal) - xorwatches.push(); // (list for variables in xors) - reason .push(PropagatedFrom()); + reason .push(PropBy()); assigns .push(l_Undef); level .push(-1); + binPropData.push(); activity .push(0); seen .push_back(0); seen .push_back(0); permDiff .push(0); - + unWindGlue.push(NULL); + + //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()); #ifdef USE_OLD_POLARITIES oldPolarity.push_back(defaultPolarity()); @@ -205,31 +190,39 @@ Var Solver::newVar(bool dvar) decision_var.push_back(dvar); insertVarOrder(v); - + varReplacer->newVar(); - if (doPartHandler) partHandler->newVar(); - if (doSubsumption || subsumeWithNonExistBinaries || regularSubsumeWithNonExistBinaries) subsumer->newVar(); - if (doXorSubsumption) xorSubsumer->newVar(); + partHandler->newVar(); + subsumer->newVar(); + xorSubsumer->newVar(); + dataSync->newVar(); insertVarOrder(v); - + #ifdef STATS_NEEDED if (dynamic_behaviour_analysis) logger.new_var(v); #endif - + 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 -XorClause* Solver::addXorClauseInt(T& ps, bool xor_clause_inverted, const uint32_t group) +XorClause* Solver::addXorClauseInt(T& ps, bool xorEqualFalse, const uint32_t group, const bool learnt) { assert(qhead == trail.size()); assert(decisionLevel() == 0); - + if (ps.size() > (0x01UL << 18)) { std::cout << "Too long clause!" << std::endl; exit(-1); @@ -243,60 +236,76 @@ XorClause* Solver::addXorClauseInt(T& ps, bool xor_clause_inverted, const uint32 j--; p = lit_Undef; if (!assigns[ps[i].var()].isUndef()) - xor_clause_inverted ^= assigns[ps[i].var()].getBool(); - } else if (assigns[ps[i].var()].isUndef()) //just add + xorEqualFalse ^= assigns[ps[i].var()].getBool(); + } else if (assigns[ps[i].var()].isUndef()) { //just add ps[j++] = p = ps[i]; - else //modify xor_clause_inverted instead of adding - xor_clause_inverted ^= (assigns[ps[i].var()].getBool()); + 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 (!xor_clause_inverted) ok = false; + if (!xorEqualFalse) ok = false; return NULL; } case 1: { - uncheckedEnqueue(Lit(ps[0].var(), xor_clause_inverted)); + uncheckedEnqueue(Lit(ps[0].var(), xorEqualFalse)); ok = (propagate().isNULL()); return NULL; } case 2: { #ifdef VERBOSE_DEBUG - cout << "--> xor is 2-long, replacing var " << ps[0].var()+1 << " with " << (!xor_clause_inverted ? "-" : "") << ps[1].var()+1 << endl; + 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, xor_clause_inverted, group); + varReplacer->replace(ps, xorEqualFalse, group); return NULL; } default: { - XorClause* c = clauseAllocator.XorClause_new(ps, xor_clause_inverted, group); + assert(!learnt); + XorClause* c = clauseAllocator.XorClause_new(ps, xorEqualFalse, group); attachClause(*c); return c; } } } -template XorClause* Solver::addXorClauseInt(vec& ps, bool xor_clause_inverted, const uint32_t group); -template XorClause* Solver::addXorClauseInt(XorClause& ps, bool xor_clause_inverted, const uint32_t group); +template XorClause* Solver::addXorClauseInt(vec& ps, bool xorEqualFalse, const uint32_t group, const bool learnt); +template XorClause* Solver::addXorClauseInt(XorClause& ps, bool xorEqualFalse, const uint32_t group, 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 -bool Solver::addXorClause(T& ps, bool xor_clause_inverted, const uint group, char* group_name) +bool Solver::addXorClause(T& ps, bool xorEqualFalse, const uint32_t group, const char* group_name) { assert(decisionLevel() == 0); if (ps.size() > (0x01UL << 18)) { std::cout << "Too long clause!" << std::endl; exit(-1); } - + if (libraryCNFFile) { fprintf(libraryCNFFile, "x"); for (uint32_t i = 0; i < ps.size(); i++) ps[i].print(libraryCNFFile); fprintf(libraryCNFFile, "0\n"); } - + #ifdef STATS_NEEDED if (dynamic_behaviour_analysis) { logger.set_group_name(group, group_name); @@ -307,72 +316,64 @@ bool Solver::addXorClause(T& ps, bool xor_clause_inverted, const uint group, cha 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 - // 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++) { + 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; - else { - Lit otherLit = varReplacer->getReplaceTable()[ps[i].var()]; - if (otherLit.var() != ps[i].var()) { - ps[i] = Lit(otherLit.var(), false); - xor_clause_inverted ^= otherLit.sign(); - } - } } } - - XorClause* c = addXorClauseInt(ps, xor_clause_inverted, group); + + XorClause* c = addXorClauseInt(ps, xorEqualFalse, group); if (c != NULL) xorclauses.push(c); return ok; } -template bool Solver::addXorClause(vec& ps, bool xor_clause_inverted, const uint group, char* group_name); -template bool Solver::addXorClause(XorClause& ps, bool xor_clause_inverted, const uint group, char* group_name); - +template bool Solver::addXorClause(vec& ps, bool xorEqualFalse, const uint32_t group, const char* group_name); +template bool Solver::addXorClause(XorClause& ps, bool xorEqualFalse, const uint32_t group, const char* group_name); -template -bool Solver::addLearntClause(T& ps, const uint group, const uint32_t activity) -{ - Clause* c = addClauseInt(ps, group); - if (c == NULL) return ok; - - //compensate for addClauseInt's attachClause, which doesn't know - //that this is a learnt clause. - clauses_literals -= c->size(); - learnts_literals += c->size(); - - c->makeLearnt(activity); - if (c->size() > 2) learnts.push(c); - else { - nbBin++; - binaryClauses.push(c); - } - return ok; -} -template bool Solver::addLearntClause(Clause& ps, const uint group, const uint32_t activity); -template bool Solver::addLearntClause(vec& ps, const uint group, const uint32_t activity); +/** +@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 -Clause* Solver::addClauseInt(T& ps, uint group) +Clause* Solver::addClauseInt(T& ps, uint32_t group + , const bool learnt, const uint32_t glue, const float miniSatActivity + , const bool inOriginalInput) { assert(ok); - + std::sort(ps.getData(), ps.getDataEnd()); Lit p = lit_Undef; uint32_t i, j; for (i = j = 0; i != ps.size(); i++) { if (value(ps[i]).getBool() || ps[i] == ~p) return NULL; - else if (value(ps[i]) != l_False && ps[i] != p) + 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; @@ -382,29 +383,35 @@ Clause* Solver::addClauseInt(T& ps, uint group) return NULL; } - Clause* c = clauseAllocator.Clause_new(ps, group); - attachClause(*c); - - return c; + if (ps.size() > 2) { + Clause* c = clauseAllocator.Clause_new(ps, group); + 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 uint group); -template Clause* Solver::addClauseInt(vec& ps, const uint group); +template Clause* Solver::addClauseInt(Clause& ps, const uint32_t group, const bool learnt, const uint32_t glue, const float miniSatActivity, const bool inOriginalInput); +template Clause* Solver::addClauseInt(vec& ps, const uint32_t group, const bool learnt, const uint32_t glue, const float miniSatActivity, const bool inOriginalInput); -template -bool Solver::addClause(T& ps, const uint group, char* group_name) +template const bool Solver::addClauseHelper(T& ps, const uint32_t group, const char* group_name) { assert(decisionLevel() == 0); if (ps.size() > (0x01UL << 18)) { std::cout << "Too long clause!" << std::endl; exit(-1); } - + if (libraryCNFFile) { for (uint32_t i = 0; i != ps.size(); i++) ps[i].print(libraryCNFFile); fprintf(libraryCNFFile, "0\n"); } - + #ifdef STATS_NEEDED if (dynamic_behaviour_analysis) { logger.set_group_name(group, group_name); @@ -412,9 +419,13 @@ bool Solver::addClause(T& ps, const uint group, char* group_name) } #endif - if (!ok) - return false; + 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()) { @@ -426,125 +437,215 @@ bool Solver::addClause(T& ps, const uint group, char* group_name) return false; } } - - Clause* c = addClauseInt(ps, group); - if (c != NULL) { - if (c->size() > 2) - clauses.push(c); - else - binaryClauses.push(c); - } + + 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 +bool Solver::addClause(T& ps, const uint32_t group, const char* group_name) +{ + #ifdef VERBOSE_DEBUG + std::cout << "addClause() called with new clause: " << ps << std::endl; + #endif //VERBOSE_DEBUG + if (!addClauseHelper(ps, group, group_name)) return false; + Clause* c = addClauseInt(ps, group, false, 0, 0, true); + if (c != NULL) clauses.push(c); + + return ok; +} + +template bool Solver::addClause(vec& ps, const uint32_t group, const char* group_name); +template bool Solver::addClause(Clause& ps, const uint32_t group, const char* group_name); + + +template +bool Solver::addLearntClause(T& ps, const uint32_t group, const char* group_name, const uint32_t glue, const float miniSatActivity) +{ + if (!addClauseHelper(ps, group, group_name)) return false; + Clause* c = addClauseInt(ps, group, true, glue, miniSatActivity, true); + if (c != NULL) learnts.push(c); return ok; } -template bool Solver::addClause(vec& ps, const uint group, char* group_name); -template bool Solver::addClause(Clause& ps, const uint group, char* group_name); +template bool Solver::addLearntClause(vec& ps, const uint32_t group, const char* group_name, const uint32_t glue, const float miniSatActivity); +template bool Solver::addLearntClause(Clause& ps, const uint32_t group, const char* group_name, 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 - xorwatches[c[0].var()].push(clauseAllocator.getOffset((Clause*)&c)); - xorwatches[c[1].var()].push(clauseAllocator.getOffset((Clause*)&c)); + 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)); + + 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() > 1); - uint32_t index0 = (~c[0]).toInt(); - uint32_t index1 = (~c[1]).toInt(); - - if (c.size() == 2) { - binwatches[index0].push(WatchedBin(c[1])); - binwatches[index1].push(WatchedBin(c[0])); + 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])); } else { ClauseOffset offset = clauseAllocator.getOffset(&c); - watches[index0].push(Watched(offset, c[c.size()/2])); - watches[index1].push(Watched(offset, c[c.size()/2])); + 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(); + 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) { - assert(c.size() > 1); - ClauseOffset offset = clauseAllocator.getOffset(&c); - assert(find(xorwatches[c[0].var()], offset)); - assert(find(xorwatches[c[1].var()], offset)); - remove(xorwatches[c[0].var()], offset); - remove(xorwatches[c[1].var()], offset); - - clauses_literals -= c.size(); + detachModifiedClause(c[0].var(), c[1].var(), c.size(), &c); } +/** +@brief Calls detachModifiedClause to do the heavy-lifting +*/ void Solver::detachClause(const Clause& c) { - assert(c.size() > 1); - if (c.size() == 2) { - assert(findWatchedBinCl(binwatches[(~c[0]).toInt()], c[1])); - assert(findWatchedBinCl(binwatches[(~c[1]).toInt()], c[0])); - - removeWatchedBinCl(binwatches[(~c[0]).toInt()], c[1]); - removeWatchedBinCl(binwatches[(~c[1]).toInt()], c[0]); - } else { - ClauseOffset offset = clauseAllocator.getOffset(&c); - - assert(findWatchedCl(watches[(~c[0]).toInt()], offset)); - assert(findWatchedCl(watches[(~c[1]).toInt()], offset)); - - removeWatchedCl(watches[(~c[0]).toInt()], offset); - removeWatchedCl(watches[(~c[1]).toInt()], offset); - } - - if (c.learnt()) learnts_literals -= c.size(); - else clauses_literals -= c.size(); + detachModifiedClause(c[0], c[1], (c.size() == 3) ? c[2] : lit_Undef, c.size(), &c); } -void Solver::detachModifiedClause(const Lit lit1, const Lit lit2, const uint origSize, const Clause* address) +/** +@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 > 1); - - if (origSize == 2) { - assert(findWatchedBinCl(binwatches[(~lit1).toInt()], lit2)); - assert(findWatchedBinCl(binwatches[(~lit2).toInt()], lit1)); - removeWatchedBinCl(binwatches[(~lit1).toInt()], lit2); - removeWatchedBinCl(binwatches[(~lit2).toInt()], lit1); + 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 { - ClauseOffset offset = clauseAllocator.getOffset(address); - assert(findW(watches[(~lit1).toInt()], offset)); - assert(findW(watches[(~lit2).toInt()], offset)); - removeW(watches[(~lit1).toInt()], offset); - removeW(watches[(~lit2).toInt()], offset); - } - if (address->learnt()) learnts_literals -= origSize; - else clauses_literals -= origSize; + fullClause: + removeWCl(watches[(~lit1).toInt()], offset); + removeWCl(watches[(~lit2).toInt()], offset); + + } + + if (address->learnt()) + learnts_literals -= origSize; + else + clauses_literals -= origSize; } -void Solver::detachModifiedClause(const Var var1, const Var var2, const uint origSize, const XorClause* address) +/** +@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(find(xorwatches[var1], offset)); - assert(find(xorwatches[var2], offset)); - remove(xorwatches[var1], offset); - remove(xorwatches[var2], offset); - + 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; } -// Revert to the state at given level (keeping all assignment at 'level' but not beyond). -// +/** +@brief Revert to the state at given level + +Also reverts all stuff in Gass-elimination, as well as resetting the old +default polarities if USE_OLD_POLARITIES is set (which is by default NOT set). +*/ void Solver::cancelUntil(int level) { #ifdef VERBOSE_DEBUG @@ -552,14 +653,14 @@ void Solver::cancelUntil(int level) if (level > 0) cout << " sublevel: " << trail_lim[level]; cout << endl; #endif - + if ((int)decisionLevel() > level) { - + #ifdef USE_GAUSS for (vector::iterator gauss = gauss_matrixes.begin(), end= gauss_matrixes.end(); gauss != end; gauss++) (*gauss)->canceling(trail_lim[level]); #endif //USE_GAUSS - + for (int sublevel = trail.size()-1; sublevel >= (int)trail_lim[level]; sublevel--) { Var var = trail[sublevel].var(); #ifdef VERBOSE_DEBUG @@ -570,6 +671,21 @@ void Solver::cancelUntil(int level) #endif //USE_OLD_POLARITIES assigns[var] = l_Undef; insertVarOrder(var); + 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; + } } qhead = trail_lim[level]; trail.shrink_(trail.size() - trail_lim[level]); @@ -581,29 +697,46 @@ void Solver::cancelUntil(int level) #endif } -void Solver::printLit(const Lit l) const +void Solver::cancelUntilLight() { - printf("%s%d:%c", l.sign() ? "-" : "", l.var()+1, value(l) == l_True ? '1' : (value(l) == l_False ? '0' : 'X')); -} + assert((int)decisionLevel() > 0); -void Solver::needLibraryCNFFile(const char* fileName) -{ - libraryCNFFile = fopen(fileName, "w"); - assert(libraryCNFFile != NULL); + 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.shrink_(trail_lim.size()); } -#ifdef USE_GAUSS -void Solver::clearGaussMatrixes() +const bool Solver::clearGaussMatrixes() { - for (uint i = 0; i < gauss_matrixes.size(); i++) + 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; } -#endif //USE_GAUSS +/** +@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(polarity_mode) { + switch(conf.polarity_mode) { case polarity_false: return true; case polarity_true: @@ -615,62 +748,100 @@ inline bool Solver::defaultPolarity() default: assert(false); } - + return true; } -void Solver::tallyVotes(const vec& cs, vector& votes) const +/** +@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& cs, vec& votes) const { for (const Clause * const*it = cs.getData(), * const*end = it + cs.size(); it != end; it++) { const Clause& c = **it; if (c.learnt()) continue; - + double divider; if (c.size() > 63) divider = 0.0; else divider = 1.0/(double)((uint64_t)1<<(c.size()-1)); - - for (const Lit *it2 = &c[0], *end2 = it2 + c.size(); it2 != end2; it2++) { + + 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::tallyVotes(const vec& cs, vector& votes) const +void Solver::tallyVotesBin(vec& votes) const +{ + uint32_t wsLit = 0; + for (const vec *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec& ws = *it; + for (const Watched *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& cs, vec& votes) const { for (const XorClause * const*it = cs.getData(), * const*end = it + cs.size(); it != end; it++) { const XorClause& c = **it; double divider; if (c.size() > 63) divider = 0.0; else divider = 1.0/(double)((uint64_t)1<<(c.size()-1)); - - for (const Lit *it2 = &c[0], *end2 = it2 + c.size(); it2 != end2; it2++) + + 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 (polarity_mode == polarity_auto) { - double time = cpuTime(); - - vector votes; - votes.resize(nVars(), 0.0); - + if (conf.polarity_mode == polarity_auto) { + double myTime = cpuTime(); + + vec votes(nVars(), 0.0); + tallyVotes(clauses, votes); - tallyVotes(binaryClauses, votes); - tallyVotes(varReplacer->getClauses(), votes); + tallyVotesBin(votes); tallyVotes(xorclauses, votes); - + Var i = 0; uint32_t posPolars = 0; uint32_t undecidedPolars = 0; - for (vector::const_iterator it = votes.begin(), end = votes.end(); it != end; it++, i++) { + 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); @@ -678,67 +849,176 @@ void Solver::calculateDefaultPolarities() std::cout << !defaultPolarities[i] << ", "; #endif //VERBOSE_DEBUG_POLARITIES } - - if (verbosity >= 2) { - std::cout << "c | Calc default polars - " - << " time: " << std::fixed << std::setw(6) << std::setprecision(2) << cpuTime()-time << " s" + + 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::setw(8) << " |" << std:: endl; + << std:: endl; } } else { - std::fill(polarity.begin(), polarity.end(), defaultPolarity()); + 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()] + || partHandler->getSavedState()[lit.var()] != l_Undef + || !decision_var[lit.var()]) + continue; + + vector& cache = transOTFCache[(~lit).toInt()].lits; + uint32_t cacheSize = cache.size(); + for (vector::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& 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 If RANDOM_LOOKAROUND_SEARCHSPACE is set, we take the previously saved +polarity, and with some chance, flip it +\li Otherwise, we simply take the saved polarity +*/ Lit Solver::pickBranchLit() { #ifdef VERBOSE_DEBUG cout << "decision level: " << decisionLevel() << " "; #endif - + Var next = var_Undef; - - bool random = mtrand.randDblExc() < random_var_freq; - + bool random = mtrand.randDblExc() < conf.random_var_freq; + // Random decision: if (random && !order_heap.empty()) { - if (restrictedPickBranch == 0) next = order_heap[mtrand.randInt(order_heap.size()-1)]; - else next = order_heap[mtrand.randInt(std::min((uint32_t)order_heap.size()-1, restrictedPickBranch))]; + if (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]) + while (next == var_Undef + || assigns[next] != l_Undef + || !decision_var[next]) { if (order_heap.empty()) { next = var_Undef; break; - } else { - next = order_heap.removeMin(); } + 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 (simplifying && random) - sign = mtrand.randInt(1); - #ifdef RANDOM_LOOKAROUND_SEARCHSPACE - else if (avgBranchDepth.isvalid()) - sign = polarity[next] ^ (mtrand.randInt(avgBranchDepth.getavg() * ((lastSelectedRestartType == static_restart) ? 2 : 1) ) == 1); - #endif - else - sign = polarity[next]; + if (next != var_Undef) { + if (signSet) { + sign = signSetTo; + } else { + if (simplifying && random) + sign = mtrand.randInt(1); + #ifdef RANDOM_LOOKAROUND_SEARCHSPACE + else if (avgBranchDepth.isvalid()) + sign = polarity[next] ^ (mtrand.randInt(avgBranchDepth.getAvgUInt() * ((lastSelectedRestartType == static_restart) ? 2 : 1) ) == 1); + #endif + else + sign = polarity[next]; + } } assert(next == var_Undef || value(next) == l_Undef); @@ -758,43 +1038,46 @@ Lit Solver::pickBranchLit() } } -// Assumes 'seen' is cleared (will leave it cleared) +/** +@brief Checks subsumption. Used in on-the-fly subsumption code + +Assumes 'seen' is cleared (will leave it cleared) +*/ template bool subset(const T1& A, const T2& B, vector& seen) { - for (uint i = 0; i != B.size(); i++) + for (uint32_t i = 0; i != B.size(); i++) seen[B[i].toInt()] = 1; - for (uint i = 0; i != A.size(); i++) { + for (uint32_t i = 0; i != A.size(); i++) { if (!seen[A[i].toInt()]) { - for (uint i = 0; i != B.size(); i++) + for (uint32_t i = 0; i != B.size(); i++) seen[B[i].toInt()] = 0; return false; } } - for (uint i = 0; i != B.size(); i++) + for (uint32_t i = 0; i != B.size(); i++) seen[B[i].toInt()] = 0; return true; } -/*_________________________________________________________________________________________________ -| -| analyze : (confl : Clause*) (out_learnt : vec&) (out_btlevel : int&) -> [void] -| -| Description: -| Analyze conflict and produce a reason clause. -| -| Pre-conditions: -| * 'out_learnt' is assumed to be cleared. -| * Current decision level must be greater than root level. -| -| Post-conditions: -| * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'. -| -| Effect: -| Will undo part of the trail, upto but not beyond the assumption of the current decision level. -|________________________________________________________________________________________________@*/ -Clause* Solver::analyze(PropagatedFrom confl, vec& out_learnt, int& out_btlevel, uint32_t &nbLevels, const bool update) +/** +@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& out_learnt, int& out_btlevel, uint32_t &glue, const bool update) { int pathC = 0; Lit p = lit_Undef; @@ -805,32 +1088,32 @@ Clause* Solver::analyze(PropagatedFrom confl, vec& out_learnt, int& out_btl int index = trail.size() - 1; out_btlevel = 0; - PropagatedFrom oldConfl; + PropByFull confl(conflHalf, failBinLit, clauseAllocator); + PropByFull oldConfl; do { assert(!confl.isNULL()); // (otherwise should be UIP) - - if (update && restartType == static_restart && !confl.isBinary() && confl.getClause()->learnt()) + + if (update && restartType == static_restart && confl.isClause() && confl.getClause()->learnt()) claBumpActivity(*confl.getClause()); - for (uint j = (p == lit_Undef) ? 0 : 1, size = confl.size(); j != size; j++) { - Lit q; - if (j == 0 && confl.isBinary()) q = failBinLit; - else q = confl[j]; + 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++; - #ifdef UPDATEVARACTIVITY + #ifdef UPDATE_VAR_ACTIVITY_BASED_ON_GLUE if (lastSelectedRestartType == dynamic_restart - && !reason[q.var()].isBinary() + && reason[q.var()].isClause() && !reason[q.var()].isNULL() - && reason[q.var()].getClause()->learnt()) + && clauseAllocator.getPointer(reason[q.var()].getClause())->learnt()) lastDecisionLevel.push(q.var()); - #endif + #endif //#define UPDATEVARACTIVITY } else { out_learnt.push(q); if (level[my_var] > out_btlevel) @@ -843,18 +1126,19 @@ Clause* Solver::analyze(PropagatedFrom confl, vec& out_learnt, int& out_btl while (!seen[trail[index--].var()]); p = trail[index+1]; oldConfl = confl; - confl = reason[p.var()]; - if (!confl.isBinary()) __builtin_prefetch(confl.getClause(), 1, 0); + confl = PropByFull(reason[p.var()], failBinLit, clauseAllocator); + if (confl.isClause()) __builtin_prefetch(confl.getClause(), 1, 0); seen[p.var()] = 0; pathC--; } while (pathC > 0); + assert(pathC == 0); out_learnt[0] = ~p; // Simplify conflict clause: // uint32_t i, j; - if (expensive_ccmin) { + 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) @@ -866,9 +1150,9 @@ Clause* Solver::analyze(PropagatedFrom confl, vec& out_learnt, int& out_btl } else { out_learnt.copyTo(analyze_toclear); for (i = j = 1; i < out_learnt.size(); i++) { - PropagatedFrom c(reason[out_learnt[i].var()]); + PropByFull c(reason[out_learnt[i].var()], failBinLit, clauseAllocator); - for (uint k = 1, size = c.size(); k < size; k++) { + 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; @@ -878,6 +1162,11 @@ Clause* Solver::analyze(PropagatedFrom confl, vec& out_learnt, int& out_btl } 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: @@ -889,60 +1178,187 @@ Clause* Solver::analyze(PropagatedFrom confl, vec& out_learnt, int& out_btl for (uint32_t i = 2; i < out_learnt.size(); i++) if (level[out_learnt[i].var()] > level[out_learnt[max_i].var()]) max_i = i; - Lit p = out_learnt[max_i]; - out_learnt[max_i] = out_learnt[1]; - out_learnt[1] = p; - out_btlevel = level[p.var()]; + std::swap(out_learnt[max_i], out_learnt[1]); + out_btlevel = level[out_learnt[1].var()]; } if (lastSelectedRestartType == dynamic_restart) { - nbLevels = calcNBLevels(out_learnt); - #ifdef UPDATEVARACTIVITY + #ifdef UPDATE_VAR_ACTIVITY_BASED_ON_GLUE for(uint32_t i = 0; i != lastDecisionLevel.size(); i++) { - PropagatedFrom cl = reason[lastDecisionLevel[i]]; - if (!cl.isBinary() && cl.getClause()->activity() < nbLevels) + PropBy cl = reason[lastDecisionLevel[i]]; + if (cl.isClause() && clauseAllocator.getPointer(cl.getClause())->getGlue() < glue) varBumpActivity(lastDecisionLevel[i]); } lastDecisionLevel.clear(); #endif - } else { - nbLevels = 1000; } - for (uint32_t j = 0; j != analyze_toclear.size(); j++) - seen[analyze_toclear[j].var()] = 0; // ('seen[]' is now cleared) - - if (out_learnt.size() == 1) return NULL; - - if (!oldConfl.isBinary() && !oldConfl.getClause()->isXor() - && out_learnt.size() < oldConfl.getClause()->size()) { - if (!subset(out_learnt, *oldConfl.getClause(), seen)) - return NULL; - improvedClauseNo++; - improvedClauseSize += oldConfl.getClause()->size() - out_learnt.size(); - return oldConfl.getClause(); + //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 (out_learnt.size() == 1 + || !oldConfl.isClause() + || oldConfl.getClause()->isXor() + || (conf.doMaxGlueDel && oldConfl.getClause()->getGlue() > conf.maxGlue) + || 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& 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); + } } - - return NULL; -} + if (clDoMinLRec) moreRecurMinLDo++; + uint64_t thisUpdateTransOTFSSCache = UPDATE_TRANSOTFSSR_CACHE; + if (tot_literals > 80000000) thisUpdateTransOTFSSCache *= 2; -// Check if 'p' can be removed. 'abstract_levels' is used to abort early if the algorithm is -// visiting literals at levels that cannot be removed later. -bool Solver::litRedundant(Lit p, uint32_t abstract_levels) -{ - analyze_stack.clear(); - analyze_stack.push(p); - int top = analyze_toclear.size(); - while (analyze_stack.size() > 0) { - assert(!reason[analyze_stack.last().var()].isNULL()); - PropagatedFrom c(reason[analyze_stack.last().var()]); - - analyze_stack.pop(); + //To count the "amount of time" invested in doing transitive on-the-fly + //self-subsuming resolution + uint32_t moreRecurProp = 0; - for (uint i = 1, size = c.size(); i < size; i++) { - Lit p = c[i]; - if (!seen[p.var()] && level[p.var()] > 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::max() + && (transOTFCache[l->toInt()].conflictLastUpdated + thisUpdateTransOTFSSCache >= conflicts))) { + for (vector::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& ws = watches[(~lit).toInt()]; + for (Watched* 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& 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& ws = watches[(~thisLit).toInt()]; + moreRecurProp += ws.size() +10; + for (Watched* 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::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); @@ -987,8 +1403,8 @@ void Solver::analyzeFinal(Lit p, vec& out_conflict) assert(level[x] > 0); out_conflict.push(~trail[i]); } else { - PropagatedFrom c = reason[x]; - for (uint j = 1, size = c.size(); j < size; j++) + 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; } @@ -1000,18 +1416,36 @@ void Solver::analyzeFinal(Lit p, vec& out_conflict) } -void Solver::uncheckedEnqueue(const Lit p, const PropagatedFrom& from) -{ +/** +@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. May also save the "old" polarity +(i.e. polarity that was in polarities[] at p.var()] of the variable if +USE_OLD_POLARITIES is set +@p p the fact to enqueue +@p from Why was it propagated (binary clause, tertiary clause, normal clause) +*/ +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 " << !p.sign() << " level: " << decisionLevel() << " sublevel: " << trail.size() << std::endl; + 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()]); - + assert(assigns[p.var()].isUndef()); const Var v = p.var(); assigns [v] = boolToLBool(!p.sign());//lbool(!sign(p)); // <<== abstract but not uttermost effecient @@ -1022,7 +1456,7 @@ void Solver::uncheckedEnqueue(const Lit p, const PropagatedFrom& from) #endif //USE_OLD_POLARITIES polarity[p.var()] = p.sign(); trail.push(p); - + #ifdef STATS_NEEDED if (dynamic_behaviour_analysis) logger.propagation(p, from); @@ -1040,118 +1474,271 @@ void Solver::uncheckedEnqueue(const Lit p, const PropagatedFrom& from) | Post-conditions: | * the propagation queue is empty, even if there was a conflict. |________________________________________________________________________________________________@*/ -PropagatedFrom Solver::propagate(const bool update) +/** +@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 +*/ +inline const bool Solver::propBinaryClause(Watched* &i, Watched* &j, Watched *end, const Lit p, PropBy& confl) +{ + *j++ = *i; + lbool val = value(i->getOtherLit()); + if (val.isUndef()) { + uncheckedEnqueue(i->getOtherLit(), PropBy(p)); + } else if (val == l_False) { + confl = PropBy(p); + failBinLit = i->getOtherLit(); + qhead = trail.size(); + 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 +*/ +inline const bool Solver::propTriClause(Watched* &i, Watched* &j, Watched *end, const Lit p, PropBy& confl) +{ + *j++ = *i; + lbool val = value(i->getOtherLit()); + lbool val2 = value(i->getOtherLit2()); + if (val.isUndef() && val2 == l_False) { + uncheckedEnqueue(i->getOtherLit(), PropBy(p, i->getOtherLit2())); + } else if (val == l_False && val2.isUndef()) { + uncheckedEnqueue(i->getOtherLit2(), PropBy(p, i->getOtherLit())); + } else if (val == l_False && val2 == l_False) { + confl = PropBy(p, i->getOtherLit2()); + failBinLit = i->getOtherLit(); + qhead = trail.size(); + 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. +*/ +inline const bool Solver::propNormalClause(Watched* &i, Watched* &j, Watched *end, const Lit p, PropBy& confl, const bool update) { - PropagatedFrom confl; - uint32_t num_props = 0; - + 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]: + //const Lit lit2 = c.size()>2 ? c[2] : c[0]; + if (c[0] == ~p) { + std::swap(c[0], c[1]); + } + //if (c.size() > 2) assert(lit2 == c[2]); + + assert(c[1] == ~p); + + // If 0th watch is true, then clause is already satisfied. + if (value(c[0]).getBool()) { + #ifdef VERBOSE_DEBUG + printf("Zeroth watch is true\n"); + #endif + j->setNormClause(); + j->setNormOffset(offset); + j->setBlockedLit(c[0]); + j++; + return true; + } + // Look for new watch: + for (Lit *k = c.getData() + 2, *end2 = c.getDataEnd(); k != end2; k++) { + #ifdef VERBOSE_DEBUG + printf("Skip watch\n"); + #endif + if (value(*k) != l_False) { + #ifdef VERBOSE_DEBUG + printf("new watch\n"); + #endif + c[1] = *k; + *k = ~p; + watches[(~c[1]).toInt()].push(Watched(offset, c[0])); + return true; + } + } + #ifdef VERBOSE_DEBUG - cout << "Propagation started" << endl; + printf("Did not find watch\n"); #endif - uint32_t qheadBin = qhead; - - while (qhead < trail.size()) { - - //First propagate binary clauses - while (qheadBin < trail.size()) { - Lit p = trail[qheadBin++]; - vec & wbin = binwatches[p.toInt()]; - num_props += wbin.size()/2; - for(WatchedBin *k = wbin.getData(), *end = wbin.getDataEnd(); k != end; k++) { - lbool val = value(k->impliedLit); - if (val.isUndef()) { - uncheckedEnqueue(k->impliedLit, PropagatedFrom(p)); - } else if (val == l_False) { - confl = PropagatedFrom(p); - failBinLit = k->impliedLit; - //goto EndPropagate; - } + // Did not find watch -- clause is unit under assignment: + *j++ = *i; + if (value(c[0]) == l_False) { + confl = PropBy(offset); + qhead = trail.size(); + return false; + } else { + uncheckedEnqueue(c[0], offset); + #ifdef DYNAMICALLY_UPDATE_GLUE + if (update && c.learnt() && c.getGlue() > 2) { // GA + uint32_t glue = calcNBLevels(c); + if (glue+1 < c.getGlue()) { + //c.setGlue(std::min(nbLevels, MAX_THEORETICAL_GLUE); + c.setGlue(glue); } } - if (!confl.isNULL()) { - goto EndPropagate; + #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 +*/ +inline const bool Solver::propXorClause(Watched* &i, Watched* &j, Watched *end, 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; } - //Next, propagate normal clauses - Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate. - vec& ws = watches[p.toInt()]; - Watched *i, *j, *end; - num_props += ws.size(); - - #ifdef VERBOSE_DEBUG - cout << "Propagating lit " << (p.sign() ? '-' : ' ') << p.var()+1 << endl; - #endif + c[k] = c[k].unsign() ^ val.getBool(); + final ^= val.getBool(); + } - for (i = j = ws.getData(), end = ws.getDataEnd(); i != end;) { - if (i+1 != end && !value((i+1)->blockedLit).getBool()) - __builtin_prefetch(clauseAllocator.getPointer((i+1)->clause), 1, 0); - - if(value(i->blockedLit).getBool()) { // Clause is sat - *j++ = *i++; - continue; - } - Lit bl = i->blockedLit; - Clause& c = *clauseAllocator.getPointer(i->clause); - ClauseOffset origClauseOffset = i->clause; - i++; + // Did not find watch -- clause is unit under assignment: + *j++ = *i; - // Make sure the false literal is data[1]: - const Lit false_lit(~p); - if (c[0] == false_lit) - c[0] = c[1], c[1] = false_lit; + if (assigns[c[0].var()].isUndef()) { + c[0] = c[0].unsign()^final; + uncheckedEnqueue(c[0], offset); + } else if (!final) { + confl = PropBy(offset); + qhead = trail.size(); + return false; + } else { + Lit tmp(c[0]); + c[0] = c[1]; + c[1] = tmp; + } - assert(c[1] == false_lit); + return true; +} - // If 0th watch is true, then clause is already satisfied. - const Lit& first = c[0]; - if (value(first).getBool()) { - j->clause = origClauseOffset; - j->blockedLit = first; - j++; - } else { - // Look for new watch: - for (Lit *k = &c[2], *end2 = c.getDataEnd(); k != end2; k++) { - if (value(*k) != l_False) { - c[1] = *k; - *k = false_lit; - watches[(~c[1]).toInt()].push(Watched(origClauseOffset, c[0])); - goto FoundWatch; - } - } +/** +@brief Does the propagation - // Did not find watch -- clause is unit under assignment: - j->clause = origClauseOffset; - j->blockedLit = bl; - j++; - if (value(first) == l_False) { - confl = PropagatedFrom(&c); - qhead = trail.size(); - // Copy the remaining watches: - while (i < end) - *j++ = *i++; - } else { - uncheckedEnqueue(first, &c); - #ifdef DYNAMICNBLEVEL - if (update && c.learnt() && c.activity() > 2) { // GA - uint32_t nbLevels = calcNBLevels(c); - if (nbLevels+1 < c.activity()) - c.setActivity(nbLevels); - } +Basically, it goes through the watchlists recursively, and calls the appropirate +propagaton function +*/ +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& ws = watches[p.toInt()]; + __builtin_prefetch(ws.getData(), 1, 0); + Watched *i, *j; + num_props += ws.size()/2 + 2; + if (qhead < trail.size()) { + __builtin_prefetch(watches[trail[qhead].toInt()].getData(), 1, 1); + } + + #ifdef VERBOSE_DEBUG + cout << "Propagating lit " << p << endl; + cout << "ws origSize: "<< ws.size() << endl; + #endif + + i = j = ws.getData(); + Watched *end = ws.getDataEnd(); + for (; i != end; i++) { + #ifdef VERBOSE_DEBUG + cout << "end-i: " << end-i << endl; + cout << "end-j: " << end-j << endl; + cout << "i-j: " << i-j << endl; + if (i->isClause()) + std::cout << "clause num " << i->getNormOffset() + << " as i of prop: " << *clauseAllocator.getPointer(i->getNormOffset()) + << std::endl; + #endif + if (i->isBinary()) { + if (!propBinaryClause(i, j, end, p, confl)) break; + else continue; + } //end BINARY + + if (i->isTriClause()) { + if (!propTriClause(i, j, end, p, confl)) break; + else continue; + } //end TRICLAUSE + + if (i->isClause()) { + num_props += 4; + if (!propNormalClause(i, j, end, p, confl, update)) break; + else { + #ifdef VERBOSE_DEBUG + std::cout << "clause num " << i->getNormOffset() << " after propNorm: " << *clauseAllocator.getPointer(i->getNormOffset()) << std::endl; #endif + continue; } - } -FoundWatch: - ; - } - ws.shrink_(i - j); + } //end CLAUSE - //Finally, propagate XOR-clauses - if (xorclauses.size() > 0 && confl.isNULL()) confl = propagate_xors(p); + if (i->isXorClause()) { + num_props += 10; + if (!propXorClause(i, j, end, p, confl)) break; + else continue; + } //end XORCLAUSE + } + if (i != end) { + i++; + //copy remaining watches + memmove(j, i, sizeof(Watched)*(end-i)); + } + assert(i >= j); + ws.shrink_(i-j); } -EndPropagate: propagations += num_props; simpDB_props -= num_props; - + #ifdef VERBOSE_DEBUG cout << "Propagation ended." << endl; #endif @@ -1159,141 +1746,158 @@ EndPropagate: return confl; } -PropagatedFrom Solver::propagateBin() +/** +@brief Only propagates binary clauses + +This is used in special algorithms outside the main Solver class +*/ +PropBy Solver::propagateBin(vec& uselessBin) { + #ifdef DEBUG_USELESS_LEARNT_BIN_REMOVAL + assert(uselessBin.empty()); + #endif + while (qhead < trail.size()) { - Lit p = trail[qhead++]; - vec & wbin = binwatches[p.toInt()]; - propagations += wbin.size()/2; - for(WatchedBin *k = wbin.getData(), *end = wbin.getDataEnd(); k != end; k++) { - lbool val = value(k->impliedLit); + Lit p = trail[qhead++]; + + uint32_t lev = binPropData[p.var()].lev + 1; + + Lit lev2Ancestor; + if (lev == 2) lev2Ancestor = p; + else if (lev < 1) lev2Ancestor = lit_Undef; + else binPropData[p.var()].lev2Ancestor; + const bool learntLeadHere = binPropData[p.var()].learntLeadHere; + + //std::cout << "lev: " << lev << " ~p: " << ~p << std::endl; + const vec & ws = watches[p.toInt()]; + propagations += ws.size()/2 + 2; + for(const Watched *k = ws.getData(), *end = ws.getDataEnd(); k != end; k++) { + if (!k->isBinary()) continue; + + //std::cout << (~p) << ", " << k->getOtherLit() << " learnt: " << k->getLearnt() << std::endl; + lbool val = value(k->getOtherLit()); if (val.isUndef()) { - //uncheckedEnqueue(k->impliedLit, k->clause); - uncheckedEnqueueLight(k->impliedLit); + uncheckedEnqueueLight2(k->getOtherLit(), lev, lev2Ancestor, learntLeadHere || k->getLearnt()); } else if (val == l_False) { - return PropagatedFrom(p); + return PropBy(p); + } else { + assert(val == l_True); + Lit lit2 = k->getOtherLit(); + if (lev > 1 + && level[lit2.var()] != 0 + && binPropData[lit2.var()].lev == 1 + && binPropData[lit2.var()].lev2Ancestor != lev2Ancestor) { + //Was propagated at level 1, and again here, this binary clause is useless + binPropData[lit2.var()].lev = lev; + binPropData[lit2.var()].lev2Ancestor = lev2Ancestor; + binPropData[lit2.var()].learntLeadHere = learntLeadHere || k->getLearnt(); + uselessBin.push(lit2); + } } } } + //std::cout << " -----------" << std::endl; - return PropagatedFrom(); + return PropBy(); } -template -inline const uint32_t Solver::calcNBLevels(const T& ps) +/** +@brief Only propagates binary clauses + +This is used in special algorithms outside the main Solver class +*/ +PropBy Solver::propagateNonLearntBin() { - MYFLAG++; - uint32_t nbLevels = 0; - for(const Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) { - int32_t lev = level[l->var()]; - if (permDiff[lev] != MYFLAG) { - permDiff[lev] = MYFLAG; - nbLevels++; + multiLevelProp = false; + uint32_t origQhead = qhead + 1; + + while (qhead < trail.size()) { + Lit p = trail[qhead++]; + const vec & ws = watches[p.toInt()]; + propagations += ws.size()/2 + 2; + for(const Watched *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 nbLevels; + + return PropBy(); } -PropagatedFrom Solver::propagate_xors(const Lit& p) +/** +@brief Propagate recursively on non-learnt binaries, but do not propagate exceptLit if we reach it +*/ +const bool Solver::propagateBinExcept(const Lit exceptLit) { - #ifdef VERBOSE_DEBUG_XOR - cout << "Xor-Propagating variable " << p.var()+1 << endl; - #endif - - PropagatedFrom confl; - - vec& ws = xorwatches[p.var()]; - ClauseOffset *i, *j, *end; - for (i = j = ws.getData(), end = i + ws.size(); i != end;) { - XorClause& c = *(XorClause*)clauseAllocator.getPointer(*i); - ClauseOffset origClauseOffset = *i; - i++; - if (i != end) - __builtin_prefetch(clauseAllocator.getPointer(*i), 1, 0); - - // Make sure the false literal is data[1]: - if (c[0].var() == p.var()) { - Lit tmp(c[0]); - c[0] = c[1]; - c[1] = tmp; - } - assert(c[1].var() == p.var()); - - #ifdef VERBOSE_DEBUG_XOR - cout << "--> xor thing -- " << endl; - printClause(c); - cout << endl; - #endif - bool final = c.xor_clause_inverted(); - for (uint32_t k = 0, size = c.size(); k != size; k++ ) { - const lbool& val = assigns[c[k].var()]; - if (val.isUndef() && k >= 2) { - Lit tmp(c[1]); - c[1] = c[k]; - c[k] = tmp; - #ifdef VERBOSE_DEBUG_XOR - cout << "new watch set" << endl << endl; - #endif - xorwatches[c[1].var()].push(origClauseOffset); - goto FoundWatch; + while (qhead < trail.size()) { + Lit p = trail[qhead++]; + const vec & ws = watches[p.toInt()]; + propagations += ws.size()/2 + 2; + for(const Watched *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; } - - c[k] = c[k].unsign() ^ val.getBool(); - final ^= val.getBool(); } + } + return true; +} - { - // Did not find watch -- clause is unit under assignment: - *j++ = origClauseOffset; +/** +@brief Propagate only for one hop(=non-recursively) on non-learnt bins +*/ +const bool Solver::propagateBinOneLevel() +{ + Lit p = trail[qhead]; + const vec & ws = watches[p.toInt()]; + propagations += ws.size()/2 + 2; + for(const Watched *i = ws.getData(), *end = ws.getDataEnd(); i != end; i++) { + if (!i->isNonLearntBinary()) break; - #ifdef VERBOSE_DEBUG_XOR - cout << "final: " << std::boolalpha << final << " - "; - #endif - if (assigns[c[0].var()].isUndef()) { - c[0] = c[0].unsign()^final; - - #ifdef VERBOSE_DEBUG_XOR - cout << "propagating "; - printLit(c[0]); - cout << endl; - cout << "propagation clause -- "; - printClause(*(Clause*)&c); - cout << endl << endl; - #endif - - uncheckedEnqueue(c[0], (Clause*)&c); - } else if (!final) { - - #ifdef VERBOSE_DEBUG_XOR - printf("conflict clause -- "); - printClause(*(Clause*)&c); - cout << endl << endl; - #endif - - confl = PropagatedFrom((Clause*)&c); - qhead = trail.size(); - // Copy the remaining watches: - while (i < end) - *j++ = *i++; - } else { - #ifdef VERBOSE_DEBUG_XOR - printf("xor satisfied\n"); - #endif - - Lit tmp(c[0]); - c[0] = c[1]; - c[1] = tmp; - } + lbool val = value(i->getOtherLit()); + if (val.isUndef()) { + uncheckedEnqueueLight(i->getOtherLit()); + } else if (val == l_False) { + return false; } -FoundWatch: - ; } - ws.shrink_(i - j); - return confl; + return true; } +/** +@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 +inline const uint32_t Solver::calcNBLevels(const T& ps) +{ + MYFLAG++; + uint32_t nbLevels = 0; + for(const Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) { + int32_t lev = level[l->var()]; + if (permDiff[lev] != MYFLAG) { + permDiff[lev] = MYFLAG; + nbLevels++; + } + } + return nbLevels; +} /*_________________________________________________________________________________________________ | @@ -1304,195 +1908,99 @@ FoundWatch: | clauses are clauses that are reason to some assignment. Binary clauses are never removed. |________________________________________________________________________________________________@*/ bool reduceDB_ltMiniSat::operator () (const Clause* x, const Clause* y) { - const uint xsize = x->size(); - const uint ysize = y->size(); - - // First criteria - if (xsize > 2 && ysize == 2) return 1; - if (ysize > 2 && xsize == 2) return 0; - - if (x->oldActivity() == y->oldActivity()) + 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->oldActivity() < y->oldActivity(); + else return x->getMiniSatAct() < y->getMiniSatAct(); } - + bool reduceDB_ltGlucose::operator () (const Clause* x, const Clause* y) { - const uint xsize = x->size(); - const uint ysize = y->size(); - - // First criteria - if (xsize > 2 && ysize == 2) return 1; - if (ysize > 2 && xsize == 2) return 0; - - if (x->activity() > y->activity()) return 1; - if (x->activity() < y->activity()) return 0; + 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.getData()+learnts.size(), reduceDB_ltGlucose()); + std::sort(learnts.getData(), learnts.getDataEnd(), reduceDB_ltGlucose()); else - std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltMiniSat()); - + std::sort(learnts.getData(), learnts.getDataEnd(), reduceDB_ltMiniSat()); + #ifdef VERBOSE_DEBUG std::cout << "Cleaning clauses" << std::endl; - for (uint i = 0; i != learnts.size(); i++) { - std::cout << "activity:" << learnts[i]->activity() - << " \toldActivity:" << learnts[i]->oldActivity() + 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 uint removeNum = (double)learnts.size() / (double)RATIOREMOVECLAUSES; + + 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++){ - //NOTE: The next instruciton only works if removeNum < learnts.size() (strictly smaller!!) - __builtin_prefetch(learnts[i+1], 0, 0); - if (learnts[i]->size() > 2 && !locked(*learnts[i]) && learnts[i]->activity() > 2) { + if (i+1 < removeNum) __builtin_prefetch(learnts[i+1], 0, 0); + 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 + } 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); - - clauseAllocator.consolidate(this); -} + learnts.shrink_(i - j); -const vec& Solver::get_learnts() const -{ - return learnts; -} - -const vec& Solver::get_sorted_learnts() -{ - if (lastSelectedRestartType == dynamic_restart) - std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltGlucose()); - else - std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltMiniSat()); - return learnts; -} - -const vector Solver::get_unitary_learnts() const -{ - vector unitaries; - if (decisionLevel() > 0) { - for (uint32_t i = 0; i != trail_lim[0]; i++) { - unitaries.push_back(trail[i]); - } + 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; } - - return unitaries; -} - -void Solver::dumpSortedLearnts(const char* file, const uint32_t maxSize) -{ - FILE* outfile = fopen(file, "w"); - if (!outfile) { - printf("Error: Cannot open file '%s' to write learnt clauses!\n", file); - exit(-1); - } - - fprintf(outfile, "c \nc ---------\n"); - fprintf(outfile, "c unitaries\n"); - fprintf(outfile, "c ---------\n"); - for (uint32_t i = 0, end = (trail_lim.size() > 0) ? trail_lim[0] : trail.size() ; i < end; i++) { - trail[i].printFull(outfile); - #ifdef STATS_NEEDED - if (dynamic_behaviour_analysis) - fprintf(outfile, "c name of var: %s\n", logger.get_var_name(trail[i].var()).c_str()); - #endif //STATS_NEEDED - } - - fprintf(outfile, "c conflicts %lu\n", (unsigned long)conflicts); - if (maxSize == 1) goto end; - fprintf(outfile, "c \nc ---------------------------------\n"); - fprintf(outfile, "c learnt clauses from binaryClauses\n"); - fprintf(outfile, "c ---------------------------------\n"); - for (uint i = 0; i != binaryClauses.size(); i++) { - if (binaryClauses[i]->learnt()) { - binaryClauses[i]->print(outfile); - } - } - - fprintf(outfile, "c \nc ---------------------------------------\n"); - fprintf(outfile, "c clauses representing 2-long XOR clauses\n"); - fprintf(outfile, "c ---------------------------------------\n"); - { - const vector& table = varReplacer->getReplaceTable(); - for (Var var = 0; var != table.size(); var++) { - Lit lit = table[var]; - if (lit.var() == var) - continue; - - fprintf(outfile, "%s%d %d 0\n", (!lit.sign() ? "-" : ""), lit.var()+1, var+1); - fprintf(outfile, "%s%d -%d 0\n", (lit.sign() ? "-" : ""), lit.var()+1, var+1); - #ifdef STATS_NEEDED - if (dynamic_behaviour_analysis) - fprintf(outfile, "c name of two vars that are anti/equivalent: '%s' and '%s'\n", logger.get_var_name(lit.var()).c_str(), logger.get_var_name(var).c_str()); - #endif //STATS_NEEDED - } - } - fprintf(outfile, "c \nc --------------------n"); - fprintf(outfile, "c clauses from learnts\n"); - fprintf(outfile, "c --------------------n"); - if (lastSelectedRestartType == dynamic_restart) - std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltGlucose()); - else - std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltMiniSat()); - for (int i = learnts.size()-1; i >= 0 ; i--) { - if (learnts[i]->size() <= maxSize) { - learnts[i]->print(outfile); - } - } - - end: - - fclose(outfile); -} - -const uint32_t Solver::getNumElimSubsume() const -{ - return subsumer->getNumElimed(); -} - -const uint32_t Solver::getNumElimXorSubsume() const -{ - return xorSubsumer->getNumElimed(); -} - -const uint32_t Solver::getNumXorTrees() const -{ - return varReplacer->getNumTrees(); -} - -const uint32_t Solver::getNumXorTreesCrownSize() const -{ - return varReplacer->getNumReplacedVars(); -} - -const double Solver::getTotalTimeSubsumer() const -{ - return subsumer->getTotalTime(); -} - -const double Solver::getTotalTimeXorSubsumer() const -{ - return xorSubsumer->getTotalTime(); -} - - -void Solver::setMaxRestarts(const uint num) -{ - maxRestarts = num; + clauseAllocator.consolidate(this); } inline int64_t abs64(int64_t a) @@ -1501,14 +2009,13 @@ inline int64_t abs64(int64_t a) return a; } -/*_________________________________________________________________________________________________ -| -| simplify : [void] -> [bool] -| -| Description: -| Simplify the clause database according to the current top-level assigment. Currently, the only -| thing done here is the removal of satisfied clauses, but more things can be put here. -|________________________________________________________________________________________________@*/ +/** +@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. +*/ const bool Solver::simplify() { testAllClauseAttach(); @@ -1522,44 +2029,40 @@ const bool Solver::simplify() if (simpDB_props > 0) { return true; } - - double slowdown = (100000.0/(double)binaryClauses.size()); - slowdown = std::min(3.5, slowdown); - slowdown = std::max(0.2, slowdown); - - double speedup = 50000000.0/(double)(propagations-lastSearchForBinaryXor); + 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 (findBinaryXors && regularlyFindBinaryXors && - (((double)abs64((int64_t)nbBin - (int64_t)lastNbBin + (int64_t)becameBinary)/BINARY_TO_XOR_APPROX) * slowdown) > + + 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->removeSatisfied(binaryClauses, ClauseCleaner::binaryClauses); + clauseCleaner->removeSatisfiedBins(); if (!ok) return false; - testAllClauseAttach(); - XorFinder xorFinder(*this, binaryClauses, ClauseCleaner::binaryClauses); - if (!xorFinder.doNoPart(2, 2)) return false; - testAllClauseAttach(); - - lastNbBin = nbBin; - becameBinary = 0; + if (!sCCFinder->find2LongXors()) return false; + + lastNbBin = numNewBin; } - + // Remove satisfied clauses: clauseCleaner->removeAndCleanAll(); - testAllClauseAttach(); if (!ok) return false; - - if (performReplace && !varReplacer->performReplace()) + + if (conf.doReplace && !varReplacer->performReplace()) return false; // Remove fixed variables from the variable heap: @@ -1570,42 +2073,43 @@ const bool Solver::simplify() if (!(*gauss)->full_init()) return false; } #endif //USE_GAUSS - + simpDB_assigns = nAssigns(); - simpDB_props = clauses_literals + learnts_literals; // (shouldn't depend on stats really, but it will do for now) + 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 -/*_________________________________________________________________________________________________ -| -| search : (nof_conflicts : int) (nof_learnts : int) (params : const SearchParams&) -> [lbool] -| -| Description: -| Search for a model the specified number of conflicts, keeping the number of learnt clauses -| below the provided limit. NOTE! Use negative value for 'nof_conflicts' or 'nof_learnts' to -| indicate infinity. -| -| Output: -| 'l_True' if a partial assigment that is consistent with respect to the clauseset is found. If -| all variables are decision variables, this means that the clause set is satisfiable. 'l_False' -| if the clause set is unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached. -|________________________________________________________________________________________________@*/ -lbool Solver::search(int nof_conflicts, int nof_conflicts_fullrestart, const bool update) +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); - int conflictC = 0; + uint64_t conflictC = 0; vec learnt_clause; llbool ret; - starts++; - if (restartType == static_restart) - staticStarts++; - else - dynStarts++; - + if (!simplifying && update) { + starts++; + if (restartType == static_restart) staticStarts++; + else dynStarts++; + } + glueHistory.fastclear(); + #ifdef USE_GAUSS for (vector::iterator gauss = gauss_matrixes.begin(), end = gauss_matrixes.end(); gauss != end; gauss++) { if (!(*gauss)->full_init()) @@ -1615,8 +2119,17 @@ lbool Solver::search(int nof_conflicts, int nof_conflicts_fullrestart, const boo testAllClauseAttach(); findAllAttach(); + #ifdef VERBOSE_DEBUG + std::cout << "c started Solver::search()" << std::endl; + //printAllClauses(); + #endif //VERBOSE_DEBUG for (;;) { - PropagatedFrom confl = propagate(update); + assert(ok); + PropBy confl = propagate(update); + #ifdef VERBOSE_DEBUG + std::cout << "c Solver::search() has finished propagation" << std::endl; + //printAllClauses(); + #endif //VERBOSE_DEBUG if (!confl.isNULL()) { ret = handle_conflict(learnt_clause, confl, conflictC, update); @@ -1631,34 +2144,49 @@ lbool Solver::search(int nof_conflicts, int nof_conflicts_fullrestart, const boo } 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; } } } -llbool Solver::new_decision(const int& nof_conflicts, const int& nof_conflicts_fullrestart, int& conflictC) +/** +@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) { + #ifdef STATS_NEEDED + if (dynamic_behaviour_analysis) + progress_estimate = progressEstimate(); + #endif + cancelUntil(0); + return l_Undef; + } + // Reached bound on number of conflicts? switch (restartType) { case dynamic_restart: - if (nbDecisionLevelHistory.isvalid() && - ((nbDecisionLevelHistory.getavg()) > (totalSumOfDecisionLevel / (double)(conflicts - conflictsAtLastSolve)))) { - + if (glueHistory.isvalid() && + 0.95*glueHistory.getAvgDouble() > glueHistory.getAvgAllDouble()) { + #ifdef DEBUG_DYNAMIC_RESTART - if (nbDecisionLevelHistory.isvalid()) { - std::cout << "nbDecisionLevelHistory.getavg():" << nbDecisionLevelHistory.getavg() <= 0 && conflictC >= nof_conflicts) { + if (conflictC >= nof_conflicts) { #ifdef STATS_NEEDED if (dynamic_behaviour_analysis) progress_estimate = progressEstimate(); @@ -1681,25 +2209,18 @@ llbool Solver::new_decision(const int& nof_conflicts, const int& nof_conflicts_f assert(false); break; } - if (nof_conflicts_fullrestart >= 0 && (int)conflicts >= nof_conflicts_fullrestart) { - #ifdef STATS_NEEDED - if (dynamic_behaviour_analysis) - progress_estimate = progressEstimate(); - #endif - cancelUntil(0); - return l_Undef; - } // Simplify the set of problem clauses: - if (decisionLevel() == 0 && !simplify()) { - return l_False; + if (decisionLevel() == 0) { + if (!dataSync->syncData()) return l_False; + if (!simplify()) return l_False; } // Reduce the set of learnt clauses: - if (conflicts >= curRestart * nbclausesbeforereduce + nbCompensateSubsumer) { - curRestart ++; + if (conflicts >= numCleanedLearnts * nbClBeforeRed + nbCompensateSubsumer) { + numCleanedLearnts ++; reduceDB(); - nbclausesbeforereduce += 500; + nbClBeforeRed += 500; } Lit next = lit_Undef; @@ -1735,89 +2256,104 @@ llbool Solver::new_decision(const int& nof_conflicts, const int& nof_conflicts_f return l_Nothing; } -llbool Solver::handle_conflict(vec& learnt_clause, PropagatedFrom confl, int& conflictC, const bool update) +/** +@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& learnt_clause, PropBy confl, uint64_t& conflictC, const bool update) { #ifdef VERBOSE_DEBUG cout << "Handling conflict: "; - for (uint i = 0; i < learnt_clause.size(); i++) + for (uint32_t i = 0; i < learnt_clause.size(); i++) cout << learnt_clause[i].var()+1 << ","; cout << endl; #endif - + int backtrack_level; - uint32_t nbLevels; + uint32_t glue; conflicts++; conflictC++; if (decisionLevel() == 0) return l_False; learnt_clause.clear(); - Clause* c = analyze(confl, learnt_clause, backtrack_level, nbLevels, update); + Clause* c = analyze(confl, learnt_clause, backtrack_level, glue, update); if (update) { #ifdef RANDOM_LOOKAROUND_SEARCHSPACE avgBranchDepth.push(decisionLevel()); - #endif //RANDOM_LOOKAROUND_SEARCHSPACE - if (restartType == dynamic_restart) - nbDecisionLevelHistory.push(nbLevels); - - totalSumOfDecisionLevel += nbLevels; - } else { - conflictsAtLastSolve++; + #endif //RANDOM_LOOKAROUND_SEARCHSPACE + if (restartType == dynamic_restart) glueHistory.push(glue); + conflSizeHist.push(learnt_clause.size()); } - + #ifdef STATS_NEEDED if (dynamic_behaviour_analysis) logger.conflict(Logger::simple_confl_type, backtrack_level, confl->getGroup(), learnt_clause); #endif cancelUntil(backtrack_level); - + #ifdef VERBOSE_DEBUG cout << "Learning:"; - for (uint i = 0; i < learnt_clause.size(); i++) printLit(learnt_clause[i]), cout << " "; + 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 (c) { + 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 (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->resize(learnt_clause.size()); - if (c->learnt()) { - if (c->activity() > nbLevels) - c->setActivity(nbLevels); // LS - if (c->size() == 2) - nbBin++; - } - c->setStrenghtened(); - } else { - c = clauseAllocator.Clause_new(learnt_clause, learnt_clause_group++, true); + 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 #ifdef STATS_NEEDED if (dynamic_behaviour_analysis) logger.set_group_name(c->getGroup(), "learnt clause"); #endif - if (c->size() > 2) { - learnts.push(c); - c->setActivity(nbLevels); // LS + c = clauseAllocator.Clause_new(learnt_clause, learnt_clause_group++, true); + 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 { - binaryClauses.push(c); - nbBin++; + learnts.push(c); } + c->setGlue(std::min(glue, MAX_THEORETICAL_GLUE)); + attachClause(*c); + uncheckedEnqueue(learnt_clause[0], clauseAllocator.getOffset(c)); } - if (nbLevels <= 2) nbDL2++; - attachClause(*c); - uncheckedEnqueue(learnt_clause[0], c); + end:; } varDecayActivity(); @@ -1826,84 +2362,37 @@ llbool Solver::handle_conflict(vec& learnt_clause, PropagatedFrom confl, in return l_Nothing; } -double Solver::progressEstimate() const -{ - double progress = 0; - double F = 1.0 / nVars(); - - for (uint32_t i = 0; i <= decisionLevel(); i++) { - int beg = i == 0 ? 0 : trail_lim[i - 1]; - int end = i == decisionLevel() ? trail.size() : trail_lim[i]; - progress += pow(F, (int)i) * (end - beg); - } - - return progress / nVars(); -} +/** +@brief After a full restart, determines which restar type to use -#ifdef USE_GAUSS -void Solver::print_gauss_sum_stats() +Uses class RestartTypeChooser to do the heavy-lifting +*/ +const bool Solver::chooseRestartType(const uint32_t& lastFullRestart) { - if (gauss_matrixes.size() == 0 && verbosity >= 2) { - printf(" no matrixes found |\n"); - return; - } - - uint called = 0; - uint useful_prop = 0; - uint useful_confl = 0; - uint disabled = 0; - for (vector::const_iterator gauss = gauss_matrixes.begin(), end= gauss_matrixes.end(); gauss != end; gauss++) { - disabled += (*gauss)->get_disabled(); - called += (*gauss)->get_called(); - useful_prop += (*gauss)->get_useful_prop(); - useful_confl += (*gauss)->get_useful_confl(); - sum_gauss_unit_truths += (*gauss)->get_unit_truths(); - //gauss->print_stats(); - //gauss->print_matrix_stats(); - } - sum_gauss_called += called; - sum_gauss_confl += useful_confl; - sum_gauss_prop += useful_prop; - - if (verbosity >= 2) { - if (called == 0) { - printf(" disabled |\n"); - } else { - printf(" %3.0lf%% |", (double)useful_prop/(double)called*100.0); - printf(" %3.0lf%% |", (double)useful_confl/(double)called*100.0); - printf(" %3.0lf%% |\n", 100.0-(double)disabled/(double)gauss_matrixes.size()*100.0); - } - } -} -#endif //USE_GAUSS + uint32_t relativeStart = starts - lastFullRestart; -const bool Solver::chooseRestartType(const uint& lastFullRestart) -{ - uint relativeStart = starts - lastFullRestart; - if (relativeStart > RESTART_TYPE_DECIDER_FROM && relativeStart < RESTART_TYPE_DECIDER_UNTIL) { - if (fixRestartType == auto_restart) + if (conf.fixRestartType == auto_restart) restartTypeChooser->addInfo(); - + if (relativeStart == (RESTART_TYPE_DECIDER_UNTIL-1)) { RestartType tmp; - if (fixRestartType == auto_restart) + if (conf.fixRestartType == auto_restart) tmp = restartTypeChooser->choose(); else - tmp = fixRestartType; - + tmp = conf.fixRestartType; + if (tmp == dynamic_restart) { - nbDecisionLevelHistory.fastclear(); - nbDecisionLevelHistory.initSize(100); - if (verbosity >= 2) - printf("c | Decided on dynamic restart strategy |\n"); + glueHistory.fastclear(); + if (conf.verbosity >= 3) + std::cout << "c Decided on dynamic restart strategy" + << std::endl; } else { - if (verbosity >= 2) - printf("c | Decided on static restart strategy |\n"); - - #ifdef USE_GAUSS + if (conf.verbosity >= 1) + std::cout << "c Decided on static restart strategy" + << std::endl; + if (!matrixFinder->findMatrixes()) return false; - #endif //USE_GAUSS } lastSelectedRestartType = tmp; restartType = tmp; @@ -1916,94 +2405,61 @@ const bool Solver::chooseRestartType(const uint& lastFullRestart) inline void Solver::setDefaultRestartType() { - if (fixRestartType != auto_restart) restartType = fixRestartType; + if (conf.fixRestartType != auto_restart) restartType = conf.fixRestartType; else restartType = static_restart; - - if (restartType == dynamic_restart) { - nbDecisionLevelHistory.fastclear(); - nbDecisionLevelHistory.initSize(100); - } - + + 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. +*/ const lbool Solver::simplifyProblem(const uint32_t numConfls) { testAllClauseAttach(); - #ifdef USE_GAUSS - bool gauss_was_cleared = (gauss_matrixes.size() == 0); - clearGaussMatrixes(); - #endif //USE_GAUSS + bool gaussWasCleared = clearGaussMatrixes(); StateSaver savedState(*this);; #ifdef BURST_SEARCH - if (verbosity >= 2) - std::cout << "c | " << std::setw(24) << " " - << "Simplifying problem for " << std::setw(8) << numConfls << " confls" - << std::setw(24) << " |" << std::endl; - random_var_freq = 1; + 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) { - printRestartStat(); - status = search(100, -1, false); - starts--; + status = search(100, std::numeric_limits::max(), false); } - if (status != l_Undef) - goto end; - printRestartStat(); + printRestartStat("S"); + if (status != l_Undef) goto end; #endif //BURST_SEARCH - if (doXorSubsumption && !xorSubsumer->simplifyBySubsumption()) { - status = l_False; - goto end; - } - testAllClauseAttach(); + if (conf.doXorSubsumption && !xorSubsumer->simplifyBySubsumption()) goto end; - if (failedVarSearch && !failedVarSearcher->search((nClauses() < 500000 && order_heap.size() < 50000) ? 9000000 : 3000000)) { - status = l_False; - goto end; - } - testAllClauseAttach(); + if (conf.doFailedLit && !failedLitSearcher->search()) goto end; - if (performReplace && (regularRemoveUselessBins || regularSubsumeWithNonExistBinaries)) { - OnlyNonLearntBins onlyNonLearntBins(*this); - if (!onlyNonLearntBins.fill()) { - status = l_False; - goto end; - } - if (regularRemoveUselessBins) { - UselessBinRemover uselessBinRemover(*this, onlyNonLearntBins); - if (!uselessBinRemover.removeUslessBinFull()) { - status = l_False; - goto end; - } - } - if (regularSubsumeWithNonExistBinaries - && !subsumer->subsumeWithBinaries(&onlyNonLearntBins)) { - status = l_False; - goto end; - } - } + if (conf.doSatELite && !subsumer->simplifyBySubsumption(false)) goto end; + if (conf.doSatELite && !subsumer->simplifyBySubsumption(true)) goto end; - if (doSubsumption && !subsumer->simplifyBySubsumption(false)) { - status = l_False; - goto end; - } - if (doSubsumption && !subsumer->simplifyBySubsumption(true)) { - status = l_False; - goto end; - } - testAllClauseAttach(); - /*if (findNormalXors && xorclauses.size() > 200 && clauses.size() < MAX_CLAUSENUM_XORFIND/8) { XorFinder xorFinder(*this, clauses, ClauseCleaner::clauses); if (!xorFinder.doNoPart(3, 7)) { @@ -2011,558 +2467,377 @@ const lbool Solver::simplifyProblem(const uint32_t numConfls) goto end; } } else*/ if (xorclauses.size() <= 200 && xorclauses.size() > 0 && nClauses() > 10000) { - XorFinder x(*this, clauses, ClauseCleaner::clauses); + 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 (verbosity >= 2) - printf("c Simplifying finished |\n"); + if (conf.verbosity >= 3) + std::cout << "c Simplifying finished" << std::endl; #endif //#ifdef BURST_SEARCH - savedState.restore(); simplifying = false; - - #ifdef USE_GAUSS - if (status == l_Undef && !gauss_was_cleared && !matrixFinder->findMatrixes()) + + if (status == l_Undef && gaussWasCleared && !matrixFinder->findMatrixes()) status = l_False; - #endif //USE_GAUSS testAllClauseAttach(); + + if (!ok) return l_False; return status; } -const bool Solver::checkFullRestart(int& nof_conflicts, int& nof_conflicts_fullrestart, uint& lastFullRestart) +/** +@brief Should we perform a full restart? + +If so, we also do the things to be done if the full restart is effected. +Currently, this means we try to find disconnected components and solve +them with sub-solvers using class PartHandler +*/ +const bool Solver::checkFullRestart(uint64_t& nof_conflicts, uint64_t& nof_conflicts_fullrestart, uint32_t& lastFullRestart) { - if (nof_conflicts_fullrestart > 0 && (int)conflicts >= nof_conflicts_fullrestart) { + if (nof_conflicts_fullrestart > 0 && conflicts >= nof_conflicts_fullrestart) { #ifdef USE_GAUSS clearGaussMatrixes(); #endif //USE_GAUSS - if (verbosity >= 2) - printf("c | Fully restarting |\n"); - nof_conflicts = restart_first + (double)restart_first*restart_inc; + nof_conflicts = 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; }*/ - - if (doPartHandler && !partHandler->handle()) + + if (conf.doPartHandler && !partHandler->handle()) return false; - + //calculateDefaultPolarities(); - + if (conf.polarity_mode != polarity_auto) { + for (uint32_t i = 0; i < polarity.size(); i++) { + polarity[i] = defaultPolarity(); + } + } + fullStarts++; } - + return true; } -inline void Solver::performStepsBeforeSolve() +/** +@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(); - if (performReplace && !varReplacer->performReplace()) return; + printRestartStat(); + if (conf.doReplace && !varReplacer->performReplace()) return; - if (doSubsumption && !subsumer->simplifyBySubsumption(true)) { - return; - } + if (conf.doClausVivif && !conf.libraryUsage + && !clauseVivifier->vivifyClauses()) return; - if (performReplace) { - OnlyNonLearntBins onlyNonLearntBins(*this); - if (!onlyNonLearntBins.fill()) return; - if (regularRemoveUselessBins) { - UselessBinRemover uselessBinRemover(*this, onlyNonLearntBins); - if (!uselessBinRemover.removeUslessBinFull()) return; - } - if (subsumeWithNonExistBinaries - && !subsumer->subsumeWithBinaries(&onlyNonLearntBins)) return; - } + bool saveDoHyperBin = conf.doHyperBinRes; + conf.doHyperBinRes = false; + if (conf.doFailedLit && !failedLitSearcher->search()) return; + conf.doHyperBinRes = saveDoHyperBin; - if (doSubsumption - && !libraryUsage - && clauses.size() + binaryClauses.size() + learnts.size() < 4800000 + #ifdef VERBOSE_DEBUG + printAllClauses(); + #endif //VERBOSE_DEBUG + if (conf.doSatELite + && !conf.libraryUsage + && clauses.size() < 4800000 && !subsumer->simplifyBySubsumption()) return; - /* - if (conflicts == 0 && learnts.size() == 0 - && noLearntBinaries()) { - if (subsumeWithNonExistBinaries && !subsumer->subsumeWithBinaries(true)) return; - OnlyNonLearntBins onlyNonLearntBins(*this); - if (!onlyNonLearntBins.fill()) return; - if (regularRemoveUselessBins) { - UselessBinRemover uselessBinRemover(*this, onlyNonLearntBins); - if (!uselessBinRemover.removeUslessBinFull()) return; - } + if (conf.doFindEqLits) { + if (!sCCFinder->find2LongXors()) return; + lastNbBin = numNewBin; + if (conf.doReplace && !varReplacer->performReplace(true)) return; } - */ - if (findBinaryXors && binaryClauses.size() < MAX_CLAUSENUM_XORFIND) { - XorFinder xorFinder(*this, binaryClauses, ClauseCleaner::binaryClauses); - if (!xorFinder.doNoPart(2, 2)) return; - if (performReplace && !varReplacer->performReplace(true)) return; + if (conf.doFindXors && clauses.size() < MAX_CLAUSENUM_XORFIND) { + XorFinder xorFinder(*this, clauses); + if (!xorFinder.fullFindXors(3, 7)) return; } - if (findNormalXors && clauses.size() < MAX_CLAUSENUM_XORFIND) { - XorFinder xorFinder(*this, clauses, ClauseCleaner::clauses); - if (!xorFinder.doNoPart(3, 7)) return; - } - if (xorclauses.size() > 1) { - testAllClauseAttach(); - if (doXorSubsumption && !xorSubsumer->simplifyBySubsumption()) + if (conf.doXorSubsumption && !xorSubsumer->simplifyBySubsumption()) return; - - testAllClauseAttach(); - if (performReplace && !varReplacer->performReplace()) + + if (conf.doReplace && !varReplacer->performReplace()) return; } -} -void Solver::checkSolution() -{ - // Extend & check: - model.growTo(nVars()); - for (Var var = 0; var != nVars(); var++) model[var] = value(var); - verifyModel(); - model.clear(); + if (conf.doSortWatched) sortWatched(); + if (conf.doCacheOTFSSR && conf.doCalcReach) calcReachability(); + + testAllClauseAttach(); } -lbool Solver::solve(const vec& assumps) +/** +@brief Initialises model, restarts, learnt cluause cleaning, burst-search, etc. +*/ +void Solver::initialiseSolver() { -#ifdef VERBOSE_DEBUG - std::cout << "Solver::solve() called" << std::endl; -#endif - if (!ok) return l_False; - assert(qhead == trail.size()); - - if (libraryCNFFile) - fprintf(libraryCNFFile, "c Solver::solve() called\n"); - + //Clear up previous stuff like model, final conflict, matrixes model.clear(); conflict.clear(); - #ifdef USE_GAUSS clearGaussMatrixes(); - #endif //USE_GAUSS + + //Initialise restarts & dynamic restart datastructures setDefaultRestartType(); - totalSumOfDecisionLevel = 0; - conflictsAtLastSolve = conflicts; + + //Initialise avg. branch depth #ifdef RANDOM_LOOKAROUND_SEARCHSPACE - avgBranchDepth.fastclear(); + avgBranchDepth.clear(); avgBranchDepth.initSize(500); #endif //RANDOM_LOOKAROUND_SEARCHSPACE - starts = 0; - assumps.copyTo(assumptions); + //Initialise number of restarts&full restarts + starts = 0; + fullStarts = 0; - int nof_conflicts = restart_first; - int nof_conflicts_fullrestart = restart_first * FULLRESTART_MULTIPLIER + conflicts; - //nof_conflicts_fullrestart = -1; - uint lastFullRestart = starts; - lbool status = l_Undef; - uint64_t nextSimplify = restart_first * SIMPLIFY_MULTIPLIER + conflicts; - - if (nClauses() * learntsize_factor < nbclausesbeforereduce) { - if (nClauses() * learntsize_factor < nbclausesbeforereduce/2) - nbclausesbeforereduce = nbclausesbeforereduce/4; + if (nClauses() * conf.learntsize_factor < nbClBeforeRed) { + if (nClauses() * conf.learntsize_factor < nbClBeforeRed/2) + nbClBeforeRed /= 4; else - nbclausesbeforereduce = (nClauses() * learntsize_factor)/2; + 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& 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::max(); + if (conflicts == 0) { - performStepsBeforeSolve(); + if (conf.doPerformPreSimp) performStepsBeforeSolve(); if (!ok) return l_False; - - printStatHeader(); } calculateDefaultPolarities(); - + + printStatHeader(); + printRestartStat("B"); + uint64_t lastConflPrint = conflicts; // Search: - while (status == l_Undef && starts < maxRestarts) { + while (status == l_Undef && starts < conf.maxRestarts) { #ifdef DEBUG_VARELIM assert(subsumer->checkElimedUnassigned()); assert(xorSubsumer->checkElimedUnassigned()); #endif //DEBUG_VARELIM - - if (schedSimplification && conflicts >= nextSimplify) { - status = simplifyProblem(500); - nextSimplify = conflicts * 1.5; + + if ((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; } - - printRestartStat(); + #ifdef STATS_NEEDED if (dynamic_behaviour_analysis) { logger.end(Logger::restarting); logger.begin(); } #endif - - status = search(nof_conflicts, nof_conflicts_fullrestart); - nof_conflicts = (double)nof_conflicts * restart_inc; + + 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)) + if (!checkFullRestart(nof_conflicts, nof_conflicts_fullrestart , lastFullRestart)) return l_False; if (!chooseRestartType(lastFullRestart)) return l_False; - #ifdef RANDOM_LOOKAROUND_SEARCHSPACE - //if (avgBranchDepth.isvalid()) - // std::cout << "avg branch depth:" << avgBranchDepth.getavg() << std::endl; - #endif //RANDOM_LOOKAROUND_SEARCHSPACE } printEndSearchStat(); - - #ifdef USE_GAUSS - for (uint i = 0; i < gauss_matrixes.size(); i++) - delete gauss_matrixes[i]; - gauss_matrixes.clear(); - #endif //USE_GAUSS -#ifdef VERBOSE_DEBUG + #ifdef VERBOSE_DEBUG if (status == l_True) std::cout << "Solution is SAT" << std::endl; else if (status == l_False) std::cout << "Solution is UNSAT" << std::endl; else std::cout << "Solutions is UNKNOWN" << std::endl; -#endif //VERBOSE_DEBUG - - if (status == l_True) { - if (greedyUnbound) { - double time = cpuTime(); - FindUndef finder(*this); - const uint unbounded = finder.unRoll(); - if (verbosity >= 1) - printf("c Greedy unbounding :%5.2lf s, unbounded: %7d vars\n", cpuTime()-time, unbounded); - } + #endif //VERBOSE_DEBUG + + if (status == l_True) handleSATSolution(); + else if (status == l_False) handleUNSATSolution(); - partHandler->addSavedState(); - varReplacer->extendModelPossible(); -#ifndef NDEBUG - //checkSolution(); -#endif - - if (subsumer->getNumElimed() || xorSubsumer->getNumElimed()) { - if (verbosity >= 1) { - std::cout << "c Solution needs extension. Extending." << std::endl; - } - Solver s; - s.doSubsumption = false; - s.performReplace = false; - s.findBinaryXors = false; - s.findNormalXors = false; - s.failedVarSearch = false; - s.conglomerateXors = false; - s.subsumeWithNonExistBinaries = false; - s.regularSubsumeWithNonExistBinaries = false; - s.removeUselessBins = false; - s.regularRemoveUselessBins = false; - s.greedyUnbound = greedyUnbound; - for (Var var = 0; var < nVars(); var++) { - s.newVar(decision_var[var] || subsumer->getVarElimed()[var] || varReplacer->varHasBeenReplaced(var) || xorSubsumer->getVarElimed()[var]); - - //assert(!(xorSubsumer->getVarElimed()[var] && (decision_var[var] || subsumer->getVarElimed()[var] || varReplacer->varHasBeenReplaced(var)))); - - if (value(var) != l_Undef) { - vec tmp; - tmp.push(Lit(var, value(var) == l_False)); - s.addClause(tmp); - } - } - varReplacer->extendModelImpossible(s); - subsumer->extendModel(s); - xorSubsumer->extendModel(s); - - status = s.solve(); - if (status != l_True) { - printf("c ERROR! Extension of model failed!\n"); - assert(status == l_True); - exit(-1); - } -#ifdef VERBOSE_DEBUG - std::cout << "Solution extending finished." << std::endl; -#endif - for (Var var = 0; var < nVars(); var++) { - if (assigns[var] == l_Undef && s.model[var] != l_Undef) uncheckedEnqueue(Lit(var, s.model[var] == l_False)); - } - ok = (propagate().isNULL()); - if (!ok) { - printf("c ERROR! Extension of model failed!\n"); - assert(ok); - exit(-1); - } - } -#ifndef NDEBUG - //checkSolution(); -#endif - //Copy model: - model.growTo(nVars()); - for (Var var = 0; var != nVars(); var++) model[var] = value(var); - } - - if (status == l_False) { - if (conflict.size() == 0) - ok = false; - } - #ifdef STATS_NEEDED if (dynamic_behaviour_analysis) { if (status == l_True) logger.end(Logger::model_found); else if (status == l_False) - logger.end(Logger::unsat_model_found); + logger.end(Logger::unsat_model_found); else if (status == l_Undef) logger.end(Logger::restarting); } #endif - - #ifdef LS_STATS_NBBUMP - for(int i=0;isize(),learnts[i]->activity(), - (uint)learnts[i]->nbBump()); - #endif cancelUntil(0); - if (doPartHandler && status != l_False) partHandler->readdRemovedClauses(); + if (conf.doPartHandler && status != l_False) partHandler->readdRemovedClauses(); restartTypeChooser->reset(); - -#ifdef VERBOSE_DEBUG - std::cout << "Solver::solve() finished" << std::endl; -#endif - return status; -} - -//================================================================================================= -// Debug methods: -bool Solver::verifyXorClauses(const vec& cs) const -{ - #ifdef VERBOSE_DEBUG - cout << "Checking xor-clauses whether they have been properly satisfied." << endl;; - #endif - - bool failed = false; - - for (uint32_t i = 0; i != xorclauses.size(); i++) { - XorClause& c = *xorclauses[i]; - bool final = c.xor_clause_inverted(); - - #ifdef VERBOSE_DEBUG - XorClause* c2 = XorClause_new(c, c.xor_clause_inverted(), c.getGroup()); - std::sort(c2->getData(), c2->getData()+ c2->size()); - c2->plainPrint(); - clauseFree(c2); - #endif - - for (uint j = 0; j < c.size(); j++) { - assert(modelValue(c[j].unsign()) != l_Undef); - final ^= (modelValue(c[j].unsign()) == l_True); - } - if (!final) { - printf("unsatisfied clause: "); - xorclauses[i]->plainPrint(); - failed = true; - } - } - - return failed; -} - -bool Solver::verifyClauses(const vec& cs) const -{ #ifdef VERBOSE_DEBUG - cout << "Checking clauses whether they have been properly satisfied." << endl;; - #endif - - bool failed = false; - - for (uint32_t i = 0; i != cs.size(); i++) { - Clause& c = *cs[i]; - for (uint j = 0; j < c.size(); j++) - if (modelValue(c[j]) == l_True) - goto next; - - printf("unsatisfied clause: "); - cs[i]->plainPrint(); - failed = true; - next: - ; - } - - return failed; -} - -void Solver::verifyModel() -{ - assert(!verifyClauses(clauses)); - assert(!verifyClauses(binaryClauses)); - assert(!verifyXorClauses(xorclauses)); - - if (verbosity >=1) - printf("c Verified %d clauses.\n", clauses.size() + xorclauses.size()); -} - - -void Solver::checkLiteralCount() -{ - // Check that sizes are calculated correctly: - int cnt = 0; - for (uint32_t i = 0; i != clauses.size(); i++) - cnt += clauses[i]->size(); - - for (uint32_t i = 0; i != xorclauses.size(); i++) - cnt += xorclauses[i]->size(); - - if ((int)clauses_literals != cnt) { - fprintf(stderr, "literal count: %d, real value = %d\n", (int)clauses_literals, cnt); - assert((int)clauses_literals == cnt); - } -} - -void Solver::printStatHeader() const -{ - #ifdef STATS_NEEDED - if (verbosity >= 1 && !(dynamic_behaviour_analysis && logger.statistics_on)) { - #else - if (verbosity >= 1) { + std::cout << "Solver::solve() finished" << std::endl; #endif - printf("c ============================[ Search Statistics ]========================================\n"); - printf("c | Conflicts | ORIGINAL | LEARNT | GAUSS |\n"); - printf("c | | Vars Clauses Literals | Limit Clauses Lit/Cl | Prop Confl On |\n"); - printf("c =========================================================================================\n"); - } + return status; } -void Solver::printRestartStat() -{ - if (verbosity >= 2) { - printf("c | %9d | %7d %8d %8d | %8d %8d %6.0f |", (int)conflicts, (int)order_heap.size(), (int)(nClauses()-nbBin), (int)clauses_literals, (int)(nbclausesbeforereduce*curRestart+nbCompensateSubsumer), (int)(nLearnts()+nbBin), (double)learnts_literals/(double)(nLearnts()+nbBin)); - } - - #ifdef USE_GAUSS - print_gauss_sum_stats(); - #else //USE_GAUSS - if (verbosity >= 2) { - printf(" |\n"); - } - #endif //USE_GAUSS -} +/** +@brief Extends a SAT solution to the full solution -void Solver::printEndSearchStat() +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() { - #ifdef STATS_NEEDED - if (verbosity >= 1 && !(dynamic_behaviour_analysis && logger.statistics_on)) { - #else - if (verbosity >= 1) { - #endif //STATS_NEEDED - printf("c ===================================================================="); - #ifdef USE_GAUSS - print_gauss_sum_stats(); - if (verbosity == 1) printf("=====================\n"); - #else //USE_GAUSS - printf("\n"); - #endif //USE_GAUSS - } -} -#ifdef DEBUG_ATTACH -void Solver::testAllClauseAttach() const -{ - for (Clause *const*it = clauses.getData(), *const*end = clauses.getDataEnd(); it != end; it++) { - const Clause& c = **it; - if (c.size() > 2) { - assert(findWatchedCl(watches[(~c[0]).toInt()], &c)); - assert(findWatchedCl(watches[(~c[1]).toInt()], &c)); - } else { - assert(findWatchedBinCl(binwatches[(~c[0]).toInt()], &c)); - assert(findWatchedBinCl(binwatches[(~c[1]).toInt()], &c)); + /*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()); + + partHandler->addSavedState(); + varReplacer->extendModelPossible(); + checkSolution(); + + if (subsumer->getNumElimed() || xorSubsumer->getNumElimed()) { + if (conf.verbosity >= 1) { + std::cout << "c Solution needs extension. Extending." << std::endl; } - } - - for (Clause *const*it = binaryClauses.getData(), *const*end = binaryClauses.getDataEnd(); it != end; it++) { - const Clause& c = **it; - assert(c.size() == 2); - assert(findWatchedBinCl(binwatches[(~c[0]).toInt()], &c)); - assert(findWatchedBinCl(binwatches[(~c[1]).toInt()], &c)); - } - - for (XorClause *const*it = xorclauses.getData(), *const*end = xorclauses.getDataEnd(); it != end; it++) { - const XorClause& c = **it; - assert(find(xorwatches[c[0].var()], &c)); - assert(find(xorwatches[c[1].var()], &c)); - if (assigns[c[0].var()]!=l_Undef || assigns[c[1].var()]!=l_Undef) { - for (uint i = 0; i < c.size();i++) { - assert(assigns[c[i].var()] != l_Undef); + 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.doPartHandler = false; + s.conf.doSortWatched = false; + s.conf.verbosity = 0; + + vec 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); } } - } -} - -void Solver::findAllAttach() const -{ - for (uint32_t i = 0; i < binwatches.size(); i++) { - for (uint32_t i2 = 0; i2 < binwatches[i].size(); i2++) { - assert(findClause(binwatches[i][i2].clause)); - } - } - for (uint32_t i = 0; i < watches.size(); i++) { - for (uint32_t i2 = 0; i2 < watches[i].size(); i2++) { - assert(findClause(watches[i][i2].clause)); - } - } + varReplacer->extendModelImpossible(s); + subsumer->extendModel(s); + xorSubsumer->extendModel(s); - for (uint32_t i = 0; i < xorwatches.size(); i++) { - for (uint32_t i2 = 0; i2 < xorwatches[i].size(); i2++) { - assert(findClause(xorwatches[i][i2])); + 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 + 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().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); } -const bool Solver::findClause(XorClause* c) const -{ - for (uint32_t i = 0; i < xorclauses.size(); i++) { - if (xorclauses[i] == c) return true; - } - return false; -} - -const bool Solver::findClause(Clause* c) const -{ - for (uint32_t i = 0; i < binaryClauses.size(); i++) { - if (binaryClauses[i] == c) return true; - } - for (uint32_t i = 0; i < clauses.size(); i++) { - if (clauses[i] == c) return true; - } - for (uint32_t i = 0; i < learnts.size(); i++) { - if (learnts[i] == c) return true; - } - vec cs = varReplacer->getClauses(); - for (uint32_t i = 0; i < cs.size(); i++) { - if (cs[i] == c) return true; - } - - return false; -} -#endif //DEBUG_ATTACH +/** +@brief When problem is decided to be UNSAT, this is called -const bool Solver::noLearntBinaries() const +There is basically nothing to be handled for the moment, but this could be +made extensible +*/ +void Solver::handleUNSATSolution() { - for (uint32_t i = 0; i < binaryClauses.size(); i++) { - if (binaryClauses[i]->learnt()) return false; - } - - return true; + if (conflict.size() == 0) + ok = false; } - -}; //NAMESPACE MINISAT diff --git a/src/sat/cryptominisat2/Solver.h b/src/sat/cryptominisat2/Solver.h index 75daea6..97d291a 100644 --- a/src/sat/cryptominisat2/Solver.h +++ b/src/sat/cryptominisat2/Solver.h @@ -25,27 +25,40 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include #include #include +#include + #ifdef _MSC_VER #include #else #include #endif //_MSC_VER -#include "time_mem.h" +#ifdef STATS_NEEDED +#include "Logger.h" +#endif //STATS_NEEDED + + +#include "PropBy.h" #include "Vec.h" #include "Heap.h" #include "Alg.h" -#include "MersenneTwister.h" +#include "MTRand/MersenneTwister.h" #include "SolverTypes.h" #include "Clause.h" -#include "Logger.h" #include "constants.h" #include "BoundedQueue.h" #include "GaussianConfig.h" - -namespace MINISAT -{ -using namespace MINISAT; +#include "ClauseAllocator.h" +#include "SolverConf.h" + +#define release_assert(a) \ + do { \ + if (!(a)) {\ + fprintf(stderr, "*** ASSERTION FAILURE in %s() [%s:%d]: %s\n", \ + __FUNCTION__, __FILE__, __LINE__, #a); \ + abort(); \ + } \ + } while (0) class Gaussian; class MatrixFinder; @@ -54,13 +67,22 @@ class VarReplacer; class XorFinder; class FindUndef; class ClauseCleaner; -class FailedVarSearcher; +class FailedLitSearcher; class Subsumer; class XorSubsumer; class PartHandler; class RestartTypeChooser; class StateSaver; class UselessBinRemover; +class SCCFinder; +class ClauseVivifier; +class SharedData; +class DataSync; + +namespace BEEV +{ + class CryptoMinisat; +} #ifdef VERBOSE_DEBUG #define DEBUG_UNCHECKEDENQUEUE_LEVEL0 @@ -81,197 +103,85 @@ struct reduceDB_ltGlucose bool operator () (const Clause* x, const Clause* y); }; -//#define DEBUG_PROPAGATEFROM - -class PropagatedFrom -{ - private: - union {Clause* clause; uint32_t otherLit;}; - - public: - PropagatedFrom(Clause* c) - { - #ifdef DEBUG_PROPAGATEFROM - assert(c != NULL); - #endif - clause = c; - } - - PropagatedFrom(const Lit& _other) - { - otherLit = _other.toInt() << 1; - otherLit |= 1; - } - - PropagatedFrom() : - clause(NULL) - { - } - - const bool isBinary() const - { - return (otherLit&1); - } - - const Lit getOtherLit() const - { - #ifdef DEBUG_PROPAGATEFROM - assert(isBinary()); - #endif - return Lit::toLit(otherLit>>1); - } - - const Clause* getClause() const - { - #ifdef DEBUG_PROPAGATEFROM - assert(!isBinary()); - #endif - return clause; - } - - Clause* getClause() - { - return clause; - } - - const bool isNULL() const - { - if (isBinary()) return false; - return clause == NULL; - } - - const uint32_t size() const - { - if (isBinary()) return 2; - - #ifdef DEBUG_PROPAGATEFROM - assert(!isNULL()); - #endif - - return getClause()->size(); - } +/** +@brief The main solver class - const Lit operator[](uint32_t i) const - { - if (isBinary()) { - #ifdef DEBUG_PROPAGATEFROM - assert(i == 1); - #endif - return getOtherLit(); - } - - #ifdef DEBUG_PROPAGATEFROM - assert(!isNULL()); - #endif - return (*getClause())[i]; - } -}; +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: + friend class BEEV::CryptoMinisat; // Constructor/Destructor: // - Solver(); + Solver(const SolverConf& conf = SolverConf(), const GaussConf& _gaussconfig = GaussConf(), SharedData* sharedUnitData = NULL); ~Solver(); // Problem specification: // - Var newVar (bool dvar = true); // Add a new variable with parameters specifying variable mode. + Var newVar (bool dvar = true); // Add a new variable with parameters specifying variable mode. + template + bool addClause (T& ps, const uint32_t group = 0, const char* group_name = NULL); // Add a clause to the solver. NOTE! 'ps' may be shrunk by this method! template - bool addClause (T& ps, const uint group = 0, char* group_name = NULL); // Add a clause to the solver. NOTE! 'ps' may be shrunk by this method! + bool addLearntClause(T& ps, const uint32_t group = 0, const char* group_name = NULL, const uint32_t glue = 10, const float miniSatActivity = 10.0); template - bool addXorClause (T& ps, bool xor_clause_inverted, const uint group = 0, char* group_name = NULL); // Add a xor-clause to the solver. NOTE! 'ps' may be shrunk by this method! + bool addXorClause (T& ps, bool xorEqualFalse, const uint32_t group = 0, const char* group_name = NULL); // Add a xor-clause to the solver. NOTE! 'ps' may be shrunk by this method! // Solving: // - lbool solve (const vec& assumps); // Search for a model that respects a given set of assumptions. - lbool solve (); // Search without assumptions. - bool okay () const; // FALSE means solver is in a conflicting state + lbool solve (const vec& assumps); /// model; // If problem is satisfiable, this vector contains the model (if any). - vec conflict; // If problem is unsatisfiable (possibly under assumptions), - // this vector represent the final conflict clause expressed in the assumptions. + vec model; /// conflict; ///& 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& get_learnts() const; //Get all learnt clauses that are >1 long const vector get_unitary_learnts() const; //return the set of unitary learnt clauses - const uint get_unitary_learnts_num() const; //return the number of unitary learnt clauses - void dumpSortedLearnts(const char* file, const uint32_t maxSize); // Dumps all learnt clauses (including unitary ones) into the file - void needLibraryCNFFile(const char* fileName); //creates file in current directory with the filename indicated, and puts all calls from the library into the file. + const uint32_t get_unitary_learnts_num() const; //return the number of unitary learnt clauses + void dumpSortedLearnts(const std::string& fileName, const uint32_t maxSize); // Dumps all learnt clauses (including unitary ones) into the file + void needLibraryCNFFile(const std::string& fileName); //creates file in current directory with the filename indicated, and puts all calls from the library into the file. + void dumpOrigClauses(const std::string& fileName) const; #ifdef USE_GAUSS const uint32_t get_sum_gauss_called() const; @@ -281,44 +191,96 @@ public: #endif //USE_GAUSS //Printing statistics - const uint32_t getNumElimSubsume() const; // Get variable elimination stats from Subsumer - const uint32_t getNumElimXorSubsume() const; // Get variable elimination stats from XorSubsumer - const 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 - const uint32_t getNumXorTreesCrownSize() const; // Get the number of variables being replaced by other variables + void printStats(); + const uint32_t getNumElimSubsume() const; /// gauss_matrixes; #ifdef USE_GAUSS void print_gauss_sum_stats(); - void clearGaussMatrixes(); - vector gauss_matrixes; - - //stats uint32_t sum_gauss_called; uint32_t sum_gauss_confl; uint32_t sum_gauss_prop; uint32_t sum_gauss_unit_truths; - friend class Gaussian; #endif //USE_GAUSS - - template - Clause* addClauseInt(T& ps, uint group); - template - XorClause* addXorClauseInt(T& ps, bool xor_clause_inverted, const uint32_t group); - template - bool addLearntClause(T& ps, const uint group, const uint32_t activity); - template - void removeWatchedCl(vec &ws, const ClauseOffset c); - template - bool findWatchedCl(const vec& ws, const ClauseOffset c) const; - template - void removeWatchedBinCl(vec &ws, const Lit impliedLit); - template - void removeWatchedBinClAll(vec &ws, const Lit impliedLit); + + // Statistics + // + template + void printStatsLine(std::string left, T value, T2 value2, std::string extra); template - bool findWatchedBinCl(const vec& ws, const Lit impliedLit) const; - + void printStatsLine(std::string left, T value, std::string extra = ""); + uint64_t starts; ///& act) : activity(act) { } }; - friend class VarFilter; struct VarFilter { const Solver& s; VarFilter(const Solver& _s) : s(_s) {} @@ -340,134 +301,192 @@ protected: // Solver state: // - bool ok; // If FALSE, the constraints are already unsatisfiable. No part of the solver state may be used! - ClauseAllocator clauseAllocator; - vec clauses; // List of problem clauses. - vec binaryClauses; // Binary clauses are regularly moved here - vec xorclauses; // List of problem xor-clauses. Will be freed - vec learnts; // List of learnt clauses. - vec freeLater; // xor clauses that need to be freed later due to Gauss - vec activity; // A heuristic measurement of the activity of a variable. - uint32_t var_inc; // Amount to bump next variable with. - double cla_inc; // Amount to bump learnt clause oldActivity with - vec > watches; // 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true). - vec > xorwatches; // 'xorwatches[var]' is a list of constraints watching var in XOR clauses. - vec > binwatches; - vec assigns; // The current assignments - vector polarity; // The preferred polarity of each variable. - #ifdef USE_OLD_POLARITIES - vector oldPolarity; // The polarity before the last setting. Good for unsetting polairties that have been changed since the last conflict - #endif //USE_OLD_POLARITIES - vector decision_var; // Declares if a variable is eligible for selection in the decision heuristic. - vec trail; // Assignment stack; stores all assigments made in the order they were made. - vec trail_lim; // Separator indices for different decision levels in 'trail'. - vec reason; // 'reason[var]' is the clause that implied the variables current value, or 'NULL' if none. - vec level; // 'level[var]' contains the level at which the assignment was made. - uint64_t curRestart; - uint32_t nbclausesbeforereduce; - uint32_t nbCompensateSubsumer; // Number of learnt clauses that subsumed normal clauses last time subs. was executed - uint32_t qhead; // Head of queue (as index into the trail -- no more explicit propagation queue in MiniSat). - Lit failBinLit; - 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()'. - vec assumptions; // Current set of assumptions provided to solve by the user. - Heap order_heap; // A priority queue of variables ordered with respect to the variable activity. - double progress_estimate;// Set by 'search()'. - bool remove_satisfied; // Indicates whether possibly inefficient linear scan for satisfied clauses should be performed in 'simplify'. - bqueue nbDecisionLevelHistory; // Set of last decision level in conflict clauses - double totalSumOfDecisionLevel; - uint64_t conflictsAtLastSolve; + 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 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 xorclauses; ///< List of problem xor-clauses. Will be freed + vec learnts; ///< List of learnt clauses. + uint32_t numBins; + vec 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 > watches; ///< 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true). + vec assigns; ///< The current assignments + vector decision_var; ///< Declares if a variable is eligible for selection in the decision heuristic. + vec trail; ///< Assignment stack; stores all assigments made in the order they were made. + vec trail_lim; ///< Separator indices for different decision levels in 'trail'. + vec reason; ///< 'reason[var]' is the clause that implied the variables current value, or 'NULL' if none. + vec level; ///< 'level[var]' contains the level at which the assignment was made. + vec 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 assumptions; ///< Current set of assumptions provided to solve by the user. #ifdef RANDOM_LOOKAROUND_SEARCHSPACE - bqueue avgBranchDepth; // Avg branch depth + bqueue avgBranchDepth; ///< Avg branch depth. We collect this, and use it to do random look-around in the searchspace during simplifyProblem() #endif //RANDOM_LOOKAROUND_SEARCHSPACE - MTRand mtrand; // random number generaton - RestartType restartType; // Used internally to determine which restart strategy to choose - RestartType lastSelectedRestartType; //the last selected restart type - friend class Logger; - #ifdef STATS_NEEDED - Logger logger; // dynamic logging, statistics - bool dynamic_behaviour_analysis; // Is logger running? + MTRand mtrand; ///< random number generator + + ///////////////// + // Variable activities + ///////////////// + Heap 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 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; /// + const uint32_t calcNBLevels(const T& ps); + vec permDiff; /// lastDecisionLevel; #endif - uint maxRestarts; // More than this number of restarts will not be performed + bqueue glueHistory; ///< Set of last decision levels in (glue of) conflict clauses. Used for dynamic restarting + vec unWindGlue; // 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 seen; + vector seen; /// analyze_stack; vec analyze_toclear; - vec add_tmp; - - - uint64_t MYFLAG; - template - const uint32_t calcNBLevels(const T& ps); - vec permDiff; // LS: permDiff[var] contains the current conflict number... Used to count the number of different decision level variables in learnt clause - #ifdef UPDATEVARACTIVITY - vec lastDecisionLevel; - #endif + //////////// + // Transitive on-the-fly self-subsuming resolution + /////////// + class TransCache { + public: + TransCache() : + conflictLastUpdated(std::numeric_limits::max()) + {}; + + vector lits; + uint64_t conflictLastUpdated; + }; + class LitReachData { + public: + LitReachData() : + lit(lit_Undef) + , numInCache(0) + {} + Lit lit; + uint32_t numInCache; + }; + vector seen2; /// allAddedToSeen2; /// toRecursiveProp; /// transOTFCache; + bqueue conflSizeHist; + void minimiseLeartFurther(vec& cl, const uint32_t glue); + void transMinimAndUpdateCache(const Lit lit, uint32_t& moreRecurProp); + void saveOTFData(); + vectorlitReachable; + void calcReachability(); + + //////////// //Logging - uint learnt_clause_group; //the group number of learnt clauses. Incremented at each added learnt clause - FILE *libraryCNFFile; //The file that all calls from the library are logged + /////////// + #ifdef STATS_NEEDED + Logger logger; // dynamic logging, statistics + bool dynamic_behaviour_analysis; // Is logger running? + #endif + uint32_t learnt_clause_group; //the group number of learnt clauses. Incremented at each added learnt clause + FILE *libraryCNFFile; //The file that all calls from the library are logged - // Main internal methods: - // - const bool simplify (); // Removes already satisfied clauses. - //int nbPropagated (int level); - void insertVarOrder (Var x); // Insert a variable in the decision order priority queue. + ///////////////// + // Propagating + //////////////// Lit pickBranchLit (); // Return the next decision variable. void newDecisionLevel (); // Begins a new decision level. - void uncheckedEnqueue (const Lit p, const PropagatedFrom& from = PropagatedFrom()); // Enqueue a literal. Assumes value of literal is undefined. + void uncheckedEnqueue (const Lit p, const PropBy& from = PropBy()); // Enqueue a literal. Assumes value of literal is undefined. void uncheckedEnqueueLight (const Lit p); - bool enqueue (Lit p, PropagatedFrom from = PropagatedFrom()); // Test if fact 'p' contradicts current state, enqueue otherwise. - PropagatedFrom propagate (const bool update = true); // Perform unit propagation. Returns possibly conflicting clause. - PropagatedFrom propagateBin(); - PropagatedFrom propagateBinNoLearnts(); - template - PropagatedFrom propagateBinExcept(const Lit& exceptLit); - template - PropagatedFrom propagateBinOneLevel(); - PropagatedFrom propagate_xors (const Lit& p); + void uncheckedEnqueueLight2(const Lit p, const uint32_t binPropDatael, const Lit lev2Ancestor, const bool learntLeadHere); + PropBy propagateBin(vec& uselessBin); + PropBy propagateNonLearntBin(); + bool multiLevelProp; + const bool propagateBinExcept(const Lit exceptLit); + const bool propagateBinOneLevel(); + PropBy propagate(const bool update = true); // Perform unit propagation. Returns possibly conflicting clause. + const bool propTriClause (Watched* &i, Watched* &j, Watched *end, const Lit p, PropBy& confl); + const bool propBinaryClause(Watched* &i, Watched* &j, Watched *end, const Lit p, PropBy& confl); + const bool propNormalClause(Watched* &i, Watched* &j, Watched *end, const Lit p, PropBy& confl, const bool update); + const bool propXorClause (Watched* &i, Watched* &j, Watched *end, const Lit p, PropBy& confl); + void sortWatched(); + + /////////////// + // Conflicting + /////////////// void cancelUntil (int level); // Backtrack until a certain level. - Clause* analyze (PropagatedFrom confl, vec& out_learnt, int& out_btlevel, uint32_t &nblevels, const bool update); // (bt = backtrack) + void cancelUntilLight(); + Clause* analyze (PropBy confl, vec& out_learnt, int& out_btlevel, uint32_t &nblevels, const bool update); void analyzeFinal (Lit p, vec& 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()') - lbool search (int nof_conflicts, int nof_conflicts_fullrestart, const bool update = true); // Search for a given number of conflicts. - void reduceDB (); // Reduce the set of learnt clauses. - llbool handle_conflict (vec& learnt_clause, PropagatedFrom confl, int& conflictC, const bool update);// Handles the conflict clause - llbool new_decision (const int& nof_conflicts, const int& nof_conflicts_fullrestart, int& conflictC); // Handles the case when all propagations have been made, and now a decision must be made + 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& 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: - // - 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 uint size, const Clause* address); - void detachModifiedClause(const Var var1, const Var var2, const uint origSize, const XorClause* address); + ///////////////// + template const bool addClauseHelper(T& ps, const uint32_t group, const char* group_name); + template + Clause* addClauseInt(T& ps, uint32_t group, const bool learnt = false, const uint32_t glue = 10, const float miniSatActivity = 10.0, const bool inOriginalInput = false); + template + XorClause* addXorClauseInt(T& ps, bool xorEqualFalse, const uint32_t group, const bool learnt = false); + 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 - 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. - //void reverse_binary_clause(Clause& c) const; // Binary clauses --- the first Lit has to be true - void testAllClauseAttach() const; - void findAllAttach() const; + 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; const bool findClause(XorClause* c) const; const bool findClause(Clause* c) const; + const bool xorClauseIsAttached(const XorClause& c) const; + 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. - - //Xor-finding related stuff + 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 Logger; friend class XorFinder; friend class Conglomerate; friend class MatrixFinder; @@ -475,7 +494,7 @@ protected: friend class VarReplacer; friend class ClauseCleaner; friend class RestartTypeChooser; - friend class FailedVarSearcher; + friend class FailedLitSearcher; friend class Subsumer; friend class XorSubsumer; friend class PartHandler; @@ -483,40 +502,81 @@ protected: friend class UselessBinRemover; friend class OnlyNonLearntBins; friend class ClauseAllocator; - Conglomerate* conglomerate; - VarReplacer* varReplacer; - ClauseCleaner* clauseCleaner; - FailedVarSearcher* failedVarSearcher; - PartHandler* partHandler; - Subsumer* subsumer; - XorSubsumer* xorSubsumer; + friend class CompleteDetachReatacher; + friend class SCCFinder; + friend class ClauseVivifier; + friend class DataSync; + Conglomerate* conglomerate; + VarReplacer* varReplacer; + ClauseCleaner* clauseCleaner; + FailedLitSearcher* failedLitSearcher; + PartHandler* partHandler; + Subsumer* subsumer; + XorSubsumer* xorSubsumer; RestartTypeChooser* restartTypeChooser; - MatrixFinder* matrixFinder; - const bool chooseRestartType(const uint& lastFullRestart); - void setDefaultRestartType(); - const bool checkFullRestart(int& nof_conflicts, int& nof_conflicts_fullrestart, uint& lastFullRestart); - void performStepsBeforeSolve(); + MatrixFinder* matrixFinder; + SCCFinder* sCCFinder; + ClauseVivifier* clauseVivifier; + + ///////////////////////// + // Restart type handling + ///////////////////////// + const bool chooseRestartType(const uint32_t& lastFullRestart); + void setDefaultRestartType(); + const bool checkFullRestart(uint64_t& nof_conflicts, uint64_t& nof_conflicts_fullrestart, uint32_t& lastFullRestart); + RestartType restartType; ///& cs) const; + const bool verifyXorClauses () const; // Debug & etc: + void printAllClauses(); void printLit (const Lit l) const; - void verifyModel (); - bool verifyClauses (const vec& cs) const; - bool verifyXorClauses (const vec& cs) const; - void checkSolution(); void checkLiteralCount(); void printStatHeader () const; - void printRestartStat (); + void printRestartStat (const char* type = "N"); void printEndSearchStat(); - double progressEstimate () const; // DELETE THIS ?? IT'S NOT VERY USEFUL ... - const bool noLearntBinaries() const; - + void addSymmBreakClauses(); + void initialiseSolver(); + + //Misc related binary clauses + void dumpBinClauses(const bool alsoLearnt, const bool alsoNonLearnt, FILE* outfile) const; + const uint32_t countNumBinClauses(const bool alsoLearnt, const bool alsoNonLearnt) const; + 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 tallyVotes(const vec& cs, vector& votes) const; - void tallyVotes(const vec& cs, vector& votes) const; + void tallyVotesBin(vec& votes) const; + void tallyVotes(const vec& cs, vec& votes) const; + void tallyVotes(const vec& cs, vec& votes) const; + void setPolarity(Var v, bool b); // Declare which polarity the decision heuristic should use for a variable. Requires mode 'polarity_user'. + vector polarity; // The preferred polarity of each variable. + #ifdef USE_OLD_POLARITIES + vector oldPolarity; // The polarity before the last setting. Good for unsetting polairties that have been changed since the last conflict + #endif //USE_OLD_POLARITIES }; @@ -546,7 +606,7 @@ inline void Solver::varBumpActivity(Var v) var_inc >>= 14; //var_inc = 1; //std::cout << "var_inc: " << var_inc << std::endl; - + /*Heap copy_order_heap2(order_heap); while(!copy_order_heap2.empty()) { Var v = copy_order_heap2.getmin(); @@ -562,10 +622,10 @@ inline void Solver::varBumpActivity(Var v) inline void Solver::claBumpActivity (Clause& c) { - if ( (c.oldActivity() += cla_inc) > 1e20 ) { + if ( (c.getMiniSatAct() += cla_inc) > 1e20 ) { // Rescale: for (uint32_t i = 0; i < learnts.size(); i++) - learnts[i]->oldActivity() *= 1e-17; + learnts[i]->getMiniSatAct() *= 1e-17; cla_inc *= 1e-20; } } @@ -575,16 +635,13 @@ inline void Solver::claDecayActivity() //cla_inc *= clause_decay; } -inline bool Solver::enqueue (Lit p, PropagatedFrom from) +inline bool Solver::locked(const Clause& c) const { - return value(p) != l_Undef ? value(p) != l_False : (uncheckedEnqueue(p, from), true); -} -inline bool Solver::locked (const Clause& c) const -{ - if (c.size() == 2) return true; //we don't know in this case :I - PropagatedFrom from(reason[c[0].var()]); - return !from.isBinary() && from.getClause() == &c && value(c[0]) == l_True; + 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()); @@ -601,19 +658,19 @@ inline uint32_t Solver::decisionLevel () const { return trail_lim.size(); } -inline uint32_t Solver::abstractLevel (const Var& x) const +inline uint32_t Solver::abstractLevel (const Var x) const { return 1 << (level[x] & 31); } -inline lbool Solver::value (const Var& x) const +inline lbool Solver::value (const Var x) const { return assigns[x]; } -inline lbool Solver::value (const Lit& p) const +inline lbool Solver::value (const Lit p) const { return assigns[p.var()] ^ p.sign(); } -inline lbool Solver::modelValue (const Lit& p) const +inline lbool Solver::modelValue (const Lit p) const { return model[p.var()] ^ p.sign(); } @@ -623,7 +680,7 @@ inline uint32_t Solver::nAssigns () const } inline uint32_t Solver::nClauses () const { - return clauses.size() + xorclauses.size()+binaryClauses.size(); + return clauses.size() + xorclauses.size(); } inline uint32_t Solver::nLiterals () const { @@ -657,10 +714,6 @@ inline bool Solver::okay () const { return ok; } -inline void Solver::setSeed (const uint32_t seed) -{ - mtrand.seed(seed); // Set seed of the variable-selection and clause-permutation(if applicable) -} #ifdef STATS_NEEDED inline void Solver::needStats() { @@ -672,14 +725,14 @@ inline void Solver::needProofGraph() dynamic_behaviour_analysis = true; // Sets the solver and the logger up to generate proof graphs during solving logger.proof_graph_on = true; } -inline void Solver::setVariableName(Var var, char* name) +inline void Solver::setVariableName(const Var var, const char* name) { while (var >= nVars()) newVar(); if (dynamic_behaviour_analysis) logger.set_variable_name(var, name); } // Sets the varible 'var'-s name to 'name' in the logger #else -inline void Solver::setVariableName(Var var, char* name) +inline void Solver::setVariableName(const Var var, const char* name) {} #endif @@ -705,77 +758,33 @@ inline const uint32_t Solver::get_sum_gauss_prop() const } #endif -inline const uint Solver::get_unitary_learnts_num() const +inline const uint32_t Solver::get_unitary_learnts_num() const { if (decisionLevel() > 0) return trail_lim[0]; else return trail.size(); } -template -inline void Solver::removeWatchedCl(vec &ws, const ClauseOffset c) { - uint32_t j = 0; - for (; j < ws.size() && ws[j].clause != c; j++); - assert(j < ws.size()); - for (; j < ws.size()-1; j++) ws[j] = ws[j+1]; - ws.pop(); -} -template -inline void Solver::removeWatchedBinCl(vec &ws, const Lit impliedLit) { - uint32_t j = 0; - for (; j < ws.size() && ws[j].impliedLit != impliedLit; j++); - assert(j < ws.size()); - for (; j < ws.size()-1; j++) ws[j] = ws[j+1]; - ws.pop(); -} -template -inline void Solver::removeWatchedBinClAll(vec &ws, const Lit impliedLit) { - T *i = ws.getData(); - T *j = i; - for (T* end = ws.getDataEnd(); i != end; i++) { - if (i->impliedLit != impliedLit) - *j++ = *i; - } - ws.shrink(i-j); -} -template -inline bool Solver::findWatchedCl(const vec& ws, const ClauseOffset c) const -{ - uint32_t j = 0; - for (; j < ws.size() && ws[j].clause != c; j++); - return j < ws.size(); -} -template -inline bool Solver::findWatchedBinCl(const vec& ws, const Lit impliedLit) const -{ - uint32_t j = 0; - for (; j < ws.size() && ws[j].impliedLit != impliedLit; j++); - return j < ws.size(); -} -/* -inline void Solver::reverse_binary_clause(Clause& c) const { - if (c.size() == 2 && value(c[0]) == l_False) { - assert(value(c[1]) == l_True); - std::swap(c[0], c[1]); - } -} -*/ +////////////////// +// Xor Clause +////////////////// + /*inline void Solver::calculate_xor_clause(Clause& c2) const { if (c2.isXor() && ((XorClause*)&c2)->updateNeeded()) { XorClause& c = *((XorClause*)&c2); - bool final = c.xor_clause_inverted(); + bool final = c.xorEqualFalse(); for (int k = 0, size = c.size(); k != size; k++ ) { const lbool& val = assigns[c[k].var()]; assert(val != l_Undef); - + c[k] = c[k].unsign() ^ val.getBool(); final ^= val.getBool(); } if (final) c[0] = c[0].unsign() ^ !assigns[c[0].var()].getBool(); - + c.setUpdateNeeded(false); } }*/ @@ -808,19 +817,7 @@ static inline void logLits(FILE* f, const vec& ls) fprintf(f, "] "); } -static inline const char* showBool(bool b) -{ - return b ? "true" : "false"; -} - - -// Just like 'assert()' but expression will be evaluated in the release version as well. -static inline void check(bool expr) -{ - assert(expr); -} - -#ifndef DEBUG_ATTACH +#ifndef DEBUG_ATTACH_FULL inline void Solver::testAllClauseAttach() const { return; @@ -829,16 +826,26 @@ inline void Solver::findAllAttach() const { return; } -#endif //DEBUG_ATTACH +#endif //DEBUG_ATTACH_FULL inline void Solver::uncheckedEnqueueLight(const Lit p) { + assert(assigns[p.var()] == l_Undef); + assigns [p.var()] = boolToLBool(!p.sign());//lbool(!sign(p)); // <<== abstract but not uttermost effecient trail.push(p); } -//================================================================================================= +inline void Solver::uncheckedEnqueueLight2(const Lit p, const uint32_t binSubLevel, const Lit lev2Ancestor, const bool learntLeadHere) +{ + assert(assigns[p.var()] == l_Undef); -}; //NAMESPACE MINISAT + 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()].lev2Ancestor = lev2Ancestor; + binPropData[p.var()].learntLeadHere = learntLeadHere; +} +//================================================================================================= #endif //SOLVER_H diff --git a/src/sat/cryptominisat2/SolverConf.cpp b/src/sat/cryptominisat2/SolverConf.cpp new file mode 100644 index 0000000..b4d7eaf --- /dev/null +++ b/src/sat/cryptominisat2/SolverConf.cpp @@ -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 . +******************************************************************************/ + +#include "SolverConf.h" +#include + +SolverConf::SolverConf() : + random_var_freq(0.02) + , 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) + , doPartHandler (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) + , doMaxGlueDel (false) + , doPrintAvgBranch (false) + , doCacheOTFSSR (true) + , doExtendedSCC (true) + , doCalcReach (true) + + , maxRestarts (std::numeric_limits::max()) + , needToDumpLearnts(false) + , needToDumpOrig (false) + , maxDumpLearntsSize(std::numeric_limits::max()) + , libraryUsage (true) + , greedyUnbound (false) + , maxGlue (DEFAULT_MAX_GLUE) + , fixRestartType (auto_restart) + , origSeed(0) +{ +} diff --git a/src/sat/cryptominisat2/SolverConf.h b/src/sat/cryptominisat2/SolverConf.h new file mode 100644 index 0000000..2abf702 --- /dev/null +++ b/src/sat/cryptominisat2/SolverConf.h @@ -0,0 +1,90 @@ +/***************************************************************************** +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 . +******************************************************************************/ + +#ifndef SOLVERCONF_H +#define SOLVERCONF_H + +#include "SolverTypes.h" +#include "constants.h" + +class SolverConf +{ + public: + SolverConf(); + + double random_var_freq; ///3-long), xor clauses + bool doMinimLearntMore; /// an enhancement of "strong minimization" of PrecoSat + bool doFailedLit; ///. +****************************************************************************/ + +#include "Solver.h" + +#include "VarReplacer.h" + +#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)); + } +} + +const 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; +} + +const 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())); + } + } +} + +const bool Solver::findClause(XorClause* c) const +{ + for (uint32_t i = 0; i < xorclauses.size(); i++) { + if (xorclauses[i] == c) return true; + } + return false; +} + +const bool Solver::findClause(Clause* c) const +{ + for (uint32_t i = 0; i < 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(); +} + +const 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; +} + +const bool Solver::verifyBinClauses() const +{ + uint32_t wsLit = 0; + for (const vec *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec& ws = *it; + + uint32_t i; + for (i = 0; i < ws.size(); i++) { + if (ws[i].isBinary() + && value(lit) != l_True + && value(ws[i].getOtherLit()) != l_True + ) { + std::cout << "bin clause: " << lit << " , " << ws[i].getOtherLit() << " not satisfied!" << std::endl; + std::cout << "value of unsat bin clause: " << value(lit) << " , " << value(ws[i].getOtherLit()) << std::endl; + return false; + } + } + } + + return true; +} + +const bool Solver::verifyClauses(const vec& 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; +} + +const 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 (const vec *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec& ws = *it; + std::cout << "watches[" << lit << "]" << std::endl; + for (const Watched *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; + } + } + } + +} \ No newline at end of file diff --git a/src/sat/cryptominisat2/SolverMisc.cpp b/src/sat/cryptominisat2/SolverMisc.cpp new file mode 100644 index 0000000..e457704 --- /dev/null +++ b/src/sat/cryptominisat2/SolverMisc.cpp @@ -0,0 +1,715 @@ +/*************************************************************************** +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 . +****************************************************************************/ + +#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 +#include + +#ifdef USE_GAUSS +#include "Gaussian.h" +#endif + +#ifndef _MSC_VER +#include +#include +#endif + +static const int space = 10; + +void Solver::dumpSortedLearnts(const std::string& fileName, const uint32_t maxSize) +{ + FILE* outfile = fopen(fileName.c_str(), "w"); + if (!outfile) { + std::cout << "Error: Cannot open file '" << fileName << "' to write learnt clauses!" << std::endl;; + exit(-1); + } + + fprintf(outfile, "c \nc ---------\n"); + fprintf(outfile, "c unitaries\n"); + fprintf(outfile, "c ---------\n"); + for (uint32_t i = 0, end = (trail_lim.size() > 0) ? trail_lim[0] : trail.size() ; i < end; i++) { + trail[i].printFull(outfile); + #ifdef STATS_NEEDED + if (dynamic_behaviour_analysis) + fprintf(outfile, "c name of var: %s\n", logger.get_var_name(trail[i].var()).c_str()); + #endif //STATS_NEEDED + } + + fprintf(outfile, "c conflicts %lu\n", (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& table = varReplacer->getReplaceTable(); + for (Var var = 0; var != table.size(); var++) { + Lit lit = table[var]; + if (lit.var() == var) + continue; + + fprintf(outfile, "%s%d %d 0\n", (!lit.sign() ? "-" : ""), lit.var()+1, var+1); + fprintf(outfile, "%s%d -%d 0\n", (lit.sign() ? "-" : ""), lit.var()+1, var+1); + #ifdef STATS_NEEDED + if (dynamic_behaviour_analysis) + fprintf(outfile, "c name of two vars that are anti/equivalent: '%s' and '%s'\n", logger.get_var_name(lit.var()).c_str(), logger.get_var_name(var).c_str()); + #endif //STATS_NEEDED + } + } + fprintf(outfile, "c \nc --------------------\n"); + fprintf(outfile, "c clauses from learnts\n"); + fprintf(outfile, "c --------------------\n"); + if (lastSelectedRestartType == dynamic_restart) + std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltGlucose()); + else + std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltMiniSat()); + for (int i = learnts.size()-1; i >= 0 ; i--) { + if (learnts[i]->size() <= maxSize) { + learnts[i]->print(outfile); + } + } + + end: + + fclose(outfile); +} + +void Solver::printStrangeBinLit(const Lit lit) const +{ + const vec& ws = watches[(~lit).toInt()]; + for (const Watched *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; + } + } +} + +const uint32_t Solver::countNumBinClauses(const bool alsoLearnt, const bool alsoNonLearnt) const +{ + uint32_t num = 0; + + uint32_t wsLit = 0; + for (const vec *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec& ws = *it; + for (const Watched *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 *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec& ws = *it; + for (const Watched *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); + } + } + } +} + +const uint32_t Solver::getBinWatchSize(const bool alsoLearnt, const Lit lit) +{ + uint32_t num = 0; + const vec& ws = watches[lit.toInt()]; + for (const Watched *it2 = ws.getData(), *end2 = ws.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary() && (alsoLearnt || !it2->getLearnt())) { + num++; + } + } + + return num; +} + +void Solver::dumpOrigClauses(const std::string& fileName) const +{ + FILE* outfile = fopen(fileName.c_str(), "w"); + if (!outfile) { + std::cout << "Error: Cannot open file '" << fileName << "' to write learnt clauses!" << std::endl; + exit(-1); + } + + 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& 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 > >& elimedOutVar = subsumer->getElimedOutVar(); + for (map > >::const_iterator it = elimedOutVar.begin(); it != elimedOutVar.end(); it++) { + const vector >& cs = it->second; + numClauses += cs.size(); + } + const map > >& elimedOutVarBin = subsumer->getElimedOutVarBin(); + for (map > >::const_iterator it = elimedOutVarBin.begin(); it != elimedOutVarBin.end(); it++) { + numClauses += it->second.size()*2; + } + + const map >& xorElimedOutVar = xorSubsumer->getElimedOutVar(); + for (map >::const_iterator it = xorElimedOutVar.begin(); it != xorElimedOutVar.end(); it++) { + const vector& 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); + #ifdef STATS_NEEDED + if (dynamic_behaviour_analysis) + fprintf(outfile, "c name of var: %s\n", logger.get_var_name(trail[i].var()).c_str()); + #endif //STATS_NEEDED + } + + fprintf(outfile, "c \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; + + fprintf(outfile, "%s%d %d 0\n", (!lit.sign() ? "-" : ""), lit.var()+1, var+1); + fprintf(outfile, "%s%d -%d 0\n", (lit.sign() ? "-" : ""), lit.var()+1, var+1); + #ifdef STATS_NEEDED + if (dynamic_behaviour_analysis) + fprintf(outfile, "c name of two vars that are anti/equivalent: '%s' and '%s'\n", logger.get_var_name(lit.var()).c_str(), logger.get_var_name(var).c_str()); + #endif //STATS_NEEDED + } + + fprintf(outfile, "c \nc ------------\n"); + fprintf(outfile, "c 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 > >::const_iterator it = elimedOutVar.begin(); it != elimedOutVar.end(); it++) { + fprintf(outfile, "c ########### cls for eliminated var %d ### start\n", it->first + 1); + const vector >& cs = it->second; + for (vector >::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 > >::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 >::const_iterator it = xorElimedOutVar.begin(); it != xorElimedOutVar.end(); it++) { + for (vector::const_iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { + it2->plainPrint(outfile); + } + } + + fclose(outfile); +} + +const vector Solver::get_unitary_learnts() const +{ + vector unitaries; + if (decisionLevel() > 0) { + for (uint32_t i = 0; i != trail_lim[0]; i++) { + unitaries.push_back(trail[i]); + } + } + + return unitaries; +} + +const vec& Solver::get_learnts() const +{ + return learnts; +} + +const vec& Solver::get_sorted_learnts() +{ + if (lastSelectedRestartType == dynamic_restart) + std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltGlucose()); + else + std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltMiniSat()); + return learnts; +} + +const uint32_t Solver::getNumElimSubsume() const +{ + return subsumer->getNumElimed(); +} + +const uint32_t Solver::getNumElimXorSubsume() const +{ + return xorSubsumer->getNumElimed(); +} + +const uint32_t Solver::getNumXorTrees() const +{ + return varReplacer->getNumTrees(); +} + +const uint32_t Solver::getNumXorTreesCrownSize() const +{ + return varReplacer->getNumReplacedVars(); +} + +const double Solver::getTotalTimeSubsumer() const +{ + return subsumer->getTotalTime(); +} + +const double Solver::getTotalTimeFailedLitSearcher() const +{ + return failedLitSearcher->getTotalTime(); +} + +const double Solver::getTotalTimeXorSubsumer() const +{ + return xorSubsumer->getTotalTime(); +} + +const double Solver::getTotalTimeSCC() const +{ + return sCCFinder->getTotalTime(); +} + +void Solver::printStatHeader() const +{ + #ifdef STATS_NEEDED + if (conf.verbosity >= 2 && !(dynamic_behaviour_analysis && logger.statistics_on)) { + #else + if (conf.verbosity >= 2) { + #endif + 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) << "BinCls" + << std::setw(space) << "Learnts" + << std::setw(space) << "ClLits" + << std::setw(space) << "LtLits" + << 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) << 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() +{ + #ifdef STATS_NEEDED + if (conf.verbosity >= 1 && !(dynamic_behaviour_analysis && logger.statistics_on)) { + #else + if (conf.verbosity >= 1) { + #endif //STATS_NEEDED + 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::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 *i = watches.getData(), *end = watches.getDataEnd(); i != end; i++) { + if (i->size() == 0) continue; + #ifdef VERBOSE_DEBUG + vec& 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 +*/ +void Solver::needLibraryCNFFile(const std::string& fileName) +{ + libraryCNFFile = fopen(fileName.c_str(), "w"); + if (libraryCNFFile == NULL) { + std::cout << "Couldn't open library-call dump file " + << libraryCNFFile << std::endl; + exit(-1); + } +} + +template +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 +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/sat/cryptominisat2/SolverTypes.h b/src/sat/cryptominisat2/SolverTypes.h index 6f38ed5..f7fc751 100644 --- a/src/sat/cryptominisat2/SolverTypes.h +++ b/src/sat/cryptominisat2/SolverTypes.h @@ -1,40 +1,28 @@ -/***********************************************************************************[SolverTypes.h] +/***************************************************************************** MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson +glucose -- Gilles Audemard, Laurent Simon (2008) 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. -**************************************************************************************************/ +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 +#include +#include #ifdef _MSC_VER #include #else #include #endif //_MSC_VER -#include "Alg.h" #include - -namespace MINISAT -{ -using namespace MINISAT; +#include +#include "constants.h" //================================================================================================= // Variables, literals, lifted booleans, clauses: @@ -47,6 +35,9 @@ typedef uint32_t Var; #define 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; @@ -83,12 +74,15 @@ public: 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); + fprintf(outfile,"%s%d ", sign() ? "-" : "", var()+1); } inline void printFull(FILE* outfile = stdout) const { @@ -103,6 +97,36 @@ public: const Lit lit_Undef(var_Undef, false); // Useful special constants. 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& lits) +{ + for (uint32_t i = 0; i < lits.size(); i++) { + cout << lits[i] << " "; + } + return cout; +} + +inline void printClause(FILE* outFile, const std::vector& 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& 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: @@ -157,7 +181,18 @@ 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; @@ -184,6 +219,23 @@ const llbool l_Continue = toLbool(3); lbool::lbool(llbool b) : value(b.value) {}; -}; //NAMESPACE MINISAT +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 lev2Ancestor; + bool learntLeadHere; +}; + #endif //SOLVERTYPES_H diff --git a/src/sat/cryptominisat2/StateSaver.cpp b/src/sat/cryptominisat2/StateSaver.cpp index ceb5eab..22b7cc1 100644 --- a/src/sat/cryptominisat2/StateSaver.cpp +++ b/src/sat/cryptominisat2/StateSaver.cpp @@ -17,10 +17,6 @@ along with this program. If not, see . #include "StateSaver.h" -namespace MINISAT -{ -using namespace MINISAT; - StateSaver::StateSaver(Solver& _solver) : solver(_solver) , backup_order_heap(Solver::VarOrderLt(solver.activity)) @@ -32,8 +28,8 @@ StateSaver::StateSaver(Solver& _solver) : backup_order_heap = solver.order_heap; backup_polarities = solver.polarity; backup_restartType = solver.restartType; - backup_random_var_freq = solver.random_var_freq; backup_propagations = solver.propagations; + backup_random_var_freq = solver.conf.random_var_freq; } void StateSaver::restore() @@ -44,11 +40,9 @@ void StateSaver::restore() solver.order_heap = backup_order_heap; solver.polarity = backup_polarities; solver.restartType = backup_restartType; - solver.random_var_freq = backup_random_var_freq; - + 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)); - solver.propagations = backup_propagations; } - -}; //NAMESPACE MINISAT diff --git a/src/sat/cryptominisat2/StateSaver.h b/src/sat/cryptominisat2/StateSaver.h index 7d1f1c3..120388a 100644 --- a/src/sat/cryptominisat2/StateSaver.h +++ b/src/sat/cryptominisat2/StateSaver.h @@ -20,10 +20,6 @@ along with this program. If not, see . #include "Solver.h" -namespace MINISAT -{ -using namespace MINISAT; - class StateSaver { public: @@ -41,6 +37,4 @@ class StateSaver uint64_t backup_propagations; }; -}; //NAMESPACE MINISAT - #endif //STATESAVER__H diff --git a/src/sat/cryptominisat2/StreamBuffer.h b/src/sat/cryptominisat2/StreamBuffer.h new file mode 100644 index 0000000..1d6298a --- /dev/null +++ b/src/sat/cryptominisat2/StreamBuffer.h @@ -0,0 +1,73 @@ +/******************************************************************************************[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 +#endif // DISABLE_ZLIB + +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/sat/cryptominisat2/Subsumer.cpp b/src/sat/cryptominisat2/Subsumer.cpp index 149e579..d511e7f 100644 --- a/src/sat/cryptominisat2/Subsumer.cpp +++ b/src/sat/cryptominisat2/Subsumer.cpp @@ -1,7 +1,10 @@ -/************************************************************************************************** -Originally From: Solver.C -- (C) Niklas Een, Niklas Sorensson, 2004 -Substantially modified by: Mate Soos (2010) -**************************************************************************************************/ +/***************************************************************************** +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" @@ -13,7 +16,10 @@ Substantially modified by: Mate Soos (2010) #include #include "VarReplacer.h" #include "XorFinder.h" +#include "CompleteDetachReattacher.h" #include "OnlyNonLearntBins.h" +#include "UselessBinRemover.h" +#include "DataSync.h" #ifdef _MSC_VER #define __builtin_prefetch(a,b,c) @@ -32,27 +38,32 @@ using std::cout; using std::endl; #endif //VERBOSE_DEBUG -namespace MINISAT -{ -using namespace MINISAT; - Subsumer::Subsumer(Solver& s): solver(s) , totalTime(0.0) , numElimed(0) - , numCalls(0) + , numCalls(1) + , alsoLearnt(false) { }; -Subsumer::~Subsumer() -{ -} +/** +@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 tmp; - typedef map > elimType; + typedef map > > elimType; for (elimType::iterator it = elimedOutVar.begin(), end = elimedOutVar.end(); it != end; it++) { #ifndef NDEBUG Var var = it->first; @@ -63,134 +74,206 @@ void Subsumer::extendModel(Solver& solver2) assert(solver.assigns[var] == l_Undef); assert(!solver.order_heap.inHeap(var)); #endif - - for (vector::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { - Clause& c = **it2; + + for (vector >::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 > > 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 >::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { tmp.clear(); - tmp.growTo(c.size()); - std::copy(c.getData(), c.getDataEnd(), tmp.getData()); - + tmp.growTo(2); + tmp[0] = it2->first; + tmp[1] = it2->second; + #ifdef VERBOSE_DEBUG - std::cout << "Reinserting Clause: "; - c.plainPrint(); + 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 +*/ const bool Subsumer::unEliminate(const Var var) { assert(var_elimed[var]); vec tmp; - typedef map > elimType; + typedef map > > elimType; + typedef map > > 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()) return solver.ok; - + if (it == elimedOutVar.end() && it2 == elimedOutVarBin.end()) return solver.ok; + FILE* backup_libraryCNFfile = solver.libraryCNFFile; solver.libraryCNFFile = NULL; - for (vector::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { - solver.addClause(**it2); - solver.clauseAllocator.clauseFree(*it2); + + if (it == elimedOutVar.end()) goto next; + for (vector >::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); } - solver.libraryCNFFile = backup_libraryCNFfile; elimedOutVar.erase(it); - + + next: + if (it2 == elimedOutVarBin.end()) goto next2; + for (vector >::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; } -bool selfSubset(uint32_t A, uint32_t B) -{ - uint32_t B_tmp = B | ((B & 0xAAAAAAAALL) >> 1) | ((B & 0x55555555LL) << 1); - if ((A & ~B_tmp) == 0){ - uint32_t C = A & ~B; - return (C & (C-1)) == 0; - }else - return false; -} +/** +@brief Backward-subsumption using given clause: helper function -// Assumes 'seen' is cleared (will leave it cleared) -bool selfSubset(Clause& A, Clause& B, vec& seen) -{ - for (uint32_t i = 0; i < B.size(); i++) - seen[B[i].toInt()] = 1; - - bool flip = false; - for (uint32_t i = 0; i < A.size(); i++) { - if (!seen[A[i].toInt()]) { - if (flip == true || !seen[(~A[i]).toInt()]) { - for (uint32_t i = 0; i < B.size(); i++) seen[B[i].toInt()] = 0; - return false; - } - flip = true; - } - } - for (uint32_t i = 0; i < B.size(); i++) - seen[B[i].toInt()] = 0; - return flip; -} +Checks all clauses in the occurrence lists if they are subsumed by ps or not. -template <> -inline uint32_t Subsumer::subsume0(Clause& ps, uint32_t abs) +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) { - ps.subsume0Finished(); - ps.unsetVarChanged(); #ifdef VERBOSE_DEBUG - cout << "subsume0 orig clause: "; + cout << "subsume0-ing with clause: "; ps.plainPrint(); #endif - return subsume0Orig(ps, abs); + 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(); + } + } } -template -inline uint32_t Subsumer::subsume0(T& ps, uint32_t abs) -{ - #ifdef VERBOSE_DEBUG - cout << "subsume0 orig vec: "; - ps[0].print(); std::cout << " "; - ps[1].printFull(); - #endif - return subsume0Orig(ps, abs); -} +/** +@brief Backward-subsumption using given clause -// Will put NULL in 'cs' if clause removed. +@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 -uint32_t Subsumer::subsume0Orig(const T& ps, uint32_t abs) +Subsumer::subsume0Happened Subsumer::subsume0Orig(const T& ps, uint32_t abs) { - subsumedNonLearnt = false; - uint32_t retIndex = std::numeric_limits::max(); + subsume0Happened ret; + ret.subsumedNonLearnt = false; + ret.glue = std::numeric_limits::max(); + ret.act = std::numeric_limits< float >::min(); + vec subs; findSubsumed(ps, abs, subs); for (uint32_t i = 0; i < subs.size(); i++){ - clauses_subsumed++; #ifdef VERBOSE_DEBUG cout << "-> subsume0 removing:"; subs[i].clause->plainPrint(); #endif - + Clause* tmp = subs[i].clause; - subsumedNonLearnt |= !tmp->learnt(); - retIndex = subs[i].index; + 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]); - solver.clauseAllocator.clauseFree(tmp); } - - return retIndex; -} -void Subsumer::subsume0BIN(const Lit lit1, const vec& lits) + return ret; +} +/** +@brief Backward-subsumption&self-subsuming resolution for binary clause sets + +Takes in a set of binary clauses: +lit1 OR lits[0] +lit1 OR lits[1] +... +and backward-subsumes clauses in the occurence lists with it, as well as +performing self-subsuming resolution using these binary clauses on clauses in +the occurrence lists. + +@param[in] lit1 As defined above +@param[in] lits The abstraction of the clause +*/ +void Subsumer::subsume0BIN(const Lit lit1, const vec& lits, const uint32_t abst) { vec subs; vec subs2; @@ -198,590 +281,537 @@ void Subsumer::subsume0BIN(const Lit lit1, const vec& lits) vec& 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, 0, 1); + if (it+1 != end) __builtin_prefetch((it+1)->clause, 0, 1); 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 (!removed) { - for (uint32_t i = 0; i < c.size(); i++) { - if (lits[(~c[i]).toInt()]) { - subs2.push(*it); - subs2Lit.push(c[i]); - 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++){ - clauses_subsumed++; - #ifdef VERBOSE_DEBUG - cout << "-> subsume0 removing:"; - subs[i].clause->plainPrint(); - #endif - - Clause* tmp = subs[i].clause; unlinkClause(subs[i]); - solver.clauseAllocator.clauseFree(tmp); } - if (subs2.size() == 0) return; - registerIteration(subs2); - for (uint32_t j = 0; j < subs2.size(); j++){ - if (subs2[j].clause == NULL) continue; - ClauseSimp c = subs2[j]; - Clause& cl = *c.clause; - #ifdef VERBOSE_DEBUG - cout << "-> Strenghtening clause :"; - cl.plainPrint(); - #endif - unlinkClause(c); + for (uint32_t i = 0; i < subs2.size(); i++) { + strenghten(subs2[i], subs2Lit[i]); + if (!solver.ok) break; + } - literals_removed++; - cl.strengthen(subs2Lit[j]); - Lit *a, *b, *end; - for (a = b = cl.getData(), end = a + cl.size(); a != end; a++) { - lbool val = solver.value(*a); - if (val == l_Undef) - *b++ = *a; + #ifdef VERBOSE_DEBUG + if (!solver.ok) { + std::cout << "solver.ok is false when returning from subsume0BIN()" << std::endl; + } + #endif //VERBOSE_DEBUG +} +/** +@brief Backward subsumption and self-subsuming resolution - if (val == l_True) { - #ifdef VERBOSE_DEBUG - std::cout << "--> Clause was satisfied." << std::endl; - #endif - solver.clauseAllocator.clauseFree(&cl); - goto endS; - } - } - cl.shrink(a-b); - cl.setStrenghtened(); +Performs backward subsumption AND +self-subsuming resolution using backward-subsumption - #ifdef VERBOSE_DEBUG - cout << "--> Strenghtened clause:"; - cl.plainPrint(); - #endif +@param[in] ps The clause to use for backw-subsumption and self-subs. resolution +*/ +void Subsumer::subsume1(Clause& ps) +{ + vec subs; + vec subsLits; + #ifdef VERBOSE_DEBUG + cout << "subsume1-ing with clause:"; + ps.plainPrint(); + #endif - if (cl.size() == 0) { - solver.ok = false; - unregisterIteration(subs2); - solver.clauseAllocator.clauseFree(&cl); - return; + 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; } - if (cl.size() > 2) { - cl.calcAbstractionClause(); - linkInAlreadyClause(c); - clauses[c.index] = c; - solver.attachClause(cl); - updateClause(c); - } else if (cl.size() == 2) { - cl.calcAbstractionClause(); - solver.attachClause(cl); - solver.becameBinary++; - addBinaryClauses.push(&cl); - //updateClause(c); + } +} + +const bool Subsumer::subsume1(vec& ps, const bool wasLearnt) +{ + vec subs; + vec 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 { - assert(cl.size() == 1); - solver.uncheckedEnqueue(cl[0]); - solver.ok = (solver.propagate().isNULL()); - if (!solver.ok) { - unregisterIteration(subs2); - return; - } - #ifdef VERBOSE_DEBUG - cout << "--> Found that var " << cl[0].var()+1 << " must be " << std::boolalpha << !cl[0].sign() << endl; - #endif - solver.clauseAllocator.clauseFree(&cl); + strenghten(c, subsLits[j]); + if (!solver.ok) return false; } - endS:; } - unregisterIteration(subs2); + + return toMakeNonLearnt; } -void Subsumer::unlinkClause(ClauseSimp c, Var elim) +/** +@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; - - if (elim != var_Undef) { - assert(!cl.learnt()); - #ifdef VERBOSE_DEBUG - std::cout << "Eliminating clause: "; c.clause->plainPrint(); - std::cout << "On variable: " << elim+1 << std::endl; - #endif //VERBOSE_DEBUG - elimedOutVar[elim].push_back(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); #ifndef TOUCH_LESS - touch(cl[i]); + touch(cl[i], cl.learnt()); #endif } - - solver.detachClause(cl); - + // Remove from iterator vectors/sets: - for (uint32_t i = 0; i < iter_vecs.size(); i++) { - vec& cs = *iter_vecs[i]; - for (uint32_t j = 0; j < cs.size(); j++) - if (cs[j].clause == &cl) - cs[j].clause = NULL; - } 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); - cl_added.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 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; } -void Subsumer::unlinkModifiedClause(vec& origClause, ClauseSimp c, bool detachAndNull) + +/** +@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 +*/ +const bool Subsumer::cleanClause(Clause& ps) { - for (uint32_t i = 0; i < origClause.size(); i++) { - maybeRemove(occur[origClause[i].toInt()], c.clause); - #ifndef TOUCH_LESS - touch(origClause[i]); - #endif - } - - // Remove from iterator vectors/sets: - for (uint32_t i = 0; i < iter_vecs.size(); i++){ - vec& cs = *iter_vecs[i]; - for (uint32_t j = 0; j < cs.size(); j++) - if (cs[j].clause == c.clause) - cs[j].clause = NULL; - } - 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); - cl_added.exclude(c); + bool retval = false; - if (detachAndNull) { - solver.detachModifiedClause(origClause[0], origClause[1], origClause.size(), c.clause); - clauses[c.index].clause = NULL; + 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; + #ifndef TOUCH_LESS + touch(*i, ps.learnt()); + #endif + continue; + } + if (val == l_True) { + *j++ = *i; + retval = true; + continue; + } + assert(false); } + ps.shrink(i-j); + + return retval; } -void Subsumer::subsume1(ClauseSimp& ps) +const bool Subsumer::cleanClause(vec& ps) const { - vec Q; - vec subs; - vec qs; - uint32_t q; - - ps.clause->unsetStrenghtened(); - registerIteration(Q); - registerIteration(subs); - - Q.push(ps); - q = 0; - while (q < Q.size()){ - if (Q[q].clause == NULL) { q++; continue; } - #ifdef VERBOSE_DEBUG - cout << "subsume1 with clause:"; - Q[q].clause->plainPrint(); - #endif - - qs.clear(); - for (uint32_t i = 0; i < Q[q].clause->size(); i++) - qs.push((*Q[q].clause)[i]); - - for (uint32_t i = 0; i < qs.size(); i++){ - qs[i] = ~qs[i]; - - uint32_t abst = calcAbstraction(qs); - - findSubsumed(qs, abst, subs); - for (uint32_t j = 0; j < subs.size(); j++){ - /*#ifndef NDEBUG - if (&counter != NULL && counter == -1){ - dump(*subs[j].clause); - qs[i] = ~qs[i]; - dump(qs); - printf(L_LIT"\n", L_lit(qs[i])); - exit(0); - } - #endif*/ - if (subs[j].clause == NULL) continue; - ClauseSimp c = subs[j]; - Clause& cl = *c.clause; - #ifdef VERBOSE_DEBUG - cout << "-> Strenghtening clause :"; - cl.plainPrint(); - #endif - unlinkClause(c); - - literals_removed++; - cl.strengthen(qs[i]); - Lit *a, *b, *end; - for (a = b = cl.getData(), end = a + cl.size(); a != end; a++) { - lbool val = solver.value(*a); - if (val == l_Undef) - *b++ = *a; - - if (val == l_True) { - #ifdef VERBOSE_DEBUG - std::cout << "--> Clause was satisfied." << std::endl; - #endif - solver.clauseAllocator.clauseFree(&cl); - goto endS; - } - } - cl.shrink(a-b); - cl.setStrenghtened(); - - #ifdef VERBOSE_DEBUG - cout << "--> Strenghtened clause:"; - cl.plainPrint(); - #endif - - if (cl.size() == 0) { - solver.ok = false; - unregisterIteration(Q); - unregisterIteration(subs); - solver.clauseAllocator.clauseFree(&cl); - return; - } - if (cl.size() > 1) { - cl.calcAbstractionClause(); - linkInAlreadyClause(c); - clauses[c.index] = c; - solver.attachClause(cl); - if (cl.size() == 2) solver.becameBinary++; - updateClause(c); - Q.push(c); - } else { - assert(cl.size() == 1); - solver.uncheckedEnqueue(cl[0]); - solver.ok = (solver.propagate().isNULL()); - if (!solver.ok) { - unregisterIteration(Q); - unregisterIteration(subs); - return; - } - #ifdef VERBOSE_DEBUG - cout << "--> Found that var " << cl[0].var()+1 << " must be " << std::boolalpha << !cl[0].sign() << endl; - #endif - solver.clauseAllocator.clauseFree(&cl); - } - endS:; - } - - qs[i] = ~qs[i]; - subs.clear(); + 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; } - q++; + assert(false); } - - unregisterIteration(Q); - unregisterIteration(subs); + ps.shrink(i-j); + + return retval; } -template -void Subsumer::subsume1Partial(const T& ps) +/** +@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) { - assert(solver.decisionLevel() == 0); - registerIteration(subsume1PartialSubs); - #ifdef VERBOSE_DEBUG - cout << "-> Strenghtening using clause :"; - ps[0].print(); std::cout << " "; - ps[1].printFull(); + cout << "-> Strenghtening clause :"; + c.clause->plainPrint(); + cout << " with lit: " << toRemoveLit << std::endl; #endif - assert(ps.size() == 2); - subsume1PartialQs.clear(); - for (uint8_t i = 0; i < 2; i++) - subsume1PartialQs.push(ps[i]); - - for (uint8_t i = 0; i < 2; i++){ - subsume1PartialQs[i] = ~subsume1PartialQs[i]; - - uint32_t abst = calcAbstraction(subsume1PartialQs); - - findSubsumed(subsume1PartialQs, abst, subsume1PartialSubs); - for (uint32_t j = 0; j < subsume1PartialSubs.size(); j++){ - if (subsume1PartialSubs[j].clause == NULL) continue; - ClauseSimp c = subsume1PartialSubs[j]; - Clause& cl = *c.clause; - #ifdef VERBOSE_DEBUG - cout << "-> Strenghtening clause :"; - cl.plainPrint(); - #endif - unlinkClause(subsume1PartialSubs[j]); - - literals_removed++; - cl.strengthen(subsume1PartialQs[i]); - Lit *a, *b, *end; - for (a = b = cl.getData(), end = a + cl.size(); a != end; a++) { - lbool val = solver.value(*a); - if (val == l_Undef) - *b++ = *a; - - if (val == l_True) { - #ifdef VERBOSE_DEBUG - std::cout << "--> Clause was satisfied." << std::endl; - #endif - solver.clauseAllocator.clauseFree(&cl); - goto endS; - } - } - cl.shrink(a-b); - cl.setStrenghtened(); + literals_removed++; + c.clause->strengthen(toRemoveLit); + removeW(occur[toRemoveLit.toInt()], c.clause); + numMaxSubsume1 -= occur[toRemoveLit.toInt()].size()/2; + #ifndef TOUCH_LESS + touch(toRemoveLit, c.clause->learnt()); + #endif + if (cleanClause(*c.clause)) { + unlinkClause(c); + c.clause = NULL; + return; + } + switch (c.clause->size()) { + case 0: #ifdef VERBOSE_DEBUG - cout << "--> Strenghtened clause:"; - cl.plainPrint(); - #endif + 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); + } +} - if (cl.size() == 0) { - solver.ok = false; - unregisterIteration(subsume1PartialSubs); - solver.clauseAllocator.clauseFree(&cl); - return; - } - if (cl.size() > 2) { - cl.calcAbstractionClause(); - linkInAlreadyClause(c); - clauses[c.index] = c; - solver.attachClause(cl); - updateClause(c); - } else if (cl.size() == 2) { - cl.calcAbstractionClause(); - solver.attachClause(cl); - solver.becameBinary++; - addBinaryClauses.push(&cl); - //updateClause(c); - } else { - assert(cl.size() == 1); - solver.uncheckedEnqueue(cl[0]); - solver.ok = (solver.propagate().isNULL()); - if (!solver.ok) { - unregisterIteration(subsume1PartialSubs); - return; - } - #ifdef VERBOSE_DEBUG - cout << "--> Found that var " << cl[0].var()+1 << " must be " << std::boolalpha << !cl[0].sign() << endl; - #endif - solver.clauseAllocator.clauseFree(&cl); +const 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 lits(2); + for (list::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); } - endS:; } + if (!solver.ok) return false; + clBinSize++; + } + clBinTouched.clear(); - subsume1PartialQs[i] = ~subsume1PartialQs[i]; - subsume1PartialSubs.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; } - unregisterIteration(subsume1PartialSubs); + + return true; } -void Subsumer::updateClause(ClauseSimp c) +/** +@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) { - subsume0(*c.clause, c.clause->getAbst()); - if (c.clause->learnt() && subsumedNonLearnt) - c.clause->makeNonLearnt(); - - cl_touched.add(c); + if (solver.value(lit) == l_False) { + solver.ok = false; + } else if (solver.value(lit) == l_Undef) { + solver.uncheckedEnqueue(lit); + solver.ok = solver.propagate().isNULL(); + } else { + assert(solver.value(lit) == l_True); + } } -void Subsumer::almost_all_database() +/** +@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. +*/ +const bool Subsumer::subsume0AndSubsume1() { + CSet s0, s1; + + //uint32_t clTouchedTodo = cl_touched.nElems(); + uint32_t clTouchedTodo = 100000; + if (addedClauseLits > 1500000) clTouchedTodo /= 2; + if (addedClauseLits > 3000000) clTouchedTodo /= 2; + if (addedClauseLits > 10000000) clTouchedTodo /= 2; + if (alsoLearnt) { + clTouchedTodo /= 2; + /*clTouchedTodo = std::max(clTouchedTodo, (uint32_t)20000); + clTouchedTodo = std::min(clTouchedTodo, (uint32_t)5000);*/ + } else { + /*clTouchedTodo = std::max(clTouchedTodo, (uint32_t)20000); + clTouchedTodo = std::min(clTouchedTodo, (uint32_t)5000);*/ + } + + if (!solver.conf.doSubsume1) clTouchedTodo = 0; + + registerIteration(s0); + registerIteration(s1); + vec remClTouched; + + // Fixed-point for 1-subsumption: #ifdef BIT_MORE_VERBOSITY - std::cout << "c Larger database" << std::endl; + std::cout << "c cl_touched.nElems() = " << cl_touched.nElems() << std::endl; #endif - // Optimized variant when virtually whole database is involved: - cl_added .clear(); - cl_touched.clear(); - - for (uint32_t i = 0; i < clauses.size(); i++) { - if (numMaxSubsume1 == 0) break; - if (clauses[i].clause != NULL) { - subsume1(clauses[i]); - numMaxSubsume1--; - if (!solver.ok) return; - } - } - - assert(solver.ok); - solver.ok = (solver.propagate().isNULL()); - if (!solver.ok) { - return; - } - solver.clauseCleaner->cleanClausesBewareNULL(clauses, ClauseCleaner::simpClauses, *this); - - #ifdef VERBOSE_DEBUG - cout << "subsume1 part 1 finished" << endl; - #endif - - CSet s1; - registerIteration(s1); - while (cl_touched.size() > 0 && numMaxSubsume1 > 0){ + do { #ifdef VERBOSE_DEBUG - std::cout << "c cl_touched was > 0, new iteration" << std::endl; - #endif + 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; + vec setNeg; for (CSet::iterator it = cl_touched.begin(), end = cl_touched.end(); it != end; ++it) { - if (it->clause != NULL) - s1.add(*it); - } - cl_touched.clear(); - - for (CSet::iterator it = s1.begin(), end = s1.end(); it != end; ++it) { - if (numMaxSubsume1 == 0) break; - if (it->clause != NULL) { - subsume1(*it); - numMaxSubsume1--; - if (!solver.ok) return; + + if (it->clause == NULL) continue; + Clause& cl = *it->clause; + + bool tooMuch = s1Added >= clTouchedTodo; + if (numMaxSubsume1 <= 0) tooMuch = false; + bool addedAnyway = true; + + uint32_t smallestPosSize = std::numeric_limits::max(); + Lit smallestPos = lit_Undef; + + if (!tooMuch) s1Added += s1.add(*it); + else if (!s1.alreadyIn(*it)) addedAnyway = false; + s0.add(*it); + + for (uint32_t j = 0; j < cl.size() && addedAnyway; j++) { + if (ol_seenPos[cl[j].toInt()] || smallestPos == lit_Error) { + smallestPos = lit_Error; + goto next; + } + if (occur[cl[j].toInt()].size() < smallestPosSize) { + smallestPos = cl[j]; + smallestPosSize = occur[cl[j].toInt()].size(); + } + + next: + if (ol_seenNeg[(~cl[j]).toInt()]) continue; + vec& n_occs = occur[(~cl[j]).toInt()]; + for (uint32_t k = 0; k < n_occs.size(); k++) { + if (tooMuch && !s1.alreadyIn(n_occs[k])) { + addedAnyway = false; + goto next2; + } + s1Added += s1.add(n_occs[k]); + } + ol_seenNeg[(~cl[j]).toInt()] = 1; + setNeg.push(~cl[j]); } + next2:; + + if (smallestPos != lit_Undef && smallestPos != lit_Error && addedAnyway) { + vec& p_occs = occur[smallestPos.toInt()]; + for (uint32_t k = 0; k < p_occs.size(); k++) { + if (tooMuch && !s0.alreadyIn(p_occs[k])) { + addedAnyway = false; + goto next3; + } + s0.add(p_occs[k]); + } + ol_seenPos[smallestPos.toInt()] = 1; + } + + next3: + if (addedAnyway) remClTouched.push(*it); } - s1.clear(); - - if (!solver.ok) return; - solver.ok = (solver.propagate().isNULL()); - if (!solver.ok) { - unregisterIteration(s1); - return; - } - solver.clauseCleaner->cleanClausesBewareNULL(clauses, ClauseCleaner::simpClauses, *this); - } - unregisterIteration(s1); -} + //std::cout << "s0.nElems(): " << s0.nElems() << std::endl; + //std::cout << "s1.nElems(): " << s1.nElems() << std::endl; -void Subsumer::smaller_database() -{ - #ifdef BIT_MORE_VERBOSITY - std::cout << "c Smaller database" << std::endl; - #endif - // Set used in 1-subs: - // (1) clauses containing a negated literal of an added clause. - // (2) all added or strengthened ("touched") clauses. - // - // Set used in 0-subs: - // (1) clauses containing a (non-negated) literal of an added clause, including the added clause itself. - // (2) all strenghtened clauses -- REMOVED!! We turned on eager backward subsumption which supersedes this. - - #ifdef BIT_MORE_VERBOSITY - printf(" PREPARING\n"); - #endif - - CSet s0, s1; // 's0' is used for 0-subsumption, 's1' for 1-subsumption - vec ol_seen(solver.nVars()*2, 0); - for (CSet::iterator it = cl_added.begin(), end = cl_added.end(); it != end; ++it) { - if (it->clause == NULL) continue; - ClauseSimp& c = *it; - Clause& cl = *it->clause; - - s1.add(c); - for (uint32_t j = 0; j < cl.size(); j++){ - if (ol_seen[cl[j].toInt()]) continue; - ol_seen[cl[j].toInt()] = 1; - - vec& n_occs = occur[(~cl[j]).toInt()]; - for (uint32_t k = 0; k < n_occs.size(); k++) - if (n_occs[k].clause != c.clause && n_occs[k].clause->size() <= cl.size() && selfSubset(n_occs[k].clause->getAbst(), c.clause->getAbst()) && selfSubset(*n_occs[k].clause, cl, seen_tmp)) - s1.add(n_occs[k]); - - vec& p_occs = occur[cl[j].toInt()]; - for (uint32_t k = 0; k < p_occs.size(); k++) - if (subsetAbst(p_occs[k].clause->getAbst(), c.clause->getAbst())) - s0.add(p_occs[k]); + + bool doneAll = (numMaxSubsume1 > 0); + for (CSet::iterator it = s0.begin(), end = s0.end(); it != end; ++it) { + if (it->clause == NULL) continue; + subsume0(*it->clause); + if (!doneAll && numMaxSubsume0 < 0) break; } - } - cl_added.clear(); - - registerIteration(s0); - registerIteration(s1); - - #ifdef BIT_MORE_VERBOSITY - printf("c FIXED-POINT\n"); - #endif - - // Fixed-point for 1-subsumption: - while (s1.size() > 0 || cl_touched.size() > 0){ - for (CSet::iterator it = cl_touched.begin(), end = cl_touched.end(); it != end; ++it) { - if (it->clause != NULL) { - s1.add(*it); - s0.add(*it); + s0.clear(); + + if (doneAll) { + for (CSet::iterator it = s1.begin(), end = s1.end(); it != end; ++it) { + if (it->clause == NULL) continue; + subsume1(*it->clause); + /*if (numMaxSubsume1 < 0) { + doneAll = false; + break; + }*/ + //s0.exclude(*it); + if (!solver.ok) goto end; } + s1.clear(); } - - cl_touched.clear(); - assert(solver.qhead == solver.trail.size()); - - #ifdef BIT_MORE_VERBOSITY - printf("c s1.size()=%d cl_touched.size()=%d\n", s1.size(), cl_touched.size()); - #endif - - for (CSet::iterator it = s1.begin(), end = s1.end(); it != end; ++it) { - if (numMaxSubsume1 == 0) break; - if (it->clause != NULL) { - subsume1(*it); - numMaxSubsume1--; - if (!solver.ok) return; - } + + if (!handleClBinTouched()) goto end; + for (ClauseSimp *it = remClTouched.getData(), *end = remClTouched.getDataEnd(); it != end; it++) { + if (it->clause == NULL) continue; + if (doneAll) it->clause->unsetStrenghtened(); + cl_touched.exclude(*it); } - s1.clear(); - - if (!solver.ok) return; - solver.ok = (solver.propagate().isNULL()); - if (!solver.ok){ - unregisterIteration(s1); - unregisterIteration(s0); - return; + if (!doneAll) { + for (Lit *l = setNeg.getData(), *end = setNeg.getDataEnd(); l != end; l++) + ol_seenNeg[l->toInt()] = 0; } - solver.clauseCleaner->cleanClausesBewareNULL(clauses, ClauseCleaner::simpClauses, *this); - } + + #ifdef BIT_MORE_VERBOSITY + if (doneAll) + std::cout << "c Success with " << remClTouched.size() << " clauses, s1Added: " << s1Added << std::endl; + else + std::cout << "c No success with " << remClTouched.size() << " clauses, s1Added: " << s1Added << std::endl; + #endif //BIT_MORE_VERBOSITY + remClTouched.clear(); + } while ((cl_touched.nElems() > 100) && numMaxSubsume0 > 0); + + end: + cl_touched.clear(); unregisterIteration(s1); - - // Iteration pass for 0-subsumption: - for (CSet::iterator it = s0.begin(), end = s0.end(); it != end; ++it) { - if (it->clause != NULL) { - subsume0(*it->clause, it->clause->getAbst()); - if (subsumedNonLearnt && it->clause->learnt()) it->clause->makeNonLearnt(); - } - } - s0.clear(); 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); - touch(cl[i].var()); + touch(cl[i], cl.learnt()); } - cl_added.add(c); - + cl_touched.add(c); + return c; } -void Subsumer::linkInAlreadyClause(ClauseSimp& c) -{ - Clause& cl = *c.clause; - for (uint32_t i = 0; i < cl.size(); i++) { - occur[cl[i].toInt()].push(c); - touch(cl[i].var()); - } -} +/** +@brief Adds clauses from the solver to here, and removes them from the solver -template -void Subsumer::addFromSolver(vec& cs, bool alsoLearnt) +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. +*/ +const uint64_t Subsumer::addFromSolver(vec& cs) { + uint64_t numLitsAdded = 0; Clause **i = cs.getData(); Clause **j = i; for (Clause **end = i + cs.size(); i != end; i++) { @@ -790,14 +820,6 @@ void Subsumer::addFromSolver(vec& cs, bool alsoLearnt) if (!alsoLearnt && (*i)->learnt()) { *j++ = *i; - (*i)->setUnsorted(); - continue; - } - - if (!UseCL && (*i)->size() == 2) { - //don't add binary clauses in this case - *j++ = *i; - (*i)->setUnsorted(); continue; } @@ -806,19 +828,20 @@ void Subsumer::addFromSolver(vec& cs, bool alsoLearnt) Clause& cl = *c.clause; for (uint32_t i = 0; i < cl.size(); i++) { occur[cl[i].toInt()].push(c); - touch(cl[i].var()); - } - if (UseCL) { - if (fullSubsume || cl.getVarChanged()) cl_added.add(c); - else if (cl.getStrenghtened()) cl_touched.add(c); + //if (cl.getStrenghtened()) touch(cl[i], cl.learnt()); } + numLitsAdded += cl.size(); - if (!cl.learnt() && (cl.getVarChanged() || cl.getStrenghtened())) - cl.calcAbstractionClause(); + if (cl.getStrenghtened()) cl_touched.add(c); } 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++) { @@ -826,45 +849,29 @@ void Subsumer::freeMemory() } } +/** +@brief Adds clauses from here, back to the solver +*/ void Subsumer::addBackToSolver() { - #ifdef HYPER_DEBUG2 - uint32_t binaryLearntAdded = 0; - #endif - assert(solver.clauses.size() == 0); for (uint32_t i = 0; i < clauses.size(); i++) { - if (clauses[i].clause != NULL) { - assert(clauses[i].clause->size() > 1); - if (clauses[i].clause->size() == 2) { - #ifdef HYPER_DEBUG2 - if (clauses[i].clause->learnt()) - binaryLearntAdded++; - #endif - Clause* c = clauses[i].clause; - if (!c->wasBin()) { - solver.detachClause(*c); - Clause *c2 = solver.clauseAllocator.Clause_new(*c); - solver.clauseAllocator.clauseFree(c); - solver.attachClause(*c2); - solver.becameBinary++; - c = c2; - } - solver.binaryClauses.push(c); - } else { - if (clauses[i].clause->learnt()) - solver.learnts.push(clauses[i].clause); - else - solver.clauses.push(clauses[i].clause); - } - } + 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); } - - #ifdef HYPER_DEBUG2 - std::cout << "Binary learnt added:" << binaryLearntAdded << std::endl; - #endif } +/** +@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& cs) { Clause **i = cs.getData(); @@ -879,7 +886,7 @@ void Subsumer::removeWrong(vec& cs) for (Lit *l = c.getData(), *end2 = l+c.size(); l != end2; l++) { if (var_elimed[l->var()]) { remove = true; - solver.detachClause(c); + //solver.detachClause(c); solver.clauseAllocator.clauseFree(&c); break; } @@ -890,6 +897,44 @@ void Subsumer::removeWrong(vec& cs) cs.shrink(i-j); } +void Subsumer::removeWrongBinsAndAllTris() +{ + uint32_t numRemovedHalfLearnt = 0; + uint32_t wsLit = 0; + for (vec *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + vec& ws = *it; + + Watched* i = ws.getData(); + Watched* j = i; + for (Watched *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); @@ -898,14 +943,11 @@ void Subsumer::fillCannotEliminate() for (uint32_t i2 = 0; i2 < c.size(); i2++) cannot_eliminate[c[i2].var()] = true; } - - const vec& tmp = solver.varReplacer->getClauses(); - for (uint32_t i = 0; i < tmp.size(); i++) { - const Clause& c = *tmp[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++) @@ -915,975 +957,1254 @@ void Subsumer::fillCannotEliminate() #endif } -const bool Subsumer::subsumeWithBinaries(OnlyNonLearntBins* onlyNonLearntBins) -{ - clearAll(); - clauseID = 0; - fullSubsume = true; - addBinaryClauses.clear(); +/** +@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(). +*/ +const bool Subsumer::subsumeWithBinaries() +{ //Clearing stats - subsNonExistentumFailed = 0; + double myTime = cpuTime(); clauses_subsumed = 0; literals_removed = 0; - double myTime = cpuTime(); uint32_t origTrailSize = solver.trail.size(); - clauses.reserve(solver.clauses.size()); - solver.clauseCleaner->cleanClauses(solver.clauses, ClauseCleaner::clauses); - addFromSolver(solver.clauses); - #ifdef DEBUG_BINARIES - for (uint32_t i = 0; i < clauses.size(); i++) { - assert(clauses[i].clause->size() != 2); - } - #endif //DEBUG_BINARIES - - numMaxSubsume0 = 300000 * (1+numCalls/2); - numMaxSubsume1 = 10000 * (1+numCalls); - - for (uint32_t i = 0; i < solver.binaryClauses.size(); i++) { - if (!solver.binaryClauses[i]->learnt() && numMaxSubsume0 > 0) { - Clause& c = *solver.binaryClauses[i]; - subsume0(c, c.getAbst()); - numMaxSubsume0--; - } - } - for (uint32_t i = 0; i < solver.binaryClauses.size(); i++) { - if (numMaxSubsume1 > 0) { - Clause& c = *solver.binaryClauses[i]; - subsume1Partial(c); - if (!solver.ok) return false; - numMaxSubsume1--; + vec lits(2); + uint32_t counter = 0; + uint32_t thisRand = solver.mtrand.randInt(); + for (const vec *it = solver.watches.getData(); counter != solver.nVars()*2; counter++) { + uint32_t wsLit = (counter + thisRand) % (solver.nVars()*2); + Lit lit = ~Lit::toLit(wsLit); + lits[0] = lit; + const vec ws_backup = *(it + wsLit); + for (const Watched *it2 = ws_backup.getData(), *end2 = ws_backup.getDataEnd(); it2 != end2; it2++) { + if (it2->isBinary() && lit.toInt() < it2->getOtherLit().toInt()) { + lits[1] = it2->getOtherLit(); + bool toMakeNonLearnt = subsume1(lits, it2->getLearnt()); + if (toMakeNonLearnt) makeNonLearntBin(lit, it2->getOtherLit(), it2->getLearnt()); + if (!solver.ok) return false; + } } + if (numMaxSubsume1 < 0) break; } - if (solver.verbosity >= 1) { + + if (solver.conf.verbosity >= 1) { std::cout << "c subs with bin: " << std::setw(8) << clauses_subsumed << " lits-rem: " << std::setw(9) << literals_removed << " v-fix: " << std::setw(4) <size() != 2); + return true; +} + +const bool Subsumer::subsWNonExitsBinsFullFull() +{ + double myTime = cpuTime(); + clauses_subsumed = 0; + literals_removed = 0; + for (vec *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++) { + if (it->size() < 2) continue; + std::sort(it->getData(), it->getDataEnd(), BinSorter2()); } - #endif //DEBUG_BINARIES - addBackToSolver(); - for (uint32_t i = 0; i < addBinaryClauses.size(); i++) { - Clause& c = *addBinaryClauses[i]; - solver.detachClause(c); - Clause *c2 = solver.clauseAllocator.Clause_new(c); - solver.clauseAllocator.clauseFree(&c); - solver.attachClause(*c2); - solver.becameBinary++; - solver.binaryClauses.push(c2); - } - addBinaryClauses.clear(); - freeMemory(); - - if (solver.verbosity >= 1) { - std::cout << "c Subs w/ non-existent bins: " << std::setw(6) << subsNonExistentNum - << " l-rem: " << std::setw(6) << subsNonExistentLitsRemoved - << " v-fix: " << std::setw(5) << subsNonExistentumFailed + + 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) << subsNonExistentTime << " s" - << std::setw(2) << " |" << std::endl; + << " time: " << std::fixed << std::setprecision(2) << std::setw(5) << (cpuTime() - myTime) << " s" + << std::endl; } - totalTime += cpuTime() - myTime; - solver.order_heap.filter(Solver::VarFilter(solver)); + totalTime += cpuTime() - myTime; return true; } -#define MAX_BINARY_PROP 40000000 +void Subsumer::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; +} + +#define MAX_BINARY_PROP 60000000 + +/** +@brief Call subsWNonExistBins with randomly picked starting literals -const bool Subsumer::subsWNonExistBinsFull(OnlyNonLearntBins* onlyNonLearntBins) +This is the function that overviews the deletion of all clauses that could be +inferred from non-existing binary clauses, and the strenghtening (through self- +subsuming resolution) of clauses that could be strenghtened using non-existent +binary clauses. +*/ +const bool Subsumer::subsWNonExistBinsFull() { - uint32_t oldClausesSubusmed = clauses_subsumed; - uint32_t oldLitsRemoved = literals_removed; - double myTime = cpuTime(); uint64_t oldProps = solver.propagations; - uint32_t oldTrailSize = solver.trail.size(); - uint64_t maxProp = MAX_BINARY_PROP; - //if (!startUp) maxProp /= 3; - if (clauses.size() > 2000000) maxProp /= 2; - ps2.clear(); - ps2.growTo(2); + 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[(i+startFrom)%solver.order_heap.size()]; - if (solver.propagations - oldProps > maxProp) break; + 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.cancelUntil(0); + solver.cancelUntilLight(); solver.uncheckedEnqueue(~lit); - solver.ok = (solver.propagate().isNULL()); + solver.ok = solver.propagate().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.cancelUntil(0); + solver.cancelUntilLight(); solver.uncheckedEnqueue(~lit); - solver.ok = (solver.propagate().isNULL()); + solver.ok = solver.propagate().isNULL(); if (!solver.ok) return false; continue; } + extraTimeNonExist += 10; } - subsNonExistentNum = clauses_subsumed - oldClausesSubusmed; - subsNonExistentTime = cpuTime() - myTime; - subsNonExistentumFailed = solver.trail.size() - oldTrailSize; - subsNonExistentLitsRemoved = literals_removed - oldLitsRemoved; + + if (onlyNonLearntBins) delete onlyNonLearntBins; return true; } +/** +@brief Subsumes&strenghtens clauses with non-existent binary clauses + +Generates binary clauses that could exist, then calls \function subsume0BIN() +with them, thus performing self-subsuming resolution and subsumption on the +clauses. + +@param[in] lit This literal is the starting point of this set of non-existent +binary clauses (this literal is the starting point in the binary graph) +@param onlyNonLearntBins This class is initialised before calling this function +and contains all the non-learnt binary clauses +*/ const bool Subsumer::subsWNonExistBins(const Lit& lit, OnlyNonLearntBins* onlyNonLearntBins) { #ifdef VERBOSE_DEBUG - std::cout << "subsWNonExistBins called with lit "; lit.print(); - std::cout << std::endl; + std::cout << "subsWNonExistBins called with lit " << lit << std::endl; #endif //VERBOSE_DEBUG toVisit.clear(); solver.newDecisionLevel(); solver.uncheckedEnqueueLight(lit); - bool failed = !onlyNonLearntBins->propagate(); + 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 c = solver.trail.size()-1; c > (int)solver.trail_lim[0]; c--) { - Lit x = solver.trail[c]; + 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.cancelUntil(0); - - if (toVisit.size() <= 1) { - ps2[0] = ~lit; - for (Lit *l = toVisit.getData(), *end = toVisit.getDataEnd(); l != end; l++) { - ps2[1] = *l; - assert(ps2[0] != ps2[1]); - #ifdef VERBOSE_DEBUG - std::cout << "Non-existent bin. lit1: "; ps2[0].print(); - std::cout << " lit2: "; ps2[1].print(); std::cout << std::endl; - #endif //VERBOSE_DEBUG - subsume0(ps2, calcAbstraction(ps2)); - subsume1Partial(ps2); - if (!solver.ok) goto end; - } + solver.assigns[x.var()] = l_Undef; + } + solver.assigns[solver.trail[solver.trail_lim[0]].var()] = l_Undef; + solver.qhead = solver.trail_lim[0]; + solver.trail.shrink_(solver.trail.size() - solver.trail_lim[0]); + solver.trail_lim.shrink_(solver.trail_lim.size()); + //solver.cancelUntilLight(); + + if ((onlyNonLearntBins != NULL && toVisit.size() <= onlyNonLearntBins->getWatchSize(lit)) + || (!solver.multiLevelProp)) { + //This has been performed above, with subsume1Partial of binary clauses: + //this toVisit.size()<=1, there mustn't have been more than 1 binary + //clause in the watchlist, so this has been performed above. } else { - subsume0BIN(~lit, toVisitAll); - if (!solver.ok) goto end; + subsume0BIN(~lit, toVisitAll, abst); } - end: for (uint32_t i = 0; i < toVisit.size(); i++) toVisitAll[toVisit[i].toInt()] = false; return solver.ok; } +/** +@brief Clears and deletes (almost) everything in this class +Clears touchlists, occurrance lists, clauses, and variable touched lists +*/ void Subsumer::clearAll() { - touched_list.clear(); - touched.clear(); - touched.growTo(solver.nVars(), false); + touchedVarsList.clear(); + touchedVars.clear(); + touchedVars.growTo(solver.nVars(), false); for (Var var = 0; var < solver.nVars(); var++) { if (solver.decision_var[var] && solver.assigns[var] == l_Undef) touch(var); occur[2*var].clear(); occur[2*var+1].clear(); } clauses.clear(); - cl_added.clear(); cl_touched.clear(); + addedClauseLits = 0; } -const bool Subsumer::simplifyBySubsumption(const bool alsoLearnt) +const bool Subsumer::eliminateVars() { - if (solver.nClauses() > 20000000) return true; - - double myTime = cpuTime(); - uint32_t origTrailSize = solver.trail.size(); - clauses_subsumed = 0; - literals_removed = 0; - numblockedClauseRemoved = 0; - numCalls++; - clauseID = 0; - numVarsElimed = 0; - blockTime = 0.0; - clearAll(); - - //if (solver.xorclauses.size() < 30000 && solver.clauses.size() < MAX_CLAUSENUM_XORFIND/10) addAllXorAsNorm(); - - if (solver.performReplace && !solver.varReplacer->performReplace(true)) - return false; - fillCannotEliminate(); - - uint32_t expected_size; - if (!alsoLearnt) - expected_size = solver.clauses.size() + solver.binaryClauses.size(); - else - expected_size = solver.clauses.size() + solver.binaryClauses.size() + solver.learnts.size(); - clauses.reserve(expected_size); - cl_added.reserve(expected_size); - cl_touched.reserve(expected_size); - - if (clauses.size() < 200000) fullSubsume = true; - else fullSubsume = false; - if (alsoLearnt) fullSubsume = true; - - //solver.clauseCleaner->cleanClauses(solver.learnts, ClauseCleaner::learnts); - //addFromSolver(solver.learnts, alsoLearnt); - solver.clauseCleaner->cleanClauses(solver.clauses, ClauseCleaner::clauses); - addFromSolver(solver.clauses, alsoLearnt); - - //It is IMPERATIVE to add binaryClauses last. The non-binary clauses can - //move to binaryClauses during cleaning!!!! - solver.clauseCleaner->removeSatisfied(solver.binaryClauses, ClauseCleaner::binaryClauses); - addFromSolver(solver.binaryClauses, alsoLearnt); - - //Limits - if (clauses.size() > 3500000) { - numMaxSubsume0 = 900000 * (1+numCalls/2); - numMaxElim = (uint32_t)((double)solver.order_heap.size() / 5.0 * (0.8+(double)(numCalls)/4.0)); - numMaxSubsume1 = 100000 * (1+numCalls/2); - numMaxBlockToVisit = (int64_t)(30000.0 * (0.8+(double)(numCalls)/3.0)); - } - if (clauses.size() <= 3500000 && clauses.size() > 1500000) { - numMaxSubsume0 = 2000000 * (1+numCalls/2); - numMaxElim = (uint32_t)((double)solver.order_heap.size() / 2.0 * (0.8+(double)(numCalls)/4.0)); - numMaxSubsume1 = 300000 * (1+numCalls/2); - numMaxBlockToVisit = (int64_t)(50000.0 * (0.8+(double)(numCalls)/3.0)); - } - if (clauses.size() <= 1500000) { - numMaxSubsume0 = 4000000 * (1+numCalls/2); - numMaxElim = (uint32_t)((double)solver.order_heap.size() / 2.0 * (0.8+(double)(numCalls)/2.0)); - numMaxSubsume1 = 400000 * (1+numCalls/2); - numMaxBlockToVisit = (int64_t)(80000.0 * (0.8+(double)(numCalls)/3.0)); - } - 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 (numCalls == 1) numMaxSubsume1 = 0; - if (!solver.doSubsume1) numMaxSubsume1 = 0; - if (alsoLearnt) { - numMaxElim = 0; - numMaxSubsume1 = 0; - numMaxBlockVars = 0; - numMaxBlockToVisit = 0; - fullSubsume = true; - } - - //For debugging - //numMaxBlockToVisit = std::numeric_limits::max(); - //numMaxElim = std::numeric_limits::max(); - //numMaxSubsume0 = std::numeric_limits::max(); - //numMaxSubsume1 = std::numeric_limits::max(); - //numMaxBlockVars = std::numeric_limits::max(); - #ifdef BIT_MORE_VERBOSITY - std::cout << "c num clauses:" << clauses.size() << std::endl; - std::cout << "c time to link in:" << cpuTime()-myTime << std::endl; + std::cout << "c VARIABLE ELIMINIATION -- touchedVarsList size:" << touchedVarsList.size() << std::endl; #endif - - for (uint32_t i = 0; i < clauses.size(); i++) { - if (numMaxSubsume0 == 0) break; - if (clauses[i].clause != NULL && - (fullSubsume - || !clauses[i].clause->subsume0IsFinished()) - ) - { - subsume0(*clauses[i].clause, clauses[i].clause->getAbst()); - if (subsumedNonLearnt && clauses[i].clause->learnt()) clauses[i].clause->makeNonLearnt(); - numMaxSubsume0--; + vec init_order; + orderVarsForElim(init_order); // (will untouch all variables) + + for (bool first = true; numMaxElim > 0 && numMaxElimVars > 0; first = false) { + uint32_t vars_elimed = 0; + vec order; + + if (first) { + for (uint32_t i = 0; i < init_order.size(); i++) { + const Var var = init_order[i]; + if (!cannot_eliminate[var] && solver.decision_var[var]) + order.push(var); + //no need to set touched[var] to false -- orderVarsForElim did that already + } + } else { + for (Var *it = touchedVarsList.getData(), *end = touchedVarsList.getDataEnd(); it != end; it++) { + const Var var = *it; + if (!cannot_eliminate[var] && solver.decision_var[var]) + order.push(var); + touchedVars[var] = false; + } + touchedVarsList.clear(); } - } - - origNClauses = clauses.size(); - - #ifdef BIT_MORE_VERBOSITY - std::cout << "c time until pre-subsume0 clauses and subsume1 2-learnts:" << cpuTime()-myTime << std::endl; - #endif - - if (!solver.ok) return false; - #ifdef VERBOSE_DEBUG - std::cout << "c pre-subsumed:" << clauses_subsumed << std::endl; - std::cout << "c cl_added:" << cl_added.size() << std::endl; - std::cout << "c cl_touched:" << cl_touched.size() << std::endl; - std::cout << "c clauses:" << clauses.size() << std::endl; - std::cout << "c origNClauses:" << origNClauses << std::endl; - #endif - - if (clauses.size() > 10000000) goto endSimplifyBySubsumption; - if (solver.doBlockedClause && numCalls % 3 == 1) blockedClauseRemoval(); - do{ - #ifdef BIT_MORE_VERBOSITY - std::cout << "c time before the start of almost_all/smaller: " << cpuTime() - myTime << std::endl; + #ifdef VERBOSE_DEBUG + std::cout << "Order size:" << order.size() << std::endl; #endif - if (numMaxSubsume0 > 0) { - if (cl_added.size() > origNClauses / 2) { - almost_all_database(); - if (!solver.ok) return false; - } else { - smaller_database(); + + for (uint32_t i = 0; i < order.size() && numMaxElim > 0 && numMaxElimVars > 0; i++) { + if (maybeEliminate(order[i])) { if (!solver.ok) return false; + vars_elimed++; + numMaxElimVars--; } } - cl_added.clear(); - assert(cl_added.size() == 0); - assert(solver.ok); - solver.ok = (solver.propagate().isNULL()); - if (!solver.ok) { - return false; - } - solver.clauseCleaner->cleanClausesBewareNULL(clauses, ClauseCleaner::simpClauses, *this); - - #ifdef BIT_MORE_VERBOSITY - std::cout << "c time until the end of almost_all/smaller: " << cpuTime() - myTime << std::endl; - #endif - - if (!solver.doVarElim) break; - + if (vars_elimed == 0) break; + + numVarsElimed += vars_elimed; #ifdef BIT_MORE_VERBOSITY - printf("c VARIABLE ELIMINIATION\n"); - std::cout << "c toucheds list size:" << touched_list.size() << std::endl; + std::cout << "c #var-elim: " << vars_elimed << std::endl; #endif - vec init_order; - orderVarsForElim(init_order); // (will untouch all variables) - - for (bool first = true; numMaxElim > 0; first = false){ - uint32_t vars_elimed = 0; - vec order; - - if (first) { - //init_order.copyTo(order); - for (uint32_t i = 0; i < init_order.size(); i++) { - const Var var = init_order[i]; - if (!cannot_eliminate[var] && solver.decision_var[var]) - order.push(var); - } - } else { - for (uint32_t i = 0; i < touched_list.size(); i++) { - const Var var = touched_list[i]; - if (!cannot_eliminate[var] && solver.decision_var[var]) - order.push(var); - touched[var] = false; - } - touched_list.clear(); + } + + return true; +} + +void Subsumer::subsumeBinsWithBins() +{ + double myTime = cpuTime(); + uint32_t numBinsBefore = solver.numBins; + + uint32_t wsLit = 0; + for (vec *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + vec& ws = *it; + Lit lit = ~Lit::toLit(wsLit); + if (ws.size() < 2) continue; + + std::sort(ws.getData(), ws.getDataEnd(), BinSorter()); + + Watched* i = ws.getData(); + Watched* j = i; + + Lit lastLit = lit_Undef; + bool lastLearnt = false; + for (Watched *end = ws.getDataEnd(); i != end; i++) { + if (!i->isBinary()) { + *j++ = *i; + continue; } - #ifdef VERBOSE_DEBUG - std::cout << "Order size:" << order.size() << std::endl; - #endif - - assert(solver.qhead == solver.trail.size()); - for (uint32_t i = 0; i < order.size() && numMaxElim > 0; i++, numMaxElim--) { - if (maybeEliminate(order[i])) { - if (!solver.ok) { - return false; - } - vars_elimed++; + 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; + touch(lit, i->getLearnt()); + touch(i->getOtherLit(), i->getLearnt()); } + solver.numBins--; + } else { + lastLit = i->getOtherLit(); + lastLearnt = i->getLearnt(); + *j++ = *i; } - assert(solver.qhead == solver.trail.size()); - - if (vars_elimed == 0) break; - - numVarsElimed += vars_elimed; - #ifdef BIT_MORE_VERBOSITY - printf("c #var-elim: %d\n", vars_elimed); - std::cout << "c time until the end of varelim: " << cpuTime() - myTime << std::endl; - #endif } - }while (cl_added.size() > 100 && numMaxElim > 0); - endSimplifyBySubsumption: - - if (!solver.ok) return false; - solver.ok = (solver.propagate().isNULL()); - if (!solver.ok) { - return false; + ws.shrink_(i-j); } - - #ifndef NDEBUG - verifyIntegrity(); - #endif - - removeWrong(solver.learnts); - removeWrong(solver.binaryClauses); - removeAssignedVarsFromEliminated(); - solver.order_heap.filter(Solver::VarFilter(solver)); - - addBackToSolver(); - freeMemory(); - - if (solver.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) < 0 || blockTime > 0.0) { - std::cout - << "c | Blocked clauses removed: " << std::setw(8) << numblockedClauseRemoved - << " Time: " << std::fixed << std::setprecision(2) << std::setw(4) << blockTime << " s" - << " |" << std::endl; - } + 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; - - solver.testAllClauseAttach(); - return true; + clauses_subsumed += (numBinsBefore - solver.numBins); } -void Subsumer::removeAssignedVarsFromEliminated() +/** +@brief Main function in this class + +Performs, recursively: +* backward-subsumption +* self-subsuming resolution +* variable elimination + +@param[in] alsoLearnt Should learnt clauses be also hooked into the occurrence +lists? If so, variable elimination cannot take place. +*/ +const bool Subsumer::simplifyBySubsumption(const bool _alsoLearnt) { - 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 >::iterator it = elimedOutVar.find(var); - if (it != elimedOutVar.end()) { - //TODO memory loss here - elimedOutVar.erase(it); - } - } - } -} + alsoLearnt = _alsoLearnt; + if (solver.nClauses() > 50000000 + || solver.clauses_literals > 500000000) return true; -template + double myTime = cpuTime(); + clauseID = 0; + clearAll(); + + //if (solver.xorclauses.size() < 30000 && solver.clauses.size() < MAX_CLAUSENUM_XORFIND/10) addAllXorAsNorm(); + + if (solver.conf.doReplace && !solver.varReplacer->performReplace(true)) + return false; + fillCannotEliminate(); + + uint32_t expected_size = solver.clauses.size(); + if (alsoLearnt) expected_size += solver.learnts.size(); + clauses.reserve(expected_size); + cl_touched.reserve(expected_size); + + solver.clauseCleaner->cleanClauses(solver.clauses, ClauseCleaner::clauses); + if (alsoLearnt) { + solver.clauseCleaner->cleanClauses(solver.learnts, ClauseCleaner::learnts); + + if (solver.learnts.size() < 10000000) + std::sort(solver.learnts.getData(), solver.learnts.getDataEnd(), sortBySize()); + addedClauseLits += addFromSolver(solver.learnts); + } else { + if (solver.clauses.size() < 10000000) + std::sort(solver.clauses.getData(), solver.clauses.getDataEnd(), sortBySize()); + addedClauseLits += addFromSolver(solver.clauses); + } + + CompleteDetachReatacher reattacher(solver); + reattacher.detachNonBinsNonTris(false); + totalTime += myTime - cpuTime(); + + //Do stuff with binaries + if (alsoLearnt) { + numMaxSubsume1 = 500*1000*1000; + if (solver.conf.doSubsWBins && !subsumeWithBinaries()) return false; + addedClauseLits += addFromSolver(solver.clauses); + } else { + if ((solver.conf.doBlockedClause || numCalls == 2) + && solver.conf.doVarElim) { + numMaxBlockToVisit = (int64_t)800*1000*1000; + blockedClauseRemoval(); + } + + subsumeBinsWithBins(); + numMaxSubsume1 = 2*1000*1000*1000; + if (solver.conf.doSubsWBins && !subsumeWithBinaries()) return false; + 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 + + /*for (ClauseSimp *it = clauses.getData(), *end = clauses.getDataEnd(); it != end; ++it) { + if (it->clause == NULL) continue; + //if (!it->clause->learnt()) continue; + subsume1(*it->clause); + }*/ + //setLimits(alsoLearnt); + + if (clauses.size() > 10000000 || + (numMaxSubsume1 < 0 && numMaxElim == 0 && numMaxBlockVars == 0)) + goto endSimplifyBySubsumption; + + do { + if (!subsume0AndSubsume1()) return false; + + if (!solver.conf.doVarElim) break; + + if (!eliminateVars()) return false; + + //subsumeBinsWithBins(); + //if (solver.conf.doSubsWBins && !subsumeWithBinaries()) return false; + solver.clauseCleaner->removeSatisfiedBins(); + } while (cl_touched.nElems() > 100); + endSimplifyBySubsumption: + + 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) <::max(); + + #ifdef BIT_MORE_VERBOSITY + std::cout << "c addedClauseLits: " << addedClauseLits << std::endl; + #endif + if (addedClauseLits < 10000000) { + numMaxElim *= 3; + numMaxSubsume0 *= 3; + numMaxSubsume1 *= 3; + } + + if (addedClauseLits < 5000000) { + numMaxElim *= 4; + numMaxSubsume0 *= 4; + numMaxSubsume1 *= 4; + } + + if (addedClauseLits < 3000000) { + numMaxElim *= 4; + numMaxSubsume0 *= 4; + numMaxSubsume1 *= 4; + } + + if (addedClauseLits < 1000000) { + numMaxElim *= 4; + numMaxSubsume0 *= 4; + numMaxSubsume1 *= 4; + } + + numMaxElimVars = (solver.order_heap.size()/3)*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; + + if (numCalls == 1) { + numMaxSubsume1 = 10*1000*1000; + } + + if (alsoLearnt) { + numMaxElim = 0; + numMaxElimVars = 0; + numMaxSubsume0 /= 2; + numMaxSubsume1 /= 2; + numMaxBlockVars = 0; + } else { + numCalls++; + } + + //For debugging + + //numMaxSubsume0 = 0; + //numMaxSubsume1 = 0; + //numMaxSubsume0 = std::numeric_limits::max(); + //numMaxSubsume1 = std::numeric_limits::max(); + + //numMaxBlockToVisit = std::numeric_limits::max(); + //numMaxBlockVars = std::numeric_limits::max(); +} + +/** +@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 > >::iterator it = elimedOutVar.find(var); + if (it != elimedOutVar.end()) elimedOutVar.erase(it); + + map > >::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 void Subsumer::findSubsumed(const T& ps, uint32_t abs, vec& out_subsumed) { #ifdef VERBOSE_DEBUG - 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"); + 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& 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, 1, 1); - - if (it->clause != (Clause*)&ps && subsetAbst(abs, it->clause->getAbst()) && ps.size() <= it->clause->size() && subset(ps, *it->clause)) { - out_subsumed.push(*it); + + 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 +void Subsumer::findSubsumed1(const T& ps, uint32_t abs, vec& out_subsumed, vec& out_lits) +{ + #ifdef VERBOSE_DEBUG + cout << "findSubsumed1: " << ps << std::endl; + #endif + + Var minVar = var_Undef; + uint32_t bestSize = std::numeric_limits::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 +void inline Subsumer::fillSubs(const T& ps, uint32_t abs, vec& out_subsumed, vec& out_lits, const Lit lit) +{ + Lit litSub; + vec& 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, 1, 1); + + 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& todo, const Var var, std::pair& removed) +{ + pair 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 - cout << "subsumed: "; - it->clause->plainPrint(); + 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)); + #ifndef TOUCH_LESS + touch(c.lit1, false); + touch(c.lit2, false); #endif } } } -void inline Subsumer::MigrateToPsNs(vec& poss, vec& negs, vec& ps, vec& ns, const Var x) +/** +@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& posAll, vec& negAll, const Var var) { - poss.moveTo(ps); - negs.moveTo(ns); - - for (uint32_t i = 0; i < ps.size(); i++) - unlinkClause(ps[i], x); - for (uint32_t i = 0; i < ns.size(); i++) - unlinkClause(ns[i], x); + pair 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; } -void inline Subsumer::DeallocPsNs(vec& ps, vec& ns) +const uint32_t Subsumer::numNonLearntBins(const Lit lit) const { - for (uint32_t i = 0; i < ps.size(); i++) { - //clauses[ps[i].index].clause = NULL; - //clauseFree(ps[i].clause); + uint32_t num = 0; + const vec& ws = solver.watches[(~lit).toInt()]; + for (const Watched *it = ws.getData(), *end = ws.getDataEnd(); it != end; it++) { + if (it->isBinary() && !it->getLearnt()) num++; } - for (uint32_t i = 0; i < ns.size(); i++) { - //clauses[ns[i].index].clause = NULL; - //clauseFree(ns[i].clause); + + return num; +} + +void Subsumer::fillClAndBin(vec& all, vec& cs, const Lit lit) +{ + for (uint32_t i = 0; i < cs.size(); i++) + all.push(ClAndBin(cs[i])); + + const vec& ws = solver.watches[(~lit).toInt()]; + for (const Watched *it = ws.getData(), *end = ws.getDataEnd(); it != end; it++) { + if (it->isBinary() &&!it->getLearnt()) all.push(ClAndBin(lit, it->getOtherLit())); } } -// Returns TRUE if variable was eliminated. -bool Subsumer::maybeEliminate(const Var x) +/** +@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(solver.qhead == solver.trail.size()); - assert(!var_elimed[x]); - assert(!cannot_eliminate[x]); - assert(solver.decision_var[x]); - if (solver.value(x) != l_Undef) return false; - if (occur[Lit(x, false).toInt()].size() == 0 && occur[Lit(x, true).toInt()].size() == 0) - return false; - - vec& poss = occur[Lit(x, false).toInt()]; - vec& negs = occur[Lit(x, true).toInt()]; - + 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;*/ + + const uint32_t numNonLearntPos = numNonLearntBins(lit); + const uint32_t posSize = occur[lit.toInt()].size() + numNonLearntPos; + const uint32_t numNonLearntNeg = numNonLearntBins(~lit); + const uint32_t negSize = occur[(~lit).toInt()].size() + numNonLearntNeg; + vec& poss = occur[lit.toInt()]; + vec& negs = occur[(~lit).toInt()]; + numMaxElim -= posSize + negSize; + // Heuristic CUT OFF: - if (poss.size() >= 10 && negs.size() >= 10) - return false; - + if (posSize >= 10 && negSize >= 10) return false; + // Count clauses/literals before elimination: - int before_clauses = poss.size() + negs.size(); - uint32_t before_literals = 0; + uint32_t before_literals = numNonLearntNeg*2 + numNonLearntPos*2; for (uint32_t i = 0; i < poss.size(); i++) before_literals += poss[i].clause->size(); for (uint32_t i = 0; i < negs.size(); i++) before_literals += negs[i].clause->size(); - + // Heuristic CUT OFF2: - if ((poss.size() >= 3 && negs.size() >= 3 && before_literals > 300) - && clauses.size() > 1500000) + if ((posSize >= 3 && negSize >= 3 && before_literals > 300) + && clauses.size() > 700000) return false; - if ((poss.size() >= 5 && negs.size() >= 5 && before_literals > 400) - && clauses.size() <= 1500000 && clauses.size() > 200000) + if ((posSize >= 5 && negSize >= 5 && before_literals > 400) + && clauses.size() <= 700000 && clauses.size() > 100000) return false; - if ((poss.size() >= 8 && negs.size() >= 8 && before_literals > 700) - && clauses.size() <= 200000) + if ((posSize >= 8 && negSize >= 8 && before_literals > 700) + && clauses.size() <= 100000) return false; - + + vec posAll, negAll; + fillClAndBin(posAll, poss, lit); + fillClAndBin(negAll, negs, ~lit); + assert(posAll.size() == posSize); + assert(negAll.size() == negSize); + // Count clauses/literals after elimination: - int after_clauses = 0; - vec dummy; - for (uint32_t i = 0; i < poss.size(); i++) for (uint32_t j = 0; j < negs.size(); j++){ + numMaxElim -= posSize * negSize + before_literals; + uint32_t before_clauses = posSize + negSize; + uint32_t after_clauses = 0; + vec 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(); - bool ok = merge(*poss[i].clause, *negs[j].clause, Lit(x, false), Lit(x, true), dummy); + bool ok = merge(posAll[i], negAll[j], lit, ~lit, dummy); if (ok){ after_clauses++; - if (after_clauses > before_clauses) goto Abort; + if (after_clauses > before_clauses) return false; } } - Abort:; - + //Eliminate: - if (after_clauses <= before_clauses) { - vec ps, ns; - MigrateToPsNs(poss, negs, ps, ns, x); - for (uint32_t i = 0; i < ps.size(); i++) for (uint32_t j = 0; j < ns.size(); j++){ - dummy.clear(); - bool ok = merge(*ps[i].clause, *ns[j].clause, Lit(x, false), Lit(x, true), dummy); - if (ok){ - uint32_t group_num = 0; - #ifdef STATS_NEEDED - group_num = solver.learnt_clause_group++; - if (solver.dynamic_behaviour_analysis) { - string name = solver.logger.get_group_name(ps[i].clause->getGroup()) + " " + solver.logger.get_group_name(ns[j].clause->getGroup()); - solver.logger.set_group_name(group_num, name); - } - #endif - Clause* cl = solver.addClauseInt(dummy, group_num); - if (cl != NULL) { - ClauseSimp c = linkInClause(*cl); - subsume0(*cl, cl->getAbst()); + numMaxElim -= posSize * negSize + before_literals; + poss.clear(); + negs.clear(); + removeClauses(posAll, negAll, var); + + #ifndef NDEBUG + for (uint32_t i = 0; i < solver.watches[lit.toInt()].size(); i++) { + Watched& w = solver.watches[lit.toInt()][i]; + assert(w.isTriClause() || (w.isBinary() && w.getLearnt())); + } + for (uint32_t i = 0; i < solver.watches[(~lit).toInt()].size(); i++) { + Watched& w = solver.watches[(~lit).toInt()][i]; + assert(w.isTriClause() || (w.isBinary() && w.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; + + uint32_t group_num = 0; + #ifdef STATS_NEEDED + group_num = solver.learnt_clause_group++; + if (solver.dynamic_behaviour_analysis) { + string name = solver.logger.get_group_name(ps[i].clause->getGroup()) + " " + solver.logger.get_group_name(ns[j].clause->getGroup()); + solver.logger.set_group_name(group_num, name); + } + #endif + + 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 (!solver.ok) return true; + subsume1(dummy, false); + break; + } + default: { + Clause* cl = solver.clauseAllocator.Clause_new(dummy, group_num); + ClauseSimp c = linkInClause(*cl); + if (numMaxSubsume1 > 0) subsume1(*c.clause); + else subsume0(*c.clause); } } - DeallocPsNs(ps, ns); - goto Eliminated; - } - - return false; - - Eliminated: - assert(occur[Lit(x, false).toInt()].size() + occur[Lit(x, true).toInt()].size() == 0); - var_elimed[x] = true; + if (!solver.ok) return true; + } + + assert(occur[lit.toInt()].size() == 0 && occur[(~lit).toInt()].size() == 0); + var_elimed[var] = true; numElimed++; - solver.setDecisionVar(x, false); + solver.setDecisionVar(var, false); return true; } -// Returns FALSE if clause is always satisfied ('out_clause' should not be used). 'seen' is assumed to be cleared. -bool Subsumer::merge(const Clause& ps, const Clause& qs, const Lit without_p, const Lit without_q, vec& out_clause) +/** +@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& out_clause) { - for (uint32_t i = 0; i < ps.size(); i++){ - if (ps[i] != without_p){ - seen_tmp[ps[i].toInt()] = 1; - out_clause.push(ps[i]); + bool retval = true; + if (ps.isBin) { + 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(); + 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]); + } } } - - for (uint32_t i = 0; i < qs.size(); i++){ - if (qs[i] != without_q){ - if (seen_tmp[(~qs[i]).toInt()]){ - for (uint32_t i = 0; i < ps.size(); i++) - seen_tmp[ps[i].toInt()] = 0; - return false; + + if (qs.isBin) { + 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(); + 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]); } - if (!seen_tmp[qs[i].toInt()]) - out_clause.push(qs[i]); } } - - for (uint32_t i = 0; i < ps.size(); i++) - seen_tmp[ps[i].toInt()] = 0; - - return true; -} -struct myComp { - bool operator () (const pair& x, const pair& y) { - return x.first < y.first || - (!(y.first < x.first) && x.second < y.second); + end: + if (ps.isBin) { + seen_tmp[ps.lit2.toInt()] = 0; + } else { + Clause& c = *ps.clsimp.clause; + numMaxElim -= c.size(); + for (uint32_t i = 0; i < c.size(); i++) + seen_tmp[c[i].toInt()] = 0; } -}; - -// Side-effect: Will untouch all variables. + + 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& order) { order.clear(); vec > cost_var; - for (uint32_t i = 0; i < touched_list.size(); i++){ - Var x = touched_list[i]; - touched[x] = 0; - cost_var.push(std::make_pair( occur[Lit(x, false).toInt()].size() * occur[Lit(x, true).toInt()].size() , x )); + for (uint32_t i = 0; i < touchedVarsList.size(); i++){ + Lit x = Lit(touchedVarsList[i], false); + touchedVars[x.var()] = false; + //this is not perfect -- solver.watches[] is an over-approximation + uint32_t pos = occur[x.toInt()].size(); + uint32_t neg = occur[(~x).toInt()].size(); + uint32_t cost = pos * neg * 2 + numNonLearntBins(x) * neg + numNonLearntBins(~x) * pos; + cost_var.push(std::make_pair(cost, x.var())); } - - touched_list.clear(); + touchedVarsList.clear(); + std::sort(cost_var.getData(), cost_var.getData()+cost_var.size(), myComp()); - for (uint32_t x = 0; x < cost_var.size(); x++) { if (cost_var[x].first != 0) order.push(cost_var[x].second); } } -void Subsumer::verifyIntegrity() +/** +@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 +*/ +const bool Subsumer::verifyIntegrity() { - vector occurNum(solver.nVars()*2, 0); - + vector 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++) { - assert(occurNum[i] == occur[i].size()); + #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; } -const bool Subsumer::allTautology(const vec& ps, const Lit lit) +template +const bool Subsumer::allTautology(const T& ps, const Lit lit) { #ifdef VERBOSE_DEBUG - cout << "allTautology: "; - for (uint32_t i = 0; i < ps.size(); i++) { - if (ps[i].sign()) printf("-"); - printf("%d ", ps[i].var() + 1); - } - printf("0\n"); + cout << "allTautology: " << ps << std::endl; #endif - - vec& cs = occur[lit.toInt()]; - if (cs.size() == 0) return true; - + + numMaxBlockToVisit -= ps.size()*2; for (const Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) { - seen_tmp[l->toInt()] = true; + if (*l != ~lit) seen_tmp[l->toInt()] = true; } - + bool allIsTautology = true; - for (ClauseSimp *it = cs.getData(), *end = cs.getDataEnd(); it != end; it++){ - if (it+1 != end) - __builtin_prefetch((it+1)->clause, 1, 1); - - Clause& c = *it->clause; - for (Lit *l = c.getData(), *end2 = l + c.size(); l != end2; l++) { - if (*l != lit && seen_tmp[(~(*l)).toInt()]) { + const vec& cs = occur[lit.toInt()]; + const vec& 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, 1, 1); + + 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 (const Watched *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.size() < 1) return; + if (solver.order_heap.empty()) return; + double myTime = cpuTime(); - vec toRemove; - + numblockedClauseRemoved = 0; + uint32_t numElimedBefore = numElimed; + touchedBlockedVars = priority_queue, MyComp>(); touchedBlockedVarsBool.clear(); touchedBlockedVarsBool.growTo(solver.nVars(), false); - for (uint32_t i = 0; i < solver.order_heap.size() && i < numMaxBlockVars; i++) { - touchBlockedVar(solver.order_heap[solver.mtrand.randInt(solver.order_heap.size()-1)]); + 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]); } - - while (touchedBlockedVars.size() > 100 && numMaxBlockToVisit > 0) { + + uint32_t triedToBlock = 0; + while (numMaxBlockToVisit > 0 && !touchedBlockedVars.empty()) { VarOcc vo = touchedBlockedVars.top(); touchedBlockedVars.pop(); - - if (solver.assigns[vo.var] != l_Undef || !solver.decision_var[vo.var] || cannot_eliminate[vo.var]) - continue; 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); - Lit negLit = Lit(vo.var, true); - - numMaxBlockToVisit -= (int64_t)occur[lit.toInt()].size(); - numMaxBlockToVisit -= (int64_t)occur[negLit.toInt()].size(); - //if (!tryOneSetting(lit, negLit)) { - tryOneSetting(negLit, lit); + + //if (!tryOneSetting(lit)) { + tryOneSetting(lit); // } } - blockTime += cpuTime() - myTime; - - #ifdef BIT_MORE_VERBOSITY - std::cout << "c Total fime for block until now: " << blockTime << std::endl; - #endif + + removeWrongBinsAndAllTris(); + + 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; + } } -const bool Subsumer::tryOneSetting(const Lit lit, const Lit negLit) +const bool Subsumer::tryOneSetting(const Lit lit) { - uint32_t toRemove = 0; - bool returnVal = false; - vec cl; - + numMaxBlockToVisit -= occur[lit.toInt()].size(); for(ClauseSimp *it = occur[lit.toInt()].getData(), *end = occur[lit.toInt()].getDataEnd(); it != end; it++) { - cl.clear(); - cl.growTo(it->clause->size()-1); - for (uint32_t i = 0, i2 = 0; i < it->clause->size(); i++) { - if ((*it->clause)[i] != lit) { - cl[i2] = (*it->clause)[i]; - i2++; - } - } - - if (allTautology(cl, negLit)) { - toRemove++; - } else { - break; - } - } - - if (toRemove == occur[lit.toInt()].size()) { - var_elimed[lit.var()] = true; - solver.setDecisionVar(lit.var(), false); - vec 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++; - } - - vec toRemove2(occur[negLit.toInt()]); - for (ClauseSimp *it = toRemove2.getData(), *end = toRemove2.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++; + if (!allTautology(*it->clause, ~lit)) { + return false; } - returnVal = true; } - - return returnVal; -} -const bool Subsumer::checkElimedUnassigned() const -{ - for (uint32_t i = 0; i < var_elimed.size(); i++) { - if (var_elimed[i]) { - assert(solver.assigns[i] == l_Undef); - if (solver.assigns[i] != l_Undef) return false; - } + vec lits(1); + const vec& ws = solver.watches[(~lit).toInt()]; + numMaxBlockToVisit -= ws.size(); + for (const Watched *it = ws.getData(), *end = ws.getDataEnd(); it != end; it++) { + if (!it->isNonLearntBinary()) continue; + lits[0] = it->getOtherLit(); + if (!allTautology(lits, ~lit)) return false; } - return true; -} + blockedClauseElimAll(lit); + blockedClauseElimAll(~lit); -/* -int hash32shift(int key) -{ - key = ~key + (key << 15); // key = (key << 15) - key - 1; - key = key ^ (key >> 12); - key = key + (key << 2); - key = key ^ (key >> 4); - key = key * 2057; // key = (key + (key << 3)) + (key << 11); - key = key ^ (key >> 16); - return key; + var_elimed[lit.var()] = true; + numElimed++; + numMaxElimVars--; + solver.setDecisionVar(lit.var(), false); + + return true; } -vector Subsumer::merge() +void Subsumer::blockedClauseElimAll(const Lit lit) { - vector var_merged(solver.nVars(), false); - double myTime = cpuTime(); - - vector varData(solver.nVars()); - - for (Var var = 0; var < solver.nVars(); var++) if (solver.decision_var[var] && solver.assigns[var] == l_Undef && !cannot_eliminate[var]) { - varDataStruct thisVar; - - vec& toCountPos = occur[Lit(var, false).toInt()]; - thisVar.numPosClauses = toCountPos.size(); - for (uint32_t i2 = 0; i2 < toCountPos.size(); i2++) { - thisVar.sumPosClauseSize += toCountPos[i2].clause->size(); - for (Lit *l = toCountPos[i2].clause->getData(), *end = l + toCountPos[i2].clause->size(); l != end; l++) { - if (l->var() != var) thisVar.posHash ^= hash32shift(l->toInt()); - } - } - - vec& toCountNeg = occur[Lit(var, true).toInt()]; - thisVar.numNegClauses = toCountNeg.size(); - for (uint32_t i2 = 0; i2 < toCountNeg.size(); i2++) { - thisVar.sumNegClauseSize += toCountNeg[i2].clause->size(); - for (Lit *l = toCountNeg[i2].clause->getData(), *end = l + toCountNeg[i2].clause->size(); l != end; l++) { - if (l->var() != var) thisVar.negHash ^= hash32shift(l->toInt()); - } - } - - varData[var] = thisVar; - } - - map > dataToVar; - for (Var var = 0; var < solver.nVars(); var++) if (solver.decision_var[var] && solver.assigns[var] == l_Undef) { - dataToVar[varData[var]].push_back(var); - assert(dataToVar[varData[var]].size() > 0); - } - - for (map >::iterator it = dataToVar.begin(); it != dataToVar.end(); it++) { - //std::cout << "size: " << it->second.size() << std::endl; - for (uint i = 0; i < it->second.size()-1; i++) { - assert(it->second.size() > i+1); - assert(varData[it->second[i]] == varData[it->second[i+1]]); - } + vec 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++; } - - uint64_t checked = 0; - uint64_t replaced = 0; - for (Var var = 0; var < solver.nVars(); var++) if (solver.decision_var[var] && solver.assigns[var] == l_Undef && !cannot_eliminate[var]) { - varDataStruct tmp = varData[var]; - assert(dataToVar[tmp].size() > 0); - - if (dataToVar[tmp].size() > 0) { - map >::iterator it = dataToVar.find(tmp); - for (uint i = 0; i < it->second.size(); i++) if (it->second[i] != var) { - checked ++; - if (checkIfSame(Lit(var, false), Lit(it->second[i], false)) && - (checkIfSame(Lit(var, true), Lit(it->second[i], true)))) - { - vec ps(2); - ps[0] = Lit(var, false); - ps[1] = Lit(it->second[i], false); - solver.varReplacer->replace(ps, true, 0); - replaced++; - goto next; - - } - } - } - - tmp.reversePolarity(); - if (dataToVar[tmp].size() > 0) { - map >::iterator it = dataToVar.find(tmp); - for (uint i = 0; i < it->second.size(); i++) if (it->second[i] != var) { - checked ++; - if (checkIfSame(Lit(var, true), Lit(it->second[i], false)) && - (checkIfSame(Lit(var, false), Lit(it->second[i], true)))) - { - vec ps(2); - ps[0] = Lit(var, false); - ps[1] = Lit(it->second[i], false); - solver.varReplacer->replace(ps, false, 0); - replaced++; - goto next; - } - } + + uint32_t removedNum = 0; + vec& ws = solver.watches[(~lit).toInt()]; + Watched *i = ws.getData(); + Watched *j = i; + for (Watched *end = ws.getDataEnd(); i != end; i++) { + if (!i->isNonLearntBinary()) { + *j++ = *i; + continue; } - - next:; + assert(!i->getLearnt()); + removeWBin(solver.watches[(~i->getOtherLit()).toInt()], lit, false); + elimedOutVarBin[lit.var()].push_back(std::make_pair(lit, i->getOtherLit())); + touch(i->getOtherLit(), false); + removedNum++; } - - std::cout << "c | Merging vars in same clauses. checked: " << std::setw(5) << checked << " replaced: " << std::setw(5) << replaced << " time: " << std::setprecision(2) << std::setw(5) << cpuTime()-myTime << std::endl; - - return var_merged; -}*/ + ws.shrink_(i-j); -/*const bool Subsumer::checkIfSame(const Lit lit1, const Lit lit2) + 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 +*/ +const bool Subsumer::checkElimedUnassigned() const { - assert(lit1.var() != lit2.var()); - #ifdef VERBOSE_DEBUG - std::cout << "checking : " << lit1.var()+1 << " , " << lit2.var()+1 << std::endl; - #endif - - vec& occSet1 = occur[lit1.toInt()]; - vec& occSet2 = occur[lit2.toInt()]; - vec tmp; - - for (ClauseSimp *it = occSet1.getData(), *end = it + occSet1.size(); it != end; it++) { - bool found = false; - tmp.clear(); - uint32_t clauseSize = it->clause->size(); - - for (Lit *l = it->clause->getData(), *end2 = l + it->clause->size(); l != end2; l++) { - if (l->var() != lit1.var()) { - tmp.push(*l); - seen_tmp[l->toInt()] = true; - } - } - #ifdef VERBOSE_DEBUG - std::cout << "orig: "; - it->clause->plainPrint(); - #endif - - for (ClauseSimp *it2 = occSet2.getData(), *end2 = it2 + occSet2.size(); (it2 != end2 && !found); it2++) { - if (it2->clause->size() != clauseSize) continue; - - for (Lit *l = it2->clause->getData(), *end3 = l + tmp.size(); l != end3; l++) if (l->var() != lit1.var()) { - if (!seen_tmp[l->toInt()]) goto next; - } - found = true; - - #ifdef VERBOSE_DEBUG - std::cout << "OK: "; - it2->clause->plainPrint(); - #endif - next:; - } - - for (Lit *l = tmp.getData(), *end2 = l + tmp.size(); l != end2; l++) { - seen_tmp[l->toInt()] = false; + 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; } - - if (!found) return false; } - #ifdef VERBOSE_DEBUG - std::cout << "OK" << std::endl; - #endif - - return true; -}*/ + assert(numElimed == checkNumElimed); -}; //NAMESPACE MINISAT + return true; +} diff --git a/src/sat/cryptominisat2/Subsumer.h b/src/sat/cryptominisat2/Subsumer.h index a36ea7a..19f44e4 100644 --- a/src/sat/cryptominisat2/Subsumer.h +++ b/src/sat/cryptominisat2/Subsumer.h @@ -1,7 +1,10 @@ -/************************************************************************************************** -Originally From: Solver.C -- (C) Niklas Een, Niklas Sorensson, 2004 -Substantially modified by: Mate Soos (2010) -**************************************************************************************************/ +/***************************************************************************** +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 @@ -12,148 +15,266 @@ Substantially modified by: Mate Soos (2010) #include "BitArray.h" #include #include +#include #include using std::vector; +using std::list; using std::map; using std::priority_queue; -namespace MINISAT -{ -using namespace MINISAT; - class ClauseCleaner; class OnlyNonLearntBins; +/** +@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); - ~Subsumer(); //Called from main const bool simplifyBySubsumption(const bool alsoLearnt = false); - const bool subsumeWithBinaries(OnlyNonLearntBins* onlyNonLearntBins); void newVar(); - //Used by cleaner - void unlinkModifiedClause(vec& origClause, ClauseSimp c, const bool detachAndNull); - void unlinkClause(ClauseSimp cc, Var elim = var_Undef); - ClauseSimp linkInClause(Clause& cl); - void linkInAlreadyClause(ClauseSimp& c); - void updateClause(ClauseSimp c); - - //UnElimination void extendModel(Solver& solver2); const bool unEliminate(const Var var); + //touching + void touchChangeVars(const Lit p); //Get-functions const vec& getVarElimed() const; const uint32_t getNumElimed() const; const bool checkElimedUnassigned() const; const double getTotalTime() const; - + const map > >& getElimedOutVar() const; + const map > >& getElimedOutVarBin() const; + private: - + + const bool subsumeWithBinaries(); + 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 clauses; - CSet learntClauses; - vec touched; // Is set to true when a variable is part of a removed clause. Also true initially (upon variable creation). - vec touched_list; // A list of the true elements in 'touched'. - CSet cl_touched; // Clauses strengthened. - CSet cl_added; // Clauses created. - vec > occur; // 'occur[index(lit)]' is a list of constraints containing 'lit'. - vec* > iter_vecs; // Vectors currently used for iterations. Removed clauses will be looked up and replaced by 'Clause_NULL'. - vec iter_sets; // Sets currently used for iterations. - vec cannot_eliminate;// + vec touchedVars; /// touchedVarsList; /// > occur; /// iter_sets; /// cannot_eliminate;/// seen_tmp; /// var_elimed; //TRUE if var has been eliminated - double totalTime; - uint32_t numElimed; - map > elimedOutVar; - - // Temporaries (to reduce allocation overhead): - // - vec seen_tmp; // (used in various places) - - + Solver& solver; /// var_elimed; /// > > elimedOutVar; /// > > elimedOutVarBin; /// - void addFromSolver(vec& cs, bool alsoLearnt = false); + const uint64_t addFromSolver(vec& cs); void fillCannotEliminate(); void clearAll(); + void setLimits(); + const bool subsume0AndSubsume1(); + vec ol_seenPos; + vec ol_seenNeg; //Finish-up void freeMemory(); void addBackToSolver(); void removeWrong(vec& 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); } - void registerIteration (vec& iter_vec) { iter_vecs.push(&iter_vec); } - void unregisterIteration(vec& iter_vec) { remove(iter_vecs, &iter_vec); } - - // Subsumption: + + //Touching void touch(const Var x); - void touch(const Lit p); + void touch(const Lit p, const bool learnt); + + //Used by cleaner + void unlinkClause(ClauseSimp cc, const Var elim = var_Undef); + ClauseSimp linkInClause(Clause& cl); + + //Findsubsumed template void findSubsumed(const T& ps, const uint32_t abst, vec& out_subsumed); - bool isSubsumed(Clause& ps); template - uint32_t subsume0(T& ps, uint32_t abs); + void findSubsumed1(const T& ps, uint32_t abs, vec& out_subsumed, vec& out_lits); template - uint32_t subsume0Orig(const T& ps, uint32_t abs); - bool subsumedNonLearnt; - void subsume0BIN(const Lit lit, const vec& lits); - void subsume1(ClauseSimp& ps); - void smaller_database(); - void almost_all_database(); + void fillSubs(const T& ps, uint32_t abs, vec& out_subsumed, vec& out_lits, const Lit lit); + template + bool subset(const uint32_t aSize, const T2& B); template - bool subset(const T1& A, const T2& B); + const Lit subset1(const T1& A, const T2& B); bool subsetAbst(uint32_t A, uint32_t B); - + + //binary clause-subsumption + struct BinSorter { + const 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 + { + const bool operator () (const Clause* x, const Clause* y) + { + return (x->size() < y->size()); + } + }; + void subsume0(Clause& ps); + template + subsume0Happened subsume0Orig(const T& ps, uint32_t abs); + void subsume0Touched(); + void makeNonLearntBin(const Lit lit1, const Lit lit2, const bool learnt); + + //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 clBinTouched; ///& ps, const bool wasLearnt); + void strenghten(ClauseSimp& c, const Lit toRemoveLit); + const bool cleanClause(Clause& ps); + const bool cleanClause(vec& ps) const; + void handleSize1Clause(const Lit lit); + + //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& x, const std::pair& y) { + return x.first < y.first || + (!(y.first < x.first) && x.second < y.second); + } + }; + 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& order); + const uint32_t numNonLearntBins(const Lit lit) const; bool maybeEliminate(Var x); - void MigrateToPsNs(vec& poss, vec& negs, vec& ps, vec& ns, const Var x); - void DeallocPsNs(vec& ps, vec& ns); - bool merge(const Clause& ps, const Clause& qs, const Lit without_p, const Lit without_q, vec& out_clause); + void removeClauses(vec& posAll, vec& negAll, const Var var); + void removeClausesHelper(vec& todo, const Var var, std::pair& removed); + bool merge(const ClAndBin& ps, const ClAndBin& qs, const Lit without_p, const Lit without_q, vec& out_clause); + const bool eliminateVars(); + void fillClAndBin(vec& all, vec& cs, const Lit lit); //Subsume with Nonexistent Bins - const bool subsWNonExistBinsFull(OnlyNonLearntBins* onlyNonLearntBins); - const bool subsWNonExistBins(const Lit& lit, OnlyNonLearntBins* onlyNonLearntBins); - template - void subsume1Partial(const T& ps); - uint32_t subsNonExistentNum; - uint32_t subsNonExistentumFailed; + struct BinSorter2 { + const 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; + }; + }; + const bool subsWNonExitsBinsFullFull(); + const bool subsWNonExistBinsFull(); + const bool subsWNonExistBins(const Lit& lit, OnlyNonLearntBins* OnlyNonLearntBins); + void subsume0BIN(const Lit lit, const vec& lits, const uint32_t abst); bool subsNonExistentFinish; - double subsNonExistentTime; - uint32_t subsNonExistentLitsRemoved; - vec addBinaryClauses; uint32_t doneNum; - vec subsume1PartialSubs; - vec subsume1PartialQs; - vec toVisit; - vec toVisitAll; - vec ps2; - + uint64_t extraTimeNonExist; + vec toVisit; /// toVisitAll; /// l2.occurnum; } }; - void blockedClauseRemoval(); - const bool allTautology(const vec& ps, const Lit lit); + template + const bool allTautology(const T& ps, const Lit lit); uint32_t numblockedClauseRemoved; - const bool tryOneSetting(const Lit lit, const Lit negLit); + const bool tryOneSetting(const Lit lit); priority_queue, MyComp> touchedBlockedVars; - vec touchedBlockedVarsBool; + vec touchedBlockedVarsBool; void touchBlockedVar(const Var x); - double blockTime; - - + void blockedClauseElimAll(const Lit lit); + + //validity checking - void verifyIntegrity(); - - uint32_t clauses_subsumed; - uint32_t literals_removed; - uint32_t origNClauses; - uint32_t numCalls; - bool fullSubsume; - uint32_t clauseID; + const bool verifyIntegrity(); + + uint32_t clauses_subsumed; /// @@ -198,14 +317,32 @@ void maybeRemove(vec& ws, const T2& elem) removeW(ws, elem); } +/** +@brief Put varible in touched_list + +call it when the number of occurrences of this variable changed. + +@param[in] x The varible that must be put into touched_list +*/ inline void Subsumer::touch(const Var x) { - if (!touched[x]) { - touched[x] = 1; - touched_list.push(x); + if (!touchedVars[x]) { + touchedVars[x] = 1; + touchedVarsList.push(x); } } +inline void Subsumer::touchChangeVars(const Lit p) +{ + ol_seenNeg[(~p).toInt()] = false; + ol_seenPos[p.toInt()] = false; +} + +/** +@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]) { @@ -214,44 +351,114 @@ inline void Subsumer::touchBlockedVar(const Var x) } } -inline void Subsumer::touch(const Lit p) +/** +@brief Put variable of literal in touched_list + +call it when the number of occurrences of this variable changed +*/ +inline void Subsumer::touch(const Lit p, const bool learnt) { - touch(p.var()); + if (!learnt) { + touch(p.var()); + touchBlockedVar(p.var()); + } } -inline bool Subsumer::subsetAbst(uint32_t A, uint32_t B) +/** +@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); } -// Assumes 'seen' is cleared (will leave it cleared) +//A subsumes B (A is <= B) +template +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 -bool Subsumer::subset(const T1& A, const T2& B) +const 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()]) { - for (uint32_t i = 0; i != B.size(); i++) - seen_tmp[B[i].toInt()] = 0; - return false; + 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 true; + 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); - touched .push(1); + touchedVars .push(0); 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); + touch(solver.nVars()-1); +} + +inline const map > >& Subsumer::getElimedOutVar() const +{ + return elimedOutVar; +} + +inline const map > >& Subsumer::getElimedOutVarBin() const +{ + return elimedOutVarBin; } inline const vec& Subsumer::getVarElimed() const @@ -269,6 +476,4 @@ inline const double Subsumer::getTotalTime() const return totalTime; } -}; //NAMESPACE MINISAT - #endif //SIMPLIFIER_H diff --git a/src/sat/cryptominisat2/UselessBinRemover.cpp b/src/sat/cryptominisat2/UselessBinRemover.cpp index 56fb654..4014df8 100644 --- a/src/sat/cryptominisat2/UselessBinRemover.cpp +++ b/src/sat/cryptominisat2/UselessBinRemover.cpp @@ -1,4 +1,4 @@ -/*********************************************************************************** +/*************************************************************************** CryptoMiniSat -- Copyright (c) 2009 Mate Soos This program is free software: you can redistribute it and/or modify @@ -13,28 +13,36 @@ 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 . -**************************************************************************************************/ +****************************************************************************/ #include #include "UselessBinRemover.h" #include "VarReplacer.h" #include "ClauseCleaner.h" #include "time_mem.h" -#include "OnlyNonLearntBins.h" -namespace MINISAT -{ -using namespace MINISAT; +//#define VERBOSE_DEBUG -UselessBinRemover::UselessBinRemover(Solver& _solver, OnlyNonLearntBins& _onlyNonLearntBins) : +UselessBinRemover::UselessBinRemover(Solver& _solver) : solver(_solver) - , onlyNonLearntBins(_onlyNonLearntBins) { } +/** +@brief Time limiting +*/ #define MAX_REMOVE_BIN_FULL_PROPS 20000000 -#define EXTRATIME_DIVIDER 2 +/** +@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" +*/ const bool UselessBinRemover::removeUslessBinFull() { double myTime = cpuTime(); @@ -43,7 +51,9 @@ const bool UselessBinRemover::removeUslessBinFull() uint32_t origHeapSize = solver.order_heap.size(); uint64_t origProps = solver.propagations; bool fixed = false; - uint32_t extraTime = solver.binaryClauses.size() / EXTRATIME_DIVIDER; + 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++) { @@ -54,7 +64,7 @@ const bool UselessBinRemover::removeUslessBinFull() Lit lit(var, true); if (!removeUselessBinaries(lit)) { fixed = true; - solver.cancelUntil(0); + solver.cancelUntilLight(); solver.uncheckedEnqueue(~lit); solver.ok = (solver.propagate().isNULL()); if (!solver.ok) return false; @@ -64,7 +74,7 @@ const bool UselessBinRemover::removeUslessBinFull() lit = ~lit; if (!removeUselessBinaries(lit)) { fixed = true; - solver.cancelUntil(0); + solver.cancelUntilLight(); solver.uncheckedEnqueue(~lit); solver.ok = (solver.propagate().isNULL()); if (!solver.ok) return false; @@ -72,27 +82,40 @@ const bool UselessBinRemover::removeUslessBinFull() } } - uint32_t removedUselessBin = onlyNonLearntBins.removeBins(); - if (fixed) solver.order_heap.filter(Solver::VarFilter(solver)); - if (solver.verbosity >= 1) { + if (solver.conf.verbosity >= 1) { std::cout - << "c Removed useless bin:" << std::setw(8) << removedUselessBin + << "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::setw(16) << " |" << std::endl; + << std::endl; } return true; } -const bool UselessBinRemover::removeUselessBinaries(const Lit& lit) +/** +@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. +*/ +const bool UselessBinRemover::removeUselessBinaries(const Lit lit) { solver.newDecisionLevel(); solver.uncheckedEnqueueLight(lit); - failed = !onlyNonLearntBins.propagateBinOneLevel(); + //Propagate only one hop + failed = !solver.propagateBinOneLevel(); if (failed) return false; bool ret = true; @@ -100,9 +123,10 @@ const bool UselessBinRemover::removeUselessBinaries(const Lit& lit) assert(solver.decisionLevel() > 0); int c; if (solver.trail.size()-solver.trail_lim[0] == 0) { - solver.cancelUntil(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]; @@ -118,6 +142,8 @@ const bool UselessBinRemover::removeUselessBinaries(const Lit& lit) //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' @@ -141,40 +167,43 @@ const bool UselessBinRemover::removeUselessBinaries(const Lit& lit) return ret; } -void UselessBinRemover::removeBin(const Lit& lit1, const Lit& lit2) -{ - /******************* - Lit litFind1 = lit_Undef; - Lit litFind2 = lit_Undef; - - if (solver.binwatches[(~lit1).toInt()].size() < solver.binwatches[(~lit2).toInt()].size()) { - litFind1 = lit1; - litFind2 = lit2; - } else { - litFind1 = lit2; - litFind2 = lit1; - } - ********************/ +/** +@brief Removes a binary clause (lit1 V lit2) - //Find AND remove from watches +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.print(); lit2.printFull(); + std::cout << "Removing useless bin: " << lit1 << " " << lit2 << std::endl; #endif //VERBOSE_DEBUG - - solver.removeWatchedBinClAll(solver.binwatches[(~lit1).toInt()], lit2); - solver.removeWatchedBinClAll(solver.binwatches[(~lit2).toInt()], lit1); - onlyNonLearntBins.removeBin(lit1, lit2); + + std::pair removed1 = removeWBinAll(solver.watches[(~lit1).toInt()], lit2); + std::pair 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; } -const bool UselessBinRemover::fillBinImpliesMinusLast(const Lit& origLit, const Lit& lit, vec& wrong) +/** +@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 +*/ +const bool UselessBinRemover::fillBinImpliesMinusLast(const Lit origLit, const Lit lit, vec& wrong) { solver.newDecisionLevel(); solver.uncheckedEnqueueLight(lit); //if it's a cycle, it doesn't work, so don't propagate origLit - failed = !onlyNonLearntBins.propagateBinExcept(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; @@ -187,13 +216,12 @@ const bool UselessBinRemover::fillBinImpliesMinusLast(const Lit& origLit, const 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; } -}; //NAMESPACE MINISAT diff --git a/src/sat/cryptominisat2/UselessBinRemover.h b/src/sat/cryptominisat2/UselessBinRemover.h index 771bd1b..6670aaf 100644 --- a/src/sat/cryptominisat2/UselessBinRemover.h +++ b/src/sat/cryptominisat2/UselessBinRemover.h @@ -20,34 +20,62 @@ along with this program. If not, see . #include "Vec.h" #include "Solver.h" -#include "OnlyNonLearntBins.h" +#ifdef _MSC_VER +#include +#else #include +#endif //_MSC_VER -namespace MINISAT -{ -using namespace MINISAT; +/** +@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, OnlyNonLearntBins& onlyNonLearntBins); + UselessBinRemover(Solver& solver); const bool removeUslessBinFull(); - + private: - bool failed; - uint32_t extraTime; - + bool failed; ///& wrong); - const bool removeUselessBinaries(const Lit& lit); - void removeBin(const Lit& lit1, const Lit& lit2); + const bool fillBinImpliesMinusLast(const Lit origLit, const Lit lit, vec& wrong); + const 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 toDeleteSet; - vec oneHopAway; + vec oneHopAway; /// wrong; - Solver& solver; - OnlyNonLearntBins& onlyNonLearntBins; + Solver& solver; ///. -**************************************************************************************************/ +******************************************************************************/ #include "VarReplacer.h" #include #include +#include #include "ClauseCleaner.h" #include "PartHandler.h" #include "time_mem.h" +#include "DataSync.h" //#define VERBOSE_DEBUG //#define DEBUG_REPLACER //#define REPLACE_STATISTICS +//#define DEBUG_BIN_REPLACER #ifdef VERBOSE_DEBUG #include @@ -33,10 +36,6 @@ using std::cout; using std::endl; #endif -namespace MINISAT -{ -using namespace MINISAT; - VarReplacer::VarReplacer(Solver& _solver) : replacedLits(0) , replacedVars(0) @@ -47,63 +46,74 @@ VarReplacer::VarReplacer(Solver& _solver) : VarReplacer::~VarReplacer() { - for (uint i = 0; i != clauses.size(); i++) - solver.clauseAllocator.clauseFree(clauses[i]); } +/** +@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 +*/ const bool VarReplacer::performReplaceInternal() { #ifdef VERBOSE_DEBUG - cout << "Replacer started." << endl; + cout << "PerformReplacInternal started." << endl; + //solver.printAllClauses(); #endif double time = cpuTime(); - + #ifdef REPLACE_STATISTICS - uint numRedir = 0; - for (uint i = 0; i < table.size(); i++) { + 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; - /*map >::iterator it = reverseTable.begin(); - map >::iterator end = reverseTable.end(); - for (;it != end; it++) { - std::cout << "Tree size: " << it->second.size() << 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 { - uint i = 0; + uint32_t i = 0; for (vector::const_iterator it = table.begin(); it != table.end(); it++, i++) { if (it->var() == i) continue; - cout << "Replacing var " << i+1 << " with Lit " << (it->sign() ? "-" : "") << it->var()+1 << endl; + cout << "Replacing var " << i+1 << " with Lit " << *it << endl; } } #endif - + Var var = 0; - const vec* removedVars = solver.doXorSubsumption ? &solver.xorSubsumer->getVarElimed() : NULL; - const vec* removedVars2 = solver.doPartHandler ? &solver.partHandler->getSavedState() : NULL; - const vec* removedVars3 = solver.doSubsumption ? &solver.subsumer->getVarElimed() : NULL; + const vec& removedVars = solver.xorSubsumer->getVarElimed(); + const vec& removedVars2 = solver.partHandler->getSavedState(); + const vec& removedVars3 = solver.subsumer->getVarElimed(); for (vector::const_iterator it = table.begin(); it != table.end(); it++, var++) { if (it->var() == var - || (removedVars != NULL && (*removedVars)[it->var()]) - || (removedVars2 != NULL && (*removedVars2)[it->var()] != l_Undef) - || (removedVars3!= NULL && (*removedVars3)[it->var()]) + || removedVars[it->var()] + || removedVars2[it->var()] != l_Undef + || 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(removedVars2[var] == l_Undef); + assert(!removedVars3[var]); + uint32_t& activity1 = solver.activity[var]; uint32_t& activity2 = solver.activity[it->var()]; if (wasDecisionVar && activity1 > activity2) { @@ -111,70 +121,80 @@ const bool VarReplacer::performReplaceInternal() solver.order_heap.update(it->var()); solver.polarity[it->var()] = solver.polarity[var]^it->sign(); } - + activity1 = 0.0; solver.order_heap.update(var); } assert(solver.order_heap.heapProperty()); - - if (solver.verbosity >= 2) - std::cout << "c | Replacing " << std::setw(8) << replacedVars-lastReplacedVars << " vars" << std::flush; - + + uint32_t thisTimeReplaced = replacedVars -lastReplacedVars; lastReplacedVars = replacedVars; - + solver.testAllClauseAttach(); - if (!replace_set(solver.binaryClauses, true)) goto end; - if (!replace_set(solver.clauses, false)) goto end; - if (!replace_set(solver.learnts, false)) goto end; + 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: - for (uint i = 0; i != clauses.size(); i++) - solver.removeClause(*clauses[i]); - clauses.clear(); - - if (solver.verbosity >= 2) { - std::cout << " Replaced " << std::setw(8) << replacedLits<< " lits" - << " Time: " << std::setw(8) << std::fixed << std::setprecision(2) << cpuTime()-time << " s " - << std::setw(10) << " |" << std::endl; + assert(solver.qhead == solver.trail.size() || !solver.ok); + + if (solver.conf.verbosity >= 2) { + 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 +*/ const bool VarReplacer::replace_set(vec& 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()); - c.setVarChanged(); 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 { @@ -182,13 +202,16 @@ const bool VarReplacer::replace_set(vec& cs) } } cs.shrink(r-a); - + return solver.ok; } +/** +@brief Helper function for replace_set() +*/ const bool VarReplacer::handleUpdatedClause(XorClause& c, const Var origVar1, const Var origVar2) { - uint origSize = c.size(); + uint32_t origSize = c.size(); std::sort(c.getData(), c.getDataEnd()); Lit p; uint32_t i, j; @@ -201,31 +224,33 @@ const bool VarReplacer::handleUpdatedClause(XorClause& c, const Var origVar1, co 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 xor_clause_inverted instead of adding + else c.invert(solver.assigns[c[i].var()].getBool()); //modify xorEqualFalse instead of adding } c.shrink(i - j); - + c.setStrenghtened(); + #ifdef VERBOSE_DEBUG cout << "xor-clause after replacing: "; c.plainPrint(); #endif - + switch (c.size()) { case 0: solver.detachModifiedClause(origVar1, origVar2, origSize, &c); - if (!c.xor_clause_inverted()) + if (!c.xorEqualFalse()) { solver.ok = false; + } return true; case 1: solver.detachModifiedClause(origVar1, origVar2, origSize, &c); - solver.uncheckedEnqueue(Lit(c[0].var(), c.xor_clause_inverted())); + solver.uncheckedEnqueue(Lit(c[0].var(), c.xorEqualFalse())); solver.ok = (solver.propagate().isNULL()); return true; case 2: { solver.detachModifiedClause(origVar1, origVar2, origSize, &c); - c[0] = c[0].unsign(); + c[0] = c[0].unsign() ^ c.xorEqualFalse(); c[1] = c[1].unsign(); - addBinaryXorClause(c, c.xor_clause_inverted(), c.getGroup(), true); + addBinaryXorClause(c[0], c[1], c.getGroup()); return true; } default: @@ -233,59 +258,162 @@ const bool VarReplacer::handleUpdatedClause(XorClause& c, const Var origVar1, co solver.attachClause(c); return false; } - + assert(false); return false; } -const bool VarReplacer::replace_set(vec& cs, const bool binClauses) +const bool VarReplacer::replaceBins() +{ + #ifdef DEBUG_BIN_REPLACER + vec removed(solver.nVars()*2, 0); + uint32_t replacedLitsBefore = replacedLits; + #endif + + uint32_t removedLearnt = 0; + uint32_t removedNonLearnt = 0; + uint32_t wsLit = 0; + for (vec *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit1 = ~Lit::toLit(wsLit); + vec& ws = *it; + + Watched *i = ws.getData(); + Watched *j = i; + for (Watched *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(); + Lit origLit2 = lit2; + 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().isNULL()); + return solver.ok; +} + +/** +@brief Replaces variables in normal clauses +*/ +const bool VarReplacer::replace_set(vec& 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(); - c.setVarChanged(); replacedLits++; } } - - if (changed && handleUpdatedClause(c, origLit1, origLit2)) { + + 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 { - if (!binClauses && c.size() == 2) { - solver.detachClause(c); - Clause *c2 = solver.clauseAllocator.Clause_new(c); - solver.clauseAllocator.clauseFree(&c); - solver.attachClause(*c2); - solver.becameBinary++; - solver.binaryClauses.push(c2); - } else - *a++ = *r; + *a++ = *r; } } cs.shrink(r-a); - + return solver.ok; } -const bool VarReplacer::handleUpdatedClause(Clause& c, const Lit origLit1, const Lit origLit2) +/** +@brief Helper function for replace_set() +*/ +const 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 uint origSize = c.size(); + 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; @@ -295,59 +423,79 @@ const bool VarReplacer::handleUpdatedClause(Clause& c, const Lit origLit1, const c[j++] = p = c[i]; } c.shrink(i - j); - - if (satisfied) { - solver.detachModifiedClause(origLit1, origLit2, origSize, &c); - return true; + c.setStrenghtened(); + + if (!c.learnt()) { + for (Lit *i2 = c.getData(), *end2 = c.getDataEnd(); i2 != end2; i2++) + solver.subsumer->touchChangeVars(*i2); } - + + 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.detachModifiedClause(origLit1, origLit2, origSize, &c); solver.ok = false; return true; case 1 : - solver.detachModifiedClause(origLit1, origLit2, origSize, &c); solver.uncheckedEnqueue(c[0]); solver.ok = (solver.propagate().isNULL()); return true; + case 2: + solver.attachBinClause(c[0], c[1], c.learnt()); + solver.numNewBin++; + solver.dataSync->signalNewBinClause(c); + return true; default: - solver.detachModifiedClause(origLit1, origLit2, origSize, &c); solver.attachClause(c); - return false; } - + assert(false); return false; } +/** +@brief Returns variables that have been replaced +*/ const vector VarReplacer::getReplacingVars() const { vector replacingVars; - + for(map >::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 - uint i = 0; + uint32_t i = 0; for (vector::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); @@ -361,27 +509,34 @@ void VarReplacer::extendModelPossible() const } } +/** +@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 tmpClause; - uint i = 0; + uint32_t i = 0; for (vector::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)); @@ -391,121 +546,141 @@ void VarReplacer::extendModelImpossible(Solver& solver2) const } } +/** +@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 -const bool VarReplacer::replace(T& ps, const bool xor_clause_inverted, const uint group) +const bool VarReplacer::replace(T& ps, const bool xorEqualFalse, const uint32_t group) { #ifdef VERBOSE_DEBUG - std::cout << "replace() called with var " << ps[0].var()+1 << " and var " << ps[1].var()+1 << " with xor_clause_inverted " << xor_clause_inverted << std::endl; + 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 - - - Var var = ps[0].var(); - Lit lit = Lit(ps[1].var(), !xor_clause_inverted); - assert(var != lit.var()); - + //Detect circle - if (alreadyIn(var, lit)) return solver.ok; - - Lit lit1 = table[var]; - bool inverted = false; - - //This pointer is already set, try to invert - if (lit1.var() != var) { - Var tmp_var = var; - - var = lit.var(); - lit = Lit(tmp_var, lit.sign()); - inverted = true; - } - - if (inverted) { - Lit lit2 = table[var]; - - //Inversion is also set, triangular cycle - //A->B, A->C, B->C. There is nothing to add - if (lit1.var() == lit2.var()) { - if ((lit1.sign() ^ lit2.sign()) != lit.sign()) { - #ifdef VERBOSE_DEBUG - cout << "Inverted cycle in var-replacement -> UNSAT" << endl; - #endif - return (solver.ok = false); - } - return true; + 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; } - - //Inversion is also set - if (lit2.var() != var) { - assert(table[lit1.var()].var() == lit1.var()); - setAllThatPointsHereTo(lit1.var(), Lit(lit.var(), lit1.sign())); - - assert(table[lit2.var()].var() == lit2.var()); - setAllThatPointsHereTo(lit2.var(), lit ^ lit2.sign()); - - table[lit.var()] = Lit(lit.var(), false); - replacedVars++; - addBinaryXorClause(ps, xor_clause_inverted, group); - return true; + 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().isNULL()); + return solver.ok; + } + + #ifdef DEBUG_REPLACER + assert(val1 == l_Undef && val2 == l_Undef); + #endif //DEBUG_REPLACER + + addBinaryXorClause(lit1, lit2 ^ true, group, false); + + 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; } - - //Follow forwards - Lit litX = table[lit.var()]; - if (litX.var() != lit.var()) - lit = litX ^ lit.sign(); - - //Follow backwards - setAllThatPointsHereTo(var, lit); + + //both have children + setAllThatPointsHereTo(lit1.var(), lit2 ^ lit1.sign()); //erases reverseTable[lit1.var()] replacedVars++; - addBinaryXorClause(ps, xor_clause_inverted, group); - return true; } -template const bool VarReplacer::replace(vec& ps, const bool xor_clause_inverted, const uint group); -template const bool VarReplacer::replace(XorClause& ps, const bool xor_clause_inverted, const uint group); +template const bool VarReplacer::replace(vec& ps, const bool xorEqualFalse, const uint32_t group); +template const bool VarReplacer::replace(XorClause& ps, const bool xorEqualFalse, const uint32_t group); -template -void VarReplacer::addBinaryXorClause(T& ps, const bool xor_clause_inverted, const uint group, const bool internal) +/** +@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 uint32_t group, const bool addBinAsLearnt) { - assert(internal || (replacedVars > lastReplacedVars)); - #ifdef DEBUG_REPLACER - assert(!ps[0].sign()); - assert(!ps[1].sign()); - #endif - - Clause* c; - ps[0] ^= xor_clause_inverted; - - c = solver.clauseAllocator.Clause_new(ps, group, false); - if (internal) { - solver.binaryClauses.push(c); - solver.becameBinary++; - } else - clauses.push(c); - solver.attachClause(*c); - - ps[0] ^= true; - ps[1] ^= true; - c = solver.clauseAllocator.Clause_new(ps, group, false); - if (internal) { - solver.binaryClauses.push(c); - solver.becameBinary++; - } else - clauses.push(c); - solver.attachClause(*c); + solver.attachBinClause(lit1, lit2, addBinAsLearnt); + solver.dataSync->signalNewBinClause(lit1, lit2); + + lit1 ^= true; + lit2 ^= true; + solver.attachBinClause(lit1, lit2, addBinAsLearnt); + solver.dataSync->signalNewBinClause(lit1, lit2); } -template void VarReplacer::addBinaryXorClause(vec& ps, const bool xor_clause_inverted, const uint group, const bool internal); -template void VarReplacer::addBinaryXorClause(XorClause& ps, const bool xor_clause_inverted, const uint group, const bool internal); +/** +@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]; @@ -518,7 +693,7 @@ bool VarReplacer::alreadyIn(const Var var, const Lit lit) } return true; } - + lit2 = table[lit.var()]; if (lit2.var() == var) { if (lit2.sign() != lit.sign()) { @@ -529,10 +704,13 @@ bool VarReplacer::alreadyIn(const Var var, const Lit lit) } 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 >::iterator it = reverseTable.find(var); @@ -553,20 +731,5 @@ void VarReplacer::setAllThatPointsHereTo(const Var var, const Lit lit) void VarReplacer::newVar() { table.push_back(Lit(table.size(), false)); + cannot_eliminate.push(false); } - -void VarReplacer::reattachInternalClauses() -{ - Clause **i = clauses.getData(); - Clause **j = i; - for (Clause **end = clauses.getDataEnd(); i != end; i++) { - if (solver.value((**i)[0]) == l_Undef && - solver.value((**i)[1]) == l_Undef) { - solver.attachClause(**i); - *j++ = *i; - } - } - clauses.shrink(i-j); -} - -}; //NAMESPACE MINISAT diff --git a/src/sat/cryptominisat2/VarReplacer.h b/src/sat/cryptominisat2/VarReplacer.h index 4d54d9d..eebee76 100644 --- a/src/sat/cryptominisat2/VarReplacer.h +++ b/src/sat/cryptominisat2/VarReplacer.h @@ -34,10 +34,9 @@ using std::vector; #include "Clause.h" #include "Vec.h" -namespace MINISAT -{ -using namespace MINISAT; - +/** +@brief Replaces variables with their anti/equivalents +*/ class VarReplacer { public: @@ -46,49 +45,48 @@ class VarReplacer const bool performReplace(const bool always = false); const bool needsReplace(); template - const bool replace(T& ps, const bool xor_clause_inverted, const uint group); - + const bool replace(T& ps, const bool xorEqualFalse, const uint32_t group); + void extendModelPossible() const; void extendModelImpossible(Solver& solver2) const; - void reattachInternalClauses(); - - const uint getNumReplacedLits() const; - const uint getNumReplacedVars() const; - const uint getNumLastReplacedVars() const; - const uint getNewToReplaceVars() const; + + const uint32_t getNumReplacedLits() const; + const uint32_t getNumReplacedVars() const; + const uint32_t getNumLastReplacedVars() const; + const uint32_t getNewToReplaceVars() const; const uint32_t getNumTrees() const; const vector getReplacingVars() const; const vector& getReplaceTable() const; - const vec& getClauses() const; const bool varHasBeenReplaced(const Var var) const; const bool replacingVar(const Var var) const; void newVar(); + vec cannot_eliminate; + //No need to update, only stores binary clauses, that //have been allocated within pool //friend class ClauseAllocator; - + private: const bool performReplaceInternal(); - - const bool replace_set(vec& cs, const bool binClauses); + + const bool replace_set(vec& cs); + const bool replaceBins(); const bool replace_set(vec& cs); - const bool handleUpdatedClause(Clause& c, const Lit origLit1, const Lit origLit2); + const bool handleUpdatedClause(Clause& c, const Lit origLit1, const Lit origLit2, const Lit origLit3); const bool handleUpdatedClause(XorClause& c, const Var origVar1, const Var origVar2); - template - void addBinaryXorClause(T& ps, const bool xor_clause_inverted, const uint group, const bool internal = false); - + void addBinaryXorClause(Lit lit1, Lit lit2, const uint32_t group, const bool addBinAsLearnt = false); + void setAllThatPointsHereTo(const Var var, const Lit lit); bool alreadyIn(const Var var, const Lit lit); - - vector table; - map > reverseTable; - vec clauses; - - uint replacedLits; - uint replacedVars; - uint lastReplacedVars; - Solver& solver; + + vector table; /// > reverseTable; /// 0) || getNewToReplaceVars() > limit) return performReplaceInternal(); - + return true; } @@ -107,22 +105,22 @@ inline const bool VarReplacer::needsReplace() return (getNewToReplaceVars() > limit); } -inline const uint VarReplacer::getNumReplacedLits() const +inline const uint32_t VarReplacer::getNumReplacedLits() const { return replacedLits; } -inline const uint VarReplacer::getNumReplacedVars() const +inline const uint32_t VarReplacer::getNumReplacedVars() const { return replacedVars; } -inline const uint VarReplacer::getNumLastReplacedVars() const +inline const uint32_t VarReplacer::getNumLastReplacedVars() const { return lastReplacedVars; } -inline const uint VarReplacer::getNewToReplaceVars() const +inline const uint32_t VarReplacer::getNewToReplaceVars() const { return replacedVars-lastReplacedVars; } @@ -132,11 +130,6 @@ inline const vector& VarReplacer::getReplaceTable() const return table; } -inline const vec& VarReplacer::getClauses() const -{ - return clauses; -} - inline const bool VarReplacer::varHasBeenReplaced(const Var var) const { return table[var].var() != var; @@ -152,6 +145,4 @@ inline const uint32_t VarReplacer::getNumTrees() const return reverseTable.size(); } -}; //NAMESPACE MINISAT - #endif //VARREPLACER_H diff --git a/src/sat/cryptominisat2/Watched.h b/src/sat/cryptominisat2/Watched.h new file mode 100644 index 0000000..cd150f8 --- /dev/null +++ b/src/sat/cryptominisat2/Watched.h @@ -0,0 +1,264 @@ +/*************************************************************************** +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 . +*****************************************************************************/ + +#ifndef WATCHED_H +#define WATCHED_H + +#ifdef _MSC_VER +#include +#else +#include +#endif //_MSC_VER + +//#define DEBUG_WATCHED + +#include "ClauseOffset.h" +#include "SolverTypes.h" +#include +#include "constants.h" + +/** +@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); + } + + /** + @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(); + } + + const bool isBinary() const + { + return ((data2&3) == 0); + } + + const bool isNonLearntBinary() const + { + return (data2 == 0); + } + + const bool isClause() const + { + return ((data2&3) == 1); + } + + const bool isXorClause() const + { + return ((data2&3) == 2); + } + + const bool isTriClause() const + { + return ((data2&3) == 3); + } + + /** + @brief Get the sole other lit of the binary clause, or get lit2 of the tertiary clause + */ + const 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(); + } + + const 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 + */ + const Lit getOtherLit2() const + { + #ifdef DEBUG_WATCHED + assert(isTriClause()); + #endif + return data2AsLit(); + } + + /** + @brief Get example literal (blocked lit) of a normal >3-long clause + */ + const 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) + */ + const ClauseOffset getNormOffset() const + { + #ifdef DEBUG_WATCHED + assert(isClause()); + #endif + return (ClauseOffset)(data2 >> 2); + } + + const 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; + } + + private: + const Lit data1AsLit() const + { + return (Lit::toLit(data1)); + } + + const 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/sat/cryptominisat2/XSet.h b/src/sat/cryptominisat2/XSet.h index 13fb315..b898aa4 100644 --- a/src/sat/cryptominisat2/XSet.h +++ b/src/sat/cryptominisat2/XSet.h @@ -13,10 +13,6 @@ From: Solver.C -- (C) Niklas Een, Niklas Sorensson, 2004 #include #endif //_MSC_VER -namespace MINISAT -{ -using namespace MINISAT; - class XorClause; template @@ -131,6 +127,5 @@ class XSet { } }; -}; //NAMESPACE MINISAT - #endif //XSET_H + diff --git a/src/sat/cryptominisat2/XorFinder.cpp b/src/sat/cryptominisat2/XorFinder.cpp index 13c1e65..e7983d4 100644 --- a/src/sat/cryptominisat2/XorFinder.cpp +++ b/src/sat/cryptominisat2/XorFinder.cpp @@ -36,129 +36,70 @@ using std::cout; using std::endl; #endif -namespace MINISAT -{ -using namespace MINISAT; - using std::make_pair; -XorFinder::XorFinder(Solver& _solver, vec& _cls, ClauseCleaner::ClauseSetType _type) : +XorFinder::XorFinder(Solver& _solver, vec& _cls) : cls(_cls) - , type(_type) , solver(_solver) { } -const bool XorFinder::doNoPart(const uint minSize, const uint maxSize) +const bool XorFinder::fullFindXors(const uint32_t minSize, const uint32_t maxSize) { - uint sumLengths = 0; + uint32_t sumLengths = 0; double time = cpuTime(); foundXors = 0; solver.clauseCleaner->cleanClauses(solver.clauses, ClauseCleaner::clauses); - if (type == ClauseCleaner::binaryClauses) { - solver.clauseCleaner->cleanClauses(solver.binaryClauses, ClauseCleaner::binaryClauses); - } 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()); - - ClauseTable unsortedTable; - unsortedTable.reserve(cls.size()); - ClauseTable sortedTable; - sortedTable.reserve(cls.size()); - - for (Clause **it = cls.getData(), **end = it + cls.size(); it != end; it ++) { - if (it+1 != end) - __builtin_prefetch(*(it+1), 0); - //if ((**it)[0].toInt() < (**it)[1].toInt()) - // std::swap((**it)[0], (**it)[1]); + + for (Clause **it = cls.getData(), **end = cls.getDataEnd(); it != end; it ++) { + if (it+1 != end) __builtin_prefetch(*(it+1), 0); Clause& c = (**it); - if ((*it)->size() != 2) { - bool sorted = true; - for (uint 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); - } - } else { - std::sort(c.getData(), c.getData()+c.size()); + 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); } } - - uint i = 0; - for (Clause **it = cls.getData(), **end = it + cls.size(); it != end; it++, i++) { - const uint size = (*it)->size(); + + 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; } - if ((*it)->getSorted()) sortedTable.push_back(make_pair(*it, i)); - else unsortedTable.push_back(make_pair(*it, i)); - } - - clause_sorter_primary sorter; - - std::sort(unsortedTable.begin(), unsortedTable.end(), clause_sorter_primary()); - //std::sort(sortedTable.begin(), sortedTable.end(), clause_sorter_primary()); - #ifdef DEBUG_XORFIND - for (uint i = 0; i+1 < unsortedTable.size(); i++) { - assert(!sorter(unsortedTable[i+1], unsortedTable[i])); - } - for (uint i = 0; i+1 < sortedTable.size(); i++) { - assert(!sorter(sortedTable[i+1], sortedTable[i])); - } - #endif //DEBUG_XORFIND - - for (uint i = 0, j = 0; i < unsortedTable.size() || j < sortedTable.size();) { - if (j == sortedTable.size()) { - table.push_back(unsortedTable[i++]); - continue; - } - if (i == unsortedTable.size()) { - table.push_back(sortedTable[j++]); - continue; - } - if (sorter(unsortedTable[i], sortedTable[j])) { - table.push_back(unsortedTable[i++]); - } else { - table.push_back(sortedTable[j++]); - } - } - #ifdef DEBUG_XORFIND - for (uint i = 0; i+1 < table.size(); i++) { - assert(!sorter(table[i+1], table[i])); - //table[i].first->plainPrint(); + table.push_back(make_pair(*it, i)); } - #endif //DEBUG_XORFIND - - if (findXors(sumLengths) == false) goto end; + std::sort(table.begin(), table.end(), clause_sorter_primary()); + + if (!findXors(sumLengths)) goto end; solver.ok = (solver.propagate().isNULL()); - + end: - if (minSize == maxSize && minSize == 2) { - if (solver.verbosity >= 2 || (solver.conflicts == 0 && solver.verbosity >= 1)) { - printf("c | Finding binary XORs: %5.2lf s (found: %7d, avg size: %3.1lf) |\n", cpuTime()-time, foundXors, (double)sumLengths/(double)foundXors); - } - } else { - if (solver.verbosity >= 2 || (solver.verbosity >= 1 && foundXors > 0)) { - printf("c | Finding non-binary XORs: %5.2lf s (found: %7d, avg size: %3.1lf) |\n", cpuTime()-time, foundXors, (double)sumLengths/(double)foundXors); - } + + if (solver.conf.verbosity >= 1 || (solver.conf.verbosity >= 1 && foundXors > 0)) { + printf("c Finding non-binary XORs: %5.2lf s (found: %7d, avg size: %3.1lf)\n", cpuTime()-time, foundXors, (double)sumLengths/(double)foundXors); } - + i = 0; uint32_t j = 0; uint32_t toSkip = 0; - for (uint end = cls.size(); i != end; i++) { + for (uint32_t end = cls.size(); i != end; i++) { if (toLeaveInPlace[i]) { cls[j] = cls[i]; j++; @@ -166,24 +107,30 @@ end: continue; } if (!toRemove[table[i-toSkip].second]) { - table[i-toSkip].first->setSorted(); cls[j] = table[i-toSkip].first; j++; } } cls.shrink(i-j); - + return solver.ok; } -const bool XorFinder::findXors(uint& sumLengths) + +/** +@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. +*/ +const 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 lits; @@ -194,68 +141,46 @@ const bool XorFinder::findXors(uint& sumLengths) for (const Lit *it = &c[0], *cend = it+c.size() ; it != cend; it++) { lits.push(Lit(it->var(), false)); } - uint old_group = c.getGroup(); - + uint32_t old_group = c.getGroup(); + #ifdef VERBOSE_DEBUG cout << "- Found clauses:" << endl; #endif - - for (ClauseTable::iterator it = begin; it != end; it++) + + 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); - } - - switch(lits.size()) { - case 2: { - solver.varReplacer->replace(lits, impair, old_group); - - #ifdef VERBOSE_DEBUG - XorClause* x = XorClause_new(lits, impair, old_group); - cout << "- Final 2-long xor-clause: "; - x->plainPrint(); - clauseFree(x); - #endif - break; - } - default: { - XorClause* x = solver.clauseAllocator.XorClause_new(lits, impair, old_group); - solver.xorclauses.push(x); - solver.attachClause(*x); - - #ifdef VERBOSE_DEBUG - cout << "- Final xor-clause: "; - x->plainPrint(); - #endif - } + #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, old_group); + 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; } -void XorFinder::clearToRemove() -{ - assert(toRemove.size() == cls.size()); - - Clause **a = cls.getData(); - Clause **r = cls.getData(); - Clause **cend = cls.getData() + cls.size(); - for (uint i = 0; r != cend; i++) { - if (!toRemove[i]) - *a++ = *r++; - else - r++; - } - cls.shrink(r-a); -} +/** +@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(); @@ -271,48 +196,66 @@ bool XorFinder::getNextXor(ClauseTable::iterator& begin, ClauseTable::iterator& 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 (uint i = 0, size = c1.size(); i < size; i++) + 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 { - uint num = 0; + 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 uint requiredSize = 1 << (begin->first->size()-1); - - if (size < requiredSize) - return false; - + 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 vars; Clause& c = *begin->first; - for (uint i = 0; i < c.size(); i++) + 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 (uint i = 0; i < c.size(); i++) + 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++; @@ -321,41 +264,51 @@ bool XorFinder::isXor(const uint32_t size, const ClauseTable::iterator& begin, c } } #endif //DEBUG_XORFIND - + + //We now sort them according to literal content std::sort(begin, end, clause_sorter_secondary()); - - uint numPair = 0; - uint numImpair = 0; + + 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; } -void XorFinder::countImpairs(const ClauseTable::iterator& begin, const ClauseTable::iterator& end, uint& numImpair, uint& numPair) const +/** +@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); @@ -367,6 +320,16 @@ void XorFinder::countImpairs(const ClauseTable::iterator& begin, const ClauseTab } } +/** +@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; @@ -382,41 +345,46 @@ void XorFinder::addAllXorAsNorm() solver.removeClause(**i); } solver.xorclauses.shrink(i-j); - if (solver.verbosity >= 1) { - std::cout << "c | Added XOR as norm:" << added << std::endl; + 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 vars; vec vars2(c.size()); - const bool inverted = c.xor_clause_inverted(); - + 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); tmp = solver.addClauseInt(vars2, c.getGroup()); 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); tmp = solver.addClauseInt(vars2, c.getGroup()); 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); tmp = solver.addClauseInt(vars2, c.getGroup()); 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); @@ -424,67 +392,72 @@ void XorFinder::addXorAsNormal3(XorClause& c) 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 vars; vec vars2(c.size()); - const bool inverted = !c.xor_clause_inverted(); - + 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, c.getGroup()); 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, c.getGroup()); 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, c.getGroup()); 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, c.getGroup()); 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, c.getGroup()); 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, c.getGroup()); 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, c.getGroup()); 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); @@ -493,5 +466,3 @@ void XorFinder::addXorAsNormal4(XorClause& c) if (tmp) solver.clauses.push(tmp); } - -}; //NAMESPACE MINISAT diff --git a/src/sat/cryptominisat2/XorFinder.h b/src/sat/cryptominisat2/XorFinder.h index 038afa0..c038b09 100644 --- a/src/sat/cryptominisat2/XorFinder.h +++ b/src/sat/cryptominisat2/XorFinder.h @@ -35,113 +35,119 @@ class Solver; using std::pair; -namespace MINISAT -{ -using namespace MINISAT; - +/** +@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& cls, ClauseCleaner::ClauseSetType _type); - const bool doNoPart(const uint minSize, const uint maxSize); + XorFinder(Solver& _solver, vec& cls); + const bool fullFindXors(const uint32_t minSize, const uint32_t maxSize); void addAllXorAsNorm(); - + private: - typedef vector > ClauseTable; - - const bool findXors(uint& sumLengths); + typedef vector > ClauseTable; + + const bool findXors(uint32_t& sumLengths); bool getNextXor(ClauseTable::iterator& begin, ClauseTable::iterator& end, bool& impair); - - struct clause_hasher { - size_t operator()(const Clause* c) const - { - size_t hash = 5381; - hash = ((hash << 5) + hash) ^ c->size(); - for (uint i = 0, size = c->size(); i < size; i++) - hash = ((hash << 5) + hash) ^ (*c)[i].var(); - - return hash; - } - }; - + + /** + @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& c11, const pair& c22) + bool operator()(const pair& c11, const pair& c22) { if (c11.first->size() != c22.first->size()) return (c11.first->size() < c22.first->size()); - + #ifdef DEBUG_XORFIND2 Clause& c1 = *c11.first; - for (uint i = 0; i+1 < c1.size(); i++) + for (uint32_t i = 0; i+1 < c1.size(); i++) assert(c1[i].var() <= c1[i+1].var()); - + Clause& c2 = *c22.first; - for (uint i = 0; i+1 < c2.size(); i++) + 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 = a + c11.first->size(); a != end; a++, b++) { + + 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& c11, const pair& c22) const + bool operator()(const pair& c11, const pair& c22) const { const Clause& c1 = *(c11.first); const Clause& c2 = *(c22.first); + assert(c1.size() == c2.size()); - for (uint i = 0, size = c1.size(); i < size; i++) { + 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 (uint i = 0, size = c1->size(); i < size; i++) + 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 toRemove; vector toLeaveInPlace; void clearToRemove(); uint32_t foundXors; - - //For adding xor as norm + + //For adding xor clause as normal clause void addXorAsNormal3(XorClause& c); void addXorAsNormal4(XorClause& c); - + vec& cls; - ClauseCleaner::ClauseSetType type; - + 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, uint& numImpair, uint& numPair) 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; }; -}; //NAMESPACE MINISAT - #endif //XORFINDER_H diff --git a/src/sat/cryptominisat2/XorSubsumer.cpp b/src/sat/cryptominisat2/XorSubsumer.cpp index dc5c4fb..8509ee2 100644 --- a/src/sat/cryptominisat2/XorSubsumer.cpp +++ b/src/sat/cryptominisat2/XorSubsumer.cpp @@ -1,7 +1,10 @@ -/************************************************************************************************** -Originally From: Solver.C -- (C) Niklas Een, Niklas Sorensson, 2004 -Substantially modified by: Mate Soos (2010) -**************************************************************************************************/ +/***************************************************************************** +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" @@ -26,10 +29,6 @@ using std::cout; using std::endl; #endif //VERBOSE_DEBUG -namespace MINISAT -{ -using namespace MINISAT; - XorSubsumer::XorSubsumer(Solver& s): solver(s) , totalTime(0.0) @@ -60,9 +59,8 @@ void XorSubsumer::subsume0(XorClauseSimp ps) #endif clauses_subsumed++; assert(tmp->size() == ps.clause->size()); - if (ps.clause->xor_clause_inverted() == tmp->xor_clause_inverted()) { + if (ps.clause->xorEqualFalse() == tmp->xorEqualFalse()) { unlinkClause(subs[i]); - solver.clauseAllocator.clauseFree(tmp); } else { solver.ok = false; return; @@ -74,7 +72,7 @@ void XorSubsumer::subsume0(XorClauseSimp ps) std::cout << "Cutting xor-clause:"; subs[i].clause->plainPrint(); #endif //VERBOSE_DEBUG - XorClause *c = solver.addXorClauseInt(unmatchedPart, tmp->xor_clause_inverted() ^ !ps.clause->xor_clause_inverted(), tmp->getGroup()); + XorClause *c = solver.addXorClauseInt(unmatchedPart, tmp->xorEqualFalse() ^ !ps.clause->xorEqualFalse(), tmp->getGroup()); if (c != NULL) linkInClause(*c); unlinkClause(subs[i]); @@ -102,16 +100,22 @@ void XorSubsumer::findUnMatched(const T& A, const T& B, vec& unmatchedPart) 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) - elimedOutVar[elim].push_back(c.clause); - + + 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; } @@ -120,9 +124,9 @@ void XorSubsumer::unlinkModifiedClause(vec& 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; } @@ -140,14 +144,14 @@ XorClauseSimp XorSubsumer::linkInClause(XorClause& cl) 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); } @@ -161,10 +165,8 @@ void XorSubsumer::addFromSolver(vec& cs) for (XorClause **end = i + cs.size(); i != end; i++) { if (i+1 != end) __builtin_prefetch(*(i+1), 1, 1); - + linkInClause(**i); - if ((*i)->getVarChanged() || (*i)->getStrenghtened()) - (*i)->calcXorAbstraction(); } cs.clear(); cs.push(NULL); //HACK --to force xor-propagation @@ -177,7 +179,6 @@ void XorSubsumer::addBackToSolver() if (clauses[i].clause != NULL) { solver.xorclauses.push(clauses[i].clause); clauses[i].clause->unsetStrenghtened(); - clauses[i].clause->unsetVarChanged(); } } for (Var var = 0; var < solver.nVars(); var++) { @@ -193,13 +194,22 @@ void XorSubsumer::fillCannotEliminate() for (uint32_t i = 0; i < solver.clauses.size(); i++) addToCannotEliminate(solver.clauses[i]); - for (uint32_t i = 0; i < solver.binaryClauses.size(); i++) - if (!(*solver.binaryClauses[i]).learnt()) addToCannotEliminate(solver.binaryClauses[i]); - - const vec& tmp = solver.varReplacer->getClauses(); - for (uint32_t i = 0; i < tmp.size(); i++) - addToCannotEliminate(tmp[i]); - + uint32_t wsLit = 0; + for (const vec *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + const vec& ws = *it; + for (const Watched *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++) @@ -211,26 +221,29 @@ void XorSubsumer::fillCannotEliminate() void XorSubsumer::extendModel(Solver& solver2) { + #ifdef VERBOSE_DEBUG + std::cout << "XorSubsumer::extendModel(Solver& solver2) called" << std::endl; + #endif + assert(checkElimedUnassigned()); vec tmp; - typedef map > elimType; + typedef map > 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::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { - XorClause& c = **it2; + + for (vector::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.size()); - std::copy(c.getData(), c.getDataEnd(), tmp.getData()); - bool inverted = c.xor_clause_inverted(); - solver2.addXorClause(tmp, inverted); + tmp.growTo(c.lits.size()); + std::copy(c.lits.begin(), c.lits.end(), tmp.getData()); + solver2.addXorClause(tmp, c.xorEqualFalse); assert(solver2.ok); } } @@ -255,10 +268,8 @@ const bool XorSubsumer::localSubstitute() std::cout << "Clause 2:"; c2.plainPrint(); #endif //VERBOSE_DEBUG localSubstituteUseful++; - uint32_t lastSize = solver.varReplacer->getClauses().size(); - solver.addXorClauseInt(tmp, c1.xor_clause_inverted() ^ !c2.xor_clause_inverted(), c1.getGroup()); - for (uint32_t i = lastSize; i < solver.varReplacer->getClauses().size(); i++) - addToCannotEliminate(solver.varReplacer->getClauses()[i]); + XorClause* ret = solver.addXorClauseInt(tmp, c1.xorEqualFalse() ^ !c2.xorEqualFalse(), c1.getGroup()); + release_assert(ret == NULL); if (!solver.ok) { #ifdef VERBOSE_DEBUG std::cout << "solver.ok is false after local substitution" << std::endl; @@ -269,7 +280,7 @@ const bool XorSubsumer::localSubstitute() } } } - + return true; } @@ -320,6 +331,35 @@ void XorSubsumer::removeWrong(vec& cs) cs.shrink(i-j); } +void XorSubsumer::removeWrongBins() +{ + uint32_t numRemovedHalfLearnt = 0; + uint32_t wsLit = 0; + for (vec *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) { + Lit lit = ~Lit::toLit(wsLit); + vec& ws = *it; + + Watched* i = ws.getData(); + Watched* j = i; + for (Watched *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; +} + const bool XorSubsumer::removeDependent() { @@ -341,13 +381,15 @@ const bool XorSubsumer::removeDependent() XorClause& c1 = *(occ[0].clause); lits.growTo(c1.size()); std::copy(c1.getData(), c1.getDataEnd(), lits.getData()); - bool inverted = c1.xor_clause_inverted(); - + 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.xor_clause_inverted(); + inverted ^= !c2.xorEqualFalse(); uint32_t group = c2.getGroup(); + 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; @@ -357,13 +399,13 @@ const bool XorSubsumer::removeDependent() XorClauseSimp toUnlink0 = occ[0]; XorClauseSimp toUnlink1 = occ[1]; unlinkClause(toUnlink0); - solver.clauseAllocator.clauseFree(toUnlink0.clause); unlinkClause(toUnlink1, var); solver.setDecisionVar(var, false); var_elimed[var] = true; numElimed++; - - uint32_t lastSize = solver.varReplacer->getClauses().size(); + + for (uint32_t i = 0; i < lits.size(); i++) + cannot_eliminate[lits[i].var()] = true; XorClause* c = solver.addXorClauseInt(lits, inverted, group); #ifdef VERBOSE_DEBUG if (c != NULL) { @@ -372,8 +414,6 @@ const bool XorSubsumer::removeDependent() std::cout << "-> Combined xor clause is NULL" << std::endl; #endif if (c != NULL) linkInClause(*c); - for (uint32_t i = lastSize; i < solver.varReplacer->getClauses().size(); i++) - addToCannotEliminate(solver.varReplacer->getClauses()[i]); if (!solver.ok) { #ifdef VERBOSE_DEBUG std::cout << "solver.ok is false after var-elim through xor" << std::endl; @@ -382,7 +422,7 @@ const bool XorSubsumer::removeDependent() } } } - + return true; } @@ -396,7 +436,8 @@ inline void XorSubsumer::addToCannotEliminate(Clause* it) const bool XorSubsumer::unEliminate(const Var var) { assert(var_elimed[var]); - typedef map > elimType; + vec tmp; + typedef map > elimType; elimType::iterator it = elimedOutVar.find(var); //MUST set to decision, since it would never have been eliminated @@ -405,22 +446,30 @@ const bool XorSubsumer::unEliminate(const Var var) 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::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) { - XorClause& c = **it2; - solver.addXorClause(c, c.xor_clause_inverted()); - solver.clauseAllocator.clauseFree(&c); + for (vector::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; } -const bool XorSubsumer::simplifyBySubsumption(const bool doFullSubsume) +const bool XorSubsumer::simplifyBySubsumption() { double myTime = cpuTime(); uint32_t origTrailSize = solver.trail.size(); @@ -429,34 +478,33 @@ const bool XorSubsumer::simplifyBySubsumption(const bool doFullSubsume) clauseID = 0; uint32_t lastNumElimed = numElimed; localSubstituteUseful = 0; - while (solver.performReplace && solver.varReplacer->needsReplace()) { + 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; - solver.testAllClauseAttach(); - + 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) { @@ -470,32 +518,28 @@ const bool XorSubsumer::simplifyBySubsumption(const bool doFullSubsume) } } } - + propagated = (solver.qhead != solver.trail.size()); solver.ok = (solver.propagate().isNULL()); if (!solver.ok) { return false; } - solver.clauseCleaner->cleanXorClausesBewareNULL(clauses, ClauseCleaner::xorSimpClauses, *this); if (!solver.ok) return false; - testAllClauseAttach(); fillCannotEliminate(); - if (solver.conglomerateXors && !removeDependent()) { + if (solver.conf.doConglXors && !removeDependent()) { addBackToSolver(); return false; } - testAllClauseAttach(); - if (solver.heuleProcess && !localSubstitute()) { + if (solver.conf.doHeuleProcess && !localSubstitute()) { addBackToSolver(); return false; } - testAllClauseAttach(); - /*if (solver.performReplace && solver.varReplacer->needsReplace()) { + /*if (solver.doReplace && solver.varReplacer->needsReplace()) { addBackToSolver(); - while (solver.performReplace && solver.varReplacer->needsReplace()) { + while (solver.doReplace && solver.varReplacer->needsReplace()) { replaced = true; if (!solver.varReplacer->performReplace()) return false; @@ -507,46 +551,25 @@ const bool XorSubsumer::simplifyBySubsumption(const bool doFullSubsume) solver.order_heap.filter(Solver::VarFilter(solver)); removeWrong(solver.learnts); - removeWrong(solver.binaryClauses); + removeWrongBins(); addBackToSolver(); - - if (solver.verbosity >= 1) { - std::cout << "c | x-sub: " << std::setw(5) << clauses_subsumed + 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) <clause == NULL) continue; - const XorClause& c = *it->clause; - assert(find(solver.xorwatches[c[0].var()], &c)); - assert(find(solver.xorwatches[c[1].var()], &c)); - if (solver.assigns[c[0].var()]!=l_Undef || solver.assigns[c[1].var()]!=l_Undef) { - for (uint i = 0; i < c.size();i++) { - assert(solver.assigns[c[i].var()] != l_Undef); - } - } - } -} -#else -inline void XorSubsumer::testAllClauseAttach() const -{ - return; -} -#endif //DEBUG_ATTACH - void XorSubsumer::findSubsumed(XorClause& ps, vec& out_subsumed) { #ifdef VERBOSE_DEBUGSUBSUME0 @@ -557,18 +580,18 @@ void XorSubsumer::findSubsumed(XorClause& ps, vec& out_subsumed) } 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& 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, 1, 1); - + 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 @@ -581,14 +604,28 @@ void XorSubsumer::findSubsumed(XorClause& ps, vec& out_subsumed) const 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; } -}; //NAMESPACE MINISAT +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 >::iterator it = elimedOutVar.find(var); + if (it != elimedOutVar.end()) elimedOutVar.erase(it); + } + } +} diff --git a/src/sat/cryptominisat2/XorSubsumer.h b/src/sat/cryptominisat2/XorSubsumer.h index 43867fa..e03fa36 100644 --- a/src/sat/cryptominisat2/XorSubsumer.h +++ b/src/sat/cryptominisat2/XorSubsumer.h @@ -1,7 +1,10 @@ -/************************************************************************************************** -Originally From: Solver.C -- (C) Niklas Een, Niklas Sorensson, 2004 -Substantially modified by: Mate Soos (2010) -**************************************************************************************************/ +/***************************************************************************** +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 @@ -10,18 +13,30 @@ Substantially modified by: Mate Soos (2010) #include "Vec.h" #include "XSet.h" -namespace MINISAT -{ -using namespace MINISAT; - 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); - const bool simplifyBySubsumption(const bool doFullSubsume = false); + const bool simplifyBySubsumption(); void unlinkModifiedClause(vec& origClause, XorClauseSimp c); void unlinkModifiedClauseNoDetachNoNULL(vec& origClause, XorClauseSimp c); void unlinkClause(XorClauseSimp cc, Var elim = var_Undef); @@ -29,30 +44,49 @@ public: void linkInAlreadyClause(XorClauseSimp& c); void newVar(); void extendModel(Solver& solver2); + const uint32_t getNumElimed() const; const vec& getVarElimed() const; const bool unEliminate(const Var var); const bool checkElimedUnassigned() const; const double getTotalTime() const; - + + struct XorElimedClause + { + vector 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 >& getElimedOutVar() const; + private: - + friend class ClauseCleaner; friend class ClauseAllocator; - + //Main vec clauses; vec > occur; // 'occur[index(lit)]' is a list of constraints containing 'lit'. Solver& solver; // The Solver - + // Temporaries (to reduce allocation overhead): // vec seen_tmp; // (used in various places) - + //Start-up void addFromSolver(vec& cs); void addBackToSolver(); - + // Subsumption: void findSubsumed(XorClause& ps, vec& out_subsumed); bool isSubsumed(XorClause& ps); @@ -65,26 +99,28 @@ private: //helper void testAllClauseAttach() const; - + //dependent removal const bool removeDependent(); void fillCannotEliminate(); vec cannot_eliminate; void addToCannotEliminate(Clause* it); void removeWrong(vec& cs); + void removeWrongBins(); + void removeAssignedVarsFromEliminated(); //Global stats double totalTime; - map > elimedOutVar; + map > elimedOutVar; vec var_elimed; uint32_t numElimed; - + //Heule-process template void xorTwoClauses(const T& c1, const T& c2, vec& xored); const bool localSubstitute(); uint32_t localSubstituteUseful; - + uint32_t clauses_subsumed; uint32_t clauses_cut; uint32_t origNClauses; @@ -137,6 +173,9 @@ inline const double XorSubsumer::getTotalTime() const return totalTime; } -}; //NAMESPACE MINISAT +inline const map >& XorSubsumer::getElimedOutVar() const +{ + return elimedOutVar; +} #endif //XORSIMPLIFIER_H diff --git a/src/sat/cryptominisat2/constants.h b/src/sat/cryptominisat2/constants.h index 436128d..d1ec2b2 100644 --- a/src/sat/cryptominisat2/constants.h +++ b/src/sat/cryptominisat2/constants.h @@ -18,32 +18,90 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************************************************/ -#define RATIOREMOVECLAUSES 2 +/////////////////// +// Settings (magic constants) +/////////////////// + +//Parameters for learnt-clause cleaning +#define RATIOREMOVECLAUSES 1.0/2.0 #define NBCLAUSESBEFOREREDUCE 20000 -#define DYNAMICNBLEVEL -#define UPDATEVARACTIVITY + #define FIXCLEANREPLACE 30U #define PERCENTAGEPERFORMREPLACE 0.01 #define PERCENTAGECLEANCLAUSES 0.01 -#define MAX_CLAUSENUM_XORFIND 5000000 -#define BINARY_TO_XOR_APPROX 4.0 -#define FULLRESTART_MULTIPLIER 250 + +//Parameters for xor-finding (binary and non-binary) +#define MAX_CLAUSENUM_XORFIND 1500000 +#define BINARY_TO_XOR_APPROX 12.0 + +#define RANDOM_LOOKAROUND_SEARCHSPACE +#define UPDATE_TRANSOTFSSR_CACHE 200000 +//#define USE_OLD_POLARITIES + +//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 -//#define VERBOSE_DEBUG_XOR -//#define VERBOSE_DEBUG -#define USE_GAUSS + +//Gaussian elimination parameters #define MIN_GAUSS_XOR_CLAUSES 5 #define MAX_GAUSS_XOR_CLAUSES 30000 -#define MAX_OLD_LEARNTS 2000000 -//#define DEBUG_ATTACH -#define RANDOM_LOOKAROUND_SEARCHSPACE -//#define USE_OLD_POLARITIES -//#define DEBUG_VARELIM -#define BURST_SEARCH -//#define DEBUG_PROPAGATEFROM + +//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 +#define DYNAMICALLY_UPDATE_GLUE +#define UPDATE_VAR_ACTIVITY_BASED_ON_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_HYPERBIN +//#define DEBUG_USELESS_LEARNT_BIN_REMOVAL +#endif + +//#define DEBUG_ATTACH_FULL + +/////////////////// +// For Automake tools +/////////////////// #ifdef HAVE_CONFIG_H #include "config.h" diff --git a/src/sat/cryptominisat2/msvc/stdint.h b/src/sat/cryptominisat2/msvc/stdint.h index fee624d..c8399d3 100644 --- a/src/sat/cryptominisat2/msvc/stdint.h +++ b/src/sat/cryptominisat2/msvc/stdint.h @@ -243,8 +243,4 @@ typedef uint64_t uintmax_t; #endif // __STDC_CONSTANT_MACROS ] -#ifndef uint -#define uint unsigned int -#endif - #endif // _MSC_STDINT_H_ ] diff --git a/src/sat/cryptominisat2/mtl/Alg.h b/src/sat/cryptominisat2/mtl/Alg.h index 2825a9c..711dd87 100644 --- a/src/sat/cryptominisat2/mtl/Alg.h +++ b/src/sat/cryptominisat2/mtl/Alg.h @@ -20,20 +20,20 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #ifndef Alg_h #define Alg_h +#include +#include "Vec.h" +#include "../SolverTypes.h" +#include "../Watched.h" + #ifdef _MSC_VER #include #else #include #endif //_MSC_VER -namespace MINISAT -{ -using namespace MINISAT; - //================================================================================================= // Useful functions on vectors - template static inline void remove(V& ts, const T& t) { @@ -44,6 +44,21 @@ static inline void remove(V& ts, const T& t) ts.pop(); } +template +static inline const uint32_t removeAll(V& ts, const Var t) +{ + Lit* i = ts.getData(); + Lit* j = i; + for (Lit *end = ts.getDataEnd(); i != end; i++) { + if (i->var() != t) { + *j++ = *i; + } + } + ts.shrink(i-j); + + return (i-j); +} + template static inline void removeW(V& ts, const T& t) { @@ -70,6 +85,154 @@ static inline bool findW(V& ts, const T& t) return j < ts.size(); } -}; //NAMESPACE MINISAT + +//Normal clause +static bool findWCl(const vec& ws, const ClauseOffset c); +static void removeWCl(vec &ws, const ClauseOffset c); + +//Binary clause +static bool findWBin(const vec >& wsFull, const Lit lit1, const Lit impliedLit); +static bool findWBin(const vec >& wsFull, const Lit lit1, const Lit impliedLit, const bool learnt); +static void removeWBin(vec &ws, const Lit impliedLit, const bool learnt); +static void removeWTri(vec &ws, const Lit lit1, Lit lit2); +static const std::pair removeWBinAll(vec &ws, const Lit impliedLit); +static Watched& findWatchedOfBin(vec >& wsFull, const Lit lit1, const Lit lit2, const bool learnt); +static Watched& findWatchedOfBin(vec >& wsFull, const Lit lit1, const Lit lit2); + +//Xor Clause +static bool findWXCl(const vec& ws, const ClauseOffset c); +static void removeWXCl(vec &ws, const ClauseOffset c); + +////////////////// +// NORMAL Clause +////////////////// +static inline bool findWCl(const vec& ws, const ClauseOffset c) +{ + uint32_t j = 0; + for (; j < ws.size() && (!ws[j].isClause() || ws[j].getNormOffset() != c); j++); + return j < ws.size(); +} + +static inline void removeWCl(vec &ws, const ClauseOffset c) +{ + uint32_t j = 0; + for (; j < ws.size() && (!ws[j].isClause() || ws[j].getNormOffset() != c); j++); + assert(j < ws.size()); + for (; j < ws.size()-1; j++) ws[j] = ws[j+1]; + ws.pop(); +} + +////////////////// +// XOR Clause +////////////////// +static inline bool findWXCl(const vec& ws, const ClauseOffset c) +{ + uint32_t j = 0; + for (; j < ws.size() && (!ws[j].isXorClause() || ws[j].getXorOffset() != c); j++); + return j < ws.size(); +} + +static inline void removeWXCl(vec &ws, const ClauseOffset c) +{ + uint32_t j = 0; + for (; j < ws.size() && (!ws[j].isXorClause() || ws[j].getXorOffset() != c); j++); + assert(j < ws.size()); + for (; j < ws.size()-1; j++) ws[j] = ws[j+1]; + ws.pop(); +} + +////////////////// +// TRI Clause +////////////////// + +static inline const bool findWTri(const vec &ws, const Lit lit1, const Lit lit2) +{ + uint32_t j = 0; + for (; j < ws.size() && (!ws[j].isTriClause() || ws[j].getOtherLit() != lit1 || ws[j].getOtherLit2() != lit2); j++); + return(j < ws.size()); +} + +static inline void removeWTri(vec &ws, const Lit lit1, const Lit lit2) +{ + uint32_t j = 0; + for (; j < ws.size() && (!ws[j].isTriClause() || ws[j].getOtherLit() != lit1 || ws[j].getOtherLit2() != lit2); j++); + assert(j < ws.size()); + for (; j < ws.size()-1; j++) ws[j] = ws[j+1]; + ws.pop(); +} + +////////////////// +// BINARY Clause +////////////////// +static inline bool findWBin(const vec >& wsFull, const Lit lit1, const Lit impliedLit) +{ + uint32_t j = 0; + const vec& ws = wsFull[(~lit1).toInt()]; + for (; j < ws.size() && (!ws[j].isBinary() || ws[j].getOtherLit() != impliedLit); j++); + return j < ws.size(); +} + +static inline bool findWBin(const vec >& wsFull, const Lit lit1, const Lit impliedLit, const bool learnt) +{ + uint32_t j = 0; + const vec& ws = wsFull[(~lit1).toInt()]; + for (; j < ws.size() && (!ws[j].isBinary() || ws[j].getOtherLit() != impliedLit || ws[j].getLearnt() != learnt); j++); + return j < ws.size(); +} + +static inline void removeWBin(vec &ws, const Lit impliedLit, const bool learnt) +{ + uint32_t j = 0; + for (; j < ws.size() && (!ws[j].isBinary() || ws[j].getOtherLit() != impliedLit || ws[j].getLearnt() != learnt); j++); + assert(j < ws.size()); + for (; j < ws.size()-1; j++) ws[j] = ws[j+1]; + ws.pop(); +} + +static inline const std::pair removeWBinAll(vec &ws, const Lit impliedLit) +{ + uint32_t removedLearnt = 0; + uint32_t removedNonLearnt = 0; + + Watched *i = ws.getData(); + Watched *j = i; + for (Watched* end = ws.getDataEnd(); i != end; i++) { + if (!i->isBinary() || i->getOtherLit() != impliedLit) + *j++ = *i; + else { + if (i->getLearnt()) + removedLearnt++; + else + removedNonLearnt++; + } + } + ws.shrink_(i-j); + + return std::make_pair(removedLearnt, removedNonLearnt); +} + +static inline Watched& findWatchedOfBin(vec >& wsFull, const Lit lit1, const Lit lit2, const bool learnt) +{ + vec& ws = wsFull[(~lit1).toInt()]; + for (Watched *i = ws.getData(), *end = ws.getDataEnd(); i != end; i++) { + if (i->isBinary() && i->getOtherLit() == lit2 && i->getLearnt() == learnt) + return *i; + } + assert(false); + + return wsFull[0][0]; +} + +static inline Watched& findWatchedOfBin(vec >& wsFull, const Lit lit1, const Lit lit2) +{ + vec& ws = wsFull[(~lit1).toInt()]; + for (Watched *i = ws.getData(), *end = ws.getDataEnd(); i != end; i++) { + if (i->isBinary() && i->getOtherLit() == lit2) + return *i; + } + assert(false); + + return wsFull[0][0]; +} #endif diff --git a/src/sat/cryptominisat2/mtl/BasicHeap.h b/src/sat/cryptominisat2/mtl/BasicHeap.h index 8748d2a..85775e8 100644 --- a/src/sat/cryptominisat2/mtl/BasicHeap.h +++ b/src/sat/cryptominisat2/mtl/BasicHeap.h @@ -28,10 +28,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include "Vec.h" -namespace MINISAT -{ -using namespace MINISAT; - //================================================================================================= // A heap implementation with support for decrease/increase key. @@ -103,7 +99,6 @@ class BasicHeap { int getmin () { return removeMin(); } }; -}; //NAMESPACE MINISAT //================================================================================================= #endif diff --git a/src/sat/cryptominisat2/mtl/BoxedVec.h b/src/sat/cryptominisat2/mtl/BoxedVec.h index 63b8c6d..bddf410 100644 --- a/src/sat/cryptominisat2/mtl/BoxedVec.h +++ b/src/sat/cryptominisat2/mtl/BoxedVec.h @@ -24,10 +24,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include #include -namespace MINISAT -{ -using namespace MINISAT; - //================================================================================================= // Automatically resizable arrays // @@ -147,6 +143,5 @@ public: }; -}; //NAMESPACE MINISAT #endif diff --git a/src/sat/cryptominisat2/mtl/Heap.h b/src/sat/cryptominisat2/mtl/Heap.h index a2ae468..8a9c004 100644 --- a/src/sat/cryptominisat2/mtl/Heap.h +++ b/src/sat/cryptominisat2/mtl/Heap.h @@ -31,10 +31,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include #endif //_MSC_VER -namespace MINISAT -{ -using namespace MINISAT; - //================================================================================================= // A heap implementation with support for decrease/increase key. @@ -179,7 +175,7 @@ class Heap { indices[heap[i]] = std::numeric_limits::max(); heap.shrink(i - j); - for (int i = heap.size() / 2 - 1; i >= 0; i--) + for (int i = ((int)heap.size()) / 2 - 1; i >= 0; i--) percolateDown(i); assert(heapProperty()); @@ -198,8 +194,6 @@ class Heap { }; -//================================================================================================= - -}; //NAMESPACE MINISAT +//================================================================================================= #endif diff --git a/src/sat/cryptominisat2/mtl/Map.h b/src/sat/cryptominisat2/mtl/Map.h index bd791c3..b855c3b 100644 --- a/src/sat/cryptominisat2/mtl/Map.h +++ b/src/sat/cryptominisat2/mtl/Map.h @@ -28,10 +28,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include "Vec.h" -namespace MINISAT -{ -using namespace MINISAT; - //================================================================================================= // Default hash/equals functions // @@ -123,6 +119,4 @@ class Map { } }; -}; //NAMESPACE MINISAT - #endif diff --git a/src/sat/cryptominisat2/mtl/Queue.h b/src/sat/cryptominisat2/mtl/Queue.h index 4138559..2cc110c 100644 --- a/src/sat/cryptominisat2/mtl/Queue.h +++ b/src/sat/cryptominisat2/mtl/Queue.h @@ -22,10 +22,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include "Vec.h" -namespace MINISAT -{ -using namespace MINISAT; - //================================================================================================= @@ -83,7 +79,4 @@ public: //}; //================================================================================================= - -}; //NAMESPACE MINISAT - #endif diff --git a/src/sat/cryptominisat2/mtl/Vec.h b/src/sat/cryptominisat2/mtl/Vec.h index 1c6c1ae..193eccd 100644 --- a/src/sat/cryptominisat2/mtl/Vec.h +++ b/src/sat/cryptominisat2/mtl/Vec.h @@ -22,6 +22,7 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include #include +#include #include #ifdef _MSC_VER #include @@ -29,10 +30,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include #endif //_MSC_VER -namespace MINISAT -{ -using namespace MINISAT; - //================================================================================================= // Automatically resizable arrays // @@ -54,7 +51,7 @@ class vec { static inline uint32_t imax(int x, int y) { int mask = (y-x) >> (sizeof(int)*8-1); return (x&mask) + (y&(~mask)); } - + void myCopy (const vec& other); public: @@ -86,11 +83,27 @@ public: void growTo (uint32_t size, const T& pad); void clear (bool dealloc = false); void capacity (uint32_t size) { grow(size); } + const bool empty() const {return size() == 0;} // Stack interface: void reserve(uint32_t res) { if (cap < res) {cap = res; data = (T*)realloc(data, cap * sizeof(T));}} - void push (void) { if (sz == cap) { cap = imax(2, (cap*3+1)>>1); data = (T*)realloc(data, cap * sizeof(T)); } new (&data[sz]) T(); sz++; } - void push (const T& elem) { if (sz == cap) { cap = imax(2, (cap*3+1)>>1); data = (T*)realloc(data, cap * sizeof(T)); } data[sz++] = elem; } + void push (void) + { + if (sz == cap) { + cap = imax(2, (cap*3+1)>>1); + data = (T*)realloc(data, cap * sizeof(T)); + } + new (&data[sz]) T(); + sz++; + } + void push (const T& elem) + { + if (sz == cap) { + cap = imax(2, (cap*3+1)>>1); + data = (T*)realloc(data, cap * sizeof(T)); + } + data[sz++] = elem; + } void push_ (const T& elem) { assert(sz < cap); data[sz++] = elem; } const T& last (void) const { return data[sz-1]; } @@ -126,7 +139,7 @@ void vec::growTo(uint32_t size) { grow(size); for (uint32_t i = sz; i != size; i++) new (&data[i]) T(); sz = size; } - + template void vec::myCopy(const vec& other) { assert(sz == 0); @@ -139,9 +152,13 @@ void vec::clear(bool dealloc) { if (data != NULL){ for (uint32_t i = 0; i != sz; i++) data[i].~T(); sz = 0; - if (dealloc) free(data), data = NULL, cap = 0; } } - + if (dealloc) { + free(data); + data = NULL; + cap = 0; + } + } +} -}; //NAMESPACE MINISAT #endif diff --git a/src/sat/cryptominisat2/time_mem.h b/src/sat/cryptominisat2/time_mem.h index f923c9a..c615eb3 100644 --- a/src/sat/cryptominisat2/time_mem.h +++ b/src/sat/cryptominisat2/time_mem.h @@ -22,33 +22,45 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #define TIME_MEM_H #ifdef _MSC_VER - #include - #include +#include #else - #include - #include - #include - #include -#endif +#include +#endif //_MSC_VER -namespace MINISAT -{ -using namespace MINISAT; +#if defined (_MSC_VER) || defined(CROSS_COMPILE) +#include -/*************************************************************************************/ -#ifdef _MSC_VER +static inline double cpuTime(void) +{ + return (double)clock() / CLOCKS_PER_SEC; +} +#else //_MSC_VER +#include +#include +#include -static inline double cpuTime(void) { - return (double)clock() / CLOCKS_PER_SEC; } -#else +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 cpuTime(void) { +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; } -#endif + return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000.0; +} +#endif //CROSS_COMPILE + #if defined(__linux__) +#include static inline int memReadStat(int field) { char name[256]; @@ -57,29 +69,34 @@ static inline int memReadStat(int field) FILE* in = fopen(name, "rb"); if (in == NULL) return 0; int value; - for (; field >= 0; field--) - fscanf(in, "%d", &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(); } +static inline uint64_t memUsed() +{ + return (uint64_t)memReadStat(0) * (uint64_t)getpagesize(); +} #elif defined(__FreeBSD__) -static inline uint64_t memUsed(void) { +static inline uint64_t memUsed(void) +{ struct rusage ru; getrusage(RUSAGE_SELF, &ru); - return ru.ru_maxrss*1024; } + return ru.ru_maxrss*1024; +} #else -static inline uint64_t memUsed() { return 0; } -#endif - -#if defined(__linux__) -#include +static inline uint64_t memUsed() +{ + return 0; +} #endif -}; - #endif //TIME_MEM_H