00001 /*****************************************************************************/ 00002 /*! 00003 *\file cnf_manager.h 00004 *\brief Manager for conversion to and traversal of CNF formulas 00005 * 00006 * Author: Clark Barrett 00007 * 00008 * Created: Thu Dec 15 13:53:16 2005 00009 * 00010 * <hr> 00011 * Copyright (C) 2005 by the Board of Trustees of Leland Stanford 00012 * Junior University and by New York University. 00013 * 00014 * License to use, copy, modify, sell and/or distribute this software 00015 * and its documentation for any purpose is hereby granted without 00016 * royalty, subject to the terms and conditions defined in the \ref 00017 * LICENSE file provided with this distribution. In particular: 00018 * 00019 * - The above copyright notice and this permission notice must appear 00020 * in all copies of the software and related documentation. 00021 * 00022 * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES, 00023 * EXPRESSED OR IMPLIED. USE IT AT YOUR OWN RISK. 00024 * 00025 * <hr> 00026 */ 00027 /*****************************************************************************/ 00028 00029 #ifndef _cvcl__include__cnf_manager_h_ 00030 #define _cvcl__include__cnf_manager_h_ 00031 00032 #include "cnf.h" 00033 #include "expr.h" 00034 #include "expr_map.h" 00035 #include "cdmap.h" 00036 00037 namespace CVCL { 00038 00039 class CommonProofRules; 00040 class CNF_Rules; 00041 00042 } 00043 00044 namespace SAT { 00045 00046 class CNF_Manager { 00047 00048 //! Common proof rules 00049 CVCL::CommonProofRules* d_commonRules; 00050 00051 //! Rules for manipulating CNF 00052 CVCL::CNF_Rules* d_rules; 00053 00054 //! Information kept for each CNF variable 00055 struct Varinfo { 00056 CVCL::Expr expr; 00057 std::vector<Lit> fanins; 00058 std::vector<Var> fanouts; 00059 }; 00060 00061 //! vector that maps a variable index to information for that variable 00062 std::vector<Varinfo> d_varInfo; 00063 00064 //! Map from Exprs to Vars representing those Exprs 00065 CVCL::ExprMap<Var> d_cnfVars; 00066 00067 //! Cached translation of term-ite-containing expressions 00068 CVCL::ExprMap<CVCL::Theorem> d_iteMap; 00069 00070 //! Maps a clause id to the theorem justifying that clause 00071 /*! Note that clauses created by simple CNF translation are not given id's. 00072 * This is because theorems for these clauses can be created lazily later. */ 00073 CVCL::CDMap<int, CVCL::Theorem> d_theorems; 00074 00075 //! Next clause id 00076 int d_clauseIdNext; 00077 00078 //! Whether expr has already been translated 00079 // CVCL::CDMap<CVCL::Expr, bool> d_translated; 00080 00081 //! Bottom scope in which translation is valid 00082 int d_bottomScope; 00083 00084 //! Queue of theorems to translate 00085 std::deque<CVCL::Theorem> d_translateQueueThms; 00086 00087 //! Queue of fanouts corresponding to thms to translate 00088 std::deque<Var> d_translateQueueVars; 00089 00090 //! Whether thm to translate is "translate only" 00091 std::deque<bool> d_translateQueueFlags; 00092 00093 private: 00094 00095 CVCL::CNF_Rules* createProofRules(CVCL::TheoremManager* tm); 00096 00097 //! Recursively translate e into cnf 00098 /*! A non-context dependent cache, d_cnfVars is used to remember translations 00099 * of expressions. A context-dependent attribute, isTranslated, is used to 00100 * remember whether an expression has been translated in the current context */ 00101 Lit translateExprRec(const CVCL::Expr& e, CNF_Formula& cnf); 00102 00103 //! Recursively traverse an expression with an embedded term ITE 00104 /*! Term ITE's are handled by introducing a skolem variable for the ITE term 00105 * and then adding new constraints describing the ITE in terms of the new variable. 00106 */ 00107 CVCL::Theorem replaceITErec(const CVCL::Expr& e, Var v, bool translateOnly); 00108 00109 //! Recursively translate e into cnf 00110 /*! Call translateExprRec. If additional expressions are queued up, 00111 * translate them too, until none are left. */ 00112 Lit translateExpr(const CVCL::Expr& e, CNF_Formula& cnf); 00113 00114 // bool isTranslated(const CVCL::Expr& e) 00115 // { CVCL::CDMap<CVCL::Expr, bool>::iterator i = d_translated.find(e); 00116 // return i != d_translated.end() && (*i).second; } 00117 // void setTranslated(const CVCL::Expr& e) 00118 // { DebugAssert(!isTranslated(e),"already set"); 00119 // d_translated.insert(e, true, d_bottomScope); } 00120 // void clearTranslated(const CVCL::Expr& e) 00121 // { d_translated.insert(e, false, d_bottomScope); } 00122 00123 public: 00124 CNF_Manager(CVCL::TheoremManager* tm); 00125 ~CNF_Manager(); 00126 00127 //! Set scope for translation 00128 void setBottomScope(int scope) { d_bottomScope = scope; } 00129 00130 //! Return the number of variables being managed 00131 unsigned numVars() { return d_varInfo.size(); } 00132 00133 //! Return number of fanins for CNF node c 00134 /*! A CNF node x is a fanin of CNF node y if the expr for x is a child of the 00135 * expr for y or if y is an ITE leaf and x is a new CNF node obtained by 00136 * translating the ITE leaf y. 00137 * \sa isITELeaf() 00138 */ 00139 unsigned numFanins(Lit c) { 00140 if (!c.isVar()) return 0; 00141 int index = c.getVar(); 00142 if ((unsigned)index >= d_varInfo.size()) return 0; 00143 return d_varInfo[index].fanins.size(); 00144 } 00145 00146 //! Returns the ith fanin of c. 00147 Lit getFanin(Lit c, unsigned i) { 00148 DebugAssert(i < numFanins(c), "attempt to access unknown fanin"); 00149 return d_varInfo[c.getVar()].fanins[i]; 00150 } 00151 00152 //! Return number of fanins for c 00153 /*! x is a fanout of y if y is a fanin of x 00154 * \sa numFanins 00155 */ 00156 unsigned numFanouts(Lit c) { 00157 if (!c.isVar()) return 0; 00158 int index = c.getVar(); 00159 if ((unsigned)index >= d_varInfo.size()) return 0; 00160 return d_varInfo[index].fanouts.size(); 00161 } 00162 00163 //! Returns the ith fanout of c. 00164 Lit getFanout(Lit c, unsigned i) { 00165 DebugAssert(i < numFanouts(c), "attempt to access unknown fanin"); 00166 return d_varInfo[c.getVar()].fanouts[i]; 00167 } 00168 00169 //! Convert a CNF literal to an Expr literal 00170 /*! Returns a NULL Expr if there is no corresponding Expr for l 00171 */ 00172 CVCL::Expr concreteLit(Lit l) { 00173 if (l.isNull()) return CVCL::Expr(); 00174 bool inverted = !l.isPositive(); 00175 int index = l.getVar(); 00176 if ((unsigned)index >= d_varInfo.size() || 00177 !d_varInfo[index].expr.isTranslated()) return CVCL::Expr(); 00178 return inverted ? !d_varInfo[index].expr : d_varInfo[index].expr; 00179 } 00180 00181 //! Look up the CNF literal for an Expr 00182 /*! Returns a NULL Lit if there is no corresponding CNF literal for e 00183 */ 00184 Lit getCNFLit(const CVCL::Expr& e) { 00185 if (e.isFalse()) return Lit::getFalse(); 00186 if (e.isTrue()) return Lit::getTrue(); 00187 if (e.isNot()) return !getCNFLit(e[0]); 00188 CVCL::ExprMap<Var>::iterator i = d_cnfVars.find(e); 00189 if (!e.isTranslated() || i == d_cnfVars.end()) return Lit(); 00190 return Lit((*i).second); 00191 } 00192 00193 //! Convert thm A |- B (A is a set of literals) into a clause ~A \/ B 00194 /*! c should be an empty clause that will be filled with the result */ 00195 void convertLemma(const CVCL::Theorem& thm, Clause& c); 00196 00197 //! Given thm of form A |- B, convert B to CNF and add it to cnf 00198 /*! Returns Lit corresponding to the root of the expression that was 00199 * translated. */ 00200 Lit addAssumption(const CVCL::Theorem& thm, CNF_Formula& cnf); 00201 00202 //! Convert thm to CNF and add it to the current formula 00203 /*! \param thm should be of form A |- B where A is a set of literals 00204 * The new clauses are added to cnf. 00205 * Returns Lit corresponding to the root of the expression that was 00206 * translated. */ 00207 Lit addLemma(const CVCL::Theorem& thm, CNF_Formula& cnf); 00208 00209 }; 00210 00211 } 00212 00213 #endif