endif
-LDFLAGS = $(LDFLAGS_BASE)
+LDFLAGS = $(LDFLAGS_BASE) -lz -fopenmp
CFLAGS = $(CFLAGS_BASE) $(CFLAGS_M32)
CryptoMinisat::CryptoMinisat()
{
- s = new MINISAT::Solver();
+ s = new Solver();
}
CryptoMinisat::~CryptoMinisat()
// Cryptominisat uses a slightly different Lit class too.
// VERY SLOW>
- MINISAT::vec<MINISAT::Lit> v;
+ vec<Lit> v;
for (int i =0; i<ps.size();i++)
- v.push(MINISAT::Lit(var(ps[i]), sign(ps[i])));
+ v.push(Lit(var(ps[i]), sign(ps[i])));
s->addClause(v);
}
int CryptoMinisat::setVerbosity(int v)
{
- s->verbosity = v;
+ s->conf.verbosity = v;
}
int CryptoMinisat::nVars()
#include "SATSolver.h"
-namespace MINISAT
-{
- class Solver;
-}
+class Solver;
namespace BEEV
{
class CryptoMinisat : public SATSolver
{
- MINISAT::Solver* s;
+ Solver* s;
public:
CryptoMinisat();
#include <stdint.h>
#endif //_MSC_VER
-namespace MINISAT
-{
-using namespace MINISAT;
-
class BitArray
{
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) {
mp = new uint64_t[size];
}
memcpy(mp, b.mp, sizeof(uint64_t)*size);
-
+
return *this;
}
-
+
BitArray& operator&=(const BitArray& b)
{
assert(size == b.size);
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)
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) {
if (fill) setOne();
else setZero();
}
-
+
~BitArray()
{
delete[] mp;
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;
{
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
/*****************************************************************************************[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 <msvc/stdint.h>
#include "Vec.h"
-//=================================================================================================
-
-namespace MINISAT
-{
-using namespace MINISAT;
-
template <class T>
class bqueue {
vec<T> 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<size;i++) elems[i]=0;
+ for(uint32_t i=0;i<size;i++) elems[i]=0;
}
void fastclear() {first = 0; last = 0; queuesize=0; sumofqueue=0;} // to be called after restarts... Discard the queue
-
- int size(void) { return queuesize; }
- void clear(bool dealloc = false) { elems.clear(dealloc); first = 0; maxsize=0; queuesize=0;sumofqueue=0;}
-};
+ int size(void) { return queuesize; }
-//=================================================================================================
+ void clear(bool dealloc = false) {
+ elems.clear(dealloc);
+ first = 0;
+ last = 0;
+ maxsize=0;
+ queuesize=0;
+ sumofqueue=0;
-}; //namespace MINISAT
+ totalNumElems = 0;
+ sumOfAllElems = 0;
+ }
+};
-#endif
+#endif //BOUNDEDQUEUE_H
-cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
+include_directories(${cryptoms_SOURCE_DIR}/mtl)
+include_directories(${cryptoms_SOURCE_DIR}/Solver)
+include_directories(${cryptoms_SOURCE_DIR}/MTRand)
-IF(DEFINED CMAKE_BUILD_TYPE)
- SET(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
-ELSE()
- SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
-ENDIF()
+# cmake_minimum_required( VERSION 2.6 FATAL_ERROR )
+# find_package( Boost 1.34 COMPONENTS REQUIRED thread )
+# link_directories ( ${Boost_LIBRARY_DIRS} )
+# include_directories ( ${Boost_INCLUDE_DIRS} )
-#set(CMAKE_C_COMPILER "gcc-4.4")
-#set(CMAKE_CXX_COMPILER "/usr/bin/g++-4.4")
-
-PROJECT(cryptoms)
-SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -Wall -Werror -g -mtune=native")
-SET(CMAKE_CXX_FLAGS_DEBUG "-Wall -Werror -O0 -ggdb")
-SET(CMAKE_CXX_FLAGS_RELEASE "-Wall -fprofile-use -Werror -O3 -g0 -fno-exceptions -DNDEBUG -mtune=native -fomit-frame-pointer")
-SET(CMAKE_EXE_LINKER_FLAGS "-static")
-
-find_package( ZLIB )
-link_directories( ${ZLIB_LIBRARY} )
-include_directories( ${ZLIB_INCLUDE_DIR} )
-
-find_package(Boost REQUIRED)
-
-add_definitions(-DVERSION="STP version")
-
-include_directories(mtl)
-include_directories(MTRand)
add_executable(cryptominisat
+ Main.cpp
Logger.cpp
Solver.cpp
+ SolverDebug.cpp
+ SolverMisc.cpp
Gaussian.cpp
PackedRow.cpp
XorFinder.cpp
MatrixFinder.cpp
VarReplacer.cpp
- FindUndef.cpp
+# FindUndef.cpp
ClauseCleaner.cpp
RestartTypeChooser.cpp
- FailedVarSearcher.cpp
+ FailedLitSearcher.cpp
PartFinder.cpp
Subsumer.cpp
PartHandler.cpp
ClauseAllocator.cpp
UselessBinRemover.cpp
OnlyNonLearntBins.cpp
- Main.cpp
+ CompleteDetachReattacher.cpp
+ DimacsParser.cpp
+ SCCFinder.cpp
+ SolverConf.cpp
+ ClauseVivifier.cpp
+ DataSync.cpp
)
target_link_libraries(cryptominisat
${ZLIB_LIBRARY}
- ${Boost_LIBRARIES}
+ ${Perftools_LIBRARIES}
+# ${Boost_LIBRARIES}
+# ${CMAKE_THREAD_LIBS_INIT}
)
-
-
#include <stdint.h>
#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:
clause(c)
, index(_index)
{}
-
- Clause* clause;
- uint32_t index;
+
+ Clause* clause; ///<The clause to be stored
+ uint32_t index; ///<The index of the clause in Subsumer::clauses
};
-//#pragma pack(pop)
+/**
+@brief Used to quicky add, remove and iterate through a clause set
+
+Used in Subsumer to put into a set all clauses that need to be treated
+*/
class CSet {
- vec<uint32_t> where; // Map clause ID to position in 'which'.
- vec<ClauseSimp> which; // List of clauses (for fast iteration). May contain 'Clause_NULL'.
- vec<uint32_t> free; // List of positions holding 'Clause_NULL'.
-
+ vec<uint32_t> where; ///<Map clause ID to position in 'which'.
+ vec<ClauseSimp> which; ///< List of clauses (for fast iteration). May contain 'Clause_NULL'.
+ vec<uint32_t> free; ///<List of positions holding 'Clause_NULL'.
+
public:
//ClauseSimp& operator [] (uint32_t index) { return which[index]; }
void reserve(uint32_t size) { where.reserve(size);}
- uint32_t size(void) const { return which.size(); }
+ //uint32_t size(void) const { return which.size(); }
+ ///@brief Number of elements in the set
uint32_t nElems(void) const { return which.size() - free.size(); }
-
- bool add(const ClauseSimp& c) {
+
+ /**
+ @brief Add a clause to the set
+ */
+ const bool add(const ClauseSimp& c) {
assert(c.clause != NULL);
where.growTo(c.index+1, std::numeric_limits<uint32_t>::max());
if (where[c.index] != std::numeric_limits<uint32_t>::max()) {
- return true;
+ return false;
}
if (free.size() > 0){
where[c.index] = free.last();
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<uint32_t>::max())
+ return true;
return false;
}
-
+
+ /**
+ @brief Remove clause from set
+
+ Handles it correctly if the clause was not in the set anyway
+ */
bool exclude(const ClauseSimp& c) {
assert(c.clause != NULL);
if (c.index >= where.size() || where[c.index] == std::numeric_limits<uint32_t>::max()) {
where[c.index] = std::numeric_limits<uint32_t>::max();
return true;
}
-
+
+ /**
+ @brief Fully clear the set
+ */
void clear(void) {
for (uint32_t i = 0; i < which.size(); i++) {
if (which[i].clause != NULL) {
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
-
-/***********************************************************************************[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
#include <cstdio>
#include <vector>
#include <sys/types.h>
-#include "Vec.h"
+#include <string.h>
+
#include "SolverTypes.h"
-#include "PackedRow.h"
#include "constants.h"
-#include "ClauseAllocator.h"
+#include "Watched.h"
+#include "Alg.h"
+#include "constants.h"
template <class T>
uint32_t calcAbstraction(const T& ps) {
uint32_t abstraction = 0;
for (uint32_t i = 0; i != ps.size(); i++)
- abstraction |= 1 << (ps[i].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; ///<Is the clause a learnt clause?
+ uint32_t strenghtened:1; ///<Has the clause been strenghtened since last SatELite-like work?
+ /**
+ @brief Is the XOR equal to 1 or 0?
+
+ i.e. "a + b" = TRUE or FALSE? -- we only have variables inside xor clauses,
+ so this is important to know
+
+ NOTE: ONLY set if the clause is an xor clause.
+ */
+ uint32_t isXorEqualFalse:1;
+ uint32_t isXorClause:1; ///< Is the clause an XOR clause?
+ uint32_t isRemoved:1; ///<Is this clause queued for removal because of usless binary removal?
+ uint32_t isFreed:1; ///<Has this clause been marked as freed by the ClauseAllocator ?
+ uint32_t glue:MAX_GLUE_BITS; ///<Clause glue -- clause activity according to GLUCOSE
+ uint32_t mySize:19; ///<The current size of the clause
+
+ float miniSatAct; ///<Clause activity according to MiniSat
+
+ uint32_t abst; //Abstraction of clause
+
#ifdef STATS_NEEDED
- uint group;
+ uint32_t group;
#endif
-
- uint32_t isLearnt:1;
- uint32_t strenghtened:1;
- uint32_t varChanged:1;
- uint32_t sorted:1;
- uint32_t invertedXor:1;
- uint32_t isXorClause:1;
- uint32_t subsume0Done:1;
- uint32_t isRemoved:1;
- uint32_t isFreed:1;
- uint32_t wasBinInternal:1;
- uint32_t mySize:20;
-
- union {uint32_t act; uint32_t abst;} extra;
- float oldActivityInter;
+
#ifdef _MSC_VER
Lit data[1];
#else
+ /**
+ @brief Stores the literals in the clause
+
+ This is the reason why we cannot have an instance of this class as it is:
+ it cannot hold any literals in that case! This is a trick so that the
+ literals are at the same place as the data of the clause, i.e. its size,
+ glue, etc. We allocate therefore the clause manually, taking care that
+ there is enough space for data[] to hold the literals
+ */
Lit data[0];
#endif //_MSC_VER
public:
#endif //_MSC_VER
template<class V>
- 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
{
group = _group;
}
#else
- const uint getGroup() const
+ const uint32_t getGroup() const
{
return 0;
}
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<class V>
- 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
#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<class T>
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<Lit>& 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<class T>
-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;
template XorClause* ClauseAllocator::XorClause_new(const vec<Lit>& 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());
assert(sizeof(Clause)%sizeof(uint32_t) == 0);
assert(sizeof(Lit)%sizeof(uint32_t) == 0);
- if (size == 2) {
- return clausePoolBin.malloc();
+ if (dataStarts.size() == (1<<NUM_BITS_OUTER_OFFSET)) {
+ std::cerr << "Memory manager cannot handle the load. Sorry. Exiting." << std::endl;
+ exit(-1);
}
-
- uint32_t needed = sizeof(Clause)+sizeof(Lit)*size;
+ assert(size > 2);
+
+ uint32_t needed = (sizeof(Clause)+sizeof(Lit)*size)/sizeof(uint32_t);
bool found = false;
uint32_t which = std::numeric_limits<uint32_t>::max();
for (uint32_t i = 0; i < sizes.size(); i++) {
}
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]
assert(which != std::numeric_limits<uint32_t>::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);
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<uint32_t>::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<uint32_t>::max());
return which;
}
+/**
+@brief Given a pointer and its stack number, returns its position inside the stack
+*/
inline uint32_t ClauseAllocator::getInterOffset(const Clause* ptr, uint32_t outerOffset) const
{
return ((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++) {
#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<uint32_t> newOrigClauseSizes;
- //}
-
- map<Clause*, Clause*> oldToNewPointer;
- map<uint32_t, uint32_t> 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<uint32_t> newMaxSizes;
+ for (uint32_t i = 0; i < (1 << NUM_BITS_OUTER_OFFSET); i++) {
+ if (newMaxSizeNeed <= 0) break;
+
+ uint32_t thisMaxSize = std::min(newMaxSizeNeed, (int64_t)MAXSIZE);
+ if (i == 0) {
+ thisMaxSize = std::max(thisMaxSize, (uint32_t)MIN_LIST_SIZE);
+ } else {
+ assert(i > 0);
+ thisMaxSize = std::max(thisMaxSize, newMaxSizes[i-1]/2);
+ thisMaxSize = std::max(thisMaxSize, (uint32_t)MIN_LIST_SIZE*2);
}
+ newMaxSizeNeed -= thisMaxSize;
+ assert(thisMaxSize <= MAXSIZE);
+ newMaxSizes.push(thisMaxSize);
+ //because the clauses don't always fit
+ //it might occur that there is enough place in total
+ //but the very last clause would need to be fragmented
+ //over multiple lists' ends :O
+ //So this "magic" constant could take care of that....
+ //or maybe not (if _very_ large clauses are used, always
+ //bad chance, etc. :O )
+ //NOTE: the + MIN_LIST_SIZE should take care of this above at
+ // newMaxSizeNeed = sum + MIN_LIST_SIZE;
+ #ifdef DEBUG_CLAUSEALLOCATOR
+ std::cout << "c NEW MaxSizes:" << newMaxSizes[i] << std::endl;
+ #endif //DEBUG_CLAUSEALLOCATOR
}
- 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<Var, vector<Clause*> >::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<Var, vector<XorClause*> >::iterator it = solver->xorSubsumer->elimedOutVar.begin(); it != solver->xorSubsumer->elimedOutVar.end(); it++) {
- updatePointers(it->second, oldToNewPointer);
+
+ vec<uint32_t> newSizes;
+ vec<vec<uint32_t> > newOrigClauseSizes;
+ vec<uint32_t*> newDataStartsPointers;
+ vec<uint32_t*> 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<PropagatedFrom>& 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<uint32_t>::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<class T>
-void ClauseAllocator::updateOffsets(vec<vec<T> >& watches, const map<ClauseOffset, ClauseOffset>& oldToNewOffset)
+void ClauseAllocator::updateAllOffsetsAndPointers(Solver* solver)
{
- for (uint32_t i = 0; i < watches.size(); i++) {
- vec<T>& list = watches[i];
- for (T *it = list.getData(), *end = list.getDataEnd(); it != end; it++) {
- map<ClauseOffset, ClauseOffset>::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<PropBy>& reason = solver->reason;
+ Var var = 0;
+ for (PropBy *it = reason.getData(), *end = reason.getDataEnd(); it != end; it++, var++) {
+ if ((uint32_t)solver->level[var] > solver->decisionLevel()
+ || solver->level[var] == 0
+ || solver->value(var) == l_Undef) {
+ *it = PropBy();
+ continue;
+ }
+
+ if (it->isClause() && !it->isNULL()) {
+ assert(((NewPointerAndOffset*)(getPointer(it->getClause())))->newOffset != std::numeric_limits<uint32_t>::max());
+ *it = PropBy(((NewPointerAndOffset*)(getPointer(it->getClause())))->newOffset);
}
}
}
-template<class T>
-void ClauseAllocator::updateOffsetsXor(vec<vec<T> >& watches, const map<ClauseOffset, ClauseOffset>& oldToNewOffset)
+/**
+@brief A dumb helper function to update offsets
+*/
+void ClauseAllocator::updateOffsets(vec<vec<Watched> >& watches)
{
for (uint32_t i = 0; i < watches.size(); i++) {
- vec<T>& list = watches[i];
- for (T *it = list.getData(), *end = list.getDataEnd(); it != end; it++) {
- map<ClauseOffset, ClauseOffset>::const_iterator it2 = oldToNewOffset.find(*it);
- assert(it2 != oldToNewOffset.end());
- *it = it2->second;
+ vec<Watched>& 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<class T>
-void ClauseAllocator::updatePointers(vec<T*>& toUpdate, const map<Clause*, Clause*>& oldToNewPointer)
+void ClauseAllocator::updatePointers(vec<T*>& toUpdate)
{
for (T **it = toUpdate.getData(), **end = toUpdate.getDataEnd(); it != end; it++) {
- if (!(*it)->wasBin()) {
- //assert(oldToNewPointer.find((TT*)*it) != oldToNewPointer.end());
- map<Clause*, Clause*>::const_iterator it2 = oldToNewPointer.find((Clause*)*it);
- *it = (T*)it2->second;
+ if (*it != NULL) {
+ *it = (T*)(((NewPointerAndOffset*)(*it))->newPointer);
}
}
}
-void ClauseAllocator::updatePointers(vector<Clause*>& toUpdate, const map<Clause*, Clause*>& oldToNewPointer)
+/**
+@brief A dumb helper function to update pointers
+*/
+void ClauseAllocator::updatePointers(vector<Clause*>& toUpdate)
{
for (vector<Clause*>::iterator it = toUpdate.begin(), end = toUpdate.end(); it != end; it++) {
- if (!(*it)->wasBin()) {
- //assert(oldToNewPointer.find((TT*)*it) != oldToNewPointer.end());
- map<Clause*, Clause*>::const_iterator it2 = oldToNewPointer.find((Clause*)*it);
- *it = it2->second;
- }
+ *it = (((NewPointerAndOffset*)(*it))->newPointer);
}
}
-void ClauseAllocator::updatePointers(vector<XorClause*>& toUpdate, const map<Clause*, Clause*>& oldToNewPointer)
+/**
+@brief A dumb helper function to update pointers
+*/
+void ClauseAllocator::updatePointers(vector<XorClause*>& toUpdate)
{
for (vector<XorClause*>::iterator it = toUpdate.begin(), end = toUpdate.end(); it != end; it++) {
- if (!(*it)->wasBin()) {
- //assert(oldToNewPointer.find((TT*)*it) != oldToNewPointer.end());
- map<Clause*, Clause*>::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<pair<Clause*, uint32_t> >& toUpdate)
+{
+ for (vector<pair<Clause*, uint32_t> >::iterator it = toUpdate.begin(), end = toUpdate.end(); it != end; it++) {
+ it->first = (((NewPointerAndOffset*)(it->first))->newPointer);
+ }
+}
#include <stdint.h>
#endif //_MSC_VER
+#include <stdlib.h>
#include "Vec.h"
-#include <boost/pool/pool.hpp>
#include <map>
#include <vector>
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<class T>
Clause* Clause_new(const T& ps, const uint32_t group, const bool learnt = false);
template<class T>
- 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);
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<class T>
- void updatePointers(vec<T*>& toUpdate, const map<Clause*, Clause*>& oldToNewPointer);
- void updatePointers(vector<Clause*>& toUpdate, const map<Clause*, Clause*>& oldToNewPointer);
- void updatePointers(vector<XorClause*>& toUpdate, const map<Clause*, Clause*>& oldToNewPointer);
-
- template<class T>
- void updateOffsets(vec<vec<T> >& watches, const map<ClauseOffset, ClauseOffset>& oldToNewOffset);
- template<class T>
- void updateOffsetsXor(vec<vec<T> >& watches, const map<ClauseOffset, ClauseOffset>& oldToNewOffset);
-
- vec<uint32_t*> dataStarts;
- vec<size_t> sizes;
+ void updatePointers(vec<T*>& toUpdate);
+ void updatePointers(vector<Clause*>& toUpdate);
+ void updatePointers(vector<XorClause*>& toUpdate);
+ void updatePointers(vector<std::pair<Clause*, uint32_t> >& toUpdate);
+
+ void updateOffsets(vec<vec<Watched> >& watches);
+
+ vec<uint32_t*> dataStarts; ///<Stacks start at these positions
+ vec<size_t> sizes; ///<The number of 32-bit datapieces currently used in each stack
+ /**
+ @brief Clauses in the stack had this size when they were allocated
+ This my NOT be their current size: the clauses may be shrinked during
+ the running of the solver. Therefore, it is imperative that their orignal
+ size is saved. This way, we can later move clauses around.
+ */
vec<vec<uint32_t> > origClauseSizes;
- vec<size_t> maxSizes;
- vec<size_t> currentlyUsedSize;
- vec<uint32_t> origSizes;
-
- boost::pool<> clausePoolBin;
+ vec<size_t> maxSizes; ///<The number of 32-bit datapieces allocated in each stack
+ /**
+ @brief The estimated used size of the stack
+ This is incremented by clauseSize each time a clause is allocated, and
+ decremetented by clauseSize each time a clause is deallocated. The
+ problem is, that clauses can shrink, and thus this value will be an
+ overestimation almost all the time
+ */
+ vec<size_t> currentlyUsedSizes;
void* allocEnough(const uint32_t size);
-};
-}; //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; ///<The new offset where the clause now resides
+ Clause* newPointer; ///<The new place
+ };
+};
+#endif //CLAUSEALLOCATOR_H
-/***********************************************************************************
+/***************************************************************************
CryptoMiniSat -- Copyright (c) 2009 Mate Soos
This program is free software: you can redistribute it and/or modify
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-**************************************************************************************************/
+****************************************************************************/
#include "ClauseCleaner.h"
#include "VarReplacer.h"
+#include "DataSync.h"
#ifdef _MSC_VER
#define __builtin_prefetch(a,b,c)
//#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<XorClause*>& 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<Clause*>& 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<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit = ~Lit::toLit(wsLit);
+ vec<Watched>& 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<Clause*>& cs, ClauseSetType type, const uint limit)
+void ClauseCleaner::cleanClauses(vec<Clause*>& cs, ClauseSetType type, const uint32_t limit)
{
assert(solver.decisionLevel() == 0);
assert(solver.qhead == solver.trail.size());
-
+
if (lastNumUnitaryClean[type] + limit >= solver.get_unitary_learnts_num())
return;
#ifdef VERBOSE_DEBUG
std::cout << "Cleaning " << (type==binaryClauses ? "binaryClauses" : "normal clauses" ) << std::endl;
#endif //VERBOSE_DEBUG
-
+
Clause **s, **ss, **end;
- for (s = ss = cs.getData(), end = s + cs.size(); s != end;) {
+ 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
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);
*j++ = *i;
continue;
}
-
+
if (val == l_True) {
- solver.detachModifiedClause(origLit1, origLit2, origSize, &c);
+ solver.detachModifiedClause(origLit1, origLit2, origLit3, origSize, &c);
return true;
}
}
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;
solver.clauses_literals -= i-j;
}
}
-
+
return false;
}
-void ClauseCleaner::cleanClauses(vec<XorClause*>& cs, ClauseSetType type, const uint limit)
+void ClauseCleaner::cleanClauses(vec<XorClause*>& cs, ClauseSetType type, const uint32_t limit)
{
assert(solver.decisionLevel() == 0);
assert(solver.qhead == solver.trail.size());
-
+
if (lastNumUnitaryClean[type] + limit >= solver.get_unitary_learnts_num())
return;
-
+
XorClause **s, **ss, **end;
for (s = ss = cs.getData(), end = s + cs.size(); s != end; s++) {
if (s+1 != end)
__builtin_prefetch(*(s+1), 1, 0);
- #ifdef DEBUG_ATTACH
- 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
} else c.invert(val.getBool());
}
c.shrink(i-j);
-
+
assert(c.size() != 1);
switch (c.size()) {
case 0: {
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;
return false;
}
-void ClauseCleaner::cleanClausesBewareNULL(vec<ClauseSimp>& 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<Lit> 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<XorClauseSimp>& 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<Lit> 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<Lit> 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;
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();
return final;
}
-void ClauseCleaner::moveBinClausesToBinClauses()
+
+
+/*void ClauseCleaner::removeSatisfied(vec<XorClause*>& cs, ClauseSetType type, const uint32_t limit)
{
+ #ifdef DEBUG_CLEAN
assert(solver.decisionLevel() == 0);
- assert(solver.qhead == solver.trail.size());
+ #endif
- vec<Clause*>& 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<Clause*>& 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();
+}*/
#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<Clause*>& cs, ClauseSetType type, const uint limit = 0);
- void cleanClausesBewareNULL(vec<ClauseSimp>& cs, ClauseSetType type, Subsumer& subs, const uint limit = 0);
- void cleanXorClausesBewareNULL(vec<XorClauseSimp>& 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<XorClause*>& cs, ClauseSetType type, const uint limit = 0);
- void removeSatisfied(vec<Clause*>& cs, ClauseSetType type, const uint limit = 0);
- void removeSatisfied(vec<XorClause*>& cs, ClauseSetType type, const uint limit = 0);
+
+ enum ClauseSetType {clauses, binaryClauses, xorclauses, learnts};
+
+ void cleanClauses(vec<Clause*>& cs, ClauseSetType type, const uint32_t limit = 0);
+
+ void cleanClauses(vec<XorClause*>& cs, ClauseSetType type, const uint32_t limit = 0);
+ void removeSatisfiedBins(const uint32_t limit = 0);
+ //void removeSatisfied(vec<Clause*>& cs, ClauseSetType type, const uint32_t limit = 0);
+ //void removeSatisfied(vec<XorClause*>& cs, ClauseSetType type, const uint32_t limit = 0);
void removeAndCleanAll(const bool nolimit = false);
bool satisfied(const Clause& c) const;
bool satisfied(const XorClause& c) const;
- 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]; ///<Last time we cleaned from satisfied clauses, this many unitary clauses were known
+ uint32_t lastNumUnitaryClean[6]; ///<Last time we cleaned from satisfied clauses&false literals, this many unitary clauses were known
+
Solver& solver;
};
+/**
+@brief Removes all satisfied clauses, and cleans false literals
+
+There is a heuristic in place not to try to clean all the time. However,
+this limit can be overridden with "nolimit"
+@p nolimit set this to force cleaning&removing. Useful if a really clean
+state is needed, which is important for certain algorithms
+*/
inline void ClauseCleaner::removeAndCleanAll(const bool nolimit)
{
- //uint limit = std::min((uint)((double)solver.order_heap.size() * PERCENTAGECLEANCLAUSES), FIXCLEANREPLACE);
- uint limit = (double)solver.order_heap.size() * PERCENTAGECLEANCLAUSES;
+ //uint32_t limit = std::min((uint32_t)((double)solver.order_heap.size() * PERCENTAGECLEANCLAUSES), FIXCLEANREPLACE);
+ uint32_t limit = (double)solver.order_heap.size() * PERCENTAGECLEANCLAUSES;
if (nolimit) limit = 0;
-
- removeSatisfied(solver.binaryClauses, ClauseCleaner::binaryClauses, limit);
+
+ removeSatisfiedBins(limit);
cleanClauses(solver.clauses, ClauseCleaner::clauses, limit);
cleanClauses(solver.xorclauses, ClauseCleaner::xorclauses, limit);
cleanClauses(solver.learnts, ClauseCleaner::learnts, limit);
}
-}; //NAMESPACE MINISAT
-
#endif //CLAUSECLEANER_H
--- /dev/null
+#ifndef CLAUSEOFFSET_H
+#define CLAUSEOFFSET_H
+
+#ifdef _MSC_VER
+#include <msvc/stdint.h>
+#else
+#include <stdint.h>
+#endif //_MSC_VER
+
+typedef uint32_t ClauseOffset;
+
+#endif //CLAUSEOFFSET_H
--- /dev/null
+/**************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+#include "ClauseVivifier.h"
+#include "ClauseCleaner.h"
+#include "time_mem.h"
+#include <iomanip>
+
+//#define ASSYM_DEBUG
+
+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<Lit> lits;
+ vec<Lit> unused;
+
+ if (solver.clauses.size() < 1000000) {
+ //if too many clauses, random order will do perfectly well
+ std::sort(solver.clauses.getData(), solver.clauses.getDataEnd(), sortBySize());
+ }
+
+ uint32_t queueByBy = 2;
+ if (numCalls > 8
+ && (solver.clauses_literals + solver.learnts_literals < 4000000)
+ && (solver.clauses.size() < 50000))
+ queueByBy = 1;
+
+ Clause **i, **j;
+ i = j = solver.clauses.getData();
+ for (Clause **end = solver.clauses.getDataEnd(); i != end; i++) {
+ if (needToFinish || lastTimeWentUntil > 0) {
+ if (!needToFinish) {
+ lastTimeWentUntil--;
+ thisTimeWentUntil++;
+ }
+ *j++ = *i;
+ continue;
+ }
+
+ //if done enough, stop doing it
+ if (solver.propagations-oldProps + extraDiff > maxNumProps) {
+ //std::cout << "Need to finish -- ran out of prop" << std::endl;
+ needToFinish = true;
+ }
+
+ //if bad performance, stop doing it
+ /*if ((i-solver.clauses.getData() > 5000 && effectiveLit < 300)) {
+ std::cout << "Need to finish -- not effective" << std::endl;
+ needToFinish = true;
+ }*/
+
+ Clause& c = **i;
+ extraDiff += c.size();
+ checkedClauses++;
+ thisTimeWentUntil++;
+
+ assert(c.size() > 2);
+ assert(!c.learnt());
+
+ unused.clear();
+ lits.clear();
+ lits.growTo(c.size());
+ memcpy(lits.getData(), c.getData(), c.size() * sizeof(Lit));
+
+ failed = false;
+ uint32_t done = 0;
+ solver.newDecisionLevel();
+ for (; done < lits.size();) {
+ uint32_t i2 = 0;
+ for (; (i2 < queueByBy) && ((done+i2) < lits.size()); i2++) {
+ lbool val = solver.value(lits[done+i2]);
+ if (val == l_Undef) {
+ solver.uncheckedEnqueueLight(~lits[done+i2]);
+ } else if (val == l_False) {
+ unused.push(lits[done+i2]);
+ }
+ }
+ done += i2;
+ failed = (!solver.propagate(false).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<Clause*>& clauses)
+{
+ assert(solver.ok);
+
+ vec<char> 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<Lit> 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<Lit>::const_iterator it2 = solver.transOTFCache[l->toInt()].lits.begin()
+ , end2 = solver.transOTFCache[l->toInt()].lits.end(); it2 != end2; it2++) {
+ seen[(~(*it2)).toInt()] = 0;
+ }
+ }
+
+ lits.clear();
+ for (const Lit *it2 = cl.getData(), *end2 = cl.getDataEnd(); it2 != end2; it2++) {
+ if (seen[it2->toInt()]) lits.push(*it2);
+ else litsRem++;
+ seen[it2->toInt()] = 0;
+ }
+ 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;
+}
--- /dev/null
+/**************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+#ifndef CLAUSEVIVIFIER_H
+#define CLAUSEVIVIFIER_H
+
+#include "Solver.h"
+
+class ClauseVivifier {
+ public:
+ ClauseVivifier(Solver& solver);
+ const bool vivifyClauses();
+ const bool vivifyClauses2(vec<Clause*>& clauses);
+
+ private:
+
+ /**
+ @brief Records data for asymmBranch()
+
+ Clauses are ordered accurding to sze in asymmBranch() and then some are
+ checked if we could shorten them. This value records that between calls
+ to asymmBranch() where we stopped last time in the list
+ */
+ uint32_t lastTimeWentUntil;
+
+ /**
+ @brief Sort clauses according to size
+ */
+ struct sortBySize
+ {
+ const bool operator () (const Clause* x, const Clause* y)
+ {
+ return (x->size() > y->size());
+ }
+ };
+
+ uint32_t numCalls;
+ Solver& solver;
+};
+
+#endif //CLAUSEVIVIFIER_H
--- /dev/null
+/**************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+#include "CompleteDetachReattacher.h"
+#include "VarReplacer.h"
+#include "ClauseCleaner.h"
+
+CompleteDetachReatacher::CompleteDetachReatacher(Solver& _solver) :
+ solver(_solver)
+{
+}
+
+/**
+@brief Completely detach all non-binary clauses
+*/
+void CompleteDetachReatacher::detachNonBinsNonTris(const bool removeTri)
+{
+ uint32_t oldNumBins = solver.numBins;
+ ClausesStay stay;
+
+ for (vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++) {
+ stay += clearWatchNotBinNotTri(*it, removeTri);
+ }
+
+ solver.learnts_literals = stay.learntBins;
+ solver.clauses_literals = stay.nonLearntBins;
+ solver.numBins = (stay.learntBins + stay.nonLearntBins)/2;
+ release_assert(solver.numBins == oldNumBins);
+}
+
+/**
+@brief Helper function for detachPointerUsingClauses()
+*/
+const CompleteDetachReatacher::ClausesStay CompleteDetachReatacher::clearWatchNotBinNotTri(vec<Watched>& ws, const bool removeTri)
+{
+ ClausesStay stay;
+
+ 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<Clause*>& 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<XorClause*>& cs)
+{
+ XorClause **i = cs.getData();
+ XorClause **j = i;
+ for (XorClause **end = cs.getDataEnd(); i != end; i++) {
+ if (cleanClause(**i)) {
+ solver.attachClause(**i);
+ *j++ = *i;
+ } else {
+ solver.clauseAllocator.clauseFree(*i);
+ }
+ }
+ cs.shrink(i-j);
+}
+
+/**
+@brief Not only cleans a clause from false literals, but if clause is satisfied, it reports it
+*/
+inline 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;
+}
--- /dev/null
+/**************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+#include "Solver.h"
+
+/**
+@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<Watched>& ws, const bool removeTri = false);
+
+ void cleanAndAttachClauses(vec<Clause*>& cs);
+ void cleanAndAttachClauses(vec<XorClause*>& cs);
+ const bool cleanClause(Clause*& ps);
+ const bool cleanClause(XorClause& ps);
+
+ Solver& solver;
+};
--- /dev/null
+/*****************************************************************************
+CryptoMiniSat -- Copyright (c) 2010 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+******************************************************************************/
+
+#include "DataSync.h"
+#include "Subsumer.h"
+#include "VarReplacer.h"
+#include "XorSubsumer.h"
+#include <iomanip>
+
+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<Lit>& bins = shared.bins[wsLit];
+ vec<Watched>& ws = solver.watches[wsLit];
+
+ if (bins.size() > syncFinish[wsLit]
+ && !syncBinFromOthers(lit1, bins, syncFinish[wsLit], ws)) return false;
+ }
+
+ syncBinToOthers();
+
+ if (solver.conf.verbosity >= 3) {
+ std::cout << "c got bins " << std::setw(10) << (recvBinData - oldRecvBinData)
+ << std::setw(10) << " sent bins " << (sentBinData - oldSentBinData) << std::endl;
+ }
+
+ return true;
+}
+
+template <class T>
+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<Lit>& ps);
+
+const bool DataSync::syncBinFromOthers(const Lit lit, const vector<Lit>& bins, uint32_t& finished, vec<Watched>& ws)
+{
+ assert(solver.varReplacer->getReplaceTable()[lit.var()].var() == lit.var());
+ assert(solver.subsumer->getVarElimed()[lit.var()] == false);
+ assert(solver.xorSubsumer->getVarElimed()[lit.var()] == false);
+
+ vec<Lit> addedToSeen;
+ for (Watched *it = ws.getData(), *end = ws.getDataEnd(); it != end; it++) {
+ if (it->isBinary()) {
+ addedToSeen.push(it->getOtherLit());
+ seen[it->getOtherLit().toInt()] = true;
+ }
+ }
+
+ vec<Lit> lits(2);
+ for (uint32_t i = finished; i < bins.size(); i++) {
+ if (!seen[bins[i].toInt()]) {
+ Lit otherLit = bins[i];
+ otherLit = solver.varReplacer->getReplaceTable()[otherLit.var()] ^ otherLit.sign();
+ if (solver.subsumer->getVarElimed()[otherLit.var()]
+ || solver.xorSubsumer->getVarElimed()[otherLit.var()]
+ || solver.value(otherLit.var()) != l_Undef
+ ) continue;
+
+ recvBinData++;
+ lits[0] = lit;
+ lits[1] = otherLit;
+ solver.addClauseInt(lits, 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<std::pair<Lit, Lit> >::const_iterator it = newBinClauses.begin(), end = newBinClauses.end(); it != end; it++) {
+ addOneBinToOthers(it->first, it->second);
+ }
+
+ newBinClauses.clear();
+}
+
+void DataSync::addOneBinToOthers(const Lit lit1, const Lit lit2)
+{
+ assert(lit1.toInt() < lit2.toInt());
+
+ vector<Lit>& bins = sharedData->bins[(~lit1).toInt()];
+ for (vector<Lit>::const_iterator it = bins.begin(), end = bins.end(); it != end; it++) {
+ if (*it == lit2) return;
+ }
+
+ bins.push_back(lit2);
+ sentBinData++;
+}
+
+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
--- /dev/null
+/*****************************************************************************
+CryptoMiniSat -- Copyright (c) 2010 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+******************************************************************************/
+
+#include "SharedData.h"
+#include "Solver.h"
+
+class DataSync
+{
+ public:
+ DataSync(Solver& solver, SharedData* sharedData);
+ void newVar();
+ const bool syncData();
+
+
+ template <class T> 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<Lit>& bins, uint32_t& finished, vec<Watched>& ws);
+ void syncBinToOthers();
+ void addOneBinToOthers(const Lit lit1, const Lit lit2);
+ const bool shareBinData();
+
+ //stuff to sync
+ vector<std::pair<Lit, Lit> > newBinClauses;
+
+ //stats
+ uint64_t lastSyncConf;
+ vec<uint32_t> syncFinish;
+ uint32_t sentUnitData;
+ uint32_t recvUnitData;
+ uint32_t sentBinData;
+ uint32_t recvBinData;
+
+ //misc
+ vec<char> seen;
+
+ //main data
+ SharedData* sharedData;
+ Solver& solver;
+};
+
+inline 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;
+}
+
--- /dev/null
+/*****************************************************************************
+MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+Original code by MiniSat authors are under an MIT licence.
+Modifications for CryptoMiniSat are under GPLv3 licence.
+******************************************************************************/
+
+#include "DimacsParser.h"
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+
+#include "Solver.h"
+
+#ifdef VERBOSE_DEBUG
+#define DEBUG_COMMENT_PARSING
+#endif //VERBOSE_DEBUG
+
+//#define DEBUG_COMMENT_PARSING
+
+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<Lit>& 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 <class T>
+void DimacsParser::parse_DIMACS(T input_stream)
+{
+ debugLibPart = 1;
+ numLearntClauses = 0;
+ numNormClauses = 0;
+ numXorClauses = 0;
+ uint32_t origNumVars = solver->nVars();
+
+ StreamBuffer in(input_stream);
+ parse_DIMACS_main(in);
+
+ if (solver->conf.verbosity >= 1) {
+ std::cout << "c -- clauses added: "
+ << std::setw(12) << numLearntClauses
+ << " learnts, "
+ << std::setw(12) << numNormClauses
+ << " normals, "
+ << std::setw(12) << numXorClauses
+ << " xors"
+ << std::endl;
+
+ std::cout << "c -- vars added " << std::setw(10) << (solver->nVars() - origNumVars)
+ << std::endl;
+ }
+}
+
+#ifndef DISABLE_ZLIB
+template void DimacsParser::parse_DIMACS(gzFile input_stream);
+#endif
+template void DimacsParser::parse_DIMACS(FILE* input_stream);
--- /dev/null
+/*****************************************************************************
+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 <string>
+#include "SolverTypes.h"
+#include "constants.h"
+#include "StreamBuffer.h"
+#include "Vec.h"
+
+#ifdef _MSC_VER
+#include <msvc/stdint.h>
+#else
+#include <stdint.h>
+#endif //_MSC_VER
+
+#ifndef DISABLE_ZLIB
+#include <zlib.h>
+#endif // DISABLE_ZLIB
+
+#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 <class T>
+ void parse_DIMACS(T input_stream);
+
+ private:
+ void parse_DIMACS_main(StreamBuffer& in);
+ void skipWhitespace(StreamBuffer& in);
+ void skipLine(StreamBuffer& in);
+ std::string untilEnd(StreamBuffer& in);
+ int parseInt(StreamBuffer& in, uint32_t& len);
+ float parseFloat(StreamBuffer& in);
+ void parseString(StreamBuffer& in, std::string& str);
+ void readClause(StreamBuffer& in, vec<Lit>& 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; ///<printing partial solutions to debugLibPart1..N.output when "debugLib" is set to TRUE
+ uint32_t groupId;
+ vec<Lit> lits; ///<To reduce temporary creation overhead
+ uint32_t numLearntClauses; ///<Number of learnt non-xor clauses added
+ uint32_t numNormClauses; ///<Number of non-learnt, non-xor claues added
+ uint32_t numXorClauses; ///<Number of non-learnt xor clauses added
+};
+
+#endif //DIMACSPARSER_H
--- /dev/null
+/**************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+#include "FailedLitSearcher.h"
+
+#include <iomanip>
+#include <utility>
+#include <set>
+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<uint32_t>& occ = occur[var];
+ if (occ.empty()) return;
+
+ for (uint32_t *it = &occ[0], *end = it + occ.size(); it != end; it++) {
+ xorClauseSizes[*it]--;
+ if (!xorClauseTouched[*it]) {
+ xorClauseTouched.setBit(*it);
+ investigateXor.push(*it);
+ }
+ }
+}
+
+/**
+@brief Undoes what removeVarFromXors() has done
+*/
+inline void FailedLitSearcher::addVarFromXors(const Var var)
+{
+ vector<uint32_t>& occ = occur[var];
+ if (occ.empty()) return;
+
+ for (uint32_t *it = &occ[0], *end = it + occ.size(); it != end; it++) {
+ xorClauseSizes[*it]++;
+ }
+}
+
+/**
+@brief Returns the 2-long xor clause that has been made of the longer xor-clause under current assignement
+
+We KNOW that the xorclause "c" passed as a parameter must be 2-long. We just
+need it so that we can work with it. We KNOW it's 2-long because of the
+data structures and functions in place
+
+@p[in] c MUST be a 2-long xor clause under current assignement
+*/
+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<Solver::VarOrderLt> order_heap_copy(solver.order_heap); //for hyperbin
+
+ //General Stats
+ numFailed = 0;
+ goodBothSame = 0;
+ numCalls++;
+
+ //If failed var searching is going good, do successively more and more of it
+ if ((double)lastTimeFoundTruths > (double)solver.order_heap.size() * 0.10) numPropsMultiplier = std::max(numPropsMultiplier*1.3, 2.0);
+ else numPropsMultiplier = 1.0;
+ numProps = (uint64_t) ((double)numProps * numPropsMultiplier * solver.conf.failedLitMultiplier);
+
+ //For BothSame
+ propagated.resize(solver.nVars(), 0);
+ propValue.resize(solver.nVars(), 0);
+
+ //For calculating how many variables have really been set
+ origTrailSize = solver.trail.size();
+
+ //For 2-long xor (rule 6 of Equivalent literal propagation in the DLL procedure by Chu-Min Li)
+ toReplaceBefore = solver.varReplacer->getNewToReplaceVars();
+ lastTrailSize = solver.trail.size();
+ binXorFind = true;
+ twoLongXors.clear();
+ if (solver.xorclauses.size() < 5 ||
+ solver.xorclauses.size() > 30000 ||
+ solver.order_heap.size() > 30000 ||
+ solver.nClauses() > 100000)
+ binXorFind = false;
+ if (binXorFind) {
+ solver.clauseCleaner->cleanClauses(solver.xorclauses, ClauseCleaner::xorclauses);
+ addFromSolver(solver.xorclauses);
+ }
+ xorClauseTouched.resize(solver.xorclauses.size(), 0);
+ newBinXor = 0;
+
+ //For 2-long xor through Le Berre paper
+ bothInvert = 0;
+
+ //For HyperBin
+ addedBin = 0;
+ unPropagatedBin.resize(solver.nVars(), 0);
+ needToVisit.resize(solver.nVars(), 0);
+ dontRemoveAncestor.resize(solver.nVars(), 0);
+ hyperbinProps = 0;
+ maxHyperBinProps = numProps/4;
+ 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<Lit> toVisit;
+ uint64_t extraTime = 0;
+
+ solver.newDecisionLevel();
+ solver.uncheckedEnqueueLight2(lit, 0, lit_Undef, false);
+ failed = (!solver.propagateBin(uselessBin).isNULL());
+ assert(!failed);
+
+ if (solver.conf.doRemUselessLBins && !uselessBin.empty()) {
+ for (const Lit *it = uselessBin.getData(), *end = uselessBin.getDataEnd(); it != end; it++) {
+ if (dontRemoveAncestor[it->var()]) continue;
+
+ extraTime += solver.watches[lit.toInt()].size()/2;
+ extraTime += solver.watches[(~*it).toInt()].size()/2;
+ if (findWBin(solver.watches, ~lit, *it, true)) {
+ removeWBin(solver.watches[lit.toInt()], *it, true);
+ removeWBin(solver.watches[(~*it).toInt()], ~lit, true);
+ solver.learnts_literals -= 2;
+ solver.numBins--;
+ removedUselessLearnt++;
+ } else if (!solver.binPropData[it->var()].learntLeadHere) {
+ removeWBin(solver.watches[lit.toInt()], *it, false);
+ removeWBin(solver.watches[(~*it).toInt()], ~lit, false);
+ solver.clauses_literals -= 2;
+ solver.numBins--;
+ removedUselessNonLearnt++;
+ } else {
+ continue;
+ }
+
+ Var ancestorVar = solver.binPropData[it->var()].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++;
+}
--- /dev/null
+/***************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+****************************************************************************/
+
+#ifndef FAILEDLITSEARCHER_H
+#define FAILEDLITSEARCHER_H
+
+#include <set>
+#include <map>
+#include <vector>
+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; ///<The solver we are updating&working with
+
+ bool failed; ///<For checking that a specific propagation failed (=conflict). It is used in many places
+
+ //bothprop finding
+ BitArray propagated; ///<These lits have been propagated by propagating the lit picked
+ BitArray propValue; ///<The value (0 or 1) of the lits propagated set in "propagated"
+ /**
+ @brief Lits that have been propagated to the same value both by "var" and "~var"
+
+ value that the literal has been propagated to is available in propValue
+ */
+ vec<Lit> bothSame;
+
+ //2-long xor-finding
+ /**
+ @brief used to find 2-long xor by shortening longer xors to this size
+
+ -# We propagate "var" and record all xors that become 2-long
+ -# We propagate "~var" and record all xors that become 2-long
+ -# if (1) and (2) have something in common, we add it as a variable
+ replacement instruction
+
+ We must be able to order these 2-long xors, so that we can search
+ for matching couples fast. This class is used for that
+ */
+ class TwoLongXor
+ {
+ public:
+ 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<XorClause*>& cs);
+ void removeVarFromXors(const Var var);
+ void addVarFromXors(const Var var);
+
+ uint32_t newBinXor;
+ vec<uint32_t> xorClauseSizes;
+ vector<vector<uint32_t> > occur; ///<Occurence list for XORs. Indexed by variables
+ BitArray xorClauseTouched;
+ vec<uint32_t> investigateXor;
+ std::set<TwoLongXor> twoLongXors;
+ bool binXorFind;
+ uint32_t lastTrailSize;
+ vector<BinXorToAdd> binXorToAdd;
+
+ /**
+ @brief Num. 2-long xor-found through Le Berre paper
+
+ In case:
+ -# (a->b, ~a->~b) -> a=b
+ -# binary clause (a,c) exists: (a->g, c->~g) -> a = ~c
+ */
+ uint32_t bothInvert;
+
+ //finding HyperBins
+ struct LitOrder2
+ {
+ LitOrder2(const vec<BinPropData>& _binPropData) :
+ binPropData(_binPropData)
+ {}
+
+ const bool operator () (const Lit x, const Lit y) const
+ {
+ return binPropData[x.var()].lev > binPropData[y.var()].lev;
+ }
+
+ const vec<BinPropData>& binPropData;
+ };
+ uint32_t addedBin;
+ void hyperBinResolution(const Lit lit);
+ BitArray unPropagatedBin;
+ BitArray needToVisit;
+ vec<Var> propagatedVars;
+ void addBin(const Lit lit1, const Lit lit2);
+ void fillImplies(const Lit lit);
+ vec<Var> myImpliesSet; ///<variables set in myimplies
+ uint64_t hyperbinProps; ///<Number of bogoprops done by the hyper-binary resolution function hyperBinResolution()
+
+ //bin-removal within hyper-bin-res
+ vec<Lit> uselessBin;
+ uint32_t removedUselessLearnt;
+ uint32_t removedUselessNonLearnt;
+ BitArray dontRemoveAncestor;
+ vec<Var> toClearDontRemoveAcestor;
+ /**
+ @brief Controls hyper-binary resolution's time-usage
+
+ Don't do more than this many propagations within hyperBinResolution()
+ */
+ uint64_t maxHyperBinProps;
+
+ //Temporaries
+ vec<Lit> tmpPs;
+
+ //State for this run
+ /**
+ @brief Records num. var-replacement istructions between 2-long xor findings through longer xor shortening
+
+ Finding 2-long xor claues by shortening is fine, but sometimes we find
+ the same thing, or find something that is trivially a consequence of
+ other 2-long xors that we already know. To filter out these bogus
+ "findigs" from the statistics reported, we save in this value the
+ real var-replacement insturctions before and after the 2-long xor
+ finding through longer xor-shortening, and then compare the changes
+ made
+ */
+ uint32_t toReplaceBefore;
+ uint32_t origTrailSize; ///<Records num. of 0-depth assignments at the start-up of search()
+ uint64_t origProps; ///<Records num. of bogoprops at the start-up of search()
+ uint32_t numFailed; ///<Records num. of failed literals during search()
+ uint32_t goodBothSame; ///<Records num. of literals that have been propagated to the same value by both "var" and "~var"
+
+ //State between runs
+ double totalTime;
+ double numPropsMultiplier; ///<If last time we called search() all went fine, then this is incremented, so we do more searching this time
+ uint32_t lastTimeFoundTruths; ///<Records how many unit clauses we found last time we called search()
+ uint32_t numCalls; ///<Number of times search() has been called
+ uint32_t lastTimeStopped;
+};
+
+inline const double FailedLitSearcher::getTotalTime() const
+{
+ return totalTime;
+}
+
+
+#endif //FAILEDVARSEARCHER_H
+
+++ /dev/null
-/***********************************************************************************
-CryptoMiniSat -- Copyright (c) 2009 Mate Soos
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-**************************************************************************************************/
-
-#include "FailedVarSearcher.h"
-
-#include <iomanip>
-#include <utility>
-#include <set>
-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<uint32_t>& occ = occur[var];
- if (occ.empty()) return;
-
- for (uint32_t *it = &occ[0], *end = it + occ.size(); it != end; it++) {
- xorClauseSizes[*it]--;
- if (!xorClauseTouched[*it]) {
- xorClauseTouched.setBit(*it);
- investigateXor.push(*it);
- }
- }
-}
-
-inline void FailedVarSearcher::addVarFromXors(const Var var)
-{
- vector<uint32_t>& occ = occur[var];
- if (occ.empty()) return;
-
- for (uint32_t *it = &occ[0], *end = it + occ.size(); it != end; it++) {
- xorClauseSizes[*it]++;
- }
-}
-
-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<Solver::VarOrderLt> 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<uint32_t>& _litDegrees) :
- litDegrees(_litDegrees)
- {}
-
- bool operator () (const Lit& x, const Lit& y) {
- return litDegrees[x.toInt()] > litDegrees[y.toInt()];
- }
-
- const vector<uint32_t>& 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<Lit> 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<class T>
-inline void FailedVarSearcher::cleanAndAttachClauses(vec<T*>& 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
+++ /dev/null
-/***********************************************************************************
-CryptoMiniSat -- Copyright (c) 2009 Mate Soos
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-**************************************************************************************************/
-
-#ifndef FAILEDVARSEARCHER_H
-#define FAILEDVARSEARCHER_H
-
-#include <set>
-#include <map>
-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<XorClause*>& cs);
- uint32_t newBinXor;
-
- //For detach&re-attach (when lots of vars found)
- template<class T>
- void cleanAndAttachClauses(vec<T*>& 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<Lit> bothSame;
-
- //2-long xor-finding
- vec<uint32_t> xorClauseSizes;
- vector<vector<uint32_t> > occur;
- void removeVarFromXors(const Var var);
- void addVarFromXors(const Var var);
- BitArray xorClauseTouched;
- vec<uint32_t> investigateXor;
- std::set<TwoLongXor> 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<Var> propagatedVars;
- void addBin(const Lit& lit1, const Lit& lit2);
- void fillImplies(const Lit& lit);
- BitArray myimplies;
- vec<Var> myImpliesSet;
- uint64_t hyperbinProps;
- vector<uint32_t> litDegrees;
- const bool orderLits();
- uint64_t maxHyperBinProps;
- uint64_t binClauseAdded;
-
- //Temporaries
- vec<Lit> 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
-
#include "VarReplacer.h"
#include <algorithm>
-namespace MINISAT
-{
-using namespace MINISAT;
-
FindUndef::FindUndef(Solver& _solver) :
solver(_solver)
, isPotentialSum(0)
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();
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;
}
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;
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;
{
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;
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()]) {
return allSat;
}
-}; //NAMESPACE MINISAT
#include "Solver.h"
-namespace MINISAT
-{
-using namespace MINISAT;
-
class FindUndef {
public:
FindUndef(Solver& _solver);
- const uint unRoll();
+ const uint32_t unRoll();
private:
Solver& solver;
};
-}; //NAMESPACE MINISAT
-
-#endif //
\ No newline at end of file
+#endif //
-/***********************************************************************************
+/***************************************************************************
CryptoMiniSat -- Copyright (c) 2009 Mate Soos
This program is free software: you can redistribute it and/or modify
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-**************************************************************************************************/
+*****************************************************************************/
#include "Gaussian.h"
#include "Clause.h"
#include <algorithm>
#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 <iterator>
#endif
-namespace MINISAT
-{
-using namespace MINISAT;
static const uint16_t unassigned_col = std::numeric_limits<uint16_t>::max();
static const Var unassigned_var = std::numeric_limits<Var>::max();
-ostream& operator << (ostream& os, const vec<Lit>& 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<XorClause*>& _xorclauses) :
+Gaussian::Gaussian(Solver& _solver, const GaussConf& _config, const uint32_t _matrix_no, const vector<XorClause*>& _xorclauses) :
solver(_solver)
, config(_config)
, matrix_no(_matrix_no)
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
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:
badlevel = 0;
return;
}
-
+
matrix_sets.clear();
matrix_sets.push_back(cur_matrixset);
gauss_last_level = solver.trail.size();
#endif
}
-uint Gaussian::select_columnorder(vector<uint16_t>& var_to_col, matrixset& origMat)
+uint32_t Gaussian::select_columnorder(vector<uint16_t>& 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);
else v = vars[iterReduceIt++];
if (var_to_col[v] == 1) {
#ifdef DEBUG_GAUSS
- vector<uint>::iterator it =
+ vector<uint32_t>::iterator it =
std::find(origMat.col_to_var.begin(), origMat.col_to_var.end(), v);
assert(it == origMat.col_to_var.end());
#endif
-
+
origMat.col_to_var.push_back(v);
var_to_col[v] = origMat.col_to_var.size()-1;
var_is_in.setBit(v);
}
//for the ones that were not in the order_heap, but are marked in var_to_col
- for (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;
}
}
- #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<uint>(cout, ","));
+ std::copy(origMat.col_to_var.begin(), origMat.col_to_var.end(), std::ostream_iterator<uint32_t>(cout, ","));
cout << endl;
#endif
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);
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);
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();
}
}
} 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);
{
#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);
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();
*i = m.num_rows;
}
-Gaussian::gaussian_ret Gaussian::gaussian(Clause*& confl)
+Gaussian::gaussian_ret Gaussian::gaussian(PropBy& confl)
{
if (solver.decisionLevel() >= badlevel)
return nothing;
#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];
}
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();
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])
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
#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;
#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()) {
}
j++;
}
-
+
finish:
m.least_column_changed = INT_MAX;
#ifdef VERBOSE_DEBUG
cout << "Finished elimination" << endl;
cout << "Returning with i,j:" << i << ", " << j << "(" << m.num_rows << ", " << m.num_cols << ")" << endl;
+ #ifdef VERBOSE_DEBUG_MORE
print_matrix(m);
print_last_one_in_cols(m);
+ #endif
cout << "(" << matrix_no << ")Exchanged:" << no_exchanged << " row additions:" << number_of_row_additions << endl;
#endif
-
+
#ifdef DEBUG_GAUSS
assert(check_last_one_in_cols(m));
- 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);
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)
#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<int32_t>::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
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
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++;
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<Gaussian*>::iterator gauss = solver.gauss_matrixes.begin(), end= solver.gauss_matrixes.end(); gauss != end; gauss++)
if (*gauss != this) (*gauss)->canceling(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);
#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;
|| (this_size <= 1)
)) {
assert(maxlevel != std::numeric_limits<int32_t>::max());
-
+
#ifdef VERBOSE_DEBUG
cout << "(" << matrix_no << ")Other found conflict just as good or better.";
cout << "(" << matrix_no << ") || Old maxlevel:" << maxlevel << " new maxlevel:" << this_maxlevel;
cout << "(" << matrix_no << ") || Old size:" << size << " new size:" << this_size << endl;
//assert(!(maxlevel != UINT_MAX && maxlevel != this_maxlevel)); //NOTE: only holds if gauss is executed at each level
#endif
-
+
return;
}
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;
}
//&& 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<Lit>& learnt_clause, int& conflictC)
+llbool Gaussian::find_truths(vec<Lit>& 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;
}
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:
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]) << ")";
}
col++;
}
- if (!row.is_true()) cout << "xor_clause_inverted";
+ if (!row.is_true()) cout << "xorEqualFalse";
}
const string Gaussian::lbool_to_string(const lbool toprint)
return "false";
if (toprint == l_Undef)
return "undef";
-
+
assert(false);
return "";
}
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;
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)
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;
}
}
{
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;
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);
assert(!m.var_is_set[var]);
assert(mat_row[col]);
} else assert(false);
-
+
col++;
}
if ((final^!mat_row.is_true()) != !var_row.is_true()) {
}
}
-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);
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;
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]]);
{
#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()) {
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);
#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));
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
cout << "Updated " << num_updated << " matrix cols. Could remove " << m.removeable_cols << " cols (out of " << m.num_cols << " )" <<endl;
#endif
}*/
-
-}; //NAMESPACE MINISAT
#include <vector>
#include <limits>
+#include <string>
+#include <utility>
+using std::string;
+using std::pair;
+
#ifdef _MSC_VER
#include <msvc/stdint.h>
#else
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<XorClause*>& xorclauses);
+ Gaussian(Solver& solver, const GaussConf& config, const uint32_t matrix_no, const vector<XorClause*>& xorclauses);
~Gaussian();
const bool full_init();
- llbool find_truths(vec<Lit>& learnt_clause, int& conflictC);
+ llbool find_truths(vec<Lit>& 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<XorClause*> xorclauses;
enum gaussian_ret {conflict, unit_conflict, propagation, unit_propagation, nothing};
- gaussian_ret gaussian(Clause*& confl);
+ gaussian_ret gaussian(PropBy& confl);
vector<Var> col_to_var_original; //Matches columns to variables
BitArray var_is_in; //variable is part of the the matrix. var_is_in's size is _minimal_ so you should check whether var_is_in.getSize() < var before issuing var_is_in[var]
- uint badlevel;
+ uint32_t badlevel;
class matrixset
{
BitArray var_is_set;
vector<Var> col_to_var; // col_to_var[COL] tells which variable is at a given column in the matrix. Gives unassigned_var if the COL has been zeroed (i.e. the variable assigned)
uint16_t num_rows; // number of active rows in the matrix. Unactive rows are rows that contain only zeros (and if they are conflicting, then the conflict has been treated)
- 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<uint16_t> last_one_in_col; //last_one_in_col[COL] tells the last row+1 that has a '1' in that column. Used to reduce the burden of Gauss elim. (it only needs to look until that row)
vector<uint16_t> first_one_in_row;
- 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
//Varibales to keep Gauss state
bool messed_matrix_vars_since_reversal;
int gauss_last_level;
- vector<pair<Clause*, uint> > clauses_toclear;
+ vector<pair<Clause*, uint32_t> > clauses_toclear;
bool disabled; // Gauss is disabled
-
+
//State of current elimnation
- vec<uint> propagatable_rows; //used to store which rows were deemed propagatable during elimination
+ vec<uint32_t> propagatable_rows; //used to store which rows were deemed propagatable during elimination
vector<unsigned char> changed_rows; //used to store which rows were deemed propagatable during elimination
//Statistics
- 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<uint16_t>& var_to_col, matrixset& origMat); // Fills var_to_col and col_to_var of the origMat matrix.
+ uint32_t select_columnorder(vector<uint16_t>& var_to_col, matrixset& origMat); // Fills var_to_col and col_to_var of the origMat matrix.
//Main function
- 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<Lit> 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?
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);
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);
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;
}
std::ostream& operator << (std::ostream& os, const vec<Lit>& v);
-}; //NAMESPACE MINISAT
-
#endif //GAUSSIAN_H
#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)
, 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
#define SND_WIDTH 35
#define TRD_WIDTH 10
-namespace MINISAT
-{
-using namespace MINISAT;
-
Logger::Logger(int& _verbosity) :
proof_graph_on(false)
, mini_proof(false)
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();
}
last_unitary_learnt_clauses = S->get_unitary_learnts_num();
}
-}; //NAMESPACE MINISAT
using std::string;
using std::map;
-namespace MINISAT
-{
-using namespace MINISAT;
-
class Solver;
class MyAvg {
uint proofStarts;
};
-}; //NAMESPACE MINISAT
-
#endif //LOGGER_H
#ifndef MERSENNETWISTER_H
#define MERSENNETWISTER_H
+// Not thread safe (unless auto-initialization is avoided and each thread has
+// its own MTRand object)
+
#include <iostream>
#include <limits.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
-namespace MINISAT
-{
-
-// Not thread safe (unless auto-initialization is avoided and each thread has
-// its own MTRand object)
-
class MTRand {
// Data
public:
mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left];
return is;
}
-};
#endif // MERSENNETWISTER_H
-/******************************************************************************************[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 <ctime>
#include <cstring>
#include <sstream>
#include <iostream>
#include <iomanip>
-#include <vector>
+#include <omp.h>
#ifdef _MSC_VER
#include <msvc/stdint.h>
#else
#include <stdint.h>
#endif //_MSC_VER
+#include <map>
+#include <set>
#include <signal.h>
-#ifndef DISABLE_ZLIB
-#include <zlib.h>
-#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 <fpu_control.h>
#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<uint32_t>::max();
-static bool printResult = true;
-
-//=================================================================================================
-// DIMACS Parser:
+std::map<uint32_t, Solver*> solversToInterrupt;
+std::set<uint32_t> 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<class B>
-static void skipWhitespace(B& in)
-{
- while ((*in >= 9 && *in <= 13) || *in == 32)
- ++in;
}
-template<class B>
-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<class B>
-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<class B>
-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<class B>
-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<class B>
-static void readClause(B& in, Solver& S, vec<Lit>& 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<class B>
-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<class B>
-static void parse_DIMACS_main(B& in, Solver& S)
-{
- vec<Lit> 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<class T, class T2>
-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<class T>
-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] <input-file> <result-output-file>\n\n where input is plain DIMACS.\n\n", argv[0]);
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");
printf(" should be maximum length of the clause dumped. Useful\n");
printf(" to make the resulting file smaller. Default is 2^32-1\n");
printf(" note: 2-long XOR-s are always dumped.\n");
+ printf(" --dumporig = <filename> If interrupted or reached restart limit, dump\n");
+ printf(" the original problem instance, simplified to the\n");
+ printf(" current point.\n");
+ printf(" --alsoread = <filename> Also read this file in\n");
+ printf(" Can be used to re-read dumped learnts, for example\n");
printf(" --maxsolutions = Search for given amount of solutions\n");
- printf(" --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");
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)
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);
} 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;
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);
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="))) {
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=<filename> must be first activated before issuing -maxdumplearnts=<size>\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);
} 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 ? "<stdin>" : 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<Lit> lits;
+ for (Var var = 0; var != solver.nVars(); var++) {
+ if (solver.model[var] != l_Undef) {
+ lits.push( Lit(var, (solver.model[var] == l_True)? true : false) );
+ }
+ }
+ solver.addClause(lits);
+ }
}
- if (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<Lit> 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();
}
-
--- /dev/null
+/*****************************************************************************
+MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+Original code by MiniSat authors are under an MIT licence.
+Modifications for CryptoMiniSat are under GPLv3 licence.
+******************************************************************************/
+
+#ifndef MAIN_H
+#define MAIN_H
+
+#include <string>
+using std::string;
+#include <vector>
+#ifndef DISABLE_ZLIB
+#include <zlib.h>
+#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<std::string> filesToRead;
+
+ SharedData sharedData;
+
+ int argc;
+ char** argv;
+};
+
+#endif //MAIN_H
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
using std::cout;
using std::endl;
-namespace MINISAT
-{
-using namespace MINISAT;
-
//#define PART_FINDING
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++;
i2++;
}
}
-
+
return (i1 == c1.size());
}
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<XorClause*> xorclauses;
xorclauses.reserve(solver.xorclauses.size());
for (uint32_t i = 0; i < solver.xorclauses.size(); i++)
solver.gauss_matrixes.push_back(new Gaussian(solver, solver.gaussconfig, 0, xorclauses));
return true;
}
-
+
for (XorClause** c = solver.xorclauses.getData(), **end = c + solver.xorclauses.size(); c != end; c++) {
- set<uint> tomerge;
+ set<uint32_t> tomerge;
vector<Var> newSet;
for (Lit *l = &(**c)[0], *end2 = l + (**c).size(); l != end2; l++) {
if (table[l->var()] != var_Undef)
newSet.push_back(l->var());
}
if (tomerge.size() == 1) {
- const uint into = *tomerge.begin();
- map<uint, vector<Var> >::iterator intoReverse = reverseTable.find(into);
- for (uint i = 0; i < newSet.size(); i++) {
+ const uint32_t into = *tomerge.begin();
+ map<uint32_t, vector<Var> >::iterator intoReverse = reverseTable.find(into);
+ for (uint32_t i = 0; i < newSet.size(); i++) {
intoReverse->second.push_back(newSet[i]);
table[newSet[i]] = into;
}
continue;
}
-
- for (set<uint>::iterator it = tomerge.begin(); it != tomerge.end(); it++) {
+
+ for (set<uint32_t>::iterator it = tomerge.begin(); it != tomerge.end(); it++) {
newSet.insert(newSet.end(), reverseTable[*it].begin(), reverseTable[*it].end());
reverseTable.erase(*it);
}
- for (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<uint, vector<Var> >::iterator it = reverseTable.begin(), end = reverseTable.end(); it != end; it++) {
+ for (map<uint32_t, vector<Var> >::iterator it = reverseTable.begin(), end = reverseTable.end(); it != end; it++) {
cout << "-- set begin --" << endl;
for (vector<Var>::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) {
cout << *it2 << ", ";
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<Gaussian*>::iterator gauss = solver.gauss_matrixes.begin(), end = solver.gauss_matrixes.end(); gauss != end; gauss++) {
if (!(*gauss)->full_init()) return false;
return true;
}
-const uint MatrixFinder::setMatrixes()
+const uint32_t MatrixFinder::setMatrixes()
{
- vector<pair<uint, uint> > numXorInMatrix;
- for (uint i = 0; i < matrix_no; i++)
+ vector<pair<uint32_t, uint32_t> > numXorInMatrix;
+ for (uint32_t i = 0; i < matrix_no; i++)
numXorInMatrix.push_back(std::make_pair(i, 0));
-
- vector<uint> sumXorSizeInMatrix(matrix_no, 0);
- vector<vector<uint> > xorSizesInMatrix(matrix_no);
+
+ vector<uint32_t> sumXorSizeInMatrix(matrix_no, 0);
+ vector<vector<uint32_t> > xorSizesInMatrix(matrix_no);
vector<vector<XorClause*> > xorsInMatrix(matrix_no);
-
+
#ifdef PART_FINDING
vector<vector<Var> > xorFingerprintInMatrix(matrix_no);
#endif
-
+
for (XorClause** c = solver.xorclauses.getData(), **end = c + solver.xorclauses.size(); c != end; c++) {
XorClause& x = **c;
- const 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<Var>& xorFingerprintInMatrix, vector<XorClause*>& 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];
}
}
}
-
-}; //NAMESPACE MINISAT
#include "Clause.h"
#include "Solver.h"
-namespace MINISAT
-{
-using namespace MINISAT;
-
class Solver;
using std::map;
const bool findMatrixes();
private:
- const uint setMatrixes();
+ const uint32_t setMatrixes();
struct mysorter
{
- bool operator () (const pair<uint, uint>& left, const pair<uint, uint>& right)
+ bool operator () (const pair<uint32_t, uint32_t>& left, const pair<uint32_t, uint32_t>& right)
{
return left.second < right.second;
}
inline const Var fingerprint(const XorClause& c) const;
inline const bool firstPartOfSecond(const XorClause& c1, const XorClause& c2) const;
- map<uint, vector<Var> > reverseTable; //matrix -> vars
+ map<uint32_t, vector<Var> > reverseTable; //matrix -> vars
vector<Var> table; //var -> matrix
- uint matrix_no;
+ uint32_t matrix_no;
Solver& solver;
};
-}; //NAMESPACE MINISAT
#endif //MATRIXFINDER_H
+++ /dev/null
-// 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 <iostream>
-#include <limits.h>
-#include <stdio.h>
-#include <time.h>
-#include <math.h>
-
-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
#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<WatchedBin> & 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()) {
return true;
}
-const bool OnlyNonLearntBins::propagateBinExcept(const Lit& exceptLit)
-{
- while (solver.qhead < solver.trail.size()) {
- Lit p = solver.trail[solver.qhead++];
- vec<WatchedBin> & 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<WatchedBin> & 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<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit = ~Lit::toLit(wsLit);
+ const vec<Watched>& 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
#define ONLYNONLEARNTBINS_H
#include "Solver.h"
-#include <set>
-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<vec<WatchedBin> >& getBinWatches() const;
private:
- vec<vec<WatchedBin> > binwatches;
- set<uint64_t> toRemove;
-
+ vec<vec<WatchedBin> > binwatches; ///<Internal wathclists for non-learnt binary clauses
+
Solver& solver;
};
-}; //NAMESPACE MINISAT
+inline const uint32_t OnlyNonLearntBins::getWatchSize(const Lit lit) const
+{
+ return binwatches[lit.toInt()].size();
+}
-#endif //ONLYNONLEARNTBINS_H
+inline const vec<vec<OnlyNonLearntBins::WatchedBin> >& OnlyNonLearntBins::getBinWatches() const
+{
+ return binwatches;
+}
+#endif //ONLYNONLEARNTBINS_H
//#define DEBUG_MATRIX
-namespace MINISAT
-{
-using namespace MINISAT;
-
class PackedMatrix
{
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)) {
numCols = num_cols;
}
- void resizeNumRows(const uint num_rows)
+ void resizeNumRows(const uint32_t num_rows)
{
#ifdef DEBUG_MATRIX
assert(num_rows <= numRows);
return *this;
}
- inline PackedRow getMatrixAt(const uint i)
+ inline PackedRow getMatrixAt(const uint32_t i)
{
#ifdef DEBUG_MATRIX
assert(i <= numRows);
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);
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);
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);
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;
}
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()
return iterator(mp+(numCols+1)+numRows*2*(numCols+1), numCols);
}
- inline const uint getSize() const
+ inline const uint32_t getSize() const
{
return numRows;
}
private:
uint64_t* mp;
- uint numRows;
- uint numCols;
+ uint32_t numRows;
+ uint32_t numCols;
};
-}; //NAMESPACE MINISAT
-
#endif //PACKEDMATRIX_H
#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++) {
assert(b.size > 0);
assert(size == b.size);
#endif
-
+
return (std::equal(b.mp-1, b.mp+size, mp-1));
}
assert(b.size > 0);
assert(size == b.size);
#endif
-
+
return (!std::equal(b.mp-1, b.mp+size, mp-1));
}
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;
}
return popcnt;
}
-void PackedRow::fill(vec<Lit>& tmp_clause, const vec<lbool>& assigns, const vector<Var>& col_to_var_original) const
+const bool PackedRow::fill(vec<Lit>& tmp_clause, const vec<lbool>& assigns, const vector<Var>& col_to_var_original) const
{
bool final = !is_true_internal;
-
+
tmp_clause.clear();
uint32_t col = 0;
bool wasundef = false;
if ((mp[i] >> i2) &1) {
const Var& var = col_to_var_original[col];
assert(var != std::numeric_limits<Var>::max());
-
- const lbool& val = assigns[var];
+
+ const lbool val = assigns[var];
const bool val_bool = val.getBool();
tmp_clause.push(Lit(var, val_bool));
final ^= val_bool;
//assert(ps != ps_first+1);
} else
assert(!final);
+
+ return wasundef;
}
-}; //NAMESPACE MINISAT
#include <iostream>
#include <algorithm>
#include <limits>
-#ifndef uint
-#define uint unsigned int
-#endif
using std::vector;
-namespace MINISAT
-{
-using namespace MINISAT;
-
class PackedMatrix;
public:
bool operator ==(const PackedRow& b) const;
bool operator !=(const PackedRow& b) const;
-
+
PackedRow& operator=(const PackedRow& b)
{
#ifdef DEBUG_ROW
assert(b.size > 0);
assert(size == b.size);
#endif
-
+
memcpy(mp-1, b.mp-1, size+1);
return *this;
}
-
+
PackedRow& operator^=(const PackedRow& b)
{
#ifdef DEBUG_ROW
assert(b.size > 0);
assert(b.size == size);
#endif
-
+
for (uint32_t i = 0; i != size; i++) {
*(mp + i) ^= *(b.mp + i);
}
-
+
is_true_internal ^= b.is_true_internal;
return *this;
}
-
+
void xorBoth(const PackedRow& b)
{
#ifdef DEBUG_ROW
assert(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) {
}
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;
{
mp[i/64] |= ((uint64_t)1 << (i%64));
}
-
+
void swapBoth(PackedRow b)
{
#ifdef DEBUG_ROW
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++;
#ifdef DEBUG_ROW
assert(size*64 > i);
#endif
-
+
return (mp[i/64] >> (i%64)) & 1;
}
for (uint32_t i = 0; i != v.size(); i++) {
const uint32_t toset_var = var_to_col[v[i].var()];
assert(toset_var != std::numeric_limits<uint32_t>::max());
-
+
setBit(toset_var);
}
-
- is_true_internal = !v.xor_clause_inverted();
+
+ is_true_internal = !v.xorEqualFalse();
}
-
- void fill(vec<Lit>& tmp_clause, const vec<lbool>& assigns, const vector<Var>& col_to_var_original) const;
-
+
+ const bool fill(vec<Lit>& tmp_clause, const vec<lbool>& assigns, const vector<Var>& col_to_var_original) const;
+
inline unsigned long int scan(const unsigned long int var) const
{
#ifdef DEBUG_ROW
assert(size > 0);
#endif
-
- for(uint32_t i = var; i != size*64; i++)
+
+ for(uint32_t i = var; i != size*64; i++) {
if (this->operator[](i)) return i;
- return std::numeric_limits<unsigned long int>::max();
+ }
+
+ return std::numeric_limits<unsigned long int>::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;
std::ostream& operator << (std::ostream& os, const PackedRow& m);
-}; //NAMESPACE MINISAT
-
#endif //PACKEDROW_H
#include <map>
#include <iomanip>
#include <math.h>
-#include "FailedVarSearcher.h"
+#include "FailedLitSearcher.h"
using std::set;
using std::map;
//#define PART_FINDING
-namespace MINISAT
-{
-using namespace MINISAT;
-
PartFinder::PartFinder(Solver& _solver) :
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<uint32_t>::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<uint, vector<Var> >::const_iterator it = reverseTable.begin(); it != reverseTable.end(); it++) {
- for (uint i2 = 0; i2 < it->second.size(); i2++) {
+ for (map<uint32_t, vector<Var> >::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<class T>
void PartFinder::addToPart(const vec<T*>& cs)
{
- set<uint> tomerge;
- vector<Var> 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<uint32_t>::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<uint, vector<Var> >::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<Lit> lits(2);
+ uint32_t wsLit = 0;
+ for (const vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit = ~Lit::toLit(wsLit);
+ lits[0] = lit;
+ const vec<Watched>& 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<uint>::iterator it = tomerge.begin(); it != tomerge.end(); it++) {
- newSet.insert(newSet.end(), reverseTable[*it].begin(), reverseTable[*it].end());
- reverseTable.erase(*it);
+ }
+}
+
+template<class T>
+void PartFinder::addToPartClause(T& cl)
+{
+ set<uint32_t> tomerge;
+ vector<Var> newSet;
+ for (const Lit *l = cl.getData(), *end2 = cl.getDataEnd(); l != end2; l++) {
+ if (table[l->var()] != std::numeric_limits<uint32_t>::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<uint32_t, vector<Var> >::iterator intoReverse = reverseTable.find(into);
+ for (uint32_t i = 0; i < newSet.size(); i++) {
+ intoReverse->second.push_back(newSet[i]);
+ table[newSet[i]] = into;
}
-
- for (uint i = 0; i < newSet.size(); i++)
- table[newSet[i]] = part_no;
- reverseTable[part_no] = newSet;
- part_no++;
+ return;
}
+
+ for (set<uint32_t>::iterator it = tomerge.begin(); it != tomerge.end(); it++) {
+ newSet.insert(newSet.end(), reverseTable[*it].begin(), reverseTable[*it].end());
+ reverseTable.erase(*it);
+ }
+
+ for (uint32_t i = 0; i < newSet.size(); i++)
+ table[newSet[i]] = part_no;
+ reverseTable[part_no] = newSet;
+ part_no++;
}
-const uint PartFinder::setParts()
+const uint32_t PartFinder::setParts()
{
- vector<uint> numClauseInPart(part_no, 0);
- vector<uint> sumLitsInPart(part_no, 0);
-
+ vector<uint32_t> numClauseInPart(part_no, 0);
+ vector<uint32_t> 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<uint, vector<Var> >::iterator it = reverseTable.begin(), end = reverseTable.end(); it != end; it++) {
+ for (map<uint32_t, vector<Var> >::iterator it = reverseTable.begin(), end = reverseTable.end(); it != end; it++) {
cout << "-- set begin --" << endl;
for (vector<Var>::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) {
cout << *it2 << ", ";
}
#endif
}
-
+
return parts;
}
+void PartFinder::calcInBins(vector<uint32_t>& numClauseInPart, vector<uint32_t>& sumLitsInPart)
+{
+ uint32_t wsLit = 0;
+ for (const vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit = ~Lit::toLit(wsLit);
+ const vec<Watched>& ws = *it;
+ for (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<class T>
-void PartFinder::calcIn(const vec<T*>& cs, vector<uint>& numClauseInPart, vector<uint>& sumLitsInPart)
+void PartFinder::calcIn(const vec<T*>& cs, vector<uint32_t>& numClauseInPart, vector<uint32_t>& 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
#include "Clause.h"
-namespace MINISAT
-{
-using namespace MINISAT;
-
class Solver;
using std::map;
using std::pair;
class PartFinder {
-
+
public:
PartFinder(Solver& solver);
const bool findParts();
-
+
const map<uint32_t, vector<Var> >& getReverseTable() const; // part->var
const uint32_t getVarPart(const Var var) const;
const vector<uint32_t>& getTable() const; //var -> part
const vector<Var>& getPartVars(const uint32_t part);
-
+
private:
- const uint setParts();
- template<class T>
- void addToPart(const vec<T*>& cs);
-
+ const uint32_t setParts();
+ void addToPartBins();
+ template<class T> void addToPartClause(T& cl);
+ template<class T> void addToPart(const vec<T*>& cs);
+
struct mysorter
{
- bool operator () (const pair<uint, uint>& left, const pair<uint, uint>& right)
+ bool operator () (const pair<uint32_t, uint32_t>& left, const pair<uint32_t, uint32_t>& right)
{
return left.second < right.second;
}
};
-
+
//const bool findParts(vector<Var>& xorFingerprintInMatrix, vector<XorClause*>& xorsInMatrix);
template<class T>
- void calcIn(const vec<T*>& cs, vector<uint>& numClauseInPart, vector<uint>& sumLitsInPart);
-
+ void calcIn(const vec<T*>& cs, vector<uint32_t>& numClauseInPart, vector<uint32_t>& sumLitsInPart);
+ void calcInBins(vector<uint32_t>& numClauseInPart, vector<uint32_t>& sumLitsInPart);
+
map<uint32_t, vector<Var> > reverseTable; //part -> vars
vector<uint32_t> table; //var -> part
uint32_t part_no;
-
+
Solver& solver;
};
return reverseTable[part];
}
-}; //NAMESPACE MINISAT
-
#endif //PARTFINDER_H
-/***********************************************************************************
+/*****************************************************************************
CryptoMiniSat -- Copyright (c) 2009 Mate Soos
This program is free software: you can redistribute it and/or modify
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-**************************************************************************************************/
+******************************************************************************/
#include "PartHandler.h"
#include "VarReplacer.h"
//#define VERBOSE_DEBUG
-namespace MINISAT
-{
-using namespace MINISAT;
-
PartHandler::PartHandler(Solver& s) :
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
#endif //VERBOSE_DEBUG
return false;
}
-
+
uint32_t num_parts = partFinder.getReverseTable().size();
if (num_parts == 1)
return true;
-
+
map<uint32_t, vector<Var> > reverseTable = partFinder.getReverseTable();
assert(num_parts == partFinder.getReverseTable().size());
-
+
vector<pair<uint32_t, uint32_t> > sizes;
for (map<uint32_t, vector<Var> >::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<Var> 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!??
}
}
}
-
- 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<Var>& 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<class T>
const bool PartHandler::checkOnlyThisPart(const vec<T*>& cs, const uint32_t part, const PartFinder& partFinder) const
{
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<Watched> *it = thisSolver.watches.getData(), *end = thisSolver.watches.getDataEnd(); it != end; it++, wsLit++) {
+ const Lit lit = ~Lit::toLit(wsLit);
+ const vec<Watched>& 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<Clause*>& 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<Lit> 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<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) {
+ const Lit lit = ~Lit::toLit(wsLit);
+ vec<Watched>& 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<Lit> 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<XorClause*>& cs, Solver& newSolver, const uint32_t part, PartFinder& partFinder)
{
XorClause **i, **j, **end;
XorClause& c = **i;
vec<Lit> 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<Clause*>& cs, Solver& newSolver, const uint32_t part, PartFinder& partFinder)
{
Clause **i, **j, **end;
*j++ = *i;
continue;
}
-
+
Clause& c = **i;
assert(c.size() > 0);
uint32_t clause_part = partFinder.getVarPart(c[0].var());
#ifdef VERBOSE_DEBUG
std::cout << "Learnt clause in both parts:"; c.plainPrint();
#endif
-
+
removed = true;
solver.removeClause(c);
break;
#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
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;
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<pair<Lit, Lit> >::const_iterator it = binClausesRemoved.begin(), end = binClausesRemoved.end(); it != end; it++) {
+ vec<Lit> lits(2);
+ lits[0] = it->first;
+ lits[1] = it->second;
+ solver.addClause(lits);
+ assert(solver.ok);
+ }
+ binClausesRemoved.clear();
+
solver.libraryCNFFile = backup_libraryCNFfile;
}
-}; //NAMESPACE MINISAT
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:
void readdRemovedClauses();
friend class ClauseAllocator;
-
+
private:
struct sort_pred {
bool operator()(const std::pair<int,int> &left, const std::pair<int,int> &right) {
return left.second < right.second;
}
};
-
+
+ void configureNewSolver(Solver& newSolver) const;
+ void moveVariablesBetweenSolvers(Solver& newSolver, vector<Var>& vars, const uint32_t part, const PartFinder& partFinder);
+
//For moving clauses
+ void moveBinClauses(Solver& newSolver, const uint32_t part, PartFinder& partFinder);
void moveClauses(vec<XorClause*>& cs, Solver& newSolver, const uint32_t part, PartFinder& partFinder);
void moveClauses(vec<Clause*>& cs, Solver& newSolver, const uint32_t part, PartFinder& partFinder);
void moveLearntClauses(vec<Clause*>& 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<class T>
const bool checkOnlyThisPart(const vec<T*>& 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; ///<The base solver
+ /**
+ @brief The SAT solutions that have been found by the parts
+
+ When a part finishes with SAT, its soluton is saved here. In th end
+ the solutions are aggregaed using addSavedState()
+ */
vec<lbool> savedState;
- vec<Var> decisionVarRemoved; //variables whose decision-ness has been removed
+ vec<Var> decisionVarRemoved; ///<List of variables whose decision-ness has been removed (set to FALSE)
+
+ //Clauses that have been moved to other parts
vec<Clause*> clausesRemoved;
+ vector<pair<Lit, Lit> > binClausesRemoved;
vec<XorClause*> xorClausesRemoved;
};
+/**
+@brief Returns the saved state of a variable
+*/
inline const vec<lbool>& 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
--- /dev/null
+/***********************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+************************************************************************/
+
+#ifndef PROPBY_H
+#define PROPBY_H
+
+#include "SolverTypes.h"
+#include "Clause.h"
+#ifdef _MSC_VER
+#include <msvc/stdint.h>
+#else
+#include <stdint.h>
+#endif //_MSC_VER
+#include <stdio.h>
+
+//#define DEBUG_PROPAGATEFROM
+
+#include "ClauseOffset.h"
+#include "ClauseAllocator.h"
+
+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: " << " ? , " <<propByFull[1] << " , " << propByFull[2];
+ } else if (propByFull.isClause()) {
+ if (propByFull.isNULL()) cout << "null clause";
+ else cout << "clause:" << *propByFull.getClause();
+ }
+ return cout;
+}
+
+#endif //PROPBY_H
-/***********************************************************************************
+/****************************************************************************
CryptoMiniSat -- Copyright (c) 2009 Mate Soos
This program is free software: you can redistribute it and/or modify
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-**************************************************************************************************/
+*****************************************************************************/
#include "RestartTypeChooser.h"
+
+#include <utility>
#include "Solver.h"
+using std::pair;
//#define VERBOSE_DEBUG
//#define PRINT_VARS
-namespace MINISAT
-{
-using namespace MINISAT;
-
RestartTypeChooser::RestartTypeChooser(const Solver& s) :
solver(s)
, topX(100)
{
}
+/**
+@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++;
}
#endif
sameIns.push_back(sameIn);
}
-
+
#ifdef VERBOSE_DEBUG
std::cout << "Avg same vars in first&second first 100: " << avg() << " standard Deviation:" << stdDeviation(sameIns) <<std::endl;
#endif
}
+/**
+@brief After accumulation of data, this function finally decides which type to choose
+*/
const RestartType RestartTypeChooser::choose()
{
pair<double, double> 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))
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<uint32_t>& 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);
}
vector<uint32_t> 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;
}
}
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);
}
for (T * const*c = cs.getData(), * const*end = c + cs.size(); c != end; c++) {
T& cl = **c;
if (cl.learnt()) continue;
-
+
for (const Lit *l = cl.getData(), *end2 = l + cl.size(); l != end2; l++) {
degrees[l->var()]++;
}
template void RestartTypeChooser::addDegrees(const vec<Clause*>& cs, vector<uint32_t>& degrees) const;
template void RestartTypeChooser::addDegrees(const vec<XorClause*>& cs, vector<uint32_t>& degrees) const;
-}; //NAMESPACE MINISAT
+void RestartTypeChooser::addDegreesBin(vector<uint32_t>& degrees) const
+{
+ uint32_t wsLit = 0;
+ for (const vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit = ~Lit::toLit(wsLit);
+ const vec<Watched>& ws = *it;
+ for (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()]++;
+ }
+ }
+ }
+}
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:
void addInfo();
const RestartType choose();
void reset();
-
+
private:
void calcHeap();
const double avg() const;
const std::pair<double, double> countVarsDegreeStDev() const;
const double stdDeviation(vector<uint32_t>& measure) const;
-
+
template<class T>
void addDegrees(const vec<T*>& cs, vector<uint32_t>& degrees) const;
-
+ void addDegreesBin(vector<uint32_t>& degrees) const;
+
const Solver& solver;
- const uint32_t topX;
- const uint32_t limit;
+ const uint32_t topX; ///<The how many is the top X? 100 is default
+ const uint32_t limit; ///<If top x contains on average this many common varables, we select MiniSat-type
vector<Var> sameIns;
-
- vector<Var> firstVars, firstVarsOld;
+
+ vector<Var> firstVars; ///<The top x variables (in terms of var activity)
+ vector<Var> firstVarsOld; ///<The previous top x variables (in terms of var activity)
};
inline void RestartTypeChooser::reset()
sameIns.clear();
}
-}; //NAMESPACE MINISAT
-
#endif //RESTARTTYPECHOOSER_H
--- /dev/null
+/*****************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+******************************************************************************/
+
+#include <iostream>
+#include <vector>
+#include "SolverTypes.h"
+#include "SCCFinder.h"
+#include "VarReplacer.h"
+#include <iomanip>
+#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<uint32_t>::max());
+ lowlink.clear();
+ lowlink.resize(solver.nVars()*2, std::numeric_limits<uint32_t>::max());
+ stackIndicator.clear();
+ stackIndicator.growTo(solver.nVars()*2, false);
+ assert(stack.empty());
+
+ for (uint32_t vertex = 0; vertex < solver.nVars()*2; vertex++) {
+ //Start a DFS at each node we haven't visited yet
+ if (index[vertex] == std::numeric_limits<uint32_t>::max()) {
+ recurDepth = 0;
+ tarjan(vertex);
+ assert(stack.empty());
+ }
+ }
+
+ if (solver.conf.verbosity >= 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<Watched>& 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<Lit>& transCache = solver.transOTFCache[(~Lit::toLit(vertex)).toInt()].lits;
+ vector<Lit>::iterator it = transCache.begin();
+ vector<Lit>::iterator it2 = it;
+ uint32_t newSize = 0;
+ for (vector<Lit>::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<Lit> lits(2);
+ lits[0] = Lit::toLit(tmp[0]).unsign();
+ lits[1] = Lit::toLit(tmp[i]).unsign();
+ const bool xorEqualsFalse = Lit::toLit(tmp[0]).sign()
+ ^ Lit::toLit(tmp[i]).sign()
+ ^ true;
+ if (solver.value(lits[0]) == l_Undef && solver.value(lits[1]) == l_Undef) {
+ solver.varReplacer->replace(lits, xorEqualsFalse, 0);
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/*****************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+******************************************************************************/
+
+#ifndef SCCFINDER_H
+#define SCCFINDER_H
+
+#include "Vec.h"
+#include "Clause.h"
+#include "Solver.h"
+#include <stack>
+
+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<uint32_t> index;
+ vector<uint32_t> lowlink;
+ std::stack<uint32_t> stack;
+ vec<char> stackIndicator;
+ vec<uint32_t> tmp;
+
+ uint32_t recurDepth;
+
+ Solver& solver;
+ const vec<char>& varElimed1;
+ const vec<char>& varElimed2;
+ const vector<Lit>& replaceTable;
+ double totalTime;
+};
+
+inline void SCCFinder::doit(const Lit lit, const uint32_t vertex) {
+ // Was successor v' visited?
+ if (index[lit.toInt()] == std::numeric_limits<uint32_t>::max()) {
+ tarjan(lit.toInt());
+ recurDepth--;
+ lowlink[vertex] = std::min(lowlink[vertex], lowlink[lit.toInt()]);
+ } else if (stackIndicator[lit.toInt()]) {
+ lowlink[vertex] = std::min(lowlink[vertex], lowlink[lit.toInt()]);
+ }
+}
+
+inline const double SCCFinder::getTotalTime() const
+{
+ return totalTime;
+}
+
+#endif //SCCFINDER_H
--- /dev/null
+/**************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+#ifndef SHARED_DATA_H
+#define SHARED_DATA_H
+
+#include "Vec.h"
+#include "SolverTypes.h"
+
+#include <vector>
+
+class SharedData
+{
+ public:
+ vec<lbool> value;
+ std::vector<std::vector<Lit> > bins;
+};
+
+#endif //SHARED_DATA_H
-/****************************************************************************************[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 <cmath>
#include <limits.h>
#include <vector>
#include <iomanip>
+#include <algorithm>
#include "Clause.h"
#include "time_mem.h"
#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);
}
// 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());
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<class T>
-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);
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<Lit>& ps, bool xor_clause_inverted, const uint32_t group);
-template XorClause* Solver::addXorClauseInt(XorClause& ps, bool xor_clause_inverted, const uint32_t group);
+template XorClause* Solver::addXorClauseInt(vec<Lit>& 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<class T>
-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);
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<Lit>& ps, bool xor_clause_inverted, const uint group, char* group_name);
-template bool Solver::addXorClause(XorClause& ps, bool xor_clause_inverted, const uint group, char* group_name);
-
+template bool Solver::addXorClause(vec<Lit>& 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<class T>
-bool Solver::addLearntClause(T& ps, const uint group, const uint32_t activity)
-{
- Clause* c = addClauseInt(ps, group);
- if (c == NULL) return ok;
-
- //compensate for addClauseInt's attachClause, which doesn't know
- //that this is a learnt clause.
- clauses_literals -= c->size();
- learnts_literals += c->size();
-
- c->makeLearnt(activity);
- if (c->size() > 2) learnts.push(c);
- else {
- nbBin++;
- binaryClauses.push(c);
- }
- return ok;
-}
-template bool Solver::addLearntClause(Clause& ps, const uint group, const uint32_t activity);
-template bool Solver::addLearntClause(vec<Lit>& ps, const uint group, const uint32_t activity);
+/**
+@brief Adds a clause to the problem. Should ONLY be called internally
+This code is very specific in that it must NOT be called with varibles in
+"ps" that have been replaced, eliminated, etc. Also, it must not be called
+when the solver is in an UNSAT (!ok) state, for example. Use it carefully,
+and only internally
+*/
template <class T>
-Clause* Solver::addClauseInt(T& ps, 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;
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<Lit>& 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<Lit>& ps, const uint32_t group, const bool learnt, const uint32_t glue, const float miniSatActivity, const bool inOriginalInput);
-template<class T>
-bool Solver::addClause(T& ps, const uint group, char* group_name)
+template<class T> 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);
}
#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()) {
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<class T>
+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<Lit>& ps, const uint32_t group, const char* group_name);
+template bool Solver::addClause(Clause& ps, const uint32_t group, const char* group_name);
+
+
+template<class T>
+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<Lit>& ps, const uint group, char* group_name);
-template bool Solver::addClause(Clause& ps, const uint group, char* group_name);
+template bool Solver::addLearntClause(vec<Lit>& 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
if (level > 0) cout << " sublevel: " << trail_lim[level];
cout << endl;
#endif
-
+
if ((int)decisionLevel() > level) {
-
+
#ifdef USE_GAUSS
for (vector<Gaussian*>::iterator gauss = gauss_matrixes.begin(), end= gauss_matrixes.end(); gauss != end; gauss++)
(*gauss)->canceling(trail_lim[level]);
#endif //USE_GAUSS
-
+
for (int sublevel = trail.size()-1; sublevel >= (int)trail_lim[level]; sublevel--) {
Var var = trail[sublevel].var();
#ifdef VERBOSE_DEBUG
#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]);
#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:
default:
assert(false);
}
-
+
return true;
}
-void Solver::tallyVotes(const vec<Clause*>& cs, vector<double>& 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<Clause*>& cs, vec<double>& votes) const
{
for (const Clause * const*it = cs.getData(), * const*end = it + cs.size(); it != end; it++) {
const Clause& c = **it;
if (c.learnt()) continue;
-
+
double divider;
if (c.size() > 63) divider = 0.0;
else divider = 1.0/(double)((uint64_t)1<<(c.size()-1));
-
- for (const Lit *it2 = &c[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<XorClause*>& cs, vector<double>& votes) const
+void Solver::tallyVotesBin(vec<double>& votes) const
+{
+ uint32_t wsLit = 0;
+ for (const vec<Watched> *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit = ~Lit::toLit(wsLit);
+ const vec<Watched>& ws = *it;
+ for (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<XorClause*>& cs, vec<double>& votes) const
{
for (const XorClause * const*it = cs.getData(), * const*end = it + cs.size(); it != end; it++) {
const XorClause& c = **it;
double divider;
if (c.size() > 63) divider = 0.0;
else divider = 1.0/(double)((uint64_t)1<<(c.size()-1));
-
- for (const Lit *it2 = &c[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<double> votes;
- votes.resize(nVars(), 0.0);
-
+ if (conf.polarity_mode == polarity_auto) {
+ double myTime = cpuTime();
+
+ vec<double> 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<double>::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);
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<Lit>& cache = transOTFCache[(~lit).toInt()].lits;
+ uint32_t cacheSize = cache.size();
+ for (vector<Lit>::const_iterator it = cache.begin(), end = cache.end(); it != end; it++) {
+ /*if (solver.value(it->var()) != l_Undef
+ || solver.subsumer->getVarElimed()[it->var()]
+ || solver.xorSubsumer->getVarElimed()[it->var()])
+ continue;*/
+ if ((*it == lit) || (*it == ~lit)) continue;
+ if (litReachable[it->toInt()].lit == lit_Undef || litReachable[it->toInt()].numInCache < cacheSize) {
+ litReachable[it->toInt()].lit = lit;
+ litReachable[it->toInt()].numInCache = cacheSize;
+ }
+ }
+ }
+
+ /*for (uint32_t i = 0; i < nVars()*2; i++) {
+ std::sort(litReachable[i].begin(), litReachable[i].end(), MySorterX(transOTFCache));
+ }*/
+
+ /*for (uint32_t i = 0; i < nVars()*2; i++) {
+ vector<Lit>& myset = litReachable[i];
+ for (uint32_t i2 = 0; i2 < myset.size(); i2++) {
+ std::cout << transOTFCache[myset[i2].toInt()].lits.size() << " , ";
+ }
+ std::cout << std::endl;
+ }*/
+
+ if (conf.verbosity >= 1) {
+ std::cout << "c calculated reachability. Time: " << (cpuTime() - myTime) << std::endl;
+ }
+}
+
+void Solver::saveOTFData()
+{
+ assert(decisionLevel() == 1);
+
+ Lit lev0Lit = trail[trail_lim[0]];
+ Solver::TransCache& oTFCache = transOTFCache[(~lev0Lit).toInt()];
+ oTFCache.conflictLastUpdated = conflicts;
+ oTFCache.lits.clear();
+
+ for (int sublevel = trail.size()-1; sublevel > (int)trail_lim[0]; sublevel--) {
+ Lit lit = trail[sublevel];
+ oTFCache.lits.push_back(lit);
+ }
+}
+
//=================================================================================================
// Major methods:
+/**
+@brief Picks a branching variable and its value (True/False)
+
+We do three things here:
+-# Try to do random decision (rare, less than 2%)
+-# Try acitivity-based decision
+
+Then, we pick a sign (True/False):
+\li If we are in search-burst mode ("simplifying" is set), we pick a sign
+totally randomly
+\li 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);
}
}
-// 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<class T1, class T2>
bool subset(const T1& A, const T2& B, vector<bool>& 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<Lit>&) (out_btlevel : int&) -> [void]
-|
-| Description:
-| Analyze conflict and produce a reason clause.
-|
-| Pre-conditions:
-| * 'out_learnt' is assumed to be cleared.
-| * Current decision level must be greater than root level.
-|
-| Post-conditions:
-| * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'.
-|
-| Effect:
-| Will undo part of the trail, upto but not beyond the assumption of the current decision level.
-|________________________________________________________________________________________________@*/
-Clause* Solver::analyze(PropagatedFrom confl, vec<Lit>& 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<Lit>& out_learnt, int& out_btlevel, uint32_t &glue, const bool update)
{
int pathC = 0;
Lit p = lit_Undef;
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)
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)
} 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;
}
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:
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<Lit>& cl, const uint32_t glue)
+{
+ //80 million is kind of a hack. It seems that the longer the solving
+ //the slower this operation gets. So, limiting the "time" with total
+ //number of conflict literals is maybe a good way of doing this
+ bool clDoMinLRec = false;
+ if (conf.doCacheOTFSSR && conf.doMinimLMoreRecur) {
+ switch(lastSelectedRestartType) {
+ case dynamic_restart :
+ clDoMinLRec |= glue < 0.6*glueHistory.getAvgAllDouble();
+ //NOTE: No "break;" here on purpose
+ case static_restart :
+ clDoMinLRec |= cl.size() < 0.6*conflSizeHist.getAvgDouble();
+ break;
+ default :
+ assert(false);
+ }
}
-
- 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<uint64_t>::max()
+ && (transOTFCache[l->toInt()].conflictLastUpdated + thisUpdateTransOTFSSCache >= conflicts))) {
+ for (vector<Lit>::const_iterator it = transOTFCache[l->toInt()].lits.begin(), end2 = transOTFCache[l->toInt()].lits.end(); it != end2; it++) {
+ seen[(~(*it)).toInt()] = 0;
+ }
+ } else {
+ updateTransCache++;
+ transMinimAndUpdateCache(lit, moreRecurProp);
+ }
+ }
+
+ //watched is messed: lit is in watched[~lit]
+ vec<Watched>& ws = watches[(~lit).toInt()];
+ for (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<Lit>& allAddedToSeen2 = transOTFCache[lit.toInt()].lits;
+ allAddedToSeen2.clear();
+
+ toRecursiveProp.push(lit);
+ while(!toRecursiveProp.empty()) {
+ Lit thisLit = toRecursiveProp.top();
+ toRecursiveProp.pop();
+ //watched is messed: lit is in watched[~lit]
+ vec<Watched>& ws = watches[(~thisLit).toInt()];
+ moreRecurProp += ws.size() +10;
+ for (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<Lit>::const_iterator it = allAddedToSeen2.begin(), end = allAddedToSeen2.end(); it != end; it++) {
+ seen[(~(*it)).toInt()] = 0;
+ seen2[it->toInt()] = 0;
+ }
+
+ transOTFCache[lit.toInt()].conflictLastUpdated = conflicts;
+}
+
+/**
+@brief Check if 'p' can be removed from a learnt clause
+
+'abstract_levels' is used to abort early if the algorithm is
+visiting literals at levels that cannot be removed later.
+*/
+bool Solver::litRedundant(Lit p, uint32_t abstract_levels)
+{
+ analyze_stack.clear();
+ analyze_stack.push(p);
+ int top = analyze_toclear.size();
+ while (analyze_stack.size() > 0) {
+ assert(!reason[analyze_stack.last().var()].isNULL());
+ PropByFull c(reason[analyze_stack.last().var()], failBinLit, clauseAllocator);
+
+ analyze_stack.pop();
+
+ for (uint32_t i = 1, size = c.size(); i < size; i++) {
+ Lit p = c[i];
+ if (!seen[p.var()] && level[p.var()] > 0) {
if (!reason[p.var()].isNULL() && (abstractLevel(p.var()) & abstract_levels) != 0) {
seen[p.var()] = 1;
analyze_stack.push(p);
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;
}
}
-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
#endif //USE_OLD_POLARITIES
polarity[p.var()] = p.sign();
trail.push(p);
-
+
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
logger.propagation(p, 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<WatchedBin> & wbin = binwatches[p.toInt()];
- num_props += wbin.size()/2;
- for(WatchedBin *k = wbin.getData(), *end = wbin.getDataEnd(); k != end; k++) {
- lbool val = value(k->impliedLit);
- if (val.isUndef()) {
- uncheckedEnqueue(k->impliedLit, 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<Watched>& ws = watches[p.toInt()];
- Watched *i, *j, *end;
- num_props += ws.size();
-
- #ifdef VERBOSE_DEBUG
- cout << "Propagating lit " << (p.sign() ? '-' : ' ') << p.var()+1 << endl;
- #endif
+ 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<Watched>& 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
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<Lit>& uselessBin)
{
+ #ifdef DEBUG_USELESS_LEARNT_BIN_REMOVAL
+ assert(uselessBin.empty());
+ #endif
+
while (qhead < trail.size()) {
- Lit p = trail[qhead++];
- vec<WatchedBin> & wbin = binwatches[p.toInt()];
- propagations += wbin.size()/2;
- for(WatchedBin *k = wbin.getData(), *end = wbin.getDataEnd(); k != end; k++) {
- lbool val = value(k->impliedLit);
+ 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<Watched> & 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<class T>
-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<Watched> & 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<ClauseOffset>& 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<Watched> & 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<Watched> & 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<class T>
+inline const uint32_t Solver::calcNBLevels(const T& ps)
+{
+ MYFLAG++;
+ uint32_t nbLevels = 0;
+ for(const Lit *l = ps.getData(), *end = ps.getDataEnd(); l != end; l++) {
+ int32_t lev = level[l->var()];
+ if (permDiff[lev] != MYFLAG) {
+ permDiff[lev] = MYFLAG;
+ nbLevels++;
+ }
+ }
+ return nbLevels;
+}
/*_________________________________________________________________________________________________
|
| 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<Clause*>& Solver::get_learnts() const
-{
- return learnts;
-}
-
-const vec<Clause*>& Solver::get_sorted_learnts()
-{
- if (lastSelectedRestartType == dynamic_restart)
- std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltGlucose());
- else
- std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltMiniSat());
- return learnts;
-}
-
-const vector<Lit> Solver::get_unitary_learnts() const
-{
- vector<Lit> unitaries;
- if (decisionLevel() > 0) {
- for (uint32_t i = 0; i != trail_lim[0]; i++) {
- unitaries.push_back(trail[i]);
- }
+ 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<Lit>& table = varReplacer->getReplaceTable();
- for (Var var = 0; var != table.size(); var++) {
- Lit lit = table[var];
- if (lit.var() == var)
- continue;
-
- fprintf(outfile, "%s%d %d 0\n", (!lit.sign() ? "-" : ""), lit.var()+1, var+1);
- fprintf(outfile, "%s%d -%d 0\n", (lit.sign() ? "-" : ""), lit.var()+1, var+1);
- #ifdef STATS_NEEDED
- if (dynamic_behaviour_analysis)
- fprintf(outfile, "c name of two vars that are anti/equivalent: '%s' and '%s'\n", logger.get_var_name(lit.var()).c_str(), logger.get_var_name(var).c_str());
- #endif //STATS_NEEDED
- }
- }
- fprintf(outfile, "c \nc --------------------n");
- fprintf(outfile, "c clauses from learnts\n");
- fprintf(outfile, "c --------------------n");
- if (lastSelectedRestartType == dynamic_restart)
- std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltGlucose());
- else
- std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltMiniSat());
- for (int i = learnts.size()-1; i >= 0 ; i--) {
- if (learnts[i]->size() <= maxSize) {
- learnts[i]->print(outfile);
- }
- }
-
- 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)
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();
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:
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<Lit> 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<Gaussian*>::iterator gauss = gauss_matrixes.begin(), end = gauss_matrixes.end(); gauss != end; gauss++) {
if (!(*gauss)->full_init())
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);
}
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() <<std::endl;
- //std::cout << "calculated limit:" << ((double)(nbDecisionLevelHistory.getavg())*0.9*((double)fullStarts + 20.0)/20.0) << std::endl;
- std::cout << "totalSumOfDecisionLevel:" << totalSumOfDecisionLevel << std::endl;
+ if (glueHistory.isvalid()) {
+ std::cout << "glueHistory.getavg():" << glueHistory.getavg() <<std::endl;
+ std::cout << "totalSumOfGlue:" << totalSumOfGlue << std::endl;
std::cout << "conflicts:" << conflicts<< std::endl;
- std::cout << "conflictsAtLastSolve:" << conflictsAtLastSolve << std::endl;
- std::cout << "conflicts-conflictsAtLastSolve:" << conflicts-conflictsAtLastSolve<< std::endl;
- std::cout << "fullStarts:" << fullStarts << std::endl;
+ std::cout << "compTotSumGlue:" << compTotSumGlue << std::endl;
+ std::cout << "conflicts-compTotSumGlue:" << conflicts-compTotSumGlue<< std::endl;
}
#endif
-
- nbDecisionLevelHistory.fastclear();
+
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
progress_estimate = progressEstimate();
}
break;
case static_restart:
- if (nof_conflicts >= 0 && conflictC >= nof_conflicts) {
+ if (conflictC >= nof_conflicts) {
#ifdef STATS_NEEDED
if (dynamic_behaviour_analysis)
progress_estimate = progressEstimate();
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;
return l_Nothing;
}
-llbool Solver::handle_conflict(vec<Lit>& 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<Lit>& 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();
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<Gaussian*>::const_iterator gauss = gauss_matrixes.begin(), end= gauss_matrixes.end(); gauss != end; gauss++) {
- disabled += (*gauss)->get_disabled();
- called += (*gauss)->get_called();
- useful_prop += (*gauss)->get_useful_prop();
- useful_confl += (*gauss)->get_useful_confl();
- sum_gauss_unit_truths += (*gauss)->get_unit_truths();
- //gauss->print_stats();
- //gauss->print_matrix_stats();
- }
- sum_gauss_called += called;
- sum_gauss_confl += useful_confl;
- sum_gauss_prop += useful_prop;
-
- if (verbosity >= 2) {
- if (called == 0) {
- printf(" disabled |\n");
- } else {
- printf(" %3.0lf%% |", (double)useful_prop/(double)called*100.0);
- printf(" %3.0lf%% |", (double)useful_confl/(double)called*100.0);
- printf(" %3.0lf%% |\n", 100.0-(double)disabled/(double)gauss_matrixes.size()*100.0);
- }
- }
-}
-#endif //USE_GAUSS
+ 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;
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<uint64_t>::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)) {
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<Lit>& 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<Lit>& assumps)
+{
+ #ifdef VERBOSE_DEBUG
+ std::cout << "Solver::solve() called" << std::endl;
+ #endif
+ if (!ok) return l_False;
+ assert(qhead == trail.size());
+ assert(subsumer->checkElimedUnassigned());
+ assert(xorSubsumer->checkElimedUnassigned());
+
+ if (libraryCNFFile)
+ fprintf(libraryCNFFile, "c Solver::solve() called\n");
+
+ assumps.copyTo(assumptions);
+ initialiseSolver();
+ uint64_t nof_conflicts = conf.restart_first; //Geometric restart policy, start with this many
+ uint64_t nof_conflicts_fullrestart = conf.restart_first * FULLRESTART_MULTIPLIER + conflicts; //at this point, do a full restart
+ uint32_t lastFullRestart = starts; //last time a full restart was made was at this number of restarts
+ lbool status = l_Undef; //Current status
+ uint64_t nextSimplify = conf.restart_first * conf.simpStartMult + conflicts; //Do simplifyProblem() at this number of conflicts
+ if (!conf.doSchedSimp) nextSimplify = std::numeric_limits<uint64_t>::max();
+
if (conflicts == 0) {
- 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<Lit> tmp;
- tmp.push(Lit(var, value(var) == l_False));
- s.addClause(tmp);
- }
- }
- varReplacer->extendModelImpossible(s);
- subsumer->extendModel(s);
- xorSubsumer->extendModel(s);
-
- status = s.solve();
- if (status != l_True) {
- printf("c ERROR! Extension of model failed!\n");
- assert(status == l_True);
- exit(-1);
- }
-#ifdef VERBOSE_DEBUG
- std::cout << "Solution extending finished." << std::endl;
-#endif
- for (Var var = 0; var < nVars(); var++) {
- if (assigns[var] == l_Undef && s.model[var] != l_Undef) uncheckedEnqueue(Lit(var, s.model[var] == l_False));
- }
- ok = (propagate().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;i<learnts.size();i++)
- printf("## %d %d %d\n", learnts[i]->size(),learnts[i]->activity(),
- (uint)learnts[i]->nbBump());
- #endif
cancelUntil(0);
- if (doPartHandler && status != l_False) partHandler->readdRemovedClauses();
+ 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<XorClause*>& cs) const
-{
- #ifdef VERBOSE_DEBUG
- cout << "Checking xor-clauses whether they have been properly satisfied." << endl;;
- #endif
-
- bool failed = false;
-
- for (uint32_t i = 0; i != xorclauses.size(); i++) {
- XorClause& c = *xorclauses[i];
- bool final = c.xor_clause_inverted();
-
- #ifdef VERBOSE_DEBUG
- XorClause* c2 = XorClause_new(c, c.xor_clause_inverted(), c.getGroup());
- std::sort(c2->getData(), c2->getData()+ c2->size());
- c2->plainPrint();
- clauseFree(c2);
- #endif
-
- for (uint j = 0; j < c.size(); j++) {
- assert(modelValue(c[j].unsign()) != l_Undef);
- final ^= (modelValue(c[j].unsign()) == l_True);
- }
- if (!final) {
- printf("unsatisfied clause: ");
- xorclauses[i]->plainPrint();
- failed = true;
- }
- }
-
- return failed;
-}
-
-bool Solver::verifyClauses(const vec<Clause*>& cs) const
-{
#ifdef VERBOSE_DEBUG
- cout << "Checking clauses whether they have been properly satisfied." << endl;;
- #endif
-
- bool failed = false;
-
- for (uint32_t i = 0; i != cs.size(); i++) {
- Clause& c = *cs[i];
- for (uint j = 0; j < c.size(); j++)
- if (modelValue(c[j]) == l_True)
- goto next;
-
- printf("unsatisfied clause: ");
- cs[i]->plainPrint();
- failed = true;
- next:
- ;
- }
-
- return failed;
-}
-
-void Solver::verifyModel()
-{
- assert(!verifyClauses(clauses));
- assert(!verifyClauses(binaryClauses));
- assert(!verifyXorClauses(xorclauses));
-
- if (verbosity >=1)
- printf("c Verified %d clauses.\n", clauses.size() + xorclauses.size());
-}
-
-
-void Solver::checkLiteralCount()
-{
- // Check that sizes are calculated correctly:
- int cnt = 0;
- for (uint32_t i = 0; i != clauses.size(); i++)
- cnt += clauses[i]->size();
-
- for (uint32_t i = 0; i != xorclauses.size(); i++)
- cnt += xorclauses[i]->size();
-
- if ((int)clauses_literals != cnt) {
- fprintf(stderr, "literal count: %d, real value = %d\n", (int)clauses_literals, cnt);
- assert((int)clauses_literals == cnt);
- }
-}
-
-void Solver::printStatHeader() const
-{
- #ifdef STATS_NEEDED
- if (verbosity >= 1 && !(dynamic_behaviour_analysis && logger.statistics_on)) {
- #else
- if (verbosity >= 1) {
+ 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<Lit> tmp;
+ for (Var var = 0; var < nVars(); var++) {
+ s.newVar(decision_var[var] || subsumer->getVarElimed()[var] || varReplacer->varHasBeenReplaced(var) || xorSubsumer->getVarElimed()[var]);
+
+ //assert(!(xorSubsumer->getVarElimed()[var] && (decision_var[var] || subsumer->getVarElimed()[var] || varReplacer->varHasBeenReplaced(var))));
+
+ if (value(var) != l_Undef) {
+ #ifdef VERBOSE_DEBUG
+ std::cout << "Setting var " << var + 1
+ << " in extend-solver to " << value(var) << std::endl;
+ #endif
+ tmp.clear();
+ tmp.push(Lit(var, value(var) == l_False));
+ s.addClause(tmp);
}
}
- }
-}
-
-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<Clause*> 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
#include <cstdio>
#include <string.h>
#include <stdio.h>
+#include <stack>
+
#ifdef _MSC_VER
#include <msvc/stdint.h>
#else
#include <stdint.h>
#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;
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
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<class T>
+ 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<class T>
- 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<class T>
- 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<Lit>& 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<Lit>& assumps); ///<Search for a model that respects a given set of assumptions.
+ lbool solve (); ///<Search without assumptions.
+ void handleSATSolution(); ///<Extends model, if needed, and fills "model"
+ void handleUNSATSolution(); ///<If conflict really was zero-length, sets OK to false
+ bool okay () const; ///<FALSE means solver is in a conflicting state
// Variable mode:
//
- void setPolarity (Var v, bool b); // Declare which polarity the decision heuristic should use for a variable. Requires mode 'polarity_user'.
- void setDecisionVar (Var v, bool b); // Declare if a variable should be eligible for selection in the decision heuristic.
- void setSeed (const uint32_t seed); // Sets the seed to be the given number
- void setMaxRestarts(const uint num); //sets the maximum number of restarts to given value
+ void setDecisionVar (Var v, bool b); ///<Declare if a variable should be eligible for selection in the decision heuristic.
// Read state:
//
- lbool value (const Var& x) const; // The current value of a variable.
- lbool value (const Lit& p) const; // The current value of a literal.
- lbool modelValue (const Lit& p) const; // The value of a literal in the last model. The last call to solve must have been satisfiable.
- uint32_t nAssigns () const; // The current number of assigned literals.
- uint32_t nClauses () const; // The current number of original clauses.
- uint32_t nLiterals () const; // The current number of total literals.
- uint32_t nLearnts () const; // The current number of learnt clauses.
- uint32_t nVars () const; // The current number of variables.
+ lbool value (const Var x) const; ///<The current value of a variable.
+ lbool value (const Lit p) const; ///<The current value of a literal.
+ lbool modelValue (const Lit p) const; ///<The value of a literal in the last model. The last call to solve must have been satisfiable.
+ uint32_t nAssigns () const; ///<The current number of assigned literals.
+ uint32_t nClauses () const; ///<The current number of original clauses.
+ uint32_t nLiterals () const; ///<The current number of total literals.
+ uint32_t nLearnts () const; ///<The current number of learnt clauses.
+ uint32_t nVars () const; ///<The current number of variables.
// Extra results: (read-only member variable)
//
- vec<lbool> model; // If problem is satisfiable, this vector contains the model (if any).
- vec<Lit> conflict; // If problem is unsatisfiable (possibly under assumptions),
- // this vector represent the final conflict clause expressed in the assumptions.
+ vec<lbool> model; ///<If problem is satisfiable, this vector contains the model (if any).
+ vec<Lit> conflict; ///<If problem is unsatisfiable (possibly under assumptions), this vector represent the final conflict clause expressed in the assumptions.
// Mode of operation:
//
- double random_var_freq; // The frequency with which the decision heuristic tries to choose a random variable. (default 0.02)
- double clause_decay; // Inverse of the clause activity decay factor. (1 / 0.999)
- int restart_first; // The initial restart limit. (default 100)
- double restart_inc; // The factor with which the restart limit is multiplied in each restart. (default 1.5)
- double learntsize_factor; // The intitial limit for learnt clauses is a factor of the original clauses. (default 1 / 3)
- double learntsize_inc; // The limit for learnt clauses is multiplied with this factor each restart. (default 1.1)
- bool expensive_ccmin; // Controls conflict clause minimization. (default TRUE)
- int polarity_mode; // Controls which polarity the decision heuristic chooses. See enum below for allowed modes. (default polarity_false)
- int verbosity; // Verbosity level. 0=silent, 1=some progress report (default 0)
- Var restrictedPickBranch; // Pick variables to branch on preferentally from the highest [0, restrictedPickBranch]. If set to 0, preferentiality is turned off (i.e. picked randomly between [0, all])
- bool findNormalXors; // Automatically find non-binary xor-clauses and convert them
- bool findBinaryXors; // Automatically find binary xor-clauses and convert them
- bool regularlyFindBinaryXors; // Regularly find binary xor-clauses and convert them
- bool performReplace; // Should var-replacing be performed?
- bool conglomerateXors; // Conglomerate XORs
- bool heuleProcess; // Process XORs according to Heule
- bool schedSimplification;// Schedule simplification
- bool doSubsumption; // Should try to subsume clauses
- bool doXorSubsumption; // Should try to subsume xor clauses
- bool doPartHandler; // Should try to subsume clauses
- bool doHyperBinRes; // Should try carry out hyper-binary resolution
- bool doBlockedClause; // Should try to remove blocked clauses
- bool doVarElim; // Perform variable elimination
- bool doSubsume1; // Perform clause contraction through resolution
- bool failedVarSearch; // Should search for failed vars and doulbly propagated vars
- bool addExtraBins; // Should add extra binaries in failed literal probing
- bool removeUselessBins; // Should try to remove useless binary clauses
- bool regularRemoveUselessBins; // Should try to remove useless binary clauses regularly
- bool subsumeWithNonExistBinaries;
- bool regularSubsumeWithNonExistBinaries;
- bool libraryUsage; // Set true if not used as a library
- friend class FindUndef;
- bool greedyUnbound; //If set, then variables will be greedily unbounded (set to l_Undef)
- RestartType fixRestartType; // If set, the solver will always choose the given restart strategy
- GaussianConfig gaussconfig;
-
-
- enum { polarity_true = 0, polarity_false = 1, polarity_rnd = 3, polarity_auto = 4};
-
- // Statistics: (read-only member variable)
- //
- uint64_t starts, dynStarts, staticStarts, fullStarts, decisions, rnd_decisions, propagations, conflicts;
- uint64_t clauses_literals, learnts_literals, max_literals, tot_literals;
- uint64_t nbDL2, nbBin, lastNbBin, becameBinary, lastSearchForBinaryXor, nbReduceDB;
- uint64_t improvedClauseNo, improvedClauseSize;
+ SolverConf conf;
+ GaussConf gaussconfig; ///<Configuration for the gaussian elimination can be set here
+ bool needToInterrupt; ///<Used internally mostly. If set to TRUE, we will interrupt cleanly ASAP. The important thing is "cleanly", since we need to wait until a point when all datastructures are in a sane state (i.e. not in the middle of some algorithm)
//Logging
void needStats(); // Prepares the solver to output statistics
void needProofGraph(); // Prepares the solver to output proof graphs during solving
- void setVariableName(Var var, char* name); // Sets the name of the variable 'var' to 'name'. Useful for statistics and proof logs (i.e. used by 'logger')
+ void setVariableName(const Var var, const char* name); // Sets the name of the variable 'var' to 'name'. Useful for statistics and proof logs (i.e. used by 'logger')
const vec<Clause*>& get_sorted_learnts(); //return the set of learned clauses, sorted according to the logic used in MiniSat to distinguish between 'good' and 'bad' clauses
const vec<Clause*>& get_learnts() const; //Get all learnt clauses that are >1 long
const vector<Lit> 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;
#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; ///<Get number of variables eliminated
+ const uint32_t getNumElimXorSubsume() const; ///<Get number of variables eliminated with xor-magic
+ 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
+ /**
+ @brief Get total time spent in Subsumer.
+
+ This includes: subsumption, self-subsuming resolution, variable elimination,
+ blocked clause elimination, subsumption and self-subsuming resolution
+ using non-existent binary clauses.
+ */
const double getTotalTimeSubsumer() const;
- const double getTotalTimeXorSubsumer() const;
-
+ const double getTotalTimeFailedLitSearcher() const;
+ const double getTotalTimeSCC() const;
+
+ /**
+ @brief Get total time spent in XorSubsumer.
+
+ This included subsumption, variable elimination through XOR, and local
+ substitution (see Heule's Thesis)
+ */
+ const double getTotalTimeXorSubsumer() const;
+
protected:
+ //gauss
+ const bool clearGaussMatrixes();
+ vector<Gaussian*> gauss_matrixes;
#ifdef USE_GAUSS
void print_gauss_sum_stats();
- void clearGaussMatrixes();
- vector<Gaussian*> 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 <class T>
- Clause* addClauseInt(T& ps, uint group);
- template<class T>
- XorClause* addXorClauseInt(T& ps, bool xor_clause_inverted, const uint32_t group);
- template<class T>
- bool addLearntClause(T& ps, const uint group, const uint32_t activity);
- template<class T>
- void removeWatchedCl(vec<T> &ws, const ClauseOffset c);
- template<class T>
- bool findWatchedCl(const vec<T>& ws, const ClauseOffset c) const;
- template<class T>
- void removeWatchedBinCl(vec<T> &ws, const Lit impliedLit);
- template<class T>
- void removeWatchedBinClAll(vec<T> &ws, const Lit impliedLit);
+
+ // Statistics
+ //
+ template<class T, class T2>
+ void printStatsLine(std::string left, T value, T2 value2, std::string extra);
template<class T>
- bool findWatchedBinCl(const vec<T>& ws, const Lit impliedLit) const;
-
+ void printStatsLine(std::string left, T value, std::string extra = "");
+ uint64_t starts; ///<Num restarts
+ uint64_t dynStarts; ///<Num dynamic restarts
+ uint64_t staticStarts; ///<Num static restarts: note that after full restart, we do a couple of static restarts always
+ /**
+ @brief Num full restarts
+
+ Full restarts are restarts that are made always, no matter what, after
+ a certan number of conflicts have passed. The problem will tried to be
+ decomposed into multiple parts, and then there will be a couple of static
+ restarts made. Finally, the problem will be determined to be MiniSat-type
+ or Glucose-type.
+
+ NOTE: I belive there is a point in having full restarts even if the
+ glue-clause vs. MiniSat clause can be fully resolved
+ */
+ uint64_t fullStarts; ///<Number of full restarts made
+ uint64_t decisions; ///<Number of decisions made
+ uint64_t rnd_decisions; ///<Numer of random decisions made
+ /**
+ @brief An approximation of accumulated propagation difficulty
+
+ It does not hold the number of propagations made. Rather, it holds a
+ value that is approximate of the difficulty of the propagations made
+ This makes sense, since it is not at all the same difficulty to proapgate
+ a 2-long clause than to propagate a 20-long clause. In certain algorihtms,
+ there is a need to know how difficult the propagation part was. This value
+ can be used in these algorihms. However, the reported "statistic" will be
+ bogus.
+ */
+ uint64_t propagations;
+ uint64_t conflicts; ///<Num conflicts
+ uint64_t clauses_literals, learnts_literals, max_literals, tot_literals;
+ uint64_t nbGlue2; ///<Num learnt clauses that had a glue of 2 when created
+ uint64_t numNewBin; ///<new binary clauses that have been found through some form of resolution (shrinking, conflicts, etc.)
+ uint64_t lastNbBin; ///<Last time we seached for SCCs, numBins was this much
+ uint64_t lastSearchForBinaryXor; ///<Last time we looked for binary xors, this many bogoprops(=propagations) has been done
+ uint64_t nbReduceDB; ///<Number of times learnt clause have been cleaned
+ uint64_t improvedClauseNo; ///<Num clauses improved using on-the-fly subsumption
+ uint64_t improvedClauseSize; ///<Num literals removed using on-the-fly subsumption
+ uint64_t numShrinkedClause; ///<Num clauses improved using on-the-fly self-subsuming resolution
+ uint64_t numShrinkedClauseLits; ///<Num literals removed by on-the-fly self-subsuming resolution
+ uint64_t moreRecurMinLDo; ///<Decided to carry out transitive on-the-fly self-subsuming resolution on this many clauses
+ uint64_t updateTransCache; ///<Number of times the transitive OTF-reduction cache has been updated
+ uint64_t nbClOverMaxGlue; ///<Number or clauses over maximum glue defined in maxGlue
+
+ //Multi-threading
+ DataSync* dataSync;
+
// Helper structures:
//
struct VarOrderLt {
VarOrderLt(const vec<uint32_t>& act) : activity(act) { }
};
- friend class VarFilter;
struct VarFilter {
const Solver& s;
VarFilter(const Solver& _s) : s(_s) {}
// Solver state:
//
- bool ok; // If FALSE, the constraints are already unsatisfiable. No part of the solver state may be used!
- ClauseAllocator clauseAllocator;
- vec<Clause*> clauses; // List of problem clauses.
- vec<Clause*> binaryClauses; // Binary clauses are regularly moved here
- vec<XorClause*> xorclauses; // List of problem xor-clauses. Will be freed
- vec<Clause*> learnts; // List of learnt clauses.
- vec<XorClause*> freeLater; // xor clauses that need to be freed later due to Gauss
- vec<uint32_t> 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<vec<Watched> > watches; // 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true).
- vec<vec<ClauseOffset> > xorwatches; // 'xorwatches[var]' is a list of constraints watching var in XOR clauses.
- vec<vec<WatchedBin> > binwatches;
- vec<lbool> assigns; // The current assignments
- vector<bool> polarity; // The preferred polarity of each variable.
- #ifdef USE_OLD_POLARITIES
- vector<bool> oldPolarity; // The polarity before the last setting. Good for unsetting polairties that have been changed since the last conflict
- #endif //USE_OLD_POLARITIES
- vector<bool> decision_var; // Declares if a variable is eligible for selection in the decision heuristic.
- vec<Lit> trail; // Assignment stack; stores all assigments made in the order they were made.
- vec<uint32_t> trail_lim; // Separator indices for different decision levels in 'trail'.
- vec<PropagatedFrom> reason; // 'reason[var]' is the clause that implied the variables current value, or 'NULL' if none.
- vec<int32_t> level; // 'level[var]' contains the level at which the assignment was made.
- 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<Lit> assumptions; // Current set of assumptions provided to solve by the user.
- Heap<VarOrderLt> 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<uint> 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<Clause*> clauses; ///< List of problem clauses that are normally larger than 2. Sometimes, due to on-the-fly self-subsuming resoulution, clauses here become 2-long. They are never purposfully put here such that they are long
+ vec<XorClause*> xorclauses; ///< List of problem xor-clauses. Will be freed
+ vec<Clause*> learnts; ///< List of learnt clauses.
+ uint32_t numBins;
+ vec<XorClause*> freeLater; ///< xor clauses that need to be freed later (this is needed due to Gauss) \todo Get rid of this
+ float cla_inc; ///< Amount to bump learnt clause oldActivity with
+ vec<vec<Watched> > watches; ///< 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true).
+ vec<lbool> assigns; ///< The current assignments
+ vector<bool> decision_var; ///< Declares if a variable is eligible for selection in the decision heuristic.
+ vec<Lit> trail; ///< Assignment stack; stores all assigments made in the order they were made.
+ vec<uint32_t> trail_lim; ///< Separator indices for different decision levels in 'trail'.
+ vec<PropBy> reason; ///< 'reason[var]' is the clause that implied the variables current value, or 'NULL' if none.
+ vec<int32_t> level; ///< 'level[var]' contains the level at which the assignment was made.
+ vec<BinPropData> binPropData;
+ uint32_t qhead; ///< Head of queue (as index into the trail)
+ Lit failBinLit; ///< Used to store which watches[~lit] we were looking through when conflict occured
+ vec<Lit> assumptions; ///< Current set of assumptions provided to solve by the user.
#ifdef RANDOM_LOOKAROUND_SEARCHSPACE
- bqueue<uint> avgBranchDepth; // Avg branch depth
+ bqueue<uint32_t> 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<VarOrderLt> order_heap; ///< A priority queue of variables ordered with respect to the variable activity. All variables here MUST be decision variables. If you changed the decision variables, you MUST filter this
+ vec<uint32_t> activity; ///< A heuristic measurement of the activity of a variable.
+ uint32_t var_inc; ///< Amount to bump next variable with.
+
+ /////////////////
+ // Learnt clause cleaning
+ /////////////////
+ uint64_t numCleanedLearnts; ///< Number of times learnt clauses have been removed through simplify() up until now
+ uint32_t nbClBeforeRed; ///< Number of learnt clauses before learnt-clause cleaning
+ uint32_t nbCompensateSubsumer; ///< Number of learnt clauses that subsumed normal clauses last time subs. was executed (used to delay learnt clause-cleaning)
+
+ /////////////////////////
+ // For glue calculation & dynamic restarts
+ /////////////////////////
+ uint64_t MYFLAG; ///<For glue calculation
+ template<class T>
+ const uint32_t calcNBLevels(const T& ps);
+ vec<uint64_t> permDiff; ///<permDiff[var] is used to count the number of different decision level variables in learnt clause (filled with data from MYFLAG )
+ #ifdef UPDATE_VAR_ACTIVITY_BASED_ON_GLUE
+ vec<Var> lastDecisionLevel;
#endif
- uint maxRestarts; // More than this number of restarts will not be performed
+ bqueue<uint32_t> glueHistory; ///< Set of last decision levels in (glue of) conflict clauses. Used for dynamic restarting
+ vec<Clause*> 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<bool> seen;
+ vector<bool> seen; ///<Used in multiple places. Contains 2 * numVars() elements, all zeroed out
vec<Lit> analyze_stack;
vec<Lit> analyze_toclear;
- vec<Lit> add_tmp;
-
-
- uint64_t MYFLAG;
- template<class T>
- const uint32_t calcNBLevels(const T& ps);
- vec<uint64_t> 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<Var> lastDecisionLevel;
- #endif
+ ////////////
+ // Transitive on-the-fly self-subsuming resolution
+ ///////////
+ class TransCache {
+ public:
+ TransCache() :
+ conflictLastUpdated(std::numeric_limits<uint64_t>::max())
+ {};
+
+ vector<Lit> lits;
+ uint64_t conflictLastUpdated;
+ };
+ class LitReachData {
+ public:
+ LitReachData() :
+ lit(lit_Undef)
+ , numInCache(0)
+ {}
+ Lit lit;
+ uint32_t numInCache;
+ };
+ vector<bool> seen2; ///<To reduce temoprary data creation overhead. Used in minimiseLeartFurther(). contains 2 * numVars() elements, all zeroed out
+ vec<Lit> allAddedToSeen2; ///<To reduce temoprary data creation overhead. Used in minimiseLeartFurther()
+ std::stack<Lit> toRecursiveProp; ///<To reduce temoprary data creation overhead. Used in minimiseLeartFurther()
+ vector<TransCache> transOTFCache;
+ bqueue<uint32_t> conflSizeHist;
+ void minimiseLeartFurther(vec<Lit>& cl, const uint32_t glue);
+ void transMinimAndUpdateCache(const Lit lit, uint32_t& moreRecurProp);
+ void saveOTFData();
+ vector<LitReachData>litReachable;
+ void calcReachability();
+
+ ////////////
//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<bool dontCareLearnt>
- PropagatedFrom propagateBinExcept(const Lit& exceptLit);
- template<bool dontCareLearnt>
- 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<Lit>& 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<Lit>& out_learnt, int& out_btlevel, uint32_t &nblevels, const bool update); // (bt = backtrack)
+ void cancelUntilLight();
+ Clause* analyze (PropBy confl, vec<Lit>& out_learnt, int& out_btlevel, uint32_t &nblevels, const bool update);
void analyzeFinal (Lit p, vec<Lit>& out_conflict); // COULD THIS BE IMPLEMENTED BY THE ORDINARIY "analyze" BY SOME REASONABLE GENERALIZATION?
bool litRedundant (Lit p, uint32_t abstract_levels); // (helper method for 'analyze()')
- 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<Lit>& 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<Lit>& learnt_clause, PropBy confl, uint64_t& conflictC, const bool update);// Handles the conflict clause
+ llbool new_decision (const uint64_t nof_conflicts, const uint64_t nof_conflicts_fullrestart, const uint64_t conflictC); // Handles the case when all propagations have been made, and now a decision must be made
+
+ /////////////////
// Maintaining Variable/Clause activity:
- //
+ /////////////////
void claBumpActivity (Clause& c);
void varDecayActivity (); // Decay all variables with the specified factor. Implemented by increasing the 'bump' value instead.
void varBumpActivity (Var v); // Increase a variable with the current 'bump' value.
void claDecayActivity (); // Decay all clauses with the specified factor. Implemented by increasing the 'bump' value instead.
+ /////////////////
// Operations on clauses:
- //
- 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<class T> const bool addClauseHelper(T& ps, const uint32_t group, const char* group_name);
+ template <class T>
+ 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<class T>
+ 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<class T>
- void removeClause(T& c); // Detach and free a clause.
- bool locked (const Clause& c) const; // Returns TRUE if a clause is a reason for some implication in the current state.
- //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;
friend class VarReplacer;
friend class ClauseCleaner;
friend class RestartTypeChooser;
- friend class FailedVarSearcher;
+ friend class FailedLitSearcher;
friend class Subsumer;
friend class XorSubsumer;
friend class PartHandler;
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; ///<Used internally to determine which restart strategy is currently in use
+ RestartType lastSelectedRestartType; ///<The last selected restart type. Used when we are just after a full restart, and need to know how to really act
+
+ //////////////////////////
+ // Problem simplification
+ //////////////////////////
+ void performStepsBeforeSolve();
const lbool simplifyProblem(const uint32_t numConfls);
- bool simplifying;
+ void reduceDB(); // Reduce the set of learnt clauses.
+ const bool simplify(); // Removes satisfied clauses and finds binary xors
+ bool simplifying; ///<We are currently doing burst search
+ double totalSimplifyTime;
+ uint32_t simpDB_assigns; ///< Number of top-level assignments since last execution of 'simplify()'.
+ int64_t simpDB_props; ///< Remaining number of propagations that must be made before next execution of 'simplify()'.
+
+ /////////////////////////////
+ // SAT solution verification
+ /////////////////////////////
+ void checkSolution ();
+ const bool verifyModel () const;
+ const bool verifyBinClauses() const;
+ const bool verifyClauses (const vec<Clause*>& cs) const;
+ const bool verifyXorClauses () const;
// Debug & etc:
+ void printAllClauses();
void printLit (const Lit l) const;
- void verifyModel ();
- bool verifyClauses (const vec<Clause*>& cs) const;
- bool verifyXorClauses (const vec<XorClause*>& 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<Clause*>& cs, vector<double>& votes) const;
- void tallyVotes(const vec<XorClause*>& cs, vector<double>& votes) const;
+ void tallyVotesBin(vec<double>& votes) const;
+ void tallyVotes(const vec<Clause*>& cs, vec<double>& votes) const;
+ void tallyVotes(const vec<XorClause*>& cs, vec<double>& votes) const;
+ void setPolarity(Var v, bool b); // Declare which polarity the decision heuristic should use for a variable. Requires mode 'polarity_user'.
+ vector<bool> polarity; // The preferred polarity of each variable.
+ #ifdef USE_OLD_POLARITIES
+ vector<bool> oldPolarity; // The polarity before the last setting. Good for unsetting polairties that have been changed since the last conflict
+ #endif //USE_OLD_POLARITIES
};
var_inc >>= 14;
//var_inc = 1;
//std::cout << "var_inc: " << var_inc << std::endl;
-
+
/*Heap<VarOrderLt> copy_order_heap2(order_heap);
while(!copy_order_heap2.empty()) {
Var v = copy_order_heap2.getmin();
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;
}
}
//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());
{
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();
}
}
inline uint32_t Solver::nClauses () const
{
- return clauses.size() + xorclauses.size()+binaryClauses.size();
+ return clauses.size() + xorclauses.size();
}
inline uint32_t Solver::nLiterals () 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()
{
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
}
#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 <class T>
-inline void Solver::removeWatchedCl(vec<T> &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 <class T>
-inline void Solver::removeWatchedBinCl(vec<T> &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 <class T>
-inline void Solver::removeWatchedBinClAll(vec<T> &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<class T>
-inline bool Solver::findWatchedCl(const vec<T>& ws, const ClauseOffset c) const
-{
- uint32_t j = 0;
- for (; j < ws.size() && ws[j].clause != c; j++);
- return j < ws.size();
-}
-template<class T>
-inline bool Solver::findWatchedBinCl(const vec<T>& 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);
}
}*/
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;
{
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
--- /dev/null
+/*****************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+******************************************************************************/
+
+#include "SolverConf.h"
+#include <limits>
+
+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<uint32_t>::max())
+ , needToDumpLearnts(false)
+ , needToDumpOrig (false)
+ , maxDumpLearntsSize(std::numeric_limits<uint32_t>::max())
+ , libraryUsage (true)
+ , greedyUnbound (false)
+ , maxGlue (DEFAULT_MAX_GLUE)
+ , fixRestartType (auto_restart)
+ , origSeed(0)
+{
+}
--- /dev/null
+/*****************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+******************************************************************************/
+
+#ifndef SOLVERCONF_H
+#define SOLVERCONF_H
+
+#include "SolverTypes.h"
+#include "constants.h"
+
+class SolverConf
+{
+ public:
+ SolverConf();
+
+ double random_var_freq; ///<The frequency with which the decision heuristic tries to choose a random variable. (default 0.02) NOTE: This is really strange. If the number of variables set is large, then the random chance is in fact _far_ lower than this value. This is because the algorithm tries to set one variable randomly, but if that variable is already set, then it _silently_ fails, and moves on (doing non-random flip)!
+ double clause_decay; ///<Inverse of the clause activity decay factor. Only applies if using MiniSat-style clause activities (default: 1 / 0.999)
+ int restart_first; ///<The initial restart limit. (default 100)
+ double restart_inc; ///<The factor with which the restart limit is multiplied in each restart. (default 1.5)
+ double learntsize_factor; ///<The intitial limit for learnt clauses is a factor of the original clauses. (default 1 / 3)
+ double learntsize_inc; ///<The limit for learnt clauses is multiplied with this factor each restart. (default 1.1)
+ bool expensive_ccmin; ///<Should clause minimisation by Sorensson&Biere be used? (default TRUE)
+ int polarity_mode; ///<Controls which polarity the decision heuristic chooses. Auto means Jeroslow-Wang (default: polarity_auto)
+ int verbosity; ///<Verbosity level. 0=silent, 1=some progress report, 2=lots of report, 3 = all report (default 2)
+ Var restrictPickBranch; ///<Pick variables to branch on preferentally from the highest [0, restrictedPickBranch]. If set to 0, preferentiality is turned off (i.e. picked randomly between [0, all])
+ uint32_t simpBurstSConf;
+ double simpStartMult;
+ double simpStartMMult;
+ bool doPerformPreSimp;
+ double failedLitMultiplier;
+
+ //Optimisations to do
+ bool doFindXors; ///<Automatically find non-binary xor clauses and convert them to xor clauses
+ bool doFindEqLits; ///<Automatically find binary xor clauses (i.e. variable equi- and antivalences)
+ bool doRegFindEqLits; ///<Regularly find binary xor clauses (i.e. variable equi- and antivalences)
+ bool doReplace; ///<Should var-replacing be performed? If set to FALSE, equi- and antivalent variables will not be replaced with one another. NOTE: This precludes using a lot of the algorithms!
+ bool doConglXors; ///<Do variable elimination at the XOR-level (xor-ing 2 xor clauses thereby removing a variable)
+ bool doHeuleProcess; ///<Perform local subsitutuion as per Heule's theis
+ bool doSchedSimp; ///<Should simplifyProblem() be scheduled regularly? (if set to FALSE, a lot of opmitisations are disabled)
+ bool doSatELite; ///<Should try to subsume & self-subsuming resolve & variable-eliminate & block-clause eliminate?
+ bool doXorSubsumption; ///<Should try to subsume & local-subsitute xor clauses
+ bool doPartHandler; ///<Should try to find disconnected components and solve them individually?
+ bool doHyperBinRes; ///<Should try carry out hyper-binary resolution
+ bool doBlockedClause; ///<Should try to remove blocked clauses
+ bool doVarElim; ///<Perform variable elimination
+ bool doSubsume1; ///<Perform self-subsuming resolution
+ bool doClausVivif; ///<Perform asymmetric branching at the beginning of the solving
+ bool doSortWatched; ///<Sort watchlists according to size&type: binary, tertiary, normal (>3-long), xor clauses
+ bool doMinimLearntMore; ///<Perform learnt-clause minimisation using watchists' binary and tertiary clauses? ("strong minimization" in PrecoSat)
+ bool doMinimLMoreRecur; ///<Always perform recursive/transitive on-the-fly self self-subsuming resolution --> an enhancement of "strong minimization" of PrecoSat
+ bool doFailedLit; ///<Carry out Failed literal probing + doubly propagated literal detection + 2-long xor clause detection during failed literal probing + hyper-binary resoolution
+ bool doRemUselessBins; ///<Should try to remove useless binary clauses at the beginning of solving?
+ bool doSubsWBins;
+ bool doSubsWNonExistBins; ///<Try to do subsumption and self-subsuming resolution with non-existent binary clauses (i.e. binary clauses that don't exist but COULD exists)
+ bool doRemUselessLBins; ///<Try to remove useless learnt binary clauses
+ bool doMaxGlueDel;
+ bool doPrintAvgBranch;
+ bool doCacheOTFSSR;
+ bool doExtendedSCC;
+ bool doCalcReach; ///<Calculate reachability, and influence variable decisions with that
+
+ //interrupting & dumping
+ uint32_t maxRestarts;
+ bool needToDumpLearnts; ///<If set to TRUE, learnt clauses will be dumped to the file speified by "learntsFilename"
+ bool needToDumpOrig; ///<If set to TRUE, a simplified version of the original clause-set will be dumped to the file speified by "origFilename". The solution to this file should perfectly satisfy the problem
+ std::string learntsFilename; ///<Dump sorted learnt clauses to this file. Only active if "needToDumpLearnts" is set to TRUE
+ std::string origFilename; ///<Dump simplified original problem CNF to this file. Only active if "needToDumpOrig" is set to TRUE
+ uint32_t maxDumpLearntsSize; ///<When dumping the learnt clauses, this is the maximum clause size that should be dumped
+ bool libraryUsage; ///<Set to true if not used as a library. In fact, this is TRUE by default, and Main.cpp sets it to "FALSE". Disables some simplifications at the beginning of solving (mostly performStepsBeforeSolve() )
+ bool greedyUnbound; ///<If set, then variables will be greedily unbounded (set to l_Undef). This is EXPERIMENTAL
+ uint32_t maxGlue; ///< Learnt clauses (when doing dynamic restarts) with glue above this value will be removed immediately on backtracking
+ RestartType fixRestartType; ///<If set, the solver will always choose the given restart strategy instead of automatically trying to guess a strategy. Note that even if set to dynamic_restart, there will be a few restarts made statically after each full restart.
+
+ uint32_t origSeed;
+};
+
+#endif //SOLVERCONF_H
--- /dev/null
+/***************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+****************************************************************************/
+
+#include "Solver.h"
+
+#include "VarReplacer.h"
+
+#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<Watched> *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit = ~Lit::toLit(wsLit);
+ const vec<Watched>& 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<Clause*>& cs) const
+{
+ #ifdef VERBOSE_DEBUG
+ cout << "Checking clauses whether they have been properly satisfied." << endl;;
+ #endif
+
+ bool verificationOK = true;
+
+ for (uint32_t i = 0; i != cs.size(); i++) {
+ Clause& c = *cs[i];
+ for (uint32_t j = 0; j < c.size(); j++)
+ if (modelValue(c[j]) == l_True)
+ goto next;
+
+ printf("unsatisfied clause: ");
+ cs[i]->plainPrint();
+ verificationOK = false;
+ next:
+ ;
+ }
+
+ return verificationOK;
+}
+
+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<Watched> *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit = ~Lit::toLit(wsLit);
+ const vec<Watched>& ws = *it;
+ std::cout << "watches[" << lit << "]" << std::endl;
+ for (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
--- /dev/null
+/***************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+****************************************************************************/
+
+#include "Solver.h"
+#include "VarReplacer.h"
+#include "Subsumer.h"
+#include "XorSubsumer.h"
+#include "time_mem.h"
+#include "DimacsParser.h"
+#include "FailedLitSearcher.h"
+#include "DataSync.h"
+#include "SCCFinder.h"
+#include <iomanip>
+#include <omp.h>
+
+#ifdef USE_GAUSS
+#include "Gaussian.h"
+#endif
+
+#ifndef _MSC_VER
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+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<Lit>& table = varReplacer->getReplaceTable();
+ for (Var var = 0; var != table.size(); var++) {
+ Lit lit = table[var];
+ if (lit.var() == var)
+ continue;
+
+ fprintf(outfile, "%s%d %d 0\n", (!lit.sign() ? "-" : ""), lit.var()+1, var+1);
+ fprintf(outfile, "%s%d -%d 0\n", (lit.sign() ? "-" : ""), lit.var()+1, var+1);
+ #ifdef STATS_NEEDED
+ if (dynamic_behaviour_analysis)
+ fprintf(outfile, "c name of two vars that are anti/equivalent: '%s' and '%s'\n", logger.get_var_name(lit.var()).c_str(), logger.get_var_name(var).c_str());
+ #endif //STATS_NEEDED
+ }
+ }
+ fprintf(outfile, "c \nc --------------------\n");
+ fprintf(outfile, "c clauses from learnts\n");
+ fprintf(outfile, "c --------------------\n");
+ if (lastSelectedRestartType == dynamic_restart)
+ std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltGlucose());
+ else
+ std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltMiniSat());
+ for (int i = learnts.size()-1; i >= 0 ; i--) {
+ if (learnts[i]->size() <= maxSize) {
+ learnts[i]->print(outfile);
+ }
+ }
+
+ end:
+
+ fclose(outfile);
+}
+
+void Solver::printStrangeBinLit(const Lit lit) const
+{
+ const vec<Watched>& 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<Watched> *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit = ~Lit::toLit(wsLit);
+ const vec<Watched>& 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<Watched> *it = watches.getData(), *end = watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit = ~Lit::toLit(wsLit);
+ const vec<Watched>& 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<Watched>& 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<Lit>& table = varReplacer->getReplaceTable();
+ for (Var var = 0; var != table.size(); var++) {
+ Lit lit = table[var];
+ if (lit.var() == var)
+ continue;
+ numClauses += 2;
+ }
+
+ //binary normal clauses
+ numClauses += countNumBinClauses(false, true);
+
+ //normal clauses
+ numClauses += clauses.size();
+
+ //xor clauses
+ numClauses += xorclauses.size();
+
+ //previously eliminated clauses
+ const map<Var, vector<vector<Lit> > >& elimedOutVar = subsumer->getElimedOutVar();
+ for (map<Var, vector<vector<Lit> > >::const_iterator it = elimedOutVar.begin(); it != elimedOutVar.end(); it++) {
+ const vector<vector<Lit> >& cs = it->second;
+ numClauses += cs.size();
+ }
+ const map<Var, vector<std::pair<Lit, Lit> > >& elimedOutVarBin = subsumer->getElimedOutVarBin();
+ for (map<Var, vector<std::pair<Lit, Lit> > >::const_iterator it = elimedOutVarBin.begin(); it != elimedOutVarBin.end(); it++) {
+ numClauses += it->second.size()*2;
+ }
+
+ const map<Var, vector<XorSubsumer::XorElimedClause> >& xorElimedOutVar = xorSubsumer->getElimedOutVar();
+ for (map<Var, vector<XorSubsumer::XorElimedClause> >::const_iterator it = xorElimedOutVar.begin(); it != xorElimedOutVar.end(); it++) {
+ const vector<XorSubsumer::XorElimedClause>& cs = it->second;
+ numClauses += cs.size();
+ }
+
+ fprintf(outfile, "p cnf %d %d\n", nVars(), numClauses);
+
+ ////////////////////////////////////////////////////////////////////
+
+ fprintf(outfile, "c \nc ---------\n");
+ fprintf(outfile, "c unitaries\n");
+ fprintf(outfile, "c ---------\n");
+ for (uint32_t i = 0, end = (trail_lim.size() > 0) ? trail_lim[0] : trail.size() ; i < end; i++) {
+ trail[i].printFull(outfile);
+ #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<Var, vector<vector<Lit> > >::const_iterator it = elimedOutVar.begin(); it != elimedOutVar.end(); it++) {
+ fprintf(outfile, "c ########### cls for eliminated var %d ### start\n", it->first + 1);
+ const vector<vector<Lit> >& cs = it->second;
+ for (vector<vector<Lit> >::const_iterator it2 = cs.begin(); it2 != cs.end(); it2++) {
+ printClause(outfile, *it2);
+ }
+ fprintf(outfile, "c ########### cls for eliminated var %d ### finish\n", it->first + 1);
+ }
+ for (map<Var, vector<std::pair<Lit, Lit> > >::const_iterator it = elimedOutVarBin.begin(); it != elimedOutVarBin.end(); it++) {
+ for (uint32_t i = 0; i < it->second.size(); i++) {
+ it->second[i].first.print(outfile);
+ it->second[i].second.printFull(outfile);
+ }
+ }
+
+ fprintf(outfile, "c -------------------------------\n");
+ fprintf(outfile, "c previously xor-eliminated variables\n");
+ fprintf(outfile, "c -------------------------------\n");
+ for (map<Var, vector<XorSubsumer::XorElimedClause> >::const_iterator it = xorElimedOutVar.begin(); it != xorElimedOutVar.end(); it++) {
+ for (vector<XorSubsumer::XorElimedClause>::const_iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) {
+ it2->plainPrint(outfile);
+ }
+ }
+
+ fclose(outfile);
+}
+
+const vector<Lit> Solver::get_unitary_learnts() const
+{
+ vector<Lit> unitaries;
+ if (decisionLevel() > 0) {
+ for (uint32_t i = 0; i != trail_lim[0]; i++) {
+ unitaries.push_back(trail[i]);
+ }
+ }
+
+ return unitaries;
+}
+
+const vec<Clause*>& Solver::get_learnts() const
+{
+ return learnts;
+}
+
+const vec<Clause*>& Solver::get_sorted_learnts()
+{
+ if (lastSelectedRestartType == dynamic_restart)
+ std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltGlucose());
+ else
+ std::sort(learnts.getData(), learnts.getData()+learnts.size(), reduceDB_ltMiniSat());
+ return learnts;
+}
+
+const 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<Gaussian*>::const_iterator gauss = gauss_matrixes.begin(), end= gauss_matrixes.end(); gauss != end; gauss++) {
+ disabled += (*gauss)->get_disabled();
+ called += (*gauss)->get_called();
+ useful_prop += (*gauss)->get_useful_prop();
+ useful_confl += (*gauss)->get_useful_confl();
+ sum_gauss_unit_truths += (*gauss)->get_unit_truths();
+ //gauss->print_stats();
+ //gauss->print_matrix_stats();
+ }
+ sum_gauss_called += called;
+ sum_gauss_confl += useful_confl;
+ sum_gauss_prop += useful_prop;
+
+ if (conf.verbosity >= 2) {
+ if (called == 0) {
+ std::cout << " --";
+ } else {
+ std::cout << " "
+ << std::fixed << std::setprecision(1) << std::setw(5)
+ << ((double)useful_prop/(double)called*100.0) << "% "
+ << std::fixed << std::setprecision(1) << std::setw(5)
+ << ((double)useful_confl/(double)called*100.0) << "% "
+ << std::fixed << std::setprecision(1) << std::setw(5)
+ << (100.0-(double)disabled/(double)gauss_matrixes.size()*100.0) << "%";
+ }
+ }
+}
+#endif //USE_GAUSS
+
+/**
+@brief Sorts the watchlists' clauses as: binary, tertiary, normal, xor
+*/
+void Solver::sortWatched()
+{
+ #ifdef VERBOSE_DEBUG
+ std::cout << "Sorting watchlists:" << std::endl;
+ #endif
+ double myTime = cpuTime();
+ for (vec<Watched> *i = watches.getData(), *end = watches.getDataEnd(); i != end; i++) {
+ if (i->size() == 0) continue;
+ #ifdef VERBOSE_DEBUG
+ vec<Watched>& ws = *i;
+ std::cout << "Before sorting:" << std::endl;
+ for (uint32_t i2 = 0; i2 < ws.size(); i2++) {
+ if (ws[i2].isBinary()) std::cout << "Binary,";
+ if (ws[i2].isTriClause()) std::cout << "Tri,";
+ if (ws[i2].isClause()) std::cout << "Normal,";
+ if (ws[i2].isXorClause()) std::cout << "Xor,";
+ }
+ std::cout << std::endl;
+ #endif //VERBOSE_DEBUG
+
+ std::sort(i->getData(), i->getDataEnd(), WatchedSorter());
+
+ #ifdef VERBOSE_DEBUG
+ std::cout << "After sorting:" << std::endl;
+ for (uint32_t i2 = 0; i2 < ws.size(); i2++) {
+ if (ws[i2].isBinary()) std::cout << "Binary,";
+ if (ws[i2].isTriClause()) std::cout << "Tri,";
+ if (ws[i2].isClause()) std::cout << "Normal,";
+ if (ws[i2].isXorClause()) std::cout << "Xor,";
+ }
+ std::cout << std::endl;
+ #endif //VERBOSE_DEBUG
+ }
+
+ if (conf.verbosity >= 3) {
+ std::cout << "c watched "
+ << "sorting time: " << cpuTime() - myTime
+ << std::endl;
+ }
+}
+
+void Solver::addSymmBreakClauses()
+{
+ if (xorclauses.size() > 0) {
+ std::cout << "c xor clauses present -> no saucy" << std::endl;
+ return;
+ }
+ double myTime = cpuTime();
+ std::cout << "c Doing saucy" << std::endl;
+ dumpOrigClauses("origProblem.cnf");
+
+ int rvalue;
+ rvalue= system("grep -v \"^c\" origProblem.cnf > origProblem2.cnf");
+ if (rvalue >= 2) { // unsuccessful grep in POSIX standard
+ std::cout << "c impossible to complete saucy" << std::endl;
+ return;
+ }
+ rvalue= system("python saucyReader.py origProblem2.cnf > output");
+ if (rvalue != 0) { // unsuccessful saucyReader.py
+ std::cout << "c impossible to complete saucy" << std::endl;
+ return;
+ }
+
+
+ DimacsParser parser(this, false, false, false, true);
+
+ #ifdef DISABLE_ZLIB
+ FILE * in = fopen("output", "rb");
+ #else
+ gzFile in = gzopen("output", "rb");
+ #endif // DISABLE_ZLIB
+ parser.parse_DIMACS(in);
+ #ifdef DISABLE_ZLIB
+ fclose(in);
+ #else
+ gzclose(in);
+ #endif // DISABLE_ZLIB
+ std::cout << "c Finished saucy, time: " << (cpuTime() - myTime) << std::endl;
+}
+
+/**
+@brief Pretty-prints a literal
+*/
+void Solver::printLit(const Lit l) const
+{
+ printf("%s%d:%c", l.sign() ? "-" : "", l.var()+1, value(l) == l_True ? '1' : (value(l) == l_False ? '0' : 'X'));
+}
+
+/**
+@brief Sets that we need a CNF file that documents all commands
+
+newVar() and addClause(), addXorClause() commands are logged to this CNF
+file and then can be re-read with special arguments to the main program. This
+can help simulate a segfaulting library-call
+*/
+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<class T, class T2>
+void Solver::printStatsLine(std::string left, T value, T2 value2, std::string extra)
+{
+ std::cout << std::fixed << std::left << std::setw(27) << left << ": " << std::setw(11) << std::setprecision(2) << value << " (" << std::left << std::setw(9) << std::setprecision(2) << value2 << " " << extra << ")" << std::endl;
+}
+
+template<class T>
+void Solver::printStatsLine(std::string left, T value, std::string extra)
+{
+ std::cout << std::fixed << std::left << std::setw(27) << left << ": " << std::setw(11) << std::setprecision(2) << value << extra << std::endl;
+}
+
+/**
+@brief prints the statistics line at the end of solving
+
+Prints all sorts of statistics, like number of restarts, time spent in
+SatELite-type simplification, number of unit claues found, etc.
+*/
+void Solver::printStats()
+{
+ double cpu_time = cpuTime();
+ uint64_t mem_used = memUsed();
+
+ int numThreads = omp_get_num_threads();
+ if (numThreads > 1) {
+ std::cout << "c Following stats are for *FIRST FINISHED THREAD ONLY*" << std::endl;
+ #if !defined(_MSC_VER) && !defined(RUSAGE_THREAD)
+ std::cout << "c There is no platform-independent way to measure time per thread" << std::endl;
+ std::cout << "c All times indicated are sum of ALL threads" << std::endl;
+ std::cout << "c Use a utilty provided by your platform to get total thread time, etc." << std::endl;
+ #endif
+ }
+ printStatsLine("c num threads" , numThreads);
+
+ //Restarts stats
+ printStatsLine("c restarts", starts);
+ printStatsLine("c dynamic restarts", dynStarts);
+ printStatsLine("c static restarts", staticStarts);
+ printStatsLine("c full restarts", fullStarts);
+ printStatsLine("c total simplify time", totalSimplifyTime);
+
+ //Learnts stats
+ printStatsLine("c learnts DL2", nbGlue2);
+ printStatsLine("c learnts size 2", numNewBin);
+ printStatsLine("c learnts size 1", get_unitary_learnts_num(), (double)get_unitary_learnts_num()/(double)nVars()*100.0, "% of vars");
+ printStatsLine("c filedLit time", getTotalTimeFailedLitSearcher(), getTotalTimeFailedLitSearcher()/cpu_time*100.0, "% time");
+
+ //Subsumer stats
+ printStatsLine("c v-elim SatELite", getNumElimSubsume(), (double)getNumElimSubsume()/(double)nVars()*100.0, "% vars");
+ printStatsLine("c SatELite time", getTotalTimeSubsumer(), getTotalTimeSubsumer()/cpu_time*100.0, "% time");
+
+ //XorSubsumer stats
+ printStatsLine("c v-elim xor", getNumElimXorSubsume(), (double)getNumElimXorSubsume()/(double)nVars()*100.0, "% vars");
+ printStatsLine("c xor elim time", getTotalTimeXorSubsumer(), getTotalTimeXorSubsumer()/cpu_time*100.0, "% time");
+
+ //VarReplacer stats
+ printStatsLine("c num binary xor trees", getNumXorTrees());
+ printStatsLine("c binxor trees' crown", getNumXorTreesCrownSize(), (double)getNumXorTreesCrownSize()/(double)getNumXorTrees(), "leafs/tree");
+ printStatsLine("c bin xor find time", getTotalTimeSCC());
+
+ //OTF clause improvement stats
+ printStatsLine("c OTF clause improved", improvedClauseNo, (double)improvedClauseNo/(double)conflicts, "clauses/conflict");
+ printStatsLine("c OTF impr. size diff", improvedClauseSize, (double)improvedClauseSize/(double)improvedClauseNo, " lits/clause");
+
+ //Clause-shrinking through watchlists
+ printStatsLine("c OTF cl watch-shrink", numShrinkedClause, (double)numShrinkedClause/(double)conflicts, "clauses/conflict");
+ printStatsLine("c OTF cl watch-sh-lit", numShrinkedClauseLits, (double)numShrinkedClauseLits/(double)numShrinkedClause, " lits/clause");
+ printStatsLine("c tried to recurMin cls", moreRecurMinLDo, (double)moreRecurMinLDo/(double)conflicts*100.0, " % of conflicts");
+ printStatsLine("c updated cache", updateTransCache, updateTransCache/(double)moreRecurMinLDo, " lits/tried recurMin");
+
+ //Multi-threading
+ if (numThreads > 1) {
+ printStatsLine("c unit cls received", dataSync->getRecvUnitData(), (double)dataSync->getRecvUnitData()/(double)get_unitary_learnts_num()*100.0, "% of units");
+ printStatsLine("c unit cls sent", dataSync->getSentUnitData(), (double)dataSync->getSentUnitData()/(double)get_unitary_learnts_num()*100.0, "% of units");
+ printStatsLine("c bin cls received", dataSync->getRecvBinData());
+ printStatsLine("c bin cls sent", dataSync->getSentBinData());
+ }
+
+ #ifdef USE_GAUSS
+ if (gaussconfig.decision_until > 0) {
+ std::cout << "c " << std::endl;
+ printStatsLine("c gauss unit truths ", get_sum_gauss_unit_truths());
+ printStatsLine("c gauss called", get_sum_gauss_called());
+ printStatsLine("c gauss conflicts ", get_sum_gauss_confl(), (double)get_sum_gauss_confl() / (double)get_sum_gauss_called() * 100.0, " %");
+ printStatsLine("c gauss propagations ", get_sum_gauss_prop(), (double)get_sum_gauss_prop() / (double)get_sum_gauss_called() * 100.0, " %");
+ printStatsLine("c gauss useful", ((double)get_sum_gauss_prop() + (double)get_sum_gauss_confl())/ (double)get_sum_gauss_called() * 100.0, " %");
+ std::cout << "c " << std::endl;
+ }
+ #endif
+
+ printStatsLine("c clauses over max glue", nbClOverMaxGlue, (double)nbClOverMaxGlue/(double)conflicts*100.0, "% of all clauses");
+
+ //Search stats
+ printStatsLine("c conflicts", conflicts, (double)conflicts/cpu_time, "/ sec");
+ printStatsLine("c decisions", decisions, (double)rnd_decisions*100.0/(double)decisions, "% random");
+ printStatsLine("c bogo-props", propagations, (double)propagations/cpu_time, "/ sec");
+ printStatsLine("c conflict literals", tot_literals, (double)(max_literals - tot_literals)*100.0/ (double)max_literals, "% deleted");
+
+ //General stats
+ printStatsLine("c Memory used", (double)mem_used / 1048576.0, " MB");
+ if (numThreads > 1) {
+ #if !defined(_MSC_VER) && defined(RUSAGE_THREAD)
+ printStatsLine("c single-thread CPU time", cpu_time, " s");
+ printStatsLine("c all-threads sum CPU time", cpuTimeTotal(), " s");
+ #else
+ printStatsLine("c all-threads sum CPU time", cpu_time, " s");
+ #endif
+ } else {
+ printStatsLine("c CPU time", cpu_time, " s");
+ }
+}
-/***********************************************************************************[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 <cassert>
+#include <iostream>
+#include <Vec.h>
#ifdef _MSC_VER
#include <msvc/stdint.h>
#else
#include <stdint.h>
#endif //_MSC_VER
-#include "Alg.h"
#include <stdio.h>
-
-namespace MINISAT
-{
-using namespace MINISAT;
+#include <vector>
+#include "constants.h"
//=================================================================================================
// Variables, literals, lifted booleans, clauses:
#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;
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
{
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<Lit>& lits)
+{
+ for (uint32_t i = 0; i < lits.size(); i++) {
+ cout << lits[i] << " ";
+ }
+ return cout;
+}
+
+inline void printClause(FILE* outFile, const std::vector<Lit>& clause)
+{
+ for (size_t i = 0; i < clause.size(); i++) {
+ fprintf(outFile,"%s%d ", clause[i].sign() ? "-" : "", clause[i].var()+1);
+ }
+ fprintf(outFile, "0\n");
+}
+
+inline void printClause(FILE* outFile, const vec<Lit>& clause)
+{
+ for (uint32_t i = 0; i < clause.size(); i++) {
+ fprintf(outFile,"%s%d ", clause[i].sign() ? "-" : "", clause[i].var()+1);
+ }
+ fprintf(outFile, "0\n");
+}
+
//=================================================================================================
// Lifted booleans:
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;
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
#include "StateSaver.h"
-namespace MINISAT
-{
-using namespace MINISAT;
-
StateSaver::StateSaver(Solver& _solver) :
solver(_solver)
, backup_order_heap(Solver::VarOrderLt(solver.activity))
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()
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
#include "Solver.h"
-namespace MINISAT
-{
-using namespace MINISAT;
-
class StateSaver
{
public:
uint64_t backup_propagations;
};
-}; //NAMESPACE MINISAT
-
#endif //STATESAVER__H
--- /dev/null
+/******************************************************************************************[Main.C]
+MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**************************************************************************************************/
+
+#ifndef STREAMBUFFER_H
+#define STREAMBUFFER_H
+
+#define CHUNK_LIMIT 1048576
+
+#ifndef DISABLE_ZLIB
+#include <zlib.h>
+#endif // DISABLE_ZLIB
+
+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
-/**************************************************************************************************
-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"
#include <algorithm>
#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)
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<Lit> tmp;
- typedef map<Var, vector<Clause*> > elimType;
+ typedef map<Var, vector<vector<Lit> > > elimType;
for (elimType::iterator it = elimedOutVar.begin(), end = elimedOutVar.end(); it != end; it++) {
#ifndef NDEBUG
Var var = it->first;
assert(solver.assigns[var] == l_Undef);
assert(!solver.order_heap.inHeap(var));
#endif
-
- for (vector<Clause*>::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) {
- Clause& c = **it2;
+
+ for (vector<vector<Lit> >::const_iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) {
+ tmp.clear();
+ tmp.growTo(it2->size());
+ std::copy(it2->begin(), it2->end(), tmp.getData());
+
+ #ifdef VERBOSE_DEBUG
+ std::cout << "Reinserting elimed clause: " << tmp << std::endl;;
+ #endif
+
+ solver2.addClause(tmp);
+ assert(solver2.ok);
+ }
+ }
+
+ typedef map<Var, vector<std::pair<Lit, Lit> > > elimType2;
+ for (elimType2::iterator it = elimedOutVarBin.begin(), end = elimedOutVarBin.end(); it != end; it++) {
+ #ifndef NDEBUG
+ Var var = it->first;
+ #ifdef VERBOSE_DEBUG
+ std::cout << "Reinserting elimed var: " << var+1 << std::endl;
+ #endif
+ assert(!solver.decision_var[var]);
+ assert(solver.assigns[var] == l_Undef);
+ assert(!solver.order_heap.inHeap(var));
+ #endif
+
+ for (vector<std::pair<Lit, Lit> >::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) {
tmp.clear();
- tmp.growTo(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<Lit> tmp;
- typedef map<Var, vector<Clause*> > elimType;
+ typedef map<Var, vector<vector<Lit> > > elimType;
+ typedef map<Var, vector<std::pair<Lit, Lit> > > elimType2;
elimType::iterator it = elimedOutVar.find(var);
+ elimType2::iterator it2 = elimedOutVarBin.find(var);
//it MUST have been decision var, otherwise we would
//never have removed it
solver.setDecisionVar(var, true);
var_elimed[var] = false;
numElimed--;
-
+ #ifdef VERBOSE_DEBUG
+ std::cout << "Reinserting normal (non-xor) elimed var: " << var+1 << std::endl;
+ #endif
+
//If the variable was removed because of
//pure literal removal (by blocked clause
//elimination, there are no clauses to re-insert
- if (it == elimedOutVar.end()) return solver.ok;
-
+ if (it == elimedOutVar.end() && it2 == elimedOutVarBin.end()) return solver.ok;
+
FILE* backup_libraryCNFfile = solver.libraryCNFFile;
solver.libraryCNFFile = NULL;
- for (vector<Clause*>::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<vector<Lit> >::iterator itt = it->second.begin(), end2 = it->second.end(); itt != end2; itt++) {
+ #ifdef VERBOSE_DEBUG
+ std::cout << "Reinserting elimed clause: ";
+ for (uint32_t i = 0; i < itt->size(); i++) {
+ std::cout << (*itt)[i] << " , ";
+ }
+ std::cout << std::endl;
+ #endif
+ tmp.clear();
+ tmp.growTo(itt->size());
+ std::copy(itt->begin(), itt->end(), tmp.getData());
+ solver.addClause(tmp);
}
- solver.libraryCNFFile = backup_libraryCNFfile;
elimedOutVar.erase(it);
-
+
+ next:
+ if (it2 == elimedOutVarBin.end()) goto next2;
+ for (vector<std::pair<Lit, Lit> >::iterator itt = it2->second.begin(), end2 = it2->second.end(); itt != end2; itt++) {
+ tmp.clear();
+ tmp.growTo(2);
+ tmp[0] = itt->first;
+ tmp[1] = itt->second;
+ #ifdef VERBOSE_DEBUG
+ std::cout << "Reinserting bin clause: " << itt->first << " , " << itt->second << std::endl;
+ #endif
+ solver.addClause(tmp);
+ }
+ elimedOutVarBin.erase(it2);
+
+ next2:
+ solver.libraryCNFFile = backup_libraryCNFfile;
+
return solver.ok;
}
-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<char>& 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 <class T>
-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<class T>
-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<uint32_t>::max();
+ subsume0Happened ret;
+ ret.subsumedNonLearnt = false;
+ ret.glue = std::numeric_limits<uint32_t>::max();
+ ret.act = std::numeric_limits< float >::min();
+
vec<ClauseSimp> subs;
findSubsumed(ps, abs, subs);
for (uint32_t i = 0; i < subs.size(); i++){
- 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<char>& 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<char>& lits, const uint32_t abst)
{
vec<ClauseSimp> subs;
vec<ClauseSimp> subs2;
vec<ClauseSimp>& cs = occur[lit1.toInt()];
for (ClauseSimp *it = cs.getData(), *end = it + cs.size(); it != end; it++){
- if (it+1 != end)
- __builtin_prefetch((it+1)->clause, 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<ClauseSimp> subs;
+ vec<Lit> 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<Lit>& ps, const bool wasLearnt)
+{
+ vec<ClauseSimp> subs;
+ vec<Lit> subsLits;
+ bool toMakeNonLearnt = false;
+
+ findSubsumed1(ps, calcAbstraction(ps), subs, subsLits);
+ for (uint32_t j = 0; j < subs.size(); j++) {
+ if (subs[j].clause == NULL) continue;
+ ClauseSimp c = subs[j];
+ if (subsLits[j] == lit_Undef) {
+ if (wasLearnt && !c.clause->learnt()) toMakeNonLearnt = true;
+ unlinkClause(c);
} else {
- 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<ClauseSimp>& 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<Lit> lits(c.clause->size());
+ std::copy(c.clause->getData(), c.clause->getDataEnd(), lits.begin());
+ elimedOutVar[elim].push_back(lits);
+ } else {
+ clauses_subsumed++;
+ }
+ solver.clauseAllocator.clauseFree(c.clause);
+
clauses[c.index].clause = NULL;
}
-void Subsumer::unlinkModifiedClause(vec<Lit>& 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<ClauseSimp>& 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<Lit>& ps) const
{
- vec<ClauseSimp> Q;
- vec<ClauseSimp> subs;
- vec<Lit> 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<class T>
-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<Lit> lits(2);
+ for (list<NewBinaryClause>::const_iterator it = clBinTouched.begin(); it != clBinTouched.end(); it++) {
+ lits[0] = it->lit1;
+ lits[1] = it->lit2;
+ const bool learnt = it->learnt;
+
+ if (subsume1(lits, learnt)) {
+ //if we can't find it, that must be because it has been made non-learnt
+ //note: if it has been removed through elimination, it must't
+ //be able to subsume any non-learnt clauses, so we never enter here
+ if (findWBin(solver.watches, lits[0], lits[1], true)) {
+ findWatchedOfBin(solver.watches, lits[0], lits[1], learnt).setLearnt(false);
+ findWatchedOfBin(solver.watches, lits[1], lits[0], learnt).setLearnt(false);
}
- 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<ClauseSimp> 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<Lit> 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<uint32_t>::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<ClauseSimp>& 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<ClauseSimp>& 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<char> 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<ClauseSimp>& 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<ClauseSimp>& 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<bool UseCL>
-void Subsumer::addFromSolver(vec<Clause*>& 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<Clause*>& cs)
{
+ uint64_t numLitsAdded = 0;
Clause **i = cs.getData();
Clause **j = i;
for (Clause **end = i + cs.size(); i != end; i++) {
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;
}
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++) {
}
}
+/**
+@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<Clause*>& cs)
{
Clause **i = cs.getData();
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;
}
cs.shrink(i-j);
}
+void Subsumer::removeWrongBinsAndAllTris()
+{
+ uint32_t numRemovedHalfLearnt = 0;
+ uint32_t wsLit = 0;
+ for (vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit = ~Lit::toLit(wsLit);
+ vec<Watched>& ws = *it;
+
+ 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);
for (uint32_t i2 = 0; i2 < c.size(); i2++)
cannot_eliminate[c[i2].var()] = true;
}
-
- const vec<Clause*>& 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++)
#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<false>(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<Lit> lits(2);
+ uint32_t counter = 0;
+ uint32_t thisRand = solver.mtrand.randInt();
+ for (const vec<Watched> *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<Watched> 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) <<solver.trail.size() - origTrailSize
<< " time: " << std::setprecision(2) << std::setw(5) << cpuTime() - myTime << " s"
- << std::setw(17) << " |" << std::endl;
+ << std::endl;
}
-
- if (!subsWNonExistBinsFull(onlyNonLearntBins)) return false;
- #ifdef DEBUG_BINARIES
- for (uint32_t i = 0; i < clauses.size(); i++) {
- assert(clauses[i].clause == NULL || clauses[i].clause->size() != 2);
+ return true;
+}
+
+const bool Subsumer::subsWNonExitsBinsFullFull()
+{
+ double myTime = cpuTime();
+ clauses_subsumed = 0;
+ literals_removed = 0;
+ for (vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++) {
+ if (it->size() < 2) continue;
+ std::sort(it->getData(), it->getDataEnd(), BinSorter2());
}
- #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<true>(solver.learnts, alsoLearnt);
- solver.clauseCleaner->cleanClauses(solver.clauses, ClauseCleaner::clauses);
- addFromSolver<true>(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<true>(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<int64_t>::max();
- //numMaxElim = std::numeric_limits<uint32_t>::max();
- //numMaxSubsume0 = std::numeric_limits<uint32_t>::max();
- //numMaxSubsume1 = std::numeric_limits<uint32_t>::max();
- //numMaxBlockVars = std::numeric_limits<uint32_t>::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<Var> 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<Var> 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<Var> init_order;
- orderVarsForElim(init_order); // (will untouch all variables)
-
- for (bool first = true; numMaxElim > 0; first = false){
- uint32_t vars_elimed = 0;
- vec<Var> 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<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) {
+ vec<Watched>& ws = *it;
+ Lit lit = ~Lit::toLit(wsLit);
+ if (ws.size() < 2) continue;
+
+ std::sort(ws.getData(), ws.getDataEnd(), BinSorter());
+
+ 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) <<solver.trail.size() - origTrailSize
- << " time: " << std::setprecision(2) << std::setw(5) << (cpuTime() - myTime) << " s"
- //<< " blkClRem: " << std::setw(5) << numblockedClauseRemoved
- << " |" << std::endl;
-
- if (numblockedClauseRemoved > 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<Var, vector<Clause*> >::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<class T>
+ 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) <<solver.trail.size() - origTrailSize
+ << " time: " << std::setprecision(2) << std::setw(5) << (cpuTime() - myTime) << " s"
+ //<< " blkClRem: " << std::setw(5) << numblockedClauseRemoved
+ << std::endl;
+ }
+ totalTime += cpuTime() - myTime;
+
+ solver.testAllClauseAttach();
+ return true;
+}
+
+/**
+@brief Calculate limits for backw-subsumption, var elim, etc.
+
+It is important to have limits, otherwise the time taken to perfom these tasks
+could be huge. Furthermore, it seems that there is a benefit in doing these
+simplifications slowly, instead of trying to use them as much as possible
+from the beginning.
+
+@param[in] alsoLearnt Have learnt clauses also been hooked in? If so, variable
+elimination must be excluded, for example (i.e. its limit must be 0)
+*/
+void Subsumer::setLimits()
+{
+ numMaxSubsume0 = 130*1000*1000;
+ numMaxSubsume1 = 80*1000*1000;
+
+ numMaxElim = 500*1000*1000;
+
+ //numMaxElim = 0;
+ //numMaxElim = std::numeric_limits<int64_t>::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<int64_t>::max();
+ //numMaxSubsume1 = std::numeric_limits<int64_t>::max();
+
+ //numMaxBlockToVisit = std::numeric_limits<int64_t>::max();
+ //numMaxBlockVars = std::numeric_limits<uint32_t>::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<Var, vector<vector<Lit> > >::iterator it = elimedOutVar.find(var);
+ if (it != elimedOutVar.end()) elimedOutVar.erase(it);
+
+ map<Var, vector<std::pair<Lit, Lit> > >::iterator it2 = elimedOutVarBin.find(var);
+ if (it2 != elimedOutVarBin.end()) elimedOutVarBin.erase(it2);
+ }
+ }
+}
+
+/**
+@brief Finds clauses that are backward-subsumed by given clause
+
+Only handles backward-subsumption. Uses occurrence lists
+
+@param[in] ps The clause to backward-subsume with.
+@param[in] abs Abstraction of the clause ps
+@param[out] out_subsumed The set of clauses subsumed by this clause
+*/
+template<class T>
void Subsumer::findSubsumed(const T& ps, uint32_t abs, vec<ClauseSimp>& out_subsumed)
{
#ifdef VERBOSE_DEBUG
- cout << "findSubsumed: ";
- 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<ClauseSimp>& cs = occur[ps[min_i].toInt()];
+ numMaxSubsume0 -= cs.size()*10 + 5;
for (ClauseSimp *it = cs.getData(), *end = it + cs.size(); it != end; it++){
if (it+1 != end)
__builtin_prefetch((it+1)->clause, 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<class T>
+void Subsumer::findSubsumed1(const T& ps, uint32_t abs, vec<ClauseSimp>& out_subsumed, vec<Lit>& out_lits)
+{
+ #ifdef VERBOSE_DEBUG
+ cout << "findSubsumed1: " << ps << std::endl;
+ #endif
+
+ Var minVar = var_Undef;
+ uint32_t bestSize = std::numeric_limits<uint32_t>::max();
+ for (uint32_t i = 0; i < ps.size(); i++){
+ uint32_t newSize = occur[ps[i].toInt()].size()+ occur[(~ps[i]).toInt()].size();
+ if (newSize < bestSize) {
+ minVar = ps[i].var();
+ bestSize = newSize;
+ }
+ }
+ assert(minVar != var_Undef);
+
+ numMaxSubsume1 -= bestSize*10 + 10;
+ fillSubs(ps, abs, out_subsumed, out_lits, Lit(minVar, true));
+ fillSubs(ps, abs, out_subsumed, out_lits, Lit(minVar, false));
+}
+
+/**
+@brief Helper function for findSubsumed1
+
+Used to avoid duplication of code
+*/
+template<class T>
+void inline Subsumer::fillSubs(const T& ps, uint32_t abs, vec<ClauseSimp>& out_subsumed, vec<Lit>& out_lits, const Lit lit)
+{
+ Lit litSub;
+ vec<ClauseSimp>& cs = occur[lit.toInt()];
+ for (ClauseSimp *it = cs.getData(), *end = it + cs.size(); it != end; it++) {
+ if (it+1 != end)
+ __builtin_prefetch((it+1)->clause, 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<ClAndBin>& todo, const Var var, std::pair<uint32_t, uint32_t>& removed)
+{
+ pair<uint32_t, uint32_t> tmp;
+ for (uint32_t i = 0; i < todo.size(); i++) {
+ ClAndBin& c = todo[i];
+ if (!c.isBin) {
+ unlinkClause(c.clsimp, var);
+ } else {
#ifdef VERBOSE_DEBUG
- 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<ClauseSimp>& poss, vec<ClauseSimp>& negs, vec<ClauseSimp>& ps, vec<ClauseSimp>& 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<ClAndBin>& posAll, vec<ClAndBin>& 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<uint32_t, uint32_t> removed;
+ removed.first = 0;
+ removed.second = 0;
+
+ removeClausesHelper(posAll, var, removed);
+ removeClausesHelper(negAll, var, removed);
+
+ solver.learnts_literals -= removed.first;
+ solver.clauses_literals -= removed.second;
+ solver.numBins -= (removed.first + removed.second)/2;
}
-void inline Subsumer::DeallocPsNs(vec<ClauseSimp>& ps, vec<ClauseSimp>& 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<Watched>& 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<ClAndBin>& all, vec<ClauseSimp>& cs, const Lit lit)
+{
+ for (uint32_t i = 0; i < cs.size(); i++)
+ all.push(ClAndBin(cs[i]));
+
+ const vec<Watched>& 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<ClauseSimp>& poss = occur[Lit(x, false).toInt()];
- vec<ClauseSimp>& 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<ClauseSimp>& poss = occur[lit.toInt()];
+ vec<ClauseSimp>& 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<ClAndBin> 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<Lit> 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<Lit> dummy; //to reduce temporary data allocation
+ for (uint32_t i = 0; i < posAll.size(); i++) for (uint32_t j = 0; j < negAll.size(); j++){
// Merge clauses. If 'y' and '~y' exist, clause will not be created.
dummy.clear();
- 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<ClauseSimp> 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<Lit>& 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<Lit>& 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<int, Var>& x, const pair<int, Var>& 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<Var>& order)
{
order.clear();
vec<pair<int, Var> > 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<uint> occurNum(solver.nVars()*2, 0);
-
+ vector<uint32_t> occurNum(solver.nVars()*2, 0);
+
for (uint32_t i = 0; i < clauses.size(); i++) {
if (clauses[i].clause == NULL) continue;
Clause& c = *clauses[i].clause;
for (uint32_t i2 = 0; i2 < c.size(); i2++)
occurNum[c[i2].toInt()]++;
}
-
+
for (uint32_t i = 0; i < occurNum.size(); i++) {
- 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<Lit>& ps, const Lit lit)
+template<class T>
+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<ClauseSimp>& 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<ClauseSimp>& cs = occur[lit.toInt()];
+ const vec<Watched>& ws = solver.watches[(~lit).toInt()];
+
+ for (const ClauseSimp *it = cs.getData(), *end = cs.getDataEnd(); it != end; it++){
+ if (it+1 != end) __builtin_prefetch((it+1)->clause, 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<ClauseSimp> toRemove;
-
+ numblockedClauseRemoved = 0;
+ uint32_t numElimedBefore = numElimed;
+
touchedBlockedVars = priority_queue<VarOcc, vector<VarOcc>, MyComp>();
touchedBlockedVarsBool.clear();
touchedBlockedVarsBool.growTo(solver.nVars(), false);
- for (uint32_t i = 0; i < solver.order_heap.size() && i < 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<Lit> 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<ClauseSimp> toRemove(occur[lit.toInt()]);
- for (ClauseSimp *it = toRemove.getData(), *end = toRemove.getDataEnd(); it != end; it++) {
- #ifdef VERBOSE_DEBUG
- std::cout << "Next varelim because of block clause elim" << std::endl;
- #endif //VERBOSE_DEBUG
- unlinkClause(*it, lit.var());
- numblockedClauseRemoved++;
- }
-
- vec<ClauseSimp> 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<Lit> lits(1);
+ const vec<Watched>& 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<char> Subsumer::merge()
+void Subsumer::blockedClauseElimAll(const Lit lit)
{
- vector<char> var_merged(solver.nVars(), false);
- double myTime = cpuTime();
-
- vector<varDataStruct> 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<ClauseSimp>& 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<ClauseSimp>& 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<varDataStruct, vector<Var> > 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<varDataStruct, vector<Var> >::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<ClauseSimp> toRemove(occur[lit.toInt()]);
+ for (ClauseSimp *it = toRemove.getData(), *end = toRemove.getDataEnd(); it != end; it++) {
+ #ifdef VERBOSE_DEBUG
+ std::cout << "Next varelim because of block clause elim" << std::endl;
+ #endif //VERBOSE_DEBUG
+ unlinkClause(*it, lit.var());
+ numblockedClauseRemoved++;
}
-
- 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<varDataStruct, vector<Var> >::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<Lit> 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<varDataStruct, vector<Var> >::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<Lit> 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<Watched>& 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<ClauseSimp>& occSet1 = occur[lit1.toInt()];
- vec<ClauseSimp>& occSet2 = occur[lit2.toInt()];
- vec<Lit> 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;
+}
-/**************************************************************************************************
-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
#include "BitArray.h"
#include <map>
#include <vector>
+#include <list>
#include <queue>
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<Lit>& 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<char>& getVarElimed() const;
const uint32_t getNumElimed() const;
const bool checkElimedUnassigned() const;
const double getTotalTime() const;
-
+ const map<Var, vector<vector<Lit> > >& getElimedOutVar() const;
+ const map<Var, vector<std::pair<Lit, Lit> > >& 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<ClauseSimp> clauses;
- CSet learntClauses;
- vec<char> touched; // Is set to true when a variable is part of a removed clause. Also true initially (upon variable creation).
- vec<Var> touched_list; // A list of the true elements in 'touched'.
- CSet cl_touched; // Clauses strengthened.
- CSet cl_added; // Clauses created.
- vec<vec<ClauseSimp> > occur; // 'occur[index(lit)]' is a list of constraints containing 'lit'.
- vec<vec<ClauseSimp>* > iter_vecs; // Vectors currently used for iterations. Removed clauses will be looked up and replaced by 'Clause_NULL'.
- vec<CSet* > iter_sets; // Sets currently used for iterations.
- vec<char> cannot_eliminate;//
+ vec<char> touchedVars; ///<Is set to true when a variable is part of a removed clause. Also true initially (upon variable creation).
+ vec<Var> touchedVarsList; ///<A list of the true elements in 'touched'.
+ CSet cl_touched; ///<Clauses strengthened/added
+ vec<vec<ClauseSimp> > occur; ///<occur[index(lit)]' is a list of constraints containing 'lit'.
+ vec<CSet* > iter_sets; ///<Sets currently used in iterations.
+ vec<char> cannot_eliminate;///<Variables that cannot be eliminated due to, e.g. XOR-clauses
+ vec<char> seen_tmp; ///<Used in various places to help perform algorithms
//Global stats
- Solver& solver;
- vec<char> var_elimed; //TRUE if var has been eliminated
- double totalTime;
- uint32_t numElimed;
- map<Var, vector<Clause*> > elimedOutVar;
-
- // Temporaries (to reduce allocation overhead):
- //
- vec<char> seen_tmp; // (used in various places)
-
-
+ Solver& solver; ///<The solver this simplifier is connected to
+ vec<char> var_elimed; ///<Contains TRUE if var has been eliminated
+ double totalTime; ///<Total time spent in this class
+ uint32_t numElimed; ///<Total number of variables eliminated
+ map<Var, vector<vector<Lit> > > elimedOutVar; ///<Contains the clauses to use to uneliminate a variable
+ map<Var, vector<std::pair<Lit, Lit> > > elimedOutVarBin; ///<Contains the clauses to use to uneliminate a variable
+
//Limits
- uint32_t numVarsElimed;
- uint32_t numMaxSubsume1;
- uint32_t numMaxSubsume0;
- uint32_t numMaxElim;
- int64_t numMaxBlockToVisit;
- uint32_t numMaxBlockVars;
-
+ uint64_t addedClauseLits;
+ uint32_t numVarsElimed; ///<Number of variables elimed in this run
+ int64_t numMaxSubsume1; ///<Max. number self-subsuming resolution tries to do this run
+ int64_t numMaxSubsume0; ///<Max. number backward-subsumption tries to do this run
+ int64_t numMaxElim; ///<Max. number of variable elimination tries to do this run
+ uint32_t numMaxElimVars;
+ int64_t numMaxBlockToVisit; ///<Max. number variable-blocking clauses to visit to do this run
+ uint32_t numMaxBlockVars; ///<Max. number variable-blocking tries to do this run
+
//Start-up
- template<bool UseCL>
- void addFromSolver(vec<Clause*>& cs, bool alsoLearnt = false);
+ const uint64_t addFromSolver(vec<Clause*>& cs);
void fillCannotEliminate();
void clearAll();
+ void setLimits();
+ const bool subsume0AndSubsume1();
+ vec<char> ol_seenPos;
+ vec<char> ol_seenNeg;
//Finish-up
void freeMemory();
void addBackToSolver();
void removeWrong(vec<Clause*>& cs);
+ void removeWrongBinsAndAllTris();
void removeAssignedVarsFromEliminated();
-
+
//Iterations
void registerIteration (CSet& iter_set) { iter_sets.push(&iter_set); }
void unregisterIteration(CSet& iter_set) { remove(iter_sets, &iter_set); }
- void registerIteration (vec<ClauseSimp>& iter_vec) { iter_vecs.push(&iter_vec); }
- void unregisterIteration(vec<ClauseSimp>& 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<class T>
void findSubsumed(const T& ps, const uint32_t abst, vec<ClauseSimp>& out_subsumed);
- bool isSubsumed(Clause& ps);
template<class T>
- uint32_t subsume0(T& ps, uint32_t abs);
+ void findSubsumed1(const T& ps, uint32_t abs, vec<ClauseSimp>& out_subsumed, vec<Lit>& out_lits);
template<class T>
- uint32_t subsume0Orig(const T& ps, uint32_t abs);
- bool subsumedNonLearnt;
- void subsume0BIN(const Lit lit, const vec<char>& lits);
- void subsume1(ClauseSimp& ps);
- void smaller_database();
- void almost_all_database();
+ void fillSubs(const T& ps, uint32_t abs, vec<ClauseSimp>& out_subsumed, vec<Lit>& out_lits, const Lit lit);
+ template<class T2>
+ bool subset(const uint32_t aSize, const T2& B);
template<class T1, class T2>
- 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<class T>
+ 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<NewBinaryClause> clBinTouched; ///<Binary clauses strengthened/added
+ const bool handleClBinTouched();
+
+ void subsume1(Clause& ps);
+ const bool subsume1(vec<Lit>& ps, const bool wasLearnt);
+ void strenghten(ClauseSimp& c, const Lit toRemoveLit);
+ const bool cleanClause(Clause& ps);
+ const bool cleanClause(vec<Lit>& 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<int, Var>& x, const std::pair<int, Var>& 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<Var>& order);
+ const uint32_t numNonLearntBins(const Lit lit) const;
bool maybeEliminate(Var x);
- void MigrateToPsNs(vec<ClauseSimp>& poss, vec<ClauseSimp>& negs, vec<ClauseSimp>& ps, vec<ClauseSimp>& ns, const Var x);
- void DeallocPsNs(vec<ClauseSimp>& ps, vec<ClauseSimp>& ns);
- bool merge(const Clause& ps, const Clause& qs, const Lit without_p, const Lit without_q, vec<Lit>& out_clause);
+ void removeClauses(vec<ClAndBin>& posAll, vec<ClAndBin>& negAll, const Var var);
+ void removeClausesHelper(vec<ClAndBin>& todo, const Var var, std::pair<uint32_t, uint32_t>& removed);
+ bool merge(const ClAndBin& ps, const ClAndBin& qs, const Lit without_p, const Lit without_q, vec<Lit>& out_clause);
+ const bool eliminateVars();
+ void fillClAndBin(vec<ClAndBin>& all, vec<ClauseSimp>& cs, const Lit lit);
//Subsume with Nonexistent Bins
- const bool subsWNonExistBinsFull(OnlyNonLearntBins* onlyNonLearntBins);
- const bool subsWNonExistBins(const Lit& lit, OnlyNonLearntBins* onlyNonLearntBins);
- template<class T>
- 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<char>& lits, const uint32_t abst);
bool subsNonExistentFinish;
- double subsNonExistentTime;
- uint32_t subsNonExistentLitsRemoved;
- vec<Clause*> addBinaryClauses;
uint32_t doneNum;
- vec<ClauseSimp> subsume1PartialSubs;
- vec<Lit> subsume1PartialQs;
- vec<Lit> toVisit;
- vec<char> toVisitAll;
- vec<Lit> ps2;
-
+ uint64_t extraTimeNonExist;
+ vec<Lit> toVisit; ///<Literals that we have visited from a given literal during subsumption w/ non-existent binaries (list)
+ vec<char> toVisitAll; ///<Literals that we have visited from a given literal during subsumption w/ non-existent binaries (contains '1' for literal.toInt() that we visited)
+
+ //Blocked clause elimination
class VarOcc {
public:
VarOcc(const Var& v, const uint32_t num) :
Var var;
uint32_t occurnum;
};
-
struct MyComp {
const bool operator() (const VarOcc& l1, const VarOcc& l2) const {
return l1.occurnum > l2.occurnum;
}
};
-
void blockedClauseRemoval();
- const bool allTautology(const vec<Lit>& ps, const Lit lit);
+ template<class T>
+ 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<VarOcc, vector<VarOcc>, MyComp> touchedBlockedVars;
- vec<bool> touchedBlockedVarsBool;
+ vec<char> 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; ///<Number of clauses subsumed in this run
+ uint32_t literals_removed; ///<Number of literals removed from clauses through self-subsuming resolution in this run
+ uint32_t numCalls; ///<Number of times simplifyBySubsumption() has been called
+ uint32_t clauseID; ///<We need to have clauseIDs since clauses don't natively have them. The ClauseID is stored by ClauseSimp, which also stores a pointer to the clause
+ bool alsoLearnt;
};
template <class T, class T2>
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]) {
}
}
-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<class T2>
+bool Subsumer::subset(const uint32_t aSize, const T2& B)
+{
+ uint32_t num = 0;
+ for (uint32_t i = 0; i != B.size(); i++) {
+ num += seen_tmp[B[i].toInt()];
+ }
+ return num == aSize;
+}
+
+
+/**
+@brief Decides if A subsumes B, or if not, if A could strenghten B
+
+@note: Assumes 'seen' is cleared (will leave it cleared)
+
+Helper function findSubsumed1. Does two things in one go:
+1) decides if clause A could subsume clause B
+1) decides if clause A could be used to perform self-subsuming resoltuion on
+clause B
+
+@return lit_Error, if neither (1) or (2) is true. Returns lit_Undef (1) is true,
+and returns the literal to remove if (2) is true
+*/
template<class T1, class T2>
-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<Var, vector<vector<Lit> > >& Subsumer::getElimedOutVar() const
+{
+ return elimedOutVar;
+}
+
+inline const map<Var, vector<std::pair<Lit, Lit> > >& Subsumer::getElimedOutVarBin() const
+{
+ return elimedOutVarBin;
}
inline const vec<char>& Subsumer::getVarElimed() const
return totalTime;
}
-}; //NAMESPACE MINISAT
-
#endif //SIMPLIFIER_H
-/***********************************************************************************
+/***************************************************************************
CryptoMiniSat -- Copyright (c) 2009 Mate Soos
This program is free software: you can redistribute it and/or modify
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-**************************************************************************************************/
+****************************************************************************/
#include <iomanip>
#include "UselessBinRemover.h"
#include "VarReplacer.h"
#include "ClauseCleaner.h"
#include "time_mem.h"
-#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();
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++) {
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;
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;
}
}
- 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;
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];
//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'
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<uint32_t, uint32_t> removed1 = removeWBinAll(solver.watches[(~lit1).toInt()], lit2);
+ std::pair<uint32_t, uint32_t> removed2 = removeWBinAll(solver.watches[(~lit2).toInt()], lit1);
+ assert(removed1 == removed2);
+
+ assert((removed1.first + removed2.first) % 2 == 0);
+ assert((removed1.second + removed2.second) % 2 == 0);
+ solver.learnts_literals -= (removed1.first + removed2.first);
+ solver.clauses_literals -= (removed1.second + removed2.second);
+ solver.numBins -= (removed1.first + removed2.first + removed1.second + removed2.second)/2;
}
-const bool UselessBinRemover::fillBinImpliesMinusLast(const Lit& origLit, const Lit& lit, vec<Lit>& 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<Lit>& 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;
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
#include "Vec.h"
#include "Solver.h"
-#include "OnlyNonLearntBins.h"
+#ifdef _MSC_VER
+#include <msvc/stdint.h>
+#else
#include <stdint.h>
+#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; ///<Has the previous propagation failed? (=conflict)
+ uint32_t extraTime; ///<Time that cannot be meausured in bogoprops (~propagation time)
+
//Remove useless binaries
- const bool fillBinImpliesMinusLast(const Lit& origLit, const Lit& lit, vec<Lit>& 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<Lit>& 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<char> toDeleteSet;
- vec<Lit> oneHopAway;
+ vec<Lit> oneHopAway; ///<Lits that are one hop away from selected lit (sometimes called origLit)
+ /**
+ @brief Binary clauses to be removed are gathered here
+
+ We only gather the second lit, the one we can reach from selected lit
+ (calld origLit some places) see fillBinImpliesMinusLast() for details
+ */
vec<Lit> wrong;
- Solver& solver;
- OnlyNonLearntBins& onlyNonLearntBins;
+ Solver& solver; ///<The solver class e want to remove useless binary clauses from
};
#endif //USELESSBINREMOVER_H
-
-}; //NAMESPACE MINISAT
CryptoMiniSat
-GIT revision: e540792aa3a01ec047b005b6351247fa87ae6eb6
+GIT revision: 588152bb03adf98ffd581c4579e1d6c5eec92f8f
-/***********************************************************************************
+/*****************************************************************************
CryptoMiniSat -- Copyright (c) 2009 Mate Soos
This program is free software: you can redistribute it and/or modify
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-**************************************************************************************************/
+******************************************************************************/
#include "VarReplacer.h"
#include <iostream>
#include <iomanip>
+#include <set>
#include "ClauseCleaner.h"
#include "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 <iostream>
using std::endl;
#endif
-namespace MINISAT
-{
-using namespace MINISAT;
-
VarReplacer::VarReplacer(Solver& _solver) :
replacedLits(0)
, replacedVars(0)
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<Var, vector<Var> >::iterator it = reverseTable.begin();
- map<Var, vector<Var> >::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<Lit>::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<char>* removedVars = solver.doXorSubsumption ? &solver.xorSubsumer->getVarElimed() : NULL;
- const vec<lbool>* removedVars2 = solver.doPartHandler ? &solver.partHandler->getSavedState() : NULL;
- const vec<char>* removedVars3 = solver.doSubsumption ? &solver.subsumer->getVarElimed() : NULL;
+ const vec<char>& removedVars = solver.xorSubsumer->getVarElimed();
+ const vec<lbool>& removedVars2 = solver.partHandler->getSavedState();
+ const vec<char>& removedVars3 = solver.subsumer->getVarElimed();
for (vector<Lit>::const_iterator it = table.begin(); it != table.end(); it++, var++) {
if (it->var() == var
- || (removedVars != 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) {
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<XorClause*>& cs)
{
XorClause **a = cs.getData();
XorClause **r = a;
for (XorClause **end = a + cs.size(); r != end; r++) {
XorClause& c = **r;
-
+
bool changed = false;
Var origVar1 = c[0].var();
Var origVar2 = c[1].var();
-
+
for (Lit *l = &c[0], *end2 = l + c.size(); l != end2; l++) {
Lit newlit = table[l->var()];
if (newlit.var() != l->var()) {
changed = true;
*l = Lit(newlit.var(), false);
c.invert(newlit.sign());
- 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 {
}
}
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;
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:
solver.attachClause(c);
return false;
}
-
+
assert(false);
return false;
}
-const bool VarReplacer::replace_set(vec<Clause*>& cs, const bool binClauses)
+const bool VarReplacer::replaceBins()
+{
+ #ifdef DEBUG_BIN_REPLACER
+ vec<uint32_t> removed(solver.nVars()*2, 0);
+ uint32_t replacedLitsBefore = replacedLits;
+ #endif
+
+ uint32_t removedLearnt = 0;
+ uint32_t removedNonLearnt = 0;
+ uint32_t wsLit = 0;
+ for (vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit1 = ~Lit::toLit(wsLit);
+ vec<Watched>& ws = *it;
+
+ 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<Clause*>& cs)
{
Clause **a = cs.getData();
Clause **r = a;
for (Clause **end = a + cs.size(); r != end; r++) {
Clause& c = **r;
+ assert(c.size() > 2);
bool changed = false;
Lit origLit1 = c[0];
Lit origLit2 = c[1];
+ Lit origLit3 = (c.size() == 3) ? c[2] : lit_Undef;
for (Lit *l = c.getData(), *end2 = l + c.size(); l != end2; l++) {
if (table[l->var()].var() != l->var()) {
changed = true;
*l = table[l->var()] ^ l->sign();
- 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;
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<Var> VarReplacer::getReplacingVars() const
{
vector<Var> replacingVars;
-
+
for(map<Var, vector<Var> >::const_iterator it = reverseTable.begin(), end = reverseTable.end(); it != end; it++) {
replacingVars.push_back(it->first);
}
-
+
return replacingVars;
}
+/**
+@brief Given a partial model, it tries to extend it to variables that have been replaced
+
+Cannot extend it fully, because it might be that a replaced d&f, but a was
+later variable-eliminated. That's where extendModelImpossible() comes in
+*/
void VarReplacer::extendModelPossible() const
{
#ifdef VERBOSE_DEBUG
std::cout << "extendModelPossible() called" << std::endl;
#endif //VERBOSE_DEBUG
- uint i = 0;
+ uint32_t i = 0;
for (vector<Lit>::const_iterator it = table.begin(); it != table.end(); it++, i++) {
if (it->var() == i) continue;
-
+
#ifdef VERBOSE_DEBUG
cout << "Extending model: var "; solver.printLit(Lit(i, false));
cout << " to "; solver.printLit(*it);
cout << endl;
#endif
-
+
if (solver.assigns[it->var()] != l_Undef) {
if (solver.assigns[i] == l_Undef) {
bool val = (solver.assigns[it->var()] == l_False);
}
}
+/**
+@brief Used when a variable was eliminated, but it replaced some other variables
+
+This function will add to solver2 clauses that represent the relationship of
+the variables to their replaced cousins. Then, calling solver2.solve() should
+take care of everything
+*/
void VarReplacer::extendModelImpossible(Solver& solver2) const
{
#ifdef VERBOSE_DEBUG
std::cout << "extendModelImpossible() called" << std::endl;
#endif //VERBOSE_DEBUG
-
+
vec<Lit> tmpClause;
- uint i = 0;
+ uint32_t i = 0;
for (vector<Lit>::const_iterator it = table.begin(); it != table.end(); it++, i++) {
if (it->var() == i) continue;
if (solver.assigns[it->var()] == l_Undef) {
assert(solver.assigns[it->var()] == l_Undef);
assert(solver.assigns[i] == l_Undef);
-
+
tmpClause.clear();
tmpClause.push(Lit(it->var(), true));
tmpClause.push(Lit(i, it->sign()));
solver2.addClause(tmpClause);
assert(solver2.ok);
-
+
tmpClause.clear();
tmpClause.push(Lit(it->var(), false));
tmpClause.push(Lit(i, it->sign()^true));
}
}
+/**
+@brief Replaces two two vars in "ps" with one another. xorEqualFalse defines anti/equivalence
+
+It can be tricky to do this. For example, if:
+
+\li a replaces: b, c
+\li f replaces: f, h
+\li we just realised that c = h
+This is the most difficult case, but there are other cases, e.g. if we already
+know that c=h, in which case we don't do anything
+
+@p ps must contain 2 variables(!), i.e literals with no sign
+@p xorEqualFalse if True, the two variables are equivalent. Otherwise, they are antivalent
+@p group of clause they have been inspired from. Sometimes makes no sense...
+*/
template<class T>
-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<Lit>& 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<Lit>& ps, const bool xorEqualFalse, const uint32_t group);
+template const bool VarReplacer::replace(XorClause& ps, const bool xorEqualFalse, const uint32_t group);
-template<class T>
-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<Lit>& 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];
}
return true;
}
-
+
lit2 = table[lit.var()];
if (lit2.var() == var) {
if (lit2.sign() != lit.sign()) {
}
return true;
}
-
+
return false;
}
+/**
+@brief Changes internal graph to set everything that pointed to var to point to lit
+*/
void VarReplacer::setAllThatPointsHereTo(const Var var, const Lit lit)
{
map<Var, vector<Var> >::iterator it = reverseTable.find(var);
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
#include "Clause.h"
#include "Vec.h"
-namespace MINISAT
-{
-using namespace MINISAT;
-
+/**
+@brief Replaces variables with their anti/equivalents
+*/
class VarReplacer
{
public:
const bool performReplace(const bool always = false);
const bool needsReplace();
template<class T>
- 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<Var> getReplacingVars() const;
const vector<Lit>& getReplaceTable() const;
- const vec<Clause*>& getClauses() const;
const bool varHasBeenReplaced(const Var var) const;
const bool replacingVar(const Var var) const;
void newVar();
+ vec<char> cannot_eliminate;
+
//No need to update, only stores binary clauses, that
//have been allocated within pool
//friend class ClauseAllocator;
-
+
private:
const bool performReplaceInternal();
-
- const bool replace_set(vec<Clause*>& cs, const bool binClauses);
+
+ const bool replace_set(vec<Clause*>& cs);
+ const bool replaceBins();
const bool replace_set(vec<XorClause*>& 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<class T>
- 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<Lit> table;
- map<Var, vector<Var> > reverseTable;
- vec<Clause*> clauses;
-
- uint replacedLits;
- uint replacedVars;
- uint lastReplacedVars;
- Solver& solver;
+
+ vector<Lit> table; ///<Stores which variables have been replaced by which literals. Index by: table[VAR]
+ map<Var, vector<Var> > reverseTable; ///<mapping of variable to set of variables it replaces
+
+ uint32_t replacedLits; ///<Num literals replaced during var-replacement
+ uint32_t replacedVars; ///<Num vars replaced during var-replacement
+ uint32_t lastReplacedVars; ///<Last time performReplace() was called, "replacedVars" contained this
+ Solver& solver; ///<The solver we are working with
};
inline const bool VarReplacer::performReplace(const bool always)
uint32_t limit = (uint32_t)((double)solver.order_heap.size()*PERCENTAGEPERFORMREPLACE);
if ((always && getNewToReplaceVars() > 0) || getNewToReplaceVars() > limit)
return performReplaceInternal();
-
+
return true;
}
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;
}
return table;
}
-inline const vec<Clause*>& VarReplacer::getClauses() const
-{
- return clauses;
-}
-
inline const bool VarReplacer::varHasBeenReplaced(const Var var) const
{
return table[var].var() != var;
return reverseTable.size();
}
-}; //NAMESPACE MINISAT
-
#endif //VARREPLACER_H
--- /dev/null
+/***************************************************************************
+CryptoMiniSat -- Copyright (c) 2009 Mate Soos
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*****************************************************************************/
+
+#ifndef WATCHED_H
+#define WATCHED_H
+
+#ifdef _MSC_VER
+#include <msvc/stdint.h>
+#else
+#include <stdint.h>
+#endif //_MSC_VER
+
+//#define DEBUG_WATCHED
+
+#include "ClauseOffset.h"
+#include "SolverTypes.h"
+#include <stdio.h>
+#include "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
#include <stdint.h>
#endif //_MSC_VER
-namespace MINISAT
-{
-using namespace MINISAT;
-
class XorClause;
template <class T>
}
};
-}; //NAMESPACE MINISAT
-
#endif //XSET_H
+
using std::endl;
#endif
-namespace MINISAT
-{
-using namespace MINISAT;
-
using std::make_pair;
-XorFinder::XorFinder(Solver& _solver, vec<Clause*>& _cls, ClauseCleaner::ClauseSetType _type) :
+XorFinder::XorFinder(Solver& _solver, vec<Clause*>& _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++;
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<Lit> lits;
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();
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<Var> 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++;
}
}
#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);
}
}
+/**
+@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;
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<Var> vars;
vec<Lit> 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);
if (tmp) solver.clauses.push(tmp);
}
+/**
+@brief Utility function for addAllXorAsNorm() for converting 4-long xor clauses to normal clauses
+
+\todo clean this up, it's ugly
+*/
void XorFinder::addXorAsNormal4(XorClause& c)
{
assert(c.size() == 4);
Clause *tmp;
vec<Var> vars;
vec<Lit> vars2(c.size());
- const bool inverted = !c.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);
if (tmp) solver.clauses.push(tmp);
}
-
-}; //NAMESPACE MINISAT
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<Clause*>& cls, ClauseCleaner::ClauseSetType _type);
- const bool doNoPart(const uint minSize, const uint maxSize);
+ XorFinder(Solver& _solver, vec<Clause*>& cls);
+ const bool fullFindXors(const uint32_t minSize, const uint32_t maxSize);
void addAllXorAsNorm();
-
+
private:
- typedef vector<pair<Clause*, uint> > ClauseTable;
-
- const bool findXors(uint& sumLengths);
+ typedef vector<pair<Clause*, uint32_t> > 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<Clause*, uint>& c11, const pair<Clause*, uint>& c22)
+ bool operator()(const pair<Clause*, uint32_t>& c11, const pair<Clause*, uint32_t>& c22)
{
if (c11.first->size() != c22.first->size())
return (c11.first->size() < c22.first->size());
-
+
#ifdef DEBUG_XORFIND2
Clause& c1 = *c11.first;
- for (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<Clause*, uint>& c11, const pair<Clause*, uint>& c22) const
+ bool operator()(const pair<Clause*, uint32_t>& c11, const pair<Clause*, uint32_t>& c22) const
{
const Clause& c1 = *(c11.first);
const Clause& c2 = *(c22.first);
+ assert(c1.size() == c2.size());
- for (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<bool> toRemove;
vector<bool> 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<Clause*>& 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
-/**************************************************************************************************
-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"
using std::endl;
#endif //VERBOSE_DEBUG
-namespace MINISAT
-{
-using namespace MINISAT;
-
XorSubsumer::XorSubsumer(Solver& s):
solver(s)
, totalTime(0.0)
#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;
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]);
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;
}
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;
}
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);
}
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
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++) {
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<Clause*>& tmp = solver.varReplacer->getClauses();
- for (uint32_t i = 0; i < tmp.size(); i++)
- addToCannotEliminate(tmp[i]);
-
+ uint32_t wsLit = 0;
+ for (const vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit = ~Lit::toLit(wsLit);
+ const vec<Watched>& ws = *it;
+ for (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++)
void XorSubsumer::extendModel(Solver& solver2)
{
+ #ifdef VERBOSE_DEBUG
+ std::cout << "XorSubsumer::extendModel(Solver& solver2) called" << std::endl;
+ #endif
+
assert(checkElimedUnassigned());
vec<Lit> tmp;
- typedef map<Var, vector<XorClause*> > elimType;
+ typedef map<Var, vector<XorElimedClause> > elimType;
for (elimType::iterator it = elimedOutVar.begin(), end = elimedOutVar.end(); it != end; it++) {
#ifdef VERBOSE_DEBUG
Var var = it->first;
std::cout << "Reinserting elimed var: " << var+1 << std::endl;
#endif
-
- for (vector<XorClause*>::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) {
- XorClause& c = **it2;
+
+ for (vector<XorElimedClause>::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) {
+ XorElimedClause& c = *it2;
#ifdef VERBOSE_DEBUG
std::cout << "Reinserting Clause: ";
c.plainPrint();
#endif
tmp.clear();
- tmp.growTo(c.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);
}
}
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;
}
}
}
-
+
return true;
}
cs.shrink(i-j);
}
+void XorSubsumer::removeWrongBins()
+{
+ uint32_t numRemovedHalfLearnt = 0;
+ uint32_t wsLit = 0;
+ for (vec<Watched> *it = solver.watches.getData(), *end = solver.watches.getDataEnd(); it != end; it++, wsLit++) {
+ Lit lit = ~Lit::toLit(wsLit);
+ vec<Watched>& ws = *it;
+
+ 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()
{
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;
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) {
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;
}
}
}
-
+
return true;
}
const bool XorSubsumer::unEliminate(const Var var)
{
assert(var_elimed[var]);
- typedef map<Var, vector<XorClause*> > elimType;
+ vec<Lit> tmp;
+ typedef map<Var, vector<XorElimedClause> > elimType;
elimType::iterator it = elimedOutVar.find(var);
//MUST set to decision, since it would never have been eliminated
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<XorClause*>::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<XorElimedClause>::iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; it2++) {
+ XorElimedClause& c = *it2;
+ tmp.clear();
+ tmp.growTo(c.lits.size());
+ std::copy(c.lits.begin(), c.lits.end(), tmp.getData());
+ #ifdef VERBOSE_DEBUG
+ std::cout << "Reinserting elimed clause: " << tmp << std::endl;;
+ #endif
+ solver.addXorClause(tmp, c.xorEqualFalse);
}
solver.libraryCNFFile = backup_libraryCNFfile;
elimedOutVar.erase(it);
-
+
return solver.ok;
}
-const bool XorSubsumer::simplifyBySubsumption(const bool doFullSubsume)
+const bool XorSubsumer::simplifyBySubsumption()
{
double myTime = cpuTime();
uint32_t origTrailSize = solver.trail.size();
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) {
}
}
}
-
+
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;
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) <<solver.trail.size() - origTrailSize
<< " v-elim: " <<std::setw(6) << numElimed - lastNumElimed
<< " locsubst:" << std::setw(6) << localSubstituteUseful
<< " time: " << std::setw(6) << std::setprecision(2) << (cpuTime() - myTime)
- << std::setw(3) << " |" << std::endl;
+ << std::endl;
}
totalTime += cpuTime() - myTime;
-
+
solver.testAllClauseAttach();
return true;
}
-#ifdef DEBUG_ATTACH
-void XorSubsumer::testAllClauseAttach() const
-{
- for (const XorClauseSimp *it = clauses.getData(), *end = clauses.getDataEnd(); it != end; it++) {
- if (it->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<XorClauseSimp>& out_subsumed)
{
#ifdef VERBOSE_DEBUGSUBSUME0
}
printf("0\n");
#endif
-
+
uint32_t min_i = 0;
for (uint32_t i = 1; i < ps.size(); i++){
if (occur[ps[i].var()].size() < occur[ps[min_i].var()].size())
min_i = i;
}
-
+
vec<XorClauseSimp>& cs = occur[ps[min_i].var()];
for (XorClauseSimp *it = cs.getData(), *end = it + cs.size(); it != end; it++){
if (it+1 != end)
__builtin_prefetch((it+1)->clause, 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
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<Var, vector<XorElimedClause> >::iterator it = elimedOutVar.find(var);
+ if (it != elimedOutVar.end()) elimedOutVar.erase(it);
+ }
+ }
+}
-/**************************************************************************************************
-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
#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<Lit>& origClause, XorClauseSimp c);
void unlinkModifiedClauseNoDetachNoNULL(vec<Lit>& origClause, XorClauseSimp c);
void unlinkClause(XorClauseSimp cc, Var elim = var_Undef);
void linkInAlreadyClause(XorClauseSimp& c);
void newVar();
void extendModel(Solver& solver2);
+
const uint32_t getNumElimed() const;
const vec<char>& getVarElimed() const;
const bool unEliminate(const Var var);
const bool checkElimedUnassigned() const;
const double getTotalTime() const;
-
+
+ struct XorElimedClause
+ {
+ vector<Lit> lits;
+ bool xorEqualFalse;
+
+ void plainPrint(FILE* to = stdout) const
+ {
+ fprintf(to, "x");
+ if (xorEqualFalse) fprintf(to, "-");
+ for (size_t i = 0; i < lits.size(); i++) {
+ assert(!lits[i].sign());
+ fprintf(to, "%d ", lits[i].var() + 1);
+ }
+ fprintf(to, "0\n");
+ }
+ };
+ const map<Var, vector<XorElimedClause> >& getElimedOutVar() const;
+
private:
-
+
friend class ClauseCleaner;
friend class ClauseAllocator;
-
+
//Main
vec<XorClauseSimp> clauses;
vec<vec<XorClauseSimp> > occur; // 'occur[index(lit)]' is a list of constraints containing 'lit'.
Solver& solver; // The Solver
-
+
// Temporaries (to reduce allocation overhead):
//
vec<char> seen_tmp; // (used in various places)
-
+
//Start-up
void addFromSolver(vec<XorClause*>& cs);
void addBackToSolver();
-
+
// Subsumption:
void findSubsumed(XorClause& ps, vec<XorClauseSimp>& out_subsumed);
bool isSubsumed(XorClause& ps);
//helper
void testAllClauseAttach() const;
-
+
//dependent removal
const bool removeDependent();
void fillCannotEliminate();
vec<char> cannot_eliminate;
void addToCannotEliminate(Clause* it);
void removeWrong(vec<Clause*>& cs);
+ void removeWrongBins();
+ void removeAssignedVarsFromEliminated();
//Global stats
double totalTime;
- map<Var, vector<XorClause*> > elimedOutVar;
+ map<Var, vector<XorElimedClause> > elimedOutVar;
vec<char> var_elimed;
uint32_t numElimed;
-
+
//Heule-process
template<class T>
void xorTwoClauses(const T& c1, const T& c2, vec<Lit>& xored);
const bool localSubstitute();
uint32_t localSubstituteUseful;
-
+
uint32_t clauses_subsumed;
uint32_t clauses_cut;
uint32_t origNClauses;
return totalTime;
}
-}; //NAMESPACE MINISAT
+inline const map<Var, vector<XorSubsumer::XorElimedClause> >& XorSubsumer::getElimedOutVar() const
+{
+ return elimedOutVar;
+}
#endif //XORSIMPLIFIER_H
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"
#endif // __STDC_CONSTANT_MACROS ]
-#ifndef uint
-#define uint unsigned int
-#endif
-
#endif // _MSC_STDINT_H_ ]
#ifndef Alg_h
#define Alg_h
+#include <iostream>
+#include "Vec.h"
+#include "../SolverTypes.h"
+#include "../Watched.h"
+
#ifdef _MSC_VER
#include <msvc/stdint.h>
#else
#include <stdint.h>
#endif //_MSC_VER
-namespace MINISAT
-{
-using namespace MINISAT;
-
//=================================================================================================
// Useful functions on vectors
-
template<class V, class T>
static inline void remove(V& ts, const T& t)
{
ts.pop();
}
+template<class V>
+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<class V, class T>
static inline void removeW(V& ts, const T& t)
{
return j < ts.size();
}
-}; //NAMESPACE MINISAT
+
+//Normal clause
+static bool findWCl(const vec<Watched>& ws, const ClauseOffset c);
+static void removeWCl(vec<Watched> &ws, const ClauseOffset c);
+
+//Binary clause
+static bool findWBin(const vec<vec<Watched> >& wsFull, const Lit lit1, const Lit impliedLit);
+static bool findWBin(const vec<vec<Watched> >& wsFull, const Lit lit1, const Lit impliedLit, const bool learnt);
+static void removeWBin(vec<Watched> &ws, const Lit impliedLit, const bool learnt);
+static void removeWTri(vec<Watched> &ws, const Lit lit1, Lit lit2);
+static const std::pair<uint32_t, uint32_t> removeWBinAll(vec<Watched> &ws, const Lit impliedLit);
+static Watched& findWatchedOfBin(vec<vec<Watched> >& wsFull, const Lit lit1, const Lit lit2, const bool learnt);
+static Watched& findWatchedOfBin(vec<vec<Watched> >& wsFull, const Lit lit1, const Lit lit2);
+
+//Xor Clause
+static bool findWXCl(const vec<Watched>& ws, const ClauseOffset c);
+static void removeWXCl(vec<Watched> &ws, const ClauseOffset c);
+
+//////////////////
+// NORMAL Clause
+//////////////////
+static inline bool findWCl(const vec<Watched>& 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<Watched> &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<Watched>& 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<Watched> &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<Watched> &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<Watched> &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<vec<Watched> >& wsFull, const Lit lit1, const Lit impliedLit)
+{
+ uint32_t j = 0;
+ const vec<Watched>& 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<vec<Watched> >& wsFull, const Lit lit1, const Lit impliedLit, const bool learnt)
+{
+ uint32_t j = 0;
+ const vec<Watched>& 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<Watched> &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<uint32_t, uint32_t> removeWBinAll(vec<Watched> &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<vec<Watched> >& wsFull, const Lit lit1, const Lit lit2, const bool learnt)
+{
+ vec<Watched>& 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<vec<Watched> >& wsFull, const Lit lit1, const Lit lit2)
+{
+ vec<Watched>& 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
#include "Vec.h"
-namespace MINISAT
-{
-using namespace MINISAT;
-
//=================================================================================================
// A heap implementation with support for decrease/increase key.
int getmin () { return removeMin(); }
};
-}; //NAMESPACE MINISAT
//=================================================================================================
#endif
#include <cassert>
#include <new>
-namespace MINISAT
-{
-using namespace MINISAT;
-
//=================================================================================================
// Automatically resizable arrays
//
};
-}; //NAMESPACE MINISAT
#endif
#include <stdint.h>
#endif //_MSC_VER
-namespace MINISAT
-{
-using namespace MINISAT;
-
//=================================================================================================
// A heap implementation with support for decrease/increase key.
indices[heap[i]] = std::numeric_limits<uint32_t>::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());
};
-//=================================================================================================
-
-}; //NAMESPACE MINISAT
+//=================================================================================================
#endif
#include "Vec.h"
-namespace MINISAT
-{
-using namespace MINISAT;
-
//=================================================================================================
// Default hash/equals functions
//
}
};
-}; //NAMESPACE MINISAT
-
#endif
#include "Vec.h"
-namespace MINISAT
-{
-using namespace MINISAT;
-
//=================================================================================================
//};
//=================================================================================================
-
-}; //NAMESPACE MINISAT
-
#endif
#include <cstdlib>
#include <cassert>
+#include <iostream>
#include <new>
#ifdef _MSC_VER
#include <msvc/stdint.h>
#include <stdint.h>
#endif //_MSC_VER
-namespace MINISAT
-{
-using namespace MINISAT;
-
//=================================================================================================
// Automatically resizable arrays
//
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<T>& other);
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]; }
grow(size);
for (uint32_t i = sz; i != size; i++) new (&data[i]) T();
sz = size; }
-
+
template<class T>
void vec<T>::myCopy(const vec<T>& other) {
assert(sz == 0);
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
#define TIME_MEM_H
#ifdef _MSC_VER
- #include <ctime>
- #include <msvc/stdint.h>
+#include <msvc/stdint.h>
#else
- #include <sys/time.h>
- #include <sys/resource.h>
- #include <unistd.h>
- #include <stdint.h>
-#endif
+#include <stdint.h>
+#endif //_MSC_VER
-namespace MINISAT
-{
-using namespace MINISAT;
+#if defined (_MSC_VER) || defined(CROSS_COMPILE)
+#include <ctime>
-/*************************************************************************************/
-#ifdef _MSC_VER
+static inline double cpuTime(void)
+{
+ return (double)clock() / CLOCKS_PER_SEC;
+}
+#else //_MSC_VER
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
-static inline double cpuTime(void) {
- 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 <stdio.h>
static inline int memReadStat(int field)
{
char name[256];
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 <fpu_control.h>
+static inline uint64_t memUsed()
+{
+ return 0;
+}
#endif
-};
-
#endif //TIME_MEM_H