/***************************************************************************** SatELite -- (C) Niklas Een, Niklas Sorensson, 2004 CryptoMiniSat -- Copyright (c) 2009 Mate Soos Original code by SatELite authors are under an MIT licence. Modifications for CryptoMiniSat are under GPLv3. ******************************************************************************/ #ifndef SIMPLIFIER_H #define SIMPLIFIER_H #include "Solver.h" #include "CSet.h" #include "BitArray.h" #include #include #include #include namespace CMSat { using std::vector; using std::list; using std::map; using std::priority_queue; class ClauseCleaner; class OnlyNonLearntBins; class TouchList { public: void resize(uint32_t size) { touched.resize(size, 0); } void addOne(Var var) { assert(touched.size() == var); touched.push_back(1); touchedList.push_back(var); } void touch(Lit lit, const bool learnt) { if (!learnt) touch(lit.var()); } void touch(Var var) { if (!touched[var]) { touchedList.push_back(var); touched[var]= 1; } } void clear() { touchedList.clear(); std::fill(touched.begin(), touched.end(), 0); } uint32_t size() const { return touchedList.size(); } vector::const_iterator begin() const { return touchedList.begin(); } vector::const_iterator end() const { return touchedList.end(); } private: vector touchedList; vector touched; }; /** @brief Handles subsumption, self-subsuming resolution, variable elimination, and related algorithms There are two main functions in this class, simplifyBySubsumption() and subsumeWithBinaries(). The first one is the most important of the two: it performs everything, except manipuation with non-existing binary clauses. The second does self-subsuming resolution with existing binary clauses, and then does self-subsuming resolution and subsumption with binary clauses that don't exist and never will exist: they are temporarily "created" (memorised), and used by subsume0BIN(). */ class Subsumer { public: //Construct-destruct Subsumer(Solver& S2); //Called from main bool simplifyBySubsumption(); void newVar(); //UnElimination void extendModel(Solver& solver2); bool unEliminate(const Var var); //Get-functions const vec& getVarElimed() const; uint32_t getNumElimed() const; bool checkElimedUnassigned() const; double getTotalTime() const; const map > >& getElimedOutVar() const; const map > >& getElimedOutVarBin() const; private: /*bool subsumeWithBinTri(); bool subsumeWithBinTri( vec& cls , bool learnt , uint32_t& subsumed_bin_num , uint32_t& subsumed_tri_num , uint32_t& lit_rem_bin , uint32_t& lit_rem_tri );*/ friend class ClauseCleaner; friend class ClauseAllocator; //Main /** @brief Clauses to be treated are moved here ClauseSimp::index refers to the index of the clause here */ vec clauses; TouchList touchedVars; /// > occur; /// iter_sets; /// cannot_eliminate;/// seen_tmp; /// var_elimed; /// > > elimedOutVar; /// > > elimedOutVarBin; ///& cs); void fillCannotEliminate(); void clearAll(); void setLimits(); bool subsume0AndSubsume1(); vec ol_seenPos; vec ol_seenNeg; //Finish-up void freeMemory(); void addBackToSolver(); void removeWrong(vec& cs); void removeWrongBinsAndAllTris(); void removeAssignedVarsFromEliminated(); //Iterations void registerIteration (CSet& iter_set) { iter_sets.push(&iter_set); } void unregisterIteration(CSet& iter_set) { remove(iter_sets, &iter_set); } //Used by cleaner void unlinkClause(ClauseSimp cc, const Var elim = var_Undef); ClauseSimp linkInClause(Clause& cl); //Findsubsumed template void findSubsumed(const T& ps, const uint32_t abst, vec& out_subsumed); template void findSubsumed1(const T& ps, uint32_t abs, vec& out_subsumed, vec& out_lits); template void fillSubs(const T& ps, uint32_t abs, vec& out_subsumed, vec& out_lits, const Lit lit); template bool subset(const uint32_t aSize, const T2& B); template Lit subset1(const T1& A, const T2& B); bool subsetAbst(uint32_t A, uint32_t B); //binary clause-subsumption struct BinSorter { bool operator()(const Watched& first, const Watched& second) { assert(first.isBinary() || first.isTriClause()); assert(second.isBinary() || second.isTriClause()); if (first.isTriClause() && second.isTriClause()) return false; if (first.isBinary() && second.isTriClause()) return true; if (second.isBinary() && first.isTriClause()) return false; assert(first.isBinary() && second.isBinary()); if (first.getOtherLit().toInt() < second.getOtherLit().toInt()) return true; if (first.getOtherLit().toInt() > second.getOtherLit().toInt()) return false; if (first.getLearnt() == second.getLearnt()) return false; if (!first.getLearnt()) return true; return false; }; }; void subsumeBinsWithBins(); //subsume0 struct subsume0Happened { bool subsumedNonLearnt; uint32_t glue; float act; }; /** @brief Sort clauses according to size */ struct sortBySize { bool operator () (const Clause* x, const Clause* y) { return (x->size() < y->size()); } }; void subsume0(Clause& ps); template subsume0Happened subsume0Orig(const T& ps, uint32_t abs); void subsume0Touched(); //subsume1 class NewBinaryClause { public: NewBinaryClause(const Lit _lit1, const Lit _lit2, const bool _learnt) : lit1(_lit1), lit2(_lit2), learnt(_learnt) {}; const Lit lit1; const Lit lit2; const bool learnt; }; list clBinTouched; ///& ps, const bool wasLearnt); void strenghten(ClauseSimp& c, const Lit toRemoveLit); bool cleanClause(Clause& ps); bool cleanClause(vec& ps) const; void handleSize1Clause(const Lit lit); /*bool subsWNonExitsBinsFullFull(); bool subsWNonExistBinsFull(); bool subsWNonExistBins(const Lit& lit, OnlyNonLearntBins* OnlyNonLearntBins); uint64_t extraTimeNonExist; bool subsNonExistentFinish; vec toVisit; vec toVisitAll;*/ //Variable elimination /** @brief Struct used to compare variable elimination difficulties Used to order variables according to their difficulty of elimination. Used by the std::sort() function. in \function orderVarsForElim() */ struct myComp { bool operator () (const std::pair& x, const std::pair& y) { return x.first < y.first; } }; class ClAndBin { public: ClAndBin(ClauseSimp& cl) : clsimp(cl) , lit1(lit_Undef) , lit2(lit_Undef) , isBin(false) {} ClAndBin(const Lit _lit1, const Lit _lit2) : clsimp(NULL, 0) , lit1(_lit1) , lit2(_lit2) , isBin(true) {} ClauseSimp clsimp; Lit lit1; Lit lit2; bool isBin; }; void orderVarsForElim(vec& order); uint32_t numNonLearntBins(const Lit lit) const; bool maybeEliminate(Var x); void removeClauses(vec& posAll, vec& negAll, const Var var); void removeClausesHelper(vec& todo, const Var var, std::pair& removed); bool merge(const ClAndBin& ps, const ClAndBin& qs, const Lit without_p, const Lit without_q, vec& out_clause); bool eliminateVars(); void fillClAndBin(vec& all, vec& cs, const Lit lit); //Subsume with Nonexistent Bins struct BinSorter2 { bool operator()(const Watched& first, const Watched& second) { assert(first.isBinary() || first.isTriClause()); assert(second.isBinary() || second.isTriClause()); if (first.isTriClause() && second.isTriClause()) return false; if (first.isBinary() && second.isTriClause()) return true; if (second.isBinary() && first.isTriClause()) return false; assert(first.isBinary() && second.isBinary()); if (first.getLearnt() && !second.getLearnt()) return true; if (!first.getLearnt() && second.getLearnt()) return false; return false; }; }; void subsume0BIN(const Lit lit, const vec& lits, const uint32_t abst); uint32_t doneNum; //Blocked clause elimination class VarOcc { public: VarOcc(const Var& v, const uint32_t num) : var(v) , occurnum(num) {} Var var; uint32_t occurnum; }; struct MyComp { bool operator() (const VarOcc& l1, const VarOcc& l2) const { return l1.occurnum > l2.occurnum; } }; void blockedClauseRemoval(); template bool allTautology(const T& ps, const Lit lit); uint32_t numblockedClauseRemoved; bool tryOneSetting(const Lit lit); priority_queue, MyComp> touchedBlockedVars; vec touchedBlockedVarsBool; void touchBlockedVar(const Var x); void blockedClauseElimAll(const Lit lit); //validity checking bool verifyIntegrity(); uint32_t clauses_subsumed; /// void maybeRemove(vec& ws, const T2& elem) { if (ws.size() > 0) removeW(ws, elem); } /** @brief Put varible in touchedBlockedVars call it when the number of occurrences of this variable changed. */ inline void Subsumer::touchBlockedVar(const Var x) { if (!touchedBlockedVarsBool[x]) { touchedBlockedVars.push(VarOcc(x, occur[Lit(x, false).toInt()].size()*occur[Lit(x, true).toInt()].size())); touchedBlockedVarsBool[x] = 1; } } /** @brief Decides only using abstraction if clause A could subsume clause B @note: It can give false positives. Never gives false negatives. For A to subsume B, everything that is in A MUST be in B. So, if (A & ~B) contains even one bit, it means that A contains something that B doesn't. So A may be a subset of B only if (A & ~B) == 0 */ inline bool Subsumer::subsetAbst(const uint32_t A, const uint32_t B) { return !(A & ~B); } //A subsumes B (A is <= B) template 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 Lit Subsumer::subset1(const T1& A, const T2& B) { Lit retLit = lit_Undef; for (uint32_t i = 0; i != B.size(); i++) seen_tmp[B[i].toInt()] = 1; for (uint32_t i = 0; i != A.size(); i++) { if (!seen_tmp[A[i].toInt()]) { if (retLit == lit_Undef && seen_tmp[(~A[i]).toInt()]) retLit = ~A[i]; else { retLit = lit_Error; goto end; } } } end: for (uint32_t i = 0; i != B.size(); i++) seen_tmp[B[i].toInt()] = 0; return retLit; } /** @brief New var has been added to the solver @note: MUST be called if a new var has been added to the solver Adds occurrence list places, increments seen_tmp, etc. */ inline void Subsumer::newVar() { occur .push(); occur .push(); seen_tmp .push(0); // (one for each polarity) seen_tmp .push(0); touchedVars .addOne(solver.nVars()-1); var_elimed .push(0); touchedBlockedVarsBool.push(0); cannot_eliminate.push(0); ol_seenPos.push(1); ol_seenPos.push(1); ol_seenNeg.push(1); ol_seenNeg.push(1); } inline const map > >& Subsumer::getElimedOutVar() const { return elimedOutVar; } inline const map > >& Subsumer::getElimedOutVarBin() const { return elimedOutVarBin; } inline const vec& Subsumer::getVarElimed() const { return var_elimed; } inline uint32_t Subsumer::getNumElimed() const { return numElimed; } inline double Subsumer::getTotalTime() const { return totalTime; } } #endif //SIMPLIFIER_H