/*****************************************************************************/ /*! *\file cnf_manager.h *\brief Manager for conversion to and traversal of CNF formulas * * Author: Clark Barrett * * Created: Thu Dec 15 13:53:16 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #ifndef _cvc3__include__cnf_manager_h_ #define _cvc3__include__cnf_manager_h_ #include "cnf.h" #include "expr.h" #include "expr_map.h" #include "cdmap.h" #include "statistics.h" namespace CVC3 { class CommonProofRules; class CNF_Rules; class ValidityChecker; class Statistics; } namespace SAT { class CNF_Manager { //! For clause minimization CVC3::ValidityChecker* d_vc; //! Whether to use brute-force clause minimization bool d_minimizeClauses; //! Common proof rules CVC3::CommonProofRules* d_commonRules; //! Rules for manipulating CNF CVC3::CNF_Rules* d_rules; //! Information kept for each CNF variable struct Varinfo { CVC3::Expr expr; std::vector fanins; std::vector fanouts; }; //! vector that maps a variable index to information for that variable std::vector d_varInfo; //! Map from Exprs to Vars representing those Exprs CVC3::ExprMap d_cnfVars; //! Cached translation of term-ite-containing expressions CVC3::ExprMap d_iteMap; //! Maps a clause id to the theorem justifying that clause /*! Note that clauses created by simple CNF translation are not given id's. * This is because theorems for these clauses can be created lazily later. */ // CVC3::CDMap d_theorems; //! Next clause id int d_clauseIdNext; //! Whether expr has already been translated // CVC3::CDMap d_translated; //! Bottom scope in which translation is valid int d_bottomScope; //! Queue of theorems to translate std::deque d_translateQueueThms; //! Queue of fanouts corresponding to thms to translate std::deque d_translateQueueVars; //! Whether thm to translate is "translate only" std::deque d_translateQueueFlags; //! Reference to statistics object CVC3::Statistics& d_statistics; public: //! Abstract class for callbacks class CNFCallback { public: CNFCallback() {} virtual ~CNFCallback() {} //! Register an atom virtual void registerAtom(const CVC3::Expr& e, const CVC3::Theorem& thm) = 0; }; private: //! Instance of CNF_CallBack: must be registered CNFCallback* d_cnfCallback; CVC3::CNF_Rules* createProofRules(CVC3::TheoremManager* tm); //! Register a new atomic formula void registerAtom(const CVC3::Expr& e, const CVC3::Theorem& thm); //! Recursively translate e into cnf /*! A non-context dependent cache, d_cnfVars is used to remember translations * of expressions. A context-dependent attribute, isTranslated, is used to * remember whether an expression has been translated in the current context */ Lit translateExprRec(const CVC3::Expr& e, CNF_Formula& cnf, const CVC3::Theorem& thmIn); //! Recursively traverse an expression with an embedded term ITE /*! Term ITE's are handled by introducing a skolem variable for the ITE term * and then adding new constraints describing the ITE in terms of the new variable. */ CVC3::Theorem replaceITErec(const CVC3::Expr& e, Var v, bool translateOnly); //! Recursively translate e into cnf /*! Call translateExprRec. If additional expressions are queued up, * translate them too, until none are left. */ Lit translateExpr(const CVC3::Theorem& thmIn, CNF_Formula& cnf); // bool isTranslated(const CVC3::Expr& e) // { CVC3::CDMap::iterator i = d_translated.find(e); // return i != d_translated.end() && (*i).second; } // void setTranslated(const CVC3::Expr& e) // { DebugAssert(!isTranslated(e),"already set"); // d_translated.insert(e, true, d_bottomScope); } // void clearTranslated(const CVC3::Expr& e) // { d_translated.insert(e, false, d_bottomScope); } public: CNF_Manager(CVC3::TheoremManager* tm, CVC3::Statistics& statistics, bool minimizeClauses); ~CNF_Manager(); //! Register CNF callback void registerCNFCallback(CNFCallback* cnfCallback) { d_cnfCallback = cnfCallback; } //! Set scope for translation void setBottomScope(int scope) { d_bottomScope = scope; } //! Return the number of variables being managed unsigned numVars() { return d_varInfo.size(); } //! Return number of fanins for CNF node c /*! A CNF node x is a fanin of CNF node y if the expr for x is a child of the * expr for y or if y is an ITE leaf and x is a new CNF node obtained by * translating the ITE leaf y. * \sa isITELeaf() */ unsigned numFanins(Lit c) { if (!c.isVar()) return 0; int index = c.getVar(); if ((unsigned)index >= d_varInfo.size()) return 0; return d_varInfo[index].fanins.size(); } //! Returns the ith fanin of c. Lit getFanin(Lit c, unsigned i) { DebugAssert(i < numFanins(c), "attempt to access unknown fanin"); return d_varInfo[c.getVar()].fanins[i]; } //! Return number of fanins for c /*! x is a fanout of y if y is a fanin of x * \sa numFanins */ unsigned numFanouts(Lit c) { if (!c.isVar()) return 0; int index = c.getVar(); if ((unsigned)index >= d_varInfo.size()) return 0; return d_varInfo[index].fanouts.size(); } //! Returns the ith fanout of c. Lit getFanout(Lit c, unsigned i) { DebugAssert(i < numFanouts(c), "attempt to access unknown fanin"); return Lit(d_varInfo[c.getVar()].fanouts[i]); } //! Convert a CNF literal to an Expr literal /*! Returns a NULL Expr if there is no corresponding Expr for l */ CVC3::Expr concreteLit(Lit l, bool checkTranslated = true) { if (l.isNull()) return CVC3::Expr(); bool inverted = !l.isPositive(); int index = l.getVar(); if ((unsigned)index >= d_varInfo.size() || (checkTranslated && !d_varInfo[index].expr.isTranslated())) return CVC3::Expr(); return inverted ? !d_varInfo[index].expr : d_varInfo[index].expr; } //! Look up the CNF literal for an Expr /*! Returns a NULL Lit if there is no corresponding CNF literal for e */ Lit getCNFLit(const CVC3::Expr& e) { if (e.isFalse()) return Lit::getFalse(); if (e.isTrue()) return Lit::getTrue(); if (e.isNot()) return !getCNFLit(e[0]); CVC3::ExprMap::iterator i = d_cnfVars.find(e); if (!e.isTranslated() || i == d_cnfVars.end()) return Lit(); return Lit((*i).second); } void cons(unsigned lb, unsigned ub, const CVC3::Expr& e2, std::vector& newLits); //! Convert thm A |- B (A is a set of literals) into a clause ~A \/ B /*! c should be an empty clause that will be filled with the result */ void convertLemma(const CVC3::Theorem& thm, Clause& c); //! Given thm of form A |- B, convert B to CNF and add it to cnf /*! Returns Lit corresponding to the root of the expression that was * translated. */ Lit addAssumption(const CVC3::Theorem& thm, CNF_Formula& cnf); //! Convert thm to CNF and add it to the current formula /*! \param thm should be of form A |- B where A is a set of literals. * \param cnf the new clauses are added to cnf. * Returns Lit corresponding to the root of the expression that was * translated. */ Lit addLemma(const CVC3::Theorem& thm, CNF_Formula& cnf); }; } #endif