summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLiana Hadarean <lianahady@gmail.com>2016-01-26 16:04:26 -0800
committerLiana Hadarean <lianahady@gmail.com>2016-01-26 16:04:26 -0800
commit42b665f2a00643c81b42932fab1441987628c5a5 (patch)
treeaa851e1fc4828f5a4d94ce0c11fa6d2d1199636f /src
parent7006d5ba2f68c01638a2ab2c98a86b41dcf4467c (diff)
Merged bit-vector and uf proof branch.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am9
-rw-r--r--src/options/bv_options8
-rw-r--r--src/proof/array_proof.h78
-rw-r--r--src/proof/bitvector_proof.cpp602
-rw-r--r--src/proof/bitvector_proof.h142
-rw-r--r--src/proof/cnf_proof.cpp1049
-rw-r--r--src/proof/cnf_proof.h136
-rw-r--r--src/proof/proof.h21
-rw-r--r--src/proof/proof_manager.cpp546
-rw-r--r--src/proof/proof_manager.h196
-rw-r--r--src/proof/proof_utils.cpp127
-rw-r--r--src/proof/proof_utils.h178
-rw-r--r--src/proof/sat_proof.h291
-rw-r--r--src/proof/sat_proof_implementation.h1100
-rw-r--r--src/proof/theory_proof.cpp684
-rw-r--r--src/proof/theory_proof.h282
-rw-r--r--src/proof/uf_proof.cpp804
-rw-r--r--src/proof/uf_proof.h75
-rw-r--r--src/prop/bvminisat/bvminisat.cpp37
-rw-r--r--src/prop/bvminisat/bvminisat.h11
-rw-r--r--src/prop/bvminisat/core/Solver.cc407
-rw-r--r--src/prop/bvminisat/core/Solver.h82
-rw-r--r--src/prop/bvminisat/core/SolverTypes.h27
-rw-r--r--src/prop/bvminisat/simp/SimpSolver.cc20
-rw-r--r--src/prop/bvminisat/simp/SimpSolver.h20
-rw-r--r--src/prop/cnf_stream.cpp212
-rw-r--r--src/prop/cnf_stream.h58
-rw-r--r--src/prop/minisat/core/Solver.cc132
-rw-r--r--src/prop/minisat/core/Solver.h61
-rw-r--r--src/prop/minisat/core/SolverTypes.h37
-rw-r--r--src/prop/minisat/minisat.cpp41
-rw-r--r--src/prop/minisat/minisat.h5
-rw-r--r--src/prop/minisat/simp/SimpSolver.cc12
-rw-r--r--src/prop/minisat/simp/SimpSolver.h30
-rw-r--r--src/prop/prop_engine.cpp9
-rw-r--r--src/prop/sat_solver.h19
-rw-r--r--src/prop/sat_solver_factory.h4
-rw-r--r--src/prop/theory_proxy.cpp3
-rw-r--r--src/smt/smt_engine.cpp27
-rw-r--r--src/smt/smt_engine_check_proof.cpp5
-rw-r--r--src/smt/smt_engine_scope.h3
-rw-r--r--src/smt_util/command.cpp4
-rw-r--r--src/smt_util/command.h1
-rw-r--r--src/theory/arrays/theory_arrays.cpp37
-rw-r--r--src/theory/arrays/theory_arrays.h2
-rw-r--r--src/theory/bv/bitblast_strategies_template.h57
-rw-r--r--src/theory/bv/bitblast_utils.h2
-rw-r--r--src/theory/bv/bitblaster_template.h13
-rw-r--r--src/theory/bv/bv_eager_solver.cpp11
-rw-r--r--src/theory/bv/bv_eager_solver.h5
-rw-r--r--src/theory/bv/bv_subtheory.h3
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.cpp45
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.h7
-rw-r--r--src/theory/bv/eager_bitblaster.cpp52
-rw-r--r--src/theory/bv/lazy_bitblaster.cpp37
-rw-r--r--src/theory/bv/theory_bv.cpp14
-rw-r--r--src/theory/bv/theory_bv.h8
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_core.h3
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h3
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_simplification.h6
-rw-r--r--src/theory/bv/theory_bv_utils.h10
-rw-r--r--src/theory/output_channel.h26
-rw-r--r--src/theory/rewriter.cpp10
-rw-r--r--src/theory/theory.cpp9
-rw-r--r--src/theory/theory.h38
-rw-r--r--src/theory/theory_engine.cpp47
-rw-r--r--src/theory/theory_engine.h23
-rw-r--r--src/theory/theory_test_utils.h7
-rw-r--r--src/theory/uf/equality_engine.cpp78
-rw-r--r--src/theory/uf/equality_engine.h4
-rw-r--r--src/theory/uf/kinds3
-rw-r--r--src/theory/uf/symmetry_breaker.cpp51
-rw-r--r--src/theory/uf/symmetry_breaker.h51
-rw-r--r--src/theory/uf/theory_uf.cpp52
-rw-r--r--src/theory/uf/theory_uf.h10
-rw-r--r--src/theory/uf/theory_uf_type_rules.h8
76 files changed, 6643 insertions, 1684 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index ec6464cdb..c71caea51 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -78,13 +78,20 @@ libcvc4_la_SOURCES = \
printer/tptp/tptp_printer.cpp \
proof/proof.h \
proof/sat_proof.h \
- proof/sat_proof.cpp \
+ proof/sat_proof_implementation.h \
proof/cnf_proof.h \
proof/cnf_proof.cpp \
proof/theory_proof.h \
proof/theory_proof.cpp \
+ proof/uf_proof.h \
+ proof/uf_proof.cpp \
+ proof/array_proof.h \
+ proof/bitvector_proof.h \
+ proof/bitvector_proof.cpp \
proof/proof_manager.h \
proof/proof_manager.cpp \
+ proof/proof_utils.h \
+ proof/proof_utils.cpp \
proof/unsat_core.cpp \
proof/unsat_core.h \
prop/registrar.h \
diff --git a/src/options/bv_options b/src/options/bv_options
index 73790b562..245c56b51 100644
--- a/src/options/bv_options
+++ b/src/options/bv_options
@@ -19,19 +19,19 @@ expert-option bitvectorAigSimplifications --bv-aig-simp=COMMAND std::string :def
# Options for lazy bit-blasting
-option bitvectorPropagate --bv-propagate bool :default true :read-write :link --bitblast=lazy
+option bitvectorPropagate --bv-propagate bool :default true :read-write
use bit-vector propagation in the bit-blaster
-option bitvectorEqualitySolver --bv-eq-solver bool :default true :read-write :link --bitblast=lazy
+option bitvectorEqualitySolver --bv-eq-solver bool :default true :read-write
use the equality engine for the bit-vector theory (only if --bitblast=lazy)
option bitvectorEqualitySlicer --bv-eq-slicer=MODE CVC4::theory::bv::BvSlicerMode :handler CVC4::options::stringToBvSlicerMode :default CVC4::theory::bv::BITVECTOR_SLICER_OFF :read-write :include "options/bv_bitblast_mode.h" :handler-include "options/options_handler_interface.h" :read-write :link --bv-eq-solver
turn on the slicing equality solver for the bit-vector theory (only if --bitblast=lazy)
-option bitvectorInequalitySolver --bv-inequality-solver bool :default true :read-write :link --bitblast=lazy
+option bitvectorInequalitySolver --bv-inequality-solver bool :default true :read-write
turn on the inequality solver for the bit-vector theory (only if --bitblast=lazy)
-option bitvectorAlgebraicSolver --bv-algebraic-solver bool :default true :read-write :link --bitblast=lazy
+option bitvectorAlgebraicSolver --bv-algebraic-solver bool :default true :read-write
turn on the algebraic solver for the bit-vector theory (only if --bitblast=lazy)
expert-option bitvectorAlgebraicBudget --bv-algebraic-budget unsigned :default 1500 :read-write :link --bv-algebraic-solver
diff --git a/src/proof/array_proof.h b/src/proof/array_proof.h
new file mode 100644
index 000000000..beaf5194c
--- /dev/null
+++ b/src/proof/array_proof.h
@@ -0,0 +1,78 @@
+/********************* */
+/*! \file array_proof.h
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Arrray proof
+ **
+ ** Arrau proof
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__ARRAY__PROOF_H
+#define __CVC4__ARRAY__PROOF_H
+
+#include "expr/expr.h"
+#include "proof/proof_manager.h"
+#include "proof/theory_proof.h"
+#include "theory/arrays/theory_arrays.h"
+
+namespace CVC4 {
+
+namespace theory {
+namespace arrays{
+class TheoryArrays;
+} /* namespace CVC4::theory::arrays */
+} /* namespace CVC4::theory */
+
+class ArrayProof : public TheoryProof {
+ // TODO: whatever goes in this theory
+public:
+ ArrayProof(theory::arrays::TheoryArrays* arrays, TheoryProofEngine* proofEngine)
+ : TheoryProof(arrays, proofEngine)
+ {}
+ virtual void registerTerm(Expr term) {}
+
+ virtual void printTerm(Expr term, std::ostream& os, const LetMap& map) = 0;
+ virtual void printSort(Type type, std::ostream& os) = 0;
+ /**
+ * Print a proof for the theory lemma. Must prove
+ * clause representing lemma to be used in resolution proof.
+ *
+ * @param lemma clausal form of lemma
+ * @param os output stream
+ */
+ virtual void printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren) = 0;
+ /**
+ * Print the variable/sorts declarations for this theory.
+ *
+ * @param os
+ * @param paren
+ */
+ virtual void printDeclarations(std::ostream& os, std::ostream& paren) = 0;
+};
+
+class LFSCArrayProof : public ArrayProof {
+public:
+ LFSCArrayProof(theory::arrays::TheoryArrays* uf, TheoryProofEngine* proofEngine)
+ : ArrayProof(uf, proofEngine)
+ {}
+ // TODO implement
+ virtual void printTerm(Expr term, std::ostream& os, const LetMap& map) {}
+ virtual void printSort(Type type, std::ostream& os) {}
+ virtual void printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren) {}
+ virtual void printDeclarations(std::ostream& os, std::ostream& paren) {}
+
+};
+
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__ARRAY__PROOF_H */
diff --git a/src/proof/bitvector_proof.cpp b/src/proof/bitvector_proof.cpp
new file mode 100644
index 000000000..e067f0bce
--- /dev/null
+++ b/src/proof/bitvector_proof.cpp
@@ -0,0 +1,602 @@
+/********************* */
+/*! \file bitvector_proof.cpp
+** \verbatim
+** Original author: Liana Hadarean
+** Major contributors: none
+** Minor contributors (to current version): none
+** This file is part of the CVC4 project.
+** Copyright (c) 2009-2014 New York University and The University of Iowa
+** See the file COPYING in the top-level source directory for licensing
+** information.\endverbatim
+**
+** \brief [[ Add one-line brief description here ]]
+**
+** [[ Add lengthier description here ]]
+** \todo document this file
+**/
+
+
+#include "proof/bitvector_proof.h"
+#include "options/bv_options.h"
+#include "proof/proof_utils.h"
+#include "proof/sat_proof_implementation.h"
+#include "prop/bvminisat/bvminisat.h"
+#include "theory/bv/bitblaster_template.h"
+#include "theory/bv/theory_bv.h"
+
+using namespace CVC4::theory;
+using namespace CVC4::theory::bv;
+
+namespace CVC4 {
+
+BitVectorProof::BitVectorProof(theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine)
+ : TheoryProof(bv, proofEngine)
+ , d_declarations()
+ , d_seenBBTerms()
+ , d_bbTerms()
+ , d_bbAtoms()
+ , d_resolutionProof(NULL)
+ , d_cnfProof(NULL)
+ , d_bitblaster(NULL)
+{}
+
+void BitVectorProof::initSatProof(CVC4::BVMinisat::Solver* solver) {
+ Assert (d_resolutionProof == NULL);
+ d_resolutionProof = new LFSCBVSatProof(solver, "bb", true);
+}
+
+void BitVectorProof::initCnfProof(prop::CnfStream* cnfStream,
+ context::Context* cnf) {
+ Assert (d_cnfProof == NULL);
+ d_cnfProof = new LFSCCnfProof(cnfStream, cnf, "bb");
+ Assert (d_resolutionProof != NULL);
+ d_resolutionProof->setCnfProof(d_cnfProof);
+
+ // true and false have to be setup in a special way
+ Node true_node = NodeManager::currentNM()->mkConst<bool>(true);
+ Node false_node = NodeManager::currentNM()->mkConst<bool>(false).notNode();
+
+ d_cnfProof->pushCurrentAssertion(true_node);
+ d_cnfProof->pushCurrentDefinition(true_node);
+ d_cnfProof->registerConvertedClause(d_resolutionProof->getTrueUnit());
+ d_cnfProof->popCurrentAssertion();
+ d_cnfProof->popCurrentDefinition();
+
+ d_cnfProof->pushCurrentAssertion(false_node);
+ d_cnfProof->pushCurrentDefinition(false_node);
+ d_cnfProof->registerConvertedClause(d_resolutionProof->getFalseUnit());
+ d_cnfProof->popCurrentAssertion();
+ d_cnfProof->popCurrentDefinition();
+}
+
+void BitVectorProof::setBitblaster(bv::TBitblaster<Node>* bb) {
+ Assert (d_bitblaster == NULL);
+ d_bitblaster = bb;
+}
+
+BVSatProof* BitVectorProof::getSatProof() {
+ Assert (d_resolutionProof != NULL);
+ return d_resolutionProof;
+}
+
+void BitVectorProof::registerTermBB(Expr term) {
+ if (d_seenBBTerms.find(term) != d_seenBBTerms.end())
+ return;
+
+ d_seenBBTerms.insert(term);
+ d_bbTerms.push_back(term);
+}
+
+void BitVectorProof::registerAtomBB(Expr atom, Expr atom_bb) {
+ Expr def = atom.iffExpr(atom_bb);
+ d_bbAtoms.insert(std::make_pair(atom, def));
+ registerTerm(atom);
+}
+
+void BitVectorProof::registerTerm(Expr term) {
+ d_usedBB.insert(term);
+
+ if (Theory::isLeafOf(term, theory::THEORY_BV) &&
+ !term.isConst()) {
+ d_declarations.insert(term);
+ }
+
+ // don't care about parametric operators for bv?
+ for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+ d_proofEngine->registerTerm(term[i]);
+ }
+}
+
+std::string BitVectorProof::getBBTermName(Expr expr) {
+ std::ostringstream os;
+ os << "bt"<< expr.getId();
+ return os.str();
+}
+
+void BitVectorProof::startBVConflict(CVC4::BVMinisat::Solver::TCRef cr) {
+ d_resolutionProof->startResChain(cr);
+}
+
+void BitVectorProof::startBVConflict(CVC4::BVMinisat::Solver::TLit lit) {
+ d_resolutionProof->startResChain(lit);
+}
+
+void BitVectorProof::endBVConflict(const CVC4::BVMinisat::Solver::TLitVec& confl) {
+ std::vector<Expr> expr_confl;
+ for (int i = 0; i < confl.size(); ++i) {
+ prop::SatLiteral lit = prop::BVMinisatSatSolver::toSatLiteral(confl[i]);
+ Expr atom = d_cnfProof->getAtom(lit.getSatVariable()).toExpr();
+ Expr expr_lit = lit.isNegated() ? atom.notExpr() : atom;
+ expr_confl.push_back(expr_lit);
+ }
+ Expr conflict = utils::mkSortedExpr(kind::OR, expr_confl);
+ Debug("bv-proof") << "Make conflict for " << conflict << std::endl;
+
+ if (d_bbConflictMap.find(conflict) != d_bbConflictMap.end()) {
+ Debug("bv-proof") << "Abort...already conflict for " << conflict << std::endl;
+ // This can only happen when we have eager explanations in the bv solver
+ // if we don't get to propagate p before ~p is already asserted
+ d_resolutionProof->cancelResChain();
+ return;
+ }
+
+ // we don't need to check for uniqueness in the sat solver then
+ ClauseId clause_id = d_resolutionProof->registerAssumptionConflict(confl);
+ d_bbConflictMap[conflict] = clause_id;
+ d_resolutionProof->endResChain(clause_id);
+ Debug("bv-proof") << "BitVectorProof::endBVConflict id"<<clause_id<< " => " << conflict << "\n";
+ d_isAssumptionConflict = false;
+}
+
+void BitVectorProof::finalizeConflicts(std::vector<Expr>& conflicts) {
+ if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+ Debug("bv-proof") << "Construct full proof." << std::endl;
+ d_resolutionProof->constructProof();
+ return;
+ }
+ for(unsigned i = 0; i < conflicts.size(); ++i) {
+ Expr confl = conflicts[i];
+ Debug("bv-proof") << "Finalize conflict " << confl << std::endl;
+ //Assert (d_bbConflictMap.find(confl) != d_bbConflictMap.end());
+ if(d_bbConflictMap.find(confl) != d_bbConflictMap.end()){
+ ClauseId id = d_bbConflictMap[confl];
+ d_resolutionProof->collectClauses(id);
+ }else{
+ Debug("bv-proof") << "Do not collect clauses for " << confl << std::endl;
+ }
+ }
+}
+
+void LFSCBitVectorProof::printTerm(Expr term, std::ostream& os, const LetMap& map) {
+ Assert (Theory::theoryOf(term) == THEORY_BV);
+
+ // peel off eager bit-blasting trick
+ if (term.getKind() == kind::BITVECTOR_EAGER_ATOM) {
+ d_proofEngine->printBoundTerm(term[0], os, map);
+ return;
+ }
+
+ switch (term.getKind()) {
+ case kind::CONST_BITVECTOR : {
+ printConstant(term, os);
+ return;
+ }
+ case kind::BITVECTOR_AND :
+ case kind::BITVECTOR_OR :
+ case kind::BITVECTOR_XOR :
+ case kind::BITVECTOR_NAND :
+ case kind::BITVECTOR_NOR :
+ case kind::BITVECTOR_XNOR :
+ case kind::BITVECTOR_COMP :
+ case kind::BITVECTOR_MULT :
+ case kind::BITVECTOR_PLUS :
+ case kind::BITVECTOR_SUB :
+ case kind::BITVECTOR_UDIV :
+ case kind::BITVECTOR_UREM :
+ case kind::BITVECTOR_UDIV_TOTAL :
+ case kind::BITVECTOR_UREM_TOTAL :
+ case kind::BITVECTOR_SDIV :
+ case kind::BITVECTOR_SREM :
+ case kind::BITVECTOR_SMOD :
+ case kind::BITVECTOR_SHL :
+ case kind::BITVECTOR_LSHR :
+ case kind::BITVECTOR_ASHR :
+ case kind::BITVECTOR_CONCAT : {
+ printOperatorNary(term, os, map);
+ return;
+ }
+ case kind::BITVECTOR_NEG :
+ case kind::BITVECTOR_NOT :
+ case kind::BITVECTOR_ROTATE_LEFT :
+ case kind::BITVECTOR_ROTATE_RIGHT : {
+ printOperatorUnary(term, os, map);
+ return;
+ }
+ case kind::EQUAL :
+ case kind::BITVECTOR_ULT :
+ case kind::BITVECTOR_ULE :
+ case kind::BITVECTOR_UGT :
+ case kind::BITVECTOR_UGE :
+ case kind::BITVECTOR_SLT :
+ case kind::BITVECTOR_SLE :
+ case kind::BITVECTOR_SGT :
+ case kind::BITVECTOR_SGE : {
+ printPredicate(term, os, map);
+ return;
+ }
+ case kind::BITVECTOR_EXTRACT :
+ case kind::BITVECTOR_REPEAT :
+ case kind::BITVECTOR_ZERO_EXTEND :
+ case kind::BITVECTOR_SIGN_EXTEND : {
+ printOperatorParametric(term, os, map);
+ return;
+ }
+ case kind::BITVECTOR_BITOF : {
+ printBitOf(term, os);
+ return;
+ }
+ case kind::VARIABLE:
+ case kind::SKOLEM: {
+ os << "(a_var_bv " << utils::getSize(term)<<" " << ProofManager::sanitize(term) <<")";
+ return;
+ }
+ default:
+ Unreachable();
+ }
+}
+
+void LFSCBitVectorProof::printBitOf(Expr term, std::ostream& os) {
+ Assert (term.getKind() == kind::BITVECTOR_BITOF);
+ unsigned bit = term.getOperator().getConst<BitVectorBitOf>().bitIndex;
+ Expr var = term[0];
+ Assert (var.getKind() == kind::VARIABLE ||
+ var.getKind() == kind::SKOLEM);
+ os << "(bitof " << ProofManager::sanitize(var) <<" " << bit <<")";
+}
+
+void LFSCBitVectorProof::printConstant(Expr term, std::ostream& os) {
+ Assert (term.isConst());
+ os <<"(a_bv " << utils::getSize(term)<<" ";
+ std::ostringstream paren;
+ int size = utils::getSize(term);
+ for (int i = size - 1; i >= 0; --i) {
+ os << "(bvc ";
+ os << (utils::getBit(term, i) ? "b1" : "b0") <<" ";
+ paren << ")";
+ }
+ os << " bvn)";
+ os << paren.str();
+}
+
+void LFSCBitVectorProof::printOperatorNary(Expr term, std::ostream& os, const LetMap& map) {
+ std::string op = utils::toLFSCKind(term.getKind());
+ std::ostringstream paren;
+ std::string holes = term.getKind() == kind::BITVECTOR_CONCAT ? "_ _ " : "";
+ unsigned size = term.getKind() == kind::BITVECTOR_CONCAT? utils::getSize(term) :
+ utils::getSize(term[0]); // cause of COMP
+
+ for (unsigned i = 0; i < term.getNumChildren() - 1; ++i) {
+ os <<"("<< op <<" " << size <<" " << holes;
+ }
+ d_proofEngine->printBoundTerm(term[0], os, map);
+ os <<" ";
+ for (unsigned i = 1; i < term.getNumChildren(); ++i) {
+ d_proofEngine->printBoundTerm(term[i], os, map);
+ os << ")";
+ }
+}
+
+void LFSCBitVectorProof::printOperatorUnary(Expr term, std::ostream& os, const LetMap& map) {
+ os <<"(";
+ os << utils::toLFSCKind(term.getKind()) << " " << utils::getSize(term) <<" ";
+ os << " ";
+ d_proofEngine->printBoundTerm(term[0], os, map);
+ os <<")";
+}
+
+void LFSCBitVectorProof::printPredicate(Expr term, std::ostream& os, const LetMap& map) {
+ os <<"(";
+ os << utils::toLFSCKind(term.getKind()) << " " << utils::getSize(term[0]) <<" ";
+ os << " ";
+ d_proofEngine->printBoundTerm(term[0], os, map);
+ os << " ";
+ d_proofEngine->printBoundTerm(term[1], os, map);
+ os <<")";
+}
+
+void LFSCBitVectorProof::printOperatorParametric(Expr term, std::ostream& os, const LetMap& map) {
+ os <<"(";
+ os << utils::toLFSCKind(term.getKind()) << " " << utils::getSize(term) <<" ";
+ os <<" ";
+ if (term.getKind() == kind::BITVECTOR_REPEAT) {
+ unsigned amount = term.getOperator().getConst<BitVectorRepeat>().repeatAmount;
+ os << amount <<" _ ";
+ }
+ if (term.getKind() == kind::BITVECTOR_SIGN_EXTEND) {
+ unsigned amount = term.getOperator().getConst<BitVectorSignExtend>().signExtendAmount;
+ os << amount <<" _ ";
+ }
+
+ if (term.getKind() == kind::BITVECTOR_ZERO_EXTEND) {
+ unsigned amount = term.getOperator().getConst<BitVectorZeroExtend>().zeroExtendAmount;
+ os << amount<<" _ ";
+ }
+ if (term.getKind() == kind::BITVECTOR_EXTRACT) {
+ unsigned low = utils::getExtractLow(term);
+ unsigned high = utils::getExtractHigh(term);
+ os << high <<" " << low << " " << utils::getSize(term[0]);
+ }
+ os <<" ";
+ Assert (term.getNumChildren() == 1);
+ d_proofEngine->printBoundTerm(term[0], os, map);
+ os <<")";
+}
+
+void LFSCBitVectorProof::printSort(Type type, std::ostream& os) {
+ Assert (type.isBitVector());
+ unsigned width = utils::getSize(type);
+ os << "(BitVec "<<width<<")";
+}
+
+void LFSCBitVectorProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren) {
+ Expr conflict = utils::mkSortedExpr(kind::OR, lemma);
+ if (d_bbConflictMap.find(conflict) != d_bbConflictMap.end()) {
+ std::ostringstream lemma_paren;
+ for (unsigned i = 0; i < lemma.size(); ++i) {
+ Expr lit = lemma[i];
+
+ if (lit.getKind() == kind::NOT) {
+ os << "(intro_assump_t _ _ _ ";
+ } else {
+ os << "(intro_assump_f _ _ _ ";
+ }
+ lemma_paren <<")";
+ // print corresponding literal in main sat solver
+ ProofManager* pm = ProofManager::currentPM();
+ CnfProof* cnf = pm->getCnfProof();
+ prop::SatLiteral main_lit = cnf->getLiteral(lit);
+ os << pm->getLitName(main_lit);
+ os <<" ";
+ // print corresponding literal in bv sat solver
+ prop::SatVariable bb_var = d_cnfProof->getLiteral(lit).getSatVariable();
+ os << pm->getAtomName(bb_var, "bb");
+ os <<"(\\unit"<<bb_var<<"\n";
+ lemma_paren <<")";
+ }
+ Expr lem = utils::mkOr(lemma);
+ Assert (d_bbConflictMap.find(lem) != d_bbConflictMap.end());
+ ClauseId lemma_id = d_bbConflictMap[lem];
+ d_resolutionProof->printAssumptionsResolution(lemma_id, os, lemma_paren);
+ os <<lemma_paren.str();
+ }else{
+ Debug("bv-proof") << std::endl << "; Print non-bitblast theory conflict " << conflict << std::endl;
+ BitVectorProof::printTheoryLemmaProof( lemma, os, paren );
+ }
+}
+void LFSCBitVectorProof::printDeclarations(std::ostream& os, std::ostream& paren) {
+ ExprSet::const_iterator it = d_declarations.begin();
+ ExprSet::const_iterator end = d_declarations.end();
+ for (; it != end; ++it) {
+ os << "(% " << ProofManager::sanitize(*it) <<" var_bv\n";
+ paren <<")";
+ }
+}
+
+
+void LFSCBitVectorProof::printTermBitblasting(Expr term, std::ostream& os) {
+ // TODO: once we have the operator elimination rules remove those that we
+ // eliminated
+ Assert (term.getType().isBitVector());
+ Kind kind = term.getKind();
+
+ if (Theory::isLeafOf(term, theory::THEORY_BV) &&
+ !term.isConst()) {
+ os << "(bv_bbl_var "<<utils::getSize(term) << " " << ProofManager::sanitize(term) <<" _ )";
+ return;
+ }
+
+ switch(kind) {
+ case kind::CONST_BITVECTOR : {
+ os << "(bv_bbl_const "<< utils::getSize(term) <<" _ ";
+ std::ostringstream paren;
+ int size = utils::getSize(term);
+ for (int i = size - 1; i>= 0; --i) {
+ os << "(bvc ";
+ os << (utils::getBit(term, i) ? "b1" : "b0") <<" ";
+ paren << ")";
+ }
+ os << " bvn)";
+ os << paren.str();
+ return;
+ }
+ case kind::BITVECTOR_AND :
+ case kind::BITVECTOR_OR :
+ case kind::BITVECTOR_XOR :
+ case kind::BITVECTOR_NAND :
+ case kind::BITVECTOR_NOR :
+ case kind::BITVECTOR_XNOR :
+ case kind::BITVECTOR_COMP :
+ case kind::BITVECTOR_MULT :
+ case kind::BITVECTOR_PLUS :
+ case kind::BITVECTOR_SUB :
+ case kind::BITVECTOR_CONCAT : {
+ for (unsigned i =0; i < term.getNumChildren() - 1; ++i) {
+ os <<"(bv_bbl_"<< utils::toLFSCKind(kind);
+ if (kind == kind::BITVECTOR_CONCAT) {
+ os << " " << utils::getSize(term) <<" _ ";
+ }
+ os <<" _ _ _ _ _ _ ";
+ }
+ os << getBBTermName(term[0]) <<" ";
+
+ for (unsigned i = 1; i < term.getNumChildren(); ++i) {
+ os << getBBTermName(term[i]);
+ os << ") ";
+ }
+ return;
+ }
+ case kind::BITVECTOR_NEG :
+ case kind::BITVECTOR_NOT :
+ case kind::BITVECTOR_ROTATE_LEFT :
+ case kind::BITVECTOR_ROTATE_RIGHT : {
+ os <<"(bv_bbl_"<<utils::toLFSCKind(kind);
+ os <<" _ _ _ _ ";
+ os << getBBTermName(term[0]);
+ os <<")";
+ return;
+ }
+ case kind::BITVECTOR_EXTRACT : {
+ os <<"(bv_bbl_"<<utils::toLFSCKind(kind) <<" ";
+ os << utils::getSize(term) << " ";
+ os << utils::getExtractHigh(term) << " ";
+ os << utils::getExtractLow(term) << " ";
+ os << " _ _ _ _ ";
+ os << getBBTermName(term[0]);
+ os <<")";
+ return;
+ }
+ case kind::BITVECTOR_REPEAT :
+ case kind::BITVECTOR_ZERO_EXTEND :
+ case kind::BITVECTOR_SIGN_EXTEND : {
+ os <<"(bv_bbl_"<<utils::toLFSCKind(kind) <<" ";
+ os << utils::getSize(term) <<" ";
+ if (term.getKind() == kind::BITVECTOR_REPEAT) {
+ unsigned amount = term.getOperator().getConst<BitVectorRepeat>().repeatAmount;
+ os << amount;
+ }
+ if (term.getKind() == kind::BITVECTOR_SIGN_EXTEND) {
+ unsigned amount = term.getOperator().getConst<BitVectorSignExtend>().signExtendAmount;
+ os << amount;
+ }
+
+ if (term.getKind() == kind::BITVECTOR_ZERO_EXTEND) {
+ unsigned amount = term.getOperator().getConst<BitVectorZeroExtend>().zeroExtendAmount;
+ os << amount;
+ }
+ os <<" _ _ _ _ ";
+ os << getBBTermName(term[0]);
+ os <<")";
+ return;
+ }
+ case kind::BITVECTOR_UDIV :
+ case kind::BITVECTOR_UREM :
+ case kind::BITVECTOR_UDIV_TOTAL :
+ case kind::BITVECTOR_UREM_TOTAL :
+ case kind::BITVECTOR_SDIV :
+ case kind::BITVECTOR_SREM :
+ case kind::BITVECTOR_SMOD :
+ case kind::BITVECTOR_SHL :
+ case kind::BITVECTOR_LSHR :
+ case kind::BITVECTOR_ASHR : {
+ // these are terms for which bit-blasting is not supported yet
+ std::ostringstream paren;
+ os <<"(trust_bblast_term _ ";
+ paren <<")";
+ d_proofEngine->printLetTerm(term, os);
+ os <<" ";
+ std::vector<Node> bits;
+ d_bitblaster->bbTerm(term, bits);
+
+ for (int i = utils::getSize(term) - 1; i >= 0; --i) {
+ os << "(bbltc ";
+ d_proofEngine->printLetTerm((bits[i]).toExpr(), os);
+ paren << ")";
+ }
+ os << "bbltn" << paren.str();
+ return;
+ }
+
+ default:
+ Unreachable("LFSCBitVectorProof Unknown operator");
+ }
+}
+
+void LFSCBitVectorProof::printAtomBitblasting(Expr atom, std::ostream& os) {
+ Kind kind = atom.getKind();
+ switch(kind) {
+ case kind::BITVECTOR_ULT :
+ case kind::BITVECTOR_ULE :
+ case kind::BITVECTOR_UGT :
+ case kind::BITVECTOR_UGE :
+ case kind::BITVECTOR_SLT :
+ case kind::BITVECTOR_SLE :
+ case kind::BITVECTOR_SGT :
+ case kind::BITVECTOR_SGE :
+ case kind::EQUAL:
+ {
+ os <<"(bv_bbl_" << utils::toLFSCKind(atom.getKind());
+ os << " _ _ _ _ _ _ ";
+ os << getBBTermName(atom[0])<<" " << getBBTermName(atom[1]) <<")";
+ return;
+ }
+ default:
+ Unreachable("LFSCBitVectorProof Unknown atom kind");
+ }
+}
+
+
+void LFSCBitVectorProof::printBitblasting(std::ostream& os, std::ostream& paren) {
+ // bit-blast terms
+ std::vector<Expr>::const_iterator it = d_bbTerms.begin();
+ std::vector<Expr>::const_iterator end = d_bbTerms.end();
+ for (; it != end; ++it) {
+ if (d_usedBB.find(*it) == d_usedBB.end() &&
+ options::bitblastMode() != theory::bv::BITBLAST_MODE_EAGER)
+ continue;
+ os <<"(decl_bblast _ _ _ ";
+ printTermBitblasting(*it, os);
+ os << "(\\ "<< getBBTermName(*it);
+ paren <<"\n))";
+ }
+ // bit-blast atoms
+ ExprToExpr::const_iterator ait = d_bbAtoms.begin();
+ ExprToExpr::const_iterator aend = d_bbAtoms.end();
+ for (; ait != aend; ++ait) {
+ if (d_usedBB.find(ait->first) == d_usedBB.end() &&
+ options::bitblastMode() != theory::bv::BITBLAST_MODE_EAGER)
+ continue;
+
+ os << "(th_let_pf _ ";
+ if (ait->first.getKind() == kind::CONST_BOOLEAN) {
+ bool val = ait->first.getConst<bool>();
+ os << "(iff_symm " << (val ? "true" : "false" ) << ")";
+ } else {
+ printAtomBitblasting(ait->first, os);
+ }
+
+ os <<"(\\ " << ProofManager::getPreprocessedAssertionName(ait->second) <<"\n";
+ paren <<"))";
+ }
+}
+
+void LFSCBitVectorProof::printResolutionProof(std::ostream& os,
+ std::ostream& paren) {
+ // collect the input clauses used
+ IdToSatClause used_lemmas;
+ IdToSatClause used_inputs;
+ d_resolutionProof->collectClausesUsed(used_inputs,
+ used_lemmas);
+ Assert (used_lemmas.empty());
+
+ // print mapping between theory atoms and internal SAT variables
+ os << ";; BB atom mapping\n";
+
+ NodeSet atoms;
+ d_cnfProof->collectAtomsForClauses(used_inputs,atoms);
+
+ // first print bit-blasting
+ printBitblasting(os, paren);
+
+ // print CNF conversion proof for bit-blasted facts
+ d_cnfProof->printAtomMapping(atoms, os, paren);
+ os << ";; Bit-blasting definitional clauses \n";
+ for (IdToSatClause::iterator it = used_inputs.begin();
+ it != used_inputs.end(); ++it) {
+ d_cnfProof->printCnfProofForClause(it->first, it->second, os, paren);
+ }
+
+ os << ";; Bit-blasting learned clauses \n";
+ d_resolutionProof->printResolutions(os, paren);
+}
+
+} /* namespace CVC4 */
diff --git a/src/proof/bitvector_proof.h b/src/proof/bitvector_proof.h
new file mode 100644
index 000000000..80d567f7c
--- /dev/null
+++ b/src/proof/bitvector_proof.h
@@ -0,0 +1,142 @@
+/********************* */
+/*! \file bitvector_proof.h
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Bitvector proof
+ **
+ ** Bitvector proof
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__BITVECTOR__PROOF_H
+#define __CVC4__BITVECTOR__PROOF_H
+
+//#include <cstdint>
+#include <ext/hash_map>
+#include <ext/hash_set>
+#include <iostream>
+#include <set>
+#include <sstream>
+#include <vector>
+
+#include "expr/expr.h"
+#include "proof/theory_proof.h"
+#include "prop/bvminisat/core/Solver.h"
+
+
+namespace CVC4 {
+
+namespace prop {
+class CnfStream;
+} /* namespace CVC4::prop */
+
+namespace theory {
+namespace bv {
+class TheoryBV;
+template <class T> class TBitblaster;
+} /* namespace CVC4::theory::bv */
+} /* namespace CVC4::theory */
+
+class CnfProof;
+} /* namespace CVC4 */
+
+namespace CVC4 {
+
+template <class Solver> class TSatProof;
+typedef TSatProof< CVC4::BVMinisat::Solver> BVSatProof;
+
+template <class Solver> class LFSCSatProof;
+typedef LFSCSatProof< CVC4::BVMinisat::Solver> LFSCBVSatProof;
+
+typedef __gnu_cxx::hash_set<Expr, ExprHashFunction> ExprSet;
+typedef __gnu_cxx::hash_map<Expr, ClauseId, ExprHashFunction> ExprToClauseId;
+typedef __gnu_cxx::hash_map<Expr, unsigned, ExprHashFunction> ExprToId;
+typedef __gnu_cxx::hash_map<Expr, Expr, ExprHashFunction> ExprToExpr;
+
+class BitVectorProof : public TheoryProof {
+protected:
+ ExprSet d_declarations;
+
+ ExprSet d_usedBB; // terms and formulas that are actually relevant to the proof
+
+ ExprSet d_seenBBTerms; // terms that need to be bit-blasted
+ std::vector<Expr> d_bbTerms; // order of bit-blasting
+ ExprToExpr d_bbAtoms; // atoms that need to be bit-blasted
+
+ // map from Expr representing normalized lemma to ClauseId in SAT solver
+ ExprToClauseId d_bbConflictMap;
+ BVSatProof* d_resolutionProof;
+
+ CnfProof* d_cnfProof;
+
+ bool d_isAssumptionConflict;
+ theory::bv::TBitblaster<Node>* d_bitblaster;
+ std::string getBBTermName(Expr expr);
+public:
+ BitVectorProof(theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine);
+
+ void initSatProof(CVC4::BVMinisat::Solver* solver);
+ void initCnfProof(prop::CnfStream* cnfStream, context::Context* ctx);
+ void setBitblaster(theory::bv::TBitblaster<Node>* bb);
+
+ BVSatProof* getSatProof();
+ CnfProof* getCnfProof() {return d_cnfProof; }
+ void finalizeConflicts(std::vector<Expr>& conflicts);
+
+ void startBVConflict(CVC4::BVMinisat::Solver::TCRef cr);
+ void startBVConflict(CVC4::BVMinisat::Solver::TLit lit);
+ /**
+ * All the
+ *
+ * @param confl an inconsistent set of bv literals
+ */
+ void endBVConflict(const BVMinisat::Solver::TLitVec& confl);
+ void markAssumptionConflict() { d_isAssumptionConflict = true; }
+ bool isAssumptionConflict() { return d_isAssumptionConflict; }
+
+ void registerTermBB(Expr term);
+ void registerAtomBB(Expr atom, Expr atom_bb);
+
+ virtual void registerTerm(Expr term);
+
+ virtual void printTermBitblasting(Expr term, std::ostream& os) = 0;
+ virtual void printAtomBitblasting(Expr term, std::ostream& os) = 0;
+
+ virtual void printBitblasting(std::ostream& os, std::ostream& paren) = 0;
+ virtual void printResolutionProof(std::ostream& os, std::ostream& paren) = 0;
+
+};
+
+class LFSCBitVectorProof: public BitVectorProof {
+
+ void printConstant(Expr term, std::ostream& os);
+ void printOperatorNary(Expr term, std::ostream& os, const LetMap& map);
+ void printOperatorUnary(Expr term, std::ostream& os, const LetMap& map);
+ void printPredicate(Expr term, std::ostream& os, const LetMap& map);
+ void printOperatorParametric(Expr term, std::ostream& os, const LetMap& map);
+ void printBitOf(Expr term, std::ostream& os);
+public:
+ LFSCBitVectorProof(theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine)
+ :BitVectorProof(bv, proofEngine)
+ {}
+ virtual void printTerm(Expr term, std::ostream& os, const LetMap& map);
+ virtual void printSort(Type type, std::ostream& os);
+ virtual void printTermBitblasting(Expr term, std::ostream& os);
+ virtual void printAtomBitblasting(Expr term, std::ostream& os);
+ virtual void printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren);
+ virtual void printDeclarations(std::ostream& os, std::ostream& paren);
+ virtual void printBitblasting(std::ostream& os, std::ostream& paren);
+ virtual void printResolutionProof(std::ostream& os, std::ostream& paren);
+};
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__BITVECTOR__PROOF_H */
diff --git a/src/proof/cnf_proof.cpp b/src/proof/cnf_proof.cpp
index 263e1fe8c..884a67856 100644
--- a/src/proof/cnf_proof.cpp
+++ b/src/proof/cnf_proof.cpp
@@ -26,518 +26,709 @@ using namespace CVC4::prop;
namespace CVC4 {
-CnfProof::CnfProof(CnfStream* stream)
+CnfProof::CnfProof(CnfStream* stream,
+ context::Context* ctx,
+ const std::string& name)
: d_cnfStream(stream)
-{}
+ , d_clauseToAssertion(ctx)
+ , d_assertionToProofRule(ctx)
+ , d_currentAssertionStack()
+ , d_currentDefinitionStack()
+ , d_clauseToDefinition(ctx)
+ , d_definitions()
+ , d_cnfDeps()
+ , d_name(name)
+{
+ // Setting the proof object for the CnfStream
+ d_cnfStream->setProof(this);
+}
+
+CnfProof::~CnfProof() {}
-CnfProof::~CnfProof() {
+bool CnfProof::isAssertion(Node node) {
+ return d_assertionToProofRule.find(node) !=
+ d_assertionToProofRule.end();
}
-Expr CnfProof::getAtom(prop::SatVariable var) {
- prop::SatLiteral lit (var);
- Node node = d_cnfStream->getNode(lit);
- Expr atom = node.toExpr();
- return atom;
+bool CnfProof::isDefinition(Node node) {
+ return d_definitions.find(node) !=
+ d_definitions.end();
+}
+
+ProofRule CnfProof::getProofRule(Node node) {
+ Assert (isAssertion(node));
+ NodeToProofRule::iterator it = d_assertionToProofRule.find(node);
+ return (*it).second;
+}
+ProofRule CnfProof::getProofRule(ClauseId clause) {
+ TNode assertion = getAssertionForClause(clause);
+ return getProofRule(assertion);
}
-prop::SatLiteral CnfProof::getLiteral(TNode atom) {
- return d_cnfStream->getLiteral(atom);
+Node CnfProof::getAssertionForClause(ClauseId clause) {
+ ClauseIdToNode::const_iterator it = d_clauseToAssertion.find(clause);
+ Assert (it != d_clauseToAssertion.end());
+ return (*it).second;
}
-Expr CnfProof::getAssertion(uint64_t id) {
- return d_cnfStream->getAssertion(id).toExpr();
+Node CnfProof::getDefinitionForClause(ClauseId clause) {
+ ClauseIdToNode::const_iterator it = d_clauseToDefinition.find(clause);
+ Assert (it != d_clauseToDefinition.end());
+ return (*it).second;
}
-void LFSCCnfProof::printAtomMapping(const prop::SatClause* clause, std::ostream& os, std::ostream& paren) {
- for (unsigned i = 0; i < clause->size(); ++i) {
- prop::SatLiteral lit = clause->operator[](i);
- if(d_atomsDeclared.find(lit.getSatVariable()) == d_atomsDeclared.end()) {
- d_atomsDeclared.insert(lit.getSatVariable());
- os << "(decl_atom ";
- if (ProofManager::currentPM()->getLogic().compare("QF_UF") == 0 ||
- ProofManager::currentPM()->getLogic().compare("QF_AX") == 0 ||
- ProofManager::currentPM()->getLogic().compare("QF_SAT") == 0) {
- Expr atom = getAtom(lit.getSatVariable());
- LFSCTheoryProof::printTerm(atom, os);
- } else {
- // print fake atoms for all other logics (for now)
- os << "true ";
- }
+void CnfProof::registerConvertedClause(ClauseId clause, bool explanation) {
+ Assert (clause != ClauseIdUndef &&
+ clause != ClauseIdError &&
+ clause != ClauseIdEmpty);
+
+ // Explanations do not need a CNF conversion proof since they are in CNF
+ // (they will only need a theory proof as they are theory valid)
+ if (explanation) {
+ Debug("proof:cnf") << "CnfProof::registerConvertedClause "
+ << clause << " explanation? " << explanation << std::endl;
+ Assert (d_explanations.find(clause) == d_explanations.end());
+ d_explanations.insert(clause);
+ return;
+ }
- os << " (\\ " << ProofManager::getVarName(lit.getSatVariable()) << " (\\ " << ProofManager::getAtomName(lit.getSatVariable()) << "\n";
- paren << ")))";
- }
+ Node current_assertion = getCurrentAssertion();
+ Node current_expr = getCurrentDefinition();
+
+ Debug("proof:cnf") << "CnfProof::registerConvertedClause "
+ << clause << " assertion = " << current_assertion
+ << clause << " definition = " << current_expr << std::endl;
+
+ setClauseAssertion(clause, current_assertion);
+ setClauseDefinition(clause, current_expr);
+}
+
+void CnfProof::setClauseAssertion(ClauseId clause, Node expr) {
+ Debug("proof:cnf") << "CnfProof::setClauseAssertion "
+ << clause << " assertion " << expr << std::endl;
+ // We can add the same clause from different assertions. In this
+ // case we keep the first assertion. For example asserting a /\ b
+ // and then b /\ c where b is an atom, would assert b twice (note
+ // that since b is top level, it is not cached by the CnfStream)
+ if (d_clauseToAssertion.find(clause) != d_clauseToAssertion.end())
+ return;
+
+ d_clauseToAssertion.insert (clause, expr);
+}
+
+void CnfProof::setClauseDefinition(ClauseId clause, Node definition) {
+ Debug("proof:cnf") << "CnfProof::setClauseDefinition "
+ << clause << " definition " << definition << std::endl;
+ // We keep the first definition
+ if (d_clauseToDefinition.find(clause) != d_clauseToDefinition.end())
+ return;
+
+ d_clauseToDefinition.insert(clause, definition);
+ d_definitions.insert(definition);
+}
+
+void CnfProof::registerAssertion(Node assertion, ProofRule reason) {
+ Debug("proof:cnf") << "CnfProof::registerAssertion "
+ << assertion << " reason " << reason << std::endl;
+ // We can obtain the assertion from different reasons (e.g. if the
+ // assertion is a lemma over shared terms both theories can generate
+ // the same lemma) We only need to prove the lemma in one way, so we
+ // keep the first reason.
+ if (isAssertion(assertion)) {
+ return;
}
+ d_assertionToProofRule.insert(assertion, reason);
}
-void LFSCCnfProof::printClauses(std::ostream& os, std::ostream& paren) {
- printPreprocess(os, paren);
- printInputClauses(os, paren);
- printTheoryLemmas(os, paren);
+void CnfProof::setCnfDependence(Node from, Node to) {
+ Debug("proof:cnf") << "CnfProof::setCnfDependence "
+ << "from " << from << std::endl
+ << " to " << to << std::endl;
+
+ Assert (from != to);
+ d_cnfDeps.insert(std::make_pair(from, to));
}
-void LFSCCnfProof::printPreprocess(std::ostream& os, std::ostream& paren) {
- os << " ;; Preprocessing \n";
- __gnu_cxx::hash_map< Node, std::vector<Node>, NodeHashFunction >::const_iterator it = ProofManager::currentPM()->begin_deps();
- __gnu_cxx::hash_map< Node, std::vector<Node>, NodeHashFunction >::const_iterator end = ProofManager::currentPM()->end_deps();
+void CnfProof::pushCurrentAssertion(Node assertion) {
+ Debug("proof:cnf") << "CnfProof::pushCurrentAssertion "
+ << assertion << std::endl;
- for (; it != end; ++it) {
- if( !it->second.empty() ){
- Expr e = it->first.toExpr();
- os << "(th_let_pf _ ";
+ d_currentAssertionStack.push_back(assertion);
+}
- //TODO
- Trace("cnf-pf-debug") << "; preprocess assertion : " << e << std::endl;
- os << "(trust_f ";
- LFSCTheoryProof::printTerm(e, os);
- os << ") ";
+void CnfProof::popCurrentAssertion() {
+ Assert (d_currentAssertionStack.size());
+
+ Debug("proof:cnf") << "CnfProof::popCurrentAssertion "
+ << d_currentAssertionStack.back() << std::endl;
+
+ d_currentAssertionStack.pop_back();
+}
- os << "(\\ A" << ProofManager::currentPM()->getAssertionCounter() << std::endl;
- ProofManager::currentPM()->setAssertion( e );
- paren << "))";
+Node CnfProof::getCurrentAssertion() {
+ Assert (d_currentAssertionStack.size());
+ return d_currentAssertionStack.back();
+}
+
+void CnfProof::pushCurrentDefinition(Node definition) {
+ Debug("proof:cnf") << "CnfProof::pushCurrentDefinition "
+ << definition << std::endl;
+
+ d_currentDefinitionStack.push_back(definition);
+}
+
+void CnfProof::popCurrentDefinition() {
+ Assert (d_currentDefinitionStack.size());
+
+ Debug("proof:cnf") << "CnfProof::popCurrentDefinition "
+ << d_currentDefinitionStack.back() << std::endl;
+
+ d_currentDefinitionStack.pop_back();
+}
+
+Node CnfProof::getCurrentDefinition() {
+ Assert (d_currentDefinitionStack.size());
+ return d_currentDefinitionStack.back();
+}
+
+
+Node CnfProof::getAtom(prop::SatVariable var) {
+ prop::SatLiteral lit (var);
+ Node node = d_cnfStream->getNode(lit);
+ return node;
+}
+
+
+void CnfProof::collectAtoms(const prop::SatClause* clause,
+ NodeSet& atoms) {
+ for (unsigned i = 0; i < clause->size(); ++i) {
+ SatLiteral lit = clause->operator[](i);
+ SatVariable var = lit.getSatVariable();
+ TNode atom = getAtom(var);
+ if (atoms.find(atom) == atoms.end()) {
+ Assert (atoms.find(atom) == atoms.end());
+ atoms.insert(atom);
+ }
+ }
+}
+
+prop::SatLiteral CnfProof::getLiteral(TNode atom) {
+ return d_cnfStream->getLiteral(atom);
+}
+
+void CnfProof::collectAtomsForClauses(const IdToSatClause& clauses,
+ NodeSet& atom_map) {
+ IdToSatClause::const_iterator it = clauses.begin();
+ for (; it != clauses.end(); ++it) {
+ const prop::SatClause* clause = it->second;
+ collectAtoms(clause, atom_map);
+ }
+
+}
+
+void CnfProof::collectAssertionsForClauses(const IdToSatClause& clauses,
+ NodeSet& assertions) {
+ IdToSatClause::const_iterator it = clauses.begin();
+ for (; it != clauses.end(); ++it) {
+ TNode used_assertion = getAssertionForClause(it->first);
+ assertions.insert(used_assertion);
+ // it can be the case that a definition for a clause is an assertion
+ // but it is not the assertion for the clause
+ // e.g. the assertions [(and a b), a]
+ TNode used_definition = getDefinitionForClause(it->first);
+ if (isAssertion(used_definition)) {
+ assertions.insert(used_definition);
}
}
}
-Expr LFSCCnfProof::clauseToExpr( const prop::SatClause& clause,
- std::map< Expr, unsigned >& childIndex,
- std::map< Expr, bool >& childPol ) {
+void LFSCCnfProof::printAtomMapping(const NodeSet& atoms,
+ std::ostream& os,
+ std::ostream& paren) {
+ NodeSet::const_iterator it = atoms.begin();
+ NodeSet::const_iterator end = atoms.end();
+
+ for (;it != end; ++it) {
+ os << "(decl_atom ";
+ Node atom = *it;
+ prop::SatVariable var = getLiteral(atom).getSatVariable();
+ //FIXME hideous
+ LFSCTheoryProofEngine* pe = (LFSCTheoryProofEngine*)ProofManager::currentPM()->getTheoryProofEngine();
+ pe->printLetTerm(atom.toExpr(), os);
+
+ os << " (\\ " << ProofManager::getVarName(var, d_name)
+ << " (\\ " << ProofManager::getAtomName(var, d_name) << "\n";
+ paren << ")))";
+ }
+}
+
+// maps each expr to the position it had in the clause and the polarity it had
+Node LFSCCnfProof::clauseToNode(const prop::SatClause& clause,
+ std::map<Node, unsigned>& childIndex,
+ std::map<Node, bool>& childPol ) {
std::vector< Node > children;
for (unsigned i = 0; i < clause.size(); ++i) {
prop::SatLiteral lit = clause[i];
prop::SatVariable var = lit.getSatVariable();
- Node atom = Node::fromExpr( getAtom(var) );
+ Node atom = getAtom(var);
children.push_back( lit.isNegated() ? atom.negate() : atom );
- childIndex[atom.toExpr()] = i;
- childPol[atom.toExpr()] = !lit.isNegated();
+ childIndex[atom] = i;
+ childPol[atom] = !lit.isNegated();
}
- return children.size()==1 ? children[0].toExpr() : NodeManager::currentNM()->mkNode( kind::OR, children ).toExpr();
+ return children.size()==1 ? children[0] :
+ NodeManager::currentNM()->mkNode(kind::OR, children );
}
-void LFSCCnfProof::printInputClauses(std::ostream& os, std::ostream& paren) {
- os << " ;; Clauses\n";
- ProofManager::clause_iterator it = ProofManager::currentPM()->begin_input_clauses();
- ProofManager::clause_iterator end = ProofManager::currentPM()->end_input_clauses();
-
-
- for (; it != end; ++it) {
- ClauseId id = it->first;
- const prop::SatClause* clause = it->second;
- printAtomMapping(clause, os, paren);
- os << "(satlem _ _ ";
- std::ostringstream clause_paren;
- printClause(*clause, os, clause_paren);
- os << "(clausify_false ";
-
- Assert( clause->size()>0 );
-
- Expr base_assertion = ProofManager::currentPM()->getFormulaForClauseId( id );
- ProofRule pr = ProofManager::currentPM()->getProofRuleForClauseId( id );
- Trace("cnf-pf") << std::endl;
- Trace("cnf-pf") << "; formula for clause id " << id << " : " << base_assertion << std::endl;
-
- //get the assertion for the clause id
- std::map< Expr, unsigned > childIndex;
- std::map< Expr, bool > childPol;
- Expr assertion = clauseToExpr( *clause, childIndex, childPol );
- //if there is no reason, construct assertion directly. This can happen for unit clauses.
- if( base_assertion.isNull() ){
- base_assertion = assertion;
- }
- //os_base is proof of base_assertion
- std::stringstream os_base;
- bool is_input = ProofManager::currentPM()->isInputAssertion( base_assertion, os_base );
-
- //get base assertion with polarity
- bool base_pol = base_assertion.getKind()!=kind::NOT;
- base_assertion = base_assertion.getKind()==kind::NOT ? base_assertion[0] : base_assertion;
-
- std::map< Expr, unsigned >::iterator itci = childIndex.find( base_assertion );
- bool is_in_clause = itci!=childIndex.end();
- unsigned base_index = is_in_clause ? itci->second : 0;
- Trace("cnf-pf") << "; input = " << is_input << ", is_in_clause = " << is_in_clause << ", id = " << id << ", assertion = " << assertion << ", base assertion = " << base_assertion << std::endl;
- if( !is_input ){
- Assert( is_in_clause );
- prop::SatLiteral blit = (*clause)[ base_index ];
- os_base << ProofManager::getLitName(blit);
- base_pol = !childPol[base_assertion];
+void LFSCCnfProof::printCnfProofForClause(ClauseId id,
+ const prop::SatClause* clause,
+ std::ostream& os,
+ std::ostream& paren) {
+ os << "(satlem _ _ ";
+ std::ostringstream clause_paren;
+ printClause(*clause, os, clause_paren);
+ os << "(clausify_false ";
+
+ // FIXMEEEEEEEEEEEE
+ // os <<"trust)";
+ // os << clause_paren.str()
+ // << " (\\ " << ProofManager::getInputClauseName(id, d_name) << "\n";
+ // paren << "))";
+
+ // return;
+
+ Assert( clause->size()>0 );
+
+ Node base_assertion = getDefinitionForClause(id);
+
+ //get the assertion for the clause id
+ std::map<Node, unsigned > childIndex;
+ std::map<Node, bool > childPol;
+ Node assertion = clauseToNode( *clause, childIndex, childPol );
+ //if there is no reason, construct assertion directly. This can happen for unit clauses.
+ if( base_assertion.isNull() ){
+ base_assertion = assertion;
+ }
+ //os_base is proof of base_assertion
+ std::stringstream os_base;
+
+ // checks if tautological definitional clause or top-level clause
+ // and prints the proof of the top-level formula
+ bool is_input = printProofTopLevel(base_assertion, os_base);
+
+ //get base assertion with polarity
+ bool base_pol = base_assertion.getKind()!=kind::NOT;
+ base_assertion = base_assertion.getKind()==kind::NOT ? base_assertion[0] : base_assertion;
+
+ std::map< Node, unsigned >::iterator itci = childIndex.find( base_assertion );
+ bool is_in_clause = itci!=childIndex.end();
+ unsigned base_index = is_in_clause ? itci->second : 0;
+ Trace("cnf-pf") << std::endl;
+ Trace("cnf-pf") << "; input = " << is_input << ", is_in_clause = " << is_in_clause << ", id = " << id << ", assertion = " << assertion << ", base assertion = " << base_assertion << std::endl;
+ if (!is_input){
+ Assert(is_in_clause);
+ prop::SatLiteral blit = (*clause)[ base_index ];
+ os_base << ProofManager::getLitName(blit, d_name);
+ base_pol = !childPol[base_assertion]; // WHY? if the case is =>
+ }
+ Trace("cnf-pf") << "; polarity of base assertion = " << base_pol << std::endl;
+ Trace("cnf-pf") << "; proof of base : " << os_base.str() << std::endl;
+
+ bool success = false;
+ if( is_input &&
+ is_in_clause &&
+ childPol[base_assertion]==base_pol ){
+ //if both in input and in clause, the proof is trivial. this is the case for unit clauses.
+ Trace("cnf-pf") << "; trivial" << std::endl;
+ os << "(contra _ ";
+ success = true;
+ prop::SatLiteral lit = (*clause)[itci->second];
+ if( base_pol ){
+ os << os_base.str() << " " << ProofManager::getLitName(lit, d_name);
+ }else{
+ os << ProofManager::getLitName(lit, d_name) << " " << os_base.str();
}
- Trace("cnf-pf") << "; polarity of base assertion = " << base_pol << std::endl;
- Trace("cnf-pf") << "; proof of base : " << os_base.str() << std::endl;
-
- bool success = false;
- if( is_input && is_in_clause && childPol[base_assertion]==base_pol ){
- //if both in input and in clause, the proof is trivial. this is the case for unit clauses.
- Trace("cnf-pf") << "; trivial" << std::endl;
- os << "(contra _ ";
- success = true;
- prop::SatLiteral lit = (*clause)[itci->second];
- if( base_pol ){
- os << os_base.str() << " " << ProofManager::getLitName(lit);
- }else{
- os << ProofManager::getLitName(lit) << " " << os_base.str();
+ os << ")";
+ } else if ((base_assertion.getKind()==kind::AND && !base_pol) ||
+ ((base_assertion.getKind()==kind::OR ||
+ base_assertion.getKind()==kind::IMPLIES) && base_pol)) {
+ Trace("cnf-pf") << "; and/or case 1" << std::endl;
+ success = true;
+ std::stringstream os_main;
+ std::stringstream os_paren;
+ //eliminate each one
+ for (int j = base_assertion.getNumChildren()-2; j >= 0; j--) {
+ Node child_base = base_assertion[j].getKind()==kind::NOT ?
+ base_assertion[j][0] : base_assertion[j];
+ bool child_pol = base_assertion[j].getKind()!=kind::NOT;
+
+ if( j==0 && base_assertion.getKind()==kind::IMPLIES ){
+ child_pol = !child_pol;
}
- os << ")";
- }else if( ( base_assertion.getKind()==kind::AND && !base_pol ) || ( ( base_assertion.getKind()==kind::OR || base_assertion.getKind()==kind::IMPLIES ) && base_pol ) ){
- Trace("cnf-pf") << "; and/or case 1" << std::endl;
- success = true;
- std::stringstream os_main;
- std::stringstream os_paren;
- //eliminate each one
- for( int j=base_assertion.getNumChildren()-2; j>=0; j-- ){
- Expr child_base = base_assertion[j].getKind()==kind::NOT ? base_assertion[j][0] : base_assertion[j];
- bool child_pol = base_assertion[j].getKind()!=kind::NOT;
- if( j==0 && base_assertion.getKind()==kind::IMPLIES ){
- child_pol = !child_pol;
+
+ Trace("cnf-pf-debug") << "; child " << j << " "
+ << child_base << " "
+ << child_pol << " "
+ << childPol[child_base] << std::endl;
+
+ std::map< Node, unsigned >::iterator itcic = childIndex.find( child_base );
+
+ if( itcic!=childIndex.end() ){
+ //Assert( child_pol==childPol[child_base] );
+ os_main << "(or_elim_1 _ _ ";
+ prop::SatLiteral lit = (*clause)[itcic->second];
+ // Should be if in the original formula it was negated
+ if( childPol[child_base] && base_pol ){
+ os_main << ProofManager::getLitName(lit, d_name) << " ";
+ }else{
+ os_main << "(not_not_intro _ " << ProofManager::getLitName(lit, d_name) << ") ";
}
- Trace("cnf-pf-debug") << "; child " << j << " " << child_base << " " << child_pol << " " << childPol[child_base] << std::endl;
- std::map< Expr, unsigned >::iterator itcic = childIndex.find( child_base );
- if( itcic!=childIndex.end() ){
- //Assert( child_pol==childPol[child_base] );
- os_main << "(or_elim_1 _ _ ";
- prop::SatLiteral lit = (*clause)[itcic->second];
- if( childPol[child_base] && base_pol ){
- os_main << ProofManager::getLitName(lit) << " ";
- }else{
- os_main << "(not_not_intro _ " << ProofManager::getLitName(lit) << ") ";
- }
- if( base_assertion.getKind()==kind::AND ){
- os_main << "(not_and_elim _ _ ";
- os_paren << ")";
- }
+ if( base_assertion.getKind()==kind::AND ){
+ os_main << "(not_and_elim _ _ ";
os_paren << ")";
- }else{
- success = false;
}
+ os_paren << ")";
+ }else{
+ success = false;
}
- if( success ){
- if( base_assertion.getKind()==kind::IMPLIES ){
- os_main << "(impl_elim _ _ ";
- }
- os_main << os_base.str();
- if( base_assertion.getKind()==kind::IMPLIES ){
- os_main << ")";
- }
- os_main << os_paren.str();
- int last_index = base_assertion.getNumChildren()-1;
- Expr child_base = base_assertion[last_index].getKind()==kind::NOT ? base_assertion[last_index][0] : base_assertion[last_index];
- //bool child_pol = base_assertion[last_index].getKind()!=kind::NOT;
- std::map< Expr, unsigned >::iterator itcic = childIndex.find( child_base );
- if( itcic!=childIndex.end() ){
- os << "(contra _ ";
- prop::SatLiteral lit = (*clause)[itcic->second];
- if( childPol[child_base] && base_pol ){
- os << os_main.str() << " " << ProofManager::getLitName(lit);
- }else{
- os << ProofManager::getLitName(lit) << " " << os_main.str();
- }
- os << ")";
- }else{
- success = false;
- }
+ }
+ if( success ){
+ if( base_assertion.getKind()==kind::IMPLIES ){
+ os_main << "(impl_elim _ _ ";
}
- }else if( ( base_assertion.getKind()==kind::AND && base_pol ) || ( ( base_assertion.getKind()==kind::OR || base_assertion.getKind()==kind::IMPLIES ) && !base_pol ) ){
- std::stringstream os_main;
- Expr iatom;
- if( is_in_clause ){
- Assert( assertion.getNumChildren()==2 );
- iatom = assertion[ base_index==0 ? 1 : 0];
- }else{
- Assert( assertion.getNumChildren()==1 );
- iatom = assertion[0];
+ os_main << os_base.str();
+ if( base_assertion.getKind()==kind::IMPLIES ){
+ os_main << ")";
}
- Trace("cnf-pf") << "; and/or case 2, iatom = " << iatom << std::endl;
- Expr e_base = iatom.getKind()==kind::NOT ? iatom[0] : iatom;
- bool e_pol = iatom.getKind()!=kind::NOT;
- std::map< Expr, unsigned >::iterator itcic = childIndex.find( e_base );
+ os_main << os_paren.str();
+ int last_index = base_assertion.getNumChildren()-1;
+ Node child_base = base_assertion[last_index].getKind()==kind::NOT ? base_assertion[last_index][0] : base_assertion[last_index];
+ //bool child_pol = base_assertion[last_index].getKind()!=kind::NOT;
+ std::map< Node, unsigned >::iterator itcic = childIndex.find( child_base );
if( itcic!=childIndex.end() ){
+ os << "(contra _ ";
prop::SatLiteral lit = (*clause)[itcic->second];
- //eliminate until we find iatom
- for( unsigned j=0; j<base_assertion.getNumChildren(); j++ ){
- Expr child_base = base_assertion[j].getKind()==kind::NOT ? base_assertion[j][0] : base_assertion[j];
- bool child_pol = base_assertion[j].getKind()!=kind::NOT;
- if( j==0 && base_assertion.getKind()==kind::IMPLIES ){
- child_pol = !child_pol;
+ if( childPol[child_base] && base_pol){
+ os << os_main.str() << " " << ProofManager::getLitName(lit, d_name);
+ }else{
+ os << ProofManager::getLitName(lit, d_name) << " " << os_main.str();
+ }
+ os << ")";
+ }else{
+ success = false;
+ }
+ }
+ }else if ((base_assertion.getKind()==kind::AND && base_pol) ||
+ ((base_assertion.getKind()==kind::OR ||
+ base_assertion.getKind()==kind::IMPLIES) && !base_pol)) {
+
+ std::stringstream os_main;
+
+ Node iatom;
+ if (is_in_clause) {
+ Assert( assertion.getNumChildren()==2 );
+ iatom = assertion[ base_index==0 ? 1 : 0];
+ } else {
+ Assert( assertion.getNumChildren()==1 );
+ iatom = assertion[0];
+ }
+
+ Trace("cnf-pf") << "; and/or case 2, iatom = " << iatom << std::endl;
+ Node e_base = iatom.getKind()==kind::NOT ? iatom[0] : iatom;
+ bool e_pol = iatom.getKind()!=kind::NOT;
+ std::map< Node, unsigned >::iterator itcic = childIndex.find( e_base );
+ if( itcic!=childIndex.end() ){
+ prop::SatLiteral lit = (*clause)[itcic->second];
+ //eliminate until we find iatom
+ for( unsigned j=0; j<base_assertion.getNumChildren(); j++ ){
+ Node child_base = base_assertion[j].getKind()==kind::NOT ? base_assertion[j][0] : base_assertion[j];
+ bool child_pol = base_assertion[j].getKind()!=kind::NOT;
+ if( j==0 && base_assertion.getKind()==kind::IMPLIES ){
+ child_pol = !child_pol;
+ }
+ if( e_base==child_base && (e_pol==child_pol)==(base_assertion.getKind()==kind::AND) ){
+ success = true;
+ bool elimNn =( ( base_assertion.getKind()==kind::OR || ( base_assertion.getKind()==kind::IMPLIES && j==1 ) ) && e_pol );
+ if( elimNn ){
+ os_main << "(not_not_elim _ ";
}
- if( e_base==child_base && (e_pol==child_pol)==(base_assertion.getKind()==kind::AND) ){
- success = true;
- bool elimNn =( ( base_assertion.getKind()==kind::OR || ( base_assertion.getKind()==kind::IMPLIES && j==1 ) ) && e_pol );
- if( elimNn ){
- os_main << "(not_not_elim _ ";
- }
- std::stringstream os_paren;
- if( j+1<base_assertion.getNumChildren() ){
- os_main << "(and_elim_1 _ _ ";
- if( base_assertion.getKind()==kind::OR || base_assertion.getKind()==kind::IMPLIES ){
- os_main << "(not_" << ( base_assertion.getKind()==kind::OR ? "or" : "impl" ) << "_elim _ _ ";
- os_paren << ")";
- }
+ std::stringstream os_paren;
+ if( j+1<base_assertion.getNumChildren() ){
+ os_main << "(and_elim_1 _ _ ";
+ if( base_assertion.getKind()==kind::OR || base_assertion.getKind()==kind::IMPLIES ){
+ os_main << "(not_" << ( base_assertion.getKind()==kind::OR ? "or" : "impl" ) << "_elim _ _ ";
os_paren << ")";
}
- for( unsigned k=0; k<j; k++ ){
- os_main << "(and_elim_2 _ _ ";
- if( base_assertion.getKind()==kind::OR || base_assertion.getKind()==kind::IMPLIES ){
- os_main << "(not_" << ( base_assertion.getKind()==kind::OR ? "or" : "impl" ) << "_elim _ _ ";
- os_paren << ")";
- }
+ os_paren << ")";
+ }
+ for( unsigned k=0; k<j; k++ ){
+ os_main << "(and_elim_2 _ _ ";
+ if( base_assertion.getKind()==kind::OR || base_assertion.getKind()==kind::IMPLIES ){
+ os_main << "(not_" << ( base_assertion.getKind()==kind::OR ? "or" : "impl" ) << "_elim _ _ ";
os_paren << ")";
}
- os_main << os_base.str() << os_paren.str();
- if( elimNn ){
- os_main << ")";
- }
- break;
+ os_paren << ")";
}
- }
- if( success ){
- os << "(contra _ ";
- if( !e_pol ){
- os << ProofManager::getLitName(lit) << " " << os_main.str();
- }else{
- os << os_main.str() << " " << ProofManager::getLitName(lit);
+ os_main << os_base.str() << os_paren.str();
+ if( elimNn ){
+ os_main << ")";
}
- os << ")";
- }
- }
- }else if( base_assertion.getKind()==kind::XOR || base_assertion.getKind()==kind::IFF ){
- //eliminate negation
- int num_nots_2 = 0;
- int num_nots_1 = 0;
- Kind k;
- if( !base_pol ){
- if( base_assertion.getKind()==kind::IFF ){
- num_nots_2 = 1;
- }
- k = kind::IFF;
- }else{
- k = base_assertion.getKind();
- }
- std::vector< unsigned > indices;
- std::vector< bool > pols;
- success = true;
- int elimNum = 0;
- for( unsigned i=0; i<2; i++ ){
- Expr child_base = base_assertion[i].getKind()==kind::NOT ? base_assertion[i][0] : base_assertion[i];
- bool child_pol = base_assertion[i].getKind()!=kind::NOT;
- std::map< Expr, unsigned >::iterator itcic = childIndex.find( child_base );
- if( itcic!=childIndex.end() ){
- indices.push_back( itcic->second );
- pols.push_back( childPol[child_base] );
- if( i==0 ){
- //figure out which way to elim
- elimNum = child_pol==childPol[child_base] ? 2 : 1;
- if( (elimNum==2)==(k==kind::IFF) ){
- num_nots_2++;
- }
- if( elimNum==1 ){
- num_nots_1++;
- }
- }
- }else{
- success = false;
break;
}
}
- Trace("cnf-pf") << std::endl << "; num nots = " << num_nots_2 << std::endl;
if( success ){
os << "(contra _ ";
- std::stringstream os_base_n;
- if( num_nots_2==2 ){
- os_base_n << "(not_not_elim _ ";
- }
- os_base_n << "(or_elim_1 _ _ ";
- prop::SatLiteral lit1 = (*clause)[indices[0]];
- if( !pols[0] || num_nots_1==1 ){
- os_base_n << "(not_not_intro _ " << ProofManager::getLitName(lit1) << ") ";
- }else{
- os_base_n << ProofManager::getLitName(lit1) << " ";
- }
- Assert( elimNum!=0 );
- os_base_n << "(" << ( k==kind::IFF ? "iff" : "xor" ) << "_elim_" << elimNum << " _ _ ";
- if( !base_pol ){
- os_base_n << "(not_" << ( base_assertion.getKind()==kind::IFF ? "iff" : "xor" ) << "_elim _ _ " << os_base.str() << ")";
- }else{
- os_base_n << os_base.str();
- }
- os_base_n << "))";
- if( num_nots_2==2 ){
- os_base_n << ")";
- num_nots_2 = 0;
- }
- prop::SatLiteral lit2 = (*clause)[indices[1]];
- if( pols[1]==(num_nots_2==0) ){
- os << os_base_n.str() << " ";
- if( num_nots_2==1 ){
- os << "(not_not_intro _ " << ProofManager::getLitName(lit2) << ")";
- }else{
- os << ProofManager::getLitName(lit2);
- }
+ if( !e_pol ){
+ os << ProofManager::getLitName(lit, d_name) << " " << os_main.str();
}else{
- os << ProofManager::getLitName(lit2) << " " << os_base_n.str();
+ os << os_main.str() << " " << ProofManager::getLitName(lit, d_name);
}
os << ")";
}
- }else if( base_assertion.getKind()==kind::ITE ){
- std::map< unsigned, unsigned > appears;
- std::map< unsigned, Expr > appears_expr;
- unsigned appears_count = 0;
- for( unsigned r=0; r<3; r++ ){
- Expr child_base = base_assertion[r].getKind()==kind::NOT ? base_assertion[r][0] : base_assertion[r];
- std::map< Expr, unsigned >::iterator itcic = childIndex.find( child_base );
- if( itcic!=childIndex.end() ){
- appears[r] = itcic->second;
- appears_expr[r] = child_base;
- appears_count++;
- }
+ }
+ }else if( base_assertion.getKind()==kind::XOR || base_assertion.getKind()==kind::IFF ){
+ //eliminate negation
+ int num_nots_2 = 0;
+ int num_nots_1 = 0;
+ Kind k;
+ if( !base_pol ){
+ if( base_assertion.getKind()==kind::IFF ){
+ num_nots_2 = 1;
}
- if( appears_count==2 ){
- success = true;
- int elimNum = 1;
- unsigned index1 = 0;
- unsigned index2 = 1;
- if( appears.find( 0 )==appears.end() ){
- elimNum = 3;
- index1 = 1;
- index2 = 2;
- }else if( appears.find( 1 )==appears.end() ){
- elimNum = 2;
- index1 = 0;
- index2 = 2;
- }
- std::stringstream os_main;
- os_main << "(or_elim_1 _ _ ";
- prop::SatLiteral lit1 = (*clause)[appears[index1]];
- if( !childPol[appears_expr[index1]] || elimNum==1 || ( elimNum==3 && !base_pol ) ){
- os_main << "(not_not_intro _ " << ProofManager::getLitName(lit1) << ") ";
- }else{
- os_main << ProofManager::getLitName(lit1) << " ";
- }
- os_main << "(" << ( base_pol ? "" : "not_" ) << "ite_elim_" << elimNum << " _ _ _ ";
- os_main << os_base.str() << "))";
- os << "(contra _ ";
- prop::SatLiteral lit2 = (*clause)[appears[index2]];
- if( !childPol[appears_expr[index2]] || !base_pol ){
- os << ProofManager::getLitName(lit2) << " " << os_main.str();
- }else{
- os << os_main.str() << " " << ProofManager::getLitName(lit2);
+ k = kind::IFF;
+ }else{
+ k = base_assertion.getKind();
+ }
+ std::vector< unsigned > indices;
+ std::vector< bool > pols;
+ success = true;
+ int elimNum = 0;
+ for( unsigned i=0; i<2; i++ ){
+ Node child_base = base_assertion[i].getKind()==kind::NOT ? base_assertion[i][0] : base_assertion[i];
+ bool child_pol = base_assertion[i].getKind()!=kind::NOT;
+ std::map< Node, unsigned >::iterator itcic = childIndex.find( child_base );
+ if( itcic!=childIndex.end() ){
+ indices.push_back( itcic->second );
+ pols.push_back( childPol[child_base] );
+ if( i==0 ){
+ //figure out which way to elim
+ elimNum = child_pol==childPol[child_base] ? 2 : 1;
+ if( (elimNum==2)==(k==kind::IFF) ){
+ num_nots_2++;
+ }
+ if( elimNum==1 ){
+ num_nots_1++;
+ }
}
- os << ")";
+ }else{
+ success = false;
+ break;
+ }
+ }
+ Trace("cnf-pf") << std::endl << "; num nots = " << num_nots_2 << std::endl;
+ if( success ){
+ os << "(contra _ ";
+ std::stringstream os_base_n;
+ if( num_nots_2==2 ){
+ os_base_n << "(not_not_elim _ ";
+ }
+ os_base_n << "(or_elim_1 _ _ ";
+ prop::SatLiteral lit1 = (*clause)[indices[0]];
+ if( !pols[0] || num_nots_1==1 ){
+ os_base_n << "(not_not_intro _ " << ProofManager::getLitName(lit1, d_name) << ") ";
+ }else{
+ os_base_n << ProofManager::getLitName(lit1, d_name) << " ";
}
- }else if( base_assertion.isConst() ){
- bool pol = base_assertion==NodeManager::currentNM()->mkConst( true ).toExpr();
- if( pol!=base_pol ){
- success = true;
- if( pol ){
- os << "(contra _ truth " << os_base.str() << ")";
+ Assert( elimNum!=0 );
+ os_base_n << "(" << ( k==kind::IFF ? "iff" : "xor" ) << "_elim_" << elimNum << " _ _ ";
+ if( !base_pol ){
+ os_base_n << "(not_" << ( base_assertion.getKind()==kind::IFF ? "iff" : "xor" ) << "_elim _ _ " << os_base.str() << ")";
+ }else{
+ os_base_n << os_base.str();
+ }
+ os_base_n << "))";
+ if( num_nots_2==2 ){
+ os_base_n << ")";
+ num_nots_2 = 0;
+ }
+ prop::SatLiteral lit2 = (*clause)[indices[1]];
+ if( pols[1]==(num_nots_2==0) ){
+ os << os_base_n.str() << " ";
+ if( num_nots_2==1 ){
+ os << "(not_not_intro _ " << ProofManager::getLitName(lit2, d_name) << ")";
}else{
- os << os_base.str();
+ os << ProofManager::getLitName(lit2, d_name);
}
+ }else{
+ os << ProofManager::getLitName(lit2, d_name) << " " << os_base_n.str();
}
+ os << ")";
}
-
- if( !success ){
- Trace("cnf-pf") << std::endl;
- Trace("cnf-pf") << ";!!!!!!!!! CnfProof : Can't process " << assertion << ", base = " << base_assertion << ", id = " << id << ", proof rule = " << pr << std::endl;
- Trace("cnf-pf") << ";!!!!!!!!! Clause is : ";
- for (unsigned i = 0; i < clause->size(); ++i) {
- Trace("cnf-pf") << (*clause)[i] << " ";
+ }else if( base_assertion.getKind()==kind::ITE ){
+ std::map< unsigned, unsigned > appears;
+ std::map< unsigned, Node > appears_expr;
+ unsigned appears_count = 0;
+ for( unsigned r=0; r<3; r++ ){
+ Node child_base = base_assertion[r].getKind()==kind::NOT ? base_assertion[r][0] : base_assertion[r];
+ std::map< Node, unsigned >::iterator itcic = childIndex.find( child_base );
+ if( itcic!=childIndex.end() ){
+ appears[r] = itcic->second;
+ appears_expr[r] = child_base;
+ appears_count++;
}
- Trace("cnf-pf") << std::endl;
- os << "trust-bad";
- }
-
- os << ")" << clause_paren.str()
- << " (\\ " << ProofManager::getInputClauseName(id) << "\n";
- paren << "))";
- }
-}
-
-void LFSCCnfProof::printTheoryLemmas(std::ostream& os, std::ostream& paren) {
- os << " ;; Theory Lemmas\n";
- ProofManager::ordered_clause_iterator it = ProofManager::currentPM()->begin_lemmas();
- ProofManager::ordered_clause_iterator end = ProofManager::currentPM()->end_lemmas();
-
- for(size_t n = 0; it != end; ++it, ++n) {
- if(n % 100 == 0) {
- Chat() << "proving theory conflicts...(" << n << "/" << ProofManager::currentPM()->num_lemmas() << ")" << std::endl;
}
-
- ClauseId id = it->first;
- const prop::SatClause* clause = it->second;
- NodeBuilder<> c(kind::AND);
- for(unsigned i = 0; i < clause->size(); ++i) {
- prop::SatLiteral lit = (*clause)[i];
- prop::SatVariable var = lit.getSatVariable();
- if(lit.isNegated()) {
- c << Node::fromExpr(getAtom(var));
- } else {
- c << Node::fromExpr(getAtom(var)).notNode();
+ if( appears_count==2 ){
+ success = true;
+ int elimNum = 1;
+ unsigned index1 = 0;
+ unsigned index2 = 1;
+ if( appears.find( 0 )==appears.end() ){
+ elimNum = 3;
+ index1 = 1;
+ index2 = 2;
+ }else if( appears.find( 1 )==appears.end() ){
+ elimNum = 2;
+ index1 = 0;
+ index2 = 2;
}
- }
- Node cl = c;
- if(ProofManager::getSatProof()->d_lemmaClauses.find(id) != ProofManager::getSatProof()->d_lemmaClauses.end()) {
- uint64_t proof_id = ProofManager::getSatProof()->d_lemmaClauses[id];
- TNode orig = d_cnfStream->getAssertion(proof_id & 0xffffffff);
- if(((proof_id >> 32) & 0xffffffff) == RULE_ARRAYS_EXT) {
- Debug("cores") << "; extensional lemma!" << std::endl;
- Assert(cl.getKind() == kind::AND && cl.getNumChildren() == 2 && cl[0].getKind() == kind::EQUAL && cl[0][0].getKind() == kind::SELECT);
- TNode myk = cl[0][0][1];
- Debug("cores") << "; so my skolemized k is " << myk << std::endl;
- os << "(ext _ _ " << orig[0][0] << " " << orig[0][1] << " (\\ " << myk << " (\\ " << ProofManager::getLemmaName(id) << "\n";
- paren << ")))";
+ std::stringstream os_main;
+ os_main << "(or_elim_1 _ _ ";
+ prop::SatLiteral lit1 = (*clause)[appears[index1]];
+ if( !childPol[appears_expr[index1]] || elimNum==1 || ( elimNum==3 && !base_pol ) ){
+ os_main << "(not_not_intro _ " << ProofManager::getLitName(lit1, d_name) << ") ";
+ }else{
+ os_main << ProofManager::getLitName(lit1, d_name) << " ";
+ }
+ os_main << "(" << ( base_pol ? "" : "not_" ) << "ite_elim_" << elimNum << " _ _ _ ";
+ os_main << os_base.str() << "))";
+ os << "(contra _ ";
+ prop::SatLiteral lit2 = (*clause)[appears[index2]];
+ if( !childPol[appears_expr[index2]] || !base_pol ){
+ os << ProofManager::getLitName(lit2, d_name) << " " << os_main.str();
+ }else{
+ os << os_main.str() << " " << ProofManager::getLitName(lit2, d_name);
}
+ os << ")";
}
- printAtomMapping(clause, os, paren);
- os << "(satlem _ _ ";
- std::ostringstream clause_paren;
- printClause(*clause, os, clause_paren);
-
- Debug("cores") << "\n;id is " << id << std::endl;
- if(ProofManager::getSatProof()->d_lemmaClauses.find(id) != ProofManager::getSatProof()->d_lemmaClauses.end()) {
- uint64_t proof_id = ProofManager::getSatProof()->d_lemmaClauses[id];
- Debug("cores") << ";getting id " << int32_t(proof_id & 0xffffffff) << std::endl;
- Assert(int32_t(proof_id & 0xffffffff) != -1);
- TNode orig = d_cnfStream->getAssertion(proof_id & 0xffffffff);
- Debug("cores") << "; ID is " << id << " and that's a lemma with " << ((proof_id >> 32) & 0xffffffff) << " / " << (proof_id & 0xffffffff) << std::endl;
- Debug("cores") << "; that means the lemma was " << orig << std::endl;
- if(((proof_id >> 32) & 0xffffffff) == RULE_ARRAYS_EXT) {
- Debug("cores") << "; extensional" << std::endl;
- os << "(clausify_false trust)\n";
- } else if(proof_id == 0) {
- // theory propagation caused conflict
- //ProofManager::currentPM()->printProof(os, cl);
- os << "(clausify_false trust)\n";
- } else if(((proof_id >> 32) & 0xffffffff) == RULE_CONFLICT) {
- os << "\n;; need to generate a (conflict) proof of " << cl << "\n";
- //ProofManager::currentPM()->printProof(os, cl);
- os << "(clausify_false trust)\n";
- } else {
- os << "\n;; need to generate a (lemma) proof of " << cl;
- os << "\n;; DON'T KNOW HOW !!\n";
- os << "(clausify_false trust)\n";
+ }else if( base_assertion.isConst() ){
+ bool pol = base_assertion==NodeManager::currentNM()->mkConst( true );
+ if( pol!=base_pol ){
+ success = true;
+ if( pol ){
+ os << "(contra _ truth " << os_base.str() << ")";
+ }else{
+ os << os_base.str();
}
- } else {
- os << "\n;; need to generate a (conflict) proof of " << cl << "\n";
- ProofManager::currentPM()->printProof(os, cl);
}
- os << clause_paren.str()
- << " (\\ " << ProofManager::getLemmaClauseName(id) << "\n";
- paren << "))";
}
+
+ if( !success ){
+ Trace("cnf-pf") << std::endl;
+ Trace("cnf-pf") << ";!!!!!!!!! CnfProof : Can't process " << assertion << ", base = " << base_assertion << ", id = " << id << std::endl;
+ Trace("cnf-pf") << ";!!!!!!!!! Clause is : ";
+ for (unsigned i = 0; i < clause->size(); ++i) {
+ Trace("cnf-pf") << (*clause)[i] << " ";
+ }
+ Trace("cnf-pf") << std::endl;
+ os << "trust-bad";
+ }
+
+ os << ")" << clause_paren.str()
+ << " (\\ " << ProofManager::getInputClauseName(id, d_name) << "\n";
+ paren << "))";
}
-void LFSCCnfProof::printClause(const prop::SatClause& clause, std::ostream& os, std::ostream& paren) {
+void LFSCCnfProof::printClause(const prop::SatClause& clause,
+ std::ostream& os,
+ std::ostream& paren) {
for (unsigned i = 0; i < clause.size(); ++i) {
prop::SatLiteral lit = clause[i];
prop::SatVariable var = lit.getSatVariable();
if (lit.isNegated()) {
- os << "(ast _ _ _ " << ProofManager::getAtomName(var) << " (\\ " << ProofManager::getLitName(lit) << " ";
+ os << "(ast _ _ _ " << ProofManager::getAtomName(var, d_name) <<" (\\ " << ProofManager::getLitName(lit, d_name) << " ";
paren << "))";
} else {
- os << "(asf _ _ _ " << ProofManager::getAtomName(var) << " (\\ " << ProofManager::getLitName(lit) << " ";
+ os << "(asf _ _ _ " << ProofManager::getAtomName(var, d_name) <<" (\\ " << ProofManager::getLitName(lit, d_name) << " ";
paren << "))";
}
}
}
+// print a proof of the top-level formula e, based on the input assertions
+bool LFSCCnfProof::printProofTopLevel(Node e, std::ostream& out) {
+ if (!isAssertion(e)) {
+ // check if deduced by CNF
+ // dependence on top level fact i.e. a depends on (a and b)
+ NodeToNode::const_iterator itd = d_cnfDeps.find(e);
+ if (itd != d_cnfDeps.end()) {
+ TNode parent = itd->second;
+ //check if parent is an input assertion
+ std::stringstream out_parent;
+ if (printProofTopLevel(parent, out_parent)) {
+ if(parent.getKind()==kind::AND ||
+ (parent.getKind()==kind::NOT && (parent[0].getKind()==kind::IMPLIES ||
+ parent[0].getKind()==kind::OR))) {
+ Node parent_base = parent.getKind()==kind::NOT ? parent[0] : parent;
+ Node e_base = e.getKind()==kind::NOT ? e[0] : e;
+ bool e_pol = e.getKind()!=kind::NOT;
+ for( unsigned i=0; i<parent_base.getNumChildren(); i++ ){
+ Node child_base = parent_base[i].getKind()==kind::NOT ? parent_base[i][0] : parent_base[i];
+ bool child_pol = parent_base[i].getKind()!=kind::NOT;
+ if( parent_base.getKind()==kind::IMPLIES && i==0 ){
+ child_pol = !child_pol;
+ }
+ if (e_base==child_base &&
+ (e_pol==child_pol)==(parent_base.getKind()==kind::AND)) {
+ bool elimNn = ((parent_base.getKind()==kind::OR ||
+ (parent_base.getKind()==kind::IMPLIES && i==1)) && e_pol);
+ if (elimNn) {
+ out << "(not_not_elim _ ";
+ }
+ std::stringstream out_paren;
+ if (i+1 < parent_base.getNumChildren()) {
+ out << "(and_elim_1 _ _ ";
+ if( parent_base.getKind()==kind::OR ||
+ parent_base.getKind()==kind::IMPLIES ){
+ out << "(not_" << ( parent_base.getKind()==kind::OR ? "or" : "impl" )
+ << "_elim _ _ ";
+ out_paren << ")";
+ }
+ out_paren << ")";
+ }
+ for( unsigned j=0; j<i; j++ ){
+ out << "(and_elim_2 _ _ ";
+ if( parent_base.getKind()==kind::OR || parent_base.getKind()==kind::IMPLIES ){
+ out << "(not_" << ( parent_base.getKind()==kind::OR ? "or" : "impl" ) << "_elim _ _ ";
+ out_paren << ")";
+ }
+ out_paren << ")";
+ }
+ out << out_parent.str();
+ out << out_paren.str();
+ if( elimNn ){
+ out << ")";
+ }
+ return true;
+ }
+ }
+ } else {
+ Trace("cnf-pf-debug") << "; isInputAssertion : parent of " << e
+ << " is not correct type (" << parent << ")" << std::endl;
+ }
+ } else {
+ Trace("cnf-pf-debug") << "; isInputAssertion : parent of " << e
+ << " is not input" << std::endl;
+ }
+ } else {
+ Trace("cnf-pf-debug") << "; isInputAssertion : " << e
+ << " has no parent" << std::endl;
+ }
+ return false;
+ } else {
+ out << ProofManager::getPreprocessedAssertionName(e);
+ return true;
+ }
+}
+
+
+
} /* CVC4 namespace */
diff --git a/src/proof/cnf_proof.h b/src/proof/cnf_proof.h
index d3e59ef93..675bd9b9d 100644
--- a/src/proof/cnf_proof.h
+++ b/src/proof/cnf_proof.h
@@ -21,11 +21,14 @@
#ifndef __CVC4__CNF_PROOF_H
#define __CVC4__CNF_PROOF_H
-#include <ext/hash_map>
+#include <ext/hash_map>
#include <ext/hash_set>
#include <iosfwd>
+#include "context/cdhashmap.h"
#include "proof/sat_proof.h"
+#include "proof/sat_proof.h"
+#include "util/proof.h"
#include "util/proof.h"
namespace CVC4 {
@@ -35,38 +38,131 @@ namespace prop {
class CnfProof;
+typedef __gnu_cxx::hash_map<prop::SatVariable, Expr> SatVarToExpr;
+typedef __gnu_cxx::hash_map<Node, Node, NodeHashFunction> NodeToNode;
+typedef __gnu_cxx::hash_set<ClauseId> ClauseIdSet;
+
+typedef context::CDHashMap<ClauseId, Node> ClauseIdToNode;
+typedef context::CDHashMap<Node, ProofRule, NodeHashFunction> NodeToProofRule;
+
class CnfProof {
protected:
CVC4::prop::CnfStream* d_cnfStream;
- VarSet d_atomsDeclared;
+
+ /** Map from ClauseId to the assertion that lead to adding this clause **/
+ ClauseIdToNode d_clauseToAssertion;
+
+ /** Map from assertion to reason for adding assertion **/
+ NodeToProofRule d_assertionToProofRule;
+
+ /** Top of stack is assertion currently being converted to CNF **/
+ std::vector<Node> d_currentAssertionStack;
+
+ /** Top of stack is top-level fact currently being converted to CNF **/
+ std::vector<Node> d_currentDefinitionStack;
+
+
+ /** Map from ClauseId to the top-level fact that lead to adding this clause **/
+ ClauseIdToNode d_clauseToDefinition;
+
+ /** Top-level facts that follow from assertions during convertAndAssert **/
+ NodeSet d_definitions;
+
+ /** Map from top-level fact to facts/assertion that it follows from **/
+ NodeToNode d_cnfDeps;
+
+ ClauseIdSet d_explanations;
+
+ bool isDefinition(Node node);
+
+ Node getDefinitionForClause(ClauseId clause);
+
+ std::string d_name;
public:
- CnfProof(CVC4::prop::CnfStream* cnfStream);
+ CnfProof(CVC4::prop::CnfStream* cnfStream,
+ context::Context* ctx,
+ const std::string& name);
+
+
+ Node getAtom(prop::SatVariable var);
+ prop::SatLiteral getLiteral(TNode node);
+ void collectAtoms(const prop::SatClause* clause,
+ NodeSet& atoms);
+ void collectAtomsForClauses(const IdToSatClause& clauses,
+ NodeSet& atoms);
+ void collectAssertionsForClauses(const IdToSatClause& clauses,
+ NodeSet& assertions);
+
+ /** Methods for logging what the CnfStream does **/
+ // map the clause back to the current assertion where it came from
+ // if it is an explanation, it does not have a CNF proof since it is
+ // already in CNF
+ void registerConvertedClause(ClauseId clause, bool explanation=false);
+
+ /** Clause is one of the clauses defining the node expression*/
+ void setClauseDefinition(ClauseId clause, Node node);
+
+ /** Clause is one of the clauses defining top-level assertion node*/
+ void setClauseAssertion(ClauseId clause, Node node);
+
+ void registerAssertion(Node assertion, ProofRule reason);
+ void setCnfDependence(Node from, Node to);
+
+ void pushCurrentAssertion(Node assertion); // the current assertion being converted
+ void popCurrentAssertion();
+ Node getCurrentAssertion();
+
+ void pushCurrentDefinition(Node assertion); // the current Tseitin definition being converted
+ void popCurrentDefinition();
+ Node getCurrentDefinition();
+
+
+ // accessors for the leaf assertions that are being converted to CNF
+ bool isAssertion(Node node);
+ ProofRule getProofRule(Node assertion);
+ ProofRule getProofRule(ClauseId clause);
+ Node getAssertionForClause(ClauseId clause);
- Expr getAtom(prop::SatVariable var);
- Expr getAssertion(uint64_t id);
- prop::SatLiteral getLiteral(TNode atom);
+
+ /** Virtual methods for printing things **/
+ virtual void printAtomMapping(const NodeSet& atoms,
+ std::ostream& os,
+ std::ostream& paren) = 0;
- virtual void printClauses(std::ostream& os, std::ostream& paren) = 0;
+ virtual void printClause(const prop::SatClause& clause,
+ std::ostream& os,
+ std::ostream& paren) = 0;
+ virtual void printCnfProofForClause(ClauseId id,
+ const prop::SatClause* clause,
+ std::ostream& os,
+ std::ostream& paren) = 0;
virtual ~CnfProof();
};/* class CnfProof */
class LFSCCnfProof : public CnfProof {
- void printPreprocess(std::ostream& os, std::ostream& paren);
- void printInputClauses(std::ostream& os, std::ostream& paren);
- void printTheoryLemmas(std::ostream& os, std::ostream& paren);
- void printClause(const prop::SatClause& clause, std::ostream& os, std::ostream& paren);
- virtual void printAtomMapping(const prop::SatClause* clause, std::ostream& os, std::ostream& paren);
-
- Expr clauseToExpr( const prop::SatClause& clause,
- std::map< Expr, unsigned >& childIndex,
- std::map< Expr, bool >& childPol );
-
+ Node clauseToNode( const prop::SatClause& clause,
+ std::map<Node, unsigned>& childIndex,
+ std::map<Node, bool>& childPol );
+ bool printProofTopLevel(Node e, std::ostream& out);
public:
- LFSCCnfProof(CVC4::prop::CnfStream* cnfStream)
- : CnfProof(cnfStream)
+ LFSCCnfProof(CVC4::prop::CnfStream* cnfStream,
+ context::Context* ctx,
+ const std::string& name)
+ : CnfProof(cnfStream, ctx, name)
{}
+ ~LFSCCnfProof() {}
- virtual void printClauses(std::ostream& os, std::ostream& paren);
+ void printAtomMapping(const NodeSet& atoms,
+ std::ostream& os,
+ std::ostream& paren);
+
+ void printClause(const prop::SatClause& clause,
+ std::ostream& os,
+ std::ostream& paren);
+ void printCnfProofForClause(ClauseId id,
+ const prop::SatClause* clause,
+ std::ostream& os,
+ std::ostream& paren);
};/* class LFSCCnfProof */
} /* CVC4 namespace */
diff --git a/src/proof/proof.h b/src/proof/proof.h
index ae4c940a0..d69cd6198 100644
--- a/src/proof/proof.h
+++ b/src/proof/proof.h
@@ -9,9 +9,9 @@
** See the file COPYING in the top-level source directory for licensing
** information.\endverbatim
**
- ** \brief Proof manager
+ ** \brief Proof macros
**
- ** Proof manager
+ ** Proof macros
**/
#include "cvc4_private.h"
@@ -46,14 +46,25 @@
*/
#ifdef CVC4_PROOF
-# define PROOF(x) if(options::proof() || options::unsatCores()) { x; }
-# define NULLPROOF(x) (options::proof() || options::unsatCores()) ? x : NULL
-# define PROOF_ON() (options::proof() || options::unsatCores())
+# define PROOF(x) if(CVC4::options::proof() || CVC4::options::unsatCores()) { x; }
+# define NULLPROOF(x) (CVC4::options::proof() || CVC4::options::unsatCores()) ? x : NULL
+# define PROOF_ON() (CVC4::options::proof() || CVC4::options::unsatCores())
+# define THEORY_PROOF(x) if(CVC4::options::proof()) { x; }
+# define THEORY_NULLPROOF(x) CVC4::options::proof() ? x : NULL
+# define THEORY_PROOF_ON() CVC4::options::proof()
#else /* CVC4_PROOF */
# define PROOF(x)
# define NULLPROOF(x) NULL
# define PROOF_ON() false
+# define THEORY_PROOF(x)
+# define THEORY_NULLPROOF(x) NULL
+# define THEORY_PROOF_ON() false
#endif /* CVC4_PROOF */
+#ifdef CVC4_PROOF_STATS /* CVC4_PROOF_STATS */
+# define PSTATS(x) { x; }
+#else
+# define PSTATS(x)
+#endif /* CVC4_PROOF_STATS */
#endif /* __CVC4__PROOF__PROOF_H */
diff --git a/src/proof/proof_manager.cpp b/src/proof/proof_manager.cpp
index 88d380c4f..0ae020090 100644
--- a/src/proof/proof_manager.cpp
+++ b/src/proof/proof_manager.cpp
@@ -15,13 +15,20 @@
** \todo document this file
**/
-#include "proof/proof_manager.h"
-
-#include "base/cvc4_assert.h"
#include "context/context.h"
+
+#include "proof/proof_manager.h"
#include "proof/cnf_proof.h"
-#include "proof/sat_proof.h"
#include "proof/theory_proof.h"
+#include "proof/bitvector_proof.h"
+#include "proof/proof_utils.h"
+#include "proof/sat_proof_implementation.h"
+#include "options/bv_options.h"
+
+#include "util/proof.h"
+#include "util/hash.h"
+
+#include "base/cvc4_assert.h"
#include "smt/smt_engine.h"
#include "smt/smt_engine_scope.h"
#include "smt_util/node_visitor.h"
@@ -31,8 +38,7 @@
#include "theory/uf/equality_engine.h"
#include "theory/uf/theory_uf.h"
#include "theory/valuation.h"
-#include "util/hash.h"
-#include "util/proof.h"
+
namespace CVC4 {
@@ -46,17 +52,13 @@ ProofManager::ProofManager(ProofFormat format):
d_satProof(NULL),
d_cnfProof(NULL),
d_theoryProof(NULL),
- d_inputClauses(),
- d_theoryLemmas(),
- d_theoryPropagations(),
d_inputFormulas(),
d_inputCoreFormulas(),
d_outputCoreFormulas(),
d_nextId(0),
d_fullProof(NULL),
d_format(format),
- d_deps(),
- d_assertion_counter(1)
+ d_deps()
{
}
@@ -65,21 +67,6 @@ ProofManager::~ProofManager() {
delete d_cnfProof;
delete d_theoryProof;
delete d_fullProof;
-
- for(IdToClause::iterator it = d_inputClauses.begin();
- it != d_inputClauses.end();
- ++it) {
- delete it->second;
- }
-
- for(OrderedIdToClause::iterator it = d_theoryLemmas.begin();
- it != d_theoryLemmas.end();
- ++it) {
- delete it->second;
- }
-
- // FIXME: memory leak because there are deleted theory lemmas that
- // were not used in the SatProof
}
ProofManager* ProofManager::currentPM() {
@@ -93,13 +80,13 @@ Proof* ProofManager::getProof(SmtEngine* smt) {
Assert (currentPM()->d_format == LFSC);
currentPM()->d_fullProof = new LFSCProof(smt,
- (LFSCSatProof*)getSatProof(),
+ (LFSCCoreSatProof*)getSatProof(),
(LFSCCnfProof*)getCnfProof(),
- (LFSCTheoryProof*)getTheoryProof());
+ (LFSCTheoryProofEngine*)getTheoryProofEngine());
return currentPM()->d_fullProof;
}
-SatProof* ProofManager::getSatProof() {
+CoreSatProof* ProofManager::getSatProof() {
Assert (currentPM()->d_satProof);
return currentPM()->d_satProof;
}
@@ -109,48 +96,135 @@ CnfProof* ProofManager::getCnfProof() {
return currentPM()->d_cnfProof;
}
-TheoryProof* ProofManager::getTheoryProof() {
- //Assert (currentPM()->d_theoryProof);
+TheoryProofEngine* ProofManager::getTheoryProofEngine() {
+ Assert (options::proof());
+ Assert (currentPM()->d_theoryProof != NULL);
return currentPM()->d_theoryProof;
}
+UFProof* ProofManager::getUfProof() {
+ Assert (options::proof());
+ TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_UF);
+ return (UFProof*)pf;
+}
+BitVectorProof* ProofManager::getBitVectorProof() {
+ Assert (options::proof());
+ TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_BV);
+ return (BitVectorProof*)pf;
+}
+
+ArrayProof* ProofManager::getArrayProof() {
+ Assert (options::proof());
+ TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_ARRAY);
+ return (ArrayProof*)pf;
+}
+
void ProofManager::initSatProof(Minisat::Solver* solver) {
Assert (currentPM()->d_satProof == NULL);
Assert(currentPM()->d_format == LFSC);
- currentPM()->d_satProof = new LFSCSatProof(solver);
+ currentPM()->d_satProof = new LFSCCoreSatProof(solver, "");
}
-void ProofManager::initCnfProof(prop::CnfStream* cnfStream) {
- Assert (currentPM()->d_cnfProof == NULL);
- Assert (currentPM()->d_format == LFSC);
- currentPM()->d_cnfProof = new LFSCCnfProof(cnfStream);
+void ProofManager::initCnfProof(prop::CnfStream* cnfStream,
+ context::Context* ctx) {
+ ProofManager* pm = currentPM();
+ Assert (pm->d_cnfProof == NULL);
+ Assert (pm->d_format == LFSC);
+ CnfProof* cnf = new LFSCCnfProof(cnfStream, ctx, "");
+ pm->d_cnfProof = cnf;
+ Assert(pm-> d_satProof != NULL);
+ pm->d_satProof->setCnfProof(cnf);
+
+ // true and false have to be setup in a special way
+ Node true_node = NodeManager::currentNM()->mkConst<bool>(true);
+ Node false_node = NodeManager::currentNM()->mkConst<bool>(false).notNode();
+
+ pm->d_cnfProof->pushCurrentAssertion(true_node);
+ pm->d_cnfProof->pushCurrentDefinition(true_node);
+ pm->d_cnfProof->registerConvertedClause(pm->d_satProof->getTrueUnit());
+ pm->d_cnfProof->popCurrentAssertion();
+ pm->d_cnfProof->popCurrentDefinition();
+
+ pm->d_cnfProof->pushCurrentAssertion(false_node);
+ pm->d_cnfProof->pushCurrentDefinition(false_node);
+ pm->d_cnfProof->registerConvertedClause(pm->d_satProof->getFalseUnit());
+ pm->d_cnfProof->popCurrentAssertion();
+ pm->d_cnfProof->popCurrentDefinition();
+
}
-void ProofManager::initTheoryProof() {
+void ProofManager::initTheoryProofEngine(SmtGlobals* globals) {
Assert (currentPM()->d_theoryProof == NULL);
Assert (currentPM()->d_format == LFSC);
- currentPM()->d_theoryProof = new LFSCTheoryProof();
+ currentPM()->d_theoryProof = new LFSCTheoryProofEngine(globals);
+}
+
+std::string ProofManager::getInputClauseName(ClauseId id,
+ const std::string& prefix) {
+ return append(prefix+".pb", id);
+}
+std::string ProofManager::getLemmaClauseName(ClauseId id,
+ const std::string& prefix) {
+ return append(prefix+".lemc", id);
}
+ std::string ProofManager::getLemmaName(ClauseId id,
+ const std::string& prefix) {
+ return append(prefix+"lem", id);
+}
+
+std::string ProofManager::getLearntClauseName(ClauseId id,
+ const std::string& prefix) {
+ return append(prefix+".cl", id);
+}
+std::string ProofManager::getVarName(prop::SatVariable var,
+ const std::string& prefix) {
+ return append(prefix+".v", var);
+}
+std::string ProofManager::getAtomName(prop::SatVariable var,
+ const std::string& prefix) {
+ return append(prefix+".a", var);
+}
+std::string ProofManager::getLitName(prop::SatLiteral lit,
+ const std::string& prefix) {
+ return append(prefix+".l", lit.toInt());
+}
+
-std::string ProofManager::getInputClauseName(ClauseId id) { return append("pb", id); }
-std::string ProofManager::getLemmaName(ClauseId id) { return append("lem", id); }
-std::string ProofManager::getLemmaClauseName(ClauseId id) { return append("lemc", id); }
-std::string ProofManager::getLearntClauseName(ClauseId id) { return append("cl", id); }
-std::string ProofManager::getVarName(prop::SatVariable var) { return append("var", var); }
-std::string ProofManager::getAtomName(prop::SatVariable var) { return append("atom", var); }
-std::string ProofManager::getLitName(prop::SatLiteral lit) { return append("lit", lit.toInt()); }
+std::string ProofManager::getPreprocessedAssertionName(Node node,
+ const std::string& prefix) {
+ node = node.getKind() == kind::BITVECTOR_EAGER_ATOM ? node[0] : node;
+ return append(prefix+".PA", node.getId());
+}
+std::string ProofManager::getAssertionName(Node node,
+ const std::string& prefix) {
+ return append(prefix+".A", node.getId());
+}
-std::string ProofManager::getAtomName(TNode atom) {
+std::string ProofManager::getAtomName(TNode atom,
+ const std::string& prefix) {
prop::SatLiteral lit = currentPM()->d_cnfProof->getLiteral(atom);
Assert(!lit.isNegated());
- return getAtomName(lit.getSatVariable());
+ return getAtomName(lit.getSatVariable(), prefix);
}
-std::string ProofManager::getLitName(TNode lit) {
- return getLitName(currentPM()->d_cnfProof->getLiteral(lit));
+std::string ProofManager::getLitName(TNode lit,
+ const std::string& prefix) {
+ return getLitName(currentPM()->d_cnfProof->getLiteral(lit), prefix);
+}
+
+std::string ProofManager::sanitize(TNode var) {
+ Assert (var.isVar());
+ std::string name = var.toString();
+ std::replace(name.begin(), name.end(), ' ', '_');
+ return name;
}
+
void ProofManager::traceDeps(TNode n) {
Debug("cores") << "trace deps " << n << std::endl;
+ if ((n.isConst() && n == NodeManager::currentNM()->mkConst<bool>(true)) ||
+ (n.getKind() == kind::NOT && n[0] == NodeManager::currentNM()->mkConst<bool>(false))) {
+ return;
+ }
if(d_inputCoreFormulas.find(n.toExpr()) != d_inputCoreFormulas.end()) {
// originating formula was in core set
Debug("cores") << " -- IN INPUT CORE LIST!" << std::endl;
@@ -171,45 +245,38 @@ void ProofManager::traceDeps(TNode n) {
}
}
-void ProofManager::addClause(ClauseId id, const prop::SatClause* clause, ClauseKind kind) {
- /*for (unsigned i = 0; i < clause->size(); ++i) {
- prop::SatLiteral lit = clause->operator[](i);
- d_propVars.insert(lit.getSatVariable());
- }*/
- if (kind == INPUT) {
- Debug("cores") << "; Add to inputClauses " << id << std::endl;
- d_inputClauses.insert(std::make_pair(id, clause));
- Assert(d_satProof->d_inputClauses.find(id) != d_satProof->d_inputClauses.end());
- Debug("cores") << "; core id is " << d_satProof->d_inputClauses[id] << std::endl;
- if(d_satProof->d_inputClauses[id] == uint64_t(-1)) {
- Debug("cores") << "; + constant unit (true or false)" << std::endl;
- } else if(options::unsatCores()) {
- Expr e = d_cnfProof->getAssertion(d_satProof->d_inputClauses[id] & 0xffffffff);
- Debug("cores") << "; core input assertion from CnfStream is " << e << std::endl;
- Debug("cores") << "; with proof rule " << ((d_satProof->d_inputClauses[id] & 0xffffffff00000000llu) >> 32) << std::endl;
- // Invalid proof rules are currently used for parts of CVC4 that don't
- // support proofs (these are e.g. unproven theory lemmas) or don't need
- // proofs (e.g. split lemmas). We can ignore these safely when
- // constructing unsat cores.
- if(((d_satProof->d_inputClauses[id] & 0xffffffff00000000llu) >> 32) != RULE_INVALID) {
- // trace dependences back to actual assertions
- traceDeps(Node::fromExpr(e));
- }
+void ProofManager::traceUnsatCore() {
+ Assert (options::unsatCores());
+ d_satProof->constructProof();
+ IdToSatClause used_lemmas;
+ IdToSatClause used_inputs;
+ d_satProof->collectClausesUsed(used_inputs,
+ used_lemmas);
+ IdToSatClause::const_iterator it = used_inputs.begin();
+ for(; it != used_inputs.end(); ++it) {
+ Node node = d_cnfProof->getAssertionForClause(it->first);
+ ProofRule rule = d_cnfProof->getProofRule(node);
+
+ Debug("cores") << "core input assertion " << node << std::endl;
+ Debug("cores") << "with proof rule " << rule << std::endl;
+ if (rule == RULE_TSEITIN ||
+ rule == RULE_GIVEN) {
+ // trace dependences back to actual assertions
+ // (this adds them to the unsat core)
+ traceDeps(node);
}
- } else {
- Assert(kind == THEORY_LEMMA);
- d_theoryLemmas.insert(std::make_pair(id, clause));
}
}
-void ProofManager::addAssertion(Expr formula, bool inUnsatCore) {
- Debug("cores") << "assert: " << formula << std::endl;
+void ProofManager::addAssertion(Expr formula) {
+ Debug("proof:pm") << "assert: " << formula << std::endl;
d_inputFormulas.insert(formula);
+}
+
+void ProofManager::addCoreAssertion(Expr formula) {
+ Debug("cores") << "assert: " << formula << std::endl;
d_deps[Node::fromExpr(formula)]; // empty vector of deps
- if(inUnsatCore || options::dumpUnsatCores() || options::checkUnsatCores()) {
- Debug("cores") << "adding to input core forms: " << formula << std::endl;
- d_inputCoreFormulas.insert(formula);
- }
+ d_inputCoreFormulas.insert(formula);
}
void ProofManager::addDependence(TNode n, TNode dep) {
@@ -232,151 +299,210 @@ void ProofManager::setLogic(const LogicInfo& logic) {
d_logic = logic;
}
-void ProofManager::printProof(std::ostream& os, TNode n) {
- // no proofs here yet
-}
-void ProofManager::setCnfDep( Expr child, Expr parent ) {
- Debug("cores") << "CNF dep : " << child << " : " << parent << std::endl;
- d_cnf_dep[child] = parent;
-}
-Expr ProofManager::getFormulaForClauseId( ClauseId id ) {
- std::map< ClauseId, Expr >::const_iterator it = d_clause_id_to_assertion.find( id );
- if( it!=d_clause_id_to_assertion.end() ){
- return it->second;
- }else{
- Node ret;
- return ret.toExpr();
- }
-}
+LFSCProof::LFSCProof(SmtEngine* smtEngine,
+ LFSCCoreSatProof* sat,
+ LFSCCnfProof* cnf,
+ LFSCTheoryProofEngine* theory)
+ : d_satProof(sat)
+ , d_cnfProof(cnf)
+ , d_theoryProof(theory)
+ , d_smtEngine(smtEngine)
+{}
-ProofRule ProofManager::getProofRuleForClauseId( ClauseId id ) {
- std::map< ClauseId, ProofRule >::const_iterator it = d_clause_id_to_rule.find( id );
- if( it!=d_clause_id_to_rule.end() ){
- return it->second;
- }else{
- return RULE_INVALID;
- }
-}
+void LFSCProof::toStream(std::ostream& out) {
+ d_satProof->constructProof();
-void ProofManager::setAssertion( Expr e ) {
- d_assertion_to_id[e] = d_assertion_counter;
- d_assertion_counter++;
-}
-
-// if this function returns true, writes to out a proof of e based on input assertions
-bool ProofManager::isInputAssertion( Expr e, std::ostream& out ) {
- std::map< Expr, unsigned >::iterator itp = d_assertion_to_id.find( e );
- if( itp==d_assertion_to_id.end() ){
- //check if deduced by CNF
- std::map< Expr, Expr >::iterator itd = d_cnf_dep.find( e );
- if( itd!=d_cnf_dep.end() ){
- Expr parent = itd->second;
- //check if parent is an input assertion
- std::stringstream out_parent;
- if( isInputAssertion( parent, out_parent ) ){
- if( parent.getKind()==kind::AND || ( parent.getKind()==kind::NOT && ( parent[0].getKind()==kind::IMPLIES || parent[0].getKind()==kind::OR ) ) ){
- Expr parent_base = parent.getKind()==kind::NOT ? parent[0] : parent;
- Expr e_base = e.getKind()==kind::NOT ? e[0] : e;
- bool e_pol = e.getKind()!=kind::NOT;
- for( unsigned i=0; i<parent_base.getNumChildren(); i++ ){
- Expr child_base = parent_base[i].getKind()==kind::NOT ? parent_base[i][0] : parent_base[i];
- bool child_pol = parent_base[i].getKind()!=kind::NOT;
- if( parent_base.getKind()==kind::IMPLIES && i==0 ){
- child_pol = !child_pol;
- }
- if( e_base==child_base && (e_pol==child_pol)==(parent_base.getKind()==kind::AND) ){
- bool elimNn = ( ( parent_base.getKind()==kind::OR || ( parent_base.getKind()==kind::IMPLIES && i==1 ) ) && e_pol );
- if( elimNn ){
- out << "(not_not_elim _ ";
- }
- std::stringstream out_paren;
- if( i+1<parent_base.getNumChildren() ){
- out << "(and_elim_1 _ _ ";
- if( parent_base.getKind()==kind::OR || parent_base.getKind()==kind::IMPLIES ){
- out << "(not_" << ( parent_base.getKind()==kind::OR ? "or" : "impl" ) << "_elim _ _ ";
- out_paren << ")";
- }
- out_paren << ")";
- }
- for( unsigned j=0; j<i; j++ ){
- out << "(and_elim_2 _ _ ";
- if( parent_base.getKind()==kind::OR || parent_base.getKind()==kind::IMPLIES ){
- out << "(not_" << ( parent_base.getKind()==kind::OR ? "or" : "impl" ) << "_elim _ _ ";
- out_paren << ")";
- }
- out_paren << ")";
- }
- out << out_parent.str();
- out << out_paren.str();
- if( elimNn ){
- out << ")";
- }
- return true;
- }
- }
- }else{
- Trace("cnf-pf-debug") << "; isInputAssertion : parent of " << e << " is not correct type (" << parent << ")" << std::endl;
- }
- }else{
- Trace("cnf-pf-debug") << "; isInputAssertion : parent of " << e << " is not input" << std::endl;
- }
- }else{
- Trace("cnf-pf-debug") << "; isInputAssertion : " << e << " has no parent" << std::endl;
- }
- return false;
- }else{
- out << "A" << itp->second;
- return true;
+ // collecting leaf clauses in resolution proof
+ IdToSatClause used_lemmas;
+ IdToSatClause used_inputs;
+ d_satProof->collectClausesUsed(used_inputs,
+ used_lemmas);
+
+ // collecting assertions that lead to the clauses being asserted
+ NodeSet used_assertions;
+ d_cnfProof->collectAssertionsForClauses(used_inputs, used_assertions);
+
+ NodeSet atoms;
+ // collects the atoms in the clauses
+ d_cnfProof->collectAtomsForClauses(used_inputs, atoms);
+ d_cnfProof->collectAtomsForClauses(used_lemmas, atoms);
+
+ // collects the atoms in the assertions
+ for (NodeSet::const_iterator it = used_assertions.begin();
+ it != used_assertions.end(); ++it) {
+ utils::collectAtoms(*it, atoms);
}
-}
-void ProofManager::setRegisteringFormula( Node n, ProofRule proof_id ) {
- Trace("cnf-pf-debug") << "; set registering formula " << n << " proof rule = " << proof_id << std::endl;
- d_registering_assertion = n;
- d_registering_rule = proof_id;
-}
+ if (Debug.isOn("proof:pm")) {
+ // std::cout << NodeManager::currentNM();
+ Debug("proof:pm") << "LFSCProof::Used assertions: "<< std::endl;
+ for(NodeSet::const_iterator it = used_assertions.begin(); it != used_assertions.end(); ++it) {
+ Debug("proof:pm") << " " << *it << std::endl;
+ }
-void ProofManager::setRegisteredClauseId( ClauseId id ) {
- Trace("cnf-pf-debug") << "; set register clause id " << id << " " << d_registering_assertion << std::endl;
- if( !d_registering_assertion.isNull() ){
- d_clause_id_to_assertion[id] = d_registering_assertion.toExpr();
- d_clause_id_to_rule[id] = d_registering_rule;
- setRegisteringFormula( Node::null(), RULE_INVALID );
+ Debug("proof:pm") << "LFSCProof::Used atoms: "<< std::endl;
+ for(NodeSet::const_iterator it = atoms.begin(); it != atoms.end(); ++it) {
+ Debug("proof:pm") << " " << *it << std::endl;
+ }
}
-}
-LFSCProof::LFSCProof(SmtEngine* smtEngine, LFSCSatProof* sat, LFSCCnfProof* cnf, LFSCTheoryProof* theory)
- : d_satProof(sat)
- , d_cnfProof(cnf)
- , d_theoryProof(theory)
- , d_smtEngine(smtEngine)
-{
- d_satProof->constructProof();
-}
-void LFSCProof::toStream(std::ostream& out) {
+
smt::SmtScope scope(d_smtEngine);
std::ostringstream paren;
out << "(check\n";
out << " ;; Declarations\n";
- if (d_theoryProof == NULL) {
- d_theoryProof = new LFSCTheoryProof();
+
+ // declare the theory atoms
+ NodeSet::const_iterator it = atoms.begin();
+ NodeSet::const_iterator end = atoms.end();
+ for(; it != end; ++it) {
+ d_theoryProof->registerTerm((*it).toExpr());
}
- /*for(LFSCCnfProof::iterator i = d_cnfProof->begin_atom_mapping();
- i != d_cnfProof->end_atom_mapping();
- ++i) {
- d_theoryProof->addDeclaration(*i);
- }*/
+ // print out all the original assertions
d_theoryProof->printAssertions(out, paren);
- out << " ;; Proof of empty clause follows\n";
+
+
out << "(: (holds cln)\n";
- d_cnfProof->printClauses(out, paren);
- d_satProof->printResolutions(out, paren);
- paren <<")))\n;;";
- out << paren.str();
- out << "\n";
+
+ // print trust that input assertions are their preprocessed form
+ printPreprocessedAssertions(used_assertions, out, paren);
+
+ // print mapping between theory atoms and internal SAT variables
+ d_cnfProof->printAtomMapping(atoms, out, paren);
+
+ IdToSatClause::const_iterator cl_it = used_inputs.begin();
+ // print CNF conversion proof for each clause
+ for (; cl_it != used_inputs.end(); ++cl_it) {
+ d_cnfProof->printCnfProofForClause(cl_it->first, cl_it->second, out, paren);
+ }
+
+ // FIXME: for now assume all theory lemmas are in CNF form so
+ // distinguish between them and inputs
+ // print theory lemmas for resolution proof
+ d_theoryProof->printTheoryLemmas(used_lemmas, out, paren);
+
+
+ if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER && ProofManager::getBitVectorProof()) {
+ // print actual resolution proof
+ // d_satProof->printResolutions(out, paren);
+ ProofManager::getBitVectorProof()->getSatProof()->printResolutionEmptyClause(out, paren);
+ paren <<")))\n;;";
+ out << paren.str();
+ out << "\n";
+ } else {
+ // print actual resolution proof
+ d_satProof->printResolutions(out, paren);
+ d_satProof->printResolutionEmptyClause(out, paren);
+ paren <<")))\n;;";
+ out << paren.str();
+ out << "\n";
+ }
+}
+
+void LFSCProof::printPreprocessedAssertions(const NodeSet& assertions,
+ std::ostream& os,
+ std::ostream& paren) {
+ os << " ;; Preprocessing \n";
+ NodeSet::const_iterator it = assertions.begin();
+ NodeSet::const_iterator end = assertions.end();
+
+ for (; it != end; ++it) {
+ os << "(th_let_pf _ ";
+
+ //TODO
+ os << "(trust_f ";
+ ProofManager::currentPM()->getTheoryProofEngine()->printLetTerm((*it).toExpr(), os);
+ os << ") ";
+
+ os << "(\\ "<< ProofManager::getPreprocessedAssertionName(*it, "") << "\n";
+ paren << "))";
+
+ }
}
+
+
+//---from Morgan---
+bool ProofManager::hasOp(TNode n) const {
+ return d_bops.find(n) != d_bops.end();
+}
+
+Node ProofManager::lookupOp(TNode n) const {
+ std::map<Node, Node>::const_iterator i = d_bops.find(n);
+ Assert(i != d_bops.end());
+ return (*i).second;
+}
+
+Node ProofManager::mkOp(TNode n) {
+ if(n.getKind() != kind::BUILTIN) {
+ return n;
+ }
+ Node& op = d_ops[n];
+ if(op.isNull()) {
+ Debug("mgd") << "making an op for " << n << "\n";
+ std::stringstream ss;
+ ss << n;
+ std::string s = ss.str();
+ Debug("mgd") << " : " << s << std::endl;
+ std::vector<TypeNode> v;
+ v.push_back(NodeManager::currentNM()->integerType());
+ if(n.getConst<Kind>() == kind::SELECT) {
+ v.push_back(NodeManager::currentNM()->integerType());
+ v.push_back(NodeManager::currentNM()->integerType());
+ } else if(n.getConst<Kind>() == kind::STORE) {
+ v.push_back(NodeManager::currentNM()->integerType());
+ v.push_back(NodeManager::currentNM()->integerType());
+ v.push_back(NodeManager::currentNM()->integerType());
+ }
+ TypeNode type = NodeManager::currentNM()->mkFunctionType(v);
+ op = NodeManager::currentNM()->mkSkolem(s, type, " ignore", NodeManager::SKOLEM_NO_NOTIFY);
+ d_bops[op] = n;
+ }
+ return op;
+}
+//---end from Morgan---
+
+std::ostream& operator<<(std::ostream& out, CVC4::ProofRule k) {
+ switch(k) {
+ case RULE_GIVEN:
+ out << "RULE_GIVEN";
+ break;
+ case RULE_DERIVED:
+ out << "RULE_DERIVED";
+ break;
+ case RULE_RECONSTRUCT:
+ out << "RULE_RECONSTRUCT";
+ break;
+ case RULE_TRUST:
+ out << "RULE_TRUST";
+ break;
+ case RULE_INVALID:
+ out << "RULE_INVALID";
+ break;
+ case RULE_CONFLICT:
+ out << "RULE_CONFLICT";
+ break;
+ case RULE_TSEITIN:
+ out << "RULE_TSEITIN";
+ break;
+ case RULE_SPLIT:
+ out << "RULE_SPLIT";
+ break;
+ case RULE_ARRAYS_EXT:
+ out << "RULE_ARRAYS";
+ break;
+ case RULE_ARRAYS_ROW:
+ out << "RULE_ARRAYS";
+ break;
+ default:
+ out << "ProofRule Unknown! [" << unsigned(k) << "]";
+ }
+
+ return out;
+}
+
+
} /* CVC4 namespace */
diff --git a/src/proof/proof_manager.h b/src/proof/proof_manager.h
index 6864eca3d..5d8bf3d58 100644
--- a/src/proof/proof_manager.h
+++ b/src/proof/proof_manager.h
@@ -31,27 +31,52 @@
namespace CVC4 {
+class SmtGlobals;
+
// forward declarations
namespace Minisat {
class Solver;
}/* Minisat namespace */
+namespace BVMinisat {
+ class Solver;
+}/* BVMinisat namespace */
+
namespace prop {
class CnfStream;
}/* CVC4::prop namespace */
class SmtEngine;
-typedef int ClauseId;
+typedef unsigned ClauseId;
+const ClauseId ClauseIdEmpty(-1);
+const ClauseId ClauseIdUndef(-2);
+const ClauseId ClauseIdError(-3);
class Proof;
-class SatProof;
+template <class Solver> class TSatProof;
+typedef TSatProof< CVC4::Minisat::Solver> CoreSatProof;
+
class CnfProof;
+class RewriterProof;
+class TheoryProofEngine;
class TheoryProof;
+class UFProof;
+class ArrayProof;
+class BitVectorProof;
+
+template <class Solver> class LFSCSatProof;
+typedef LFSCSatProof< CVC4::Minisat::Solver> LFSCCoreSatProof;
-class LFSCSatProof;
class LFSCCnfProof;
-class LFSCTheoryProof;
+class LFSCTheoryProofEngine;
+class LFSCUFProof;
+class LFSCBitVectorProof;
+class LFSCRewriterProof;
+
+template <class Solver> class ProofProxy;
+typedef ProofProxy< CVC4::Minisat::Solver> CoreProofProxy;
+typedef ProofProxy< CVC4::BVMinisat::Solver> BVProofProxy;
namespace prop {
typedef uint64_t SatVariable;
@@ -67,18 +92,13 @@ enum ProofFormat {
std::string append(const std::string& str, uint64_t num);
-typedef __gnu_cxx::hash_map < ClauseId, const prop::SatClause* > IdToClause;
-typedef std::map < ClauseId, const prop::SatClause* > OrderedIdToClause;
-typedef __gnu_cxx::hash_set<prop::SatVariable > VarSet;
+typedef __gnu_cxx::hash_map < ClauseId, prop::SatClause* > IdToSatClause;
typedef __gnu_cxx::hash_set<Expr, ExprHashFunction > ExprSet;
+typedef __gnu_cxx::hash_set<Node, NodeHashFunction > NodeSet;
+typedef __gnu_cxx::hash_map<Node, std::vector<Node>, NodeHashFunction > NodeToNodes;
+typedef std::hash_set<ClauseId> IdHashSet;
-typedef int ClauseId;
-
-enum ClauseKind {
- INPUT,
- THEORY_LEMMA,
- LEARNT
-};/* enum ClauseKind */
+typedef unsigned ClauseId;
enum ProofRule {
RULE_GIVEN, /* input assertion */
@@ -88,44 +108,31 @@ enum ProofRule {
RULE_INVALID, /* assert-fail if this is ever needed in proof; use e.g. for split lemmas */
RULE_CONFLICT, /* re-construct as a conflict */
RULE_TSEITIN, /* Tseitin CNF transformation */
-
+ RULE_SPLIT, /* A splitting lemma of the form a v ~ a*/
+
RULE_ARRAYS_EXT, /* arrays, extensional */
RULE_ARRAYS_ROW, /* arrays, read-over-write */
};/* enum ProofRules */
class ProofManager {
-
- SatProof* d_satProof;
- CnfProof* d_cnfProof;
- TheoryProof* d_theoryProof;
+ CoreSatProof* d_satProof;
+ CnfProof* d_cnfProof;
+ TheoryProofEngine* d_theoryProof;
// information that will need to be shared across proofs
- IdToClause d_inputClauses;
- OrderedIdToClause d_theoryLemmas;
- IdToClause d_theoryPropagations;
ExprSet d_inputFormulas;
ExprSet d_inputCoreFormulas;
ExprSet d_outputCoreFormulas;
- //VarSet d_propVars;
int d_nextId;
Proof* d_fullProof;
ProofFormat d_format; // used for now only in debug builds
- __gnu_cxx::hash_map< Node, std::vector<Node>, NodeHashFunction > d_deps;
-
+ NodeToNodes d_deps;
// trace dependences back to unsat core
void traceDeps(TNode n);
- Node d_registering_assertion;
- ProofRule d_registering_rule;
- std::map< ClauseId, Expr > d_clause_id_to_assertion;
- std::map< ClauseId, ProofRule > d_clause_id_to_rule;
- std::map< Expr, Expr > d_cnf_dep;
- //LFSC number for assertions
- unsigned d_assertion_counter;
- std::map< Expr, unsigned > d_assertion_to_id;
protected:
LogicInfo d_logic;
@@ -137,93 +144,100 @@ public:
// initialization
static void initSatProof(Minisat::Solver* solver);
- static void initCnfProof(CVC4::prop::CnfStream* cnfStream);
- static void initTheoryProof();
-
- static Proof* getProof(SmtEngine* smt);
- static SatProof* getSatProof();
- static CnfProof* getCnfProof();
- static TheoryProof* getTheoryProof();
-
+ static void initCnfProof(CVC4::prop::CnfStream* cnfStream,
+ context::Context* ctx);
+ static void initTheoryProofEngine(SmtGlobals* globals);
+
+ // getting various proofs
+ static Proof* getProof(SmtEngine* smt);
+ static CoreSatProof* getSatProof();
+ static CnfProof* getCnfProof();
+ static TheoryProofEngine* getTheoryProofEngine();
+ static TheoryProof* getTheoryProof( theory::TheoryId id );
+ static UFProof* getUfProof();
+ static BitVectorProof* getBitVectorProof();
+ static ArrayProof* getArrayProof();
+
// iterators over data shared by proofs
- typedef IdToClause::const_iterator clause_iterator;
- typedef OrderedIdToClause::const_iterator ordered_clause_iterator;
typedef ExprSet::const_iterator assertions_iterator;
- typedef VarSet::const_iterator var_iterator;
-
-
- __gnu_cxx::hash_map< Node, std::vector<Node>, NodeHashFunction >::const_iterator begin_deps() const { return d_deps.begin(); }
- __gnu_cxx::hash_map< Node, std::vector<Node>, NodeHashFunction >::const_iterator end_deps() const { return d_deps.end(); }
-
- clause_iterator begin_input_clauses() const { return d_inputClauses.begin(); }
- clause_iterator end_input_clauses() const { return d_inputClauses.end(); }
- size_t num_input_clauses() const { return d_inputClauses.size(); }
-
- ordered_clause_iterator begin_lemmas() const { return d_theoryLemmas.begin(); }
- ordered_clause_iterator end_lemmas() const { return d_theoryLemmas.end(); }
- size_t num_lemmas() const { return d_theoryLemmas.size(); }
+ // iterate over the assertions (these are arbitrary boolean formulas)
assertions_iterator begin_assertions() const { return d_inputFormulas.begin(); }
assertions_iterator end_assertions() const { return d_inputFormulas.end(); }
size_t num_assertions() const { return d_inputFormulas.size(); }
+
+//---from Morgan---
+ Node mkOp(TNode n);
+ Node lookupOp(TNode n) const;
+ bool hasOp(TNode n) const;
+
+ std::map<Node, Node> d_ops;
+ std::map<Node, Node> d_bops;
+//---end from Morgan---
+
+
+ // variable prefixes
+ static std::string getInputClauseName(ClauseId id, const std::string& prefix = "");
+ static std::string getLemmaClauseName(ClauseId id, const std::string& prefix = "");
+ static std::string getLemmaName(ClauseId id, const std::string& prefix = "");
+ static std::string getLearntClauseName(ClauseId id, const std::string& prefix = "");
+ static std::string getPreprocessedAssertionName(Node node, const std::string& prefix = "");
+ static std::string getAssertionName(Node node, const std::string& prefix = "");
+
+ static std::string getVarName(prop::SatVariable var, const std::string& prefix = "");
+ static std::string getAtomName(prop::SatVariable var, const std::string& prefix = "");
+ static std::string getAtomName(TNode atom, const std::string& prefix = "");
+ static std::string getLitName(prop::SatLiteral lit, const std::string& prefix = "");
+ static std::string getLitName(TNode lit, const std::string& prefix = "");
+
+ // for SMT variable names that have spaces and other things
+ static std::string sanitize(TNode var);
+
- void printProof(std::ostream& os, TNode n);
-
- void addAssertion(Expr formula, bool inUnsatCore);
- void addClause(ClauseId id, const prop::SatClause* clause, ClauseKind kind);
- // note that n depends on dep (for cores)
+ /** Add proof assertion - unlinke addCoreAssertion this is post definition expansion **/
+ void addAssertion(Expr formula);
+
+ /** Public unsat core methods **/
+ void addCoreAssertion(Expr formula);
+
void addDependence(TNode n, TNode dep);
void addUnsatCore(Expr formula);
+ void traceUnsatCore();
assertions_iterator begin_unsat_core() const { return d_outputCoreFormulas.begin(); }
assertions_iterator end_unsat_core() const { return d_outputCoreFormulas.end(); }
size_t size_unsat_core() const { return d_outputCoreFormulas.size(); }
int nextId() { return d_nextId++; }
- // variable prefixes
- static std::string getInputClauseName(ClauseId id);
- static std::string getLemmaName(ClauseId id);
- static std::string getLemmaClauseName(ClauseId id);
- static std::string getLearntClauseName(ClauseId id);
-
- static std::string getVarName(prop::SatVariable var);
- static std::string getAtomName(prop::SatVariable var);
- static std::string getAtomName(TNode atom);
- static std::string getLitName(prop::SatLiteral lit);
- static std::string getLitName(TNode lit);
-
void setLogic(const LogicInfo& logic);
const std::string getLogic() const { return d_logic.getLogicString(); }
+ LogicInfo & getLogicInfo() { return d_logic; }
-
- void setCnfDep( Expr child, Expr parent );
- Expr getFormulaForClauseId( ClauseId id );
- ProofRule getProofRuleForClauseId( ClauseId id );
- unsigned getAssertionCounter() { return d_assertion_counter; }
- void setAssertion( Expr e );
- bool isInputAssertion( Expr e, std::ostream& out );
-
-public: // AJR : FIXME this is hacky
- //currently, to map between ClauseId and Expr, requires:
- // (1) CnfStream::assertClause(...) to call setRegisteringFormula,
- // (2) SatProof::registerClause(...)/registerUnitClause(...) to call setRegisteredClauseId.
- //this is under the assumption that the first call at (2) is invoked for the clause corresponding to the Expr at (1).
- void setRegisteringFormula( Node n, ProofRule proof_id );
- void setRegisteredClauseId( ClauseId id );
};/* class ProofManager */
class LFSCProof : public Proof {
- LFSCSatProof* d_satProof;
+ LFSCCoreSatProof* d_satProof;
LFSCCnfProof* d_cnfProof;
- LFSCTheoryProof* d_theoryProof;
+ LFSCTheoryProofEngine* d_theoryProof;
SmtEngine* d_smtEngine;
+
+ // FIXME: hack until we get preprocessing
+ void printPreprocessedAssertions(const NodeSet& assertions,
+ std::ostream& os,
+ std::ostream& paren);
public:
- LFSCProof(SmtEngine* smtEngine, LFSCSatProof* sat, LFSCCnfProof* cnf, LFSCTheoryProof* theory);
+ LFSCProof(SmtEngine* smtEngine,
+ LFSCCoreSatProof* sat,
+ LFSCCnfProof* cnf,
+ LFSCTheoryProofEngine* theory);
virtual void toStream(std::ostream& out);
virtual ~LFSCProof() {}
};/* class LFSCProof */
+std::ostream& operator<<(std::ostream& out, CVC4::ProofRule k);
}/* CVC4 namespace */
+
+
#endif /* __CVC4__PROOF_MANAGER_H */
diff --git a/src/proof/proof_utils.cpp b/src/proof/proof_utils.cpp
new file mode 100644
index 000000000..47b8a235e
--- /dev/null
+++ b/src/proof/proof_utils.cpp
@@ -0,0 +1,127 @@
+/********************* */
+/*! \file proof_utils.cpp
+** \verbatim
+** Original author: Liana Hadarean
+** Major contributors: none
+** Minor contributors (to current version): none
+** This file is part of the CVC4 project.
+** Copyright (c) 2009-2014 New York University and The University of Iowa
+** See the file COPYING in the top-level source directory for licensing
+** information.\endverbatim
+**
+** \brief [[ Add one-line brief description here ]]
+**
+** [[ Add lengthier description here ]]
+** \todo document this file
+**/
+
+#include "proof/proof_utils.h"
+#include "theory/theory.h"
+
+namespace CVC4 {
+namespace utils {
+
+void collectAtoms(TNode node, CVC4::NodeSet& seen) {
+ if (seen.find(node) != seen.end())
+ return;
+ if (theory::Theory::theoryOf(node) != theory::THEORY_BOOL || node.isVar()) {
+ seen.insert(node);
+ return;
+ }
+
+ for (unsigned i = 0; i < node.getNumChildren(); ++i) {
+ collectAtoms(node[i], seen);
+ }
+}
+
+std::string toLFSCKind(Kind kind) {
+ switch(kind) {
+ // core kinds
+ case kind::OR : return "or";
+ case kind::AND: return "and";
+ case kind::XOR: return "xor";
+ case kind::EQUAL: return "=";
+ case kind::IFF: return "iff";
+ case kind::IMPLIES: return "impl";
+ case kind::NOT: return "not";
+
+ // bit-vector kinds
+ case kind::BITVECTOR_AND :
+ return "bvand";
+ case kind::BITVECTOR_OR :
+ return "bvor";
+ case kind::BITVECTOR_XOR :
+ return "bvxor";
+ case kind::BITVECTOR_NAND :
+ return "bvnand";
+ case kind::BITVECTOR_NOR :
+ return "bvnor";
+ case kind::BITVECTOR_XNOR :
+ return "bvxnor";
+ case kind::BITVECTOR_COMP :
+ return "bvcomp";
+ case kind::BITVECTOR_MULT :
+ return "bvmul";
+ case kind::BITVECTOR_PLUS :
+ return "bvadd";
+ case kind::BITVECTOR_SUB :
+ return "bvsub";
+ case kind::BITVECTOR_UDIV :
+ case kind::BITVECTOR_UDIV_TOTAL :
+ return "bvudiv";
+ case kind::BITVECTOR_UREM :
+ case kind::BITVECTOR_UREM_TOTAL :
+ return "bvurem";
+ case kind::BITVECTOR_SDIV :
+ return "bvsdiv";
+ case kind::BITVECTOR_SREM :
+ return "bvsrem";
+ case kind::BITVECTOR_SMOD :
+ return "bvsmod";
+ case kind::BITVECTOR_SHL :
+ return "bvshl";
+ case kind::BITVECTOR_LSHR :
+ return "bvlshr";
+ case kind::BITVECTOR_ASHR :
+ return "bvashr";
+ case kind::BITVECTOR_CONCAT :
+ return "concat";
+ case kind::BITVECTOR_NEG :
+ return "bvneg";
+ case kind::BITVECTOR_NOT :
+ return "bvnot";
+ case kind::BITVECTOR_ROTATE_LEFT :
+ return "rotate_left";
+ case kind::BITVECTOR_ROTATE_RIGHT :
+ return "rotate_right";
+ case kind::BITVECTOR_ULT :
+ return "bvult";
+ case kind::BITVECTOR_ULE :
+ return "bvule";
+ case kind::BITVECTOR_UGT :
+ return "bvugt";
+ case kind::BITVECTOR_UGE :
+ return "bvuge";
+ case kind::BITVECTOR_SLT :
+ return "bvslt";
+ case kind::BITVECTOR_SLE :
+ return "bvsle";
+ case kind::BITVECTOR_SGT :
+ return "bvsgt";
+ case kind::BITVECTOR_SGE :
+ return "bvsge";
+ case kind::BITVECTOR_EXTRACT :
+ return "extract";
+ case kind::BITVECTOR_REPEAT :
+ return "repeat";
+ case kind::BITVECTOR_ZERO_EXTEND :
+ return "zero_extend";
+ case kind::BITVECTOR_SIGN_EXTEND :
+ return "sign_extend";
+ default:
+ Unreachable();
+ }
+}
+
+} /* namespace CVC4::utils */
+} /* namespace CVC4 */
diff --git a/src/proof/proof_utils.h b/src/proof/proof_utils.h
new file mode 100644
index 000000000..c27fbe5c2
--- /dev/null
+++ b/src/proof/proof_utils.h
@@ -0,0 +1,178 @@
+/********************* */
+/*! \file proof_utils.h
+** \verbatim
+** Original author: Liana Hadarean
+** Major contributors: none
+** Minor contributors (to current version): none
+** This file is part of the CVC4 project.
+** Copyright (c) 2009-2014 New York University and The University of Iowa
+** See the file COPYING in the top-level source directory for licensing
+** information.\endverbatim
+**
+** \brief [[ Add one-line brief description here ]]
+**
+** [[ Add lengthier description here ]]
+** \todo document this file
+**/
+
+#include "cvc4_private.h"
+
+#pragma once
+
+#include <set>
+#include <vector>
+#include <sstream>
+#include "expr/node_manager.h"
+
+namespace CVC4 {
+
+typedef __gnu_cxx::hash_set<Expr, ExprHashFunction> ExprSet;
+typedef __gnu_cxx::hash_set<Node, NodeHashFunction> NodeSet;
+
+namespace utils {
+
+std::string toLFSCKind(Kind kind);
+
+inline unsigned getExtractHigh(Expr node) {
+ return node.getOperator().getConst<BitVectorExtract>().high;
+}
+
+inline unsigned getExtractLow(Expr node) {
+ return node.getOperator().getConst<BitVectorExtract>().low;
+}
+
+inline unsigned getSize(Type type) {
+ BitVectorType bv(type);
+ return bv.getSize();
+}
+
+
+inline unsigned getSize(Expr node) {
+ Assert (node.getType().isBitVector());
+ return getSize(node.getType());
+}
+
+inline Expr mkTrue() {
+ return NodeManager::currentNM()->toExprManager()->mkConst<bool>(true);
+}
+
+inline Expr mkFalse() {
+ return NodeManager::currentNM()->toExprManager()->mkConst<bool>(false);
+}
+inline BitVector mkBitVectorOnes(unsigned size) {
+ Assert(size > 0);
+ return BitVector(1, Integer(1)).signExtend(size - 1);
+}
+
+inline Expr mkExpr(Kind k , Expr expr) {
+ return NodeManager::currentNM()->toExprManager()->mkExpr(k, expr);
+}
+inline Expr mkExpr(Kind k , Expr e1, Expr e2) {
+ return NodeManager::currentNM()->toExprManager()->mkExpr(k, e1, e2);
+}
+inline Expr mkExpr(Kind k , std::vector<Expr>& children) {
+ return NodeManager::currentNM()->toExprManager()->mkExpr(k, children);
+}
+
+
+inline Expr mkOnes(unsigned size) {
+ BitVector val = mkBitVectorOnes(size);
+ return NodeManager::currentNM()->toExprManager()->mkConst<BitVector>(val);
+}
+
+inline Expr mkConst(unsigned size, unsigned int value) {
+ BitVector val(size, value);
+ return NodeManager::currentNM()->toExprManager()->mkConst<BitVector>(val);
+}
+
+inline Expr mkConst(const BitVector& value) {
+ return NodeManager::currentNM()->toExprManager()->mkConst<BitVector>(value);
+}
+
+inline Expr mkOr(const std::vector<Expr>& nodes) {
+ std::set<Expr> all;
+ all.insert(nodes.begin(), nodes.end());
+ Assert(all.size() != 0 );
+
+ if (all.size() == 1) {
+ // All the same, or just one
+ return nodes[0];
+ }
+
+
+ NodeBuilder<> disjunction(kind::OR);
+ std::set<Expr>::const_iterator it = all.begin();
+ std::set<Expr>::const_iterator it_end = all.end();
+ while (it != it_end) {
+ disjunction << Node::fromExpr(*it);
+ ++ it;
+ }
+
+ Node res = disjunction;
+ return res.toExpr();
+}/* mkOr() */
+
+
+inline Expr mkAnd(const std::vector<Expr>& conjunctions) {
+ std::set<Expr> all;
+ all.insert(conjunctions.begin(), conjunctions.end());
+
+ if (all.size() == 0) {
+ return mkTrue();
+ }
+
+ if (all.size() == 1) {
+ // All the same, or just one
+ return conjunctions[0];
+ }
+
+
+ NodeBuilder<> conjunction(kind::AND);
+ std::set<Expr>::const_iterator it = all.begin();
+ std::set<Expr>::const_iterator it_end = all.end();
+ while (it != it_end) {
+ conjunction << Node::fromExpr(*it);
+ ++ it;
+ }
+
+ Node res = conjunction;
+ return res.toExpr();
+}/* mkAnd() */
+
+inline Expr mkSortedExpr(Kind kind, const std::vector<Expr>& children) {
+ std::set<Expr> all;
+ all.insert(children.begin(), children.end());
+
+ if (all.size() == 0) {
+ return mkTrue();
+ }
+
+ if (all.size() == 1) {
+ // All the same, or just one
+ return children[0];
+ }
+
+
+ NodeBuilder<> res(kind);
+ std::set<Expr>::const_iterator it = all.begin();
+ std::set<Expr>::const_iterator it_end = all.end();
+ while (it != it_end) {
+ res << Node::fromExpr(*it);
+ ++ it;
+ }
+
+ return ((Node)res).toExpr();
+}/* mkSortedNode() */
+
+inline const bool getBit(Expr expr, unsigned i) {
+ Assert (i < utils::getSize(expr) &&
+ expr.isConst());
+ Integer bit = expr.getConst<BitVector>().extract(i, i).getValue();
+ return (bit == 1u);
+}
+
+void collectAtoms(TNode node, NodeSet& seen);
+
+
+}
+}
diff --git a/src/proof/sat_proof.h b/src/proof/sat_proof.h
index 52319431c..95a4c8907 100644
--- a/src/proof/sat_proof.h
+++ b/src/proof/sat_proof.h
@@ -20,63 +20,63 @@
#define __CVC4__SAT__PROOF_H
#include <stdint.h>
-
#include <ext/hash_map>
#include <ext/hash_set>
#include <iosfwd>
#include <set>
#include <sstream>
#include <vector>
-
#include "expr/expr.h"
#include "proof/proof_manager.h"
+#include "util/proof.h"
+#include "util/statistics_registry.h"
+
namespace CVC4 {
-namespace Minisat {
- class Solver;
- typedef uint32_t CRef;
-}/* Minisat namespace */
-}
-#include "prop/minisat/core/SolverTypes.h"
-#include "util/proof.h"
-#include "prop/sat_solver_types.h"
-namespace std {
- using namespace __gnu_cxx;
-}/* std namespace */
-namespace CVC4 {
+class CnfProof;
/**
* Helper debugging functions
*/
-void printDebug(Minisat::Lit l);
-void printDebug(Minisat::Clause& c);
+template <class Solver> void printDebug(typename Solver::TLit l);
+template <class Solver> void printDebug(typename Solver::TClause& c);
+
+enum ClauseKind {
+ INPUT,
+ THEORY_LEMMA, // we need to distinguish because we must reprove deleted theory lemmas
+ LEARNT
+};/* enum ClauseKind */
+
+template <class Solver>
struct ResStep {
- Minisat::Lit lit;
+ typename Solver::TLit lit;
ClauseId id;
bool sign;
- ResStep(Minisat::Lit l, ClauseId i, bool s) :
+ ResStep(typename Solver::TLit l, ClauseId i, bool s) :
lit(l),
id(i),
sign(s)
{}
};/* struct ResStep */
-typedef std::vector< ResStep > ResSteps;
-typedef std::set < Minisat::Lit> LitSet;
-
+template <class Solver>
class ResChain {
+public:
+ typedef std::vector< ResStep<Solver> > ResSteps;
+ typedef std::set < typename Solver::TLit> LitSet;
+
private:
ClauseId d_start;
ResSteps d_steps;
LitSet* d_redundantLits;
public:
ResChain(ClauseId start);
- void addStep(Minisat::Lit, ClauseId, bool);
+ void addStep(typename Solver::TLit, ClauseId, bool);
bool redundantRemoved() { return (d_redundantLits == NULL || d_redundantLits->empty()); }
- void addRedundantLit(Minisat::Lit lit);
+ void addRedundantLit(typename Solver::TLit lit);
~ResChain();
// accessor methods
ClauseId getStart() { return d_start; }
@@ -84,35 +84,31 @@ public:
LitSet* getRedundant() { return d_redundantLits; }
};/* class ResChain */
-typedef std::hash_map < ClauseId, Minisat::CRef > IdCRefMap;
-typedef std::hash_map < Minisat::CRef, ClauseId > ClauseIdMap;
-typedef std::hash_map < ClauseId, Minisat::Lit> IdUnitMap;
-typedef std::hash_map < int, ClauseId> UnitIdMap; //FIXME
-typedef std::hash_map < ClauseId, ResChain*> IdResMap;
-typedef std::hash_set < ClauseId > IdHashSet;
-typedef std::hash_map < ClauseId, uint64_t > IdProofRuleMap;
-typedef std::vector < ResChain* > ResStack;
-typedef std::hash_map <ClauseId, prop::SatClause* > IdToSatClause;
-typedef std::set < ClauseId > IdSet;
-typedef std::vector < Minisat::Lit > LitVector;
-typedef __gnu_cxx::hash_map<ClauseId, Minisat::Clause& > IdToMinisatClause;
-
-class SatProof;
-
-class ProofProxy : public ProofProxyAbstract {
-private:
- SatProof* d_proof;
-public:
- ProofProxy(SatProof* pf);
- void updateCRef(Minisat::CRef oldref, Minisat::CRef newref);
-};/* class ProofProxy */
-
+template <class Solver> class ProofProxy;
class CnfProof;
-class SatProof {
+template<class Solver>
+class TSatProof {
protected:
- Minisat::Solver* d_solver;
+ typedef std::set < typename Solver::TLit> LitSet;
+ typedef std::set < typename Solver::TVar> VarSet;
+ typedef std::hash_map < ClauseId, typename Solver::TCRef > IdCRefMap;
+ typedef std::hash_map < typename Solver::TCRef, ClauseId > ClauseIdMap;
+ typedef std::hash_map < ClauseId, typename Solver::TLit> IdUnitMap;
+ typedef std::hash_map < int, ClauseId> UnitIdMap;
+ typedef std::hash_map < ClauseId, ResChain<Solver>* > IdResMap;
+ typedef std::hash_map < ClauseId, uint64_t > IdProofRuleMap;
+ typedef std::vector < ResChain<Solver>* > ResStack;
+ //typedef std::hash_map <ClauseId, prop::SatClause* > IdToSatClause;
+ typedef std::set < ClauseId > IdSet;
+ typedef std::vector < typename Solver::TLit > LitVector;
+ typedef __gnu_cxx::hash_map<ClauseId, typename Solver::TClause& > IdToMinisatClause;
+ typedef __gnu_cxx::hash_map<ClauseId, LitVector* > IdToConflicts;
+
+ typename Solver::Solver* d_solver;
+ CnfProof* d_cnfProof;
+
// clauses
IdCRefMap d_idClause;
ClauseIdMap d_clauseId;
@@ -120,10 +116,14 @@ protected:
UnitIdMap d_unitId;
IdHashSet d_deleted;
IdToSatClause d_deletedTheoryLemmas;
-public:
- IdProofRuleMap d_inputClauses;
- IdProofRuleMap d_lemmaClauses;
+
protected:
+ IdHashSet d_inputClauses;
+ IdHashSet d_lemmaClauses;
+ VarSet d_assumptions; // assumption literals for bv solver
+ IdHashSet d_assumptionConflicts; // assumption conflicts not actually added to SAT solver
+ IdToConflicts d_assumptionConflictsDebug;
+
// resolutions
IdResMap d_resChains;
ResStack d_resStack;
@@ -132,38 +132,45 @@ protected:
const ClauseId d_emptyClauseId;
const ClauseId d_nullId;
// proxy class to break circular dependencies
- ProofProxy* d_proxy;
+ ProofProxy<Solver>* d_proxy;
// temporary map for updating CRefs
ClauseIdMap d_temp_clauseId;
- IdCRefMap d_temp_idClause;
+ IdCRefMap d_temp_idClause;
// unit conflict
ClauseId d_unitConflictId;
bool d_storedUnitConflict;
+
+ ClauseId d_trueLit;
+ ClauseId d_falseLit;
+
+ std::string d_name;
public:
- SatProof(Minisat::Solver* solver, bool checkRes = false);
- virtual ~SatProof();
+ TSatProof(Solver* solver, const std::string& name, bool checkRes = false);
+ virtual ~TSatProof();
+ void setCnfProof(CnfProof* cnf_proof);
protected:
void print(ClauseId id);
void printRes(ClauseId id);
- void printRes(ResChain* res);
+ void printRes(ResChain<Solver>* res);
bool isInputClause(ClauseId id);
- bool isTheoryConflict(ClauseId id);
bool isLemmaClause(ClauseId id);
+ bool isAssumptionConflict(ClauseId id);
bool isUnit(ClauseId id);
- bool isUnit(Minisat::Lit lit);
+ bool isUnit(typename Solver::TLit lit);
bool hasResolution(ClauseId id);
void createLitSet(ClauseId id, LitSet& set);
- void registerResolution(ClauseId id, ResChain* res);
-
- ClauseId getClauseId(Minisat::CRef clause);
- ClauseId getClauseId(Minisat::Lit lit);
- Minisat::CRef getClauseRef(ClauseId id);
- Minisat::Lit getUnit(ClauseId id);
- ClauseId getUnitId(Minisat::Lit lit);
- Minisat::Clause& getClause(Minisat::CRef ref);
+ void registerResolution(ClauseId id, ResChain<Solver>* res);
+
+ ClauseId getClauseId(typename Solver::TCRef clause);
+ ClauseId getClauseId(typename Solver::TLit lit);
+ typename Solver::TCRef getClauseRef(ClauseId id);
+ typename Solver::TLit getUnit(ClauseId id);
+ ClauseId getUnitId(typename Solver::TLit lit);
+ typename Solver::TClause& getClause(typename Solver::TCRef ref);
+ void getLitVec(ClauseId id, LitVector& vec);
virtual void toStream(std::ostream& out);
bool checkResolution(ClauseId id);
@@ -174,7 +181,7 @@ protected:
*
* @return
*/
- ClauseId resolveUnit(Minisat::Lit lit);
+ ClauseId resolveUnit(typename Solver::TLit lit);
/**
* Does a depth first search on removed literals and adds the literals
* to be removed in the proper order to the stack.
@@ -183,27 +190,35 @@ protected:
* @param removedSet the previously computed set of redundant literals
* @param removeStack the stack of literals in reverse order of resolution
*/
- void removedDfs(Minisat::Lit lit, LitSet* removedSet, LitVector& removeStack, LitSet& inClause, LitSet& seen);
- void removeRedundantFromRes(ResChain* res, ClauseId id);
+ void removedDfs(typename Solver::TLit lit, LitSet* removedSet, LitVector& removeStack, LitSet& inClause, LitSet& seen);
+ void removeRedundantFromRes(ResChain<Solver>* res, ClauseId id);
public:
- void startResChain(Minisat::CRef start);
- void addResolutionStep(Minisat::Lit lit, Minisat::CRef clause, bool sign);
+ void startResChain(typename Solver::TLit start);
+ void startResChain(typename Solver::TCRef start);
+ void addResolutionStep(typename Solver::TLit lit, typename Solver::TCRef clause, bool sign);
/**
* Pops the current resolution of the stack and stores it
* in the resolution map. Also registers the 'clause' parameter
* @param clause the clause the resolution is proving
*/
- void endResChain(Minisat::CRef clause);
- void endResChain(Minisat::Lit lit);
+ //void endResChain(typename Solver::TCRef clause);
+ void endResChain(typename Solver::TLit lit);
+ void endResChain(ClauseId id);
+ /**
+ * Pops the current resolution of the stack *without* storing it.
+ *
+ */
+ void cancelResChain();
+
/**
* Stores in the current derivation the redundant literals that were
* eliminated from the conflict clause during conflict clause minimization.
* @param lit the eliminated literal
*/
- void storeLitRedundant(Minisat::Lit lit);
+ void storeLitRedundant(typename Solver::TLit lit);
/// update the CRef Id maps when Minisat does memory reallocation x
- void updateCRef(Minisat::CRef old_ref, Minisat::CRef new_ref);
+ void updateCRef(typename Solver::TCRef old_ref, typename Solver::TCRef new_ref);
void finishUpdateCRef();
/**
@@ -211,66 +226,142 @@ public:
*
* @param conflict
*/
- void finalizeProof(Minisat::CRef conflict);
+ void finalizeProof(typename Solver::TCRef conflict);
/// clause registration methods
- ClauseId registerClause(const Minisat::CRef clause, ClauseKind kind, uint64_t proof_id);
- ClauseId registerUnitClause(const Minisat::Lit lit, ClauseKind kind, uint64_t proof_id);
-
- void storeUnitConflict(Minisat::Lit lit, ClauseKind kind, uint64_t proof_id);
+ ClauseId registerClause(const typename Solver::TCRef clause,
+ ClauseKind kind);
+ ClauseId registerUnitClause(const typename Solver::TLit lit,
+ ClauseKind kind);
+ void registerTrueLit(const typename Solver::TLit lit);
+ void registerFalseLit(const typename Solver::TLit lit);
+
+ ClauseId getTrueUnit() const;
+ ClauseId getFalseUnit() const;
+
+
+ void registerAssumption(const typename Solver::TVar var);
+ ClauseId registerAssumptionConflict(const typename Solver::TLitVec& confl);
+
+ ClauseId storeUnitConflict(typename Solver::TLit lit,
+ ClauseKind kind);
+
/**
* Marks the deleted clauses as deleted. Note we may still use them in the final
* resolution.
* @param clause
*/
- void markDeleted(Minisat::CRef clause);
+ void markDeleted(typename Solver::TCRef clause);
bool isDeleted(ClauseId id) { return d_deleted.find(id) != d_deleted.end(); }
/**
* Constructs the resolution of ~q and resolves it with the current
* resolution thus eliminating q from the current clause
* @param q the literal to be resolved out
*/
- void resolveOutUnit(Minisat::Lit q);
+ void resolveOutUnit(typename Solver::TLit q);
/**
* Constructs the resolution of the literal lit. Called when a clause
* containing lit becomes satisfied and is removed.
* @param lit
*/
- void storeUnitResolution(Minisat::Lit lit);
-
- ProofProxy* getProxy() {return d_proxy; }
+ void storeUnitResolution(typename Solver::TLit lit);
+ ProofProxy<Solver>* getProxy() {return d_proxy; }
/**
- Constructs the SAT proof identifying the needed lemmas
+ * Constructs the SAT proof for the given clause,
+ * by collecting the needed clauses in the d_seen
+ * data-structures, also notifying the proofmanager.
*/
- void constructProof();
-
+ void constructProof(ClauseId id);
+ void constructProof() {
+ constructProof(d_emptyClauseId);
+ }
+ void collectClauses(ClauseId id);
+ prop::SatClause* buildClause(ClauseId id);
protected:
- IdSet d_seenLearnt;
- IdHashSet d_seenInput;
- IdHashSet d_seenTheoryConflicts;
- IdHashSet d_seenLemmas;
+ IdSet d_seenLearnt;
+ IdToSatClause d_seenInputs;
+ IdToSatClause d_seenLemmas;
+
+ std::string varName(typename Solver::TLit lit);
+ std::string clauseName(ClauseId id);
- inline std::string varName(Minisat::Lit lit);
- inline std::string clauseName(ClauseId id);
- void collectClauses(ClauseId id);
void addToProofManager(ClauseId id, ClauseKind kind);
+ void addToCnfProof(ClauseId id);
public:
+ virtual void printResolution(ClauseId id, std::ostream& out, std::ostream& paren) = 0;
virtual void printResolutions(std::ostream& out, std::ostream& paren) = 0;
-};/* class SatProof */
+ virtual void printResolutionEmptyClause(std::ostream& out, std::ostream& paren) = 0;
+ virtual void printAssumptionsResolution(ClauseId id, std::ostream& out, std::ostream& paren) = 0;
+
-class LFSCSatProof : public SatProof {
+ void collectClausesUsed(IdToSatClause& inputs,
+ IdToSatClause& lemmas);
+
+ void storeClauseGlue(ClauseId clause, int glue);
+
+private:
+ __gnu_cxx::hash_map<ClauseId, int> d_glueMap;
+ struct Statistics {
+ IntStat d_numLearnedClauses;
+ IntStat d_numLearnedInProof;
+ IntStat d_numLemmasInProof;
+ AverageStat d_avgChainLength;
+ HistogramStat<uint64_t> d_resChainLengths;
+ HistogramStat<uint64_t> d_usedResChainLengths;
+ HistogramStat<uint64_t> d_clauseGlue;
+ HistogramStat<uint64_t> d_usedClauseGlue;
+ Statistics(const std::string& name);
+ ~Statistics();
+ };
+
+ Statistics d_statistics;
+};/* class TSatProof */
+
+
+template <class S>
+class ProofProxy {
private:
- void printResolution(ClauseId id, std::ostream& out, std::ostream& paren);
+ TSatProof<S>* d_proof;
public:
- LFSCSatProof(Minisat::Solver* solver, bool checkRes = false)
- : SatProof(solver, checkRes)
+ ProofProxy(TSatProof<S>* pf);
+ void updateCRef(typename S::TCRef oldref, typename S::TCRef newref);
+};/* class ProofProxy */
+
+
+template <class SatSolver>
+class LFSCSatProof : public TSatProof<SatSolver> {
+private:
+
+public:
+ LFSCSatProof(SatSolver* solver, const std::string& name, bool checkRes = false)
+ : TSatProof<SatSolver>(solver, name, checkRes)
{}
+ virtual void printResolution(ClauseId id, std::ostream& out, std::ostream& paren);
virtual void printResolutions(std::ostream& out, std::ostream& paren);
+ virtual void printResolutionEmptyClause(std::ostream& out, std::ostream& paren);
+ virtual void printAssumptionsResolution(ClauseId id, std::ostream& out, std::ostream& paren);
};/* class LFSCSatProof */
+
+
+template<class Solver>
+prop::SatLiteral toSatLiteral(typename Solver::TLit lit);
+
+
+/**
+* Convert from minisat clause to SatClause
+*
+* @param minisat_cl
+* @param sat_cl
+*/
+template<class Solver>
+void toSatClause(const typename Solver::TClause& minisat_cl,
+ prop::SatClause& sat_cl);
+
+
}/* CVC4 namespace */
#endif /* __CVC4__SAT__PROOF_H */
diff --git a/src/proof/sat_proof_implementation.h b/src/proof/sat_proof_implementation.h
new file mode 100644
index 000000000..92645e105
--- /dev/null
+++ b/src/proof/sat_proof_implementation.h
@@ -0,0 +1,1100 @@
+/********************* */
+/*! \file sat_proof_implementation.h
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: Morgan Deters
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Resolution proof
+ **
+ ** Resolution proof
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__SAT__PROOF_IMPLEMENTATION_H
+#define __CVC4__SAT__PROOF_IMPLEMENTATION_H
+
+#include "proof/sat_proof.h"
+#include "proof/cnf_proof.h"
+#include "prop/minisat/minisat.h"
+#include "prop/bvminisat/bvminisat.h"
+#include "prop/minisat/core/Solver.h"
+#include "prop/bvminisat/core/Solver.h"
+#include "prop/sat_solver_types.h"
+#include "smt/smt_statistics_registry.h"
+
+namespace CVC4 {
+
+template <class Solver>
+void printLit (typename Solver::TLit l) {
+ Debug("proof:sat") << (sign(l) ? "-" : "") << var(l) + 1;
+}
+
+template <class Solver>
+void printClause (typename Solver::TClause& c) {
+ for (int i = 0; i < c.size(); i++) {
+ Debug("proof:sat") << (sign(c[i]) ? "-" : "") << var(c[i]) + 1 << " ";
+ }
+}
+
+template <class Solver>
+void printClause (std::vector<typename Solver::TLit>& c) {
+ for (unsigned i = 0; i < c.size(); i++) {
+ Debug("proof:sat") << (sign(c[i]) ? "-" : "") << var(c[i]) + 1 << " ";
+ }
+}
+
+
+template <class Solver>
+void printLitSet(const std::set<typename Solver::TLit>& s) {
+ typename std::set < typename Solver::TLit>::const_iterator it = s.begin();
+ for(; it != s.end(); ++it) {
+ printLit<Solver>(*it);
+ Debug("proof:sat") << " ";
+ }
+ Debug("proof:sat") << std::endl;
+}
+
+// purely debugging functions
+template <class Solver>
+void printDebug (typename Solver::TLit l) {
+ Debug("proof:sat") << (sign(l) ? "-" : "") << var(l) + 1 << std::endl;
+}
+template <class Solver>
+void printDebug (typename Solver::TClause& c) {
+ for (int i = 0; i < c.size(); i++) {
+ Debug("proof:sat") << (sign(c[i]) ? "-" : "") << var(c[i]) + 1 << " ";
+ }
+ Debug("proof:sat") << std::endl;
+}
+
+
+/**
+ * Converts the clause associated to id to a set of literals
+ *
+ * @param id the clause id
+ * @param set the clause converted to a set of literals
+ */
+template <class Solver>
+void TSatProof<Solver>::createLitSet(ClauseId id, LitSet& set) {
+ Assert(set.empty());
+ if(isUnit(id)) {
+ set.insert(getUnit(id));
+ return;
+ }
+ if ( id == d_emptyClauseId) {
+ return;
+ }
+ // if it's an assumption
+ if (d_assumptionConflictsDebug.find(id) != d_assumptionConflictsDebug.end()) {
+ LitVector* clause = d_assumptionConflictsDebug[id];
+ for (unsigned i = 0; i < clause->size(); ++i) {
+ set.insert(clause->operator[](i));
+ }
+ return;
+ }
+
+ typename Solver::TCRef ref = getClauseRef(id);
+ typename Solver::TClause& c = getClause(ref);
+ for (int i = 0; i < c.size(); i++) {
+ set.insert(c[i]);
+ }
+}
+
+
+/**
+ * Resolves clause1 and clause2 on variable var and stores the
+ * result in clause1
+ * @param v
+ * @param clause1
+ * @param clause2
+ */
+template <class Solver>
+bool resolve(const typename Solver::TLit v,
+ std::set<typename Solver::TLit>& clause1,
+ std::set<typename Solver::TLit>& clause2, bool s) {
+ Assert(!clause1.empty());
+ Assert(!clause2.empty());
+ typename Solver::TLit var = sign(v) ? ~v : v;
+ if (s) {
+ // literal appears positive in the first clause
+ if( !clause2.count(~var)) {
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "proof:resolve: Missing literal ";
+ printLit<Solver>(var);
+ Debug("proof:sat") << std::endl;
+ }
+ return false;
+ }
+ clause1.erase(var);
+ clause2.erase(~var);
+ typename std::set<typename Solver::TLit>::iterator it = clause2.begin();
+ for (; it!= clause2.end(); ++it) {
+ clause1.insert(*it);
+ }
+ } else {
+ // literal appears negative in the first clause
+ if( !clause1.count(~var) || !clause2.count(var)) {
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "proof:resolve: Missing literal ";
+ printLit<Solver>(var);
+ Debug("proof:sat") << std::endl;
+ }
+ return false;
+ }
+ clause1.erase(~var);
+ clause2.erase(var);
+ typename std::set<typename Solver::TLit>::iterator it = clause2.begin();
+ for (; it!= clause2.end(); ++it) {
+ clause1.insert(*it);
+ }
+ }
+ return true;
+}
+
+/// ResChain
+template <class Solver>
+ResChain<Solver>::ResChain(ClauseId start) :
+ d_start(start),
+ d_steps(),
+ d_redundantLits(NULL)
+ {}
+template <class Solver>
+void ResChain<Solver>::addStep(typename Solver::TLit lit, ClauseId id, bool sign) {
+ ResStep<Solver> step(lit, id, sign);
+ d_steps.push_back(step);
+}
+
+template <class Solver>
+void ResChain<Solver>::addRedundantLit(typename Solver::TLit lit) {
+ if (d_redundantLits) {
+ d_redundantLits->insert(lit);
+ } else {
+ d_redundantLits = new LitSet();
+ d_redundantLits->insert(lit);
+ }
+}
+
+
+/// ProxyProof
+template <class Solver>
+ProofProxy<Solver>::ProofProxy(TSatProof<Solver>* proof):
+ d_proof(proof)
+{}
+
+template <class Solver>
+void ProofProxy<Solver>::updateCRef(typename Solver::TCRef oldref, typename Solver::TCRef newref) {
+ d_proof->updateCRef(oldref, newref);
+}
+
+
+/// SatProof
+template <class Solver>
+TSatProof<Solver>::TSatProof(Solver* solver, const std::string& name, bool checkRes)
+ : d_solver(solver)
+ , d_cnfProof(NULL)
+ , d_idClause()
+ , d_clauseId()
+ , d_idUnit()
+ , d_deleted()
+ , d_inputClauses()
+ , d_lemmaClauses()
+ , d_assumptions()
+ , d_assumptionConflicts()
+ , d_assumptionConflictsDebug()
+ , d_resChains()
+ , d_resStack()
+ , d_checkRes(checkRes)
+ , d_emptyClauseId(ClauseIdEmpty)
+ , d_nullId(-2)
+ , d_temp_clauseId()
+ , d_temp_idClause()
+ , d_unitConflictId()
+ , d_storedUnitConflict(false)
+ , d_trueLit(ClauseIdUndef)
+ , d_falseLit(ClauseIdUndef)
+ , d_name(name)
+ , d_seenLearnt()
+ , d_seenInputs()
+ , d_seenLemmas()
+ , d_statistics(name)
+{
+ d_proxy = new ProofProxy<Solver>(this);
+}
+
+template <class Solver>
+TSatProof<Solver>::~TSatProof() {
+ delete d_proxy;
+
+ // FIXME: double free if deleted clause also appears in d_seenLemmas?
+ IdToSatClause::iterator it = d_deletedTheoryLemmas.begin();
+ IdToSatClause::iterator end = d_deletedTheoryLemmas.end();
+
+ for (; it != end; ++it) {
+ ClauseId id = it->first;
+ // otherwise deleted in next loop
+ if (d_seenLemmas.find(id) == d_seenLemmas.end())
+ delete it->second;
+ }
+
+ IdToSatClause::iterator seen_it = d_seenLemmas.begin();
+ IdToSatClause::iterator seen_end = d_seenLemmas.end();
+
+ for (; seen_it != seen_end; ++seen_it) {
+ delete seen_it->second;
+ }
+
+ seen_it = d_seenInputs.begin();
+ seen_end = d_seenInputs.end();
+
+ for (; seen_it != seen_end; ++seen_it) {
+ delete seen_it->second;
+ }
+}
+
+template <class Solver>
+void TSatProof<Solver>::setCnfProof(CnfProof* cnf_proof) {
+ Assert (d_cnfProof == NULL);
+ d_cnfProof = cnf_proof;
+}
+
+/**
+ * Returns true if the resolution chain corresponding to id
+ * does resolve to the clause associated to id
+ * @param id
+ *
+ * @return
+ */
+template <class Solver>
+bool TSatProof<Solver>::checkResolution(ClauseId id) {
+ if(d_checkRes) {
+ bool validRes = true;
+ Assert(d_resChains.find(id) != d_resChains.end());
+ ResChain<Solver>* res = d_resChains[id];
+ LitSet clause1;
+ createLitSet(res->getStart(), clause1);
+ typename ResChain<Solver>::ResSteps& steps = res->getSteps();
+ for (unsigned i = 0; i < steps.size(); i++) {
+ typename Solver::TLit var = steps[i].lit;
+ LitSet clause2;
+ createLitSet (steps[i].id, clause2);
+ bool res = resolve<Solver> (var, clause1, clause2, steps[i].sign);
+ if(res == false) {
+ validRes = false;
+ break;
+ }
+ }
+ // compare clause we claimed to prove with the resolution result
+ if (isUnit(id)) {
+ // special case if it was a unit clause
+ typename Solver::TLit unit = getUnit(id);
+ validRes = clause1.size() == clause1.count(unit) && !clause1.empty();
+ return validRes;
+ }
+ if (id == d_emptyClauseId) {
+ return clause1.empty();
+ }
+
+ LitVector c;
+ getLitVec(id, c);
+
+ for (unsigned i = 0; i < c.size(); ++i) {
+ int count = clause1.erase(c[i]);
+ if (count == 0) {
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "proof:checkResolution::literal not in computed result ";
+ printLit<Solver>(c[i]);
+ Debug("proof:sat") << "\n";
+ }
+ validRes = false;
+ }
+ }
+ validRes = clause1.empty();
+ if (! validRes) {
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "proof:checkResolution::Invalid Resolution, unremoved literals: \n";
+ printLitSet<Solver>(clause1);
+ Debug("proof:sat") << "proof:checkResolution:: result should be: \n";
+ printClause<Solver>(c);
+ }
+ }
+ return validRes;
+
+ } else {
+ return true;
+ }
+}
+
+
+
+
+/// helper methods
+template <class Solver>
+ClauseId TSatProof<Solver>::getClauseId(typename Solver::TCRef ref) {
+ if(d_clauseId.find(ref) == d_clauseId.end()) {
+ Debug("proof:sat") << "Missing clause \n";
+ }
+ Assert(d_clauseId.find(ref) != d_clauseId.end());
+ return d_clauseId[ref];
+}
+
+template <class Solver>
+ClauseId TSatProof<Solver>::getClauseId(typename Solver::TLit lit) {
+ Assert(d_unitId.find(toInt(lit)) != d_unitId.end());
+ return d_unitId[toInt(lit)];
+}
+template <class Solver>
+typename Solver::TCRef TSatProof<Solver>::getClauseRef(ClauseId id) {
+ if (d_idClause.find(id) == d_idClause.end()) {
+ Debug("proof:sat") << "proof:getClauseRef cannot find clause "<<id<<" "
+ << ((d_deleted.find(id) != d_deleted.end()) ? "deleted" : "")
+ << (isUnit(id)? "Unit" : "") << std::endl;
+ }
+ Assert(d_idClause.find(id) != d_idClause.end());
+ return d_idClause[id];
+}
+
+template <class Solver>
+typename Solver::TClause& TSatProof<Solver>::getClause(typename Solver::TCRef ref) {
+ Assert(ref != Solver::TCRef_Undef);
+ Assert(ref >= 0 && ref < d_solver->ca.size());
+ return d_solver->ca[ref];
+}
+
+template <class Solver>
+void TSatProof<Solver>::getLitVec(ClauseId id, LitVector& vec) {
+ if (isUnit(id)) {
+ typename Solver::TLit lit = getUnit(id);
+ vec.push_back(lit);
+ return;
+ }
+ if (isAssumptionConflict(id)) {
+ vec = *(d_assumptionConflictsDebug[id]);
+ return;
+ }
+ typename Solver::TCRef cref = getClauseRef(id);
+ typename Solver::TClause& cl = getClause(cref);
+ for (int i = 0; i < cl.size(); ++i) {
+ vec.push_back(cl[i]);
+ }
+}
+
+
+template <class Solver>
+typename Solver::TLit TSatProof<Solver>::getUnit(ClauseId id) {
+ Assert(d_idUnit.find(id) != d_idUnit.end());
+ return d_idUnit[id];
+}
+template <class Solver>
+bool TSatProof<Solver>::isUnit(ClauseId id) {
+ return d_idUnit.find(id) != d_idUnit.end();
+}
+template <class Solver>
+bool TSatProof<Solver>::isUnit(typename Solver::TLit lit) {
+ return d_unitId.find(toInt(lit)) != d_unitId.end();
+}
+template <class Solver>
+ClauseId TSatProof<Solver>::getUnitId(typename Solver::TLit lit) {
+ Assert(isUnit(lit));
+ return d_unitId[toInt(lit)];
+}
+template <class Solver>
+bool TSatProof<Solver>::hasResolution(ClauseId id) {
+ return d_resChains.find(id) != d_resChains.end();
+}
+template <class Solver>
+bool TSatProof<Solver>::isInputClause(ClauseId id) {
+ return (d_inputClauses.find(id) != d_inputClauses.end());
+}
+template <class Solver>
+bool TSatProof<Solver>::isLemmaClause(ClauseId id) {
+ return (d_lemmaClauses.find(id) != d_lemmaClauses.end());
+}
+
+template <class Solver>
+bool TSatProof<Solver>::isAssumptionConflict(ClauseId id) {
+ return d_assumptionConflicts.find(id) != d_assumptionConflicts.end();
+}
+
+
+template <class Solver>
+void TSatProof<Solver>::print(ClauseId id) {
+ if (d_deleted.find(id) != d_deleted.end()) {
+ Debug("proof:sat") << "del"<<id;
+ } else if (isUnit(id)) {
+ printLit<Solver>(getUnit(id));
+ } else if (id == d_emptyClauseId) {
+ Debug("proof:sat") << "empty "<< std::endl;
+ }
+ else {
+ typename Solver::TCRef ref = getClauseRef(id);
+ printClause<Solver>(getClause(ref));
+ }
+}
+template <class Solver>
+void TSatProof<Solver>::printRes(ClauseId id) {
+ Assert(hasResolution(id));
+ Debug("proof:sat") << "id "<< id <<": ";
+ printRes(d_resChains[id]);
+}
+template <class Solver>
+void TSatProof<Solver>::printRes(ResChain<Solver>* res) {
+ ClauseId start_id = res->getStart();
+
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "(";
+ print(start_id);
+ }
+
+ typename ResChain<Solver>::ResSteps& steps = res->getSteps();
+ for(unsigned i = 0; i < steps.size(); i++ ) {
+ typename Solver::TLit v = steps[i].lit;
+ ClauseId id = steps[i].id;
+
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "[";
+ printLit<Solver>(v);
+ Debug("proof:sat") << "] ";
+ print(id);
+ }
+ }
+ Debug("proof:sat") << ") \n";
+}
+
+/// registration methods
+template <class Solver>
+ ClauseId TSatProof<Solver>::registerClause(typename Solver::TCRef clause,
+ ClauseKind kind) {
+ Assert(clause != Solver::TCRef_Undef);
+ typename ClauseIdMap::iterator it = d_clauseId.find(clause);
+ if (it == d_clauseId.end()) {
+ ClauseId newId = ProofManager::currentPM()->nextId();
+ d_clauseId.insert(std::make_pair(clause, newId));
+ d_idClause.insert(std::make_pair(newId, clause));
+ if (kind == INPUT) {
+ Assert(d_inputClauses.find(newId) == d_inputClauses.end());
+ d_inputClauses.insert(newId);
+ }
+ if (kind == THEORY_LEMMA) {
+ Assert(d_lemmaClauses.find(newId) == d_lemmaClauses.end());
+ d_lemmaClauses.insert(newId);
+ }
+ }
+
+ ClauseId id = d_clauseId[clause];
+ Assert(kind != INPUT || d_inputClauses.count(id));
+ Assert(kind != THEORY_LEMMA || d_lemmaClauses.count(id));
+
+ Debug("proof:sat:detailed") << "registerClause CRef: " << clause << " id: " << d_clauseId[clause]
+ <<" kind: " << kind << "\n";
+ //ProofManager::currentPM()->setRegisteredClauseId( d_clauseId[clause] );
+ return id;
+}
+
+template <class Solver>
+ClauseId TSatProof<Solver>::registerUnitClause(typename Solver::TLit lit,
+ ClauseKind kind) {
+ Debug("cores") << "registerUnitClause " << kind << std::endl;
+ typename UnitIdMap::iterator it = d_unitId.find(toInt(lit));
+ if (it == d_unitId.end()) {
+ ClauseId newId = ProofManager::currentPM()->nextId();
+ d_unitId.insert(std::make_pair(toInt(lit), newId));
+ d_idUnit.insert(std::make_pair(newId, lit));
+
+ if (kind == INPUT) {
+ Assert(d_inputClauses.find(newId) == d_inputClauses.end());
+ d_inputClauses.insert(newId);
+ }
+ if (kind == THEORY_LEMMA) {
+ Assert(d_lemmaClauses.find(newId) == d_lemmaClauses.end());
+ d_lemmaClauses.insert(newId);
+ }
+ }
+ ClauseId id = d_unitId[toInt(lit)];
+ Assert(kind != INPUT || d_inputClauses.count(id));
+ Assert(kind != THEORY_LEMMA || d_lemmaClauses.count(id));
+ Debug("proof:sat:detailed") << "registerUnitClause id: " << id
+ <<" kind: " << kind << "\n";
+ // ProofManager::currentPM()->setRegisteredClauseId( d_unitId[toInt(lit)] );
+ return id;
+}
+template <class Solver>
+void TSatProof<Solver>::registerTrueLit(const typename Solver::TLit lit) {
+ Assert (d_trueLit == ClauseIdUndef);
+ d_trueLit = registerUnitClause(lit, INPUT);
+}
+
+template <class Solver>
+void TSatProof<Solver>::registerFalseLit(const typename Solver::TLit lit) {
+ Assert (d_falseLit == ClauseIdUndef);
+ d_falseLit = registerUnitClause(lit, INPUT);
+}
+
+template <class Solver>
+ClauseId TSatProof<Solver>::getTrueUnit() const {
+ Assert (d_trueLit != ClauseIdUndef);
+ return d_trueLit;
+}
+
+template <class Solver>
+ClauseId TSatProof<Solver>::getFalseUnit() const {
+ Assert (d_falseLit != ClauseIdUndef);
+ return d_falseLit;
+}
+
+
+template <class Solver>
+void TSatProof<Solver>::registerAssumption(const typename Solver::TVar var) {
+ Assert (d_assumptions.find(var) == d_assumptions.end());
+ d_assumptions.insert(var);
+}
+
+template <class Solver>
+ClauseId TSatProof<Solver>::registerAssumptionConflict(const typename Solver::TLitVec& confl) {
+ Debug("proof:sat:detailed") << "registerAssumptionConflict " << std::endl;
+ // Uniqueness is checked in the bit-vector proof
+ // should be vars
+ for (int i = 0; i < confl.size(); ++i) {
+ Assert (d_assumptions.find(var(confl[i])) != d_assumptions.end());
+ }
+ ClauseId new_id = ProofManager::currentPM()->nextId();
+ d_assumptionConflicts.insert(new_id);
+ LitVector* vec_confl = new LitVector(confl.size());
+ for (int i = 0; i < confl.size(); ++i) {
+ vec_confl->operator[](i) = confl[i];
+ }
+ if (Debug.isOn("proof:sat:detailed")) {
+ printClause<Solver>(*vec_confl);
+ Debug("proof:sat:detailed") << "\n";
+ }
+
+ d_assumptionConflictsDebug[new_id] = vec_confl;
+ return new_id;
+}
+
+
+template <class Solver>
+void TSatProof<Solver>::removedDfs(typename Solver::TLit lit, LitSet* removedSet, LitVector& removeStack, LitSet& inClause, LitSet& seen) {
+ // if we already added the literal return
+ if (seen.count(lit)) {
+ return;
+ }
+
+ typename Solver::TCRef reason_ref = d_solver->reason(var(lit));
+ if (reason_ref == Solver::TCRef_Undef) {
+ seen.insert(lit);
+ removeStack.push_back(lit);
+ return;
+ }
+
+ int size = getClause(reason_ref).size();
+ for (int i = 1; i < size; i++ ) {
+ typename Solver::TLit v = getClause(reason_ref)[i];
+ if(inClause.count(v) == 0 && seen.count(v) == 0) {
+ removedDfs(v, removedSet, removeStack, inClause, seen);
+ }
+ }
+ if(seen.count(lit) == 0) {
+ seen.insert(lit);
+ removeStack.push_back(lit);
+ }
+}
+
+template <class Solver>
+void TSatProof<Solver>::removeRedundantFromRes(ResChain<Solver>* res, ClauseId id) {
+ LitSet* removed = res->getRedundant();
+ if (removed == NULL) {
+ return;
+ }
+
+ LitSet inClause;
+ createLitSet(id, inClause);
+
+ LitVector removeStack;
+ LitSet seen;
+ for (typename LitSet::iterator it = removed->begin(); it != removed->end(); ++it) {
+ removedDfs(*it, removed, removeStack, inClause, seen);
+ }
+
+ for (int i = removeStack.size()-1; i >= 0; --i) {
+ typename Solver::TLit lit = removeStack[i];
+ typename Solver::TCRef reason_ref = d_solver->reason(var(lit));
+ ClauseId reason_id;
+
+ if (reason_ref == Solver::TCRef_Undef) {
+ Assert(isUnit(~lit));
+ reason_id = getUnitId(~lit);
+ } else {
+ reason_id = registerClause(reason_ref, LEARNT);
+ }
+ res->addStep(lit, reason_id, !sign(lit));
+ }
+ removed->clear();
+}
+
+template <class Solver>
+void TSatProof<Solver>::registerResolution(ClauseId id, ResChain<Solver>* res) {
+ Assert(res != NULL);
+
+ removeRedundantFromRes(res, id);
+ Assert(res->redundantRemoved());
+
+ d_resChains[id] = res;
+ if(Debug.isOn("proof:sat")) {
+ printRes(id);
+ }
+ if(d_checkRes) {
+ Assert(checkResolution(id));
+ }
+
+ PSTATS(
+ d_statistics.d_resChainLengths << ((uint64_t)res->getSteps().size());
+ d_statistics.d_avgChainLength.addEntry((uint64_t)res->getSteps().size());
+ ++(d_statistics.d_numLearnedClauses);
+ )
+}
+
+
+/// recording resolutions
+template <class Solver>
+void TSatProof<Solver>::startResChain(typename Solver::TCRef start) {
+ ClauseId id = getClauseId(start);
+ ResChain<Solver>* res = new ResChain<Solver>(id);
+ d_resStack.push_back(res);
+}
+
+template <class Solver>
+void TSatProof<Solver>::startResChain(typename Solver::TLit start) {
+ ClauseId id = getUnitId(start);
+ ResChain<Solver>* res = new ResChain<Solver>(id);
+ d_resStack.push_back(res);
+}
+
+
+template <class Solver>
+void TSatProof<Solver>::addResolutionStep(typename Solver::TLit lit,
+ typename Solver::TCRef clause, bool sign) {
+ ClauseId id = registerClause(clause, LEARNT);
+ ResChain<Solver>* res = d_resStack.back();
+ res->addStep(lit, id, sign);
+}
+
+template <class Solver>
+void TSatProof<Solver>::endResChain(ClauseId id) {
+ Debug("proof:sat:detailed") <<"endResChain " << id << "\n";
+ Assert(d_resStack.size() > 0);
+ ResChain<Solver>* res = d_resStack.back();
+ registerResolution(id, res);
+ d_resStack.pop_back();
+}
+
+
+// template <class Solver>
+// void TSatProof<Solver>::endResChain(typename Solver::TCRef clause) {
+// Assert(d_resStack.size() > 0);
+// ClauseId id = registerClause(clause, LEARNT);
+// ResChain<Solver>* res = d_resStack.back();
+// registerResolution(id, res);
+// d_resStack.pop_back();
+// }
+
+template <class Solver>
+void TSatProof<Solver>::endResChain(typename Solver::TLit lit) {
+ Assert(d_resStack.size() > 0);
+ ClauseId id = registerUnitClause(lit, LEARNT);
+ Debug("proof:sat:detailed") <<"endResChain unit " << id << "\n";
+ ResChain<Solver>* res = d_resStack.back();
+ d_glueMap[id] = 1;
+ registerResolution(id, res);
+ d_resStack.pop_back();
+}
+
+
+template <class Solver>
+void TSatProof<Solver>::cancelResChain() {
+ Assert(d_resStack.size() > 0);
+ d_resStack.pop_back();
+}
+
+
+template <class Solver>
+void TSatProof<Solver>::storeLitRedundant(typename Solver::TLit lit) {
+ Assert(d_resStack.size() > 0);
+ ResChain<Solver>* res = d_resStack.back();
+ res->addRedundantLit(lit);
+}
+
+/// constructing resolutions
+template <class Solver>
+void TSatProof<Solver>::resolveOutUnit(typename Solver::TLit lit) {
+ ClauseId id = resolveUnit(~lit);
+ ResChain<Solver>* res = d_resStack.back();
+ res->addStep(lit, id, !sign(lit));
+}
+template <class Solver>
+void TSatProof<Solver>::storeUnitResolution(typename Solver::TLit lit) {
+ Debug("cores") << "STORE UNIT RESOLUTION" << std::endl;
+ resolveUnit(lit);
+}
+template <class Solver>
+ClauseId TSatProof<Solver>::resolveUnit(typename Solver::TLit lit) {
+ // first check if we already have a resolution for lit
+ if(isUnit(lit)) {
+ ClauseId id = getClauseId(lit);
+ Assert(hasResolution(id) || isInputClause(id) || isLemmaClause(id));
+ return id;
+ }
+ typename Solver::TCRef reason_ref = d_solver->reason(var(lit));
+ Assert(reason_ref != Solver::TCRef_Undef);
+
+ ClauseId reason_id = registerClause(reason_ref, LEARNT);
+
+ ResChain<Solver>* res = new ResChain<Solver>(reason_id);
+ // Here, the call to resolveUnit() can reallocate memory in the
+ // clause allocator. So reload reason ptr each time.
+ typename Solver::TClause* reason = &getClause(reason_ref);
+ for (int i = 0;
+ i < reason->size();
+ i++, reason = &getClause(reason_ref)) {
+ typename Solver::TLit l = (*reason)[i];
+ if(lit != l) {
+ ClauseId res_id = resolveUnit(~l);
+ res->addStep(l, res_id, !sign(l));
+ }
+ }
+ ClauseId unit_id = registerUnitClause(lit, LEARNT);
+ registerResolution(unit_id, res);
+ return unit_id;
+}
+template <class Solver>
+void TSatProof<Solver>::toStream(std::ostream& out) {
+ Debug("proof:sat") << "TSatProof<Solver>::printProof\n";
+ Unimplemented("native proof printing not supported yet");
+}
+template <class Solver>
+ClauseId TSatProof<Solver>::storeUnitConflict(typename Solver::TLit conflict_lit,
+ ClauseKind kind) {
+ Debug("cores") << "STORE UNIT CONFLICT" << std::endl;
+ Assert(!d_storedUnitConflict);
+ d_unitConflictId = registerUnitClause(conflict_lit, kind);
+ d_storedUnitConflict = true;
+ Debug("proof:sat:detailed") <<"storeUnitConflict " << d_unitConflictId << "\n";
+ return d_unitConflictId;
+}
+template <class Solver>
+void TSatProof<Solver>::finalizeProof(typename Solver::TCRef conflict_ref) {
+ Assert(d_resStack.size() == 0);
+ Assert(conflict_ref != Solver::TCRef_Undef);
+ ClauseId conflict_id;
+ if (conflict_ref == Solver::TCRef_Lazy) {
+ Assert(d_storedUnitConflict);
+ conflict_id = d_unitConflictId;
+
+ ResChain<Solver>* res = new ResChain<Solver>(conflict_id);
+ typename Solver::TLit lit = d_idUnit[conflict_id];
+ ClauseId res_id = resolveUnit(~lit);
+ res->addStep(lit, res_id, !sign(lit));
+
+ registerResolution(d_emptyClauseId, res);
+
+ return;
+ } else {
+ Assert(!d_storedUnitConflict);
+ conflict_id = registerClause(conflict_ref, LEARNT); //FIXME
+ }
+
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "proof::finalizeProof Final Conflict ";
+ print(conflict_id);
+ }
+
+ ResChain<Solver>* res = new ResChain<Solver>(conflict_id);
+ // Here, the call to resolveUnit() can reallocate memory in the
+ // clause allocator. So reload conflict ptr each time.
+ typename Solver::TClause* conflict = &getClause(conflict_ref);
+ for (int i = 0;
+ i < conflict->size();
+ ++i, conflict = &getClause(conflict_ref)) {
+ typename Solver::TLit lit = (*conflict)[i];
+ ClauseId res_id = resolveUnit(~lit);
+ res->addStep(lit, res_id, !sign(lit));
+ }
+ registerResolution(d_emptyClauseId, res);
+}
+
+/// CRef manager
+template <class Solver>
+void TSatProof<Solver>::updateCRef(typename Solver::TCRef oldref,
+ typename Solver::TCRef newref) {
+ if (d_clauseId.find(oldref) == d_clauseId.end()) {
+ return;
+ }
+ ClauseId id = getClauseId(oldref);
+ Assert(d_temp_clauseId.find(newref) == d_temp_clauseId.end());
+ Assert(d_temp_idClause.find(id) == d_temp_idClause.end());
+ d_temp_clauseId[newref] = id;
+ d_temp_idClause[id] = newref;
+}
+template <class Solver>
+void TSatProof<Solver>::finishUpdateCRef() {
+ d_clauseId.swap(d_temp_clauseId);
+ d_temp_clauseId.clear();
+
+ d_idClause.swap(d_temp_idClause);
+ d_temp_idClause.clear();
+}
+template <class Solver>
+void TSatProof<Solver>::markDeleted(typename Solver::TCRef clause) {
+ if (d_clauseId.find(clause) != d_clauseId.end()) {
+ ClauseId id = getClauseId(clause);
+ Assert(d_deleted.find(id) == d_deleted.end());
+ d_deleted.insert(id);
+ if (isLemmaClause(id)) {
+ const typename Solver::TClause& minisat_cl = getClause(clause);
+ prop::SatClause* sat_cl = new prop::SatClause();
+ toSatClause<Solver>(minisat_cl, *sat_cl);
+ d_deletedTheoryLemmas.insert(std::make_pair(id, sat_cl));
+ }
+ }
+}
+
+// template<>
+// void toSatClause< ::BVMinisat::Solver> (const BVMinisat::Solver::TClause& minisat_cl,
+// prop::SatClause& sat_cl) {
+
+// prop::BVMinisatSatSolver::toSatClause(minisat_cl, sat_cl);
+// }
+
+
+
+template <class Solver>
+void TSatProof<Solver>::constructProof(ClauseId conflict) {
+ collectClauses(conflict);
+}
+
+template <class Solver>
+std::string TSatProof<Solver>::clauseName(ClauseId id) {
+ std::ostringstream os;
+ if (isInputClause(id)) {
+ os << ProofManager::getInputClauseName(id, d_name);
+ return os.str();
+ } else
+ if (isLemmaClause(id)) {
+ os << ProofManager::getLemmaClauseName(id, d_name);
+ return os.str();
+ }else {
+ os << ProofManager::getLearntClauseName(id, d_name);
+ return os.str();
+ }
+}
+
+template <class Solver>
+prop::SatClause* TSatProof<Solver>::buildClause(ClauseId id) {
+ if (isUnit(id)) {
+ typename Solver::TLit lit = getUnit(id);
+ prop::SatLiteral sat_lit = toSatLiteral<Solver>(lit);
+ prop::SatClause* clause = new prop::SatClause();
+ clause->push_back(sat_lit);
+ return clause;
+ }
+
+ if (isDeleted(id)) {
+ prop::SatClause* clause = d_deletedTheoryLemmas.find(id)->second;
+ return clause;
+ }
+
+ typename Solver::TCRef ref = getClauseRef(id);
+ const typename Solver::TClause& minisat_cl = getClause(ref);
+ prop::SatClause* clause = new prop::SatClause();
+ toSatClause<Solver>(minisat_cl, *clause);
+ return clause;
+}
+
+template <class Solver>
+void TSatProof<Solver>::collectClauses(ClauseId id) {
+ if (d_seenInputs.find(id) != d_seenInputs.end() ||
+ d_seenLemmas.find(id) != d_seenLemmas.end() ||
+ d_seenLearnt.find(id) != d_seenLearnt.end()) {
+ return;
+ }
+
+ if (isInputClause(id)) {
+ d_seenInputs.insert(std::make_pair(id, buildClause(id)));
+ return;
+ } else if (isLemmaClause(id)) {
+ d_seenLemmas.insert(std::make_pair(id, buildClause(id)));
+ return;
+ } else if (!isAssumptionConflict(id)) {
+ d_seenLearnt.insert(id);
+ }
+
+ Assert(d_resChains.find(id) != d_resChains.end());
+ ResChain<Solver>* res = d_resChains[id];
+ PSTATS(
+ d_statistics.d_usedResChainLengths << ((uint64_t)res->getSteps().size());
+ d_statistics.d_usedClauseGlue << ((uint64_t) d_glueMap[id]);
+ );
+ ClauseId start = res->getStart();
+ collectClauses(start);
+
+ typename ResChain<Solver>::ResSteps steps = res->getSteps();
+ for(size_t i = 0; i < steps.size(); i++) {
+ collectClauses(steps[i].id);
+ }
+}
+
+template <class Solver>
+void TSatProof<Solver>::collectClausesUsed(IdToSatClause& inputs,
+ IdToSatClause& lemmas) {
+ inputs = d_seenInputs;
+ lemmas = d_seenLemmas;
+ PSTATS (
+ d_statistics.d_numLearnedInProof.setData(d_seenLearnt.size());
+ d_statistics.d_numLemmasInProof.setData(d_seenLemmas.size());
+ );
+}
+
+template <class Solver>
+void TSatProof<Solver>::storeClauseGlue(ClauseId clause, int glue) {
+ Assert (d_glueMap.find(clause) == d_glueMap.end());
+ d_glueMap.insert(std::make_pair(clause, glue));
+}
+
+template <class Solver>
+TSatProof<Solver>::Statistics::Statistics(const std::string& prefix)
+ : d_numLearnedClauses("satproof::"+prefix+"::NumLearnedClauses", 0)
+ , d_numLearnedInProof("satproof::"+prefix+"::NumLearnedInProof", 0)
+ , d_numLemmasInProof("satproof::"+prefix+"::NumLemmasInProof", 0)
+ , d_avgChainLength("satproof::"+prefix+"::AvgResChainLength")
+ , d_resChainLengths("satproof::"+prefix+"::ResChainLengthsHist")
+ , d_usedResChainLengths("satproof::"+prefix+"::UsedResChainLengthsHist")
+ , d_clauseGlue("satproof::"+prefix+"::ClauseGlueHist")
+ , d_usedClauseGlue("satproof::"+prefix+"::UsedClauseGlueHist") {
+ smtStatisticsRegistry()->registerStat(&d_numLearnedClauses);
+ smtStatisticsRegistry()->registerStat(&d_numLearnedInProof);
+ smtStatisticsRegistry()->registerStat(&d_numLemmasInProof);
+ smtStatisticsRegistry()->registerStat(&d_avgChainLength);
+ smtStatisticsRegistry()->registerStat(&d_resChainLengths);
+ smtStatisticsRegistry()->registerStat(&d_usedResChainLengths);
+ smtStatisticsRegistry()->registerStat(&d_clauseGlue);
+ smtStatisticsRegistry()->registerStat(&d_usedClauseGlue);
+}
+
+template <class Solver>
+TSatProof<Solver>::Statistics::~Statistics() {
+ smtStatisticsRegistry()->unregisterStat(&d_numLearnedClauses);
+ smtStatisticsRegistry()->unregisterStat(&d_numLearnedInProof);
+ smtStatisticsRegistry()->unregisterStat(&d_numLemmasInProof);
+ smtStatisticsRegistry()->unregisterStat(&d_avgChainLength);
+ smtStatisticsRegistry()->unregisterStat(&d_resChainLengths);
+ smtStatisticsRegistry()->unregisterStat(&d_usedResChainLengths);
+ smtStatisticsRegistry()->unregisterStat(&d_clauseGlue);
+ smtStatisticsRegistry()->unregisterStat(&d_usedClauseGlue);
+}
+
+
+/// LFSCSatProof class
+template <class Solver>
+void LFSCSatProof<Solver>::printResolution(ClauseId id, std::ostream& out, std::ostream& paren) {
+ out << "(satlem_simplify _ _ _ ";
+
+ ResChain<Solver>* res = this->d_resChains[id];
+ typename ResChain<Solver>::ResSteps& steps = res->getSteps();
+
+ for (int i = steps.size()-1; i >= 0; i--) {
+ out << "(";
+ out << (steps[i].sign? "R" : "Q") << " _ _ ";
+ }
+
+ ClauseId start_id = res->getStart();
+ out << this->clauseName(start_id) << " ";
+
+ for(unsigned i = 0; i < steps.size(); i++) {
+ prop::SatVariable v = prop::MinisatSatSolver::toSatVariable(var(steps[i].lit));
+ out << this->clauseName(steps[i].id) << " "<<ProofManager::getVarName(v, this->d_name) <<")";
+ }
+
+ if (id == this->d_emptyClauseId) {
+ out <<"(\\empty empty)";
+ return;
+ }
+
+ out << "(\\" << this->clauseName(id) << "\n"; // bind to lemma name
+ paren << "))"; // closing parethesis for lemma binding and satlem
+}
+
+/// LFSCSatProof class
+template <class Solver>
+void LFSCSatProof<Solver>::printAssumptionsResolution(ClauseId id, std::ostream& out, std::ostream& paren) {
+ Assert (this->isAssumptionConflict(id));
+ // print the resolution proving the assumption conflict
+ printResolution(id, out, paren);
+ // resolve out assumptions to prove empty clause
+ out << "(satlem_simplify _ _ _ ";
+ std::vector<typename Solver::TLit>& confl = *(this->d_assumptionConflictsDebug[id]);
+
+ Assert (confl.size());
+
+ for (unsigned i = 0; i < confl.size(); ++i) {
+ prop::SatLiteral lit = toSatLiteral<Solver>(confl[i]);
+ out <<"(";
+ out << (lit.isNegated() ? "Q" : "R") <<" _ _ ";
+ }
+
+ out << this->clauseName(id)<< " ";
+ for (int i = confl.size() - 1; i >= 0; --i) {
+ prop::SatLiteral lit = toSatLiteral<Solver>(confl[i]);
+ prop::SatVariable v = lit.getSatVariable();
+ out << "unit"<< v <<" ";
+ out << ProofManager::getVarName(v, this->d_name) <<")";
+ }
+ out <<"(\\ e e)\n";
+ paren <<")";
+}
+
+
+template <class Solver>
+void LFSCSatProof<Solver>::printResolutions(std::ostream& out, std::ostream& paren) {
+ Debug("bv-proof") << "; print resolutions" << std::endl;
+ std::set<ClauseId>::iterator it = this->d_seenLearnt.begin();
+ for(; it!= this->d_seenLearnt.end(); ++it) {
+ if(*it != this->d_emptyClauseId) {
+ Debug("bv-proof") << "; print resolution for " << *it << std::endl;
+ printResolution(*it, out, paren);
+ }
+ }
+ Debug("bv-proof") << "; done print resolutions" << std::endl;
+}
+
+template <class Solver>
+void LFSCSatProof<Solver>::printResolutionEmptyClause(std::ostream& out, std::ostream& paren) {
+ printResolution(this->d_emptyClauseId, out, paren);
+}
+
+
+inline std::ostream& operator<<(std::ostream& out, CVC4::ClauseKind k) {
+ switch(k) {
+ case CVC4::INPUT:
+ out << "INPUT";
+ break;
+ case CVC4::THEORY_LEMMA:
+ out << "THEORY_LEMMA";
+ break;
+ case CVC4::LEARNT:
+ out << "LEARNT";
+ break;
+ default:
+ out << "ClauseKind Unknown! [" << unsigned(k) << "]";
+ }
+
+ return out;
+}
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__SAT__PROOF_IMPLEMENTATION_H */
diff --git a/src/proof/theory_proof.cpp b/src/proof/theory_proof.cpp
index 6982509b1..b0d6988a5 100644
--- a/src/proof/theory_proof.cpp
+++ b/src/proof/theory_proof.cpp
@@ -15,145 +15,455 @@
** \todo document this file
**/
-#include "proof/theory_proof.h"
+#include "base/cvc4_assert.h"
+#include "context/context.h"
+#include "options/bv_options.h"
+#include "proof/array_proof.h"
+#include "proof/bitvector_proof.h"
+#include "proof/cnf_proof.h"
+#include "proof/cnf_proof.h"
#include "proof/proof_manager.h"
-using namespace CVC4;
+#include "proof/proof_utils.h"
+#include "proof/sat_proof.h"
+#include "proof/theory_proof.h"
+#include "proof/uf_proof.h"
+#include "prop/sat_solver_types.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_scope.h"
+#include "smt_util/node_visitor.h"
+#include "theory/arrays/theory_arrays.h"
+#include "theory/bv/theory_bv.h"
+#include "theory/output_channel.h"
+#include "theory/term_registration_visitor.h"
+#include "theory/uf/equality_engine.h"
+#include "theory/uf/theory_uf.h"
+#include "theory/valuation.h"
+#include "util/hash.h"
+#include "util/proof.h"
-TheoryProof::TheoryProof()
- : d_termDeclarations()
- , d_sortDeclarations()
- , d_declarationCache()
-{}
-void TheoryProof::addDeclaration(Expr term) {
- if (d_declarationCache.count(term)) {
- return;
- }
+namespace CVC4 {
+
+unsigned CVC4::LetCount::counter = 0;
+static unsigned LET_COUNT = 1;
+
+//for proof replay
+class ProofOutputChannel : public theory::OutputChannel {
+public:
+ Node d_conflict;
+ Proof* d_proof;
+ Node d_lemma;
- Type type = term.getType();
- if (type.isSort())
- d_sortDeclarations.insert(type);
- if (term.getKind() == kind::APPLY_UF) {
- Expr function = term.getOperator();
- d_termDeclarations.insert(function);
- } else if (term.isVariable()) {
- //Assert (type.isSort() || type.isBoolean());
- d_termDeclarations.insert(term);
+ ProofOutputChannel() : d_conflict(), d_proof(NULL) {}
+
+ void conflict(TNode n, Proof* pf) throw() {
+ Trace("theory-proof-debug") << "; CONFLICT: " << n << std::endl;
+ Assert(d_conflict.isNull());
+ Assert(!n.isNull());
+ d_conflict = n;
+ Assert(pf != NULL);
+ d_proof = pf;
}
- // recursively declare all other terms
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- addDeclaration(term[i]);
+ bool propagate(TNode x) throw() {
+ Trace("theory-proof-debug") << "got a propagation: " << x << std::endl;
+ return true;
+ }
+ theory::LemmaStatus lemma(TNode n, ProofRule rule, bool, bool, bool) throw() {
+ Trace("theory-proof-debug") << "new lemma: " << n << std::endl;
+ d_lemma = n;
+ return theory::LemmaStatus(TNode::null(), 0);
+ }
+ theory::LemmaStatus splitLemma(TNode, bool) throw() {
+ AlwaysAssert(false);
+ return theory::LemmaStatus(TNode::null(), 0);
+ }
+ void requirePhase(TNode n, bool b) throw() {
+ Trace("theory-proof-debug") << "requirePhase " << n << " " << b << std::endl;
+ }
+ bool flipDecision() throw() {
+ AlwaysAssert(false);
+ return false;
+ }
+ void setIncomplete() throw() {
+ AlwaysAssert(false);
}
- d_declarationCache.insert(term);
+};/* class ProofOutputChannel */
+
+//for proof replay
+class MyPreRegisterVisitor {
+ theory::Theory* d_theory;
+ __gnu_cxx::hash_set<TNode, TNodeHashFunction> d_visited;
+public:
+ typedef void return_type;
+ MyPreRegisterVisitor(theory::Theory* theory)
+ : d_theory(theory)
+ , d_visited()
+ {}
+ bool alreadyVisited(TNode current, TNode parent) { return d_visited.find(current) != d_visited.end(); }
+ void visit(TNode current, TNode parent) {
+ if(theory::Theory::theoryOf(current) == d_theory->getId()) {
+ //Trace("theory-proof-debug") << "preregister " << current << std::endl;
+ d_theory->preRegisterTerm(current);
+ d_visited.insert(current);
+ }
+ }
+ void start(TNode node) { }
+ void done(TNode node) { }
+}; /* class MyPreRegisterVisitor */
+
+TheoryProofEngine::TheoryProofEngine(SmtGlobals* globals)
+ : d_registrationCache()
+ , d_theoryProofTable()
+ , d_globals(globals)
+{
+ d_theoryProofTable[theory::THEORY_BOOL] = new LFSCBooleanProof(this);
}
-std::string toLFSCKind(Kind kind) {
- switch(kind) {
- case kind::OR : return "or";
- case kind::AND: return "and";
- case kind::XOR: return "xor";
- case kind::EQUAL: return "=";
- case kind::IFF: return "iff";
- case kind::IMPLIES: return "impl";
- case kind::NOT: return "not";
- default:
- Unreachable();
+TheoryProofEngine::~TheoryProofEngine() {
+ TheoryProofTable::iterator it = d_theoryProofTable.begin();
+ TheoryProofTable::iterator end = d_theoryProofTable.end();
+ for (; it != end; ++it) {
+ delete it->second;
}
}
-void LFSCTheoryProof::printTerm(Expr term, std::ostream& os) {
- if (term.isVariable()) {
- if(term.getType().isBoolean()) {
- os << "(p_app " << term << ")";
- } else {
- os << term;
+
+void TheoryProofEngine::registerTheory(theory::Theory* th) {
+ if( th ){
+ theory::TheoryId id = th->getId();
+ if(d_theoryProofTable.find(id) == d_theoryProofTable.end()) {
+
+ Trace("theory-proof-debug") << "; register theory " << id << std::endl;
+
+ if (id == theory::THEORY_UF) {
+ d_theoryProofTable[id] = new LFSCUFProof((theory::uf::TheoryUF*)th, this);
+ return;
+ }
+
+ if (id == theory::THEORY_BV) {
+ BitVectorProof * bvp = new LFSCBitVectorProof((theory::bv::TheoryBV*)th, this);
+ d_theoryProofTable[id] = bvp;
+ ((theory::bv::TheoryBV*)th)->setProofLog( bvp );
+ return;
+ }
+ if (id == theory::THEORY_ARRAY) {
+ d_theoryProofTable[id] = new LFSCArrayProof((theory::arrays::TheoryArrays*)th, this);
+ return;
+ }
+ // TODO other theories
}
+ }
+}
+
+TheoryProof* TheoryProofEngine::getTheoryProof(theory::TheoryId id) {
+ Assert (d_theoryProofTable.find(id) != d_theoryProofTable.end());
+ return d_theoryProofTable[id];
+}
+
+void TheoryProofEngine::registerTerm(Expr term) {
+ if (d_registrationCache.count(term)) {
return;
}
- switch(Kind k = term.getKind()) {
- case kind::APPLY_UF: {
- if(term.getType().isBoolean()) {
- os << "(p_app ";
- }
- Expr func = term.getOperator();
+ theory::TheoryId theory_id = theory::Theory::theoryOf(term);
+
+ // don't need to register boolean terms
+ if (theory_id == theory::THEORY_BUILTIN ||
+ term.getKind() == kind::ITE) {
for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- os << "(apply _ _ ";
+ registerTerm(term[i]);
}
- os << func << " ";
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- printTerm(term[i], os);
- os << ")";
+ d_registrationCache.insert(term);
+ return;
+ }
+
+ if (!supportedTheory(theory_id)) return;
+
+ getTheoryProof(theory_id)->registerTerm(term);
+ d_registrationCache.insert(term);
+}
+
+theory::TheoryId TheoryProofEngine::getTheoryForLemma(ClauseId id) {
+ // TODO: now CNF proof has a map from formula to proof rule
+ // that should be checked to figure out what theory is responsible for this
+ ProofManager* pm = ProofManager::currentPM();
+
+ if (pm->getLogic() == "QF_UF") return theory::THEORY_UF;
+ if (pm->getLogic() == "QF_BV") return theory::THEORY_BV;
+ if (pm->getLogic() == "ALL_SUPPORTED") return theory::THEORY_BV;
+ Unreachable();
+}
+
+void LFSCTheoryProofEngine::bind(Expr term, LetMap& map, Bindings& let_order) {
+ LetMap::iterator it = map.find(term);
+ if (it != map.end()) {
+ LetCount& count = it->second;
+ count.increment();
+ return;
+ }
+ for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+ bind(term[i], map, let_order);
+ }
+ unsigned new_id = LetCount::newId();
+ map[term] = LetCount(new_id);
+ let_order.push_back(LetOrderElement(term, new_id));
+}
+
+void LFSCTheoryProofEngine::printLetTerm(Expr term, std::ostream& os) {
+ LetMap map;
+ Bindings let_order;
+ bind(term, map, let_order);
+ std::ostringstream paren;
+ for (unsigned i = 0; i < let_order.size(); ++i) {
+ Expr current_expr = let_order[i].expr;
+ unsigned let_id = let_order[i].id;
+ LetMap::const_iterator it = map.find(current_expr);
+ Assert (it != map.end());
+ unsigned let_count = it->second.count;
+ Assert(let_count);
+ // skip terms that only appear once
+ if (let_count <= LET_COUNT) {
+ continue;
}
- if(term.getType().isBoolean()) {
- os << ")";
+
+ os << "(@ let"<<let_id << " ";
+ printTheoryTerm(current_expr, os, map);
+ paren <<")";
+ }
+ unsigned last_let_id = let_order.back().id;
+ Expr last = let_order.back().expr;
+ unsigned last_count = map.find(last)->second.count;
+ if (last_count <= LET_COUNT) {
+ printTheoryTerm(last, os, map);
+ }
+ else {
+ os << " let"<< last_let_id;
+ }
+ os << paren.str();
+}
+
+
+void LFSCTheoryProofEngine::printTheoryTerm(Expr term, std::ostream& os, const LetMap& map) {
+ theory::TheoryId theory_id = theory::Theory::theoryOf(term);
+ // boolean terms and ITEs are special because they
+ // are common to all theories
+ if (theory_id == theory::THEORY_BUILTIN ||
+ term.getKind() == kind::ITE ||
+ term.getKind() == kind::EQUAL) {
+ printCoreTerm(term, os, map);
+ return;
+ }
+ // dispatch to proper theory
+ getTheoryProof(theory_id)->printTerm(term, os, map);
+}
+
+void LFSCTheoryProofEngine::printSort(Type type, std::ostream& os) {
+ if (type.isSort()) {
+ getTheoryProof(theory::THEORY_UF)->printSort(type, os);
+ return;
+ }
+ if (type.isBitVector()) {
+ getTheoryProof(theory::THEORY_BV)->printSort(type, os);
+ return;
+ }
+
+ if (type.isArray()) {
+ getTheoryProof(theory::THEORY_ARRAY)->printSort(type, os);
+ return;
+ }
+ Unreachable();
+}
+
+void LFSCTheoryProofEngine::printAssertions(std::ostream& os, std::ostream& paren) {
+ unsigned counter = 0;
+ ProofManager::assertions_iterator it = ProofManager::currentPM()->begin_assertions();
+ ProofManager::assertions_iterator end = ProofManager::currentPM()->end_assertions();
+
+ // collect declarations first
+ for(; it != end; ++it) {
+ registerTerm(*it);
+ }
+ printDeclarations(os, paren);
+
+ it = ProofManager::currentPM()->begin_assertions();
+ for (; it != end; ++it) {
+ // FIXME: merge this with counter
+ os << "(% A" << counter++ << " (th_holds ";
+ printLetTerm(*it, os);
+ os << ")\n";
+ paren << ")";
+ }
+ //store map between assertion and counter
+ // ProofManager::currentPM()->setAssertion( *it );
+}
+
+void LFSCTheoryProofEngine::printDeclarations(std::ostream& os, std::ostream& paren) {
+ TheoryProofTable::const_iterator it = d_theoryProofTable.begin();
+ TheoryProofTable::const_iterator end = d_theoryProofTable.end();
+ for (; it != end; ++it) {
+ it->second->printDeclarations(os, paren);
+ }
+}
+
+void LFSCTheoryProofEngine::printTheoryLemmas(const IdToSatClause& lemmas,
+ std::ostream& os,
+ std::ostream& paren) {
+ os << " ;; Theory Lemmas \n";
+ ProofManager* pm = ProofManager::currentPM();
+ IdToSatClause::const_iterator it = lemmas.begin();
+ IdToSatClause::const_iterator end = lemmas.end();
+
+ // BitVector theory is special case: must know all
+ // conflicts needed ahead of time for resolution
+ // proof lemmas
+ std::vector<Expr> bv_lemmas;
+ for (; it != end; ++it) {
+ ClauseId id = it->first;
+ const prop::SatClause* clause = it->second;
+
+ theory::TheoryId theory_id = getTheoryForLemma(id);
+ if (theory_id != theory::THEORY_BV) continue;
+
+ std::vector<Expr> conflict;
+ for(unsigned i = 0; i < clause->size(); ++i) {
+ prop::SatLiteral lit = (*clause)[i];
+ Expr atom = pm->getCnfProof()->getAtom(lit.getSatVariable()).toExpr();
+ if (atom.isConst()) {
+ Assert (atom == utils::mkTrue() ||
+ (atom == utils::mkFalse() && lit.isNegated()));
+ continue;
+ }
+ Expr expr_lit = lit.isNegated() ? atom.notExpr() : atom;
+ conflict.push_back(expr_lit);
+ }
+ bv_lemmas.push_back(utils::mkSortedExpr(kind::OR, conflict));
+ }
+ // FIXME: ugly, move into bit-vector proof by adding lemma
+ // queue inside each theory_proof
+ BitVectorProof* bv = ProofManager::getBitVectorProof();
+ bv->finalizeConflicts(bv_lemmas);
+
+ bv->printResolutionProof(os, paren);
+
+ if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+ Assert (lemmas.size() == 1);
+ // nothing more to do (no combination with eager so far)
+ return;
+ }
+
+ it = lemmas.begin();
+
+ for (; it != end; ++it) {
+ ClauseId id = it->first;
+ const prop::SatClause* clause = it->second;
+ // printing clause as it appears in resolution proof
+ os << "(satlem _ _ ";
+ std::ostringstream clause_paren;
+ pm->getCnfProof()->printClause(*clause, os, clause_paren);
+
+ std::vector<Expr> clause_expr;
+ for(unsigned i = 0; i < clause->size(); ++i) {
+ prop::SatLiteral lit = (*clause)[i];
+ Expr atom = pm->getCnfProof()->getAtom(lit.getSatVariable()).toExpr();
+ if (atom.isConst()) {
+ Assert (atom == utils::mkTrue());
+ continue;
+ }
+ Expr expr_lit = lit.isNegated() ? atom.notExpr(): atom;
+ clause_expr.push_back(expr_lit);
}
+
+ // query appropriate theory for proof of clause
+ theory::TheoryId theory_id = getTheoryForLemma(id);
+ Debug("theory-proof-debug") << ";; Get theory lemma from " << theory_id << "..." << std::endl;
+ getTheoryProof(theory_id)->printTheoryLemmaProof(clause_expr, os, paren);
+ // os << " (clausify_false trust)";
+ os << clause_paren.str();
+ os << "( \\ " << pm->getLemmaClauseName(id) <<"\n";
+ paren << "))";
+ }
+}
+
+void LFSCTheoryProofEngine::printBoundTerm(Expr term, std::ostream& os, const LetMap& map) {
+ LetMap::const_iterator it = map.find(term);
+ Assert (it != map.end());
+ unsigned id = it->second.id;
+ unsigned count = it->second.count;
+ if (count > LET_COUNT) {
+ os <<"let"<<id;
+ return;
+ }
+ printTheoryTerm(term, os, map);
+}
+
+void LFSCTheoryProofEngine::printCoreTerm(Expr term, std::ostream& os, const LetMap& map) {
+ if (term.isVariable()) {
+ os << ProofManager::sanitize(term);
return;
}
+ Kind k = term.getKind();
+
+ switch(k) {
case kind::ITE:
- os << (term.getType().isBoolean() ? "(ifte " : "(ite _ ");
- printTerm(term[0], os);
+ os << (term.getType().isBoolean() ? "(ifte ": "(ite _ ");
+
+ printBoundTerm(term[0], os, map);
os << " ";
- printTerm(term[1], os);
+ printBoundTerm(term[1], os, map);
os << " ";
- printTerm(term[2], os);
+ printBoundTerm(term[2], os, map);
os << ")";
return;
case kind::EQUAL:
os << "(";
os << "= ";
- os << term[0].getType() << " ";
- printTerm(term[0], os);
+ printSort(term[0].getType(), os);
+ printBoundTerm(term[0], os, map);
os << " ";
- printTerm(term[1], os);
+ printBoundTerm(term[1], os, map);
os << ")";
return;
case kind::DISTINCT:
- os << "(not (= ";
- os << term[0].getType() << " ";
- printTerm(term[0], os);
- os << " ";
- printTerm(term[1], os);
- os << "))";
- return;
+ // Distinct nodes can have any number of chidlren.
+ Assert (term.getNumChildren() >= 2);
- case kind::OR:
- case kind::AND:
- case kind::XOR:
- case kind::IFF:
- case kind::IMPLIES:
- case kind::NOT:
- // print the Boolean operators
- os << "(" << toLFSCKind(k);
- if(term.getNumChildren() > 2) {
- // LFSC doesn't allow declarations with variable numbers of
- // arguments, so we have to flatten these N-ary versions.
- std::ostringstream paren;
+ if (term.getNumChildren() == 2) {
+ os << "(not (= ";
+ printSort(term[0].getType(), os);
+ printBoundTerm(term[0], os, map);
os << " ";
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- printTerm(term[i], os);
- os << " ";
- if(i < term.getNumChildren() - 2) {
- os << "(" << toLFSCKind(k) << " ";
- paren << ")";
- }
- }
- os << paren.str() << ")";
+ printBoundTerm(term[1], os, map);
+ os << "))";
} else {
- // this is for binary and unary operators
+ unsigned numOfPairs = term.getNumChildren() * (term.getNumChildren() - 1) / 2;
+ for (unsigned i = 1; i < numOfPairs; ++i) {
+ os << "(and ";
+ }
+
for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- os << " ";
- printTerm(term[i], os);
+ for (unsigned j = i + 1; j < term.getNumChildren(); ++j) {
+ if ((i != 0) || (j != 1)) {
+ os << "(not (= ";
+ printSort(term[0].getType(), os);
+ printBoundTerm(term[i], os, map);
+ os << " ";
+ printBoundTerm(term[j], os, map);
+ os << ")))";
+ } else {
+ os << "(not (= ";
+ printSort(term[0].getType(), os);
+ printBoundTerm(term[0], os, map);
+ os << " ";
+ printBoundTerm(term[1], os, map);
+ os << "))";
+ }
+ }
}
- os << ")";
}
- return;
- case kind::CONST_BOOLEAN:
- os << (term.getConst<bool>() ? "true" : "false");
return;
case kind::CHAIN: {
@@ -164,13 +474,13 @@ void LFSCTheoryProof::printTerm(Expr term, std::ostream& os) {
std::ostringstream paren;
for(size_t i = 1; i < n; ++i) {
if(i + 1 < n) {
- os << "(" << toLFSCKind(kind::AND) << " ";
+ os << "(" << utils::toLFSCKind(kind::AND) << " ";
paren << ")";
}
- os << "(" << toLFSCKind(op) << " ";
- printTerm(term[i - 1], os);
+ os << "(" << utils::toLFSCKind(op) << " ";
+ printBoundTerm(term[i - 1], os, map);
os << " ";
- printTerm(term[i], os);
+ printBoundTerm(term[i], os, map);
os << ")";
if(i + 1 < n) {
os << " ";
@@ -184,66 +494,144 @@ void LFSCTheoryProof::printTerm(Expr term, std::ostream& os) {
Unhandled(k);
}
- Unreachable();
}
-void LFSCTheoryProof::printAssertions(std::ostream& os, std::ostream& paren) {
- ProofManager::assertions_iterator it = ProofManager::currentPM()->begin_assertions();
- ProofManager::assertions_iterator end = ProofManager::currentPM()->end_assertions();
-
- // collect declarations first
- for(; it != end; ++it) {
- addDeclaration(*it);
+void TheoryProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren) {
+ //default method for replaying proofs: assert (negated) literals back to a fresh copy of the theory
+ Assert( d_theory!=NULL );
+ context::UserContext fakeContext;
+ ProofOutputChannel oc;
+ theory::Valuation v(NULL);
+ //make new copy of theory
+ theory::Theory* th;
+ Trace("theory-proof-debug") << ";; Print theory lemma proof, theory id = " << d_theory->getId() << std::endl;
+ if(d_theory->getId()==theory::THEORY_UF) {
+ th = new theory::uf::TheoryUF(&fakeContext, &fakeContext, oc, v,
+ ProofManager::currentPM()->getLogicInfo(),
+ ProofManager::currentPM()->getTheoryProofEngine()->d_globals,
+ "replay::");
+ } else if(d_theory->getId()==theory::THEORY_ARRAY) {
+ th = new theory::arrays::TheoryArrays(&fakeContext, &fakeContext, oc, v,
+ ProofManager::currentPM()->getLogicInfo(),
+ ProofManager::currentPM()->getTheoryProofEngine()->d_globals,
+ "replay::");
+ } else {
+ InternalError(std::string("can't generate theory-proof for ") + ProofManager::currentPM()->getLogic());
}
- printDeclarations(os, paren);
-
- it = ProofManager::currentPM()->begin_assertions();
- for (; it != end; ++it) {
- os << "(% A" << ProofManager::currentPM()->getAssertionCounter() << " (th_holds ";
- printTerm(*it, os);
- os << ")\n";
- paren << ")";
- //store map between assertion and counter
- ProofManager::currentPM()->setAssertion( *it );
+ th->produceProofs();
+ MyPreRegisterVisitor preRegVisitor(th);
+ for( unsigned i=0; i<lemma.size(); i++ ){
+ Node lit = Node::fromExpr( lemma[i] ).negate();
+ Trace("theory-proof-debug") << "; preregistering and asserting " << lit << std::endl;
+ NodeVisitor<MyPreRegisterVisitor>::run(preRegVisitor, lit);
+ th->assertFact(lit, false);
+ }
+ th->check(theory::Theory::EFFORT_FULL);
+ if(oc.d_conflict.isNull()) {
+ Trace("theory-proof-debug") << "; conflict is null" << std::endl;
+ Assert(!oc.d_lemma.isNull());
+ Trace("theory-proof-debug") << "; ++ but got lemma: " << oc.d_lemma << std::endl;
+ Trace("theory-proof-debug") << "; asserting " << oc.d_lemma[1].negate() << std::endl;
+ th->assertFact(oc.d_lemma[1].negate(), false);
+ th->check(theory::Theory::EFFORT_FULL);
}
+ oc.d_proof->toStream(os);
+ delete th;
}
-void LFSCTheoryProof::printDeclarations(std::ostream& os, std::ostream& paren) {
- // declaring the sorts
- for (SortSet::const_iterator it = d_sortDeclarations.begin(); it != d_sortDeclarations.end(); ++it) {
- os << "(% " << *it << " sort\n";
- paren << ")";
+bool TheoryProofEngine::supportedTheory(theory::TheoryId id) {
+ return (id == theory::THEORY_ARRAY ||
+ id == theory::THEORY_BV ||
+ id == theory::THEORY_UF ||
+ id == theory::THEORY_BOOL);
+}
+
+BooleanProof::BooleanProof(TheoryProofEngine* proofEngine)
+ : TheoryProof(NULL, proofEngine)
+{}
+
+void BooleanProof::registerTerm(Expr term) {
+ Assert (term.getType().isBoolean());
+
+ if (term.isVariable() && d_declarations.find(term) == d_declarations.end()) {
+ d_declarations.insert(term);
+ return;
+ }
+ for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+ d_proofEngine->registerTerm(term[i]);
}
+}
- // declaring the terms
- for (ExprSet::const_iterator it = d_termDeclarations.begin(); it != d_termDeclarations.end(); ++it) {
- Expr term = *it;
+void LFSCBooleanProof::printTerm(Expr term, std::ostream& os, const LetMap& map) {
+ Assert (term.getType().isBoolean());
+ if (term.isVariable()) {
+ os << "(p_app " << ProofManager::sanitize(term) <<")";
+ return;
+ }
- os << "(% " << term << " ";
- os << "(term ";
-
- Type type = term.getType();
- if (type.isFunction()) {
- std::ostringstream fparen;
- FunctionType ftype = (FunctionType)type;
- std::vector<Type> args = ftype.getArgTypes();
- args.push_back(ftype.getRangeType());
- os << "(arrow";
- for (unsigned i = 0; i < args.size(); i++) {
- Type arg_type = args[i];
- //Assert (arg_type.isSort() || arg_type.isBoolean());
- os << " " << arg_type;
- if (i < args.size() - 2) {
- os << " (arrow";
- fparen << ")";
+ Kind k = term.getKind();
+ switch(k) {
+ case kind::OR:
+ case kind::AND:
+ case kind::XOR:
+ case kind::IFF:
+ case kind::IMPLIES:
+ case kind::NOT:
+ // print the Boolean operators
+ os << "(" << utils::toLFSCKind(k);
+ if(term.getNumChildren() > 2) {
+ // LFSC doesn't allow declarations with variable numbers of
+ // arguments, so we have to flatten these N-ary versions.
+ std::ostringstream paren;
+ os << " ";
+ for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+ d_proofEngine->printBoundTerm(term[i], os, map);
+ os << " ";
+ if(i < term.getNumChildren() - 2) {
+ os << "(" << utils::toLFSCKind(k) << " ";
+ paren << ")";
}
}
- os << fparen.str() << "))\n";
+ os << paren.str() << ")";
} else {
- Assert (term.isVariable());
- //Assert (type.isSort() || type.isBoolean());
- os << type << ")\n";
+ // this is for binary and unary operators
+ for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+ os << " ";
+ d_proofEngine->printBoundTerm(term[i], os, map);
+ }
+ os << ")";
}
- paren << ")";
+ return;
+
+ case kind::CONST_BOOLEAN:
+ os << (term.getConst<bool>() ? "true" : "false");
+ return;
+
+ default:
+ Unhandled(k);
}
+
}
+
+void LFSCBooleanProof::printSort(Type type, std::ostream& os) {
+ Assert (type.isBoolean());
+ os << "Bool";
+}
+void LFSCBooleanProof::printDeclarations(std::ostream& os, std::ostream& paren) {
+ for (ExprSet::const_iterator it = d_declarations.begin(); it != d_declarations.end(); ++it) {
+ Expr term = *it;
+
+ os << "(% " << ProofManager::sanitize(term) << " (term ";
+ printSort(term.getType(), os);
+ os <<")\n";
+ paren <<")";
+ }
+}
+
+void LFSCBooleanProof::printTheoryLemmaProof(std::vector<Expr>& lemma,
+ std::ostream& os,
+ std::ostream& paren) {
+ Unreachable("No boolean lemmas yet!");
+}
+
+} /* namespace CVC4 */
diff --git a/src/proof/theory_proof.h b/src/proof/theory_proof.h
index 375ec8205..3d700c388 100644
--- a/src/proof/theory_proof.h
+++ b/src/proof/theory_proof.h
@@ -1,56 +1,260 @@
/********************* */
/*! \file theory_proof.h
- ** \verbatim
- ** Original author: Liana Hadarean
- ** Major contributors: Morgan Deters
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2014 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief A manager for UfProofs.
- **
- ** A manager for UfProofs.
- **
- **
- **/
+** \verbatim
+** Original author: Liana Hadarean
+** Major contributors: Morgan Deters
+** Minor contributors (to current version): none
+** This file is part of the CVC4 project.
+** Copyright (c) 2009-2014 New York University and The University of Iowa
+** See the file COPYING in the top-level source directory for licensing
+** information.\endverbatim
+**
+** \brief A manager for UfProofs.
+**
+** A manager for UfProofs.
+**
+**
+**/
#include "cvc4_private.h"
#ifndef __CVC4__THEORY_PROOF_H
#define __CVC4__THEORY_PROOF_H
+#include "util/proof.h"
+#include "expr/expr.h"
+#include "prop/sat_solver_types.h"
#include <ext/hash_set>
#include <iosfwd>
-#include "expr/expr.h"
-#include "util/proof.h"
namespace CVC4 {
- typedef __gnu_cxx::hash_set<Type, TypeHashFunction > SortSet;
- typedef __gnu_cxx::hash_set<Expr, ExprHashFunction > ExprSet;
-
- class TheoryProof {
- protected:
- ExprSet d_termDeclarations;
- SortSet d_sortDeclarations;
- ExprSet d_declarationCache;
-
- public:
- TheoryProof();
- virtual ~TheoryProof() {}
- virtual void printAssertions(std::ostream& os, std::ostream& paren) = 0;
- void addDeclaration(Expr atom);
- };
-
- class LFSCTheoryProof : public TheoryProof {
- void printDeclarations(std::ostream& os, std::ostream& paren);
- public:
- static void printTerm(Expr term, std::ostream& os);
- virtual void printAssertions(std::ostream& os, std::ostream& paren);
- };
+class SmtGlobals;
+
+namespace theory {
+class Theory;
+}
+
+typedef unsigned ClauseId;
+
+struct LetCount {
+ static unsigned counter;
+ static void resetCounter() { counter = 0; }
+ static unsigned newId() { return ++counter; }
+
+ unsigned count;
+ unsigned id;
+ LetCount()
+ : count(0)
+ , id(-1)
+ {}
+
+ void increment() { ++count; }
+ LetCount(unsigned i)
+ : count(1)
+ , id(i)
+ {}
+ LetCount(const LetCount& other)
+ : count(other.count)
+ , id (other.id)
+ {}
+ bool operator==(const LetCount &other) const {
+ return other.id == id && other.count == count;
+ }
+ LetCount& operator=(const LetCount &rhs) {
+ if (&rhs == this) return *this;
+ id = rhs.id;
+ count = rhs.count;
+ return *this;
+ }
+};
+
+struct LetOrderElement {
+ Expr expr;
+ unsigned id;
+ LetOrderElement(Expr e, unsigned i)
+ : expr(e)
+ , id(i)
+ {}
+
+ LetOrderElement()
+ : expr()
+ , id(-1)
+ {}
+};
+
+typedef __gnu_cxx::hash_map < ClauseId, prop::SatClause* > IdToSatClause;
+
+typedef __gnu_cxx::hash_map<Expr, LetCount, ExprHashFunction> LetMap;
+typedef std::vector<LetOrderElement> Bindings;
+
+class TheoryProof;
+typedef unsigned ClauseId;
+
+typedef __gnu_cxx::hash_set<Expr, ExprHashFunction > ExprSet;
+typedef std::map<theory::TheoryId, TheoryProof* > TheoryProofTable;
+
+class TheoryProofEngine {
+protected:
+ ExprSet d_registrationCache;
+ TheoryProofTable d_theoryProofTable;
+
+ /**
+ * Returns whether the theory is currently supported in proof
+ * production mode.
+ */
+ bool supportedTheory(theory::TheoryId id);
+public:
+ SmtGlobals* d_globals;
+
+ TheoryProofEngine(SmtGlobals* globals);
+ virtual ~TheoryProofEngine();
+ /**
+ * Print the theory term (could be atom) by delegating to the
+ * proper theory
+ *
+ * @param term
+ * @param os
+ *
+ * @return
+ */
+ virtual void printLetTerm(Expr term, std::ostream& os) = 0;
+ virtual void printBoundTerm(Expr term, std::ostream& os, const LetMap& map) = 0;
+ /**
+ * Print the proof representation of the given sort.
+ *
+ * @param os
+ */
+ virtual void printSort(Type type, std::ostream& os) = 0;
+ /**
+ * Print the theory assertions (arbitrary formulas over
+ * theory atoms)
+ *
+ * @param os
+ * @param paren closing parenthesis
+ */
+ virtual void printAssertions(std::ostream& os, std::ostream& paren) = 0;
+ /**
+ * Print proofs of all the theory lemmas (must prove
+ * actual clause used in resolution proof).
+ *
+ * @param os
+ * @param paren
+ */
+ virtual void printTheoryLemmas(const IdToSatClause& lemmas,
+ std::ostream& os,
+ std::ostream& paren) = 0;
+ /**
+ * Register theory atom (ensures all terms and atoms are declared).
+ *
+ * @param atom
+ */
+ void registerTerm(Expr atom);
+ /**
+ * Ensures that a theory proof class for the given theory
+ * is created.
+ *
+ * @param theory
+ */
+ void registerTheory(theory::Theory* theory);
+ theory::TheoryId getTheoryForLemma(ClauseId id);
+ TheoryProof* getTheoryProof(theory::TheoryId id);
+};
+
+class LFSCTheoryProofEngine : public TheoryProofEngine {
+ LetMap d_letMap;
+ void printTheoryTerm(Expr term, std::ostream& os, const LetMap& map);
+ void bind(Expr term, LetMap& map, Bindings& let_order);
+public:
+ LFSCTheoryProofEngine(SmtGlobals* globals)
+ : TheoryProofEngine(globals) {}
+
+ void printDeclarations(std::ostream& os, std::ostream& paren);
+ virtual void printCoreTerm(Expr term, std::ostream& os, const LetMap& map);
+ virtual void printLetTerm(Expr term, std::ostream& os);
+ virtual void printBoundTerm(Expr term, std::ostream& os, const LetMap& map);
+ virtual void printAssertions(std::ostream& os, std::ostream& paren);
+ virtual void printTheoryLemmas(const IdToSatClause& lemmas,
+ std::ostream& os,
+ std::ostream& paren);
+ virtual void printSort(Type type, std::ostream& os);
+};
+
+class TheoryProof {
+protected:
+ // Pointer to the theory for this proof
+ theory::Theory* d_theory;
+ TheoryProofEngine* d_proofEngine;
+public:
+ TheoryProof(theory::Theory* th, TheoryProofEngine* proofEngine)
+ : d_theory(th)
+ , d_proofEngine(proofEngine)
+ {}
+ virtual ~TheoryProof() {};
+ /**
+ * Print a term belonging to this theory.
+ *
+ * @param term expresion representing term
+ * @param os output stream
+ */
+ virtual void printTerm(Expr term, std::ostream& os, const LetMap& map) = 0;
+ /**
+ * Print the proof representation of the given type.
+ *
+ * @param type
+ * @param os
+ */
+ virtual void printSort(Type type, std::ostream& os) = 0;
+ /**
+ * Print a proof for the theory lemmas. Must prove
+ * clause representing lemmas to be used in resolution proof.
+ *
+ * @param os output stream
+ */
+ virtual void printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren);
+ /**
+ * Print the variable/sorts declarations for this theory.
+ *
+ * @param os
+ * @param paren
+ */
+ virtual void printDeclarations(std::ostream& os, std::ostream& paren) = 0;
+ /**
+ * Register a term of this theory that appears in the proof.
+ *
+ * @param term
+ */
+ virtual void registerTerm(Expr term) = 0;
+};
+
+class BooleanProof : public TheoryProof {
+protected:
+ ExprSet d_declarations; // all the boolean variables
+public:
+ BooleanProof(TheoryProofEngine* proofEngine);
+
+ virtual void registerTerm(Expr term);
+
+ virtual void printTerm(Expr term, std::ostream& os, const LetMap& map) = 0;
+
+ virtual void printSort(Type type, std::ostream& os) = 0;
+ virtual void printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren) = 0;
+ virtual void printDeclarations(std::ostream& os, std::ostream& paren) = 0;
+};
+
+class LFSCBooleanProof : public BooleanProof {
+public:
+ LFSCBooleanProof(TheoryProofEngine* proofEngine)
+ : BooleanProof(proofEngine)
+ {}
+ virtual void printTerm(Expr term, std::ostream& os, const LetMap& map);
+ virtual void printSort(Type type, std::ostream& os);
+ virtual void printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren);
+ virtual void printDeclarations(std::ostream& os, std::ostream& paren);
+};
+
+
} /* CVC4 namespace */
#endif /* __CVC4__THEORY_PROOF_H */
diff --git a/src/proof/uf_proof.cpp b/src/proof/uf_proof.cpp
new file mode 100644
index 000000000..ec0d90ae7
--- /dev/null
+++ b/src/proof/uf_proof.cpp
@@ -0,0 +1,804 @@
+/********************* */
+/*! \file uf_proof.cpp
+** \verbatim
+** Original author: Liana Hadarean
+** Major contributors: none
+** Minor contributors (to current version): none
+** This file is part of the CVC4 project.
+** Copyright (c) 2009-2014 New York University and The University of Iowa
+** See the file COPYING in the top-level source directory for licensing
+** information.\endverbatim
+**
+** \brief [[ Add one-line brief description here ]]
+**
+** [[ Add lengthier description here ]]
+** \todo document this file
+**/
+
+#include "proof/theory_proof.h"
+#include "proof/proof_manager.h"
+#include "proof/uf_proof.h"
+#include "theory/uf/theory_uf.h"
+#include <stack>
+
+using namespace CVC4;
+using namespace CVC4::theory;
+using namespace CVC4::theory::uf;
+
+
+inline static Node eqNode(TNode n1, TNode n2) {
+ return NodeManager::currentNM()->mkNode(n1.getType().isBoolean() ? kind::IFF : kind::EQUAL, n1, n2);
+}
+
+// congrence matching term helper
+inline static bool match(TNode n1, TNode n2) {
+ Debug("mgd") << "match " << n1 << " " << n2 << std::endl;
+ if(ProofManager::currentPM()->hasOp(n1)) {
+ n1 = ProofManager::currentPM()->lookupOp(n1);
+ }
+ if(ProofManager::currentPM()->hasOp(n2)) {
+ n2 = ProofManager::currentPM()->lookupOp(n2);
+ }
+ Debug("mgd") << "+ match " << n1 << " " << n2 << std::endl;
+ if(n1 == n2) {
+ return true;
+ }
+ if(n1.getType().isFunction() && n2.hasOperator()) {
+ if(ProofManager::currentPM()->hasOp(n2.getOperator())) {
+ return n1 == ProofManager::currentPM()->lookupOp(n2.getOperator());
+ } else {
+ return n1 == n2.getOperator();
+ }
+ }
+ if(n2.getType().isFunction() && n1.hasOperator()) {
+ if(ProofManager::currentPM()->hasOp(n1.getOperator())) {
+ return n2 == ProofManager::currentPM()->lookupOp(n1.getOperator());
+ } else {
+ return n2 == n1.getOperator();
+ }
+ }
+ if(n1.hasOperator() && n2.hasOperator() && n1.getOperator() != n2.getOperator()) {
+ return false;
+ }
+ for(size_t i = 0; i < n1.getNumChildren() && i < n2.getNumChildren(); ++i) {
+ if(n1[i] != n2[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+void ProofUF::toStream(std::ostream& out) {
+ Trace("theory-proof-debug") << "; Print UF proof..." << std::endl;
+ //AJR : carry this further?
+ LetMap map;
+ toStreamLFSC(out, ProofManager::getUfProof(), d_proof, map);
+}
+
+void ProofUF::toStreamLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, const LetMap& map) {
+ Debug("lfsc-uf") << "Printing uf proof in LFSC : " << std::endl;
+ pf->debug_print("lfsc-uf");
+ Debug("lfsc-uf") << std::endl;
+ toStreamRecLFSC( out, tp, pf, 0, map );
+}
+
+Node ProofUF::toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, unsigned tb, const LetMap& map) {
+ Debug("gk::proof") << std::endl << std::endl << "toStreamRecLFSC called. tb = " << tb << " . proof:" << std::endl;
+ pf->debug_print("gk::proof");
+ Debug("gk::proof") << std::endl;
+
+ if(tb == 0) {
+ Assert(pf->d_id == eq::MERGED_THROUGH_TRANS);
+ Assert(!pf->d_node.isNull());
+ Assert(pf->d_children.size() >= 2);
+
+ int neg = -1;
+ theory::eq::EqProof subTrans;
+ subTrans.d_id = eq::MERGED_THROUGH_TRANS;
+ subTrans.d_node = pf->d_node;
+
+ size_t i = 0;
+ while (i < pf->d_children.size()) {
+ // Look for the negative clause, with which we will form a contradiction.
+ if(!pf->d_children[i]->d_node.isNull() && pf->d_children[i]->d_node.getKind() == kind::NOT) {
+ Assert(neg < 0);
+ neg = i;
+ ++i;
+ }
+
+ // Handle congruence closures over equalities.
+ else if (pf->d_children[i]->d_id==eq::MERGED_THROUGH_CONGRUENCE && pf->d_children[i]->d_node.isNull()) {
+ Debug("gk::proof") << "Handling congruence over equalities" << std::endl;
+
+ // Gather the sequence of consecutive congruence closures.
+ std::vector<const theory::eq::EqProof *> congruenceClosures;
+ unsigned count;
+ Debug("gk::proof") << "Collecting congruence sequence" << std::endl;
+ for (count = 0;
+ i + count < pf->d_children.size() &&
+ pf->d_children[i + count]->d_id==eq::MERGED_THROUGH_CONGRUENCE &&
+ pf->d_children[i + count]->d_node.isNull();
+ ++count) {
+ Debug("gk::proof") << "Found a congruence: " << std::endl;
+ pf->d_children[i+count]->debug_print("gk::proof");
+ congruenceClosures.push_back(pf->d_children[i+count]);
+ }
+
+ Debug("gk::proof") << "Total number of congruences found: " << congruenceClosures.size() << std::endl;
+
+ // Determine if the "target" of the congruence sequence appears right before or right after the sequence.
+ bool targetAppearsBefore = true;
+ bool targetAppearsAfter = true;
+
+ if ((i == 0) || (i == 1 && neg == 0)) {
+ Debug("gk::proof") << "Target does not appear before" << std::endl;
+ targetAppearsBefore = false;
+ }
+
+ if ((i + count >= pf->d_children.size()) ||
+ (!pf->d_children[i + count]->d_node.isNull() &&
+ pf->d_children[i + count]->d_node.getKind() == kind::NOT)) {
+ Debug("gk::proof") << "Target does not appear after" << std::endl;
+ targetAppearsAfter = false;
+ }
+
+ // Assert that we have precisely one target clause.
+ Assert(targetAppearsBefore != targetAppearsAfter);
+
+ // Begin breaking up the congruences and ordering the equalities correctly.
+ std::vector<theory::eq::EqProof *> orderedEqualities;
+
+
+ // Insert target clause first.
+ if (targetAppearsBefore) {
+ orderedEqualities.push_back(pf->d_children[i - 1]);
+ // The target has already been added to subTrans; remove it.
+ subTrans.d_children.pop_back();
+ } else {
+ orderedEqualities.push_back(pf->d_children[i + count]);
+ }
+
+ // Start with the congruence closure closest to the target clause, and work our way back/forward.
+ if (targetAppearsBefore) {
+ for (unsigned j = 0; j < count; ++j) {
+ if (pf->d_children[i + j]->d_children[0]->d_id != eq::MERGED_THROUGH_REFLEXIVITY)
+ orderedEqualities.insert(orderedEqualities.begin(), pf->d_children[i + j]->d_children[0]);
+ if (pf->d_children[i + j]->d_children[1]->d_id != eq::MERGED_THROUGH_REFLEXIVITY)
+ orderedEqualities.insert(orderedEqualities.end(), pf->d_children[i + j]->d_children[1]);
+ }
+ } else {
+ for (unsigned j = 0; j < count; ++j) {
+ if (pf->d_children[i + count - 1 - j]->d_children[0]->d_id != eq::MERGED_THROUGH_REFLEXIVITY)
+ orderedEqualities.insert(orderedEqualities.begin(), pf->d_children[i + count - 1 - j]->d_children[0]);
+ if (pf->d_children[i + count - 1 - j]->d_children[1]->d_id != eq::MERGED_THROUGH_REFLEXIVITY)
+ orderedEqualities.insert(orderedEqualities.end(), pf->d_children[i + count - 1 - j]->d_children[1]);
+ }
+ }
+
+ // Copy the result into the main transitivity proof.
+ subTrans.d_children.insert(subTrans.d_children.end(), orderedEqualities.begin(), orderedEqualities.end());
+
+ // Increase i to skip over the children that have been processed.
+ i += count;
+ if (targetAppearsAfter) {
+ ++i;
+ }
+ }
+
+ // Else, just copy the child proof as is
+ else {
+ subTrans.d_children.push_back(pf->d_children[i]);
+ ++i;
+ }
+ }
+ Assert(neg >= 0);
+
+ Node n1;
+ std::stringstream ss;
+ //Assert(subTrans.d_children.size() == pf->d_children.size() - 1);
+ Debug("mgdx") << "\nsubtrans has " << subTrans.d_children.size() << " children\n";
+ if(pf->d_children.size() > 2) {
+ n1 = toStreamRecLFSC(ss, tp, &subTrans, 1, map);
+ } else {
+ n1 = toStreamRecLFSC(ss, tp, subTrans.d_children[0], 1, map);
+ Debug("mgdx") << "\nsubTrans unique child " << subTrans.d_children[0]->d_id << " was proven\ngot: " << n1 << std::endl;
+ }
+
+ Node n2 = pf->d_children[neg]->d_node;
+ Assert(n2.getKind() == kind::NOT);
+ out << "(clausify_false (contra _ ";
+ Debug("mgdx") << "\nhave proven: " << n1 << std::endl;
+ Debug("mgdx") << "n2 is " << n2[0] << std::endl;
+
+ if (n2[0].getNumChildren() > 0) { Debug("mgdx") << "\nn2[0]: " << n2[0][0] << std::endl; }
+ if (n1.getNumChildren() > 1) { Debug("mgdx") << "n1[1]: " << n1[1] << std::endl; }
+
+ if(n2[0].getKind() == kind::APPLY_UF) {
+ out << "(trans _ _ _ _ ";
+ out << "(symm _ _ _ ";
+ out << ss.str();
+ out << ") (pred_eq_f _ " << ProofManager::getLitName(n2[0]) << ")) t_t_neq_f))" << std::endl;
+ } else {
+ Assert((n1[0] == n2[0][0] && n1[1] == n2[0][1]) || (n1[1] == n2[0][0] && n1[0] == n2[0][1]));
+ if(n1[1] == n2[0][0]) {
+ out << "(symm _ _ _ " << ss.str() << ")";
+ } else {
+ out << ss.str();
+ }
+ out << " " << ProofManager::getLitName(n2[0]) << "))" << std::endl;
+ }
+ return Node();
+ }
+
+ switch(pf->d_id) {
+ case eq::MERGED_THROUGH_CONGRUENCE: {
+ Debug("mgd") << "\nok, looking at congruence:\n";
+ pf->debug_print("mgd");
+ std::stack<const theory::eq::EqProof*> stk;
+ for(const theory::eq::EqProof* pf2 = pf; pf2->d_id == eq::MERGED_THROUGH_CONGRUENCE; pf2 = pf2->d_children[0]) {
+ Assert(!pf2->d_node.isNull());
+ Assert(pf2->d_node.getKind() == kind::PARTIAL_APPLY_UF || pf2->d_node.getKind() == kind::BUILTIN || pf2->d_node.getKind() == kind::APPLY_UF || pf2->d_node.getKind() == kind::SELECT || pf2->d_node.getKind() == kind::STORE);
+ Assert(pf2->d_children.size() == 2);
+ out << "(cong _ _ _ _ _ _ ";
+ stk.push(pf2);
+ }
+ Assert(stk.top()->d_children[0]->d_id != eq::MERGED_THROUGH_CONGRUENCE);
+ NodeBuilder<> b1(kind::PARTIAL_APPLY_UF), b2(kind::PARTIAL_APPLY_UF);
+ const theory::eq::EqProof* pf2 = stk.top();
+ stk.pop();
+ Assert(pf2->d_id == eq::MERGED_THROUGH_CONGRUENCE);
+ Node n1 = toStreamRecLFSC(out, tp, pf2->d_children[0], tb + 1, map);
+ out << " ";
+ std::stringstream ss;
+ Node n2 = toStreamRecLFSC(ss, tp, pf2->d_children[1], tb + 1, map);
+ Debug("mgd") << "\nok, in FIRST cong[" << stk.size() << "]" << "\n";
+ pf2->debug_print("mgd");
+ Debug("mgd") << "looking at " << pf2->d_node << "\n";
+ Debug("mgd") << " " << n1 << "\n";
+ Debug("mgd") << " " << n2 << "\n";
+ int side = 0;
+ if(match(pf2->d_node, n1[0])) {
+ //if(tb == 1) {
+ Debug("mgd") << "SIDE IS 0\n";
+ //}
+ side = 0;
+ } else {
+ //if(tb == 1) {
+ Debug("mgd") << "SIDE IS 1\n";
+ //}
+ if(!match(pf2->d_node, n1[1])) {
+ Debug("mgd") << "IN BAD CASE, our first subproof is\n";
+ pf2->d_children[0]->debug_print("mgd");
+ }
+ Assert(match(pf2->d_node, n1[1]));
+ side = 1;
+ }
+ if(n1[side].getKind() == kind::APPLY_UF || n1[side].getKind() == kind::PARTIAL_APPLY_UF || n1[side].getKind() == kind::SELECT || n1[side].getKind() == kind::STORE) {
+ if(n1[side].getKind() == kind::APPLY_UF || n1[side].getKind() == kind::PARTIAL_APPLY_UF) {
+ b1 << n1[side].getOperator();
+ } else {
+ b1 << ProofManager::currentPM()->mkOp(n1[side].getOperator());
+ }
+ b1.append(n1[side].begin(), n1[side].end());
+ } else {
+ b1 << n1[side];
+ }
+ if(n1[1-side].getKind() == kind::PARTIAL_APPLY_UF || n1[1-side].getKind() == kind::APPLY_UF || n1[side].getKind() == kind::SELECT || n1[side].getKind() == kind::STORE) {
+ if(n1[1-side].getKind() == kind::PARTIAL_APPLY_UF || n1[1-side].getKind() == kind::APPLY_UF) {
+ b2 << n1[1-side].getOperator();
+ } else {
+ b2 << ProofManager::currentPM()->mkOp(n1[1-side].getOperator());
+ }
+ b2.append(n1[1-side].begin(), n1[1-side].end());
+ } else {
+ b2 << n1[1-side];
+ }
+ Debug("mgd") << "pf2->d_node " << pf2->d_node << std::endl;
+ Debug("mgd") << "b1.getNumChildren() " << b1.getNumChildren() << std::endl;
+ Debug("mgd") << "n1 " << n1 << std::endl;
+ Debug("mgd") << "n2 " << n2 << std::endl;
+ Debug("mgd") << "side " << side << std::endl;
+ if(pf2->d_node[b1.getNumChildren() - (pf2->d_node.getMetaKind() == kind::metakind::PARAMETERIZED ? 0 : 1)] == n2[side]) {
+ b1 << n2[side];
+ b2 << n2[1-side];
+ out << ss.str();
+ } else {
+ Assert(pf2->d_node[b1.getNumChildren() - (pf2->d_node.getMetaKind() == kind::metakind::PARAMETERIZED ? 0 : 1)] == n2[1-side]);
+ b1 << n2[1-side];
+ b2 << n2[side];
+ out << "(symm _ _ _ " << ss.str() << ")";
+ }
+ out << ")";
+ while(!stk.empty()) {
+ if(tb == 1) {
+ Debug("mgd") << "\nMORE TO DO\n";
+ }
+ pf2 = stk.top();
+ stk.pop();
+ Assert(pf2->d_id == eq::MERGED_THROUGH_CONGRUENCE);
+ out << " ";
+ ss.str("");
+ n2 = toStreamRecLFSC(ss, tp, pf2->d_children[1], tb + 1, map);
+ Debug("mgd") << "\nok, in cong[" << stk.size() << "]" << "\n";
+ Debug("mgd") << "looking at " << pf2->d_node << "\n";
+ Debug("mgd") << " " << n1 << "\n";
+ Debug("mgd") << " " << n2 << "\n";
+ Debug("mgd") << " " << b1 << "\n";
+ Debug("mgd") << " " << b2 << "\n";
+ if(pf2->d_node[b1.getNumChildren()] == n2[side]) {
+ b1 << n2[side];
+ b2 << n2[1-side];
+ out << ss.str();
+ } else {
+ Assert(pf2->d_node[b1.getNumChildren()] == n2[1-side]);
+ b1 << n2[1-side];
+ b2 << n2[side];
+ out << "(symm _ _ _ " << ss.str() << ")";
+ }
+ out << ")";
+ }
+ n1 = b1;
+ n2 = b2;
+ Debug("mgd") << "at end assert, got " << pf2->d_node << " and " << n1 << std::endl;
+ if(pf2->d_node.getKind() == kind::PARTIAL_APPLY_UF) {
+ Assert(n1 == pf2->d_node);
+ }
+ if(n1.getOperator().getType().getNumChildren() == n1.getNumChildren() + 1) {
+ if(ProofManager::currentPM()->hasOp(n1.getOperator())) {
+ b1.clear(ProofManager::currentPM()->lookupOp(n2.getOperator()).getConst<Kind>());
+ } else {
+ b1.clear(kind::APPLY_UF);
+ b1 << n1.getOperator();
+ }
+ b1.append(n1.begin(), n1.end());
+ n1 = b1;
+ Debug("mgd") << "at[2] end assert, got " << pf2->d_node << " and " << n1 << std::endl;
+ if(pf2->d_node.getKind() == kind::APPLY_UF) {
+ Assert(n1 == pf2->d_node);
+ }
+ }
+ if(n2.getOperator().getType().getNumChildren() == n2.getNumChildren() + 1) {
+ if(ProofManager::currentPM()->hasOp(n2.getOperator())) {
+ b2.clear(ProofManager::currentPM()->lookupOp(n2.getOperator()).getConst<Kind>());
+ } else {
+ b2.clear(kind::APPLY_UF);
+ b2 << n2.getOperator();
+ }
+ b2.append(n2.begin(), n2.end());
+ n2 = b2;
+ }
+ Node n = (side == 0 ? eqNode(n1, n2) : eqNode(n2, n1));
+ if(tb == 1) {
+ Debug("mgdx") << "\ncong proved: " << n << "\n";
+ }
+ return n;
+ }
+
+ case eq::MERGED_THROUGH_REFLEXIVITY:
+ Assert(!pf->d_node.isNull());
+ Assert(pf->d_children.empty());
+ out << "(refl _ ";
+ tp->printTerm(NodeManager::currentNM()->toExpr(pf->d_node), out, map);
+ out << ")";
+ return eqNode(pf->d_node, pf->d_node);
+
+ case eq::MERGED_THROUGH_EQUALITY:
+ Assert(!pf->d_node.isNull());
+ Assert(pf->d_children.empty());
+ out << ProofManager::getLitName(pf->d_node.negate());
+ return pf->d_node;
+
+ case eq::MERGED_THROUGH_TRANS: {
+ Assert(!pf->d_node.isNull());
+ Assert(pf->d_children.size() >= 2);
+ std::stringstream ss;
+ Debug("mgd") << "\ndoing trans proof[[\n";
+ pf->debug_print("mgd");
+ Debug("mgd") << "\n";
+ Node n1 = toStreamRecLFSC(ss, tp, pf->d_children[0], tb + 1, map);
+ Debug("mgd") << "\ndoing trans proof, got n1 " << n1 << "\n";
+ if(tb == 1) {
+ Debug("mgdx") << "\ntrans proof[0], got n1 " << n1 << "\n";
+ }
+
+ bool identicalEqualities = false;
+ bool evenLengthSequence;
+ Node nodeAfterEqualitySequence;
+
+ for(size_t i = 1; i < pf->d_children.size(); ++i) {
+ std::stringstream ss1(ss.str()), ss2;
+ ss.str("");
+ Node n2 = toStreamRecLFSC(ss2, tp, pf->d_children[i], tb + 1, map);
+
+ // The following branch is dedicated to handling sequences of identical equalities,
+ // i.e. trans[ a=b, a=b, a=b ].
+ //
+ // There are two cases:
+ // 1. The number of equalities is odd. Then, the sequence can be collapsed to just one equality,
+ // i.e. a=b.
+ // 2. The number of equalities is even. Now, we have two options: a=a or b=b. To determine this,
+ // we look at the node after the equality sequence. If it needs a, we go for a=a; and if it needs
+ // b, we go for b=b. If there is no following node, we look at the goal of the transitivity proof,
+ // and use it to determine which option we need.
+ if(n2.getKind() == kind::EQUAL || n2.getKind() == kind::IFF) {
+ if (((n1[0] == n2[0]) && (n1[1] == n2[1])) || ((n1[0] == n2[1]) && (n1[1] == n2[0]))) {
+ // We are in a sequence of identical equalities
+
+ Debug("gk::proof") << "Detected identical equalities: " << std::endl << "\t" << n1 << std::endl;
+
+ if (!identicalEqualities) {
+ // The sequence of identical equalities has started just now
+ identicalEqualities = true;
+
+ Debug("gk::proof") << "The sequence is just beginning. Determining length..." << std::endl;
+
+ // Determine whether the length of this sequence is odd or even.
+ evenLengthSequence = true;
+ bool sequenceOver = false;
+ size_t j = i + 1;
+
+ while (j < pf->d_children.size() && !sequenceOver) {
+ std::stringstream dontCare;
+ nodeAfterEqualitySequence = toStreamRecLFSC(dontCare, tp, pf->d_children[j], tb + 1, map );
+
+ if (((nodeAfterEqualitySequence[0] == n1[0]) && (nodeAfterEqualitySequence[1] == n1[1])) ||
+ ((nodeAfterEqualitySequence[0] == n1[1]) && (nodeAfterEqualitySequence[1] == n1[0]))) {
+ evenLengthSequence = !evenLengthSequence;
+ } else {
+ sequenceOver = true;
+ }
+
+ ++j;
+ }
+
+ if (evenLengthSequence) {
+ // If the length is even, we need to apply transitivity for the "correct" hand of the equality.
+
+ Debug("gk::proof") << "Equality sequence of even length" << std::endl;
+ Debug("gk::proof") << "n1 is: " << n1 << std::endl;
+ Debug("gk::proof") << "n2 is: " << n2 << std::endl;
+ Debug("gk::proof") << "pf-d_node is: " << pf->d_node << std::endl;
+ Debug("gk::proof") << "Next node is: " << nodeAfterEqualitySequence << std::endl;
+
+ ss << "(trans _ _ _ _ ";
+
+ // If the sequence is at the very end of the transitivity proof, use pf->d_node to guide us.
+ if (!sequenceOver) {
+ if (match(n1[0], pf->d_node[0])) {
+ n1 = eqNode(n1[0], n1[0]);
+ ss << ss1.str() << " (symm _ _ _ " << ss1.str() << ")";
+ } else if (match(n1[1], pf->d_node[1])) {
+ n1 = eqNode(n1[1], n1[1]);
+ ss << " (symm _ _ _ " << ss1.str() << ")" << ss1.str();
+ } else {
+ Debug("gk::proof") << "Error: identical equalities over, but hands don't match what we're proving."
+ << std::endl;
+ Assert(false);
+ }
+ } else {
+ // We have a "next node". Use it to guide us.
+
+ Assert(nodeAfterEqualitySequence.getKind() == kind::EQUAL ||
+ nodeAfterEqualitySequence.getKind() == kind::IFF);
+
+ if ((n1[0] == nodeAfterEqualitySequence[0]) || (n1[0] == nodeAfterEqualitySequence[1])) {
+
+ // Eliminate n1[1]
+ ss << ss1.str() << " (symm _ _ _ " << ss1.str() << ")";
+ n1 = eqNode(n1[0], n1[0]);
+
+ } else if ((n1[1] == nodeAfterEqualitySequence[0]) || (n1[1] == nodeAfterEqualitySequence[1])) {
+
+ // Eliminate n1[0]
+ ss << " (symm _ _ _ " << ss1.str() << ")" << ss1.str();
+ n1 = eqNode(n1[1], n1[1]);
+
+ } else {
+ Debug("gk::proof") << "Error: even length sequence, but I don't know which hand to keep!" << std::endl;
+ Assert(false);
+ }
+ }
+
+ ss << ")";
+
+ } else {
+ Debug("gk::proof") << "Equality sequence length is odd!" << std::endl;
+ ss.str(ss1.str());
+ }
+
+ Debug("gk::proof") << "Have proven: " << n1 << std::endl;
+ } else {
+ ss.str(ss1.str());
+ }
+
+ // Ignore the redundancy.
+ continue;
+ }
+ }
+
+ if (identicalEqualities) {
+ // We were in a sequence of identical equalities, but it has now ended. Resume normal operation.
+ identicalEqualities = false;
+ }
+
+ Debug("mgd") << "\ndoing trans proof, got n2 " << n2 << "\n";
+ if(tb == 1) {
+ Debug("mgdx") << "\ntrans proof[" << i << "], got n2 " << n2 << "\n";
+ Debug("mgdx") << (n2.getKind() == kind::EQUAL || n2.getKind() == kind::IFF) << "\n";
+
+ if ((n1.getNumChildren() >= 2) && (n2.getNumChildren() >= 2)) {
+ Debug("mgdx") << n1[0].getId() << " " << n1[1].getId() << " / " << n2[0].getId() << " " << n2[1].getId() << "\n";
+ Debug("mgdx") << n1[0].getId() << " " << n1[0] << "\n";
+ Debug("mgdx") << n1[1].getId() << " " << n1[1] << "\n";
+ Debug("mgdx") << n2[0].getId() << " " << n2[0] << "\n";
+ Debug("mgdx") << n2[1].getId() << " " << n2[1] << "\n";
+ Debug("mgdx") << (n1[0] == n2[0]) << "\n";
+ Debug("mgdx") << (n1[1] == n2[1]) << "\n";
+ Debug("mgdx") << (n1[0] == n2[1]) << "\n";
+ Debug("mgdx") << (n1[1] == n2[0]) << "\n";
+ }
+ }
+ ss << "(trans _ _ _ _ ";
+
+ if((n2.getKind() == kind::EQUAL || n2.getKind() == kind::IFF) &&
+ (n1.getKind() == kind::EQUAL || n1.getKind() == kind::IFF))
+ // Both elements of the transitivity rule are equalities/iffs
+ {
+ if(n1[0] == n2[0]) {
+ if(tb == 1) { Debug("mgdx") << "case 1\n"; }
+ n1 = eqNode(n1[1], n2[1]);
+ ss << "(symm _ _ _ " << ss1.str() << ") " << ss2.str();
+ } else if(n1[1] == n2[1]) {
+ if(tb == 1) { Debug("mgdx") << "case 2\n"; }
+ n1 = eqNode(n1[0], n2[0]);
+ ss << ss1.str() << " (symm _ _ _ " << ss2.str() << ")";
+ } else if(n1[0] == n2[1]) {
+ if(tb == 1) { Debug("mgdx") << "case 3\n"; }
+ n1 = eqNode(n2[0], n1[1]);
+ ss << ss2.str() << " " << ss1.str();
+ if(tb == 1) { Debug("mgdx") << "++ proved " << n1 << "\n"; }
+ } else if(n1[1] == n2[0]) {
+ if(tb == 1) { Debug("mgdx") << "case 4\n"; }
+ n1 = eqNode(n1[0], n2[1]);
+ ss << ss1.str() << " " << ss2.str();
+ } else {
+ Warning() << "\n\ntrans proof failure at step " << i << "\n\n";
+ Warning() << "0 proves " << n1 << "\n";
+ Warning() << "1 proves " << n2 << "\n\n";
+ pf->debug_print("mgdx",0);
+ //toStreamRec(Warning.getStream(), pf, 0);
+ Warning() << "\n\n";
+ Unreachable();
+ }
+ Debug("mgd") << "++ trans proof[" << i << "], now have " << n1 << std::endl;
+ } else if(n1.getKind() == kind::EQUAL || n1.getKind() == kind::IFF) {
+ // n1 is an equality/iff, but n2 is a predicate
+ if(n1[0] == n2) {
+ n1 = n1[1];
+ ss << "(symm _ _ _ " << ss1.str() << ") (pred_eq_t _ " << ss2.str() << ")";
+ } else if(n1[1] == n2) {
+ n1 = n1[0];
+ ss << ss1.str() << " (pred_eq_t _ " << ss2.str() << ")";
+ } else {
+ Unreachable();
+ }
+ } else if(n2.getKind() == kind::EQUAL || n2.getKind() == kind::IFF) {
+ // n2 is an equality/iff, but n1 is a predicate
+ if(n2[0] == n1) {
+ n1 = n2[1];
+ ss << "(symm _ _ _ " << ss2.str() << ") (pred_eq_t _ " << ss1.str() << ")";
+ } else if(n2[1] == n1) {
+ n1 = n2[0];
+ ss << ss2.str() << " (pred_eq_t _ " << ss1.str() << ")";
+ } else {
+ Unreachable();
+ }
+ } else {
+ // Both n1 and n2 are prediacates. Don't know what to do...
+ Unreachable();
+ }
+
+ ss << ")";
+ }
+ out << ss.str();
+ Debug("mgd") << "\n++ trans proof done, have proven " << n1 << std::endl;
+ return n1;
+ }
+
+ case eq::MERGED_ARRAYS_ROW: {
+ Debug("mgd") << "row lemma: " << pf->d_node << std::endl;
+ Assert(pf->d_node.getKind() == kind::EQUAL);
+ TNode t1, t2, t3, t4;
+ Node ret;
+ if(pf->d_node[1].getKind() == kind::SELECT &&
+ pf->d_node[1][0].getKind() == kind::STORE &&
+ pf->d_node[0].getKind() == kind::SELECT &&
+ pf->d_node[0][0] == pf->d_node[1][0][0] &&
+ pf->d_node[0][1] == pf->d_node[1][1]) {
+ t2 = pf->d_node[1][0][1];
+ t3 = pf->d_node[1][1];
+ t1 = pf->d_node[0][0];
+ t4 = pf->d_node[1][0][2];
+ ret = pf->d_node[1].eqNode(pf->d_node[0]);
+ Debug("mgd") << "t1 " << t1 << "\nt2 " << t2 << "\nt3 " << t3 << "\nt4 " << t4 << "\n";
+ } else {
+ Assert(pf->d_node[0].getKind() == kind::SELECT &&
+ pf->d_node[0][0].getKind() == kind::STORE &&
+ pf->d_node[1].getKind() == kind::SELECT &&
+ pf->d_node[1][0] == pf->d_node[0][0][0] &&
+ pf->d_node[1][1] == pf->d_node[0][1]);
+ t2 = pf->d_node[0][0][1];
+ t3 = pf->d_node[0][1];
+ t1 = pf->d_node[1][0];
+ t4 = pf->d_node[0][0][2];
+ ret = pf->d_node;
+ Debug("mgd") << "t1 " << t1 << "\nt2 " << t2 << "\nt3 " << t3 << "\nt4 " << t4 << "\n";
+ }
+ out << "(row _ _ ";
+ tp->printTerm(t2.toExpr(), out, map);
+ out << " ";
+ tp->printTerm(t3.toExpr(), out, map);
+ out << " ";
+ tp->printTerm(t1.toExpr(), out, map);
+ out << " ";
+ tp->printTerm(t4.toExpr(), out, map);
+ out << " " << ProofManager::getLitName(t2.eqNode(t3)) << ")";
+ return ret;
+ }
+
+ case eq::MERGED_ARRAYS_ROW1: {
+ Debug("mgd") << "row1 lemma: " << pf->d_node << std::endl;
+ Assert(pf->d_node.getKind() == kind::EQUAL);
+ TNode t1, t2, t3;
+ Node ret;
+ if(pf->d_node[1].getKind() == kind::SELECT &&
+ pf->d_node[1][0].getKind() == kind::STORE &&
+ pf->d_node[1][0][1] == pf->d_node[1][1] &&
+ pf->d_node[1][0][2] == pf->d_node[0]) {
+ t1 = pf->d_node[1][0][0];
+ t2 = pf->d_node[1][0][1];
+ t3 = pf->d_node[0];
+ ret = pf->d_node[1].eqNode(pf->d_node[0]);
+ Debug("mgd") << "t1 " << t1 << "\nt2 " << t2 << "\nt3 " << t3 << "\n";
+ } else {
+ Assert(pf->d_node[0].getKind() == kind::SELECT &&
+ pf->d_node[0][0].getKind() == kind::STORE &&
+ pf->d_node[0][0][1] == pf->d_node[0][1] &&
+ pf->d_node[0][0][2] == pf->d_node[1]);
+ t1 = pf->d_node[0][0][0];
+ t2 = pf->d_node[0][0][1];
+ t3 = pf->d_node[1];
+ ret = pf->d_node;
+ Debug("mgd") << "t1 " << t1 << "\nt2 " << t2 << "\nt3 " << t3 << "\n";
+ }
+ out << "(row1 _ _ ";
+ tp->printTerm(t1.toExpr(), out, map);
+ out << " ";
+ tp->printTerm(t2.toExpr(), out, map);
+ out << " ";
+ tp->printTerm(t3.toExpr(), out, map);
+ out << ")";
+ return ret;
+ }
+
+ default:
+ Assert(!pf->d_node.isNull());
+ Assert(pf->d_children.empty());
+ Debug("mgd") << "theory proof: " << pf->d_node << " by rule " << int(pf->d_id) << std::endl;
+ AlwaysAssert(false);
+ return pf->d_node;
+ }
+}
+
+UFProof::UFProof(theory::uf::TheoryUF* uf, TheoryProofEngine* pe)
+ : TheoryProof(uf, pe)
+{}
+
+void UFProof::registerTerm(Expr term) {
+ // already registered
+ if (d_declarations.find(term) != d_declarations.end())
+ return;
+
+ Type type = term.getType();
+ if (type.isSort()) {
+ // declare uninterpreted sorts
+ d_sorts.insert(type);
+ }
+
+ if (term.getKind() == kind::APPLY_UF) {
+ Expr function = term.getOperator();
+ d_declarations.insert(function);
+ }
+
+ if (term.isVariable()) {
+ d_declarations.insert(term);
+ }
+
+ // recursively declare all other terms
+ for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+ // could belong to other theories
+ d_proofEngine->registerTerm(term[i]);
+ }
+}
+
+void LFSCUFProof::printTerm(Expr term, std::ostream& os, const LetMap& map) {
+ Assert (Theory::theoryOf(term) == THEORY_UF);
+
+ if (term.getKind() == kind::VARIABLE ||
+ term.getKind() == kind::SKOLEM) {
+ os << term;
+ return;
+ }
+
+ Assert (term.getKind() == kind::APPLY_UF);
+
+ if(term.getType().isBoolean()) {
+ os << "(p_app ";
+ }
+ Expr func = term.getOperator();
+ for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+ os << "(apply _ _ ";
+ }
+ os << func << " ";
+ for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+ printTerm(term[i], os, map);
+ os << ")";
+ }
+ if(term.getType().isBoolean()) {
+ os << ")";
+ }
+}
+
+void LFSCUFProof::printSort(Type type, std::ostream& os) {
+ Assert (type.isSort());
+ os << type <<" ";
+}
+
+void LFSCUFProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren) {
+ os << " ;; UF Theory Lemma \n;;";
+ for (unsigned i = 0; i < lemma.size(); ++i) {
+ os << lemma[i] <<" ";
+ }
+ os <<"\n";
+ //os << " (clausify_false trust)";
+ UFProof::printTheoryLemmaProof( lemma, os, paren );
+}
+
+void LFSCUFProof::printDeclarations(std::ostream& os, std::ostream& paren) {
+ // declaring the sorts
+ for (TypeSet::const_iterator it = d_sorts.begin(); it != d_sorts.end(); ++it) {
+ os << "(% " << *it << " sort\n";
+ paren << ")";
+ }
+
+ // declaring the terms
+ for (ExprSet::const_iterator it = d_declarations.begin(); it != d_declarations.end(); ++it) {
+ Expr term = *it;
+
+ os << "(% " << ProofManager::sanitize(term) << " ";
+ os << "(term ";
+
+ Type type = term.getType();
+ if (type.isFunction()) {
+ std::ostringstream fparen;
+ FunctionType ftype = (FunctionType)type;
+ std::vector<Type> args = ftype.getArgTypes();
+ args.push_back(ftype.getRangeType());
+ os << "(arrow";
+ for (unsigned i = 0; i < args.size(); i++) {
+ Type arg_type = args[i];
+ os << " " << arg_type;
+ if (i < args.size() - 2) {
+ os << " (arrow";
+ fparen << ")";
+ }
+ }
+ os << fparen.str() << "))\n";
+ } else {
+ Assert (term.isVariable());
+ os << type << ")\n";
+ }
+ paren << ")";
+ }
+}
diff --git a/src/proof/uf_proof.h b/src/proof/uf_proof.h
new file mode 100644
index 000000000..121db1fcd
--- /dev/null
+++ b/src/proof/uf_proof.h
@@ -0,0 +1,75 @@
+/********************* */
+/*! \file uf_proof.h
+ ** \verbatim
+ ** Original author: Liana Hadarean
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief UF proof
+ **
+ ** UF proof
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__UF__PROOF_H
+#define __CVC4__UF__PROOF_H
+
+#include "expr/expr.h"
+#include "proof/proof_manager.h"
+#include "theory/uf/equality_engine.h"
+
+namespace CVC4 {
+
+//proof object outputted by TheoryUF
+class ProofUF : public Proof {
+private:
+ static Node toStreamRecLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, unsigned tb, const LetMap& map);
+public:
+ ProofUF( theory::eq::EqProof * pf ) : d_proof( pf ) {}
+ //it is simply an equality engine proof
+ theory::eq::EqProof * d_proof;
+ void toStream(std::ostream& out);
+ static void toStreamLFSC(std::ostream& out, TheoryProof * tp, theory::eq::EqProof * pf, const LetMap& map);
+};
+
+
+namespace theory {
+namespace uf {
+class TheoryUF;
+}
+}
+
+typedef __gnu_cxx::hash_set<Type, TypeHashFunction > TypeSet;
+
+
+class UFProof : public TheoryProof {
+protected:
+ TypeSet d_sorts; // all the uninterpreted sorts in this theory
+ ExprSet d_declarations; // all the variable/function declarations
+
+public:
+ UFProof(theory::uf::TheoryUF* uf, TheoryProofEngine* proofEngine);
+
+ virtual void registerTerm(Expr term);
+};
+
+class LFSCUFProof : public UFProof {
+public:
+ LFSCUFProof(theory::uf::TheoryUF* uf, TheoryProofEngine* proofEngine)
+ : UFProof(uf, proofEngine)
+ {}
+ virtual void printTerm(Expr term, std::ostream& os, const LetMap& map);
+ virtual void printSort(Type type, std::ostream& os);
+ virtual void printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren);
+ virtual void printDeclarations(std::ostream& os, std::ostream& paren);
+};
+
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__UF__PROOF_H */
diff --git a/src/prop/bvminisat/bvminisat.cpp b/src/prop/bvminisat/bvminisat.cpp
index be266b6d8..936778e0d 100644
--- a/src/prop/bvminisat/bvminisat.cpp
+++ b/src/prop/bvminisat/bvminisat.cpp
@@ -19,6 +19,7 @@
#include "prop/bvminisat/bvminisat.h"
#include "prop/bvminisat/simp/SimpSolver.h"
+#include "proof/sat_proof.h"
#include "util/statistics_registry.h"
namespace CVC4 {
@@ -47,14 +48,18 @@ void BVMinisatSatSolver::setNotify(Notify* notify) {
d_minisat->setNotify(d_minisatNotify);
}
-void BVMinisatSatSolver::addClause(SatClause& clause, bool removable, uint64_t proof_id) {
+ClauseId BVMinisatSatSolver::addClause(SatClause& clause,
+ bool removable) {
Debug("sat::minisat") << "Add clause " << clause <<"\n";
BVMinisat::vec<BVMinisat::Lit> minisat_clause;
toMinisatClause(clause, minisat_clause);
// for(unsigned i = 0; i < minisat_clause.size(); ++i) {
// d_minisat->setFrozen(BVMinisat::var(minisat_clause[i]), true);
// }
- d_minisat->addClause(minisat_clause);
+ ClauseId clause_id = ClauseIdError;
+ d_minisat->addClause(minisat_clause, clause_id);
+ THEORY_PROOF(Assert (clause_id != ClauseIdError););
+ return clause_id;
}
SatValue BVMinisatSatSolver::propagate() {
@@ -91,6 +96,10 @@ void BVMinisatSatSolver::popAssumption() {
d_minisat->popAssumption();
}
+void BVMinisatSatSolver::setProofLog( BitVectorProof * bvp ) {
+ d_minisat->setProofLog( bvp );
+}
+
SatVariable BVMinisatSatSolver::newVar(bool isTheoryAtom, bool preRegister, bool canErase){
return d_minisat->newVar(true, true, !canErase);
}
@@ -126,6 +135,10 @@ SatValue BVMinisatSatSolver::solve(long unsigned int& resource){
return result;
}
+bool BVMinisatSatSolver::ok() const {
+ return d_minisat->okay();
+}
+
void BVMinisatSatSolver::getUnsatCore(SatClause& unsatCore) {
// TODO add assertion to check the call was after an unsat call
for (int i = 0; i < d_minisat->conflict.size(); ++i) {
@@ -199,8 +212,8 @@ void BVMinisatSatSolver::toMinisatClause(SatClause& clause,
Assert(clause.size() == (unsigned)minisat_clause.size());
}
-void BVMinisatSatSolver::toSatClause(BVMinisat::vec<BVMinisat::Lit>& clause,
- SatClause& sat_clause) {
+void BVMinisatSatSolver::toSatClause(const BVMinisat::Clause& clause,
+ SatClause& sat_clause) {
for (int i = 0; i < clause.size(); ++i) {
sat_clause.push_back(toSatLiteral(clause[i]));
}
@@ -281,3 +294,19 @@ void BVMinisatSatSolver::Statistics::init(BVMinisat::SimpSolver* minisat){
} /* namespace CVC4::prop */
} /* namespace CVC4 */
+
+namespace CVC4 {
+template<>
+prop::SatLiteral toSatLiteral< BVMinisat::Solver>(BVMinisat::Solver::TLit lit) {
+ return prop::BVMinisatSatSolver::toSatLiteral(lit);
+}
+
+template<>
+void toSatClause< BVMinisat::Solver> (const BVMinisat::Solver::TClause& minisat_cl,
+ prop::SatClause& sat_cl) {
+ prop::BVMinisatSatSolver::toSatClause(minisat_cl, sat_cl);
+}
+
+}
+
+
diff --git a/src/prop/bvminisat/bvminisat.h b/src/prop/bvminisat/bvminisat.h
index 986fbf339..383948e3e 100644
--- a/src/prop/bvminisat/bvminisat.h
+++ b/src/prop/bvminisat/bvminisat.h
@@ -43,7 +43,9 @@ private:
}
void notify(BVMinisat::vec<BVMinisat::Lit>& clause) {
SatClause satClause;
- toSatClause(clause, satClause);
+ for (int i = 0; i < clause.size(); ++i) {
+ satClause.push_back(toSatLiteral(clause[i]));
+ }
d_notify->notify(satClause);
}
@@ -73,7 +75,7 @@ public:
void setNotify(Notify* notify);
- void addClause(SatClause& clause, bool removable, uint64_t proof_id);
+ ClauseId addClause(SatClause& clause, bool removable);
SatValue propagate();
@@ -88,6 +90,7 @@ public:
SatValue solve();
SatValue solve(long unsigned int&);
+ bool ok() const;
void getUnsatCore(SatClause& unsatCore);
SatValue value(SatLiteral l);
@@ -106,7 +109,7 @@ public:
static SatValue toSatLiteralValue(BVMinisat::lbool res);
static void toMinisatClause(SatClause& clause, BVMinisat::vec<BVMinisat::Lit>& minisat_clause);
- static void toSatClause (BVMinisat::vec<BVMinisat::Lit>& clause, SatClause& sat_clause);
+ static void toSatClause (const BVMinisat::Clause& clause, SatClause& sat_clause);
void addMarkerLiteral(SatLiteral lit);
void explain(SatLiteral lit, std::vector<SatLiteral>& explanation);
@@ -114,6 +117,8 @@ public:
SatValue assertAssumption(SatLiteral lit, bool propagate);
void popAssumption();
+
+ void setProofLog( BitVectorProof * bvp );
private:
/* Disable the default constructor. */
diff --git a/src/prop/bvminisat/core/Solver.cc b/src/prop/bvminisat/core/Solver.cc
index 5a37da27c..2100160de 100644
--- a/src/prop/bvminisat/core/Solver.cc
+++ b/src/prop/bvminisat/core/Solver.cc
@@ -31,6 +31,10 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include "options/bv_options.h"
#include "options/smt_options.h"
#include "theory/interrupted.h"
+#include "proof/proof_manager.h"
+#include "proof/bitvector_proof.h"
+#include "proof/sat_proof.h"
+#include "proof/sat_proof_implementation.h"
#include "util/utility.h"
namespace CVC4 {
@@ -60,19 +64,6 @@ std::ostream& operator << (std::ostream& out, const BVMinisat::Clause& c) {
static const char* _cat = "CORE";
-// static DoubleOption opt_var_decay (_cat, "var-decay", "The variable activity decay factor", 0.95, DoubleRange(0, false, 1, false));
-// static DoubleOption opt_clause_decay (_cat, "cla-decay", "The clause activity decay factor", 0.999, DoubleRange(0, false, 1, false));
-// static DoubleOption opt_random_var_freq (_cat, "rnd-freq", "The frequency with which the decision heuristic tries to choose a random variable", 0.0, DoubleRange(0, true, 1, true));
-// static DoubleOption opt_random_seed (_cat, "rnd-seed", "Used by the random variable selection", 91648253, DoubleRange(0, false, HUGE_VAL, false));
-// static IntOption opt_ccmin_mode (_cat, "ccmin-mode", "Controls conflict clause minimization (0=none, 1=basic, 2=deep)", 0, IntRange(0, 2));
-// static IntOption opt_phase_saving (_cat, "phase-saving", "Controls the level of phase saving (0=none, 1=limited, 2=full)", 2, IntRange(0, 2));
-// static BoolOption opt_rnd_init_act (_cat, "rnd-init", "Randomize the initial activity", false);
-// static BoolOption opt_luby_restart (_cat, "luby", "Use the Luby restart sequence", true);
-// static IntOption opt_restart_first (_cat, "rfirst", "The base restart interval", 100, IntRange(1, INT32_MAX));
-// static DoubleOption opt_restart_inc (_cat, "rinc", "Restart interval increase factor", 1.5, DoubleRange(1, false, HUGE_VAL, false));
-// static DoubleOption opt_garbage_frac (_cat, "gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered", 0.20, DoubleRange(0, false, HUGE_VAL, false));
-
-
static DoubleOption opt_var_decay (_cat, "var-decay", "The variable activity decay factor", 0.95, DoubleRange(0, false, 1, false));
static DoubleOption opt_clause_decay (_cat, "cla-decay", "The clause activity decay factor", 0.999, DoubleRange(0, false, 1, false));
static DoubleOption opt_random_var_freq (_cat, "rnd-freq", "The frequency with which the decision heuristic tries to choose a random variable", 0, DoubleRange(0, true, 1, true));
@@ -86,6 +77,12 @@ static DoubleOption opt_restart_inc (_cat, "rinc", "Restart interv
static DoubleOption opt_garbage_frac (_cat, "gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered", 0.20, DoubleRange(0, false, HUGE_VAL, false));
//=================================================================================================
+// Proof declarations
+CRef Solver::TCRef_Undef = CRef_Undef;
+CRef Solver::TCRef_Lazy = CRef_Undef - 1; // no real lazy ref here
+
+
+//=================================================================================================
// Constructor/Destructor:
@@ -150,6 +147,7 @@ Solver::Solver(CVC4::context::Context* c) :
, conflict_budget (-1)
, propagation_budget (-1)
, asynch_interrupt (false)
+ , d_bvp (NULL)
{
// Create the constant variables
varTrue = newVar(true, false);
@@ -193,37 +191,114 @@ Var Solver::newVar(bool sign, bool dvar)
}
-bool Solver::addClause_(vec<Lit>& ps)
+bool Solver::addClause_(vec<Lit>& ps, ClauseId& id)
{
if (decisionLevel() > 0) {
cancelUntil(0);
}
- if (!ok) return false;
+ if (!ok) {
+ id = ClauseIdUndef;
+ return false;
+ }
// Check if clause is satisfied and remove false/duplicate literals:
+ // TODO proof for duplicate literals removal?
sort(ps);
Lit p; int i, j;
- for (i = j = 0, p = lit_Undef; i < ps.size(); i++)
- if (value(ps[i]) == l_True || ps[i] == ~p)
- return true;
- else if (value(ps[i]) != l_False && ps[i] != p)
- ps[j++] = p = ps[i];
+ int falseLiteralsCount = 0;
+
+ for (i = j = 0, p = lit_Undef; i < ps.size(); i++) {
+ // tautologies are ignored
+ if (value(ps[i]) == l_True || ps[i] == ~p) {
+ id = ClauseIdUndef;
+ return true;
+ }
+
+ // Ignore repeated literals
+ if (ps[i] == p) {
+ continue;
+ }
+
+ if (value(ps[i]) == l_False) {
+ if (!THEORY_PROOF_ON())
+ continue;
+ ++falseLiteralsCount;
+ }
+ ps[j++] = p = ps[i];
+ }
+
ps.shrink(i - j);
clause_added = true;
- if (ps.size() == 0)
+ Assert(falseLiteralsCount == 0 || THEORY_PROOF_ON());
+
+ if(falseLiteralsCount == 0) {
+ if (ps.size() == 0) {
+ Assert (!THEORY_PROOF_ON());
return ok = false;
- else if (ps.size() == 1){
+ }
+ else if (ps.size() == 1){
+ if(d_bvp){ id = d_bvp->getSatProof()->registerUnitClause(ps[0], INPUT);}
uncheckedEnqueue(ps[0]);
- return ok = (propagate() == CRef_Undef);
- } else {
+ CRef confl_ref = propagate();
+ ok = (confl_ref == CRef_Undef);
+ if(d_bvp){ if (!ok) d_bvp->getSatProof()->finalizeProof(confl_ref); }
+ return ok;
+ } else {
CRef cr = ca.alloc(ps, false);
clauses.push(cr);
attachClause(cr);
+ if(d_bvp){ id = d_bvp->getSatProof()->registerClause(cr, INPUT);}
+ }
+ return ok;
}
- return ok;
+
+ if (falseLiteralsCount != 0 && THEORY_PROOF_ON()) {
+ // we are in a conflicting state
+ if (ps.size() == falseLiteralsCount && falseLiteralsCount == 1) {
+ if(d_bvp){ id = d_bvp->getSatProof()->storeUnitConflict(ps[0], INPUT); }
+ if(d_bvp){ d_bvp->getSatProof()->finalizeProof(CVC4::BVMinisat::CRef_Lazy); }
+ return ok = false;
+ }
+
+ assign_lt lt(*this);
+ sort(ps, lt);
+
+ CRef cr = ca.alloc(ps, false);
+ clauses.push(cr);
+ attachClause(cr);
+
+ if(d_bvp){id = d_bvp->getSatProof()->registerClause(cr, INPUT);}
+
+ if(ps.size() == falseLiteralsCount) {
+ if(d_bvp){ d_bvp->getSatProof()->finalizeProof(cr); }
+ return ok = false;
+ }
+
+ // Check if it propagates
+ if (ps.size() == falseLiteralsCount + 1) {
+ Clause& cl = ca[cr];
+
+ Assert (value(cl[0]) == l_Undef);
+ uncheckedEnqueue(cl[0], cr);
+ Assert (cl.size() > 1);
+ CRef confl = propagate();
+ ok = (confl == CRef_Undef);
+ if(!ok) {
+ if(d_bvp){
+ if(ca[confl].size() == 1) {
+ id = d_bvp->getSatProof()->storeUnitConflict(ca[confl][0], LEARNT);
+ d_bvp->getSatProof()->finalizeProof(CVC4::BVMinisat::CRef_Lazy);
+ } else {
+ d_bvp->getSatProof()->finalizeProof(confl);
+ }
+ }
+ }
+ }
+ }
+ return ok;
}
void Solver::attachClause(CRef cr) {
@@ -237,6 +312,8 @@ void Solver::attachClause(CRef cr) {
void Solver::detachClause(CRef cr, bool strict) {
const Clause& c = ca[cr];
+ if(d_bvp){ d_bvp->getSatProof()->markDeleted(cr); }
+
assert(c.size() > 1);
if (strict){
@@ -342,6 +419,9 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip
int index = trail.size() - 1;
bool done = false;
+
+ if(d_bvp){ d_bvp->getSatProof()->startResChain(confl); }
+
do{
assert(confl != CRef_Undef); // (otherwise should be UIP)
Clause& c = ca[confl];
@@ -352,7 +432,7 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip
for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++){
Lit q = c[j];
- if (!seen[var(q)] && level(var(q)) > 0){
+ if (!seen[var(q)] && level(var(q)) > 0) {
varBumpActivity(var(q));
seen[var(q)] = 1;
if (level(var(q)) >= decisionLevel())
@@ -360,6 +440,10 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip
else
out_learnt.push(q);
}
+
+ if (level(var(q)) == 0) {
+ if(d_bvp){ d_bvp->getSatProof()->resolveOutUnit(q); }
+ }
}
// Select next clause to look at:
@@ -369,6 +453,10 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip
seen[var(p)] = 0;
pathC--;
+ if ( pathC > 0 && confl != CRef_Undef ) {
+ if(d_bvp){ d_bvp->getSatProof()->addResolutionStep(p, confl, sign(p));}
+ }
+
switch (uip) {
case UIP_FIRST:
done = pathC == 0;
@@ -392,11 +480,22 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip
for (i = 1; i < out_learnt.size(); i++)
abstract_level |= abstractLevel(var(out_learnt[i])); // (maintain an abstraction of levels involved in conflict)
- for (i = j = 1; i < out_learnt.size(); i++)
- if (reason(var(out_learnt[i])) == CRef_Undef || !litRedundant(out_learnt[i], abstract_level))
+ for (i = j = 1; i < out_learnt.size(); i++) {
+ if (reason(var(out_learnt[i])) == CRef_Undef) {
+ out_learnt[j++] = out_learnt[i];
+ } else {
+ // Check if the literal is redundant
+ if (!litRedundant(out_learnt[i], abstract_level)) {
+ // Literal is not redundant
out_learnt[j++] = out_learnt[i];
+ } else {
+ if(d_bvp){ d_bvp->getSatProof()->storeLitRedundant(out_learnt[i]); }
+ }
+ }
+ }
}else if (ccmin_mode == 1){
+ Unreachable();
for (i = j = 1; i < out_learnt.size(); i++){
Var x = var(out_learnt[i]);
@@ -452,10 +551,13 @@ 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(var(analyze_stack.last())) != CRef_Undef);
- Clause& c = ca[reason(var(analyze_stack.last()))]; analyze_stack.pop();
+ CRef c_reason = reason(var(analyze_stack.last()));
+ assert(c_reason != CRef_Undef);
+ Clause& c = ca[c_reason];
+ int c_size = c.size();
+ analyze_stack.pop();
- for (int i = 1; i < c.size(); i++){
+ for (int i = 1; i < c_size; i++){
Lit p = c[i];
if (!seen[var(p)] && level(var(p)) > 0){
if (reason(var(p)) != CRef_Undef && (abstractLevel(var(p)) & abstract_levels) != 0){
@@ -495,21 +597,36 @@ void Solver::analyzeFinal2(Lit p, CRef confl_clause, vec<Lit>& out_conflict) {
seen[var(cl[i])] = 1;
}
- for (int i = trail.size() - 1; i >= trail_lim[0]; i--) {
+ int end = options::proof() ? 0 : trail_lim[0];
+ for (int i = trail.size() - 1; i >= end; i--) {
Var x = var(trail[i]);
if (seen[x]) {
if (reason(x) == CRef_Undef) {
// we skip p if was a learnt unit
if (x != var(p)) {
- assert (marker[x] == 2);
- assert (level(x) > 0);
- out_conflict.push(~trail[i]);
+ if (marker[x] == 2) {
+ assert (level(x) > 0);
+ out_conflict.push(~trail[i]);
+ } else {
+ if(d_bvp){d_bvp->getSatProof()->resolveOutUnit(~(trail[i])); }
+ }
+ } else {
+ if(d_bvp){d_bvp->getSatProof()->resolveOutUnit(~p);}
}
} else {
Clause& c = ca[reason(x)];
- for (int j = 1; j < c.size(); j++)
+ if(d_bvp){d_bvp->getSatProof()->addResolutionStep(trail[i],reason(x), sign(trail[i]));}
+
+ for (int j = 1; j < c.size(); j++) {
if (level(var(c[j])) > 0)
seen[var(c[j])] = 1;
+ if(d_bvp){
+ if (level(var(c[j])) == 0) {
+ d_bvp->getSatProof()->resolveOutUnit(c[j]);
+ seen[var(c[j])] = 0; // we don't need to resolve it out again
+ }
+ }
+ }
}
seen[x] = 0;
}
@@ -534,12 +651,23 @@ void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict)
out_conflict.push(p);
}
- if (decisionLevel() == 0)
- return;
+ if(d_bvp){
+ if (level(var(p)) == 0 && d_bvp->isAssumptionConflict()) {
+ Assert ( marker[var(p)] == 2);
+ if (reason(var(p)) == CRef_Undef) {
+ d_bvp->startBVConflict(p);
+ }
+ }
+ }
+
+ if (decisionLevel() == 0 && !options::proof()) {
+ return;
+ }
seen[var(p)] = 1;
-
- for (int i = trail.size()-1; i >= trail_lim[0]; i--){
+ int end = options::proof() ? 0 : trail_lim[0];
+
+ for (int i = trail.size()-1; i >= end; i--){
Var x = var(trail[i]);
if (seen[x]) {
if (reason(x) == CRef_Undef) {
@@ -548,9 +676,24 @@ void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict)
out_conflict.push(~trail[i]);
} else {
Clause& c = ca[reason(x)];
- for (int j = 1; j < c.size(); j++)
- if (level(var(c[j])) > 0)
+ if(d_bvp){
+ if (d_bvp->isAssumptionConflict() &&
+ trail[i] == p) {
+ d_bvp->startBVConflict(reason(x));
+ } else {
+ d_bvp->getSatProof()->addResolutionStep(trail[i], reason(x), sign(trail[i]));
+ }
+ }
+ for (int j = 1; j < c.size(); j++) {
+ if (level(var(c[j])) > 0) {
seen[var(c[j])] = 1;
+ }
+ if(d_bvp){
+ if (level(var(c[j])) == 0) {
+ d_bvp->getSatProof()->resolveOutUnit(c[j]);
+ }
+ }
+ }
}
seen[x] = 0;
}
@@ -588,9 +731,12 @@ lbool Solver::propagateAssumptions() {
}
lbool Solver::assertAssumption(Lit p, bool propagate) {
+ // TODO need to somehow mark the assumption as unit in the current context?
+ // it's not always unit though, but this would be useful for debugging
// assert(marker[var(p)] == 1);
+
if (decisionLevel() > assumptions.size()) {
cancelUntil(assumptions.size());
}
@@ -601,7 +747,8 @@ lbool Solver::assertAssumption(Lit p, bool propagate) {
if (c->getLevel() > 0) {
assumptions.push(p);
} else {
- if (!addClause(p)) {
+ ClauseId id;
+ if (!addClause(p, id)) {
conflict.push(~p);
return l_False;
}
@@ -618,6 +765,14 @@ lbool Solver::assertAssumption(Lit p, bool propagate) {
}
}
+void Solver::addMarkerLiteral(Var var) {
+ // make sure it wasn't already marked
+ Assert(marker[var] == 0);
+ marker[var] = 1;
+ if(d_bvp){d_bvp->getSatProof()->registerAssumption(var);}
+}
+
+
/*_________________________________________________________________________________________________
|
| propagate : [void] -> [Clause*]
@@ -730,8 +885,13 @@ void Solver::removeSatisfied(vec<CRef>& cs)
int i, j;
for (i = j = 0; i < cs.size(); i++){
Clause& c = ca[cs[i]];
- if (satisfied(c))
+ if (satisfied(c)) {
+ if (locked(c)) {
+ // store a resolution of the literal c propagated
+ if(d_bvp){ d_bvp->getSatProof()->storeUnitResolution(c[0]); }
+ }
removeClause(cs[i]);
+ }
else
cs[j++] = cs[i];
}
@@ -807,7 +967,12 @@ lbool Solver::search(int nof_conflicts, UIP uip)
if (confl != CRef_Undef){
// CONFLICT
conflicts++; conflictC++;
- if (decisionLevel() == 0) return l_False;
+
+ if (decisionLevel() == 0) {
+ // can this happen for bv?
+ if(d_bvp){ d_bvp->getSatProof()->finalizeProof(confl);}
+ return l_False;
+ }
learnt_clause.clear();
analyze(confl, learnt_clause, backtrack_level, uip);
@@ -821,15 +986,42 @@ lbool Solver::search(int nof_conflicts, UIP uip)
learnts.push(cr);
attachClause(cr);
claBumpActivity(ca[cr]);
+ if(d_bvp){
+ ClauseId id = d_bvp->getSatProof()->registerClause(cr, LEARNT);
+ PSTATS(
+ __gnu_cxx::hash_set<int> cl_levels;
+ for (int i = 0; i < learnt_clause.size(); ++i) {
+ cl_levels.insert(level(var(learnt_clause[i])));
+ }
+ if( d_bvp ){ d_bvp->getSatProof()->storeClauseGlue(id, cl_levels.size()); }
+ )
+ d_bvp->getSatProof()->endResChain(id);
+ }
}
-
+
+ if (learnt_clause.size() == 1) {
+ // learning a unit clause
+ if(d_bvp){ d_bvp->getSatProof()->endResChain(learnt_clause[0]);}
+ }
+
// if the uip was an assumption we are unsat
if (level(var(p)) <= assumptions.size()) {
for (int i = 0; i < learnt_clause.size(); ++i) {
assert (level(var(learnt_clause[i])) <= decisionLevel());
seen[var(learnt_clause[i])] = 1;
}
+
+ // Starting new resolution chain for bit-vector proof
+ if( d_bvp ){
+ if (cr == CRef_Undef) {
+ d_bvp->startBVConflict(learnt_clause[0]);
+ }
+ else {
+ d_bvp->startBVConflict(cr);
+ }
+ }
analyzeFinal(p, conflict);
+ if(d_bvp){ d_bvp->endBVConflict(conflict); }
Debug("bvminisat::search") << OUTPUT_TAG << " conflict on assumptions " << std::endl;
return l_False;
}
@@ -843,7 +1035,10 @@ lbool Solver::search(int nof_conflicts, UIP uip)
CRef new_confl = propagate();
if (new_confl != CRef_Undef) {
// we have a conflict we now need to explain it
- analyzeFinal2(p, new_confl, conflict);
+ // TODO: proof for analyzeFinal2
+ if(d_bvp){ d_bvp->startBVConflict(new_confl); }
+ analyzeFinal2(p, new_confl, conflict);
+ if(d_bvp){ d_bvp->endBVConflict(conflict); }
return l_False;
}
}
@@ -912,7 +1107,10 @@ lbool Solver::search(int nof_conflicts, UIP uip)
newDecisionLevel();
}else if (value(p) == l_False){
marker[var(p)] = 2;
+
+ if(d_bvp){ d_bvp->markAssumptionConflict(); }
analyzeFinal(~p, conflict);
+ if(d_bvp){ d_bvp->endBVConflict(conflict); }
Debug("bvminisat::search") << OUTPUT_TAG << " assumption false, we're unsat" << std::endl;
return l_False;
}else{
@@ -1044,39 +1242,76 @@ lbool Solver::solve_()
//
void Solver::explain(Lit p, std::vector<Lit>& explanation) {
- vec<Lit> queue;
- queue.push(p);
-
Debug("bvminisat::explain") << OUTPUT_TAG << "starting explain of " << p << std::endl;
- __gnu_cxx::hash_set<Var> visited;
- visited.insert(var(p));
+ // top level fact, no explanation necessary
+ if (level(var(p)) == 0) {
+ if(d_bvp){
+ // the only way a marker variable is
+ if (reason(var(p)) == CRef_Undef) {
+ d_bvp->startBVConflict(p);
+ vec<Lit> confl;
+ confl.push(p);
+ d_bvp->endBVConflict(confl);
+ return;
+ }
+ }
+ if (!THEORY_PROOF_ON())
+ return;
+ }
- while(queue.size() > 0) {
- Lit l = queue.last();
-
- Debug("bvminisat::explain") << OUTPUT_TAG << "processing " << l << std::endl;
-
- assert(value(l) == l_True);
- queue.pop();
- if (reason(var(l)) == CRef_Undef) {
- if (level(var(l)) == 0) continue;
- Assert(marker[var(l)] == 2);
- explanation.push_back(l);
- visited.insert(var(l));
- } else {
- Clause& c = ca[reason(var(l))];
- for (int i = 1; i < c.size(); ++i) {
- if (level(var(c[i])) > 0 && visited.count(var(c[i])) == 0) {
- queue.push(~c[i]);
- visited.insert(var(c[i]));
+ seen[var(p)] = 1;
+
+ // if we are called at decisionLevel = 0 trail_lim is empty
+ int bottom = options::proof() ? 0 : trail_lim[0];
+ for (int i = trail.size()-1; i >= bottom; i--){
+ Var x = var(trail[i]);
+ if (seen[x]) {
+ if (reason(x) == CRef_Undef) {
+ if (marker[x] == 2) {
+ assert(level(x) > 0);
+ explanation.push_back(trail[i]);
+ } else {
+ Assert (level(x) == 0);
+ if(d_bvp){ d_bvp->getSatProof()->resolveOutUnit(~(trail[i])); }
+ }
+
+ } else {
+ Clause& c = ca[reason(x)];
+ if(d_bvp){
+ if (p == trail[i]) {
+ d_bvp->startBVConflict(reason(var(p)));
+ } else {
+ d_bvp->getSatProof()->addResolutionStep(trail[i], reason(x), sign(trail[i]));
+ }
+ }
+ for (int j = 1; j < c.size(); j++) {
+ if (level(var(c[j])) > 0 || options::proof()) {
+ seen[var(c[j])] = 1;
+ }
}
}
+ seen[x] = 0;
}
}
+ seen[var(p)] = 0;
+
+ if(d_bvp){
+ vec<Lit> conflict_clause;
+ conflict_clause.push(p);
+ for(unsigned i = 0; i < explanation.size(); ++i) {
+ conflict_clause.push(~explanation[i]);
+ }
+ d_bvp->endBVConflict(conflict_clause);
+ }
}
-
+void Solver::setProofLog( BitVectorProof * bvp ) {
+ d_bvp = bvp;
+ d_bvp->initSatProof(this);
+ d_bvp->getSatProof()->registerTrueLit(mkLit(varTrue, false));
+ d_bvp->getSatProof()->registerFalseLit(mkLit(varFalse, true));
+}
//=================================================================================================
// Writing CNF to DIMACS:
@@ -1171,7 +1406,7 @@ void Solver::relocAll(ClauseAllocator& to)
// printf(" >>> RELOCING: %s%d\n", sign(p)?"-":"", var(p)+1);
vec<Watcher>& ws = watches[p];
for (int j = 0; j < ws.size(); j++)
- ca.reloc(ws[j].cref, to);
+ ca.reloc(ws[j].cref, to, d_bvp ? d_bvp->getSatProof()->getProxy() : NULL);
}
// All reasons:
@@ -1180,18 +1415,20 @@ void Solver::relocAll(ClauseAllocator& to)
Var v = var(trail[i]);
if (reason(v) != CRef_Undef && (ca[reason(v)].reloced() || locked(ca[reason(v)])))
- ca.reloc(vardata[v].reason, to);
+ ca.reloc(vardata[v].reason, to, d_bvp ? d_bvp->getSatProof()->getProxy() : NULL);
}
// All learnt:
//
for (int i = 0; i < learnts.size(); i++)
- ca.reloc(learnts[i], to);
+ ca.reloc(learnts[i], to, d_bvp ? d_bvp->getSatProof()->getProxy() : NULL);
// All original:
//
for (int i = 0; i < clauses.size(); i++)
- ca.reloc(clauses[i], to);
+ ca.reloc(clauses[i], to, d_bvp ? d_bvp->getSatProof()->getProxy() : NULL);
+
+ if(d_bvp){ d_bvp->getSatProof()->finishUpdateCRef(); }
}
@@ -1208,5 +1445,25 @@ void Solver::garbageCollect()
to.moveTo(ca);
}
+void ClauseAllocator::reloc(CRef& cr, ClauseAllocator& to, CVC4::BVProofProxy* proxy)
+{
+ CRef old = cr; // save the old reference
+
+ Clause& c = operator[](cr);
+ if (c.reloced()) { cr = c.relocation(); return; }
+
+ cr = to.alloc(c, c.learnt());
+ c.relocate(cr);
+ if (proxy) {
+ proxy->updateCRef(old, cr);
+ }
+
+ // Copy extra data-fields:
+ // (This could be cleaned-up. Generalize Clause-constructor to be applicable here instead?)
+ to[cr].mark(c.mark());
+ if (to[cr].learnt()) to[cr].activity() = c.activity();
+ else if (to[cr].has_extra()) to[cr].calcAbstraction();
+}
+
} /* CVC4::BVMinisat namespace */
} /* CVC4 namespace */
diff --git a/src/prop/bvminisat/core/Solver.h b/src/prop/bvminisat/core/Solver.h
index 214e425f9..019c09bcd 100644
--- a/src/prop/bvminisat/core/Solver.h
+++ b/src/prop/bvminisat/core/Solver.h
@@ -26,13 +26,21 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include "prop/bvminisat/mtl/Heap.h"
#include "prop/bvminisat/mtl/Alg.h"
#include "prop/bvminisat/utils/Options.h"
-
#include "context/cdhashmap.h"
+#include "proof/sat_proof.h"
#include <ext/hash_set>
#include <vector>
namespace CVC4 {
+
+typedef unsigned ClauseId;
+namespace BVMinisat {
+class Solver;
+}
+
+class BitVectorProof;
+
namespace BVMinisat {
/** Interface for minisat callbacks */
@@ -60,7 +68,17 @@ public:
//=================================================================================================
// Solver -- the main class:
class Solver {
-
+ friend class CVC4::TSatProof< CVC4::BVMinisat::Solver>;
+public:
+ typedef Var TVar;
+ typedef Lit TLit;
+ typedef Clause TClause;
+ typedef CRef TCRef;
+ typedef vec<Lit> TLitVec;
+
+ static CRef TCRef_Undef;
+ static CRef TCRef_Lazy;
+private:
/** To notify */
Notify* notify;
@@ -89,12 +107,12 @@ public:
Var falseVar() const { return varFalse; }
- bool addClause (const vec<Lit>& ps); // Add a clause to the solver.
+ bool addClause (const vec<Lit>& ps, ClauseId& id); // Add a clause to the solver.
bool addEmptyClause(); // Add the empty clause, making the solver contradictory.
- bool addClause (Lit p); // Add a unit clause to the solver.
- bool addClause (Lit p, Lit q); // Add a binary clause to the solver.
- bool addClause (Lit p, Lit q, Lit r); // Add a ternary clause to the solver.
- bool addClause_( vec<Lit>& ps); // Add a clause to the solver without making superflous internal copy. Will
+ bool addClause (Lit p, ClauseId& id); // Add a unit clause to the solver.
+ bool addClause (Lit p, Lit q, ClauseId& id); // Add a binary clause to the solver.
+ bool addClause (Lit p, Lit q, Lit r, ClauseId& id); // Add a ternary clause to the solver.
+ bool addClause_( vec<Lit>& ps, ClauseId& id); // Add a clause to the solver without making superflous internal copy. Will
// change the passed vector 'ps'.
// Solving:
@@ -188,16 +206,14 @@ public:
// Bitvector Propagations
//
- void addMarkerLiteral(Var var) {
- // make sure it wasn't already marked
- Assert(marker[var] == 0);
- marker[var] = 1;
- }
+ void addMarkerLiteral(Var var);
bool need_to_propagate; // true if we added new clauses, set to true in propagation
bool only_bcp; // solving mode in which only boolean constraint propagation is done
void setOnlyBCP (bool val) { only_bcp = val;}
void explain(Lit l, std::vector<Lit>& explanation);
+
+ void setProofLog( CVC4::BitVectorProof * bvp );
protected:
@@ -274,6 +290,9 @@ protected:
int64_t conflict_budget; // -1 means no budget.
int64_t propagation_budget; // -1 means no budget.
bool asynch_interrupt;
+
+ //proof log
+ CVC4::BitVectorProof * d_bvp;
// Main internal methods:
//
@@ -340,6 +359,35 @@ protected:
// Returns a random integer 0 <= x < size. Seed must never be 0.
static inline int irand(double& seed, int size) {
return (int)(drand(seed) * size); }
+
+ // Less than for literals in an added clause when proofs are on.
+ struct assign_lt {
+ Solver& solver;
+ assign_lt(Solver& solver) : solver(solver) {}
+ bool operator () (Lit x, Lit y) {
+ lbool x_value = solver.value(x);
+ lbool y_value = solver.value(y);
+ // Two unassigned literals are sorted arbitrarily
+ if (x_value == l_Undef && y_value == l_Undef) {
+ return x < y;
+ }
+ // Unassigned literals are put to front
+ if (x_value == l_Undef) return true;
+ if (y_value == l_Undef) return false;
+ // Literals of the same value are sorted by decreasing levels
+ if (x_value == y_value) {
+ return solver.level(var(x)) > solver.level(var(y));
+ } else {
+ // True literals go up front
+ if (x_value == l_True) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ };
+
};
@@ -380,11 +428,11 @@ inline void Solver::checkGarbage(double gf){
// NOTE: enqueue does not set the ok flag! (only public methods do)
inline bool Solver::enqueue (Lit p, CRef from) { return value(p) != l_Undef ? value(p) != l_False : (uncheckedEnqueue(p, from), true); }
-inline bool Solver::addClause (const vec<Lit>& ps) { ps.copyTo(add_tmp); return addClause_(add_tmp); }
-inline bool Solver::addEmptyClause () { add_tmp.clear(); return addClause_(add_tmp); }
-inline bool Solver::addClause (Lit p) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); }
-inline bool Solver::addClause (Lit p, Lit q) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); }
-inline bool Solver::addClause (Lit p, Lit q, Lit r) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); }
+inline bool Solver::addClause (const vec<Lit>& ps, ClauseId& id) { ps.copyTo(add_tmp); return addClause_(add_tmp, id); }
+inline bool Solver::addEmptyClause () { add_tmp.clear(); ClauseId tmp; return addClause_(add_tmp, tmp); }
+inline bool Solver::addClause (Lit p, ClauseId& id) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, id); }
+inline bool Solver::addClause (Lit p, Lit q, ClauseId& id) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, id); }
+inline bool Solver::addClause (Lit p, Lit q, Lit r, ClauseId& id) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, id); }
inline bool Solver::locked (const Clause& c) const { return value(c[0]) == l_True && reason(var(c[0])) != CRef_Undef && ca.lea(reason(var(c[0]))) == &c; }
inline void Solver::newDecisionLevel() { trail_lim.push(trail.size()); }
diff --git a/src/prop/bvminisat/core/SolverTypes.h b/src/prop/bvminisat/core/SolverTypes.h
index aa0921b78..1fd7ac5a7 100644
--- a/src/prop/bvminisat/core/SolverTypes.h
+++ b/src/prop/bvminisat/core/SolverTypes.h
@@ -31,6 +31,15 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
namespace CVC4 {
namespace BVMinisat {
+class Solver;
+}
+template <class Solver> class ProofProxy;
+typedef ProofProxy<BVMinisat::Solver> BVProofProxy;
+}
+
+namespace CVC4 {
+
+namespace BVMinisat {
//=================================================================================================
// Variables, literals, lifted booleans, clauses:
@@ -205,6 +214,8 @@ public:
const CRef CRef_Undef = RegionAllocator<uint32_t>::Ref_Undef;
+const CRef CRef_Lazy = RegionAllocator<uint32_t>::Ref_Undef - 1;
+
class ClauseAllocator : public RegionAllocator<uint32_t>
{
static int clauseWord32Size(int size, bool has_extra){
@@ -245,21 +256,7 @@ class ClauseAllocator : public RegionAllocator<uint32_t>
RegionAllocator<uint32_t>::free(clauseWord32Size(c.size(), c.has_extra()));
}
- void reloc(CRef& cr, ClauseAllocator& to)
- {
- Clause& c = operator[](cr);
-
- if (c.reloced()) { cr = c.relocation(); return; }
-
- cr = to.alloc(c, c.learnt());
- c.relocate(cr);
-
- // Copy extra data-fields:
- // (This could be cleaned-up. Generalize Clause-constructor to be applicable here instead?)
- to[cr].mark(c.mark());
- if (to[cr].learnt()) to[cr].activity() = c.activity();
- else if (to[cr].has_extra()) to[cr].calcAbstraction();
- }
+ void reloc(CRef& cr, ClauseAllocator& to, CVC4::BVProofProxy* proxy = NULL);
};
diff --git a/src/prop/bvminisat/simp/SimpSolver.cc b/src/prop/bvminisat/simp/SimpSolver.cc
index c5b185c95..311ed1dd1 100644
--- a/src/prop/bvminisat/simp/SimpSolver.cc
+++ b/src/prop/bvminisat/simp/SimpSolver.cc
@@ -24,6 +24,7 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include "options/bv_options.h"
#include "options/smt_options.h"
#include "utils/System.h"
+#include "proof/proof.h"
namespace CVC4 {
namespace BVMinisat {
@@ -62,7 +63,7 @@ SimpSolver::SimpSolver(CVC4::context::Context* c) :
, asymm_lits (0)
, eliminated_vars (0)
, elimorder (1)
- , use_simplification (true)
+ , use_simplification (!PROOF_ON())
, occurs (ClauseDeleted(ca))
, elim_heap (ElimLt(n_occ))
, bwdsub_assigns (0)
@@ -162,7 +163,7 @@ lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
-bool SimpSolver::addClause_(vec<Lit>& ps)
+bool SimpSolver::addClause_(vec<Lit>& ps, ClauseId& id)
{
#ifndef NDEBUG
for (int i = 0; i < ps.size(); i++)
@@ -174,7 +175,7 @@ bool SimpSolver::addClause_(vec<Lit>& ps)
if (use_rcheck && implied(ps))
return true;
- if (!Solver::addClause_(ps))
+ if (!Solver::addClause_(ps, id))
return false;
if (use_simplification && clauses.size() == nclauses + 1){
@@ -544,9 +545,12 @@ bool SimpSolver::eliminateVar(Var v)
// Produce clauses in cross product:
vec<Lit>& resolvent = add_tmp;
for (int i = 0; i < pos.size(); i++)
- for (int j = 0; j < neg.size(); j++)
- if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent))
- return false;
+ for (int j = 0; j < neg.size(); j++) {
+ ClauseId id = -1;
+ if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) &&
+ !addClause_(resolvent, id))
+ return false;
+ }
// Free occurs list for this variable:
occurs[v].clear(true);
@@ -582,8 +586,8 @@ bool SimpSolver::substitute(Var v, Lit x)
}
removeClause(cls[i]);
-
- if (!addClause_(subst_clause))
+ ClauseId id;
+ if (!addClause_(subst_clause, id))
return ok = false;
}
diff --git a/src/prop/bvminisat/simp/SimpSolver.h b/src/prop/bvminisat/simp/SimpSolver.h
index 85556e935..5f6f46b91 100644
--- a/src/prop/bvminisat/simp/SimpSolver.h
+++ b/src/prop/bvminisat/simp/SimpSolver.h
@@ -42,12 +42,12 @@ class SimpSolver : public Solver {
// Problem specification:
//
Var newVar (bool polarity = true, bool dvar = true, bool freeze = false);
- bool addClause (const vec<Lit>& ps);
+ bool addClause (const vec<Lit>& ps, ClauseId& id);
bool addEmptyClause(); // Add the empty clause to the solver.
- bool addClause (Lit p); // Add a unit clause to the solver.
- bool addClause (Lit p, Lit q); // Add a binary clause to the solver.
- bool addClause (Lit p, Lit q, Lit r); // Add a ternary clause to the solver.
- bool addClause_( vec<Lit>& ps);
+ bool addClause (Lit p, ClauseId& id); // Add a unit clause to the solver.
+ bool addClause (Lit p, Lit q, ClauseId& id); // Add a binary clause to the solver.
+ bool addClause (Lit p, Lit q, Lit r, ClauseId& id); // Add a ternary clause to the solver.
+ bool addClause_( vec<Lit>& ps, ClauseId& id);
bool substitute(Var v, Lit x); // Replace all occurences of v with x (may cause a contradiction).
// Variable mode:
@@ -178,11 +178,11 @@ inline void SimpSolver::updateElimHeap(Var v) {
elim_heap.update(v); }
-inline bool SimpSolver::addClause (const vec<Lit>& ps) { ps.copyTo(add_tmp); return addClause_(add_tmp); }
-inline bool SimpSolver::addEmptyClause() { add_tmp.clear(); return addClause_(add_tmp); }
-inline bool SimpSolver::addClause (Lit p) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); }
-inline bool SimpSolver::addClause (Lit p, Lit q) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); }
-inline bool SimpSolver::addClause (Lit p, Lit q, Lit r) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); }
+inline bool SimpSolver::addClause (const vec<Lit>& ps, ClauseId& id) { ps.copyTo(add_tmp); return addClause_(add_tmp, id); }
+inline bool SimpSolver::addEmptyClause() { add_tmp.clear(); ClauseId id; return addClause_(add_tmp, id); }
+inline bool SimpSolver::addClause (Lit p, ClauseId& id) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, id); }
+inline bool SimpSolver::addClause (Lit p, Lit q, ClauseId& id) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, id); }
+inline bool SimpSolver::addClause (Lit p, Lit q, Lit r, ClauseId& id) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, id); }
inline void SimpSolver::setFrozen (Var v, bool b) { frozen[v] = (char)b; if (use_simplification && !b) { updateElimHeap(v); } }
inline lbool SimpSolver::solve ( bool do_simp, bool turn_off_simp) {
diff --git a/src/prop/cnf_stream.cpp b/src/prop/cnf_stream.cpp
index b3666875d..a3d411738 100644
--- a/src/prop/cnf_stream.cpp
+++ b/src/prop/cnf_stream.cpp
@@ -24,6 +24,7 @@
#include "options/bv_options.h"
#include "proof/proof_manager.h"
#include "proof/sat_proof.h"
+#include "proof/cnf_proof.h"
#include "prop/cnf_stream.h"
#include "prop/minisat/minisat.h"
#include "prop/prop_engine.h"
@@ -47,7 +48,7 @@ namespace prop {
CnfStream::CnfStream(SatSolver* satSolver, Registrar* registrar,
context::Context* context, SmtGlobals* globals,
- bool fullLitToNodeMap)
+ bool fullLitToNodeMap, std::string name)
: d_satSolver(satSolver),
d_booleanVariables(context),
d_nodeToLiteralMap(context),
@@ -55,19 +56,21 @@ CnfStream::CnfStream(SatSolver* satSolver, Registrar* registrar,
d_fullLitToNodeMap(fullLitToNodeMap),
d_convertAndAssertCounter(0),
d_registrar(registrar),
- d_assertionTable(context),
+ d_name(name),
+ d_cnfProof(NULL),
d_globals(globals),
d_removable(false) {
}
TseitinCnfStream::TseitinCnfStream(SatSolver* satSolver, Registrar* registrar,
context::Context* context,
- SmtGlobals* globals, bool fullLitToNodeMap)
- : CnfStream(satSolver, registrar, context, globals, fullLitToNodeMap)
+ SmtGlobals* globals, bool fullLitToNodeMap,
+ std::string name)
+ : CnfStream(satSolver, registrar, context, globals, fullLitToNodeMap, name)
{}
-void CnfStream::assertClause(TNode node, SatClause& c, ProofRule proof_id) {
- Debug("cnf") << "Inserting into stream " << c << " node = " << node << ", proof id = " << proof_id << endl;
+void CnfStream::assertClause(TNode node, SatClause& c) {
+ Debug("cnf") << "Inserting into stream " << c << " node = " << node << endl;
if(Dump.isOn("clauses")) {
if(c.size() == 1) {
Dump("clauses") << AssertCommand(Expr(getNode(c[0]).toExpr()));
@@ -81,31 +84,41 @@ void CnfStream::assertClause(TNode node, SatClause& c, ProofRule proof_id) {
Dump("clauses") << AssertCommand(Expr(n.toExpr()));
}
}
- //store map between clause and original formula
- PROOF(ProofManager::currentPM()->setRegisteringFormula( node, proof_id ); );
- d_satSolver->addClause(c, d_removable, d_proofId);
- PROOF(ProofManager::currentPM()->setRegisteringFormula( Node::null(), RULE_INVALID ); );
+
+ PROOF(if (d_cnfProof) d_cnfProof->pushCurrentDefinition(node););
+
+ ClauseId clause_id = d_satSolver->addClause(c, d_removable);
+ if (clause_id == ClauseIdUndef) return; // nothing to store (no clause was added)
+
+ PROOF
+ (
+ if (d_cnfProof) {
+ Assert (clause_id != ClauseIdError);
+ d_cnfProof->registerConvertedClause(clause_id);
+ d_cnfProof->popCurrentDefinition();
+ }
+ );
}
-void CnfStream::assertClause(TNode node, SatLiteral a, ProofRule proof_id) {
+void CnfStream::assertClause(TNode node, SatLiteral a) {
SatClause clause(1);
clause[0] = a;
- assertClause(node, clause, proof_id);
+ assertClause(node, clause);
}
-void CnfStream::assertClause(TNode node, SatLiteral a, SatLiteral b, ProofRule proof_id) {
+void CnfStream::assertClause(TNode node, SatLiteral a, SatLiteral b) {
SatClause clause(2);
clause[0] = a;
clause[1] = b;
- assertClause(node, clause, proof_id);
+ assertClause(node, clause);
}
-void CnfStream::assertClause(TNode node, SatLiteral a, SatLiteral b, SatLiteral c, ProofRule proof_id) {
+void CnfStream::assertClause(TNode node, SatLiteral a, SatLiteral b, SatLiteral c) {
SatClause clause(3);
clause[0] = a;
clause[1] = b;
clause[2] = c;
- assertClause(node, clause, proof_id);
+ assertClause(node, clause);
}
bool CnfStream::hasLiteral(TNode n) const {
@@ -116,7 +129,6 @@ bool CnfStream::hasLiteral(TNode n) const {
void TseitinCnfStream::ensureLiteral(TNode n) {
// These are not removable and have no proof ID
d_removable = false;
- d_proofId = uint64_t(-1);
Debug("cnf") << "ensureLiteral(" << n << ")" << endl;
if(hasLiteral(n)) {
@@ -165,7 +177,7 @@ void TseitinCnfStream::ensureLiteral(TNode n) {
}
SatLiteral CnfStream::newLiteral(TNode node, bool isTheoryAtom, bool preRegister, bool canEliminate) {
- Debug("cnf") << "newLiteral(" << node << ", " << isTheoryAtom << ")" << endl;
+ Debug("cnf") << d_name << "::newLiteral(" << node << ", " << isTheoryAtom << ")" << endl;
Assert(node.getKind() != kind::NOT);
// Get the literal for this node
@@ -200,10 +212,9 @@ SatLiteral CnfStream::newLiteral(TNode node, bool isTheoryAtom, bool preRegister
if (preRegister) {
// In case we are re-entered due to lemmas, save our state
bool backupRemovable = d_removable;
- uint64_t backupProofId= d_proofId;
+ // Should be fine since cnfProof current assertion is stack based.
d_registrar->preRegister(node);
d_removable = backupRemovable;
- d_proofId = backupProofId;
}
// Here, you can have it
@@ -225,6 +236,11 @@ void CnfStream::getBooleanVariables(std::vector<TNode>& outputVariables) const {
}
}
+void CnfStream::setProof(CnfProof* proof) {
+ Assert (d_cnfProof == NULL);
+ d_cnfProof = proof;
+}
+
SatLiteral CnfStream::convertAtom(TNode node) {
Debug("cnf") << "convertAtom(" << node << ")" << endl;
@@ -268,10 +284,10 @@ SatLiteral TseitinCnfStream::handleXor(TNode xorNode) {
SatLiteral xorLit = newLiteral(xorNode);
- assertClause(xorNode.negate(), a, b, ~xorLit, RULE_TSEITIN);
- assertClause(xorNode.negate(), ~a, ~b, ~xorLit, RULE_TSEITIN);
- assertClause(xorNode, a, ~b, xorLit, RULE_TSEITIN);
- assertClause(xorNode, ~a, b, xorLit, RULE_TSEITIN);
+ assertClause(xorNode.negate(), a, b, ~xorLit);
+ assertClause(xorNode.negate(), ~a, ~b, ~xorLit);
+ assertClause(xorNode, a, ~b, xorLit);
+ assertClause(xorNode, ~a, b, xorLit);
return xorLit;
}
@@ -300,14 +316,14 @@ SatLiteral TseitinCnfStream::handleOr(TNode orNode) {
// lit | ~(a_1 | a_2 | a_3 | ... | a_n)
// (lit | ~a_1) & (lit | ~a_2) & (lit & ~a_3) & ... & (lit & ~a_n)
for(unsigned i = 0; i < n_children; ++i) {
- assertClause(orNode, orLit, ~clause[i], RULE_TSEITIN);
+ assertClause(orNode, orLit, ~clause[i]);
}
// lit -> (a_1 | a_2 | a_3 | ... | a_n)
// ~lit | a_1 | a_2 | a_3 | ... | a_n
clause[n_children] = ~orLit;
// This needs to go last, as the clause might get modified by the SAT solver
- assertClause(orNode.negate(), clause, RULE_TSEITIN);
+ assertClause(orNode.negate(), clause);
// Return the literal
return orLit;
@@ -337,7 +353,7 @@ SatLiteral TseitinCnfStream::handleAnd(TNode andNode) {
// ~lit | (a_1 & a_2 & a_3 & ... & a_n)
// (~lit | a_1) & (~lit | a_2) & ... & (~lit | a_n)
for(unsigned i = 0; i < n_children; ++i) {
- assertClause(andNode.negate(), ~andLit, ~clause[i], RULE_TSEITIN);
+ assertClause(andNode.negate(), ~andLit, ~clause[i]);
}
// lit <- (a_1 & a_2 & a_3 & ... a_n)
@@ -345,7 +361,7 @@ SatLiteral TseitinCnfStream::handleAnd(TNode andNode) {
// lit | ~a_1 | ~a_2 | ~a_3 | ... | ~a_n
clause[n_children] = andLit;
// This needs to go last, as the clause might get modified by the SAT solver
- assertClause(andNode, clause, RULE_TSEITIN);
+ assertClause(andNode, clause);
return andLit;
}
@@ -364,13 +380,13 @@ SatLiteral TseitinCnfStream::handleImplies(TNode impliesNode) {
// lit -> (a->b)
// ~lit | ~ a | b
- assertClause(impliesNode.negate(), ~impliesLit, ~a, b, RULE_TSEITIN);
+ assertClause(impliesNode.negate(), ~impliesLit, ~a, b);
// (a->b) -> lit
// ~(~a | b) | lit
// (a | l) & (~b | l)
- assertClause(impliesNode, a, impliesLit, RULE_TSEITIN);
- assertClause(impliesNode, ~b, impliesLit, RULE_TSEITIN);
+ assertClause(impliesNode, a, impliesLit);
+ assertClause(impliesNode, ~b, impliesLit);
return impliesLit;
}
@@ -393,16 +409,16 @@ SatLiteral TseitinCnfStream::handleIff(TNode iffNode) {
// lit -> ((a-> b) & (b->a))
// ~lit | ((~a | b) & (~b | a))
// (~a | b | ~lit) & (~b | a | ~lit)
- assertClause(iffNode.negate(), ~a, b, ~iffLit, RULE_TSEITIN);
- assertClause(iffNode.negate(), a, ~b, ~iffLit, RULE_TSEITIN);
+ assertClause(iffNode.negate(), ~a, b, ~iffLit);
+ assertClause(iffNode.negate(), a, ~b, ~iffLit);
// (a<->b) -> lit
// ~((a & b) | (~a & ~b)) | lit
// (~(a & b)) & (~(~a & ~b)) | lit
// ((~a | ~b) & (a | b)) | lit
// (~a | ~b | lit) & (a | b | lit)
- assertClause(iffNode, ~a, ~b, iffLit, RULE_TSEITIN);
- assertClause(iffNode, a, b, iffLit, RULE_TSEITIN);
+ assertClause(iffNode, ~a, ~b, iffLit);
+ assertClause(iffNode, a, b, iffLit);
return iffLit;
}
@@ -437,9 +453,9 @@ SatLiteral TseitinCnfStream::handleIte(TNode iteNode) {
// lit -> (t | e) & (b -> t) & (!b -> e)
// lit -> (t | e) & (!b | t) & (b | e)
// (!lit | t | e) & (!lit | !b | t) & (!lit | b | e)
- assertClause(iteNode.negate(), ~iteLit, thenLit, elseLit, RULE_TSEITIN);
- assertClause(iteNode.negate(), ~iteLit, ~condLit, thenLit, RULE_TSEITIN);
- assertClause(iteNode.negate(), ~iteLit, condLit, elseLit, RULE_TSEITIN);
+ assertClause(iteNode.negate(), ~iteLit, thenLit, elseLit);
+ assertClause(iteNode.negate(), ~iteLit, ~condLit, thenLit);
+ assertClause(iteNode.negate(), ~iteLit, condLit, elseLit);
// If ITE is false then one of the branches is false and the condition
// implies which one
@@ -447,9 +463,9 @@ SatLiteral TseitinCnfStream::handleIte(TNode iteNode) {
// !lit -> (!t | !e) & (b -> !t) & (!b -> !e)
// !lit -> (!t | !e) & (!b | !t) & (b | !e)
// (lit | !t | !e) & (lit | !b | !t) & (lit | b | !e)
- assertClause(iteNode, iteLit, ~thenLit, ~elseLit, RULE_TSEITIN);
- assertClause(iteNode, iteLit, ~condLit, ~thenLit, RULE_TSEITIN);
- assertClause(iteNode, iteLit, condLit, ~elseLit, RULE_TSEITIN);
+ assertClause(iteNode, iteLit, ~thenLit, ~elseLit);
+ assertClause(iteNode, iteLit, ~condLit, ~thenLit);
+ assertClause(iteNode, iteLit, condLit, ~elseLit);
return iteLit;
}
@@ -514,14 +530,14 @@ SatLiteral TseitinCnfStream::toCNF(TNode node, bool negated) {
else return ~nodeLit;
}
-void TseitinCnfStream::convertAndAssertAnd(TNode node, bool negated, ProofRule proof_id) {
+void TseitinCnfStream::convertAndAssertAnd(TNode node, bool negated) {
Assert(node.getKind() == AND);
if (!negated) {
// If the node is a conjunction, we handle each conjunct separately
for(TNode::const_iterator conjunct = node.begin(), node_end = node.end();
conjunct != node_end; ++conjunct ) {
- PROOF(ProofManager::currentPM()->setCnfDep( (*conjunct).toExpr(), node.toExpr() ) );
- convertAndAssert(*conjunct, false, proof_id);
+ PROOF(if (d_cnfProof) d_cnfProof->setCnfDependence(*conjunct, node););
+ convertAndAssert(*conjunct, false);
}
} else {
// If the node is a disjunction, we construct a clause and assert it
@@ -533,11 +549,11 @@ void TseitinCnfStream::convertAndAssertAnd(TNode node, bool negated, ProofRule p
clause[i] = toCNF(*disjunct, true);
}
Assert(disjunct == node.end());
- assertClause(node.negate(), clause, proof_id);
+ assertClause(node.negate(), clause);
}
}
-void TseitinCnfStream::convertAndAssertOr(TNode node, bool negated, ProofRule proof_id) {
+void TseitinCnfStream::convertAndAssertOr(TNode node, bool negated) {
Assert(node.getKind() == OR);
if (!negated) {
// If the node is a disjunction, we construct a clause and assert it
@@ -549,18 +565,18 @@ void TseitinCnfStream::convertAndAssertOr(TNode node, bool negated, ProofRule pr
clause[i] = toCNF(*disjunct, false);
}
Assert(disjunct == node.end());
- assertClause(node, clause, proof_id);
+ assertClause(node, clause);
} else {
// If the node is a conjunction, we handle each conjunct separately
for(TNode::const_iterator conjunct = node.begin(), node_end = node.end();
conjunct != node_end; ++conjunct ) {
- PROOF(ProofManager::currentPM()->setCnfDep( (*conjunct).negate().toExpr(), node.negate().toExpr() ) );
- convertAndAssert(*conjunct, true, proof_id);
+ PROOF(if (d_cnfProof) d_cnfProof->setCnfDependence((*conjunct).negate(), node.negate()););
+ convertAndAssert(*conjunct, true);
}
}
}
-void TseitinCnfStream::convertAndAssertXor(TNode node, bool negated, ProofRule proof_id) {
+void TseitinCnfStream::convertAndAssertXor(TNode node, bool negated) {
if (!negated) {
// p XOR q
SatLiteral p = toCNF(node[0], false);
@@ -569,11 +585,11 @@ void TseitinCnfStream::convertAndAssertXor(TNode node, bool negated, ProofRule p
SatClause clause1(2);
clause1[0] = ~p;
clause1[1] = ~q;
- assertClause(node, clause1, proof_id);
+ assertClause(node, clause1);
SatClause clause2(2);
clause2[0] = p;
clause2[1] = q;
- assertClause(node, clause2, proof_id);
+ assertClause(node, clause2);
} else {
// !(p XOR q) is the same as p <=> q
SatLiteral p = toCNF(node[0], false);
@@ -582,15 +598,15 @@ void TseitinCnfStream::convertAndAssertXor(TNode node, bool negated, ProofRule p
SatClause clause1(2);
clause1[0] = ~p;
clause1[1] = q;
- assertClause(node.negate(), clause1, proof_id);
+ assertClause(node.negate(), clause1);
SatClause clause2(2);
clause2[0] = p;
clause2[1] = ~q;
- assertClause(node.negate(), clause2, proof_id);
+ assertClause(node.negate(), clause2);
}
}
-void TseitinCnfStream::convertAndAssertIff(TNode node, bool negated, ProofRule proof_id) {
+void TseitinCnfStream::convertAndAssertIff(TNode node, bool negated) {
if (!negated) {
// p <=> q
SatLiteral p = toCNF(node[0], false);
@@ -599,11 +615,11 @@ void TseitinCnfStream::convertAndAssertIff(TNode node, bool negated, ProofRule p
SatClause clause1(2);
clause1[0] = ~p;
clause1[1] = q;
- assertClause(node, clause1, proof_id);
+ assertClause(node, clause1);
SatClause clause2(2);
clause2[0] = p;
clause2[1] = ~q;
- assertClause(node, clause2, proof_id);
+ assertClause(node, clause2);
} else {
// !(p <=> q) is the same as p XOR q
SatLiteral p = toCNF(node[0], false);
@@ -612,15 +628,15 @@ void TseitinCnfStream::convertAndAssertIff(TNode node, bool negated, ProofRule p
SatClause clause1(2);
clause1[0] = ~p;
clause1[1] = ~q;
- assertClause(node.negate(), clause1, proof_id);
+ assertClause(node.negate(), clause1);
SatClause clause2(2);
clause2[0] = p;
clause2[1] = q;
- assertClause(node.negate(), clause2, proof_id);
+ assertClause(node.negate(), clause2);
}
}
-void TseitinCnfStream::convertAndAssertImplies(TNode node, bool negated, ProofRule proof_id) {
+void TseitinCnfStream::convertAndAssertImplies(TNode node, bool negated) {
if (!negated) {
// p => q
SatLiteral p = toCNF(node[0], false);
@@ -629,17 +645,17 @@ void TseitinCnfStream::convertAndAssertImplies(TNode node, bool negated, ProofRu
SatClause clause(2);
clause[0] = ~p;
clause[1] = q;
- assertClause(node, clause, proof_id);
+ assertClause(node, clause);
} else {// Construct the
- PROOF(ProofManager::currentPM()->setCnfDep( node[0].toExpr(), node.negate().toExpr() ) );
- PROOF(ProofManager::currentPM()->setCnfDep( node[1].negate().toExpr(), node.negate().toExpr() ) );
+ PROOF(if (d_cnfProof) d_cnfProof->setCnfDependence(node[0], node.negate()););
+ PROOF(if (d_cnfProof) d_cnfProof->setCnfDependence(node[1].negate(), node.negate()););
// !(p => q) is the same as (p && ~q)
- convertAndAssert(node[0], false, proof_id);
- convertAndAssert(node[1], true, proof_id);
+ convertAndAssert(node[0], false);
+ convertAndAssert(node[1], true);
}
}
-void TseitinCnfStream::convertAndAssertIte(TNode node, bool negated, ProofRule proof_id) {
+void TseitinCnfStream::convertAndAssertIte(TNode node, bool negated) {
// ITE(p, q, r)
SatLiteral p = toCNF(node[0], false);
SatLiteral q = toCNF(node[1], negated);
@@ -653,35 +669,47 @@ void TseitinCnfStream::convertAndAssertIte(TNode node, bool negated, ProofRule p
SatClause clause1(2);
clause1[0] = ~p;
clause1[1] = q;
- assertClause(nnode, clause1, proof_id);
+ assertClause(nnode, clause1);
SatClause clause2(2);
clause2[0] = p;
clause2[1] = r;
- assertClause(nnode, clause2, proof_id);
+ assertClause(nnode, clause2);
}
// At the top level we must ensure that all clauses that are asserted are
// not unit, except for the direct assertions. This allows us to remove the
// clauses later when they are not needed anymore (lemmas for example).
-void TseitinCnfStream::convertAndAssert(TNode node, bool removable, bool negated, ProofRule proof_id, TNode from) {
- Debug("cnf") << "convertAndAssert(" << node << ", removable = " << (removable ? "true" : "false") << ", negated = " << (negated ? "true" : "false") << ")" << endl;
+void TseitinCnfStream::convertAndAssert(TNode node,
+ bool removable,
+ bool negated,
+ ProofRule proof_id,
+ TNode from) {
+ Debug("cnf") << "convertAndAssert(" << node
+ << ", removable = " << (removable ? "true" : "false")
+ << ", negated = " << (negated ? "true" : "false") << ")" << endl;
d_removable = removable;
- if(options::proof() || options::unsatCores()) {
- // Encode the assertion ID in the proof_id to store with generated clauses.
- uint64_t assertionTableIndex = d_assertionTable.size();
- Assert((uint64_t(proof_id) & 0xffffffff00000000llu) == 0 && (assertionTableIndex & 0xffffffff00000000llu) == 0, "proof_id/table_index collision");
- d_proofId = assertionTableIndex | (uint64_t(proof_id) << 32);
- d_assertionTable.push_back(from.isNull() ? node : from);
- Debug("cores") << "; cnf is " << assertionTableIndex << " asst " << node << " proof_id " << proof_id << " from " << from << endl;
- } else {
- // We aren't producing proofs or unsat cores; use an invalid proof id.
- d_proofId = uint64_t(-1);
- }
- convertAndAssert(node, negated, proof_id);
+ PROOF
+ (if (d_cnfProof) {
+ Node assertion = negated ? node.notNode() : (Node)node;
+ Node from_assertion = negated? from.notNode() : (Node) from;
+
+ if (proof_id != RULE_INVALID) {
+ d_cnfProof->pushCurrentAssertion(from.isNull() ? assertion : from_assertion);
+ d_cnfProof->registerAssertion(from.isNull() ? assertion : from_assertion, proof_id);
+ }
+ else {
+ d_cnfProof->pushCurrentAssertion(assertion);
+ d_cnfProof->registerAssertion(assertion, proof_id);
+ }
+ });
+
+ convertAndAssert(node, negated);
+ PROOF(if (d_cnfProof) d_cnfProof->popCurrentAssertion(); );
}
-void TseitinCnfStream::convertAndAssert(TNode node, bool negated, ProofRule proof_id) {
- Debug("cnf") << "convertAndAssert(" << node << ", negated = " << (negated ? "true" : "false") << ")" << endl;
+void TseitinCnfStream::convertAndAssert(TNode node, bool negated) {
+ Debug("cnf") << "convertAndAssert(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")" << endl;
if (d_convertAndAssertCounter % ResourceManager::getFrequencyCount() == 0) {
NodeManager::currentResourceManager()->spendResource(options::cnfStep());
@@ -691,25 +719,25 @@ void TseitinCnfStream::convertAndAssert(TNode node, bool negated, ProofRule proo
switch(node.getKind()) {
case AND:
- convertAndAssertAnd(node, negated, proof_id);
+ convertAndAssertAnd(node, negated);
break;
case OR:
- convertAndAssertOr(node, negated, proof_id);
+ convertAndAssertOr(node, negated);
break;
case IFF:
- convertAndAssertIff(node, negated, proof_id);
+ convertAndAssertIff(node, negated);
break;
case XOR:
- convertAndAssertXor(node, negated, proof_id);
+ convertAndAssertXor(node, negated);
break;
case IMPLIES:
- convertAndAssertImplies(node, negated, proof_id);
+ convertAndAssertImplies(node, negated);
break;
case ITE:
- convertAndAssertIte(node, negated, proof_id);
+ convertAndAssertIte(node, negated);
break;
case NOT:
- convertAndAssert(node[0], !negated, proof_id);
+ convertAndAssert(node[0], !negated);
break;
default:
{
@@ -718,7 +746,7 @@ void TseitinCnfStream::convertAndAssert(TNode node, bool negated, ProofRule proo
nnode = node.negate();
}
// Atoms
- assertClause(nnode, toCNF(node, negated), proof_id);
+ assertClause(nnode, toCNF(node, negated));
}
break;
}
diff --git a/src/prop/cnf_stream.h b/src/prop/cnf_stream.h
index cfab216fe..a07944a58 100644
--- a/src/prop/cnf_stream.h
+++ b/src/prop/cnf_stream.h
@@ -84,8 +84,11 @@ protected:
/** The "registrar" for pre-registration of terms */
Registrar* d_registrar;
- /** A table of assertions, used for regenerating proofs. */
- context::CDList<Node> d_assertionTable;
+ /** The name of this CNF stream*/
+ std::string d_name;
+
+ /** Pointer to the proof corresponding to this CnfStream */
+ CnfProof* d_cnfProof;
/** Container for misc. globals. */
SmtGlobals* d_globals;
@@ -117,14 +120,6 @@ protected:
}
/**
- * A reference into the assertion table, used to map clauses back to
- * their "original" input assertion/lemma. This variable is manipulated
- * by the top-level convertAndAssert(). This is needed in proofs-enabled
- * runs, to justify where the SAT solver's clauses came from.
- */
- uint64_t d_proofId;
-
- /**
* Are we asserting a removable clause (true) or a permanent clause (false).
* This is set at the beginning of convertAndAssert so that it doesn't
* need to be passed on over the stack. Only pure clauses can be asserted
@@ -137,14 +132,14 @@ protected:
* @param node the node giving rise to this clause
* @param clause the clause to assert
*/
- void assertClause(TNode node, SatClause& clause, ProofRule proof_id);
+ void assertClause(TNode node, SatClause& clause);
/**
* Asserts the unit clause to the sat solver.
* @param node the node giving rise to this clause
* @param a the unit literal of the clause
*/
- void assertClause(TNode node, SatLiteral a, ProofRule proof_id);
+ void assertClause(TNode node, SatLiteral a);
/**
* Asserts the binary clause to the sat solver.
@@ -152,7 +147,7 @@ protected:
* @param a the first literal in the clause
* @param b the second literal in the clause
*/
- void assertClause(TNode node, SatLiteral a, SatLiteral b, ProofRule proof_id);
+ void assertClause(TNode node, SatLiteral a, SatLiteral b);
/**
* Asserts the ternary clause to the sat solver.
@@ -161,7 +156,7 @@ protected:
* @param b the second literal in the clause
* @param c the thirs literal in the clause
*/
- void assertClause(TNode node, SatLiteral a, SatLiteral b, SatLiteral c, ProofRule proof_id);
+ void assertClause(TNode node, SatLiteral a, SatLiteral b, SatLiteral c);
/**
* Acquires a new variable from the SAT solver to represent the node
@@ -193,9 +188,15 @@ public:
* @param registrar the entity that takes care of preregistration of Nodes
* @param context the context that the CNF should respect
* @param fullLitToNodeMap maintain a full SAT-literal-to-Node mapping,
+ * @param name string identifier to distinguish between different instances
* even for non-theory literals
*/
- CnfStream(SatSolver* satSolver, Registrar* registrar, context::Context* context, SmtGlobals* globals, bool fullLitToNodeMap = false);
+ CnfStream(SatSolver* satSolver,
+ Registrar* registrar,
+ context::Context* context,
+ SmtGlobals* globals,
+ bool fullLitToNodeMap = false,
+ std::string name="");
/**
* Destructs a CnfStream. This implementation does nothing, but we
@@ -244,13 +245,6 @@ public:
SatLiteral getLiteral(TNode node);
/**
- * Get the assertion with a given ID. (Used for reconstructing proofs.)
- */
- TNode getAssertion(uint64_t id) {
- return d_assertionTable[id];
- }
-
- /**
* Returns the Boolean variables from the input problem.
*/
void getBooleanVariables(std::vector<TNode>& outputVariables) const;
@@ -263,6 +257,7 @@ public:
return d_literalToNodeMap;
}
+ void setProof(CnfProof* proof);
};/* class CnfStream */
@@ -286,7 +281,8 @@ public:
* @param removable is this something that can be erased
* @param negated true if negated
*/
- void convertAndAssert(TNode node, bool removable, bool negated, ProofRule proof_id, TNode from = TNode::null());
+ void convertAndAssert(TNode node, bool removable,
+ bool negated, ProofRule rule, TNode from = TNode::null());
/**
* Constructs the stream to use the given sat solver.
@@ -295,14 +291,14 @@ public:
* @param fullLitToNodeMap maintain a full SAT-literal-to-Node mapping,
* even for non-theory literals
*/
- TseitinCnfStream(SatSolver* satSolver, Registrar* registrar, context::Context* context, SmtGlobals* globals, bool fullLitToNodeMap = false);
+ TseitinCnfStream(SatSolver* satSolver, Registrar* registrar, context::Context* context, SmtGlobals* globals, bool fullLitToNodeMap = false, std::string name = "");
private:
/**
* Same as above, except that removable is remembered.
*/
- void convertAndAssert(TNode node, bool negated, ProofRule proof_id);
+ void convertAndAssert(TNode node, bool negated);
// Each of these formulas handles takes care of a Node of each Kind.
//
@@ -322,12 +318,12 @@ private:
SatLiteral handleAnd(TNode node);
SatLiteral handleOr(TNode node);
- void convertAndAssertAnd(TNode node, bool negated, ProofRule proof_id);
- void convertAndAssertOr(TNode node, bool negated, ProofRule proof_id);
- void convertAndAssertXor(TNode node, bool negated, ProofRule proof_id);
- void convertAndAssertIff(TNode node, bool negated, ProofRule proof_id);
- void convertAndAssertImplies(TNode node, bool negated, ProofRule proof_id);
- void convertAndAssertIte(TNode node, bool negated, ProofRule proof_id);
+ void convertAndAssertAnd(TNode node, bool negated);
+ void convertAndAssertOr(TNode node, bool negated);
+ void convertAndAssertXor(TNode node, bool negated);
+ void convertAndAssertIff(TNode node, bool negated);
+ void convertAndAssertImplies(TNode node, bool negated);
+ void convertAndAssertIte(TNode node, bool negated);
/**
* Transforms the node into CNF recursively.
diff --git a/src/prop/minisat/core/Solver.cc b/src/prop/minisat/core/Solver.cc
index 4c431a9b1..f4489c4be 100644
--- a/src/prop/minisat/core/Solver.cc
+++ b/src/prop/minisat/core/Solver.cc
@@ -25,6 +25,7 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include "base/output.h"
#include "options/prop_options.h"
#include "proof/proof_manager.h"
+#include "proof/sat_proof_implementation.h"
#include "proof/sat_proof.h"
#include "prop/minisat/core/Solver.h"
#include "prop/minisat/minisat.h"
@@ -32,6 +33,7 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include "prop/theory_proxy.h"
#include "smt_util/command.h"
+
using namespace CVC4::prop;
namespace CVC4 {
@@ -40,7 +42,6 @@ namespace Minisat {
//=================================================================================================
// Options:
-
static const char* _cat = "CORE";
static DoubleOption opt_var_decay (_cat, "var-decay", "The variable activity decay factor", 0.95, DoubleRange(0, false, 1, false));
@@ -55,6 +56,10 @@ static IntOption opt_restart_first (_cat, "rfirst", "The base resta
static DoubleOption opt_restart_inc (_cat, "rinc", "Restart interval increase factor", 3, DoubleRange(1, false, HUGE_VAL, false));
static DoubleOption opt_garbage_frac (_cat, "gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered", 0.20, DoubleRange(0, false, HUGE_VAL, false));
+//=================================================================================================
+// Proof declarations
+CRef Solver::TCRef_Undef = CRef_Undef;
+CRef Solver::TCRef_Lazy = CRef_Lazy;
class ScopedBool {
bool& watch;
@@ -135,8 +140,12 @@ Solver::Solver(CVC4::prop::TheoryProxy* proxy, CVC4::context::Context* context,
// Assert the constants
uncheckedEnqueue(mkLit(varTrue, false));
uncheckedEnqueue(mkLit(varFalse, true));
- PROOF( ProofManager::getSatProof()->registerUnitClause(mkLit(varTrue, false), INPUT, uint64_t(-1)); )
- PROOF( ProofManager::getSatProof()->registerUnitClause(mkLit(varFalse, true), INPUT, uint64_t(-1)); )
+ // FIXME: these should be axioms I believe
+ PROOF
+ (
+ ProofManager::getSatProof()->registerTrueLit(mkLit(varTrue, false));
+ ProofManager::getSatProof()->registerFalseLit(mkLit(varFalse, true));
+ );
}
@@ -217,7 +226,9 @@ CRef Solver::reason(Var x) {
// Get the explanation from the theory
SatClause explanation_cl;
- proxy->explainPropagation(MinisatSatSolver::toSatLiteral(l), explanation_cl);
+ // FIXME: at some point return a tag with the theory that spawned you
+ proxy->explainPropagation(MinisatSatSolver::toSatLiteral(l),
+ explanation_cl);
vec<Lit> explanation;
MinisatSatSolver::toMinisatClause(explanation_cl, explanation);
@@ -263,7 +274,12 @@ CRef Solver::reason(Var x) {
// Construct the reason
CRef real_reason = ca.alloc(explLevel, explanation, true);
- PROOF (ProofManager::getSatProof()->registerClause(real_reason, THEORY_LEMMA, (uint64_t(RULE_CONFLICT) << 32)); );
+ // FIXME: at some point will need more information about where this explanation
+ // came from (ie. the theory/sharing)
+ PROOF (ClauseId id = ProofManager::getSatProof()->registerClause(real_reason, THEORY_LEMMA);
+ ProofManager::getCnfProof()->registerConvertedClause(id, true);
+ // no need to pop current assertion as this is not converted to cnf
+ );
vardata[x] = VarData(real_reason, level(x), user_level(x), intro_level(x), trail_index(x));
clauses_removable.push(real_reason);
attachClause(real_reason);
@@ -271,7 +287,7 @@ CRef Solver::reason(Var x) {
return real_reason;
}
-bool Solver::addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id)
+bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id)
{
if (!ok) return false;
@@ -289,11 +305,13 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id)
clauseLevel = std::max(clauseLevel, intro_level(var(ps[i])));
// Tautologies are ignored
if (ps[i] == ~p) {
+ id = ClauseIdUndef;
// Clause can be ignored
return true;
}
// Clauses with 0-level true literals are also ignored
if (value(ps[i]) == l_True && level(var(ps[i])) == 0 && user_level(var(ps[i])) == 0) {
+ id = ClauseIdUndef;
return true;
}
// Ignore repeated literals
@@ -321,8 +339,19 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id)
lemmas.push();
ps.copyTo(lemmas.last());
lemmas_removable.push(removable);
- Debug("cores") << "lemma push " << proof_id << " " << (proof_id & 0xffffffff) << std::endl;
- lemmas_proof_id.push(proof_id);
+ PROOF(
+ // Store the expression being converted to CNF until
+ // the clause is actually created
+ Node assertion = ProofManager::getCnfProof()->getCurrentAssertion();
+ Node def = ProofManager::getCnfProof()->getCurrentDefinition();
+ lemmas_cnf_assertion.push_back(std::make_pair(assertion, def));
+ id = ClauseIdUndef;
+ );
+ // does it have to always be a lemma?
+ // PROOF(id = ProofManager::getSatProof()->registerUnitClause(ps[0], THEORY_LEMMA););
+ // PROOF(id = ProofManager::getSatProof()->registerTheoryLemma(ps););
+ // Debug("cores") << "lemma push " << proof_id << " " << (proof_id & 0xffffffff) << std::endl;
+ // lemmas_proof_id.push(proof_id);
} else {
// If all false, we're in conflict
if (ps.size() == falseLiteralsCount) {
@@ -331,7 +360,7 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id)
// construct the clause below to give to the proof manager
// as the final conflict.
if(falseLiteralsCount == 1) {
- PROOF( ProofManager::getSatProof()->storeUnitConflict(ps[0], INPUT, proof_id); )
+ PROOF( id = ProofManager::getSatProof()->storeUnitConflict(ps[0], INPUT); )
PROOF( ProofManager::getSatProof()->finalizeProof(CVC4::Minisat::CRef_Lazy); )
return ok = false;
}
@@ -353,7 +382,9 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id)
attachClause(cr);
if(PROOF_ON()) {
- PROOF( ProofManager::getSatProof()->registerClause(cr, INPUT, proof_id); )
+ PROOF(
+ id = ProofManager::getSatProof()->registerClause(cr, INPUT);
+ )
if(ps.size() == falseLiteralsCount) {
PROOF( ProofManager::getSatProof()->finalizeProof(cr); )
return ok = false;
@@ -366,12 +397,16 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id)
if(assigns[var(ps[0])] == l_Undef) {
assert(assigns[var(ps[0])] != l_False);
uncheckedEnqueue(ps[0], cr);
- Debug("cores") << "i'm registering a unit clause, input, proof id " << proof_id << std::endl;
- PROOF( if(ps.size() == 1) { ProofManager::getSatProof()->registerUnitClause(ps[0], INPUT, proof_id); } );
+ Debug("cores") << "i'm registering a unit clause, input" << std::endl;
+ PROOF(
+ if(ps.size() == 1) {
+ id = ProofManager::getSatProof()->registerUnitClause(ps[0], INPUT);
+ }
+ );
CRef confl = propagate(CHECK_WITHOUT_THEORY);
if(! (ok = (confl == CRef_Undef)) ) {
if(ca[confl].size() == 1) {
- PROOF( ProofManager::getSatProof()->storeUnitConflict(ca[confl][0], LEARNT, proof_id); );
+ PROOF( id = ProofManager::getSatProof()->storeUnitConflict(ca[confl][0], LEARNT); );
PROOF( ProofManager::getSatProof()->finalizeProof(CVC4::Minisat::CRef_Lazy); )
} else {
PROOF( ProofManager::getSatProof()->finalizeProof(confl); );
@@ -604,7 +639,7 @@ int Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel)
for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++){
Lit q = c[j];
- if (!seen[var(q)] && level(var(q)) > 0){
+ if (!seen[var(q)] && level(var(q)) > 0) {
varBumpActivity(var(q));
seen[var(q)] = 1;
if (level(var(q)) >= decisionLevel())
@@ -646,7 +681,7 @@ int Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel)
uint32_t abstract_level = 0;
for (i = 1; i < out_learnt.size(); i++)
abstract_level |= abstractLevel(var(out_learnt[i])); // (maintain an abstraction of levels involved in conflict)
-
+
for (i = j = 1; i < out_learnt.size(); i++) {
if (reason(var(out_learnt[i])) == CRef_Undef) {
out_learnt[j++] = out_learnt[i];
@@ -901,7 +936,8 @@ void Solver::propagateTheory() {
proxy->explainPropagation(MinisatSatSolver::toSatLiteral(p), explanation_cl);
vec<Lit> explanation;
MinisatSatSolver::toMinisatClause(explanation_cl, explanation);
- addClause(explanation, true, 0);
+ ClauseId id; // FIXME: mark it as explanation here somehow?
+ addClause(explanation, true, id);
}
}
}
@@ -1159,8 +1195,17 @@ lbool Solver::search(int nof_conflicts)
attachClause(cr);
claBumpActivity(ca[cr]);
uncheckedEnqueue(learnt_clause[0], cr);
-
- PROOF( ProofManager::getSatProof()->endResChain(cr); )
+ PROOF(
+ ClauseId id = ProofManager::getSatProof()->registerClause(cr, LEARNT);
+ PSTATS(
+ __gnu_cxx::hash_set<int> cl_levels;
+ for (int i = 0; i < learnt_clause.size(); ++i) {
+ cl_levels.insert(level(var(learnt_clause[i])));
+ }
+ ProofManager::getSatProof()->storeClauseGlue(id, cl_levels.size());
+ )
+ ProofManager::getSatProof()->endResChain(id);
+ );
}
varDecayActivity();
@@ -1650,14 +1695,14 @@ CRef Solver::updateLemmas() {
// Last index in the trail
int backtrack_index = trail.size();
+ PROOF(Assert (lemmas.size() == (int)lemmas_cnf_assertion.size()););
+
// Attach all the clauses and enqueue all the propagations
for (int i = 0; i < lemmas.size(); ++ i)
{
// The current lemma
vec<Lit>& lemma = lemmas[i];
bool removable = lemmas_removable[i];
- uint64_t proof_id = lemmas_proof_id[i];
- Debug("cores") << "pulled lemma proof id " << proof_id << " " << (proof_id & 0xffffffff) << std::endl;
// Attach it if non-unit
CRef lemma_ref = CRef_Undef;
@@ -1672,7 +1717,15 @@ CRef Solver::updateLemmas() {
}
lemma_ref = ca.alloc(clauseLevel, lemma, removable);
- PROOF( ProofManager::getSatProof()->registerClause(lemma_ref, THEORY_LEMMA, proof_id); );
+ PROOF
+ (
+ TNode cnf_assertion = lemmas_cnf_assertion[i].first;
+ TNode cnf_def = lemmas_cnf_assertion[i].second;
+
+ ClauseId id = ProofManager::getSatProof()->registerClause(lemma_ref, THEORY_LEMMA);
+ ProofManager::getCnfProof()->setClauseAssertion(id, cnf_assertion);
+ ProofManager::getCnfProof()->setClauseDefinition(id, cnf_def);
+ );
if (removable) {
clauses_removable.push(lemma_ref);
} else {
@@ -1680,7 +1733,15 @@ CRef Solver::updateLemmas() {
}
attachClause(lemma_ref);
} else {
- PROOF( ProofManager::getSatProof()->registerUnitClause(lemma[0], THEORY_LEMMA, proof_id); );
+ PROOF
+ (
+ Node cnf_assertion = lemmas_cnf_assertion[i].first;
+ Node cnf_def = lemmas_cnf_assertion[i].second;
+
+ ClauseId id = ProofManager::getSatProof()->registerUnitClause(lemma[0], THEORY_LEMMA);
+ ProofManager::getCnfProof()->setClauseAssertion(id, cnf_assertion);
+ ProofManager::getCnfProof()->setClauseDefinition(id, cnf_def);
+ );
}
// If the lemma is propagating enqueue its literal (or set the conflict)
@@ -1694,7 +1755,7 @@ CRef Solver::updateLemmas() {
} else {
Debug("minisat::lemmas") << "Solver::updateLemmas(): unit conflict or empty clause" << std::endl;
conflict = CRef_Lazy;
- PROOF( ProofManager::getSatProof()->storeUnitConflict(lemma[0], LEARNT, proof_id); );
+ PROOF( ProofManager::getSatProof()->storeUnitConflict(lemma[0], LEARNT); );
}
} else {
Debug("minisat::lemmas") << "lemma size is " << lemma.size() << std::endl;
@@ -1704,10 +1765,11 @@ CRef Solver::updateLemmas() {
}
}
+ PROOF(Assert (lemmas.size() == (int)lemmas_cnf_assertion.size()););
// Clear the lemmas
lemmas.clear();
+ lemmas_cnf_assertion.clear();
lemmas_removable.clear();
- lemmas_proof_id.clear();
if (conflict != CRef_Undef) {
theoryConflict = true;
@@ -1718,6 +1780,28 @@ CRef Solver::updateLemmas() {
return conflict;
}
+void ClauseAllocator::reloc(CRef& cr, ClauseAllocator& to, CVC4::CoreProofProxy* proxy)
+{
+
+ // FIXME what is this CRef_lazy
+ if (cr == CRef_Lazy) return;
+
+ CRef old = cr; // save the old reference
+ Clause& c = operator[](cr);
+ if (c.reloced()) { cr = c.relocation(); return; }
+
+ cr = to.alloc(c.level(), c, c.removable());
+ c.relocate(cr);
+ if (proxy) {
+ proxy->updateCRef(old, cr);
+ }
+ // Copy extra data-fields:
+ // (This could be cleaned-up. Generalize Clause-constructor to be applicable here instead?)
+ to[cr].mark(c.mark());
+ if (to[cr].removable()) to[cr].activity() = c.activity();
+ else if (to[cr].has_extra()) to[cr].calcAbstraction();
+}
+
inline bool Solver::withinBudget(uint64_t ammount) const {
Assert (proxy);
// spendResource sets async_interrupt or throws UnsafeInterruptException
diff --git a/src/prop/minisat/core/Solver.h b/src/prop/minisat/core/Solver.h
index 3be6b1b22..a239eba72 100644
--- a/src/prop/minisat/core/Solver.h
+++ b/src/prop/minisat/core/Solver.h
@@ -37,13 +37,15 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
namespace CVC4 {
- class SatProof;
+template <class Solver> class TSatProof;
- namespace prop {
- class TheoryProxy;
- }/* CVC4::prop namespace */
+namespace prop {
+ class TheoryProxy;
+}/* CVC4::prop namespace */
}/* CVC4 namespace */
+typedef unsigned ClauseId;
+
namespace CVC4 {
namespace Minisat {
@@ -54,7 +56,18 @@ class Solver {
/** The only two CVC4 entry points to the private solver data */
friend class CVC4::prop::TheoryProxy;
- friend class CVC4::SatProof;
+ friend class CVC4::TSatProof<Minisat::Solver>;
+
+public:
+ static CRef TCRef_Undef;
+ static CRef TCRef_Lazy;
+
+ typedef Var TVar;
+ typedef Lit TLit;
+ typedef Clause TClause;
+ typedef CRef TCRef;
+ typedef vec<Lit> TLitVec;
+
protected:
/** The pointer to the proxy that provides interfaces to the SMT engine */
@@ -85,8 +98,8 @@ protected:
/** Is the lemma removable */
vec<bool> lemmas_removable;
- /** Proof IDs for lemmas */
- vec<uint64_t> lemmas_proof_id;
+ /** Nodes being converted to CNF */
+ std::vector< std::pair<CVC4::Node, CVC4::Node > >lemmas_cnf_assertion;
/** Do a another check if FULL_EFFORT was the last one */
bool recheck;
@@ -157,14 +170,14 @@ public:
void push ();
void pop ();
- // CVC4 adds the "proof_id" here to refer to the input assertion/lemma
- // that produced this clause
- bool addClause (const vec<Lit>& ps, bool removable, uint64_t proof_id); // Add a clause to the solver.
- bool addEmptyClause(bool removable); // Add the empty clause, making the solver contradictory.
- bool addClause (Lit p, bool removable, uint64_t proof_id); // Add a unit clause to the solver.
- bool addClause (Lit p, Lit q, bool removable, uint64_t proof_id); // Add a binary clause to the solver.
- bool addClause (Lit p, Lit q, Lit r, bool removable, uint64_t proof_id); // Add a ternary clause to the solver.
- bool addClause_( vec<Lit>& ps, bool removable, uint64_t proof_id); // Add a clause to the solver without making superflous internal copy. Will
+ // addClause returns the ClauseId corresponding to the clause added in the
+ // reference parameter id.
+ bool addClause (const vec<Lit>& ps, bool removable, ClauseId& id); // Add a clause to the solver.
+ bool addEmptyClause(bool removable); // Add the empty clause, making the solver contradictory.
+ bool addClause (Lit p, bool removable, ClauseId& id); // Add a unit clause to the solver.
+ bool addClause (Lit p, Lit q, bool removable, ClauseId& id); // Add a binary clause to the solver.
+ bool addClause (Lit p, Lit q, Lit r, bool removable, ClauseId& id); // Add a ternary clause to the solver.
+ bool addClause_( vec<Lit>& ps, bool removable, ClauseId& id); // Add a clause to the solver without making superflous internal copy. Will
// change the passed vector 'ps'.
// Solving:
@@ -495,15 +508,15 @@ inline void Solver::checkGarbage(double gf){
// NOTE: enqueue does not set the ok flag! (only public methods do)
inline bool Solver::enqueue (Lit p, CRef from) { return value(p) != l_Undef ? value(p) != l_False : (uncheckedEnqueue(p, from), true); }
-inline bool Solver::addClause (const vec<Lit>& ps, bool removable, uint64_t proof_id)
- { ps.copyTo(add_tmp); return addClause_(add_tmp, removable, proof_id); }
-inline bool Solver::addEmptyClause (bool removable) { add_tmp.clear(); return addClause_(add_tmp, removable, uint64_t(-1)); }
-inline bool Solver::addClause (Lit p, bool removable, uint64_t proof_id)
- { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, removable, proof_id); }
-inline bool Solver::addClause (Lit p, Lit q, bool removable, uint64_t proof_id)
- { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, removable, proof_id); }
-inline bool Solver::addClause (Lit p, Lit q, Lit r, bool removable, uint64_t proof_id)
- { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, removable, proof_id); }
+inline bool Solver::addClause (const vec<Lit>& ps, bool removable, ClauseId& id)
+ { ps.copyTo(add_tmp); return addClause_(add_tmp, removable, id); }
+inline bool Solver::addEmptyClause (bool removable) { add_tmp.clear(); ClauseId tmp; return addClause_(add_tmp, removable, tmp); }
+inline bool Solver::addClause (Lit p, bool removable, ClauseId& id)
+ { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, removable, id); }
+inline bool Solver::addClause (Lit p, Lit q, bool removable, ClauseId& id)
+ { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, removable, id); }
+inline bool Solver::addClause (Lit p, Lit q, Lit r, bool removable, ClauseId& id)
+ { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, removable, id); }
inline bool Solver::locked (const Clause& c) const { return value(c[0]) == l_True && isPropagatedBy(var(c[0]), c); }
inline void Solver::newDecisionLevel() { trail_lim.push(trail.size()); flipped.push(false); context->push(); if(Dump.isOn("state")) { Dump("state") << CVC4::PushCommand(); } }
diff --git a/src/prop/minisat/core/SolverTypes.h b/src/prop/minisat/core/SolverTypes.h
index b0d78242c..116a39a49 100644
--- a/src/prop/minisat/core/SolverTypes.h
+++ b/src/prop/minisat/core/SolverTypes.h
@@ -169,20 +169,22 @@ inline std::ostream& operator <<(std::ostream& out, Minisat::lbool val) {
}
-} /* Minisat */
-}
-
+class Solver;
-
-namespace CVC4 {
class ProofProxyAbstract {
public:
virtual ~ProofProxyAbstract() {}
virtual void updateCRef(Minisat::CRef oldref, Minisat::CRef newref) = 0;
};
-}
+
+} /* namespace CVC4::Minisat */
+} /* namespace CVC4 */
+namespace CVC4 {
+template <class Solver> class ProofProxy;
+typedef ProofProxy<CVC4::Minisat::Solver> CoreProofProxy;
+}
namespace CVC4 {
namespace Minisat{
@@ -305,27 +307,8 @@ class ClauseAllocator : public RegionAllocator<uint32_t>
RegionAllocator<uint32_t>::free(clauseWord32Size(c.size(), c.has_extra()));
}
- void reloc(CRef& cr, ClauseAllocator& to, CVC4::ProofProxyAbstract* proxy = NULL)
- {
-
- // FIXME what is this CRef_lazy
- if (cr == CRef_Lazy) return;
-
- CRef old = cr; // save the old reference
- Clause& c = operator[](cr);
- if (c.reloced()) { cr = c.relocation(); return; }
-
- cr = to.alloc(c.level(), c, c.removable());
- c.relocate(cr);
- if (proxy) {
- proxy->updateCRef(old, cr);
- }
- // Copy extra data-fields:
- // (This could be cleaned-up. Generalize Clause-constructor to be applicable here instead?)
- to[cr].mark(c.mark());
- if (to[cr].removable()) to[cr].activity() = c.activity();
- else if (to[cr].has_extra()) to[cr].calcAbstraction();
- }
+ void reloc(CRef& cr, ClauseAllocator& to, CVC4::CoreProofProxy* proxy = NULL);
+ // Implementation moved to Solver.cc.
};
diff --git a/src/prop/minisat/minisat.cpp b/src/prop/minisat/minisat.cpp
index ce5c1eb92..739d9087a 100644
--- a/src/prop/minisat/minisat.cpp
+++ b/src/prop/minisat/minisat.cpp
@@ -23,6 +23,7 @@
#include "options/prop_options.h"
#include "options/smt_options.h"
#include "prop/minisat/simp/SimpSolver.h"
+#include "proof/sat_proof.h"
#include "util/statistics_registry.h"
namespace CVC4 {
@@ -94,14 +95,6 @@ void MinisatSatSolver::toMinisatClause(SatClause& clause,
Assert(clause.size() == (unsigned)minisat_clause.size());
}
-void MinisatSatSolver::toSatClause(Minisat::vec<Minisat::Lit>& clause,
- SatClause& sat_clause) {
- for (int i = 0; i < clause.size(); ++i) {
- sat_clause.push_back(toSatLiteral(clause[i]));
- }
- Assert((unsigned)clause.size() == sat_clause.size());
-}
-
void MinisatSatSolver::toSatClause(const Minisat::Clause& clause,
SatClause& sat_clause) {
for (int i = 0; i < clause.size(); ++i) {
@@ -149,10 +142,18 @@ void MinisatSatSolver::setupOptions() {
d_minisat->restart_inc = options::satRestartInc();
}
-void MinisatSatSolver::addClause(SatClause& clause, bool removable, uint64_t proof_id) {
+ClauseId MinisatSatSolver::addClause(SatClause& clause, bool removable) {
Minisat::vec<Minisat::Lit> minisat_clause;
toMinisatClause(clause, minisat_clause);
- d_minisat->addClause(minisat_clause, removable, proof_id);
+ ClauseId clause_id = ClauseIdError;
+ // FIXME: This relies on the invariant that when ok() is false
+ // the SAT solver does not add the clause (which is what Minisat currently does)
+ if (!ok()) {
+ return ClauseIdUndef;
+ }
+ d_minisat->addClause(minisat_clause, removable, clause_id);
+ PROOF( Assert (clause_id != ClauseIdError););
+ return clause_id;
}
SatVariable MinisatSatSolver::newVar(bool isTheoryAtom, bool preRegister, bool canErase) {
@@ -182,6 +183,9 @@ SatValue MinisatSatSolver::solve() {
return toSatLiteralValue(d_minisat->solve());
}
+bool MinisatSatSolver::ok() const {
+ return d_minisat->okay();
+}
void MinisatSatSolver::interrupt() {
d_minisat->interrupt();
@@ -280,3 +284,20 @@ void MinisatSatSolver::Statistics::init(Minisat::SimpSolver* d_minisat){
} /* namespace CVC4::prop */
} /* namespace CVC4 */
+
+
+namespace CVC4 {
+template<>
+prop::SatLiteral toSatLiteral< CVC4::Minisat::Solver>(Minisat::Solver::TLit lit) {
+ return prop::MinisatSatSolver::toSatLiteral(lit);
+}
+
+template<>
+void toSatClause< CVC4::Minisat::Solver> (const CVC4::Minisat::Solver::TClause& minisat_cl,
+ prop::SatClause& sat_cl) {
+ prop::MinisatSatSolver::toSatClause(minisat_cl, sat_cl);
+}
+
+} /* namespace CVC4 */
+
+
diff --git a/src/prop/minisat/minisat.h b/src/prop/minisat/minisat.h
index f279b3a5b..535ce1a47 100644
--- a/src/prop/minisat/minisat.h
+++ b/src/prop/minisat/minisat.h
@@ -40,11 +40,10 @@ public:
//(Commented because not in use) static bool tobool(SatValue val);
static void toMinisatClause(SatClause& clause, Minisat::vec<Minisat::Lit>& minisat_clause);
- static void toSatClause (Minisat::vec<Minisat::Lit>& clause, SatClause& sat_clause);
static void toSatClause (const Minisat::Clause& clause, SatClause& sat_clause);
void initialize(context::Context* context, TheoryProxy* theoryProxy);
- void addClause(SatClause& clause, bool removable, uint64_t proof_id);
+ ClauseId addClause(SatClause& clause, bool removable);
SatVariable newVar(bool isTheoryAtom, bool preRegister, bool canErase);
SatVariable trueVar() { return d_minisat->trueVar(); }
@@ -53,6 +52,8 @@ public:
SatValue solve();
SatValue solve(long unsigned int&);
+ bool ok() const;
+
void interrupt();
SatValue value(SatLiteral l);
diff --git a/src/prop/minisat/simp/SimpSolver.cc b/src/prop/minisat/simp/SimpSolver.cc
index 235c97e8f..5bdaea950 100644
--- a/src/prop/minisat/simp/SimpSolver.cc
+++ b/src/prop/minisat/simp/SimpSolver.cc
@@ -160,7 +160,7 @@ lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
-bool SimpSolver::addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id)
+bool SimpSolver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id)
{
#ifndef NDEBUG
if (use_simplification) {
@@ -174,7 +174,7 @@ bool SimpSolver::addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id)
if (use_rcheck && implied(ps))
return true;
- if (!Solver::addClause_(ps, removable, proof_id))
+ if (!Solver::addClause_(ps, removable, id))
return false;
if (use_simplification && clauses_persistent.size() == nclauses + 1){
@@ -541,12 +541,14 @@ bool SimpSolver::eliminateVar(Var v)
for (int i = 0; i < cls.size(); i++)
removeClause(cls[i]);
+ ClauseId id = ClauseIdUndef;
// Produce clauses in cross product:
vec<Lit>& resolvent = add_tmp;
for (int i = 0; i < pos.size(); i++)
for (int j = 0; j < neg.size(); j++) {
bool removable = ca[pos[i]].removable() && ca[pos[neg[j]]].removable();
- if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent, removable, uint64_t(-1))) {
+ if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) &&
+ !addClause_(resolvent, removable, id)) {
return false;
}
}
@@ -585,8 +587,8 @@ bool SimpSolver::substitute(Var v, Lit x)
}
removeClause(cls[i]);
-
- if (!addClause_(subst_clause, c.removable(), uint64_t(-1))) {
+ ClauseId id = ClauseIdUndef;
+ if (!addClause_(subst_clause, c.removable(), id)) {
return ok = false;
}
}
diff --git a/src/prop/minisat/simp/SimpSolver.h b/src/prop/minisat/simp/SimpSolver.h
index 0c5062726..a19bec1ef 100644
--- a/src/prop/minisat/simp/SimpSolver.h
+++ b/src/prop/minisat/simp/SimpSolver.h
@@ -48,12 +48,12 @@ class SimpSolver : public Solver {
// Problem specification:
//
Var newVar (bool polarity = true, bool dvar = true, bool isTheoryAtom = false, bool preRegister = false, bool canErase = true);
- bool addClause (const vec<Lit>& ps, bool removable, uint64_t proof_id);
- bool addEmptyClause(bool removable, uint64_t proof_id); // Add the empty clause to the solver.
- bool addClause (Lit p, bool removable, uint64_t proof_id); // Add a unit clause to the solver.
- bool addClause (Lit p, Lit q, bool removable, uint64_t proof_id); // Add a binary clause to the solver.
- bool addClause (Lit p, Lit q, Lit r, bool removable, uint64_t proof_id); // Add a ternary clause to the solver.
- bool addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id);
+ bool addClause (const vec<Lit>& ps, bool removable, ClauseId& id);
+ bool addEmptyClause(bool removable); // Add the empty clause to the solver.
+ bool addClause (Lit p, bool removable, ClauseId& id); // Add a unit clause to the solver.
+ bool addClause (Lit p, Lit q, bool removable, ClauseId& id); // Add a binary clause to the solver.
+ bool addClause (Lit p, Lit q, Lit r, bool removable, ClauseId& id); // Add a ternary clause to the solver.
+ bool addClause_(vec<Lit>& ps, bool removable, ClauseId& id);
bool substitute(Var v, Lit x); // Replace all occurences of v with x (may cause a contradiction).
// Variable mode:
@@ -183,15 +183,15 @@ inline void SimpSolver::updateElimHeap(Var v) {
elim_heap.update(v); }
-inline bool SimpSolver::addClause (const vec<Lit>& ps, bool removable, uint64_t proof_id)
- { ps.copyTo(add_tmp); return addClause_(add_tmp, removable, proof_id); }
-inline bool SimpSolver::addEmptyClause(bool removable, uint64_t proof_id) { add_tmp.clear(); return addClause_(add_tmp, removable, proof_id); }
-inline bool SimpSolver::addClause (Lit p, bool removable, uint64_t proof_id)
- { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, removable, proof_id); }
-inline bool SimpSolver::addClause (Lit p, Lit q, bool removable, uint64_t proof_id)
- { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, removable, proof_id); }
-inline bool SimpSolver::addClause (Lit p, Lit q, Lit r, bool removable, uint64_t proof_id)
- { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, removable, proof_id); }
+inline bool SimpSolver::addClause(const vec<Lit>& ps, bool removable, ClauseId& id)
+{ ps.copyTo(add_tmp); return addClause_(add_tmp, removable, id); }
+inline bool SimpSolver::addEmptyClause(bool removable) { add_tmp.clear(); ClauseId id=-1; return addClause_(add_tmp, removable, id); }
+inline bool SimpSolver::addClause (Lit p, bool removable, ClauseId& id)
+ { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, removable, id); }
+inline bool SimpSolver::addClause (Lit p, Lit q, bool removable, ClauseId& id)
+ { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, removable, id); }
+inline bool SimpSolver::addClause (Lit p, Lit q, Lit r, bool removable, ClauseId& id)
+ { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, removable, id); }
inline void SimpSolver::setFrozen (Var v, bool b) { frozen[v] = (char)b; if (use_simplification && !b) { updateElimHeap(v); } }
// the solver can always return unknown due to resource limiting
diff --git a/src/prop/prop_engine.cpp b/src/prop/prop_engine.cpp
index 9767ac7c7..593c522a8 100644
--- a/src/prop/prop_engine.cpp
+++ b/src/prop/prop_engine.cpp
@@ -99,7 +99,9 @@ PropEngine::PropEngine(TheoryEngine* te, DecisionEngine *de, Context* satContext
d_decisionEngine->setSatSolver(d_satSolver);
d_decisionEngine->setCnfStream(d_cnfStream);
- PROOF (ProofManager::currentPM()->initCnfProof(d_cnfStream); );
+ PROOF (
+ ProofManager::currentPM()->initCnfProof(d_cnfStream, userContext);
+ );
}
PropEngine::~PropEngine() {
@@ -117,7 +119,10 @@ void PropEngine::assertFormula(TNode node) {
d_cnfStream->convertAndAssert(node, false, false, RULE_GIVEN);
}
-void PropEngine::assertLemma(TNode node, bool negated, bool removable, ProofRule rule, TNode from) {
+void PropEngine::assertLemma(TNode node, bool negated,
+ bool removable,
+ ProofRule rule,
+ TNode from) {
//Assert(d_inCheckSat, "Sat solver should be in solve()!");
Debug("prop::lemmas") << "assertLemma(" << node << ")" << endl;
diff --git a/src/prop/sat_solver.h b/src/prop/sat_solver.h
index 1c1dae410..1383308a3 100644
--- a/src/prop/sat_solver.h
+++ b/src/prop/sat_solver.h
@@ -30,10 +30,15 @@
#include "util/statistics_registry.h"
namespace CVC4 {
+
+class BitVectorProof;
+
namespace prop {
class TheoryProxy;
+typedef unsigned ClauseId;
+
class SatSolver {
public:
@@ -42,7 +47,8 @@ public:
virtual ~SatSolver() throw(AssertionException) { }
/** Assert a clause in the solver. */
- virtual void addClause(SatClause& clause, bool removable, uint64_t proof_id) = 0;
+ virtual ClauseId addClause(SatClause& clause,
+ bool removable) = 0;
/**
* Create a new boolean variable in the solver.
@@ -77,6 +83,10 @@ public:
/** Get the current assertion level */
virtual unsigned getAssertionLevel() const = 0;
+ /** Check if the solver is in an inconsistent state */
+ virtual bool ok() const = 0;
+
+
};/* class SatSolver */
@@ -121,6 +131,10 @@ public:
virtual void popAssumption() = 0;
+ virtual bool ok() const = 0;
+
+ virtual void setProofLog( BitVectorProof * bvp ) {}
+
};/* class BVSatSolverInterface */
@@ -139,7 +153,8 @@ public:
virtual bool flipDecision() = 0;
virtual bool isDecision(SatVariable decn) const = 0;
-
+
+ virtual bool ok() const = 0;
};/* class DPLLSatSolverInterface */
inline std::ostream& operator <<(std::ostream& out, prop::SatLiteral lit) {
diff --git a/src/prop/sat_solver_factory.h b/src/prop/sat_solver_factory.h
index 434bf849d..6a3053a18 100644
--- a/src/prop/sat_solver_factory.h
+++ b/src/prop/sat_solver_factory.h
@@ -31,7 +31,9 @@ namespace prop {
class SatSolverFactory {
public:
- static BVSatSolverInterface* createMinisat(context::Context* mainSatContext, StatisticsRegistry* registry, const std::string& name = "");
+ static BVSatSolverInterface* createMinisat(context::Context* mainSatContext,
+ StatisticsRegistry* registry,
+ const std::string& name = "");
static DPLLSatSolverInterface* createDPLLMinisat(StatisticsRegistry* registry);
};/* class SatSolverFactory */
diff --git a/src/prop/theory_proxy.cpp b/src/prop/theory_proxy.cpp
index e87046ad5..5304691a6 100644
--- a/src/prop/theory_proxy.cpp
+++ b/src/prop/theory_proxy.cpp
@@ -22,6 +22,7 @@
#include "options/decision_options.h"
#include "prop/cnf_stream.h"
#include "prop/prop_engine.h"
+#include "proof/cnf_proof.h"
#include "smt_util/lemma_input_channel.h"
#include "smt_util/lemma_output_channel.h"
#include "smt/smt_statistics_registry.h"
@@ -29,6 +30,7 @@
#include "theory/theory_engine.h"
#include "util/statistics_registry.h"
+
namespace CVC4 {
namespace prop {
@@ -100,6 +102,7 @@ void TheoryProxy::explainPropagation(SatLiteral l, SatClause& explanation) {
TNode lNode = d_cnfStream->getNode(l);
Debug("prop-explain") << "explainPropagation(" << lNode << ")" << std::endl;
Node theoryExplanation = d_theoryEngine->getExplanation(lNode);
+ PROOF(ProofManager::getCnfProof()->pushCurrentAssertion(theoryExplanation); );
Debug("prop-explain") << "explainPropagation() => " << theoryExplanation << std::endl;
if (theoryExplanation.getKind() == kind::AND) {
Node::const_iterator it = theoryExplanation.begin();
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index 1962c6433..c66031265 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -788,6 +788,13 @@ SmtEngine::SmtEngine(ExprManager* em) throw() :
d_stats = new SmtEngineStatistics();
d_stats->d_resourceUnitsUsed.setData(
d_private->getResourceManager()->getResourceUsage());
+
+ // The ProofManager is constructed before any other proof objects such as
+ // SatProof and TheoryProofs. The TheoryProofEngine and the SatProof are
+ // initialized in TheoryEngine and PropEngine respectively.
+ Assert(d_proofManager == NULL);
+ PROOF( d_proofManager = new ProofManager(); );
+
// We have mutual dependency here, so we add the prop engine to the theory
// engine later (it is non-essential there)
d_theoryEngine = new TheoryEngine(d_context, d_userContext,
@@ -798,6 +805,8 @@ SmtEngine::SmtEngine(ExprManager* em) throw() :
// Add the theories
for(TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST; ++id) {
TheoryConstructor::addTheory(d_theoryEngine, id);
+ //register with proof engine if applicable
+ THEORY_PROOF(ProofManager::currentPM()->getTheoryProofEngine()->registerTheory(d_theoryEngine->theoryOf(id)); );
}
// global push/pop around everything, to ensure proper destruction
@@ -817,9 +826,6 @@ void SmtEngine::finishInit() {
// ensure that our heuristics are properly set up
setDefaults();
- Assert(d_proofManager == NULL);
- PROOF( d_proofManager = new ProofManager(); );
-
d_decisionEngine = new DecisionEngine(d_context, d_userContext);
d_decisionEngine->init(); // enable appropriate strategies
@@ -857,7 +863,7 @@ void SmtEngine::finishInit() {
}
d_dumpCommands.clear();
- PROOF( ProofManager::currentPM()->setLogic(d_logic.getLogicString()); );
+ PROOF( ProofManager::currentPM()->setLogic(d_logic); );
}
void SmtEngine::finalOptionsAreSet() {
@@ -3515,6 +3521,14 @@ void SmtEnginePrivate::processAssertions() {
Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-definition-expansion" << endl;
dumpAssertions("post-definition-expansion", d_assertions);
+ // save the assertions now
+ THEORY_PROOF
+ (
+ for (unsigned i = 0; i < d_assertions.size(); ++i) {
+ ProofManager::currentPM()->addAssertion(d_assertions[i].toExpr());
+ }
+ );
+
Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
if( options::ceGuidedInst() ){
@@ -3936,7 +3950,8 @@ void SmtEnginePrivate::addFormula(TNode n, bool inUnsatCore, bool inInput)
PROOF(
if( inInput ){
// n is an input assertion
- ProofManager::currentPM()->addAssertion(n.toExpr(), inUnsatCore);
+ if (inUnsatCore || options::dumpUnsatCores() || options::checkUnsatCores())
+ ProofManager::currentPM()->addCoreAssertion(n.toExpr());
}else{
// n is the result of an unknown preprocessing step, add it to dependency map to null
ProofManager::currentPM()->addDependence(n, Node::null());
@@ -4724,7 +4739,7 @@ UnsatCore SmtEngine::getUnsatCore() throw(ModalException, UnsafeInterruptExcepti
throw ModalException("Cannot get an unsat core unless immediately preceded by UNSAT/VALID response.");
}
- d_proofManager->getProof(this);// just to trigger core creation
+ d_proofManager->traceUnsatCore();// just to trigger core creation
return UnsatCore(this, d_proofManager->begin_unsat_core(), d_proofManager->end_unsat_core());
#else /* IS_PROOFS_BUILD */
throw ModalException("This build of CVC4 doesn't have proof support (required for unsat cores).");
diff --git a/src/smt/smt_engine_check_proof.cpp b/src/smt/smt_engine_check_proof.cpp
index c4747d724..14adcc536 100644
--- a/src/smt/smt_engine_check_proof.cpp
+++ b/src/smt/smt_engine_check_proof.cpp
@@ -64,11 +64,12 @@ void SmtEngine::checkProof() {
Chat() << "checking proof..." << endl;
if( !(d_logic.isPure(theory::THEORY_BOOL) ||
+ d_logic.isPure(theory::THEORY_BV) ||
(d_logic.isPure(theory::THEORY_UF) &&
! d_logic.hasCardinalityConstraints())) ||
d_logic.isQuantified()) {
// no checking for these yet
- Notice() << "Notice: no proof-checking for non-UF/Bool proofs yet" << endl;
+ Notice() << "Notice: no proof-checking for non-UF/Bool/BV proofs yet" << endl;
return;
}
@@ -91,7 +92,7 @@ void SmtEngine::checkProof() {
a.use_nested_app = false;
a.compile_lib = false;
init();
- check_file(pfFile, args());
+ check_file(pfFile, a);
close(fd);
#else /* IS_PROOFS_BUILD */
diff --git a/src/smt/smt_engine_scope.h b/src/smt/smt_engine_scope.h
index 83da5a159..c4ec15371 100644
--- a/src/smt/smt_engine_scope.h
+++ b/src/smt/smt_engine_scope.h
@@ -23,6 +23,8 @@
#include "base/output.h"
#include "base/tls.h"
#include "expr/node_manager.h"
+#include "proof/proof.h"
+#include "proof/proof_manager.h"
#include "options/smt_options.h"
#include "smt/smt_engine.h"
#include "util/configuration_private.h"
@@ -44,6 +46,7 @@ inline bool smtEngineInScope() {
return s_smtEngine_current != NULL;
}
+// FIXME: Maybe move into SmtScope?
inline ProofManager* currentProofManager() {
#if IS_PROOFS_BUILD
Assert(options::proof() || options::unsatCores());
diff --git a/src/smt_util/command.cpp b/src/smt_util/command.cpp
index 8cc8a421c..83298836f 100644
--- a/src/smt_util/command.cpp
+++ b/src/smt_util/command.cpp
@@ -1110,6 +1110,7 @@ GetProofCommand::GetProofCommand() throw() {
void GetProofCommand::invoke(SmtEngine* smtEngine) throw() {
try {
+ d_smtEngine = smtEngine;
d_result = smtEngine->getProof();
d_commandStatus = CommandSuccess::instance();
} catch(UnsafeInterruptException& e) {
@@ -1127,6 +1128,7 @@ void GetProofCommand::printResult(std::ostream& out, uint32_t verbosity) const t
if(! ok()) {
this->Command::printResult(out, verbosity);
} else {
+ smt::SmtScope scope(d_smtEngine);
d_result->toStream(out);
}
}
@@ -1134,12 +1136,14 @@ void GetProofCommand::printResult(std::ostream& out, uint32_t verbosity) const t
Command* GetProofCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
GetProofCommand* c = new GetProofCommand();
c->d_result = d_result;
+ c->d_smtEngine = d_smtEngine;
return c;
}
Command* GetProofCommand::clone() const {
GetProofCommand* c = new GetProofCommand();
c->d_result = d_result;
+ c->d_smtEngine = d_smtEngine;
return c;
}
diff --git a/src/smt_util/command.h b/src/smt_util/command.h
index d8f9789f5..248e69b0e 100644
--- a/src/smt_util/command.h
+++ b/src/smt_util/command.h
@@ -584,6 +584,7 @@ public:
class CVC4_PUBLIC GetProofCommand : public Command {
protected:
Proof* d_result;
+ SmtEngine* d_smtEngine;
public:
GetProofCommand() throw();
~GetProofCommand() throw() {}
diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp
index 508a4b323..cbcccd734 100644
--- a/src/theory/arrays/theory_arrays.cpp
+++ b/src/theory/arrays/theory_arrays.cpp
@@ -26,9 +26,10 @@
#include "smt_util/command.h"
#include "theory/rewriter.h"
#include "theory/theory_model.h"
+#include "proof/theory_proof.h"
+#include "proof/proof_manager.h"
#include "theory/valuation.h"
-
using namespace std;
namespace CVC4 {
@@ -54,27 +55,28 @@ const bool d_solveWrite2 = false;
TheoryArrays::TheoryArrays(context::Context* c, context::UserContext* u,
OutputChannel& out, Valuation valuation,
- const LogicInfo& logicInfo, SmtGlobals* globals)
- : Theory(THEORY_ARRAY, c, u, out, valuation, logicInfo, globals),
- d_numRow("theory::arrays::number of Row lemmas", 0),
- d_numExt("theory::arrays::number of Ext lemmas", 0),
- d_numProp("theory::arrays::number of propagations", 0),
- d_numExplain("theory::arrays::number of explanations", 0),
- d_numNonLinear("theory::arrays::number of calls to setNonLinear", 0),
- d_numSharedArrayVarSplits("theory::arrays::number of shared array var splits", 0),
- d_numGetModelValSplits("theory::arrays::number of getModelVal splits", 0),
- d_numGetModelValConflicts("theory::arrays::number of getModelVal conflicts", 0),
- d_numSetModelValSplits("theory::arrays::number of setModelVal splits", 0),
- d_numSetModelValConflicts("theory::arrays::number of setModelVal conflicts", 0),
- d_ppEqualityEngine(u, "theory::arrays::TheoryArraysPP" , true),
+ const LogicInfo& logicInfo, SmtGlobals* globals,
+ std::string name)
+ : Theory(THEORY_ARRAY, c, u, out, valuation, logicInfo, globals, name),
+ d_numRow(name + "theory::arrays::number of Row lemmas", 0),
+ d_numExt(name + "theory::arrays::number of Ext lemmas", 0),
+ d_numProp(name + "theory::arrays::number of propagations", 0),
+ d_numExplain(name + "theory::arrays::number of explanations", 0),
+ d_numNonLinear(name + "theory::arrays::number of calls to setNonLinear", 0),
+ d_numSharedArrayVarSplits(name + "theory::arrays::number of shared array var splits", 0),
+ d_numGetModelValSplits(name + "theory::arrays::number of getModelVal splits", 0),
+ d_numGetModelValConflicts(name + "theory::arrays::number of getModelVal conflicts", 0),
+ d_numSetModelValSplits(name + "theory::arrays::number of setModelVal splits", 0),
+ d_numSetModelValConflicts(name + "theory::arrays::number of setModelVal conflicts", 0),
+ d_ppEqualityEngine(u, name + "theory::arrays::TheoryArraysPP" , true),
d_ppFacts(u),
// d_ppCache(u),
d_literalsToPropagate(c),
d_literalsToPropagateIndex(c, 0),
d_isPreRegistered(c),
- d_mayEqualEqualityEngine(c, "theory::arrays::TheoryArraysMayEqual", true),
+ d_mayEqualEqualityEngine(c, name + "theory::arrays::TheoryArraysMayEqual", true),
d_notify(*this),
- d_equalityEngine(d_notify, c, "theory::arrays::TheoryArrays", true),
+ d_equalityEngine(d_notify, c, name + "theory::arrays::TheoryArrays", true),
d_conflict(c, false),
d_backtracker(c),
d_infoMap(c, &d_backtracker),
@@ -1385,7 +1387,8 @@ void TheoryArrays::check(Effort e) {
weakEquivBuildCond(r[0], r[1], conjunctions);
weakEquivBuildCond(r2[0], r[1], conjunctions);
lemma = mkAnd(conjunctions, true);
- d_out->lemma(lemma, false, false, true);
+ // LSH FIXME: which kind of arrays lemma is this
+ d_out->lemma(lemma, RULE_INVALID, false, false, true);
d_readTableContext->pop();
return;
}
diff --git a/src/theory/arrays/theory_arrays.h b/src/theory/arrays/theory_arrays.h
index f1b02d99e..88d83bfb9 100644
--- a/src/theory/arrays/theory_arrays.h
+++ b/src/theory/arrays/theory_arrays.h
@@ -128,7 +128,7 @@ class TheoryArrays : public Theory {
TheoryArrays(context::Context* c, context::UserContext* u, OutputChannel& out,
Valuation valuation, const LogicInfo& logicInfo,
- SmtGlobals* globals);
+ SmtGlobals* globals, std::string name = "");
~TheoryArrays();
void setMasterEqualityEngine(eq::EqualityEngine* eq);
diff --git a/src/theory/bv/bitblast_strategies_template.h b/src/theory/bv/bitblast_strategies_template.h
index 0990c2f29..bc022a02d 100644
--- a/src/theory/bv/bitblast_strategies_template.h
+++ b/src/theory/bv/bitblast_strategies_template.h
@@ -253,17 +253,17 @@ void DefaultAndBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
Assert(node.getKind() == kind::BITVECTOR_AND &&
bits.size() == 0);
-
- for(unsigned j = 0; j < utils::getSize(node); ++j) {
- std::vector<T> and_j;
- for (unsigned i = 0; i < node.getNumChildren(); ++i) {
- std::vector<T> current;
- bb->bbTerm(node[i], current);
- and_j.push_back(current[j]);
- Assert(utils::getSize(node) == current.size());
+
+ bb->bbTerm(node[0], bits);
+ std::vector<T> current;
+ for(unsigned j = 1; j < node.getNumChildren(); ++j) {
+ bb->bbTerm(node[j], current);
+ for (unsigned i = 0; i < utils::getSize(node); ++i) {
+ bits[i] = mkAnd(bits[i], current[i]);
}
- bits.push_back(mkAnd(and_j));
+ current.clear();
}
+ Assert (bits.size() == utils::getSize(node));
}
template <class T>
@@ -272,17 +272,17 @@ void DefaultOrBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
Assert(node.getKind() == kind::BITVECTOR_OR &&
bits.size() == 0);
-
- for(unsigned j = 0; j < utils::getSize(node); ++j) {
- std::vector<T> or_j;
- for (unsigned i = 0; i < node.getNumChildren(); ++i) {
- std::vector<T> current;
- bb->bbTerm(node[i], current);
- or_j.push_back(current[j]);
- Assert(utils::getSize(node) == current.size());
+
+ bb->bbTerm(node[0], bits);
+ std::vector<T> current;
+ for(unsigned j = 1; j < node.getNumChildren(); ++j) {
+ bb->bbTerm(node[j], current);
+ for (unsigned i = 0; i < utils::getSize(node); ++i) {
+ bits[i] = mkOr(bits[i], current[i]);
}
- bits.push_back(mkOr(or_j));
+ current.clear();
}
+ Assert (bits.size() == utils::getSize(node));
}
template <class T>
@@ -291,20 +291,17 @@ void DefaultXorBB (TNode node, std::vector<T>& bits, TBitblaster<T>* bb) {
Assert(node.getKind() == kind::BITVECTOR_XOR &&
bits.size() == 0);
-
- for(unsigned j = 0; j < utils::getSize(node); ++j) {
- std::vector<T> first;
- bb->bbTerm(node[0], first);
- T bitj = first[j];
-
- for (unsigned i = 1; i < node.getNumChildren(); ++i) {
- std::vector<T> current;
- bb->bbTerm(node[i], current);
- bitj = mkXor(bitj, current[j]);
- Assert(utils::getSize(node) == current.size());
+
+ bb->bbTerm(node[0], bits);
+ std::vector<T> current;
+ for(unsigned j = 1; j < node.getNumChildren(); ++j) {
+ bb->bbTerm(node[j], current);
+ for (unsigned i = 0; i < utils::getSize(node); ++i) {
+ bits[i] = mkXor(bits[i], current[i]);
}
- bits.push_back(bitj);
+ current.clear();
}
+ Assert (bits.size() == utils::getSize(node));
}
template <class T>
diff --git a/src/theory/bv/bitblast_utils.h b/src/theory/bv/bitblast_utils.h
index a236c69e8..adaed31c1 100644
--- a/src/theory/bv/bitblast_utils.h
+++ b/src/theory/bv/bitblast_utils.h
@@ -221,7 +221,7 @@ inline void shiftAddMultiplier(const std::vector<T>&a, const std::vector<T>&b, s
T carry_in = mkFalse<T>();
T carry_out;
for(unsigned j = 0; j < res.size() -k; ++j) {
- T aj = mkAnd(a[j], b[k]);
+ T aj = mkAnd(b[k], a[j]);
carry_out = mkOr(mkAnd(res[j+k], aj),
mkAnd( mkXor(res[j+k], aj), carry_in));
res[j+k] = mkXor(mkXor(res[j+k], aj), carry_in);
diff --git a/src/theory/bv/bitblaster_template.h b/src/theory/bv/bitblaster_template.h
index ec76bb4f6..66eea0997 100644
--- a/src/theory/bv/bitblaster_template.h
+++ b/src/theory/bv/bitblaster_template.h
@@ -85,6 +85,8 @@ protected:
TermDefMap d_termCache;
ModelCache d_modelCache;
+ BitVectorProof * d_bvp;
+
void initAtomBBStrategies();
void initTermBBStrategies();
protected:
@@ -105,7 +107,7 @@ public:
bool hasBBTerm(TNode node) const;
void getBBTerm(TNode node, Bits& bits) const;
- void storeBBTerm(TNode term, const Bits& bits);
+ virtual void storeBBTerm(TNode term, const Bits& bits);
/**
* Return a constant representing the value of a in the model.
* If fullModel is true set unconstrained bits to 0. If not return
@@ -171,7 +173,9 @@ public:
void bbAtom(TNode node);
Node getBBAtom(TNode atom) const;
void storeBBAtom(TNode atom, Node atom_bb);
- bool hasBBAtom(TNode atom) const;
+ void storeBBTerm(TNode node, const Bits& bits);
+ bool hasBBAtom(TNode atom) const;
+
TLazyBitblaster(context::Context* c, bv::TheoryBV* bv, const std::string name="", bool emptyNotify = false);
~TLazyBitblaster() throw();
/**
@@ -201,6 +205,7 @@ public:
* constants to equivalence classes that don't already have them
*/
void collectModelInfo(TheoryModel* m, bool fullModel);
+ void setProofLog( BitVectorProof * bvp );
typedef TNodeSet::const_iterator vars_iterator;
vars_iterator beginVars() { return d_variables.begin(); }
@@ -277,9 +282,12 @@ public:
bool hasBBAtom(TNode atom) const;
void bbFormula(TNode formula);
void storeBBAtom(TNode atom, Node atom_bb);
+ void storeBBTerm(TNode node, const Bits& bits);
+
bool assertToSat(TNode node, bool propagate = true);
bool solve();
void collectModelInfo(TheoryModel* m, bool fullModel);
+ void setProofLog( BitVectorProof * bvp );
};
class BitblastingRegistrar: public prop::Registrar {
@@ -406,6 +414,7 @@ template <class T>
TBitblaster<T>::TBitblaster()
: d_termCache()
, d_modelCache()
+ , d_bvp( NULL )
{
initAtomBBStrategies();
initTermBBStrategies();
diff --git a/src/theory/bv/bv_eager_solver.cpp b/src/theory/bv/bv_eager_solver.cpp
index 66b1c4182..2af8d04d6 100644
--- a/src/theory/bv/bv_eager_solver.cpp
+++ b/src/theory/bv/bv_eager_solver.cpp
@@ -16,6 +16,7 @@
#include "options/bv_options.h"
#include "theory/bv/bitblaster_template.h"
+#include "proof/bitvector_proof.h"
#include "theory/bv/bv_eager_solver.h"
using namespace std;
@@ -54,6 +55,12 @@ void EagerBitblastSolver::initialize() {
d_aigBitblaster = new AigBitblaster();
} else {
d_bitblaster = new EagerBitblaster(d_bv);
+ THEORY_PROOF(
+ if( d_bvp ){
+ d_bitblaster->setProofLog( d_bvp );
+ d_bvp->setBitblaster(d_bitblaster);
+ }
+ );
}
}
@@ -112,3 +119,7 @@ void EagerBitblastSolver::collectModelInfo(TheoryModel* m, bool fullModel) {
AlwaysAssert(!d_useAig && d_bitblaster);
d_bitblaster->collectModelInfo(m, fullModel);
}
+
+void EagerBitblastSolver::setProofLog( BitVectorProof * bvp ) {
+ d_bvp = bvp;
+}
diff --git a/src/theory/bv/bv_eager_solver.h b/src/theory/bv/bv_eager_solver.h
index ff13867cc..cfc84dae1 100644
--- a/src/theory/bv/bv_eager_solver.h
+++ b/src/theory/bv/bv_eager_solver.h
@@ -39,7 +39,9 @@ class EagerBitblastSolver {
EagerBitblaster* d_bitblaster;
AigBitblaster* d_aigBitblaster;
bool d_useAig;
- TheoryBV* d_bv;
+
+ TheoryBV* d_bv;
+ BitVectorProof * d_bvp;
public:
EagerBitblastSolver(theory::bv::TheoryBV* bv);
@@ -53,6 +55,7 @@ public:
bool isInitialized();
void initialize();
void collectModelInfo(theory::TheoryModel* m, bool fullModel);
+ void setProofLog( BitVectorProof * bvp );
};
}
diff --git a/src/theory/bv/bv_subtheory.h b/src/theory/bv/bv_subtheory.h
index 9a314fd6a..402dd6be3 100644
--- a/src/theory/bv/bv_subtheory.h
+++ b/src/theory/bv/bv_subtheory.h
@@ -74,6 +74,8 @@ protected:
/** The bit-vector theory */
TheoryBV* d_bv;
+ /** proof log */
+ BitVectorProof * d_bvp;
AssertionQueue d_assertionQueue;
context::CDO<uint32_t> d_assertionIndex;
public:
@@ -102,6 +104,7 @@ public:
return res;
}
virtual void assertFact(TNode fact) { d_assertionQueue.push_back(fact); }
+ virtual void setProofLog( BitVectorProof * bvp ) {}
AssertionQueue::const_iterator assertionsBegin() { return d_assertionQueue.begin(); }
AssertionQueue::const_iterator assertionsEnd() { return d_assertionQueue.end(); }
};
diff --git a/src/theory/bv/bv_subtheory_bitblast.cpp b/src/theory/bv/bv_subtheory_bitblast.cpp
index 9f8cb580c..e7630bb3f 100644
--- a/src/theory/bv/bv_subtheory_bitblast.cpp
+++ b/src/theory/bv/bv_subtheory_bitblast.cpp
@@ -24,6 +24,8 @@
#include "theory/bv/bv_subtheory_bitblast.h"
#include "theory/bv/theory_bv.h"
#include "theory/bv/theory_bv_utils.h"
+#include "proof/proof_manager.h"
+#include "proof/bitvector_proof.h"
using namespace std;
using namespace CVC4::context;
@@ -44,7 +46,8 @@ BitblastSolver::BitblastSolver(context::Context* c, TheoryBV* bv)
d_abstractionModule(NULL),
d_quickCheck(options::bitvectorQuickXplain() ? new BVQuickCheck("bb", bv) : NULL),
d_quickXplain(options::bitvectorQuickXplain() ? new QuickXPlain("bb", d_quickCheck) : NULL)
-{}
+{
+}
BitblastSolver::~BitblastSolver() {
delete d_quickXplain;
@@ -232,40 +235,6 @@ Node BitblastSolver::getModelValue(TNode node)
return val;
}
-// Node BitblastSolver::getModelValueRec(TNode node)
-// {
-// Node val;
-// if (node.isConst()) {
-// return node;
-// }
-// NodeMap::iterator it = d_modelCache.find(node);
-// if (it != d_modelCache.end()) {
-// val = (*it).second;
-// Debug("bitvector-model") << node << " => (cached) " << val <<"\n";
-// return val;
-// }
-// if (d_bv->isLeaf(node)) {
-// val = d_bitblaster->getVarValue(node);
-// if (val == Node()) {
-// // If no value in model, just set to 0
-// val = utils::mkConst(utils::getSize(node), (unsigned)0);
-// }
-// } else {
-// NodeBuilder<> valBuilder(node.getKind());
-// if (node.getMetaKind() == kind::metakind::PARAMETERIZED) {
-// valBuilder << node.getOperator();
-// }
-// for (unsigned i = 0; i < node.getNumChildren(); ++i) {
-// valBuilder << getModelValueRec(node[i]);
-// }
-// val = valBuilder;
-// val = Rewriter::rewrite(val);
-// }
-// Assert(val.isConst());
-// d_modelCache[node] = val;
-// Debug("bitvector-model") << node << " => " << val <<"\n";
-// return val;
-// }
void BitblastSolver::setConflict(TNode conflict) {
@@ -279,6 +248,12 @@ void BitblastSolver::setConflict(TNode conflict) {
d_bv->setConflict(final_conflict);
}
+void BitblastSolver::setProofLog( BitVectorProof * bvp ) {
+ d_bitblaster->setProofLog( bvp );
+ bvp->setBitblaster(d_bitblaster);
+}
+
}/* namespace CVC4::theory::bv */
}/* namespace CVC4::theory */
}/* namespace CVC4 */
+
diff --git a/src/theory/bv/bv_subtheory_bitblast.h b/src/theory/bv/bv_subtheory_bitblast.h
index 0e066eefb..c69069109 100644
--- a/src/theory/bv/bv_subtheory_bitblast.h
+++ b/src/theory/bv/bv_subtheory_bitblast.h
@@ -73,8 +73,9 @@ public:
void bitblastQueue();
void setAbstraction(AbstractionModule* module);
uint64_t computeAtomWeight(TNode atom);
+ void setProofLog( BitVectorProof * bvp );
};
-}
-}
-}
+} /* namespace CVC4::theory::bv */
+} /* namespace CVC4::theory */
+} /* namespace CVC4 */
diff --git a/src/theory/bv/eager_bitblaster.cpp b/src/theory/bv/eager_bitblaster.cpp
index 000abe62b..2e4f06c38 100644
--- a/src/theory/bv/eager_bitblaster.cpp
+++ b/src/theory/bv/eager_bitblaster.cpp
@@ -19,16 +19,13 @@
#include "options/bv_options.h"
#include "prop/cnf_stream.h"
#include "prop/sat_solver_factory.h"
+#include "proof/bitvector_proof.h"
#include "smt/smt_statistics_registry.h"
#include "theory/bv/bitblaster_template.h"
#include "theory/bv/theory_bv.h"
#include "theory/theory_model.h"
-using namespace CVC4;
-using namespace CVC4::theory;
-using namespace CVC4::theory::bv;
-
namespace CVC4 {
namespace theory {
namespace bv {
@@ -46,13 +43,19 @@ EagerBitblaster::EagerBitblaster(TheoryBV* theory_bv)
d_bitblastingRegistrar = new BitblastingRegistrar(this);
d_nullContext = new context::Context();
- d_satSolver = prop::SatSolverFactory::createMinisat(
- d_nullContext, smtStatisticsRegistry(), "EagerBitblaster");
- d_cnfStream = new prop::TseitinCnfStream(d_satSolver, d_bitblastingRegistrar,
- d_nullContext, d_bv->globals());
-
+ d_satSolver = prop::SatSolverFactory::createMinisat(d_nullContext,
+ smtStatisticsRegistry(),
+ "EagerBitblaster");
+ d_cnfStream = new prop::TseitinCnfStream(d_satSolver,
+ d_bitblastingRegistrar,
+ d_nullContext,
+ d_bv->globals(),
+ options::proof(),
+ "EagerBitblaster");
+
MinisatEmptyNotify* notify = new MinisatEmptyNotify();
d_satSolver->setNotify(notify);
+ d_bvp = NULL;
}
EagerBitblaster::~EagerBitblaster() {
@@ -85,21 +88,34 @@ void EagerBitblaster::bbAtom(TNode node) {
// the bitblasted definition of the atom
Node normalized = Rewriter::rewrite(node);
Node atom_bb = normalized.getKind() != kind::CONST_BOOLEAN ?
- Rewriter::rewrite(d_atomBBStrategies[normalized.getKind()](normalized, this)) :
- normalized;
+ d_atomBBStrategies[normalized.getKind()](normalized, this) :
+ normalized;
+
+ if (!options::proof()) {
+ atom_bb = Rewriter::rewrite(atom_bb);
+ }
+
// asserting that the atom is true iff the definition holds
Node atom_definition = utils::mkNode(kind::IFF, node, atom_bb);
- AlwaysAssert (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER);
- storeBBAtom(node, atom_definition);
+ AlwaysAssert (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER);
+ storeBBAtom(node, atom_bb);
d_cnfStream->convertAndAssert(atom_definition, false, false, RULE_INVALID, TNode::null());
}
void EagerBitblaster::storeBBAtom(TNode atom, Node atom_bb) {
- // no need to store the definition for the lazy bit-blaster
- d_bbAtoms.insert(atom);
+ if( d_bvp ){
+ d_bvp->registerAtomBB(atom.toExpr(), atom_bb.toExpr());
+ }
+ d_bbAtoms.insert(atom);
}
+void EagerBitblaster::storeBBTerm(TNode node, const Bits& bits) {
+ if( d_bvp ){ d_bvp->registerTermBB(node.toExpr()); }
+ d_termCache.insert(std::make_pair(node, bits));
+}
+
+
bool EagerBitblaster::hasBBAtom(TNode atom) const {
return d_bbAtoms.find(atom) != d_bbAtoms.end();
}
@@ -211,6 +227,12 @@ void EagerBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
}
}
+void EagerBitblaster::setProofLog( BitVectorProof * bvp ) {
+ d_bvp = bvp;
+ d_satSolver->setProofLog(bvp);
+ bvp->initCnfProof(d_cnfStream, d_nullContext);
+}
+
bool EagerBitblaster::isSharedTerm(TNode node) {
return d_bv->d_sharedTermsSet.find(node) != d_bv->d_sharedTermsSet.end();
}
diff --git a/src/theory/bv/lazy_bitblaster.cpp b/src/theory/bv/lazy_bitblaster.cpp
index 34a9418dd..9268e2152 100644
--- a/src/theory/bv/lazy_bitblaster.cpp
+++ b/src/theory/bv/lazy_bitblaster.cpp
@@ -25,7 +25,9 @@
#include "theory/bv/theory_bv.h"
#include "theory/rewriter.h"
#include "theory/theory_model.h"
-#include "theory_bv_utils.h"
+#include "proof/bitvector_proof.h"
+#include "proof/proof_manager.h"
+#include "theory/bv/theory_bv_utils.h"
namespace CVC4 {
namespace theory {
@@ -51,8 +53,12 @@ TLazyBitblaster::TLazyBitblaster(context::Context* c, bv::TheoryBV* bv,
c, smtStatisticsRegistry(), name);
d_nullRegistrar = new prop::NullRegistrar();
d_nullContext = new context::Context();
- d_cnfStream = new prop::TseitinCnfStream(d_satSolver, d_nullRegistrar,
- d_nullContext, d_bv->globals());
+ d_cnfStream = new prop::TseitinCnfStream(d_satSolver,
+ d_nullRegistrar,
+ d_nullContext,
+ d_bv->globals(),
+ options::proof(),
+ "LazyBitblaster");
d_satSolverNotify = d_emptyNotify ?
(prop::BVSatSolverInterface::Notify*) new MinisatEmptyNotify() :
@@ -127,8 +133,12 @@ void TLazyBitblaster::bbAtom(TNode node) {
// the bitblasted definition of the atom
Node normalized = Rewriter::rewrite(node);
Node atom_bb = normalized.getKind() != kind::CONST_BOOLEAN ?
- Rewriter::rewrite(d_atomBBStrategies[normalized.getKind()](normalized, this)) :
- normalized;
+ d_atomBBStrategies[normalized.getKind()](normalized, this) : normalized;
+
+ if (!options::proof()) {
+ atom_bb = Rewriter::rewrite(atom_bb);
+ }
+
// asserting that the atom is true iff the definition holds
Node atom_definition = utils::mkNode(kind::IFF, node, atom_bb);
storeBBAtom(node, atom_bb);
@@ -136,10 +146,19 @@ void TLazyBitblaster::bbAtom(TNode node) {
}
void TLazyBitblaster::storeBBAtom(TNode atom, Node atom_bb) {
- // no need to store the definition for the lazy bit-blaster
+ // No need to store the definition for the lazy bit-blaster (unless proofs are enabled).
+ if( d_bvp != NULL ){
+ d_bvp->registerAtomBB(atom.toExpr(), atom_bb.toExpr());
+ }
d_bbAtoms.insert(atom);
}
+void TLazyBitblaster::storeBBTerm(TNode node, const Bits& bits) {
+ if( d_bvp ){ d_bvp->registerTermBB(node.toExpr()); }
+ d_termCache.insert(std::make_pair(node, bits));
+}
+
+
bool TLazyBitblaster::hasBBAtom(TNode atom) const {
return d_bbAtoms.find(atom) != d_bbAtoms.end();
}
@@ -483,6 +502,12 @@ void TLazyBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
}
}
+void TLazyBitblaster::setProofLog( BitVectorProof * bvp ){
+ d_bvp = bvp;
+ d_satSolver->setProofLog( bvp );
+ bvp->initCnfProof(d_cnfStream, d_nullContext);
+}
+
void TLazyBitblaster::clearSolver() {
Assert (d_ctx->getLevel() == 0);
delete d_satSolver;
diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp
index 4acd1b847..8f7e975cd 100644
--- a/src/theory/bv/theory_bv.cpp
+++ b/src/theory/bv/theory_bv.cpp
@@ -30,6 +30,8 @@
#include "theory/bv/theory_bv_rewriter.h"
#include "theory/bv/theory_bv_utils.h"
#include "theory/theory_model.h"
+#include "proof/theory_proof.h"
+#include "proof/proof_manager.h"
#include "theory/valuation.h"
using namespace CVC4::context;
@@ -363,7 +365,6 @@ void TheoryBV::checkForLemma(TNode fact) {
}
}
-
void TheoryBV::check(Effort e)
{
if (done() && !fullEffort(e)) {
@@ -706,6 +707,7 @@ Node TheoryBV::explain(TNode node) {
// return the explanation
Node explanation = utils::mkAnd(assumptions);
Debug("bitvector::explain") << "TheoryBV::explain(" << node << ") => " << explanation << std::endl;
+ Debug("bitvector::explain") << "TheoryBV::explain done. \n";
return explanation;
}
@@ -796,6 +798,16 @@ bool TheoryBV::applyAbstraction(const std::vector<Node>& assertions, std::vector
return changed;
}
+void TheoryBV::setProofLog( BitVectorProof * bvp ) {
+ if( options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER ){
+ d_eagerSolver->setProofLog( bvp );
+ }else{
+ for( unsigned i=0; i< d_subtheories.size(); i++ ){
+ d_subtheories[i]->setProofLog( bvp );
+ }
+ }
+}
+
void TheoryBV::setConflict(Node conflict) {
if (options::bvAbstraction()) {
Node new_conflict = d_abstractionModule->simplifyConflict(conflict);
diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h
index e7e4d464f..27138abfc 100644
--- a/src/theory/bv/theory_bv.h
+++ b/src/theory/bv/theory_bv.h
@@ -87,7 +87,10 @@ public:
void ppStaticLearn(TNode in, NodeBuilder<>& learned);
void presolve();
- bool applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
+
+ bool applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
+
+ void setProofLog( BitVectorProof * bvp );
private:
@@ -209,11 +212,10 @@ private:
void sendConflict();
- void lemma(TNode node) { d_out->lemma(node); d_lemmasAdded = true; }
+ void lemma(TNode node) { d_out->lemma(node, RULE_CONFLICT); d_lemmasAdded = true; }
void checkForLemma(TNode node);
-
friend class LazyBitblaster;
friend class TLazyBitblaster;
friend class EagerBitblaster;
diff --git a/src/theory/bv/theory_bv_rewrite_rules_core.h b/src/theory/bv/theory_bv_rewrite_rules_core.h
index 676df5dde..185985b3b 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_core.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_core.h
@@ -276,7 +276,8 @@ bool RewriteRule<ReflexivityEq>::applies(TNode node) {
template<> inline
Node RewriteRule<ReflexivityEq>::apply(TNode node) {
Debug("bv-rewrite") << "RewriteRule<ReflexivityEq>(" << node << ")" << std::endl;
- return node[1].eqNode(node[0]);
+ Node res = node[1].eqNode(node[0]);
+ return res;
}
}
diff --git a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
index cd173a6dd..d5d6c39dd 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
@@ -325,7 +325,8 @@ Node RewriteRule<XnorEliminate>::apply(TNode node) {
TNode a = node[0];
TNode b = node[1];
Node xorNode = utils::mkNode(kind::BITVECTOR_XOR, a, b);
- return utils::mkNode(kind::BITVECTOR_NOT, xorNode);
+ Node result = utils::mkNode(kind::BITVECTOR_NOT, xorNode);
+ return result;
}
diff --git a/src/theory/bv/theory_bv_rewrite_rules_simplification.h b/src/theory/bv/theory_bv_rewrite_rules_simplification.h
index 3bf390ded..4d3b676c9 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_simplification.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_simplification.h
@@ -379,8 +379,8 @@ Node RewriteRule<XorZero>::apply(TNode node) {
children.push_back(node[i]);
}
}
-
- return utils::mkNode(kind::BITVECTOR_XOR, children);
+ Node res = utils::mkNode(kind::BITVECTOR_XOR, children);
+ return res;
}
@@ -488,7 +488,7 @@ bool RewriteRule<NotIdemp>::applies(TNode node) {
template<> inline
Node RewriteRule<NotIdemp>::apply(TNode node) {
- Debug("bv-rewrite") << "RewriteRule<XorIdemp>(" << node << ")" << std::endl;
+ Debug("bv-rewrite") << "RewriteRule<NotIdemp>(" << node << ")" << std::endl;
return node[0][0];
}
diff --git a/src/theory/bv/theory_bv_utils.h b/src/theory/bv/theory_bv_utils.h
index ba8074fbb..993be309b 100644
--- a/src/theory/bv/theory_bv_utils.h
+++ b/src/theory/bv/theory_bv_utils.h
@@ -51,11 +51,11 @@ inline unsigned getSize(TNode node) {
return node.getType().getBitVectorSize();
}
-// this seems to behave strangely
-inline const Integer& getBit(TNode node, unsigned i) {
- Assert (0);
- Assert (node.getKind() == kind::CONST_BITVECTOR);
- return node.getConst<BitVector>().extract(i, i).getValue();
+inline const bool getBit(TNode node, unsigned i) {
+ Assert (i < utils::getSize(node) &&
+ node.getKind() == kind::CONST_BITVECTOR);
+ Integer bit = node.getConst<BitVector>().extract(i, i).getValue();
+ return (bit == 1u);
}
inline Node mkTrue() {
diff --git a/src/theory/output_channel.h b/src/theory/output_channel.h
index 2491aef3a..d5c12457a 100644
--- a/src/theory/output_channel.h
+++ b/src/theory/output_channel.h
@@ -22,6 +22,7 @@
#include "base/cvc4_assert.h"
#include "smt/logic_exception.h"
#include "theory/interrupted.h"
+#include "proof/proof_manager.h"
#include "util/resource_manager.h"
namespace CVC4 {
@@ -99,8 +100,10 @@ public:
* assigned false), or else a literal by itself (in the case of a
* unit conflict) which is assigned TRUE (and T-conflicting) in the
* current assignment.
+ * @param pf - a proof of the conflict. This is only non-null if proofs
+ * are enabled.
*/
- virtual void conflict(TNode n) throw(AssertionException, UnsafeInterruptException) = 0;
+ virtual void conflict(TNode n, Proof* pf = NULL) throw(AssertionException, UnsafeInterruptException) = 0;
/**
* Propagate a theory literal.
@@ -115,16 +118,31 @@ public:
* been detected. (This requests a split.)
*
* @param n - a theory lemma valid at decision level 0
+ * @param rule - the proof rule for this lemma
* @param removable - whether the lemma can be removed at any point
* @param preprocess - whether to apply more aggressive preprocessing
* @param sendAtoms - whether to ensure atoms are sent to the theory
* @return the "status" of the lemma, including user level at which
* the lemma resides; the lemma will be removed when this user level pops
*/
- virtual LemmaStatus lemma(TNode n, bool removable = false,
- bool preprocess = false, bool sendAtoms = false)
- throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException, LogicException) = 0;
+ virtual LemmaStatus lemma(TNode n, ProofRule rule,
+ bool removable = false,
+ bool preprocess = false,
+ bool sendAtoms = false)
+ throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) = 0;
+
+ /**
+ * Variant of the lemma function that does not require providing a proof rule.
+ */
+ virtual LemmaStatus lemma(TNode n,
+ bool removable = false,
+ bool preprocess = false,
+ bool sendAtoms = false)
+ throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
+ return lemma(n, RULE_INVALID, removable, preprocess, sendAtoms);
+ }
+
/**
* Request a split on a new theory atom. This is equivalent to
* calling lemma({OR n (NOT n)}).
diff --git a/src/theory/rewriter.cpp b/src/theory/rewriter.cpp
index c98429dd2..d89724cbd 100644
--- a/src/theory/rewriter.cpp
+++ b/src/theory/rewriter.cpp
@@ -40,7 +40,9 @@ static CVC4_THREADLOCAL(std::hash_set<Node, NodeHashFunction>*) s_rewriteStack =
class RewriterInitializer {
static RewriterInitializer s_rewriterInitializer;
- RewriterInitializer() { Rewriter::init(); }
+ RewriterInitializer() {
+ Rewriter::init();
+ }
~RewriterInitializer() { Rewriter::shutdown(); }
};/* class RewriterInitializer */
@@ -190,7 +192,8 @@ Node Rewriter::rewriteTo(theory::TheoryId theoryId, Node node) {
// Incorporate the children if necessary
if (rewriteStackTop.node.getNumChildren() > 0) {
- rewriteStackTop.node = rewriteStackTop.builder;
+ Node rewritten = rewriteStackTop.builder;
+ rewriteStackTop.node = rewritten;
rewriteStackTop.theoryId = theoryOf(rewriteStackTop.node);
}
@@ -208,7 +211,8 @@ Node Rewriter::rewriteTo(theory::TheoryId theoryId, Node node) {
Assert(s_rewriteStack->find(response.node) == s_rewriteStack->end());
s_rewriteStack->insert(response.node);
#endif
- rewriteStackTop.node = rewriteTo(newTheoryId, response.node);
+ Node rewritten = rewriteTo(newTheoryId, response.node);
+ rewriteStackTop.node = rewritten;
#ifdef CVC4_ASSERTIONS
s_rewriteStack->erase(response.node);
#endif
diff --git a/src/theory/theory.cpp b/src/theory/theory.cpp
index 9e946f8d7..45c9b1936 100644
--- a/src/theory/theory.cpp
+++ b/src/theory/theory.cpp
@@ -50,8 +50,9 @@ std::ostream& operator<<(std::ostream& os, Theory::Effort level){
Theory::Theory(TheoryId id, context::Context* satContext, context::UserContext* userContext,
OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo,
- SmtGlobals* globals) throw()
+ SmtGlobals* globals, std::string name) throw()
: d_id(id)
+ , d_instanceName(name)
, d_satContext(satContext)
, d_userContext(userContext)
, d_logicInfo(logicInfo)
@@ -60,12 +61,12 @@ Theory::Theory(TheoryId id, context::Context* satContext, context::UserContext*
, d_sharedTermsIndex(satContext, 0)
, d_careGraph(NULL)
, d_quantEngine(NULL)
- , d_checkTime(statName(id, "checkTime"))
- , d_computeCareGraphTime(statName(id, "computeCareGraphTime"))
+ , d_checkTime(getFullInstanceName() + "::checkTime")
+ , d_computeCareGraphTime(getFullInstanceName() + "::computeCareGraphTime")
, d_sharedTerms(satContext)
, d_out(&out)
, d_valuation(valuation)
- , d_proofEnabled(false)
+ , d_proofsEnabled(false)
, d_globals(globals)
{
smtStatisticsRegistry()->registerStat(&d_checkTime);
diff --git a/src/theory/theory.h b/src/theory/theory.h
index f7d9ee6a0..2c3c66d8b 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -149,6 +149,11 @@ private:
*/
TheoryId d_id;
+ /** Name of this theory instance. Along with the TheoryId this should provide
+ * an unique string identifier for each instance of a Theory class. We need
+ * this to ensure unique statistics names over multiple theory instances. */
+ std::string d_instanceName;
+
/**
* The SAT search context for the Theory.
*/
@@ -204,12 +209,6 @@ protected:
/** time spent in theory combination */
TimerStat d_computeCareGraphTime;
- static std::string statName(TheoryId id, const char* statName) {
- std::stringstream ss;
- ss << "theory<" << id << ">::" << statName;
- return ss.str();
- }
-
/**
* The only method to add suff to the care graph.
*/
@@ -247,7 +246,7 @@ protected:
*/
Theory(TheoryId id, context::Context* satContext, context::UserContext* userContext,
OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo,
- SmtGlobals* globals) throw();
+ SmtGlobals* globals, std::string name = "") throw(); // taking : No default.
/**
* This is called at shutdown time by the TheoryEngine, just before
@@ -272,6 +271,12 @@ protected:
Valuation d_valuation;
/**
+ * Whether proofs are enabled
+ *
+ */
+ bool d_proofsEnabled;
+
+ /**
* Returns the next assertion in the assertFact() queue.
*
* @return the next assertion in the assertFact() queue
@@ -290,12 +295,6 @@ protected:
void printFacts(std::ostream& os) const;
void debugPrintFacts() const;
- /**
- * Whether proofs are enabled
- *
- */
- bool d_proofEnabled;
-
SmtGlobals* d_globals;
public:
@@ -416,6 +415,13 @@ public:
return d_id;
}
+ std::string getFullInstanceName() const {
+ std::stringstream ss;
+ ss << "theory<" << d_id << ">" << d_instanceName;
+ return ss.str();
+ }
+
+
/**
* Get the SAT context associated to this Theory.
*/
@@ -855,7 +861,11 @@ public:
*/
virtual std::pair<bool, Node> entailmentCheck(TNode lit, const EntailmentCheckParameters* params = NULL, EntailmentCheckSideEffects* out = NULL);
-
+ /**
+ * Turn on proof-production mode.
+ */
+ void produceProofs() { d_proofsEnabled = true; }
+
/** Returns a pointer to the globals copy the theory is using. */
SmtGlobals* globals() { return d_globals; }
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index 25eac2ed4..be2a89dbc 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -27,7 +27,7 @@
#include "options/options.h"
#include "options/quantifiers_options.h"
#include "proof/proof_manager.h"
-#include "proof/proof_manager.h"
+#include "proof/theory_proof.h"
#include "smt/logic_exception.h"
#include "smt_util/ite_removal.h"
#include "smt_util/lemma_output_channel.h"
@@ -54,8 +54,6 @@ using namespace CVC4::theory;
namespace CVC4 {
void TheoryEngine::finishInit() {
- PROOF (ProofManager::initTheoryProof(); );
-
// initialize the quantifiers engine
d_quantEngine = new QuantifiersEngine(d_context, d_userContext, this);
@@ -157,6 +155,8 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_true = NodeManager::currentNM()->mkConst<bool>(true);
d_false = NodeManager::currentNM()->mkConst<bool>(false);
+ PROOF (ProofManager::currentPM()->initTheoryProofEngine(d_globals); );
+
d_iteUtilities = new ITEUtilities(d_iteRemover.getContainsVisitor());
smtStatisticsRegistry()->registerStat(&d_arithSubstitutionsAdded);
@@ -377,7 +377,7 @@ void TheoryEngine::check(Theory::Effort effort) {
printAssertions("theory::assertions::fulleffort");
}
}
-
+
// Note that we've discharged all the facts
d_factsAsserted = false;
@@ -414,7 +414,7 @@ void TheoryEngine::check(Theory::Effort effort) {
// must build model at this point
d_curr_model_builder->buildModel(d_curr_model, true);
}
- Trace("theory::assertions-model") << endl;
+ Trace("theory::assertions-model") << endl;
if (Trace.isOn("theory::assertions-model")) {
printAssertions("theory::assertions-model");
}
@@ -486,7 +486,7 @@ void TheoryEngine::combineTheories() {
// We need to split on it
Debug("combineTheories") << "TheoryEngine::combineTheories(): requesting a split " << endl;
- lemma(equality.orNode(equality.notNode()), false, false, false, carePair.theory);
+ lemma(equality.orNode(equality.notNode()), RULE_INVALID, false, false, false, carePair.theory);
// This code is supposed to force preference to follow what the theory models already have
// but it doesn't seem to make a big difference - need to explore more -Clark
// if (true) {
@@ -1371,7 +1371,12 @@ void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::The
}
}
-theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable, bool preprocess, theory::TheoryId atomsTo) {
+theory::LemmaStatus TheoryEngine::lemma(TNode node,
+ ProofRule rule,
+ bool negated,
+ bool removable,
+ bool preprocess,
+ theory::TheoryId atomsTo) {
// For resource-limiting (also does a time check).
// spendResource();
@@ -1420,10 +1425,10 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable
}
// assert to prop engine
- d_propEngine->assertLemma(additionalLemmas[0], negated, removable, RULE_INVALID, node);
+ d_propEngine->assertLemma(additionalLemmas[0], negated, removable, rule, node);
for (unsigned i = 1; i < additionalLemmas.size(); ++ i) {
additionalLemmas[i] = theory::Rewriter::rewrite(additionalLemmas[i]);
- d_propEngine->assertLemma(additionalLemmas[i], false, removable, RULE_INVALID, node);
+ d_propEngine->assertLemma(additionalLemmas[i], false, removable, rule, node);
}
// WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
@@ -1467,11 +1472,11 @@ void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
Node fullConflict = mkExplanation(explanationVector);
Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << "): full = " << fullConflict << endl;
Assert(properConflict(fullConflict));
- lemma(fullConflict, true, true, false, THEORY_LAST);
+ lemma(fullConflict, RULE_CONFLICT, true, true, false, THEORY_LAST);
} else {
// When only one theory, the conflict should need no processing
Assert(properConflict(conflict));
- lemma(conflict, true, true, false, THEORY_LAST);
+ lemma(conflict, RULE_CONFLICT, true, true, false, THEORY_LAST);
}
}
@@ -1483,27 +1488,27 @@ void TheoryEngine::staticInitializeBVOptions(const std::vector<Node>& assertions
if (options::produceModels())
throw ModalException("Slicer does not currently support model generation. Use --bv-eq-slicer=off");
useSlicer = true;
-
+
} else if (options::bitvectorEqualitySlicer() == bv::BITVECTOR_SLICER_OFF) {
return;
-
+
} else if (options::bitvectorEqualitySlicer() == bv::BITVECTOR_SLICER_AUTO) {
if (options::incrementalSolving() ||
options::produceModels())
return;
- useSlicer = true;
+ useSlicer = true;
bv::utils::TNodeBoolMap cache;
for (unsigned i = 0; i < assertions.size(); ++i) {
- useSlicer = useSlicer && bv::utils::isCoreTerm(assertions[i], cache);
+ useSlicer = useSlicer && bv::utils::isCoreTerm(assertions[i], cache);
}
}
-
+
if (useSlicer) {
- bv::TheoryBV* bv_theory = (bv::TheoryBV*)d_theoryTable[THEORY_BV];
+ bv::TheoryBV* bv_theory = (bv::TheoryBV*)d_theoryTable[THEORY_BV];
bv_theory->enableCoreTheorySlicer();
}
-
+
}
void TheoryEngine::ppBvToBool(const std::vector<Node>& assertions, std::vector<Node>& new_assertions) {
@@ -1511,12 +1516,12 @@ void TheoryEngine::ppBvToBool(const std::vector<Node>& assertions, std::vector<N
}
bool TheoryEngine::ppBvAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions) {
- bv::TheoryBV* bv_theory = (bv::TheoryBV*)d_theoryTable[THEORY_BV];
- return bv_theory->applyAbstraction(assertions, new_assertions);
+ bv::TheoryBV* bv_theory = (bv::TheoryBV*)d_theoryTable[THEORY_BV];
+ return bv_theory->applyAbstraction(assertions, new_assertions);
}
void TheoryEngine::mkAckermanizationAsssertions(std::vector<Node>& assertions) {
- bv::TheoryBV* bv_theory = (bv::TheoryBV*)d_theoryTable[THEORY_BV];
+ bv::TheoryBV* bv_theory = (bv::TheoryBV*)d_theoryTable[THEORY_BV];
bv_theory->mkAckermanizationAsssertions(assertions);
}
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index 7cb15ca97..0bf00c079 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -269,8 +269,9 @@ class TheoryEngine {
}
}
- void conflict(TNode conflictNode) throw(AssertionException, UnsafeInterruptException) {
+ void conflict(TNode conflictNode, Proof* pf = NULL) throw(AssertionException, UnsafeInterruptException) {
Trace("theory::conflict") << "EngineOutputChannel<" << d_theory << ">::conflict(" << conflictNode << ")" << std::endl;
+ Assert(pf == NULL); // theory shouldn't be producing proofs yet
++ d_statistics.conflicts;
d_engine->d_outputChannelUsed = true;
d_engine->conflict(conflictNode, d_theory);
@@ -283,18 +284,23 @@ class TheoryEngine {
return d_engine->propagate(literal, d_theory);
}
- theory::LemmaStatus lemma(TNode lemma, bool removable = false, bool preprocess = false, bool sendAtoms = false) throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException, LogicException) {
+ theory::LemmaStatus lemma(TNode lemma,
+ ProofRule rule,
+ bool removable = false,
+ bool preprocess = false,
+ bool sendAtoms = false)
+ throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << std::endl;
++ d_statistics.lemmas;
d_engine->d_outputChannelUsed = true;
- return d_engine->lemma(lemma, false, removable, preprocess, sendAtoms ? d_theory : theory::THEORY_LAST);
+ return d_engine->lemma(lemma, rule, false, removable, preprocess, sendAtoms ? d_theory: theory::THEORY_LAST);
}
theory::LemmaStatus splitLemma(TNode lemma, bool removable = false) throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << std::endl;
++ d_statistics.lemmas;
d_engine->d_outputChannelUsed = true;
- return d_engine->lemma(lemma, false, removable, false, d_theory);
+ return d_engine->lemma(lemma, RULE_SPLIT, false, removable, false, d_theory);
}
void demandRestart() throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) {
@@ -304,7 +310,7 @@ class TheoryEngine {
"A boolean variable asserted to be true to force a restart");
Trace("theory::restart") << "EngineOutputChannel<" << d_theory << ">::restart(" << restartVar << ")" << std::endl;
++ d_statistics.restartDemands;
- lemma(restartVar, true);
+ lemma(restartVar, RULE_INVALID, true);
}
void requirePhase(TNode n, bool phase)
@@ -436,7 +442,12 @@ class TheoryEngine {
* @param removable can the lemma be remove (restrictions apply)
* @param needAtoms if not THEORY_LAST, then
*/
- theory::LemmaStatus lemma(TNode node, bool negated, bool removable, bool preprocess, theory::TheoryId atomsTo);
+ theory::LemmaStatus lemma(TNode node,
+ ProofRule rule,
+ bool negated,
+ bool removable,
+ bool preprocess,
+ theory::TheoryId atomsTo);
/** Enusre that the given atoms are send to the given theory */
void ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId theory);
diff --git a/src/theory/theory_test_utils.h b/src/theory/theory_test_utils.h
index f0b616d62..6247833f8 100644
--- a/src/theory/theory_test_utils.h
+++ b/src/theory/theory_test_utils.h
@@ -71,7 +71,7 @@ public:
void safePoint(uint64_t ammount) throw(Interrupted, AssertionException) {}
- void conflict(TNode n)
+ void conflict(TNode n, Proof* pf = NULL)
throw(AssertionException, UnsafeInterruptException) {
push(CONFLICT, n);
}
@@ -87,7 +87,10 @@ public:
push(PROPAGATE_AS_DECISION, n);
}
- LemmaStatus lemma(TNode n, bool removable, bool preprocess, bool sendAtoms) throw(AssertionException, UnsafeInterruptException) {
+ LemmaStatus lemma(TNode n, ProofRule rule,
+ bool removable = false,
+ bool preprocess = false,
+ bool sendAtoms = false) throw(AssertionException, UnsafeInterruptException) {
push(LEMMA, n);
return LemmaStatus(Node::null(), 0);
}
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index 828d53144..8df323992 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -314,10 +314,10 @@ void EqualityEngine::addTermInternal(TNode t, bool isOperator) {
// How many children are not constants yet
d_subtermsToEvaluate[result] = t.getNumChildren();
for (unsigned i = 0; i < t.getNumChildren(); ++ i) {
- if (isConstant(getNodeId(t[i]))) {
- Debug("equality::evaluation") << d_name << "::eq::addTermInternal(" << t << "): evaluates " << t[i] << std::endl;
- subtermEvaluates(result);
- }
+ if (isConstant(getNodeId(t[i]))) {
+ Debug("equality::evaluation") << d_name << "::eq::addTermInternal(" << t << "): evaluates " << t[i] << std::endl;
+ subtermEvaluates(result);
+ }
}
}
} else {
@@ -335,7 +335,7 @@ void EqualityEngine::addTermInternal(TNode t, bool isOperator) {
} else if (d_constantsAreTriggers && d_isConstant[result]) {
// Non-Boolean constants are trigger terms for all tags
EqualityNodeId tId = getNodeId(t);
- // Setup the new set
+ // Setup the new set
Theory::Set newSetTags = 0;
EqualityNodeId newSetTriggers[THEORY_LAST];
unsigned newSetTriggersSize = THEORY_LAST;
@@ -629,12 +629,12 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): " << d_nodes[currentId] << " in " << d_nodes[funId] << std::endl;
const FunctionApplication& fun = d_applications[useNode.getApplicationId()].normalized;
// If it's interpreted and we can interpret
- if (fun.isInterpreted() && class1isConstant && !d_isInternal[currentId]) {
- // Get the actual term id
- TNode term = d_nodes[funId];
- subtermEvaluates(getNodeId(term));
- }
- // Check if there is an application with find arguments
+ if (fun.isInterpreted() && class1isConstant && !d_isInternal[currentId]) {
+ // Get the actual term id
+ TNode term = d_nodes[funId];
+ subtermEvaluates(getNodeId(term));
+ }
+ // Check if there is an application with find arguments
EqualityNodeId aNormalized = getEqualityNode(fun.a).getFind();
EqualityNodeId bNormalized = getEqualityNode(fun.b).getFind();
FunctionApplication funNormalized(fun.type, aNormalized, bNormalized);
@@ -972,7 +972,7 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
// If the nodes are the same, we're done
if (t1Id == t2Id){
if( eqp ) {
- eqp->d_node = d_nodes[t1Id];
+ eqp->d_node = ProofManager::currentPM()->mkOp(d_nodes[t1Id]);
}
return;
}
@@ -1029,6 +1029,7 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
MergeReasonType reasonType = d_equalityEdges[currentEdge].getReasonType();
Debug("equality") << d_name << "::eq::getExplanation(): currentEdge = " << currentEdge << ", currentNode = " << currentNode << std::endl;
+ Debug("equality") << d_name << " in currentEdge = (" << d_nodes[currentNode] << "," << d_nodes[edge.getNodeId()] << ")" << std::endl;
EqProof * eqpc = NULL;
//make child proof if a proof is being constructed
@@ -1051,6 +1052,20 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
if( eqpc ){
eqpc->d_children.push_back( eqpc1 );
eqpc->d_children.push_back( eqpc2 );
+ Debug("equality-pf") << "Congruence : " << d_nodes[currentNode] << " " << d_nodes[edgeNode] << std::endl;
+ if( d_nodes[currentNode].getKind()==kind::EQUAL ){
+ //leave node null for now
+ eqpc->d_node = Node::null();
+ }else{
+ Debug("equality-pf") << d_nodes[f1.a] << " / " << d_nodes[f2.a] << ", " << d_nodes[f1.b] << " / " << d_nodes[f2.b] << std::endl;
+ if(d_nodes[f1.a].getKind() == kind::APPLY_UF ||
+ d_nodes[f1.a].getKind() == kind::SELECT ||
+ d_nodes[f1.a].getKind() == kind::STORE) {
+ eqpc->d_node = d_nodes[f1.a];
+ } else {
+ eqpc->d_node = NodeManager::currentNM()->mkNode(kind::PARTIAL_APPLY_UF, ProofManager::currentPM()->mkOp(d_nodes[f1.a]), d_nodes[f1.b]);
+ }
+ }
}
Debug("equality") << pop;
break;
@@ -1103,13 +1118,14 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
// Construct the equality
Debug("equality") << d_name << "::eq::getExplanation(): adding: " << d_equalityEdges[currentEdge].getReason() << std::endl;
if( eqpc ){
- if( reasonType==MERGED_THROUGH_EQUALITY ){
+ if(reasonType == MERGED_THROUGH_EQUALITY) {
eqpc->d_node = d_equalityEdges[currentEdge].getReason();
- }else{
- //theory-specific proof rule : TODO
- eqpc->d_id = reasonType;
- //eqpc->d_node = d_equalityEdges[currentEdge].getNodeId();
+ } else {
+ // theory-specific proof rule
+ eqpc->d_node = d_nodes[d_equalityEdges[currentEdge].getNodeId()].eqNode(d_nodes[currentNode]);
+ Debug("equality-pf") << "theory eq : " << eqpc->d_node << std::endl;
}
+ eqpc->d_id = reasonType;
}
equalities.push_back(d_equalityEdges[currentEdge].getReason());
break;
@@ -1120,13 +1136,32 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
currentEdge = bfsQueue[currentIndex].edgeId;
currentIndex = bfsQueue[currentIndex].previousIndex;
+ //---from Morgan---
+ if(eqpc != NULL && eqpc->d_id == MERGED_THROUGH_REFLEXIVITY) {
+ if(eqpc->d_node.isNull()) {
+ Assert(eqpc->d_children.size() == 1);
+ EqProof *p = eqpc;
+ eqpc = p->d_children[0];
+ delete p;
+ } else {
+ Assert(eqpc->d_children.empty());
+ }
+ }
+ //---end from Morgan---
+
eqp_trans.push_back( eqpc );
} while (currentEdge != null_id);
- if( eqp ){
- eqp->d_id = MERGED_THROUGH_TRANS;
- eqp->d_children.insert( eqp->d_children.end(), eqp_trans.begin(), eqp_trans.end() );
+ if(eqp) {
+ if(eqp_trans.size() == 1) {
+ *eqp = *eqp_trans[0];
+ delete eqp_trans[0];
+ } else {
+ eqp->d_id = MERGED_THROUGH_TRANS;
+ eqp->d_children.insert( eqp->d_children.end(), eqp_trans.begin(), eqp_trans.end() );
+ eqp->d_node = NodeManager::currentNM()->mkNode(d_nodes[t1Id].getType().isBoolean() ? kind::IFF : kind::EQUAL, d_nodes[t1Id], d_nodes[t2Id]);
+ }
}
// Done
@@ -2057,8 +2092,7 @@ bool EqClassIterator::isFinished() const {
return d_current == null_id;
}
-
-void EqProof::debug_print( const char * c, unsigned tb ){
+void EqProof::debug_print( const char * c, unsigned tb ) const{
for( unsigned i=0; i<tb; i++ ) { Debug( c ) << " "; }
Debug( c ) << d_id << "(";
if( !d_children.empty() || !d_node.isNull() ){
diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h
index 87074aebc..9cfa16adf 100644
--- a/src/theory/uf/equality_engine.h
+++ b/src/theory/uf/equality_engine.h
@@ -879,8 +879,8 @@ public:
MergeReasonType d_id;
Node d_node;
std::vector< EqProof * > d_children;
- void debug_print( const char * c, unsigned tb = 0 );
-};
+ void debug_print( const char * c, unsigned tb = 0 ) const;
+};/* class EqProof */
} // Namespace eq
} // Namespace theory
diff --git a/src/theory/uf/kinds b/src/theory/uf/kinds
index f0b50b778..888fa140f 100644
--- a/src/theory/uf/kinds
+++ b/src/theory/uf/kinds
@@ -21,6 +21,9 @@ typerule CARDINALITY_CONSTRAINT ::CVC4::theory::uf::CardinalityConstraintTypeRul
operator COMBINED_CARDINALITY_CONSTRAINT 1 "combined cardinality constraint; parameter is a positive integer constant k that bounds the sum of the cardinalities of all sorts in the signature"
typerule COMBINED_CARDINALITY_CONSTRAINT ::CVC4::theory::uf::CombinedCardinalityConstraintTypeRule
+parameterized PARTIAL_APPLY_UF APPLY_UF 1: "partial uninterpreted function application"
+typerule PARTIAL_APPLY_UF ::CVC4::theory::uf::PartialTypeRule
+
operator CARDINALITY_VALUE 1 "cardinality value of sort S: first parameter is (any) term of sort S"
typerule CARDINALITY_VALUE ::CVC4::theory::uf::CardinalityValueTypeRule
diff --git a/src/theory/uf/symmetry_breaker.cpp b/src/theory/uf/symmetry_breaker.cpp
index d5e18ed14..4f7a2667c 100644
--- a/src/theory/uf/symmetry_breaker.cpp
+++ b/src/theory/uf/symmetry_breaker.cpp
@@ -167,7 +167,8 @@ void SymmetryBreaker::Template::reset() {
d_reps.clear();
}
-SymmetryBreaker::SymmetryBreaker(context::Context* context) :
+SymmetryBreaker::SymmetryBreaker(context::Context* context,
+ std::string name) :
ContextNotifyObj(context),
d_assertionsToRerun(context),
d_rerunningAssertions(false),
@@ -178,7 +179,10 @@ SymmetryBreaker::SymmetryBreaker(context::Context* context) :
d_template(),
d_normalizationCache(),
d_termEqs(),
- d_termEqsOnly() {
+ d_termEqsOnly(),
+ d_name(name),
+ d_stats(d_name)
+{
}
class SBGuard {
@@ -461,7 +465,7 @@ void SymmetryBreaker::apply(std::vector<Node>& newClauses) {
Debug("ufsymm") << "UFSYMM =====================================================" << endl
<< "UFSYMM have " << d_permutations.size() << " permutation sets" << endl;
if(!d_permutations.empty()) {
- { TimerStat::CodeTimer codeTimer(d_initNormalizationTimer);
+ { TimerStat::CodeTimer codeTimer(d_stats.d_initNormalizationTimer);
// normalize d_phi
for(vector<Node>::iterator i = d_phi.begin(); i != d_phi.end(); ++i) {
@@ -476,12 +480,12 @@ void SymmetryBreaker::apply(std::vector<Node>& newClauses) {
for(Permutations::iterator i = d_permutations.begin();
i != d_permutations.end();
++i) {
- ++d_permutationSetsConsidered;
+ ++(d_stats.d_permutationSetsConsidered);
const Permutation& p = *i;
Debug("ufsymm") << "UFSYMM looking at permutation: " << p << endl;
size_t n = p.size() - 1;
if(invariantByPermutations(p)) {
- ++d_permutationSetsInvariant;
+ ++(d_stats.d_permutationSetsInvariant);
selectTerms(p);
set<Node> cts;
while(!d_terms.empty() && cts.size() <= n) {
@@ -539,11 +543,11 @@ void SymmetryBreaker::apply(std::vector<Node>& newClauses) {
Node d;
if(disj.getNumChildren() > 1) {
d = disj;
- ++d_clauses;
+ ++(d_stats.d_clauses);
} else {
d = disj[0];
disj.clear();
- ++d_units;
+ ++(d_stats.d_units);
}
if(Debug.isOn("ufsymm")) {
Debug("ufsymm") << "UFSYMM symmetry-breaking clause: " << d << endl;
@@ -569,7 +573,7 @@ void SymmetryBreaker::guessPermutations() {
}
bool SymmetryBreaker::invariantByPermutations(const Permutation& p) {
- TimerStat::CodeTimer codeTimer(d_invariantByPermutationsTimer);
+ TimerStat::CodeTimer codeTimer(d_stats.d_invariantByPermutationsTimer);
// use d_phi
Debug("ufsymm") << "UFSYMM invariantByPermutations()? " << p << endl;
@@ -681,7 +685,7 @@ static bool isSubset(const T1& s, const T2& t) {
}
void SymmetryBreaker::selectTerms(const Permutation& p) {
- TimerStat::CodeTimer codeTimer(d_selectTermsTimer);
+ TimerStat::CodeTimer codeTimer(d_stats.d_selectTermsTimer);
// use d_phi, put into d_terms
Debug("ufsymm") << "UFSYMM selectTerms(): " << p << endl;
@@ -733,6 +737,35 @@ void SymmetryBreaker::selectTerms(const Permutation& p) {
}
}
+SymmetryBreaker::Statistics::Statistics(std::string name)
+ : d_clauses(name + "theory::uf::symmetry_breaker::clauses", 0)
+ , d_units(name + "theory::uf::symmetry_breaker::units", 0)
+ , d_permutationSetsConsidered(name + "theory::uf::symmetry_breaker::permutationSetsConsidered", 0)
+ , d_permutationSetsInvariant(name + "theory::uf::symmetry_breaker::permutationSetsInvariant", 0)
+ , d_invariantByPermutationsTimer(name + "theory::uf::symmetry_breaker::timers::invariantByPermutations")
+ , d_selectTermsTimer(name + "theory::uf::symmetry_breaker::timers::selectTerms")
+ , d_initNormalizationTimer(name + "theory::uf::symmetry_breaker::timers::initNormalization")
+{
+ smtStatisticsRegistry()->registerStat(&d_clauses);
+ smtStatisticsRegistry()->registerStat(&d_units);
+ smtStatisticsRegistry()->registerStat(&d_permutationSetsConsidered);
+ smtStatisticsRegistry()->registerStat(&d_permutationSetsInvariant);
+ smtStatisticsRegistry()->registerStat(&d_invariantByPermutationsTimer);
+ smtStatisticsRegistry()->registerStat(&d_selectTermsTimer);
+ smtStatisticsRegistry()->registerStat(&d_initNormalizationTimer);
+}
+
+SymmetryBreaker::Statistics::~Statistics()
+{
+ smtStatisticsRegistry()->unregisterStat(&d_clauses);
+ smtStatisticsRegistry()->unregisterStat(&d_units);
+ smtStatisticsRegistry()->unregisterStat(&d_permutationSetsConsidered);
+ smtStatisticsRegistry()->unregisterStat(&d_permutationSetsInvariant);
+ smtStatisticsRegistry()->unregisterStat(&d_invariantByPermutationsTimer);
+ smtStatisticsRegistry()->unregisterStat(&d_selectTermsTimer);
+ smtStatisticsRegistry()->unregisterStat(&d_initNormalizationTimer);
+}
+
SymmetryBreaker::Terms::iterator
SymmetryBreaker::selectMostPromisingTerm(Terms& terms) {
// use d_phi
diff --git a/src/theory/uf/symmetry_breaker.h b/src/theory/uf/symmetry_breaker.h
index 763ced650..5523c1c0d 100644
--- a/src/theory/uf/symmetry_breaker.h
+++ b/src/theory/uf/symmetry_breaker.h
@@ -128,35 +128,30 @@ private:
Node normInternal(TNode phi, size_t level);
Node norm(TNode n);
+ std::string d_name;
+
// === STATISTICS ===
/** number of new clauses that come from the SymmetryBreaker */
- KEEP_STATISTIC(IntStat,
- d_clauses,
- "theory::uf::symmetry_breaker::clauses", 0);
- /** number of new clauses that come from the SymmetryBreaker */
- KEEP_STATISTIC(IntStat,
- d_units,
- "theory::uf::symmetry_breaker::units", 0);
- /** number of potential permutation sets we found */
- KEEP_STATISTIC(IntStat,
- d_permutationSetsConsidered,
- "theory::uf::symmetry_breaker::permutationSetsConsidered", 0);
- /** number of invariant permutation sets we found */
- KEEP_STATISTIC(IntStat,
- d_permutationSetsInvariant,
- "theory::uf::symmetry_breaker::permutationSetsInvariant", 0);
- /** time spent in invariantByPermutations() */
- KEEP_STATISTIC(TimerStat,
- d_invariantByPermutationsTimer,
- "theory::uf::symmetry_breaker::timers::invariantByPermutations");
- /** time spent in selectTerms() */
- KEEP_STATISTIC(TimerStat,
- d_selectTermsTimer,
- "theory::uf::symmetry_breaker::timers::selectTerms");
- /** time spent in initial round of normalization */
- KEEP_STATISTIC(TimerStat,
- d_initNormalizationTimer,
- "theory::uf::symmetry_breaker::timers::initNormalization");
+ struct Statistics {
+ /** number of new clauses that come from the SymmetryBreaker */
+ IntStat d_clauses;
+ IntStat d_units;
+ /** number of potential permutation sets we found */
+ IntStat d_permutationSetsConsidered;
+ /** number of invariant permutation sets we found */
+ IntStat d_permutationSetsInvariant;
+ /** time spent in invariantByPermutations() */
+ TimerStat d_invariantByPermutationsTimer;
+ /** time spent in selectTerms() */
+ TimerStat d_selectTermsTimer;
+ /** time spent in initial round of normalization */
+ TimerStat d_initNormalizationTimer;
+
+ Statistics(std::string name);
+ ~Statistics();
+ };
+
+ Statistics d_stats;
protected:
@@ -167,7 +162,7 @@ protected:
public:
- SymmetryBreaker(context::Context* context);
+ SymmetryBreaker(context::Context* context, std::string name = "");
~SymmetryBreaker() throw() {}
void assertFormula(TNode phi);
void apply(std::vector<Node>& newClauses);
diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp
index e21b7ef7d..93a920f82 100644
--- a/src/theory/uf/theory_uf.cpp
+++ b/src/theory/uf/theory_uf.cpp
@@ -20,30 +20,34 @@
#include "options/quantifiers_options.h"
#include "options/smt_options.h"
#include "options/uf_options.h"
+#include "proof/proof_manager.h"
+#include "proof/theory_proof.h"
+#include "proof/uf_proof.h"
#include "theory/theory_model.h"
#include "theory/type_enumerator.h"
#include "theory/uf/theory_uf_strong_solver.h"
using namespace std;
-using namespace CVC4;
-using namespace CVC4::theory;
-using namespace CVC4::theory::uf;
+
+namespace CVC4 {
+namespace theory {
+namespace uf {
/** Constructs a new instance of TheoryUF w.r.t. the provided context.*/
TheoryUF::TheoryUF(context::Context* c, context::UserContext* u,
OutputChannel& out, Valuation valuation,
- const LogicInfo& logicInfo, SmtGlobals* globals)
- : Theory(THEORY_UF, c, u, out, valuation, logicInfo, globals),
+ const LogicInfo& logicInfo, SmtGlobals* globals, std::string name)
+ : Theory(THEORY_UF, c, u, out, valuation, logicInfo, globals, name),
d_notify(*this),
/* The strong theory solver can be notified by EqualityEngine::init(),
* so make sure it's initialized first. */
d_thss(NULL),
- d_equalityEngine(d_notify, c, "theory::uf::TheoryUF", true),
+ d_equalityEngine(d_notify, c, name + "theory::uf::TheoryUF", true),
d_conflict(c, false),
d_literalsToPropagate(c),
d_literalsToPropagateIndex(c, 0),
d_functionsTerms(c),
- d_symb(u)
+ d_symb(u, name)
{
// The kinds we are treating as function application in congruence
d_equalityEngine.addFunctionKind(kind::APPLY_UF);
@@ -204,27 +208,29 @@ Node TheoryUF::getNextDecisionRequest(){
}
}
-void TheoryUF::explain(TNode literal, std::vector<TNode>& assumptions) {
+void TheoryUF::explain(TNode literal, std::vector<TNode>& assumptions, eq::EqProof* pf) {
// Do the work
bool polarity = literal.getKind() != kind::NOT;
TNode atom = polarity ? literal : literal[0];
- eq::EqProof * eqp = d_proofEnabled ? new eq::EqProof : NULL;
if (atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) {
- d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions, eqp);
+ d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions, pf);
} else {
- d_equalityEngine.explainPredicate(atom, polarity, assumptions, eqp);
+ d_equalityEngine.explainPredicate(atom, polarity, assumptions, pf);
}
- //for now, just print debug
- //TODO : send the proof outwards : d_out->conflict( lem, eqp );
- if( eqp ){
- eqp->debug_print("uf-pf");
+ if( pf ){
+ Debug("uf-pf") << std::endl;
+ pf->debug_print("uf-pf");
}
}
Node TheoryUF::explain(TNode literal) {
+ return explain(literal, NULL);
+}
+
+Node TheoryUF::explain(TNode literal, eq::EqProof* pf) {
Debug("uf") << "TheoryUF::explain(" << literal << ")" << std::endl;
std::vector<TNode> assumptions;
- explain(literal, assumptions);
+ explain(literal, assumptions, pf);
return mkAnd(assumptions);
}
@@ -508,13 +514,14 @@ void TheoryUF::computeCareGraph() {
}/* TheoryUF::computeCareGraph() */
void TheoryUF::conflict(TNode a, TNode b) {
- //TODO: create EqProof at this level if d_proofEnabled = true
+ eq::EqProof* pf = d_proofsEnabled ? new eq::EqProof() : NULL;
if (a.getKind() == kind::CONST_BOOLEAN) {
- d_conflictNode = explain(a.iffNode(b));
+ d_conflictNode = explain(a.iffNode(b),pf);
} else {
- d_conflictNode = explain(a.eqNode(b));
+ d_conflictNode = explain(a.eqNode(b),pf);
}
- d_out->conflict(d_conflictNode);
+ ProofUF * puf = d_proofsEnabled ? new ProofUF( pf ) : NULL;
+ d_out->conflict(d_conflictNode, puf);
d_conflict = true;
}
@@ -541,3 +548,8 @@ void TheoryUF::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
d_thss->assertDisequal(t1, t2, reason);
}
}
+
+
+} /* namespace CVC4::theory::uf */
+} /* namespace CVC4::theory */
+} /* namespace CVC4 */
diff --git a/src/theory/uf/theory_uf.h b/src/theory/uf/theory_uf.h
index aff78f53d..bd0016be7 100644
--- a/src/theory/uf/theory_uf.h
+++ b/src/theory/uf/theory_uf.h
@@ -128,9 +128,15 @@ private:
/**
* Explain why this literal is true by adding assumptions
+ * with proof (if "pf" is non-NULL).
*/
- void explain(TNode literal, std::vector<TNode>& assumptions);
+ void explain(TNode literal, std::vector<TNode>& assumptions, eq::EqProof* pf);
+ /**
+ * Explain a literal, with proof (if "pf" is non-NULL).
+ */
+ Node explain(TNode literal, eq::EqProof* pf);
+
/** Literals to propagate */
context::CDList<Node> d_literalsToPropagate;
@@ -163,7 +169,7 @@ public:
/** Constructs a new instance of TheoryUF w.r.t. the provided context.*/
TheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out,
Valuation valuation, const LogicInfo& logicInfo,
- SmtGlobals* globals);
+ SmtGlobals* globals, std::string name = "");
~TheoryUF();
diff --git a/src/theory/uf/theory_uf_type_rules.h b/src/theory/uf/theory_uf_type_rules.h
index 6faab8517..05b95e9e1 100644
--- a/src/theory/uf/theory_uf_type_rules.h
+++ b/src/theory/uf/theory_uf_type_rules.h
@@ -107,6 +107,14 @@ public:
}
};/* class CardinalityConstraintTypeRule */
+class PartialTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ return n.getOperator().getType().getRangeType();
+ }
+};/* class PartialTypeRule */
+
class CardinalityValueTypeRule {
public:
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback