diff options
Diffstat (limited to 'src')
141 files changed, 1190 insertions, 17019 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 052479624..7a383d0c8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -118,50 +118,13 @@ libcvc4_add_sources( printer/smt2/smt2_printer.h printer/tptp/tptp_printer.cpp printer/tptp/tptp_printer.h - proof/arith_proof.cpp - proof/arith_proof.h - proof/arith_proof_recorder.cpp - proof/arith_proof_recorder.h - proof/array_proof.cpp - proof/array_proof.h - proof/bitvector_proof.cpp - proof/bitvector_proof.h - proof/clausal_bitvector_proof.cpp - proof/clausal_bitvector_proof.h proof/clause_id.h proof/cnf_proof.cpp proof/cnf_proof.h - proof/dimacs.cpp - proof/dimacs.h - proof/drat/drat_proof.cpp - proof/drat/drat_proof.h - proof/er/er_proof.cpp - proof/er/er_proof.h - proof/lemma_proof.cpp - proof/lemma_proof.h - proof/lfsc_proof_printer.cpp - proof/lfsc_proof_printer.h - proof/lrat/lrat_proof.cpp - proof/lrat/lrat_proof.h - proof/proof.h proof/proof_manager.cpp proof/proof_manager.h - proof/proof_output_channel.cpp - proof/proof_output_channel.h - proof/proof_utils.cpp - proof/proof_utils.h - proof/resolution_bitvector_proof.cpp - proof/resolution_bitvector_proof.h proof/sat_proof.h proof/sat_proof_implementation.h - proof/simplify_boolean_node.cpp - proof/simplify_boolean_node.h - proof/skolemization_manager.cpp - proof/skolemization_manager.h - proof/theory_proof.cpp - proof/theory_proof.h - proof/uf_proof.cpp - proof/uf_proof.h proof/unsat_core.cpp proof/unsat_core.h prop/bvminisat/bvminisat.cpp @@ -387,8 +350,6 @@ libcvc4_add_sources( theory/arith/type_enumerator.h theory/arrays/array_info.cpp theory/arrays/array_info.h - theory/arrays/array_proof_reconstruction.cpp - theory/arrays/array_proof_reconstruction.h theory/arrays/static_fact_manager.cpp theory/arrays/static_fact_manager.h theory/arrays/theory_arrays.cpp @@ -1102,7 +1063,6 @@ install(FILES util/integer_gmp_imp.h util/maybe.h util/poly_util.h - util/proof.h util/rational_cln_imp.h util/rational_gmp_imp.h util/real_algebraic_number_poly_imp.h diff --git a/src/options/bv_options.toml b/src/options/bv_options.toml index 7c0aca100..e00db9393 100644 --- a/src/options/bv_options.toml +++ b/src/options/bv_options.toml @@ -3,44 +3,6 @@ name = "Bitvector theory" header = "options/bv_options.h" [[option]] - name = "bvProofFormat" - category = "expert" - long = "bv-proof-format=MODE" - type = "BvProofFormat" - default = "ER" - predicates = ["checkSatSolverEnabled<BvProofFormat>"] - help = "choose which UNSAT proof format to use, see --bv-sat-solver=help" - help_mode = "Bit-vector proof formats." -[[option.mode.ER]] - name = "er" - help = "Extended Resolution, i.e. resolution with new variable definitions." -[[option.mode.DRAT]] - name = "drat" - help = "Deletion and Resolution Asymmetric Tautology Additions." -[[option.mode.LRAT]] - name = "lrat" - help = "DRAT with unit propagation hints to accelerate checking." - -[[option]] - name = "bvOptimizeSatProof" - category = "expert" - long = "bv-optimize-sat-proof=MODE" - type = "BvOptimizeSatProof" - default = "FORMULA" - predicates = ["checkSatSolverEnabled<BvOptimizeSatProof>"] - help = "enable SAT proof optimizations, see --bv-optimize-sat-proof=help" - help_mode = "SAT proof optimization level." -[[option.mode.NONE]] - name = "none" - help = "Do not optimize the SAT proof." -[[option.mode.PROOF]] - name = "proof" - help = "Use drat-trim to shrink the SAT proof." -[[option.mode.FORMULA]] - name = "formula" - help = "Use drat-trim to shrink the SAT proof and formula." - -[[option]] name = "bvSatSolver" smt_name = "bv-sat-solver" category = "expert" diff --git a/src/options/options.h b/src/options/options.h index 44f4be7b4..abcf21264 100644 --- a/src/options/options.h +++ b/src/options/options.h @@ -150,7 +150,6 @@ public: options::InstFormatMode getInstFormatMode() const; OutputLanguage getOutputLanguage() const; bool getUfHo() const; - bool getCheckProofs() const; bool getDumpInstantiations() const; bool getDumpModels() const; bool getDumpProofs() const; @@ -167,7 +166,6 @@ public: bool getMemoryMap() const; bool getParseOnly() const; bool getProduceModels() const; - bool getProof() const; bool getSegvSpin() const; bool getSemanticChecks() const; bool getStatistics() const; diff --git a/src/options/options_public_functions.cpp b/src/options/options_public_functions.cpp index c8104c584..2dc28b10d 100644 --- a/src/options/options_public_functions.cpp +++ b/src/options/options_public_functions.cpp @@ -54,10 +54,6 @@ OutputLanguage Options::getOutputLanguage() const { bool Options::getUfHo() const { return (*this)[options::ufHo]; } -bool Options::getCheckProofs() const{ - return (*this)[options::checkProofs]; -} - bool Options::getDumpInstantiations() const{ return (*this)[options::dumpInstantiations]; } @@ -124,10 +120,6 @@ bool Options::getProduceModels() const{ return (*this)[options::produceModels]; } -bool Options::getProof() const{ - return (*this)[options::proof]; -} - bool Options::getSegvSpin() const{ return (*this)[options::segvSpin]; } diff --git a/src/options/proof_options.toml b/src/options/proof_options.toml index a23241e3d..9db541e27 100644 --- a/src/options/proof_options.toml +++ b/src/options/proof_options.toml @@ -1,38 +1,3 @@ id = "PROOF" name = "Proof" header = "options/proof_options.h" - -[[option]] - name = "lfscLetification" - category = "regular" - long = "lfsc-letification" - type = "bool" - default = "true" - read_only = true - help = "turns on global letification in LFSC proofs" - -[[option]] - name = "aggressiveCoreMin" - category = "regular" - long = "aggressive-core-min" - type = "bool" - default = "false" - read_only = true - help = "turns on aggressive unsat core minimization (experimental)" - -[[option]] - name = "fewerPreprocessingHoles" - category = "regular" - long = "fewer-preprocessing-holes" - type = "bool" - default = "false" - help = "try to eliminate preprocessing holes in proofs" - -[[option]] - name = "allowEmptyDependencies" - category = "regular" - long = "allow-empty-dependencies" - type = "bool" - default = "false" - read_only = true - help = "if unable to track the dependencies of a rewritten/preprocessed assertion, fail silently" diff --git a/src/options/smt_options.toml b/src/options/smt_options.toml index 6b5bee6bb..2c87158de 100644 --- a/src/options/smt_options.toml +++ b/src/options/smt_options.toml @@ -131,24 +131,6 @@ header = "options/smt_options.h" help = "Block models based on the concrete model values for the free variables." [[option]] - name = "proof" - smt_name = "produce-proofs" - category = "regular" - long = "proof" - type = "bool" - default = "false" - predicates = ["proofEnabledBuild"] - help = "turn on proof generation" - -[[option]] - name = "checkProofs" - category = "regular" - long = "check-proofs" - type = "bool" - predicates = ["LFSCEnabledBuild"] - help = "after UNSAT/VALID, machine-check the generated proof" - -[[option]] name = "dumpProofs" category = "regular" long = "dump-proofs" @@ -390,7 +372,7 @@ header = "options/smt_options.h" type = "bool" default = "false" help = "calculate sort inference of input problem, convert the input based on monotonic sorts" - + [[option]] name = "incrementalSolving" category = "common" @@ -660,7 +642,7 @@ header = "options/smt_options.h" [[option.mode.BITWISE]] name = "bitwise" help = "use bitwise comparisons on binary representation of integer for refinement (experimental)" - + [[option]] name = "solveIntAsBV" category = "undocumented" diff --git a/src/preprocessing/assertion_pipeline.cpp b/src/preprocessing/assertion_pipeline.cpp index a6b9531b6..a9e2d4d36 100644 --- a/src/preprocessing/assertion_pipeline.cpp +++ b/src/preprocessing/assertion_pipeline.cpp @@ -16,7 +16,7 @@ #include "preprocessing/assertion_pipeline.h" #include "expr/node_manager.h" -#include "proof/proof.h" +#include "options/smt_options.h" #include "proof/proof_manager.h" #include "theory/rewriter.h" @@ -77,7 +77,10 @@ void AssertionPipeline::pushBackTrusted(theory::TrustNode trn) void AssertionPipeline::replace(size_t i, Node n, ProofGenerator* pgen) { - PROOF(ProofManager::currentPM()->addDependence(n, d_nodes[i]);); + if (options::unsatCores()) + { + ProofManager::currentPM()->addDependence(n, d_nodes[i]); + } if (isProofEnabled()) { d_pppg->notifyPreprocessed(d_nodes[i], n, pgen); @@ -96,11 +99,14 @@ void AssertionPipeline::replace(size_t i, const std::vector<Node>& addnDeps, ProofGenerator* pgen) { - PROOF(ProofManager::currentPM()->addDependence(n, d_nodes[i]); - for (const auto& addnDep - : addnDeps) { - ProofManager::currentPM()->addDependence(n, addnDep); - }); + if (options::unsatCores()) + { + ProofManager::currentPM()->addDependence(n, d_nodes[i]); + for (const auto& addnDep : addnDeps) + { + ProofManager::currentPM()->addDependence(n, addnDep); + } + } if (isProofEnabled()) { d_pppg->notifyPreprocessed(d_nodes[i], n, pgen); diff --git a/src/preprocessing/passes/ite_simp.cpp b/src/preprocessing/passes/ite_simp.cpp index 9a6a8ec61..388c5742d 100644 --- a/src/preprocessing/passes/ite_simp.cpp +++ b/src/preprocessing/passes/ite_simp.cpp @@ -16,7 +16,6 @@ #include <vector> -#include "options/proof_options.h" #include "smt/smt_statistics_registry.h" #include "smt_util/nary_builder.h" #include "theory/arith/arith_ite_utils.h" @@ -118,7 +117,7 @@ bool ITESimp::doneSimpITE(AssertionPipeline* assertionsToPreprocess) // This pass does not support dependency tracking yet // (learns substitutions from all assertions so just // adding addDependence is not enough) - if (options::unsatCores() || options::fewerPreprocessingHoles()) + if (options::unsatCores()) { return true; } diff --git a/src/preprocessing/passes/miplib_trick.cpp b/src/preprocessing/passes/miplib_trick.cpp index f64fce118..3a8bbdb70 100644 --- a/src/preprocessing/passes/miplib_trick.cpp +++ b/src/preprocessing/passes/miplib_trick.cpp @@ -522,8 +522,10 @@ PreprocessingPassResult MipLibTrick::applyInternal( Node n = Rewriter::rewrite(geq.andNode(leq)); assertionsToPreprocess->push_back(n); - PROOF(ProofManager::currentPM()->addDependence(n, Node::null())); - + if (options::unsatCores()) + { + ProofManager::currentPM()->addDependence(n, Node::null()); + } SubstitutionMap nullMap(&fakeContext); Theory::PPAssertStatus status CVC4_UNUSED; // just for assertions status = te->solve(geq, nullMap); @@ -591,9 +593,11 @@ PreprocessingPassResult MipLibTrick::applyInternal( Debug("miplib") << " " << newAssertion << endl; assertionsToPreprocess->push_back(newAssertion); - PROOF(ProofManager::currentPM()->addDependence(newAssertion, - Node::null())); - + if (options::unsatCores()) + { + ProofManager::currentPM()->addDependence(newAssertion, + Node::null()); + } Debug("miplib") << " assertions to remove: " << endl; for (vector<TNode>::const_iterator k = asserts[pos_var].begin(), k_end = asserts[pos_var].end(); diff --git a/src/preprocessing/passes/non_clausal_simp.cpp b/src/preprocessing/passes/non_clausal_simp.cpp index 6d2482a0e..24c1ac67b 100644 --- a/src/preprocessing/passes/non_clausal_simp.cpp +++ b/src/preprocessing/passes/non_clausal_simp.cpp @@ -19,7 +19,6 @@ #include <vector> #include "context/cdo.h" -#include "options/proof_options.h" #include "smt/smt_statistics_registry.h" #include "theory/theory_model.h" @@ -54,7 +53,7 @@ NonClausalSimp::NonClausalSimp(PreprocessingPassContext* preprocContext) PreprocessingPassResult NonClausalSimp::applyInternal( AssertionPipeline* assertionsToPreprocess) { - Assert(!options::unsatCores() && !options::fewerPreprocessingHoles()); + Assert(!options::unsatCores()); d_preprocContext->spendResource(ResourceManager::Resource::PreprocessStep); @@ -98,11 +97,14 @@ PreprocessingPassResult NonClausalSimp::applyInternal( // If in conflict, just return false Trace("non-clausal-simplify") << "conflict in non-clausal propagation" << std::endl; - Assert(!options::unsatCores() && !options::fewerPreprocessingHoles()); + Assert(!options::unsatCores()); assertionsToPreprocess->clear(); Node n = NodeManager::currentNM()->mkConst<bool>(false); assertionsToPreprocess->push_back(n); - PROOF(ProofManager::currentPM()->addDependence(n, Node::null())); + if (options::unsatCores()) + { + ProofManager::currentPM()->addDependence(n, Node::null()); + } propagator->setNeedsFinish(true); return PreprocessingPassResult::CONFLICT; } @@ -164,7 +166,10 @@ PreprocessingPassResult NonClausalSimp::applyInternal( assertionsToPreprocess->clear(); Node n = NodeManager::currentNM()->mkConst<bool>(false); assertionsToPreprocess->push_back(n); - PROOF(ProofManager::currentPM()->addDependence(n, Node::null())); + if (options::unsatCores()) + { + ProofManager::currentPM()->addDependence(n, Node::null()); + } propagator->setNeedsFinish(true); return PreprocessingPassResult::CONFLICT; } @@ -207,7 +212,10 @@ PreprocessingPassResult NonClausalSimp::applyInternal( assertionsToPreprocess->clear(); Node n = NodeManager::currentNM()->mkConst<bool>(false); assertionsToPreprocess->push_back(n); - PROOF(ProofManager::currentPM()->addDependence(n, Node::null())); + if (options::unsatCores()) + { + ProofManager::currentPM()->addDependence(n, Node::null()); + } propagator->setNeedsFinish(true); return PreprocessingPassResult::CONFLICT; } @@ -241,7 +249,6 @@ PreprocessingPassResult NonClausalSimp::applyInternal( // equations[0].second); assertionsToPreprocess->clear(); // Node n = NodeManager::currentNM()->mkConst<bool>(false); // assertionsToPreprocess->push_back(n); - // PROOF(ProofManager::currentPM()->addDependence(n, Node::null())); // false); return; // } // top_level_substs.simplifyRHS(constantPropagations); diff --git a/src/preprocessing/passes/quantifier_macros.cpp b/src/preprocessing/passes/quantifier_macros.cpp index a4d8454a0..f4bc43542 100644 --- a/src/preprocessing/passes/quantifier_macros.cpp +++ b/src/preprocessing/passes/quantifier_macros.cpp @@ -19,7 +19,6 @@ #include <vector> #include "options/quantifiers_options.h" -#include "proof/proof_manager.h" #include "smt/smt_engine.h" #include "smt/smt_engine_scope.h" #include "theory/arith/arith_msum.h" @@ -79,11 +78,14 @@ bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite for( int i=0; i<(int)assertions.size(); i++ ){ Trace("macros-debug") << " process assertion " << assertions[i] << std::endl; if( processAssertion( assertions[i] ) ){ - PROOF( - if( std::find( macro_assertions.begin(), macro_assertions.end(), assertions[i] )==macro_assertions.end() ){ - macro_assertions.push_back( assertions[i] ); - } - ); + if (options::unsatCores() + && std::find(macro_assertions.begin(), + macro_assertions.end(), + assertions[i]) + == macro_assertions.end()) + { + macro_assertions.push_back(assertions[i]); + } //process this assertion again i--; } @@ -98,17 +100,22 @@ bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite if( curr!=assertions[i] ){ curr = Rewriter::rewrite( curr ); Trace("macros-rewrite") << "Rewrite " << assertions[i] << " to " << curr << std::endl; - //for now, it is dependent upon all assertions involving macros, this is an over-approximation. - //a more fine-grained unsat core computation would require caching dependencies for each subterm of the formula, - // which is expensive. - PROOF(ProofManager::currentPM()->addDependence(curr, assertions[i]); - for (unsigned j = 0; j < macro_assertions.size(); j++) { - if (macro_assertions[j] != assertions[i]) - { - ProofManager::currentPM()->addDependence( - curr, macro_assertions[j]); - } - }); + // for now, it is dependent upon all assertions involving macros, this + // is an over-approximation. a more fine-grained unsat core + // computation would require caching dependencies for each subterm of + // the formula, which is expensive. + if (options::unsatCores()) + { + ProofManager::currentPM()->addDependence(curr, assertions[i]); + for (unsigned j = 0; j < macro_assertions.size(); j++) + { + if (macro_assertions[j] != assertions[i]) + { + ProofManager::currentPM()->addDependence(curr, + macro_assertions[j]); + } + } + } assertions[i] = curr; retVal = true; } @@ -432,9 +439,9 @@ Node QuantifierMacros::simplify( Node n ){ for( unsigned i=0; i<children.size(); i++ ){ Node etc = TypeNode::getEnsureTypeCondition( children[i], tno[i] ); if( etc.isNull() ){ - //if this does fail, we are incomplete, since we are eliminating quantified formula corresponding to op, + // if this does fail, we are incomplete, since we are eliminating + // quantified formula corresponding to op, // and not ensuring it applies to n when its types are correct. - //Assert( false ); success = false; break; }else if( !etc.isConst() ){ diff --git a/src/proof/arith_proof.cpp b/src/proof/arith_proof.cpp deleted file mode 100644 index 635767b97..000000000 --- a/src/proof/arith_proof.cpp +++ /dev/null @@ -1,1207 +0,0 @@ -/********************* */ -/*! \file arith_proof.cpp - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Liana Hadarean, Guy Katz - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** [[ Add lengthier description here ]] - - ** \todo document this file - -**/ -#include "proof/arith_proof.h" - -#include <memory> -#include <stack> - -#include "base/check.h" -#include "expr/node.h" -#include "expr/type_checker_util.h" -#include "proof/proof_manager.h" -#include "proof/theory_proof.h" -#include "theory/arith/constraint_forward.h" -#include "theory/arith/normal_form.h" -#include "theory/arith/theory_arith.h" - -#define CVC4_ARITH_VAR_TERM_PREFIX "term." - -namespace CVC4 { - -inline static Node eqNode(TNode n1, TNode n2) { - return NodeManager::currentNM()->mkNode(kind::EQUAL, n1, n2); -} - -// congrence matching term helper -inline static bool match(TNode n1, TNode n2) { - Debug("pf::arith") << "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("pf::arith") << "+ 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 ProofArith::toStream(std::ostream& out) const -{ - Trace("theory-proof-debug") << "; Print Arith proof..." << std::endl; - //AJR : carry this further? - ProofLetMap map; - toStreamLFSC(out, ProofManager::getArithProof(), *d_proof, map); -} - -void ProofArith::toStreamLFSC(std::ostream& out, - TheoryProof* tp, - const theory::eq::EqProof& pf, - const ProofLetMap& map) -{ - Debug("lfsc-arith") << "Printing arith proof in LFSC : " << std::endl; - pf.debug_print("lfsc-arith"); - Debug("lfsc-arith") << std::endl; - toStreamRecLFSC(out, tp, pf, 0, map); -} - -Node ProofArith::toStreamRecLFSC(std::ostream& out, - TheoryProof* tp, - const theory::eq::EqProof& pf, - unsigned tb, - const ProofLetMap& map) -{ - Debug("pf::arith") << std::endl - << std::endl - << "toStreamRecLFSC called. tb = " << tb - << " . proof:" << std::endl; - pf.debug_print("pf::arith"); - Debug("pf::arith") << std::endl; - - if(tb == 0) { - Assert(pf.d_id == theory::eq::MERGED_THROUGH_TRANS); - Assert(!pf.d_node.isNull()); - Assert(pf.d_children.size() >= 2); - - int neg = -1; - std::shared_ptr<theory::eq::EqProof> subTrans = - std::make_shared<theory::eq::EqProof>(); - subTrans->d_id = theory::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==theory::eq::MERGED_THROUGH_CONGRUENCE && pf.d_children[i]->d_node.isNull()) { - Debug("pf::arith") << "Handling congruence over equalities" << std::endl; - - // Gather the sequence of consecutive congruence closures. - std::vector<std::shared_ptr<const theory::eq::EqProof>> congruenceClosures; - unsigned count; - Debug("pf::arith") << "Collecting congruence sequence" << std::endl; - for (count = 0; - i + count < pf.d_children.size() && - pf.d_children[i + count]->d_id==theory::eq::MERGED_THROUGH_CONGRUENCE && - pf.d_children[i + count]->d_node.isNull(); - ++count) { - Debug("pf::arith") << "Found a congruence: " << std::endl; - pf.d_children[i+count]->debug_print("pf::arith"); - congruenceClosures.push_back(pf.d_children[i+count]); - } - - Debug("pf::arith") << "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("pf::arith") << "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("pf::arith") << "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<std::shared_ptr<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 != theory::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 != theory::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 != theory::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 != theory::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("pf::arith") << "\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("pf::arith") << "\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("pf::arith") << "\nhave proven: " << n1 << std::endl; - Debug("pf::arith") << "n2 is " << n2[0] << std::endl; - - if (n2[0].getNumChildren() > 0) { Debug("pf::arith") << "\nn2[0]: " << n2[0][0] << std::endl; } - if (n1.getNumChildren() > 1) { Debug("pf::arith") << "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 theory::eq::MERGED_THROUGH_CONGRUENCE: { - Debug("pf::arith") << "\nok, looking at congruence:\n"; - pf.debug_print("pf::arith"); - std::stack<const theory::eq::EqProof*> stk; - for (const theory::eq::EqProof* pf2 = &pf; - pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE; - pf2 = pf2->d_children[0].get()) { - 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 - != theory::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 == theory::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("pf::arith") << "\nok, in FIRST cong[" << stk.size() << "]" << "\n"; - pf2->debug_print("pf::arith"); - Debug("pf::arith") << "looking at " << pf2->d_node << "\n"; - Debug("pf::arith") << " " << n1 << "\n"; - Debug("pf::arith") << " " << n2 << "\n"; - int side = 0; - if(match(pf2->d_node, n1[0])) { - //if(tb == 1) { - Debug("pf::arith") << "SIDE IS 0\n"; - //} - side = 0; - } else { - //if(tb == 1) { - Debug("pf::arith") << "SIDE IS 1\n"; - //} - if(!match(pf2->d_node, n1[1])) { - Debug("pf::arith") << "IN BAD CASE, our first subproof is\n"; - pf2->d_children[0]->debug_print("pf::arith"); - } - 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("pf::arith") << "pf2->d_node " << pf2->d_node << std::endl; - Debug("pf::arith") << "b1.getNumChildren() " << b1.getNumChildren() << std::endl; - Debug("pf::arith") << "n1 " << n1 << std::endl; - Debug("pf::arith") << "n2 " << n2 << std::endl; - Debug("pf::arith") << "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("pf::arith") << "\nMORE TO DO\n"; - } - pf2 = stk.top(); - stk.pop(); - Assert(pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE); - out << " "; - ss.str(""); - n2 = toStreamRecLFSC(ss, tp, *(pf2->d_children[1]), tb + 1, map); - Debug("pf::arith") << "\nok, in cong[" << stk.size() << "]" << "\n"; - Debug("pf::arith") << "looking at " << pf2->d_node << "\n"; - Debug("pf::arith") << " " << n1 << "\n"; - Debug("pf::arith") << " " << n2 << "\n"; - Debug("pf::arith") << " " << b1 << "\n"; - Debug("pf::arith") << " " << 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("pf::arith") << "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("pf::arith") << "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("pf::arith") << "\ncong proved: " << n << "\n"; - } - return n; - } - - case theory::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 theory::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 theory::eq::MERGED_THROUGH_TRANS: { - Assert(!pf.d_node.isNull()); - Assert(pf.d_children.size() >= 2); - std::stringstream ss; - Debug("pf::arith") << "\ndoing trans proof[[\n"; - pf.debug_print("pf::arith"); - Debug("pf::arith") << "\n"; - Node n1 = toStreamRecLFSC(ss, tp, *(pf.d_children[0]), tb + 1, map); - Debug("pf::arith") << "\ndoing trans proof, got n1 " << n1 << "\n"; - if(tb == 1) { - Debug("pf::arith") << "\ntrans proof[0], got n1 " << n1 << "\n"; - } - - bool identicalEqualities = false; - bool evenLengthSequence; - Node nodeAfterEqualitySequence; - - std::map<size_t, Node> childToStream; - - for(size_t i = 1; i < pf.d_children.size(); ++i) { - std::stringstream ss1(ss.str()), ss2; - ss.str(""); - - // It is possible that we've already converted the i'th child to stream. If so, - // use previously stored result. Otherwise, convert and store. - Node n2; - if (childToStream.find(i) != childToStream.end()) - n2 = childToStream[i]; - else { - n2 = toStreamRecLFSC(ss2, tp, *(pf.d_children[i]), tb + 1, map); - childToStream[i] = n2; - } - - // 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) { - 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("pf::arith") << "Detected identical equalities: " << std::endl << "\t" << n1 << std::endl; - - if (!identicalEqualities) { - // The sequence of identical equalities has started just now - identicalEqualities = true; - - Debug("pf::arith") << "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("pf::arith") << "Equality sequence of even length" << std::endl; - Debug("pf::arith") << "n1 is: " << n1 << std::endl; - Debug("pf::arith") << "n2 is: " << n2 << std::endl; - Debug("pf::arith") << "pf-d_node is: " << pf.d_node << std::endl; - Debug("pf::arith") << "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("pf::arith") << "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); - - 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("pf::arith") << "Error: even length sequence, but I don't know which hand to keep!" << std::endl; - Assert(false); - } - } - - ss << ")"; - - } else { - Debug("pf::arith") << "Equality sequence length is odd!" << std::endl; - ss.str(ss1.str()); - } - - Debug("pf::arith") << "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("pf::arith") << "\ndoing trans proof, got n2 " << n2 << "\n"; - if(tb == 1) { - Debug("pf::arith") << "\ntrans proof[" << i << "], got n2 " << n2 << "\n"; - Debug("pf::arith") << (n2.getKind() == kind::EQUAL) << "\n"; - - if ((n1.getNumChildren() >= 2) && (n2.getNumChildren() >= 2)) { - Debug("pf::arith") << n1[0].getId() << " " << n1[1].getId() << " / " << n2[0].getId() << " " << n2[1].getId() << "\n"; - Debug("pf::arith") << n1[0].getId() << " " << n1[0] << "\n"; - Debug("pf::arith") << n1[1].getId() << " " << n1[1] << "\n"; - Debug("pf::arith") << n2[0].getId() << " " << n2[0] << "\n"; - Debug("pf::arith") << n2[1].getId() << " " << n2[1] << "\n"; - Debug("pf::arith") << (n1[0] == n2[0]) << "\n"; - Debug("pf::arith") << (n1[1] == n2[1]) << "\n"; - Debug("pf::arith") << (n1[0] == n2[1]) << "\n"; - Debug("pf::arith") << (n1[1] == n2[0]) << "\n"; - } - } - ss << "(trans _ _ _ _ "; - - if((n2.getKind() == kind::EQUAL) && (n1.getKind() == kind::EQUAL)) - // Both elements of the transitivity rule are equalities/iffs - { - if(n1[0] == n2[0]) { - if(tb == 1) { Debug("pf::arith") << "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("pf::arith") << "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("pf::arith") << "case 3\n"; } - n1 = eqNode(n2[0], n1[1]); - ss << ss2.str() << " " << ss1.str(); - if(tb == 1) { Debug("pf::arith") << "++ proved " << n1 << "\n"; } - } else if(n1[1] == n2[0]) { - if(tb == 1) { Debug("pf::arith") << "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("pf::arith",0); - //toStreamRec(Warning.getStream(), pf, 0); - Warning() << "\n\n"; - Unreachable(); - } - Debug("pf::arith") << "++ trans proof[" << i << "], now have " << n1 << std::endl; - } else if(n1.getKind() == kind::EQUAL) { - // 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 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("pf::arith") << "\n++ trans proof done, have proven " << n1 << std::endl; - return n1; - } - - default: - Assert(!pf.d_node.isNull()); - Assert(pf.d_children.empty()); - Debug("pf::arith") << "theory proof: " << pf.d_node << " by rule " << int(pf.d_id) << std::endl; - AlwaysAssert(false); - return pf.d_node; - } -} - -ArithProof::ArithProof(theory::arith::TheoryArith* arith, TheoryProofEngine* pe) - : TheoryProof(arith, pe), d_recorder() -{ - arith->setProofRecorder(&d_recorder); -} - -theory::TheoryId ArithProof::getTheoryId() { return theory::THEORY_ARITH; } -void ArithProof::registerTerm(Expr term) { - Debug("pf::arith") << "Arith register term: " << term << ". Kind: " << term.getKind() - << ". Type: " << term.getType() << std::endl; - - if (term.getType().isReal() && !term.getType().isInteger()) { - Debug("pf::arith") << "Entering real mode" << std::endl; - } - - if (term.isVariable() && !ProofManager::getSkolemizationManager()->isSkolem(term)) { - 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 LFSCArithProof::printOwnedTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) -{ - Debug("pf::arith") << "Arith print term: " << term << ". Kind: " << term.getKind() - << ". Type: " << term.getType() - << ". Number of children: " << term.getNumChildren() << std::endl; - - // !d_realMode <--> term.getType().isInteger() - - Assert (theory::Theory::theoryOf(term) == theory::THEORY_ARITH); - std::ostringstream closing; - if (!expectedType.isNull() && !expectedType.isInteger() && term.getType().isInteger()) { - os << "(term_int_to_real "; - closing << ")"; - } - switch (term.getKind()) - { - case kind::CONST_RATIONAL: - { - Assert(term.getNumChildren() == 0); - Assert(term.getType().isInteger() || term.getType().isReal()); - - const Rational& r = term.getConst<Rational>(); - bool neg = (r < 0); - - os << (term.getType().isInteger() ? "(a_int " : "(a_real "); - closing << ") "; - - if (neg) - { - os << "(~ "; - closing << ")"; - } - - if (term.getType().isInteger()) - { - os << r.abs(); - } - else - { - printRational(os, r.abs()); - } - - break; - } - - case kind::PLUS: - case kind::MINUS: - case kind::MULT: - case kind::DIVISION: - case kind::DIVISION_TOTAL: - { - Assert(term.getNumChildren() >= 1); - TypeNode ty = Node::fromExpr(term).getType(); - - std::string lfscFunction = getLfscFunction(term); - for (unsigned i = 0; i < term.getNumChildren() - 1; ++i) - { - os << "(" << lfscFunction << " "; - closing << ")"; - d_proofEngine->printBoundTerm(term[i], os, map, ty); - os << " "; - } - - d_proofEngine->printBoundTerm(term[term.getNumChildren() - 1], os, map, ty); - break; - } - - case kind::UMINUS: - { - Assert(term.getNumChildren() == 1); - os << "(" << getLfscFunction(term) << " "; - closing << ")"; - d_proofEngine->printBoundTerm(term[0], os, map, Node::fromExpr(term).getType()); - break; - } - - case kind::GT: - case kind::GEQ: - case kind::LT: - case kind::LEQ: - { - Assert(term.getNumChildren() == 2); - Assert(term.getType().isBoolean()); - - std::string lfscFunction = getLfscFunction(term); - TypeNode realType = NodeManager::currentNM()->realType(); - - os << "(" << lfscFunction << " "; - closing << ")"; - - d_proofEngine->printBoundTerm(term[0], os, map); - os << " "; - d_proofEngine->printBoundTerm(term[1], os, map, realType); - break; - } - case kind::EQUAL: - { - Assert(term.getType().isBoolean()); - Assert(term.getNumChildren() == 2); - - TypeNode eqType = equalityType(term[0], term[1]); - - os << "(= " << eqType << " "; - closing << ")"; - - d_proofEngine->printBoundTerm(term[0], os, map, eqType); - d_proofEngine->printBoundTerm(term[1], os, map, eqType); - break; - } - - case kind::VARIABLE: - case kind::SKOLEM: - os << CVC4_ARITH_VAR_TERM_PREFIX << ProofManager::sanitize(term); - break; - - default: - Debug("pf::arith") << "Default printing of term: " << term << std::endl; - os << term; - break; - } - os << closing.str(); -} - -void LFSCArithProof::printOwnedSort(Type type, std::ostream& os) { - Debug("pf::arith") << "Arith print sort: " << type << std::endl; - os << type; -} - -std::string LFSCArithProof::getLfscFunction(const Node & n) { - Assert(n.getType().isInteger() || n.getType().isReal() || n.getType().isBoolean()); - std::string opString; - switch (n.getKind()) { - case kind::UMINUS: - opString = "u-_"; - break; - case kind::PLUS: - opString = "+_"; - break; - case kind::MINUS: - opString = "-_"; - break; - case kind::MULT: - opString = "*_"; - break; - case kind::DIVISION: - case kind::DIVISION_TOTAL: - opString = "/_"; - break; - case kind::GT: - opString = ">_"; - break; - case kind::GEQ: - opString = ">=_"; - break; - case kind::LT: - opString = "<_"; - break; - case kind::LEQ: - opString = "<=_"; - break; - default: - Unreachable() << "Tried to get the operator for a non-operator kind: " << n.getKind(); - } - std::string typeString; - if (n.getType().isInteger()) { - typeString = "Int"; - } else if (n.getType().isReal()) { - typeString = "Real"; - } else { // Boolean - if (n[0].getType().isInteger()) { - typeString = "IntReal"; - } else { - typeString = "Real"; - } - } - return opString + typeString; -} - -void LFSCArithProof::printRational(std::ostream& o, const Rational& r) -{ - if (r.sgn() < 0) - { - o << "(~ " << r.getNumerator().abs() << "/" << r.getDenominator().abs() - << ")"; - } - else - { - o << r.getNumerator() << "/" << r.getDenominator(); - } -} - -void LFSCArithProof::printInteger(std::ostream& o, const Integer& i) -{ - if (i.sgn() < 0) - { - o << "(~ " << i.abs() << ")"; - } - else - { - o << i; - } -} - -void LFSCArithProof::printLinearPolynomialNormalizer(std::ostream& o, - const Node& n) -{ - switch (n.getKind()) - { - case kind::PLUS: - { - // Since our axioms are binary, but n may be n-ary, we rig up - // a right-associative tree. - size_t nchildren = n.getNumChildren(); - for (size_t i = 0; i < nchildren; ++i) - { - if (i < nchildren - 1) - { - o << "\n (is_aff_+ _ _ _ _ _ "; - } - printLinearMonomialNormalizer(o, n[i]); - } - std::fill_n(std::ostream_iterator<char>(o), nchildren - 1, ')'); - break; - } - case kind::MULT: - case kind::VARIABLE: - case kind::CONST_RATIONAL: - case kind::SKOLEM: - { - printLinearMonomialNormalizer(o, n); - break; - } - default: - Unreachable() << "Invalid operation " << n.getKind() - << " in linear polynomial"; - break; - } -} - -void LFSCArithProof::printLinearMonomialNormalizer(std::ostream& o, - const Node& n) -{ - switch (n.getKind()) - { - case kind::MULT: { - Assert((n[0].getKind() == kind::CONST_RATIONAL - && (n[1].getKind() == kind::VARIABLE - || n[1].getKind() == kind::SKOLEM))) - << "node " << n << " is not a linear monomial" - << " " << n[0].getKind() << " " << n[1].getKind(); - - o << "\n (is_aff_mul_c_L _ _ _ "; - printConstRational(o, n[0]); - o << " "; - printVariableNormalizer(o, n[1]); - o << ")"; - break; - } - case kind::CONST_RATIONAL: - { - o << "\n (is_aff_const "; - printConstRational(o, n); - o << ")"; - break; - } - case kind::VARIABLE: - case kind::SKOLEM: - { - o << "\n "; - printVariableNormalizer(o, n); - break; - } - default: - Unreachable() << "Invalid operation " << n.getKind() - << " in linear monomial"; - break; - } -} - -void LFSCArithProof::printConstRational(std::ostream& o, const Node& n) -{ - Assert(n.getKind() == kind::CONST_RATIONAL); - const Rational value = n.getConst<Rational>(); - printRational(o, value); -} - -void LFSCArithProof::printVariableNormalizer(std::ostream& o, const Node& n) -{ - std::ostringstream msg; - Assert(n.getKind() == kind::VARIABLE || n.getKind() == kind::SKOLEM) - << "Invalid variable kind " << n.getKind() << " in linear monomial"; - if (n.getType().isInteger()) { - o << "(is_aff_var_int "; - } else if (n.getType().isReal()) { - o << "(is_aff_var_real "; - } else { - Unreachable(); - } - o << n << ")"; -} - -void LFSCArithProof::printLinearPolynomialPredicateNormalizer(std::ostream& o, - const Node& n) -{ - Assert(n.getKind() == kind::GEQ) - << "can only print normalization witnesses for (>=) nodes"; - Assert(n[1].getKind() == kind::CONST_RATIONAL); - o << "\n (is_aff_- _ _ _ _ _ "; - printLinearPolynomialNormalizer(o, n[0]); - o << "\n (is_aff_const "; - printConstRational(o, n[1]); - o << "))"; -} - -std::pair<Node, std::string> LFSCArithProof::printProofAndMaybeTighten( - const Node& bound) -{ - const Node & nonNegBound = bound.getKind() == kind::NOT ? bound[0] : bound; - std::ostringstream pfOfPossiblyTightenedPredicate; - if (nonNegBound[0].getType().isInteger()) { - switch(bound.getKind()) - { - case kind::NOT: - { - // Tighten ~[i >= r] to [i < r] to [i <= {r}] to [-i >= -{r}] - // where - // * i is an integer - // * r is a real - // * {r} denotes the greatest int less than r - // it is equivalent to (ceil(r) - 1) - Assert(nonNegBound[1].getKind() == kind::CONST_RATIONAL); - Rational oldBound = nonNegBound[1].getConst<Rational>(); - Integer newBound = -(oldBound.ceiling() - 1); - // Since the arith theory rewrites bounds to be purely integral or - // purely real, mixed bounds should not appear in proofs - AlwaysAssert(oldBound.isIntegral()) << "Mixed int/real bound in arith proof"; - pfOfPossiblyTightenedPredicate - << "(tighten_not_>=_IntInt" - << " _ _ _ _ (" - << "check_neg_of_greatest_integer_below_int "; - printInteger(pfOfPossiblyTightenedPredicate, newBound); - pfOfPossiblyTightenedPredicate << " "; - printInteger(pfOfPossiblyTightenedPredicate, oldBound.ceiling()); - pfOfPossiblyTightenedPredicate << ") " << ProofManager::getLitName(bound.negate(), "") << ")"; - Node newLeft = (theory::arith::Polynomial::parsePolynomial(nonNegBound[0]) * -1).getNode(); - Node newRight = NodeManager::currentNM()->mkConst(Rational(newBound)); - Node newTerm = NodeManager::currentNM()->mkNode(kind::GEQ, newLeft, newRight); - return std::make_pair(newTerm, pfOfPossiblyTightenedPredicate.str()); - } - case kind::GEQ: - { - // Tighten [i >= r] to [i >= ceil(r)] - // where - // * i is an integer - // * r is a real - Assert(nonNegBound[1].getKind() == kind::CONST_RATIONAL); - - Rational oldBound = nonNegBound[1].getConst<Rational>(); - // Since the arith theory rewrites bounds to be purely integral or - // purely real, mixed bounds should not appear in proofs - AlwaysAssert(oldBound.isIntegral()) << "Mixed int/real bound in arith proof"; - pfOfPossiblyTightenedPredicate << ProofManager::getLitName(bound.negate(), ""); - return std::make_pair(bound, pfOfPossiblyTightenedPredicate.str()); - } - default: Unreachable(); - } - } else { - return std::make_pair(bound, ProofManager::getLitName(bound.negate(), "")); - } - // Silence compiler warnings about missing a return. - Unreachable(); -} - -void LFSCArithProof::printTheoryLemmaProof(std::vector<Expr>& lemma, - std::ostream& os, - std::ostream& paren, - const ProofLetMap& map) -{ - Debug("pf::arith") << "Printing proof for lemma " << lemma << std::endl; - if (Debug.isOn("pf::arith::printTheoryLemmaProof")) { - Debug("pf::arith::printTheoryLemmaProof") << "Printing proof for lemma:" << std::endl; - for (const auto & conjunct : lemma) { - Debug("pf::arith::printTheoryLemmaProof") << " " << conjunct << std::endl; - } - } - // Prefixes for the names of linearity witnesses - const char* linearizedProofPrefix = "pf_aff"; - std::ostringstream lemmaParen; - - // Construct the set of conflicting literals - std::set<Node> conflictSet; - std::transform(lemma.begin(), - lemma.end(), - std::inserter(conflictSet, conflictSet.begin()), - [](const Expr& e) { - return NodeManager::currentNM()->fromExpr(e).negate(); - }); - - // If we have Farkas coefficients stored for this lemma, use them to write a - // proof. Otherwise, just `trust` the lemma. - if (d_recorder.hasFarkasCoefficients(conflictSet)) - { - // Get farkas coefficients & literal order - const auto& farkasInfo = d_recorder.getFarkasCoefficients(conflictSet); - const Node& conflict = farkasInfo.first; - theory::arith::RationalVectorCP farkasCoefficients = farkasInfo.second; - Assert(farkasCoefficients != theory::arith::RationalVectorCPSentinel); - Assert(conflict.getNumChildren() == farkasCoefficients->size()); - const size_t nAntecedents = conflict.getNumChildren(); - - // Print proof - if (Debug.isOn("pf::arith::printTheoryLemmaProof")) { - os << "Farkas:" << std::endl; - for (const auto & n : *farkasCoefficients) { - os << " " << n << std::endl; - } - } - - // Prove affine function bounds from term bounds - os << "\n;; Farkas Proof ;;" << std::endl; - os << "\n; Linear Polynomial Proof Conversions"; - for (size_t i = 0; i != nAntecedents; ++i) - { - const Node& antecedent = conflict[i]; - os << "\n (@ " - << ProofManager::getLitName(antecedent.negate(), linearizedProofPrefix) - << " "; - lemmaParen << ")"; - const std::pair<Node, std::string> tightened = printProofAndMaybeTighten(antecedent); - switch (tightened.first.getKind()) - { - case kind::NOT: - { - Assert(conflict[i][0].getKind() == kind::GEQ); - os << "(aff_>_from_term _ _ _ _ "; - break; - } - case kind::GEQ: - { - os << "(aff_>=_from_term _ _ _ "; - break; - } - default: Unreachable(); - } - const Node& nonNegTightened = tightened.first.getKind() == kind::NOT ? tightened.first[0] : tightened.first; - printLinearPolynomialPredicateNormalizer(os, nonNegTightened); - os << " (pf_reified_arith_pred _ _ " << tightened.second << "))"; - } - - // Now, print the proof of bottom, from affine function bounds - os << "\n; Farkas Combination"; - os << "\n (clausify_false (bounded_aff_contra _ _"; - lemmaParen << "))"; - for (size_t i = 0; i != nAntecedents; ++i) - { - const Node& lit = conflict[i]; - os << "\n (bounded_aff_add _ _ _ _ _"; - os << "\n (bounded_aff_mul_c _ _ _ "; - printRational(os, (*farkasCoefficients)[i].abs()); - os << " " << ProofManager::getLitName(lit.negate(), linearizedProofPrefix) - << ")" - << " ; " << lit; - lemmaParen << ")"; - } - - os << "\n bounded_aff_ax_0_>=_0"; - os << lemmaParen.str(); // Close lemma proof - } - else - { - os << "\n; Arithmetic proofs which use reasoning more complex than Farkas " - "proofs and bound tightening are currently unsupported\n" - "(clausify_false trust)\n"; - } -} - -void LFSCArithProof::printSortDeclarations(std::ostream& os, std::ostream& paren) { - // Nothing to do here at this point. -} - -void LFSCArithProof::printTermDeclarations(std::ostream& os, std::ostream& paren) { - for (ExprSet::const_iterator it = d_declarations.begin(); - it != d_declarations.end(); - ++it) - { - Expr term = *it; - Assert(term.isVariable()); - bool isInt = term.getType().isInteger(); - const char * var_type = isInt ? "int_var" : "real_var"; - os << "(% " << ProofManager::sanitize(term) << " " << var_type << "\n"; - os << "(@ " << CVC4_ARITH_VAR_TERM_PREFIX << ProofManager::sanitize(term) - << " "; - os << "(term_" << var_type << " " << ProofManager::sanitize(term) << ")\n"; - paren << ")"; - paren << ")"; - } -} - -void LFSCArithProof::printDeferredDeclarations(std::ostream& os, std::ostream& paren) { - // Nothing to do here at this point. -} - -void LFSCArithProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) { - // Nothing to do here at this point. -} - -bool LFSCArithProof::printsAsBool(const Node& n) -{ - // Our boolean variables and constants print as sort Bool. - // All complex booleans print as formulas. - return n.getType().isBoolean() and (n.isVar() or n.isConst()); -} - -TypeNode LFSCArithProof::equalityType(const Expr& left, const Expr& right) -{ - return TypeNode::fromType(!left.getType().isInteger() ? left.getType() : right.getType()); -} - -} /* CVC4 namespace */ diff --git a/src/proof/arith_proof.h b/src/proof/arith_proof.h deleted file mode 100644 index 832afcae0..000000000 --- a/src/proof/arith_proof.h +++ /dev/null @@ -1,217 +0,0 @@ -/********************* */ -/*! \file arith_proof.h - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Guy Katz, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief Arith proof - ** - ** Arith proof - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__ARITH__PROOF_H -#define CVC4__ARITH__PROOF_H - -#include <memory> -#include <unordered_set> - -#include "expr/expr.h" -#include "proof/arith_proof_recorder.h" -#include "proof/proof_manager.h" -#include "proof/theory_proof.h" -#include "theory/uf/equality_engine.h" - -namespace CVC4 { - -//proof object outputted by TheoryArith -class ProofArith : public Proof { - public: - ProofArith(std::shared_ptr<theory::eq::EqProof> pf) : d_proof(pf) {} - void toStream(std::ostream& out) const override; - - private: - static void toStreamLFSC(std::ostream& out, TheoryProof* tp, - const theory::eq::EqProof& pf, - const ProofLetMap& map); - static Node toStreamRecLFSC(std::ostream& out, TheoryProof* tp, - const theory::eq::EqProof& pf, - unsigned tb, const ProofLetMap& map); - // it is simply an equality engine proof - std::shared_ptr<theory::eq::EqProof> d_proof; -}; - -namespace theory { -namespace arith { -class TheoryArith; -} -} - -typedef std::unordered_set<Type, TypeHashFunction > TypeSet; - - -class ArithProof : public TheoryProof { -protected: - // std::map<Expr, std::string> d_constRationalString; // all the variable/function declarations - - // TypeSet d_sorts; // all the uninterpreted sorts in this theory - ExprSet d_declarations; // all the variable/function declarations - - /** - * Where farkas proofs of lemmas are stored. - */ - proof::ArithProofRecorder d_recorder; - - theory::TheoryId getTheoryId() override; - - public: - ArithProof(theory::arith::TheoryArith* arith, TheoryProofEngine* proofEngine); - - void registerTerm(Expr term) override; -}; - -class LFSCArithProof : public ArithProof { -public: - LFSCArithProof(theory::arith::TheoryArith* arith, TheoryProofEngine* proofEngine) - : ArithProof(arith, proofEngine) - {} - void printOwnedTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) override; - void printOwnedSort(Type type, std::ostream& os) override; - - /** - * Returns the LFSC identifier for the operator of this node. - * - * e.g. "+_Real". - * - * Does not include any parens. - * - * Even if the operator is a comparison (e.g. >=) on integers, will not - * return a purely `Int` predicate like ">=_Int". Instead this treats the - * right hand side as a real. - */ - static std::string getLfscFunction(const Node& n); - - /** - * Print a rational number in LFSC format. - * e.g. 5/8 or (~ 1/1) - * - * @param o ostream to print to. - * @param r the rational to print - */ - static void printRational(std::ostream& o, const Rational& r); - - /** - * Print an integer in LFSC format. - * e.g. 5 or (~ 1) - * - * @param o ostream to print to. - * @param i the integer to print - */ - static void printInteger(std::ostream& o, const Integer& i); - - /** - * Print a value of type poly_formula_norm - * - * @param o ostream to print to - * @param n node (asserted to be of the form [linear polynomial >= constant]) - */ - static void printLinearPolynomialPredicateNormalizer(std::ostream& o, - const Node& n); - - /** - * Print a value of type poly_norm - * - * @param o ostream to print to - * @param n node (asserted to be a linear polynomial) - */ - static void printLinearPolynomialNormalizer(std::ostream& o, const Node& n); - - /** - * Print a value of type poly_norm - * - * @param o ostream to print to - * @param n node (asserted to be a linear monomial) - */ - static void printLinearMonomialNormalizer(std::ostream& o, const Node& n); - - /** - * Print a LFSC rational - * - * @param o ostream to print to - * @param n node (asserted to be a const rational) - */ - static void printConstRational(std::ostream& o, const Node& n); - - /** - * print the pn_var normalizer for n (type poly_norm) - * - * @param o the ostream to print to - * @param n the node to print (asserted to be a variable) - */ - static void printVariableNormalizer(std::ostream& o, const Node& n); - /** - * print a proof of the lemma - * - * First, we print linearity witnesses, i.e. witnesses that each literal has - * the form: - * [linear polynomial] >= 0 OR - * [linear polynomial] > 0 - * - * Then we use those witnesses to prove that the above linearized constraints - * hold. - * - * Then we use the farkas coefficients to combine the literals into a - * variable-free contradiction. The literals may be a mix of strict and - * relaxed inequalities. - * - * @param lemma the set of literals disjoined in the lemma - * @param os stream to print the proof to - * @param paren global closing stream (unused) - * @param map let map (unused) - */ - void printTheoryLemmaProof(std::vector<Expr>& lemma, - std::ostream& os, - std::ostream& paren, - const ProofLetMap& map) override; - void printSortDeclarations(std::ostream& os, std::ostream& paren) override; - void printTermDeclarations(std::ostream& os, std::ostream& paren) override; - void printDeferredDeclarations(std::ostream& os, - std::ostream& paren) override; - void printAliasingDeclarations(std::ostream& os, - std::ostream& paren, - const ProofLetMap& globalLetMap) override; - - /** - * Given a node that is an arith literal (an arith comparison or negation - * thereof), prints a proof of that literal. - * - * If the node represents a tightenable bound (e.g. [Int] < 3) then it prints - * a proof of the tightening instead. (e.g. [Int] <= 2). - * - * @return a pair comprising: - * * the new node (after tightening) and - * * a string proving it. - */ - std::pair<Node, std::string> printProofAndMaybeTighten(const Node& bound); - - /** - * Return whether this node, when serialized to LFSC, has sort `Bool`. Otherwise, the sort is `formula`. - */ - bool printsAsBool(const Node& n) override; - - TypeNode equalityType(const Expr& left, const Expr& right) override; -}; - - -}/* CVC4 namespace */ - -#endif /* CVC4__ARITH__PROOF_H */ diff --git a/src/proof/arith_proof_recorder.cpp b/src/proof/arith_proof_recorder.cpp deleted file mode 100644 index 01da402c9..000000000 --- a/src/proof/arith_proof_recorder.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/********************* */ -/*! \file arith_proof_recorder.cpp - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief A class for recording the skeletons of arithmetic proofs at solve - ** time so they can later be used during proof-production time. - **/ - -#include "proof/arith_proof_recorder.h" - -#include <algorithm> -#include <vector> - -#include "base/map_util.h" - -namespace CVC4 { -namespace proof { - -ArithProofRecorder::ArithProofRecorder() : d_lemmasToFarkasCoefficients() -{ - // Nothing else -} -void ArithProofRecorder::saveFarkasCoefficients( - Node conflict, theory::arith::RationalVectorCP farkasCoefficients) -{ - // Verify that the conflict is a conjuction of (possibly negated) real bounds - // Verify that the conflict is a conjunciton ... - Assert(conflict.getKind() == kind::AND); - Assert(conflict.getNumChildren() == farkasCoefficients->size()); - for (size_t i = 0, nchildren = conflict.getNumChildren(); i < nchildren; ++i) - { - const Node& child = conflict[i]; - // ... of possibly negated ... - const Node& nonNegativeChild = - child.getKind() == kind::NOT ? child[0] : child; - // ... real bounds - Assert(nonNegativeChild.getType().isBoolean() - && nonNegativeChild[0].getType().isReal()); - } - Debug("pf::arith") << "Saved Farkas Coefficients:" << std::endl; - if (Debug.isOn("pf::arith")) - { - for (size_t i = 0, nchildren = conflict.getNumChildren(); i < nchildren; - ++i) - { - const Node& child = conflict[i]; - const Rational& r = (*farkasCoefficients)[i]; - Debug("pf::arith") << " " << std::setw(8) << r; - Debug("pf::arith") << " " << child << std::endl; - } - } - - std::set<Node> lits; - std::copy( - conflict.begin(), conflict.end(), std::inserter(lits, lits.begin())); - - d_lemmasToFarkasCoefficients[lits] = - std::make_pair(std::move(conflict), *farkasCoefficients); -} - -bool ArithProofRecorder::hasFarkasCoefficients( - const std::set<Node>& conflict) const -{ - return d_lemmasToFarkasCoefficients.find(conflict) - != d_lemmasToFarkasCoefficients.end(); -} - -std::pair<Node, theory::arith::RationalVectorCP> -ArithProofRecorder::getFarkasCoefficients(const std::set<Node>& conflict) const -{ - if (auto *p = FindOrNull(d_lemmasToFarkasCoefficients, conflict)) - { - return std::make_pair(p->first, &p->second); - } - else - { - return std::make_pair(Node(), theory::arith::RationalVectorCPSentinel); - } -} - -} // namespace proof -} // namespace CVC4 diff --git a/src/proof/arith_proof_recorder.h b/src/proof/arith_proof_recorder.h deleted file mode 100644 index 0669e5d16..000000000 --- a/src/proof/arith_proof_recorder.h +++ /dev/null @@ -1,107 +0,0 @@ -/********************* */ -/*! \file arith_proof_recorder.h - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief A class for recording the skeletons of arithmetic proofs at solve - ** time so they can later be used during proof-production time. - ** - ** In particular, we're interested in proving bottom from a conjunction of - ** theory literals. - ** - ** For now, we assume that this can be done using a Farkas combination, and if - ** that doesn't work for some reason, then we give up and "trust" the lemma. - ** In the future we'll build support for more sophisticated reasoning. - ** - ** Given this scope, our task is to... - ** for each lemma (a set of literals) - ** save the Farkas coefficients for those literals - ** which requires we save an ordering of the literals - ** and a parallel ordering of Farkas coefficients. - ** - ** Farkas proofs have the following core structure: - ** For a list of affine bounds: c[i] dot x >= b[i] - ** (x is a vector of variables) - ** (c[i] is a vector of coefficients) - ** and a list of non-negative coefficients: f[i], - ** compute - ** - ** sum_i{ (c[i] dot x) * f[i] } and sum_i{b[i]*f[i]} - ** - ** and then verify that the left is actually < the right, a contradiction - ** - ** To be clear: this code does not check Farkas proofs, it just stores the - ** information needed to write them. - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__PROOF__ARITH_PROOF_RECORDER_H -#define CVC4__PROOF__ARITH_PROOF_RECORDER_H - -#include <map> -#include <set> - -#include "expr/node.h" -#include "theory/arith/constraint_forward.h" - -namespace CVC4 { -namespace proof { - -class ArithProofRecorder -{ - public: - ArithProofRecorder(); - - /** - * @brief For a set of incompatible literals, save the Farkas coefficients - * demonstrating their incompatibility - * - * @param conflict a conjunction of conflicting literals - * @param farkasCoefficients a list of rational coefficients which the literals - * should be multiplied by (pairwise) to produce a contradiction. - * - * The orders of the two vectors must agree! - */ - void saveFarkasCoefficients( - Node conflict, theory::arith::RationalVectorCP farkasCoefficients); - - /** - * @brief Determine whether some literals have a Farkas proof of their - * incompatibility - * - * @param conflict a conjunction of (putatively) conflicting literals - * - * @return whether or not there is actually a proof for them. - */ - bool hasFarkasCoefficients(const std::set<Node>& conflict) const; - - /** - * @brief Get the Farkas Coefficients object - * - * @param conflict a conjunction of conflicting literals - * @return theory::arith::RationalVectorCP -- the Farkas coefficients - * Node -- a conjunction of the problem literals in coefficient order - * - * theory::arith::RationalVectorCPSentinel if there is no entry for - * these lits - */ - std::pair<Node, theory::arith::RationalVectorCP> getFarkasCoefficients( - const std::set<Node>& conflict) const; - - protected: - // For each lemma, save the Farkas coefficients of that lemma - std::map<std::set<Node>, std::pair<Node, theory::arith::RationalVector>> - d_lemmasToFarkasCoefficients; -}; - -} // namespace proof -} // namespace CVC4 - -#endif diff --git a/src/proof/array_proof.cpp b/src/proof/array_proof.cpp deleted file mode 100644 index 2d42a7489..000000000 --- a/src/proof/array_proof.cpp +++ /dev/null @@ -1,1350 +0,0 @@ -/********************* */ -/*! \file array_proof.cpp - ** \verbatim - ** Top contributors (to current version): - ** Guy Katz, Yoni Zohar, Liana Hadarean - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** [[ Add lengthier description here ]] - - ** \todo document this file - -**/ - -#include "proof/array_proof.h" - -#include <stack> - -#include "proof/proof_manager.h" -#include "proof/simplify_boolean_node.h" -#include "proof/theory_proof.h" -#include "theory/arrays/theory_arrays.h" - -namespace CVC4 { - -namespace { - -class ArrayProofPrinter : public theory::eq::EqProof::PrettyPrinter { - public: - ArrayProofPrinter(unsigned row, unsigned row1, unsigned ext) - : d_row(row), d_row1(row1), d_ext(ext) {} - - std::string printTag(unsigned tag) override; - - private: - const unsigned d_row; - const unsigned d_row1; - const unsigned d_ext; -}; // class ArrayProofPrinter - -std::string ArrayProofPrinter::printTag(unsigned tag) { - if (tag == theory::eq::MERGED_THROUGH_CONGRUENCE) return "Congruence"; - if (tag == theory::eq::MERGED_THROUGH_EQUALITY) return "Pure Equality"; - if (tag == theory::eq::MERGED_THROUGH_REFLEXIVITY) return "Reflexivity"; - if (tag == theory::eq::MERGED_THROUGH_CONSTANTS) return "Constants"; - if (tag == theory::eq::MERGED_THROUGH_TRANS) return "Transitivity"; - - if (tag == d_row) return "Read Over Write"; - if (tag == d_row1) return "Read Over Write (1)"; - if (tag == d_ext) return "Extensionality"; - - std::ostringstream result; - result << tag; - return result.str(); -} - -} // namespace - - - -ProofArray::ProofArray(std::shared_ptr<theory::eq::EqProof> pf, - unsigned row, - unsigned row1, - unsigned ext) - : d_proof(pf), d_reasonRow(row), d_reasonRow1(row1), d_reasonExt(ext) -{ -} - -void ProofArray::toStream(std::ostream& out) const -{ - ProofLetMap map; - toStream(out, map); -} - -void ProofArray::toStream(std::ostream& out, const ProofLetMap& map) const -{ - Trace("pf::array") << "; Print Array proof..." << std::endl; - toStreamLFSC(out, ProofManager::getArrayProof(), *d_proof, map); - Debug("pf::array") << "; Print Array proof done!" << std::endl; -} - -void ProofArray::toStreamLFSC(std::ostream& out, - TheoryProof* tp, - const theory::eq::EqProof& pf, - const ProofLetMap& map) const -{ - Debug("pf::array") << "Printing array proof in LFSC : " << std::endl; - ArrayProofPrinter proofPrinter(d_reasonRow, d_reasonRow1, d_reasonExt); - pf.debug_print("pf::array", 0, &proofPrinter); - Debug("pf::array") << std::endl; - toStreamRecLFSC(out, tp, pf, 0, map); - Debug("pf::array") << "Printing array proof in LFSC DONE" << std::endl; -} - -Node ProofArray::toStreamRecLFSC(std::ostream& out, - TheoryProof* tp, - const theory::eq::EqProof& pf, - unsigned tb, - const ProofLetMap& map) const -{ - Debug("pf::array") << std::endl - << std::endl - << "toStreamRecLFSC called. tb = " << tb - << " . proof:" << std::endl; - ArrayProofPrinter proofPrinter(d_reasonRow, d_reasonRow1, d_reasonExt); - if(tb == 0) { - std::shared_ptr<theory::eq::EqProof> subTrans = - std::make_shared<theory::eq::EqProof>(); - - int neg = tp->assertAndPrint(pf, map, subTrans, &proofPrinter); - - Node n1; - std::stringstream ss, ss2; - Debug("mgdx") << "\nsubtrans has " << subTrans->d_children.size() << " children\n"; - bool disequalityFound = (neg >= 0); - - if (!disequalityFound || 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; - } - - out << "(clausify_false (contra _ "; - if (disequalityFound) { - Node n2 = pf.d_children[neg]->d_node; - Assert(n2.getKind() == kind::NOT); - Debug("mgdx") << "\nhave proven: " << n1 << std::endl; - Debug("mgdx") << "n2 is " << n2 << std::endl; - Debug("mgdx") << "n2->d_id is " << pf.d_children[neg]->d_id << std::endl; - Debug("mgdx") << "n2[0] 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 ((pf.d_children[neg]->d_id == d_reasonExt) || - (pf.d_children[neg]->d_id == theory::eq::MERGED_THROUGH_TRANS)) { - // Ext case: The negative node was created by an EXT rule; e.g. it is a[k]!=b[k], due to a!=b. - out << ss.str(); - out << " "; - toStreamRecLFSC(ss2, tp, *pf.d_children[neg], 1, map); - out << ss2.str(); - } else 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(); - } - Debug("pf::array") << "ArrayProof::toStream: getLitName( " << n2[0] << " ) = " << - ProofManager::getLitName(n2[0]) << std::endl; - - out << " " << ProofManager::getLitName(n2[0]); - } - } else { - Node n2 = pf.d_node; - Assert(n2.getKind() == kind::EQUAL); - Assert((n1[0] == n2[0] && n1[1] == n2[1]) - || (n1[1] == n2[0] && n1[0] == n2[1])); - - out << ss.str(); - out << " "; - ProofManager::getTheoryProofEngine()->printConstantDisequalityProof(out, - n1[0].toExpr(), - n1[1].toExpr(), - map); - } - - out << "))" << std::endl; - return Node(); - } - - switch (pf.d_id) - { - case theory::eq::MERGED_THROUGH_CONGRUENCE: - { - Debug("mgd") << "\nok, looking at congruence:\n"; - pf.debug_print("mgd", 0, &proofPrinter); - std::stack<const theory::eq::EqProof*> stk; - for (const theory::eq::EqProof* pf2 = &pf; - pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE; - pf2 = pf2->d_children[0].get()) - { - Debug("mgd") << "Looking at pf2 with d_node: " << pf2->d_node - << std::endl; - 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::PARTIAL_SELECT_0 - || pf2->d_node.getKind() == kind::PARTIAL_SELECT_1 - || 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 - != theory::eq::MERGED_THROUGH_CONGRUENCE); - // NodeBuilder<> b1(kind::PARTIAL_APPLY_UF), - // b2(kind::PARTIAL_APPLY_UF); - NodeBuilder<> b1, b2; - - const theory::eq::EqProof* pf2 = stk.top(); - stk.pop(); - Assert(pf2->d_id == theory::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", 0, &proofPrinter); - // Temp - Debug("mgd") << "n1 is a proof for: " << pf2->d_children[0]->d_node - << ". It is: " << n1 << std::endl; - Debug("mgd") << "n2 is a proof for: " << pf2->d_children[1]->d_node - << ". It is: " << n2 << std::endl; - // - Debug("mgd") << "looking at " << pf2->d_node << "\n"; - Debug("mgd") << " " << n1 << "\n"; - Debug("mgd") << " " << n2 << "\n"; - - int side = 0; - if (tp->match(pf2->d_node, n1[0])) - { - Debug("mgd") << "SIDE IS 0\n"; - side = 0; - } - else - { - Debug("mgd") << "SIDE IS 1\n"; - if (!tp->match(pf2->d_node, n1[1])) - { - Debug("mgd") << "IN BAD CASE, our first subproof is\n"; - pf2->d_children[0]->debug_print("mgd", 0, &proofPrinter); - } - Assert(tp->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::PARTIAL_SELECT_1 - || n1[side].getKind() == kind::STORE) - { - if (n1[side].getKind() == kind::APPLY_UF - || n1[side].getKind() == kind::PARTIAL_APPLY_UF) - { - b1 << kind::PARTIAL_APPLY_UF; - b1 << n1[side].getOperator(); - } - else if (n1[side].getKind() == kind::SELECT - || n1[side].getKind() == kind::PARTIAL_SELECT_1) - { - // b1 << n1[side].getKind(); - b1 << kind::SELECT; - } else { - b1 << kind::PARTIAL_APPLY_UF; - b1 << ProofManager::currentPM()->mkOp(n1[side].getOperator()); - } - b1.append(n1[side].begin(), n1[side].end()); - } - else if (n1[side].getKind() == kind::PARTIAL_SELECT_0) { - b1 << kind::PARTIAL_SELECT_1; - } else { - b1 << n1[side]; - } - - if(n1[1-side].getKind() == kind::PARTIAL_APPLY_UF || - n1[1-side].getKind() == kind::APPLY_UF || - n1[1-side].getKind() == kind::SELECT || - n1[1-side].getKind() == kind::PARTIAL_SELECT_1 || - n1[1-side].getKind() == kind::STORE) { - if(n1[1-side].getKind() == kind::APPLY_UF || - n1[1-side].getKind() == kind::PARTIAL_APPLY_UF) { - b2 << kind::PARTIAL_APPLY_UF; - b2 << n1[1-side].getOperator(); - } else if (n1[1-side].getKind() == kind::SELECT || n1[1-side].getKind() == kind::PARTIAL_SELECT_1) { - // b2 << n1[1-side].getKind(); - b2 << kind::SELECT; - } else { - b2 << kind::PARTIAL_APPLY_UF; - b2 << ProofManager::currentPM()->mkOp(n1[1-side].getOperator()); - } - b2.append(n1[1-side].begin(), n1[1-side].end()); - } else if (n1[1-side].getKind() == kind::PARTIAL_SELECT_0) { - b2 << kind::PARTIAL_SELECT_1; - } 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; - // These debug prints can cause a problem if we're constructing a SELECT node and it doesn't have enough - // children yet. - // Debug("mgd") << "b1 " << b1 << std::endl; - // Debug("mgd") << "b2 " << b2 << std::endl; - Debug("mgd") << "side " << side << std::endl; - Debug("mgd") << "pf2->d_node's number of children: " << pf2->d_node.getNumChildren() << std::endl; - Debug("mgd") << "pf2->d_node's meta kind: " << pf2->d_node.getMetaKind() << std::endl; - Debug("mgd") << "Is this meta kind considered parameterized? " << (pf2->d_node.getMetaKind() == kind::metakind::PARAMETERIZED) << std::endl; - - if(pf2->d_node[b1.getNumChildren() + - (n1[side].getKind() == kind::PARTIAL_SELECT_0 ? 1 : 0) + - (n1[side].getKind() == kind::PARTIAL_SELECT_1 ? 1 : 0) - - (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() - + (n1[side].getKind() == kind::PARTIAL_SELECT_0 ? 1 : 0) - + (n1[side].getKind() == kind::PARTIAL_SELECT_1 ? 1 : 0) - - (pf2->d_node.getMetaKind() - == kind::metakind::PARAMETERIZED - ? 0 - : 1)] - == n2[1 - side]); - b1 << n2[1-side]; - b2 << n2[side]; - out << "(symm _ _ _ " << ss.str() << ")"; - } - - Debug("mgd") << "After first insertion:" << std::endl; - Debug("mgd") << "b1 " << b1 << std::endl; - Debug("mgd") << "b2 " << b2 << std::endl; - - out << ")"; - while(!stk.empty()) { - - Debug("mgd") << "\nMORE TO DO\n"; - - pf2 = stk.top(); - stk.pop(); - Assert(pf2->d_id == theory::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!" << std::endl - << "pf2->d_node = " << pf2->d_node << std::endl - << "n1 (assigned from b1) = " << n1 << std::endl - << "n2 (assigned from b2) = " << n2 << std::endl; - - if(pf2->d_node.getKind() == kind::PARTIAL_APPLY_UF) { - Assert(n1 == pf2->d_node); - } - - Debug("mgd") << "n1.getOperator().getType().getNumChildren() = " - << n1.getOperator().getType().getNumChildren() << std::endl; - Debug("mgd") << "n1.getNumChildren() + 1 = " - << n1.getNumChildren() + 1 << std::endl; - - Assert(!( - (n1.getKind() == kind::PARTIAL_SELECT_0 && n1.getNumChildren() == 2))); - if (n1.getKind() == kind::PARTIAL_SELECT_1 && n1.getNumChildren() == 2) { - Debug("mgd") << "Finished a SELECT. Updating.." << std::endl; - b1.clear(kind::SELECT); - b1.append(n1.begin(), n1.end()); - n1 = b1; - Debug("mgd") << "New n1: " << n1 << std::endl; - } else 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); - } - } - - Debug("mgd") << "n2.getOperator().getType().getNumChildren() = " - << n2.getOperator().getType().getNumChildren() << std::endl; - Debug("mgd") << "n2.getNumChildren() + 1 = " - << n2.getNumChildren() + 1 << std::endl; - - Assert(!( - (n2.getKind() == kind::PARTIAL_SELECT_0 && n2.getNumChildren() == 2))); - if (n2.getKind() == kind::PARTIAL_SELECT_1 && n2.getNumChildren() == 2) { - Debug("mgd") << "Finished a SELECT. Updating.." << std::endl; - b2.clear(kind::SELECT); - b2.append(n2.begin(), n2.end()); - n2 = b2; - Debug("mgd") << "New n2: " << n2 << std::endl; - } else 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 ? n1.eqNode(n2) : n2.eqNode(n1)); - - Debug("mgdx") << "\ncong proved: " << n << "\n"; - return n; - } - case theory::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 pf.d_node.eqNode(pf.d_node); - } - case theory::eq::MERGED_THROUGH_EQUALITY: - { - Assert(!pf.d_node.isNull()); - Assert(pf.d_children.empty()); - Debug("pf::array") << "ArrayProof::toStream: getLitName( " << pf.d_node.negate() << " ) = " << - ProofManager::getLitName(pf.d_node.negate()) << std::endl; - out << ProofManager::getLitName(pf.d_node.negate()); - return pf.d_node; - } - - case theory::eq::MERGED_THROUGH_TRANS: - { - bool firstNeg = false; - bool secondNeg = false; - - Assert(!pf.d_node.isNull()); - Assert(pf.d_children.size() >= 2); - std::stringstream ss; - Debug("mgd") << "\ndoing trans proof[[\n"; - pf.debug_print("mgd", 0, &proofPrinter); - Debug("mgd") << "\n"; - - pf.d_children[0]->d_node = simplifyBooleanNode(pf.d_children[0]->d_node); - - 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; - std::stringstream dontCare; - Node nodeAfterEqualitySequence = - toStreamRecLFSC(dontCare, tp, *(pf.d_children[0]), tb + 1, map); - - std::map<size_t, Node> childToStream; - - std::pair<Node, Node> nodePair; - for (size_t i = 1; i < pf.d_children.size(); ++i) - { - std::stringstream ss1(ss.str()), ss2; - ss.str(""); - - // In congruences, we can have something like a[x] - it's important to - // keep these, - // and not turn them into (a[x]=true), because that will mess up the - // congruence application - // later. - - if (pf.d_children[i]->d_id != theory::eq::MERGED_THROUGH_CONGRUENCE) - pf.d_children[i]->d_node = - simplifyBooleanNode(pf.d_children[i]->d_node); - - // It is possible that we've already converted the i'th child to stream. - // If so, - // use previously stored result. Otherwise, convert and store. - Node n2; - if (childToStream.find(i) != childToStream.end()) - n2 = childToStream[i]; - else - { - n2 = toStreamRecLFSC(ss2, tp, *(pf.d_children[i]), tb + 1, map); - childToStream[i] = n2; - } - - Debug("mgd") << "\ndoing trans proof, got (first) n2 " << n2 << "\n"; - - // 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) - { - 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("pf::array") << "Detected identical equalities: " << std::endl - << "\t" << n1 << std::endl; - - if (!identicalEqualities) - { - // The sequence of identical equalities has started just now - identicalEqualities = true; - - Debug("pf::array") - << "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 ignore; - nodeAfterEqualitySequence = - toStreamRecLFSC(ignore, 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; - } - - nodePair = - tp->identicalEqualitiesPrinterHelper(evenLengthSequence, - sequenceOver, - pf, - map, - ss1.str(), - &ss, - n1, - nodeAfterEqualitySequence); - n1 = nodePair.first; - nodeAfterEqualitySequence = nodePair.second; - } - 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) << "\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"; - } - } - - // We can hadnle one of the equalities being negative, but not both - Assert((n1.getKind() != kind::NOT) || (n2.getKind() != kind::NOT)); - - firstNeg = false; - secondNeg = false; - - if (n1.getKind() == kind::NOT) { - Debug("mgdx") << "n1 is negative" << std::endl; - Debug("pf::array") << "n1 = " << n1 << ", n2 = " << n2 << std::endl; - firstNeg = true; - ss << "(negtrans1 _ _ _ _ "; - n1 = n1[0]; - } else if (n2.getKind() == kind::NOT) { - Debug("mgdx") << "n2 is negative" << std::endl; - Debug("pf::array") << "n1 = " << n1 << ", n2 = " << n2 << std::endl; - secondNeg = true; - ss << "(negtrans2 _ _ _ _ "; - n2 = n2[0]; - } else { - ss << "(trans _ _ _ _ "; - } - - if((n2.getKind() == kind::EQUAL) && (n1.getKind() == kind::EQUAL)) - // Both elements of the transitivity rule are equalities/iffs - { - if(n1[0] == n2[0]) { - if(tb == 1) { Debug("mgdx") << "case 1\n"; } - n1 = n1[1].eqNode(n2[1]); - ss << (firstNeg ? "(negsymm _ _ _ " : "(symm _ _ _ ") << ss1.str() << ") " << ss2.str(); - } else if(n1[1] == n2[1]) { - if(tb == 1) { Debug("mgdx") << "case 2\n"; } - n1 = n1[0].eqNode(n2[0]); - ss << ss1.str() << (secondNeg ? " (negsymm _ _ _ " : " (symm _ _ _ " ) << ss2.str() << ")"; - } else if(n1[0] == n2[1]) { - if(tb == 1) { Debug("mgdx") << "case 3\n"; } - if(!firstNeg && !secondNeg) { - n1 = n2[0].eqNode(n1[1]); - ss << ss2.str() << " " << ss1.str(); - } else if (firstNeg) { - n1 = n1[1].eqNode(n2[0]); - ss << " (negsymm _ _ _ " << ss1.str() << ") (symm _ _ _ " << ss2.str() << ")"; - } else { - Assert(secondNeg); - n1 = n1[1].eqNode(n2[0]); - ss << " (symm _ _ _ " << ss1.str() << ") (negsymm _ _ _ " << ss2.str() << ")"; - } - if(tb == 1) { Debug("mgdx") << "++ proved " << n1 << "\n"; } - } else if(n1[1] == n2[0]) { - if(tb == 1) { Debug("mgdx") << "case 4\n"; } - n1 = n1[0].eqNode(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, &proofPrinter); - //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 is an equality/iff, but n2 is a predicate - if(n1[0] == n2) { - n1 = n1[1]; - ss << (firstNeg ? "(negsymm _ _ _ " : "(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 is an equality/iff, but n1 is a predicate - if(n2[0] == n1) { - n1 = n2[1]; - ss << (secondNeg ? "(negsymm _ _ _ " : "(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 << ")"; - - if (firstNeg || secondNeg) { - n1 = (n1.getKind() == kind::NOT) ? n1[0] : n1.notNode(); - } - } - - out << ss.str(); - Debug("mgd") << "\n++ trans proof done, have proven " << n1 << std::endl; - //return (firstNeg || secondNeg) ? n1.notNode() : n1; - return n1; - } - - case theory::eq::MERGED_THROUGH_CONSTANTS: - { - Debug("pf::array") << "Proof for: " << pf.d_node << std::endl; - Assert(pf.d_node.getKind() == kind::NOT); - Node n = pf.d_node[0]; - Assert(n.getKind() == kind::EQUAL); - Assert(n.getNumChildren() == 2); - Assert(n[0].isConst() && n[1].isConst()); - - ProofManager::getTheoryProofEngine()->printConstantDisequalityProof( - out, n[0].toExpr(), n[1].toExpr(), map); - return pf.d_node; - } - - default: - { - if (pf.d_id == d_reasonRow) - { - Debug("mgd") << "row lemma: " << pf.d_node << std::endl; - Assert(pf.d_node.getKind() == kind::EQUAL); - - if (pf.d_node[1].getKind() == kind::SELECT) - { - // This is the case where ((a[i]:=t)[k] == a[k]), and the sub-proof - // explains why (i != k). - 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"; - } - - // inner index != outer index - // t3 is the outer index - - Assert(pf.d_children.size() == 1); - std::stringstream ss; - Node subproof = - toStreamRecLFSC(ss, tp, *(pf.d_children[0]), tb + 1, map); - - 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 << " "; - - Debug("pf::array") << "pf.d_children[0]->d_node is: " - << pf.d_children[0]->d_node << ". t3 is: " << t3 - << std::endl - << "subproof is: " << subproof << std::endl; - - Debug("pf::array") << "Subproof is: " << ss.str() << std::endl; - - // The subproof needs to show that t2 != t3. This can either be a direct - // disequality, - // or, if (wlog) t2 is constant, it can show that t3 is equal to another - // constant. - if (subproof.getKind() == kind::NOT) - { - // The subproof is for t2 != t3 (or t3 != t2) - if (subproof[0][1] == t3) - { - Debug("pf::array") << "Dont need symmetry!" << std::endl; - out << ss.str(); - } - else - { - Debug("pf::array") << "Need symmetry!" << std::endl; - out << "(negsymm _ _ _ " << ss.str() << ")"; - } - } - else - { - // Either t2 or t3 is a constant. - Assert(subproof.getKind() == kind::EQUAL); - Assert(subproof[0].isConst() || subproof[1].isConst()); - Assert(t2.isConst() || t3.isConst()); - Assert(!(t2.isConst() && t3.isConst())); - - bool t2IsConst = t2.isConst(); - if (subproof[0].isConst()) - { - if (t2IsConst) - { - // (t3 == subproof[1]) == subproof[0] != t2 - // goal is t2 != t3 - // subproof already shows constant = t3 - Assert(t3 == subproof[1]); - out << "(negtrans _ _ _ _ "; - tp->printConstantDisequalityProof( - out, t2.toExpr(), subproof[0].toExpr(), map); - out << " "; - out << ss.str(); - out << ")"; - } - else - { - Assert(t2 == subproof[1]); - out << "(negsymm _ _ _ "; - out << "(negtrans _ _ _ _ "; - tp->printConstantDisequalityProof( - out, t3.toExpr(), subproof[0].toExpr(), map); - out << " "; - out << ss.str(); - out << "))"; - } - } - else - { - if (t2IsConst) - { - // (t3 == subproof[0]) == subproof[1] != t2 - // goal is t2 != t3 - // subproof already shows constant = t3 - Assert(t3 == subproof[0]); - out << "(negtrans _ _ _ _ "; - tp->printConstantDisequalityProof( - out, t2.toExpr(), subproof[1].toExpr(), map); - out << " "; - out << "(symm _ _ _ " << ss.str() << ")"; - out << ")"; - } - else - { - Assert(t2 == subproof[0]); - out << "(negsymm _ _ _ "; - out << "(negtrans _ _ _ _ "; - tp->printConstantDisequalityProof( - out, t3.toExpr(), subproof[1].toExpr(), map); - out << " "; - out << "(symm _ _ _ " << ss.str() << ")"; - out << "))"; - } - } - } - - out << ")"; - return ret; - } - else - { - Debug("pf::array") << "In the case of NEGATIVE ROW" << std::endl; - - Debug("pf::array") << "pf.d_children[0]->d_node is: " - << pf.d_children[0]->d_node << std::endl; - - // This is the case where (i == k), and the sub-proof explains why - // ((a[i]:=t)[k] != a[k]) - - // If we wanted to remove the need for "negativerow", we would need to - // prove i==k using a new satlem. We would: - // 1. Create a new satlem. - // 2. Assume that i != k - // 3. Apply ROW to show that ((a[i]:=t)[k] == a[k]) - // 4. Contradict this with the fact that ((a[i]:=t)[k] != a[k]), - // obtaining our contradiction - - TNode t1, t2, t3, t4; - Node ret; - - // pf.d_node is an equality, i==k. - t1 = pf.d_node[0]; - t2 = pf.d_node[1]; - - // pf.d_children[0]->d_node will have the form: (not (= (select (store - // a_565 i7 e_566) i1) (select a_565 i1))), - // or its symmetrical version. - - unsigned side; - if (pf.d_children[0]->d_node[0][0].getKind() == kind::SELECT - && pf.d_children[0]->d_node[0][0][0].getKind() == kind::STORE) - { - side = 0; - } - else if (pf.d_children[0]->d_node[0][1].getKind() == kind::SELECT - && pf.d_children[0]->d_node[0][1][0].getKind() == kind::STORE) - { - side = 1; - } - else - { - Unreachable(); - } - - Debug("pf::array") << "Side is: " << side << std::endl; - - // The array's index and element types will come from the subproof... - t3 = pf.d_children[0]->d_node[0][side][0][0]; - t4 = pf.d_children[0]->d_node[0][side][0][2]; - ret = pf.d_node; - - // The order of indices needs to match; we might have to swap t1 and t2 - // and then apply symmetry. - bool swap = (t2 == pf.d_children[0]->d_node[0][side][0][1]); - - Debug("mgd") << "t1 " << t1 << "\nt2 " << t2 << "\nt3 " << t3 << "\nt4 " - << t4 << "\n"; - - Assert(pf.d_children.size() == 1); - std::stringstream ss; - Node subproof = - toStreamRecLFSC(ss, tp, *(pf.d_children[0]), tb + 1, map); - - Debug("pf::array") << "Subproof is: " << ss.str() << std::endl; - - if (swap) - { - out << "(symm _ _ _ "; - } - - out << "(negativerow _ _ "; - tp->printTerm(swap ? t2.toExpr() : t1.toExpr(), out, map); - out << " "; - tp->printTerm(swap ? t1.toExpr() : t2.toExpr(), out, map); - out << " "; - tp->printTerm(t3.toExpr(), out, map); - out << " "; - tp->printTerm(t4.toExpr(), out, map); - out << " "; - - if (side != 0) - { - out << "(negsymm _ _ _ " << ss.str() << ")"; - } - else - { - out << ss.str(); - } - - out << ")"; - - if (swap) - { - out << ") "; - } - - return ret; - } - } - else if (pf.d_id == d_reasonRow1) - { - 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; - } - else if (pf.d_id == d_reasonExt) { - Assert(pf.d_node.getKind() == kind::NOT); - Assert(pf.d_node[0].getKind() == kind::EQUAL); - Assert(pf.d_children.size() == 1); - std::shared_ptr<theory::eq::EqProof> child_proof = pf.d_children[0]; - Assert(child_proof->d_node.getKind() == kind::NOT); - Assert(child_proof->d_node[0].getKind() == kind::EQUAL); - - Debug("mgd") << "EXT lemma: " << pf.d_node << std::endl; - - TNode t1, t2, t3; - t1 = child_proof->d_node[0][0]; - t2 = child_proof->d_node[0][1]; - t3 = pf.d_node[0][0][1]; - - Debug("mgd") << "t1 " << t1 << "\nt2 " << t2 << "\nt3 " << t3 << "\n"; - - out << "(or_elim_1 _ _ "; - out << ProofManager::getLitName(child_proof->d_node[0]); - out << " "; - out << ProofManager::getArrayProof()->skolemToLiteral(t3.toExpr()); - out << ")"; - - return pf.d_node; - } - - else { - 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; - } -} - } -} - -ArrayProof::ArrayProof(theory::arrays::TheoryArrays* arrays, TheoryProofEngine* pe) - : TheoryProof(arrays, pe) -{} - -theory::TheoryId ArrayProof::getTheoryId() { return theory::THEORY_ARRAYS; } -void ArrayProof::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); - } - - if (term.getKind() == kind::SELECT && term.getType().isBoolean()) { - // Ensure cnf literals - Node asNode(term); - ProofManager::currentPM()->ensureLiteral( - asNode.eqNode(NodeManager::currentNM()->mkConst(true))); - ProofManager::currentPM()->ensureLiteral( - asNode.eqNode(NodeManager::currentNM()->mkConst(false))); - } - - // recursively declare all other terms - for (unsigned i = 0; i < term.getNumChildren(); ++i) { - // could belong to other theories - d_proofEngine->registerTerm(term[i]); - } -} - -std::string ArrayProof::skolemToLiteral(Expr skolem) { - Debug("pf::array") << "ArrayProof::skolemToLiteral( " << skolem << ")" << std::endl; - Assert(d_skolemToLiteral.find(skolem) != d_skolemToLiteral.end()); - return d_skolemToLiteral[skolem]; -} - -void LFSCArrayProof::printOwnedTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) -{ - Assert(theory::Theory::theoryOf(term) == theory::THEORY_ARRAYS); - - if (theory::Theory::theoryOf(term) != theory::THEORY_ARRAYS) { - // We can get here, for instance, if there's a (select ite ...), e.g. a non-array term - // hiding as a subterm of an array term. In that case, send it back to the dispatcher. - d_proofEngine->printBoundTerm(term, os, map); - return; - } - - if (term.getKind() == kind::VARIABLE || term.getKind() == kind::SKOLEM) { - os << term; - return; - } - - Assert((term.getKind() == kind::SELECT) - || (term.getKind() == kind::PARTIAL_SELECT_0) - || (term.getKind() == kind::PARTIAL_SELECT_1) - || (term.getKind() == kind::STORE)); - - switch (term.getKind()) { - case kind::SELECT: { - Assert(term.getNumChildren() == 2); - - bool convertToBool = (term[1].getType().isBoolean() && !d_proofEngine->printsAsBool(term[1])); - - os << "(apply _ _ (apply _ _ (read "; - printSort(ArrayType(term[0].getType()).getIndexType(), os); - os << " "; - printSort(ArrayType(term[0].getType()).getConstituentType(), os); - os << ") "; - printTerm(term[0], os, map); - os << ") "; - if (convertToBool) os << "(f_to_b "; - printTerm(term[1], os, map); - if (convertToBool) os << ")"; - os << ") "; - return; - } - - case kind::PARTIAL_SELECT_0: - Assert(term.getNumChildren() == 1); - os << "(read "; - printSort(ArrayType(term[0].getType()).getIndexType(), os); - os << " "; - printSort(ArrayType(term[0].getType()).getConstituentType(), os); - os << ") "; - return; - - case kind::PARTIAL_SELECT_1: - Debug("pf::array") << "This branch has not beed tested yet." << std::endl; - Unreachable(); - - Assert(term.getNumChildren() == 1); - os << "(apply _ _ (read "; - printSort(ArrayType(term[0].getType()).getIndexType(), os); - os << " "; - printSort(ArrayType(term[0].getType()).getConstituentType(), os); - os << ") "; - printTerm(term[0], os, map); - os << ") "; - return; - - case kind::STORE: - os << "(apply _ _ (apply _ _ (apply _ _ (write "; - printSort(ArrayType(term[0].getType()).getIndexType(), os); - os << " "; - printSort(ArrayType(term[0].getType()).getConstituentType(), os); - os << ") "; - printTerm(term[0], os, map); - os << ") "; - printTerm(term[1], os, map); - os << ") "; - printTerm(term[2], os, map); - os << ") "; - return; - - default: - Unreachable(); - return; - } -} - -void LFSCArrayProof::printOwnedSort(Type type, std::ostream& os) { - Debug("pf::array") << std::endl << "(pf::array) LFSCArrayProof::printOwnedSort: type is: " << type << std::endl; - Assert(type.isArray() || type.isSort()); - if (type.isArray()){ - ArrayType array_type(type); - - Debug("pf::array") << "LFSCArrayProof::printOwnedSort: type is an array. Index type: " - << array_type.getIndexType() - << ", element type: " << array_type.getConstituentType() << std::endl; - - os << "(Array "; - printSort(array_type.getIndexType(), os); - os << " "; - printSort(array_type.getConstituentType(), os); - os << ")"; - } else { - os << type; - } -} - -void LFSCArrayProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map) { - os << " ;; Array Theory Lemma \n;;"; - for (unsigned i = 0; i < lemma.size(); ++i) { - os << lemma[i] <<" "; - } - os <<"\n"; - //os << " (clausify_false trust)"; - ArrayProof::printTheoryLemmaProof(lemma, os, paren, map); -} - -void LFSCArrayProof::printSortDeclarations(std::ostream& os, std::ostream& paren) { - // declaring the sorts - for (TypeSet::const_iterator it = d_sorts.begin(); it != d_sorts.end(); ++it) { - if (!ProofManager::currentPM()->wasPrinted(*it)) { - os << "(% " << *it << " sort\n"; - paren << ")"; - ProofManager::currentPM()->markPrinted(*it); - } - } -} - -void LFSCArrayProof::printTermDeclarations(std::ostream& os, std::ostream& paren) { - Debug("pf::array") << "Arrays declaring terms..." << std::endl; - - for (ExprSet::const_iterator it = d_declarations.begin(); it != d_declarations.end(); ++it) { - Expr term = *it; - - Assert(term.getType().isArray() || term.isVariable()); - - Debug("pf::array") << "LFSCArrayProof::printDeclarations: term is: " << term - << ". It's type is: " << term.getType() - << std::endl; - - if (term.getType().isArray()){ - ArrayType array_type(term.getType()); - - Debug("pf::array") << "LFSCArrayProof::printDeclarations: term is an array. Index type: " - << array_type.getIndexType() - << ", element type: " << array_type.getConstituentType() << std::endl; - - os << "(% " << ProofManager::sanitize(term) << " "; - os << "(term "; - os << "(Array "; - - printSort(array_type.getIndexType(), os); - os << " "; - printSort(array_type.getConstituentType(), os); - - os << "))\n"; - paren << ")"; - } else { - Assert(term.isVariable()); - if (ProofManager::getSkolemizationManager()->isSkolem(*it)) { - Debug("pf::array") << "This term is a skoelm!" << std::endl; - d_skolemDeclarations.insert(*it); - } else { - os << "(% " << ProofManager::sanitize(term) << " "; - os << "(term "; - os << term.getType() << ")\n"; - paren << ")"; - } - } - } - - Debug("pf::array") << "Declaring terms done!" << std::endl; -} - -void LFSCArrayProof::printDeferredDeclarations(std::ostream& os, std::ostream& paren) { - Debug("pf::array") << "Array: print deferred declarations called" << std::endl; - - unsigned count = 1; - for (ExprSet::const_iterator it = d_skolemDeclarations.begin(); it != d_skolemDeclarations.end(); ++it) { - Expr term = *it; - Node equality = ProofManager::getSkolemizationManager()->getDisequality(*it); - - Debug("pf::array") << "LFSCArrayProof::printDeferredDeclarations: term is: " << *it << std::endl - << "It is a witness for: " << equality << std::endl; - - std::ostringstream newSkolemLiteral; - newSkolemLiteral << ".sl" << count++; - std::string skolemLiteral = newSkolemLiteral.str(); - - d_skolemToLiteral[*it] = skolemLiteral; - - Debug("pf::array") << "LFSCArrayProof::printDeferredDeclarations: new skolem literal is: " << skolemLiteral << std::endl; - - Assert(equality.getKind() == kind::NOT); - Assert(equality[0].getKind() == kind::EQUAL); - - Node array_one = equality[0][0]; - Node array_two = equality[0][1]; - - ProofLetMap map; - os << "(ext _ _ "; - printTerm(array_one.toExpr(), os, map); - os << " "; - printTerm(array_two.toExpr(), os, map); - os << " (\\ "; - os << ProofManager::sanitize(*it); - os << " (\\ "; - os << skolemLiteral.c_str(); - os << "\n"; - - paren << ")))"; - } -} - -void LFSCArrayProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) { - // Nothing to do here at this point. -} - -bool LFSCArrayProof::printsAsBool(const Node &n) -{ - if (n.getKind() == kind::SELECT) - return true; - - return false; -} - -} /* CVC4 namespace */ diff --git a/src/proof/array_proof.h b/src/proof/array_proof.h deleted file mode 100644 index ffcff165a..000000000 --- a/src/proof/array_proof.h +++ /dev/null @@ -1,121 +0,0 @@ -/********************* */ -/*! \file array_proof.h - ** \verbatim - ** Top contributors (to current version): - ** Tim King, Mathias Preiner, Guy Katz - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. 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 <memory> -#include <unordered_set> - -#include "expr/expr.h" -#include "proof/proof_manager.h" -#include "proof/theory_proof.h" -#include "theory/arrays/theory_arrays.h" -#include "theory/uf/equality_engine.h" - -namespace CVC4 { - -// Proof object outputted by TheoryARRAY. -class ProofArray : public Proof { - public: - ProofArray(std::shared_ptr<theory::eq::EqProof> pf, unsigned row, - unsigned row1, unsigned ext); - - void registerSkolem(Node equality, Node skolem); - - void toStream(std::ostream& out) const override; - void toStream(std::ostream& out, const ProofLetMap& map) const override; - - private: - void toStreamLFSC(std::ostream& out, - TheoryProof* tp, - const theory::eq::EqProof& pf, - const ProofLetMap& map) const; - - Node toStreamRecLFSC(std::ostream& out, - TheoryProof* tp, - const theory::eq::EqProof& pf, - unsigned tb, - const ProofLetMap& map) const; - - // It is simply an equality engine proof. - std::shared_ptr<theory::eq::EqProof> d_proof; - - /** Merge tag for ROW applications */ - unsigned d_reasonRow; - /** Merge tag for ROW1 applications */ - unsigned d_reasonRow1; - /** Merge tag for EXT applications */ - unsigned d_reasonExt; -}; - -namespace theory { -namespace arrays{ -class TheoryArrays; -} /* namespace CVC4::theory::arrays */ -} /* namespace CVC4::theory */ - -typedef std::unordered_set<Type, TypeHashFunction > TypeSet; - -class ArrayProof : public TheoryProof { - // TODO: whatever goes in this theory -protected: - TypeSet d_sorts; // all the uninterpreted sorts in this theory - ExprSet d_declarations; // all the variable/function declarations - ExprSet d_skolemDeclarations; // all the skolem variable declarations - std::map<Expr, std::string> d_skolemToLiteral; - theory::TheoryId getTheoryId() override; - - public: - ArrayProof(theory::arrays::TheoryArrays* arrays, TheoryProofEngine* proofEngine); - - std::string skolemToLiteral(Expr skolem); - - void registerTerm(Expr term) override; -}; - -class LFSCArrayProof : public ArrayProof { -public: - LFSCArrayProof(theory::arrays::TheoryArrays* arrays, TheoryProofEngine* proofEngine) - : ArrayProof(arrays, proofEngine) - {} - - void printOwnedTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) override; - void printOwnedSort(Type type, std::ostream& os) override; - void printTheoryLemmaProof(std::vector<Expr>& lemma, - std::ostream& os, - std::ostream& paren, - const ProofLetMap& map) override; - void printSortDeclarations(std::ostream& os, std::ostream& paren) override; - void printTermDeclarations(std::ostream& os, std::ostream& paren) override; - void printDeferredDeclarations(std::ostream& os, - std::ostream& paren) override; - void printAliasingDeclarations(std::ostream& os, - std::ostream& paren, - const ProofLetMap& globalLetMap) override; - - bool printsAsBool(const Node& n) override; -}; - - -}/* CVC4 namespace */ - -#endif /* CVC4__ARRAY__PROOF_H */ diff --git a/src/proof/bitvector_proof.cpp b/src/proof/bitvector_proof.cpp deleted file mode 100644 index 98e3300f5..000000000 --- a/src/proof/bitvector_proof.cpp +++ /dev/null @@ -1,792 +0,0 @@ -/********************* */ -/*! \file bitvector_proof.cpp - ** \verbatim - ** Top contributors (to current version): - ** Liana Hadarean, Guy Katz, Alex Ozdemir - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** Contains implementions (e.g. code for printing bitblasting bindings that is - ** common to all kinds of bitvector proofs. - **/ - -#include "proof/bitvector_proof.h" -#include "options/bv_options.h" -#include "options/proof_options.h" -#include "proof/proof_output_channel.h" -#include "proof/theory_proof.h" -#include "prop/sat_solver_types.h" -#include "theory/bv/bitblast/bitblaster.h" -#include "theory/bv/theory_bv.h" - -namespace CVC4 { - -namespace proof { -BitVectorProof::BitVectorProof(theory::bv::TheoryBV* bv, - TheoryProofEngine* proofEngine) - : TheoryProof(bv, proofEngine), - d_declarations(), - d_seenBBTerms(), - d_bbTerms(), - d_bbAtoms(), - d_bitblaster(nullptr), - d_useConstantLetification(false), - d_cnfProof() -{ -} - -void BitVectorProof::setBitblaster(theory::bv::TBitblaster<Node>* bb) -{ - Assert(d_bitblaster == NULL); - d_bitblaster = bb; -} - -void BitVectorProof::registerTermBB(Expr term) -{ - Debug("pf::bv") << "BitVectorProof::registerTermBB( " << term - << " )" << std::endl; - - if (d_seenBBTerms.find(term) != d_seenBBTerms.end()) return; - - d_seenBBTerms.insert(term); - d_bbTerms.push_back(term); - - // If this term gets used in the final proof, we will want to register it. - // However, we don't know this at this point; and when the theory proof engine - // sees it, if it belongs to another theory, it won't register it with this - // proof. So, we need to tell the engine to inform us. - - if (theory::Theory::theoryOf(term) != theory::THEORY_BV) - { - Debug("pf::bv") << "\tMarking term " << term - << " for future BV registration" << std::endl; - d_proofEngine->markTermForFutureRegistration(term, theory::THEORY_BV); - } -} - -void BitVectorProof::registerAtomBB(Expr atom, Expr atom_bb) { - Debug("pf::bv") << "BitVectorProof::registerAtomBB( " << atom - << ", " << atom_bb << " )" << std::endl; - - Expr def = atom.eqExpr(atom_bb); - d_bbAtoms.insert(std::make_pair(atom, def)); - registerTerm(atom); - - // Register the atom's terms for bitblasting - registerTermBB(atom[0]); - registerTermBB(atom[1]); -} - -void BitVectorProof::registerTerm(Expr term) { - Debug("pf::bv") << "BitVectorProof::registerTerm( " << term << " )" - << std::endl; - - if (options::lfscLetification() && term.isConst() - && term.getType().isBitVector()) - { - if (d_constantLetMap.find(term) == d_constantLetMap.end()) { - std::ostringstream name; - name << "letBvc" << d_constantLetMap.size(); - d_constantLetMap[term] = name.str(); - } - } - - d_usedBB.insert(term); - - if (theory::Theory::isLeafOf(term, theory::THEORY_BV) && !term.isConst()) - { - d_declarations.insert(term); - } - - Debug("pf::bv") << "Going to register children: " << std::endl; - for (unsigned i = 0; i < term.getNumChildren(); ++i) { - Debug("pf::bv") << "\t" << term[i] << std::endl; - } - - // 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) -{ - Debug("pf::bv") << "BitVectorProof::getBBTermName( " << expr << " ) = bt" - << expr.getId() << std::endl; - std::ostringstream os; - os << "bt" << expr.getId(); - return os.str(); -} - -void BitVectorProof::printOwnedTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) -{ - Debug("pf::bv") << std::endl - << "(pf::bv) BitVectorProof::printOwnedTerm( " << term - << " ), theory is: " << theory::Theory::theoryOf(term) - << std::endl; - - Assert(theory::Theory::theoryOf(term) == theory::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, map); - return; - } - - case kind::VARIABLE: { - os << "(a_var_bv " << utils::getSize(term)<< " " << ProofManager::sanitize(term) << ")"; - return; - } - - case kind::SKOLEM: { - - // TODO: we need to distinguish between "real" skolems (e.g. from array) and "fake" skolems, - // like ITE terms. Is there a more elegant way? - - if (ProofManager::getSkolemizationManager()->isSkolem(term)) { - os << ProofManager::sanitize(term); - } else { - os << "(a_var_bv " << utils::getSize(term)<< " " << ProofManager::sanitize(term) << ")"; - } - return; - } - - default: - Unreachable(); - } -} - -void BitVectorProof::printEmptyClauseProof(std::ostream& os, - std::ostream& paren) -{ - Assert(options::bitblastMode() == options::BitblastMode::EAGER) - << "the BV theory should only be proving bottom directly in the eager " - "bitblasting mode"; -} - -void BitVectorProof::printBitOf(Expr term, - std::ostream& os, - const ProofLetMap& map) -{ - Assert(term.getKind() == kind::BITVECTOR_BITOF); - unsigned bit = term.getOperator().getConst<BitVectorBitOf>().d_bitIndex; - Expr var = term[0]; - - Debug("pf::bv") << "BitVectorProof::printBitOf( " << term << " ), " - << "bit = " << bit << ", var = " << var << std::endl; - - os << "(bitof "; - os << d_exprToVariableName[var]; - os << " " << bit << ")"; -} - -void BitVectorProof::printConstant(Expr term, std::ostream& os) -{ - Assert(term.isConst()); - os << "(a_bv " << utils::getSize(term) << " "; - - if (d_useConstantLetification) { - os << d_constantLetMap[term] << ")"; - } else { - 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 BitVectorProof::printOperatorNary(Expr term, - std::ostream& os, - const ProofLetMap& map) -{ - std::string op = utils::toLFSCKindTerm(term); - 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 BitVectorProof::printOperatorUnary(Expr term, - std::ostream& os, - const ProofLetMap& map) -{ - os <<"("; - os << utils::toLFSCKindTerm(term) << " " << utils::getSize(term) <<" "; - os << " "; - d_proofEngine->printBoundTerm(term[0], os, map); - os <<")"; -} - -void BitVectorProof::printPredicate(Expr term, - std::ostream& os, - const ProofLetMap& map) -{ - os <<"("; - os << utils::toLFSCKindTerm(term) << " " << utils::getSize(term[0]) <<" "; - os << " "; - d_proofEngine->printBoundTerm(term[0], os, map); - os << " "; - d_proofEngine->printBoundTerm(term[1], os, map); - os <<")"; -} - -void BitVectorProof::printOperatorParametric(Expr term, - std::ostream& os, - const ProofLetMap& map) -{ - os <<"("; - os << utils::toLFSCKindTerm(term) << " " << utils::getSize(term) <<" "; - os <<" "; - if (term.getKind() == kind::BITVECTOR_REPEAT) { - unsigned amount = - term.getOperator().getConst<BitVectorRepeat>().d_repeatAmount; - os << amount <<" _ "; - } - if (term.getKind() == kind::BITVECTOR_SIGN_EXTEND) { - unsigned amount = - term.getOperator().getConst<BitVectorSignExtend>().d_signExtendAmount; - os << amount <<" _ "; - } - - if (term.getKind() == kind::BITVECTOR_ZERO_EXTEND) { - unsigned amount = - term.getOperator().getConst<BitVectorZeroExtend>().d_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 BitVectorProof::printOwnedSort(Type type, std::ostream& os) -{ - Debug("pf::bv") << std::endl - << "(pf::bv) BitVectorProof::printOwnedSort( " << type << " )" - << std::endl; - Assert(type.isBitVector()); - unsigned width = utils::getSize(type); - os << "(BitVec " << width << ")"; -} - -void BitVectorProof::printSortDeclarations(std::ostream& os, - std::ostream& paren) -{ - // Nothing to do here at this point. -} - -void BitVectorProof::printTermDeclarations(std::ostream& os, - std::ostream& paren) -{ - ExprSet::const_iterator it = d_declarations.begin(); - ExprSet::const_iterator end = d_declarations.end(); - for (; it != end; ++it) { - if ((it->isVariable() || it->isConst()) && !ProofManager::getSkolemizationManager()->isSkolem(*it)) { - d_exprToVariableName[*it] = ProofManager::sanitize(*it); - } else { - std::string newAlias = assignAlias(*it); - d_exprToVariableName[*it] = newAlias; - } - - os << "(% " << d_exprToVariableName[*it] <<" var_bv" << "\n"; - paren <<")"; - } -} - -void BitVectorProof::printDeferredDeclarations(std::ostream& os, - std::ostream& paren) -{ - if (options::lfscLetification()) { - os << std::endl << ";; BV const letification\n" << std::endl; - std::map<Expr,std::string>::const_iterator it; - for (it = d_constantLetMap.begin(); it != d_constantLetMap.end(); ++it) { - os << "\n(@ " << it->second << " "; - std::ostringstream localParen; - int size = utils::getSize(it->first); - for (int i = size - 1; i >= 0; --i) { - os << "(bvc "; - os << (utils::getBit(it->first, i) ? "b1" : "b0") << " "; - localParen << ")"; - } - os << "bvn"; - os << localParen.str(); - paren << ")"; - } - os << std::endl; - - d_useConstantLetification = true; - } -} - -void BitVectorProof::printAliasingDeclarations(std::ostream& os, - std::ostream& paren, - const ProofLetMap& globalLetMap) -{ - // Print "trust" statements to bind complex bv variables to their associated terms - - ExprToString::const_iterator it = d_assignedAliases.begin(); - ExprToString::const_iterator end = d_assignedAliases.end(); - - for (; it != end; ++it) { - Debug("pf::bv") << "Printing aliasing declaration for: " << *it << std::endl; - std::stringstream declaration; - declaration << ".fbvd" << d_aliasToBindDeclaration.size(); - d_aliasToBindDeclaration[it->second] = declaration.str(); - - os << "(th_let_pf _ "; - - os << "(trust_f "; - os << "(= (BitVec " << utils::getSize(it->first) << ") "; - os << "(a_var_bv " << utils::getSize(it->first) << " " << it->second << ") "; - d_proofEngine->printBoundTerm(it->first, os, globalLetMap); - os << ")) "; - os << "(\\ "<< d_aliasToBindDeclaration[it->second] << "\n"; - paren << "))"; - } - - os << "\n"; -} - -void BitVectorProof::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::Theory::isLeafOf(term, theory::THEORY_BV) && !term.isConst()) - { - // A term is a leaf if it has no children, or if it belongs to another theory - os << "(bv_bbl_var " << utils::getSize(term) << " " << d_exprToVariableName[term]; - os << " _)"; - return; - } - - switch(kind) { - case kind::CONST_BITVECTOR : { - os << "(bv_bbl_const "<< utils::getSize(term) <<" _ "; - std::ostringstream paren; - int size = utils::getSize(term); - if (d_useConstantLetification) { - os << d_constantLetMap[term] << ")"; - } else { - 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 : { - Debug("pf::bv") << "Bitblasing kind = " << kind << std::endl; - - for (int i = term.getNumChildren() - 1; i > 0; --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>().d_repeatAmount; - os << amount; - } - if (term.getKind() == kind::BITVECTOR_SIGN_EXTEND) { - unsigned amount = - term.getOperator().getConst<BitVectorSignExtend>().d_signExtendAmount; - os << amount; - } - - if (term.getKind() == kind::BITVECTOR_ZERO_EXTEND) { - unsigned amount = - term.getOperator().getConst<BitVectorZeroExtend>().d_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() << "BitVectorProof Unknown operator"; - } -} - -void BitVectorProof::printAtomBitblasting(Expr atom, - std::ostream& os, - bool swap) -{ - 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: { - Debug("pf::bv") << "Bitblasing kind = " << kind << std::endl; - - os << "(bv_bbl_" << utils::toLFSCKindTerm(atom); - - if (swap) {os << "_swap";} - - os << " _ _ _ _ _ _ "; - os << getBBTermName(atom[0]); - os << " "; - os << getBBTermName(atom[1]); - os << ")"; - - return; - } - default: Unreachable() << "BitVectorProof Unknown atom kind"; - } -} - -void BitVectorProof::printAtomBitblastingToFalse(Expr atom, std::ostream& os) -{ - Assert(atom.getKind() == kind::EQUAL); - - os << "(bv_bbl_=_false"; - os << " _ _ _ _ _ _ "; - os << getBBTermName(atom[0]); - - os << " "; - - os << getBBTermName(atom[1]); - - os << ")"; -} - -void BitVectorProof::printBitblasting(std::ostream& os, std::ostream& paren) -{ - // bit-blast terms - { - Debug("pf::bv") - << "BitVectorProof::printBitblasting: the bitblasted terms are: " - << std::endl; - 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()) { - Debug("pf::bv") << "\t" << *it << "\t(UNUSED)" << std::endl; - } else { - Debug("pf::bv") << "\t" << *it << std::endl; - } - } - - Debug("pf::bv") << std::endl; - } - - 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() != options::BitblastMode::EAGER) - continue; - - // Is this term has an alias, we inject it through the decl_bblast statement - if (hasAlias(*it)) { - os << "(decl_bblast_with_alias _ _ _ _ "; - printTermBitblasting(*it, os); - os << " " << d_aliasToBindDeclaration[d_assignedAliases[*it]] << " "; - os << "(\\ "<< getBBTermName(*it); - os << "\n"; - paren <<"))"; - } else { - os << "(decl_bblast _ _ _ "; - printTermBitblasting(*it, os); - os << "(\\ "<< getBBTermName(*it); - os << "\n"; - paren <<"))"; - } - } - // 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() != options::BitblastMode::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 { - Assert(ait->first == ait->second[0]); - - bool swap = false; - if (ait->first.getKind() == kind::EQUAL) { - Expr bitwiseEquivalence = ait->second[1]; - if ((bitwiseEquivalence.getKind() == kind::CONST_BOOLEAN) && !bitwiseEquivalence.getConst<bool>()) { - printAtomBitblastingToFalse(ait->first, os); - } else { - if (bitwiseEquivalence.getKind() != kind::AND) { - // Just one bit - if (bitwiseEquivalence.getNumChildren() > 0 && bitwiseEquivalence[0].getKind() == kind::BITVECTOR_BITOF) { - swap = (ait->first[1] == bitwiseEquivalence[0][0]); - } - } else { - // Multiple bits - if (bitwiseEquivalence[0].getNumChildren() > 0 && - bitwiseEquivalence[0][0].getKind() == kind::BITVECTOR_BITOF) { - swap = (ait->first[1] == bitwiseEquivalence[0][0][0]); - } else if (bitwiseEquivalence[0].getNumChildren() > 0 && - bitwiseEquivalence[0][1].getKind() == kind::BITVECTOR_BITOF) { - swap = (ait->first[0] == bitwiseEquivalence[0][1][0]); - } - } - - printAtomBitblasting(ait->first, os, swap); - } - } else { - printAtomBitblasting(ait->first, os, swap); - } - } - - os <<"(\\ " << ProofManager::getPreprocessedAssertionName(ait->second) <<"\n"; - paren <<"))"; - } -} - -theory::TheoryId BitVectorProof::getTheoryId() { return theory::THEORY_BV; } - -const std::set<Node>* BitVectorProof::getAtomsInBitblastingProof() -{ - return &d_atomsInBitblastingProof; -} - -std::string BitVectorProof::assignAlias(Expr expr) -{ - Assert(d_exprToVariableName.find(expr) == d_exprToVariableName.end()); - - std::stringstream ss; - ss << "fbv" << d_assignedAliases.size(); - Debug("pf::bv") << "assignAlias( " << expr << ") = " << ss.str() << std::endl; - d_assignedAliases[expr] = ss.str(); - return ss.str(); -} - -bool BitVectorProof::hasAlias(Expr expr) -{ - return d_assignedAliases.find(expr) != d_assignedAliases.end(); -} - -void BitVectorProof::printConstantDisequalityProof( - std::ostream& os, Expr c1, Expr c2, const ProofLetMap& globalLetMap) -{ - Assert(c1.isConst()); - Assert(c2.isConst()); - Assert(utils::getSize(c1) == utils::getSize(c2)); - - os << "(bv_disequal_constants " << utils::getSize(c1) << " "; - - std::ostringstream paren; - - for (int i = utils::getSize(c1) - 1; i >= 0; --i) { - os << "(bvc "; - os << (utils::getBit(c1, i) ? "b1" : "b0") << " "; - paren << ")"; - } - os << "bvn"; - os << paren.str(); - - os << " "; - - for (int i = utils::getSize(c2) - 1; i >= 0; --i) { - os << "(bvc "; - os << (utils::getBit(c2, i) ? "b1" : "b0") << " "; - - } - os << "bvn"; - os << paren.str(); - - os << ")"; -} - -void BitVectorProof::printRewriteProof(std::ostream& os, - const Node& n1, - const Node& n2) -{ - ProofLetMap emptyMap; - os << "(rr_bv_default "; - d_proofEngine->printBoundTerm(n2.toExpr(), os, emptyMap); - os << " "; - d_proofEngine->printBoundTerm(n1.toExpr(), os, emptyMap); - os << ")"; -} - -} // namespace proof - -} // namespace CVC4 diff --git a/src/proof/bitvector_proof.h b/src/proof/bitvector_proof.h deleted file mode 100644 index 9a9071e58..000000000 --- a/src/proof/bitvector_proof.h +++ /dev/null @@ -1,280 +0,0 @@ -/********************* */ -/*! \file bitvector_proof.h - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Mathias Preiner, Liana Hadarean - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief Bitvector proof base class - ** - ** Contains code (e.g. proof printing code) which is common to all bitvector - *proofs. - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__BITVECTOR_PROOF_H -#define CVC4__BITVECTOR_PROOF_H - -#include <set> -#include <unordered_map> -#include <unordered_set> -#include <vector> - -#include "expr/expr.h" -#include "proof/cnf_proof.h" -#include "proof/theory_proof.h" -#include "prop/sat_solver.h" -#include "theory/bv/theory_bv.h" - -// Since TBitblaster and BitVectorProof are cyclically dependent, we need this -// forward declaration -namespace CVC4 { -namespace theory { -namespace bv { -template <class T> -class TBitblaster; -} -} // namespace theory -} // namespace CVC4 - -namespace CVC4 { - -namespace proof { - -typedef std::unordered_set<Expr, ExprHashFunction> ExprSet; -typedef std::unordered_map<Expr, ClauseId, ExprHashFunction> ExprToClauseId; -typedef std::unordered_map<Expr, unsigned, ExprHashFunction> ExprToId; -typedef std::unordered_map<Expr, Expr, ExprHashFunction> ExprToExpr; -typedef std::unordered_map<Expr, std::string, ExprHashFunction> ExprToString; - -/** - * A bitvector proof is best understood as having - * - * 1. A declaration of a "bitblasted formulas" -- boolean formulas - * that are each translations of a BV-literal (a comparison between BVs). - * - * (and a proof that each "bitblasted formula" is implied by the - * corresponding BV literal) - * - * 2. A declaration of a cnf formula equisatisfiable to the bitblasted - * formula - * - * (and a proof that each clause is implied by some bitblasted formula) - * - * 3. A proof of UNSAT from the clauses. - * - * This class is responsible for 1 & 2. The proof of UNSAT is delegated to a - * subclass. - */ -class BitVectorProof : public TheoryProof -{ - protected: - BitVectorProof(theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine); - virtual ~BitVectorProof(){}; - - // Set of BV variables in the input. (e.g. "a" in [ a = 000 ] ^ [ a == 001 ]) - ExprSet d_declarations; - - // terms and formulas that are actually relevant to the proof - ExprSet d_usedBB; - - ExprSet d_seenBBTerms; // terms that need to be bit-blasted - std::vector<Expr> d_bbTerms; // order of bit-blasting - - /** atoms that need to be bit-blasted, - * BV-literals -> (BV-literals <=> bool formula) - * where a BV literal is a signed or unsigned comparison. - */ - ExprToExpr d_bbAtoms; - - // map from Expr representing normalized lemma to ClauseId in SAT solver - ExprToClauseId d_bbConflictMap; - - theory::bv::TBitblaster<Node>* d_bitblaster; - - /** In an LFSC proof the manifestation of this expression bit-level - * representation will have a string name. This method returns that name. - */ - std::string getBBTermName(Expr expr); - - /** A mapping from constant BV terms to identifiers that will refer to them in - * an LFSC proof, if constant-letification is enabled. - */ - std::map<Expr, std::string> d_constantLetMap; - - /** Should we introduced identifiers to refer to BV constant terms? It may - * reduce the textual size of a proof! - */ - bool d_useConstantLetification; - - /** Temporary storage for the set of nodes in the bitblasted formula which - * correspond to CNF variables eventually used in the proof of unsat on the - * CNF formula - */ - std::set<Node> d_atomsInBitblastingProof; - - /** - * Prints out - * (a) a declaration of bit-level interpretations corresponding to bits in - * the input BV terms. - * (b) a proof that the each BV literal entails a boolean formula on - * bitof expressions. - */ - void printBitblasting(std::ostream& os, std::ostream& paren); - - /** - * The proof that the bit-blasted SAT formula is correctly converted to CNF - */ - std::unique_ptr<CnfProof> d_cnfProof; - - theory::TheoryId getTheoryId() override; - - public: - void printOwnedTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) override; - - void printOwnedSort(Type type, std::ostream& os) override; - - /** - * Populate the d_atomsInBitblastingProof member. - * See its documentation - */ - virtual void calculateAtomsInBitblastingProof() = 0; - - /** - * Prints out a declaration of the bit-blasting, and the subsequent - * conversion of the result to CNF - * - * @param os the stream to print to - * @param paren a stream that will be placed at the back of the proof (for - * closing parens) - * @param letMap The let-map, which contains information about LFSC - * identifiers and the values they reference. - */ - virtual void printBBDeclarationAndCnf(std::ostream& os, - std::ostream& paren, - ProofLetMap& letMap) = 0; - - /** - * Prints a proof of the empty clause. - * - * @param os the stream to print to - * @param paren any parentheses to add to the end of the global proof - */ - virtual void printEmptyClauseProof(std::ostream& os, std::ostream& paren); - - /** - * Read the d_atomsInBitblastingProof member. - * See its documentation. - */ - const std::set<Node>* getAtomsInBitblastingProof(); - - void registerTermBB(Expr term); - - /** - * Informs the proof that the `atom` predicate was bitblasted into the - * `atom_bb` term. - * - * The `atom` term must be a comparison of bitvectors, and the `atom_bb` term - * a boolean formula on bitof expressions - */ - void registerAtomBB(Expr atom, Expr atom_bb); - - void registerTerm(Expr term) override; - - /** - * This must be done before registering any terms or atoms, since the CNF - * proof must reflect the result of bitblasting those - * - * Feeds the SAT solver's true and false variables into the CNF stream. - */ - virtual void initCnfProof(prop::CnfStream* cnfStream, - context::Context* cnf, - prop::SatVariable trueVar, - prop::SatVariable falseVar) = 0; - - CnfProof* getCnfProof() { return d_cnfProof.get(); } - - /** - * Attaches this BVP to the given SAT solver, initializing a SAT proof. - * - * This must be invoked before `initCnfProof` because a SAT proof must already - * exist to initialize a CNF proof. - */ - virtual void attachToSatSolver(prop::SatSolver& sat_solver) = 0; - - void setBitblaster(theory::bv::TBitblaster<Node>* bb); - - /** - * Kind of a mess. Used for resulution-based BVP's, where in eager mode this - * must be invoked before printing a proof of the empty clause. In lazy mode - * the behavior and purpose are both highly unclear. - * - * This exists as a virtual method of BitVectorProof, and not - * ResolutionBitVectorProof, because the machinery that invokes it is - * high-level enough that it doesn't know the difference between clausal and - * resolution proofs. - * - * TODO(aozdemir) figure out what is going on and clean this up - * Issue: https://github.com/CVC4/CVC4/issues/2789 - */ - virtual void finalizeConflicts(std::vector<Expr>& conflicts){}; - - private: - ExprToString d_exprToVariableName; - - ExprToString d_assignedAliases; - std::map<std::string, std::string> d_aliasToBindDeclaration; - std::string assignAlias(Expr expr); - bool hasAlias(Expr expr); - - // Functions for printing various BV terms. Helpers for BV's `printOwnedTerm` - void printConstant(Expr term, std::ostream& os); - void printOperatorNary(Expr term, std::ostream& os, const ProofLetMap& map); - void printOperatorUnary(Expr term, std::ostream& os, const ProofLetMap& map); - void printPredicate(Expr term, std::ostream& os, const ProofLetMap& map); - void printOperatorParametric(Expr term, std::ostream& os, const ProofLetMap& map); - void printBitOf(Expr term, std::ostream& os, const ProofLetMap& map); - - /** - * Prints the LFSC construction of a bblast_term for `term` - */ - void printTermBitblasting(Expr term, std::ostream& os); - - /** - * For a given BV-atom (a comparison), prints a proof that that comparison - * holds iff the bitblasted equivalent of it holds. - * Uses a side-condidition to do the bit-blasting. - */ - void printAtomBitblasting(Expr term, std::ostream& os, bool swap); - void printAtomBitblastingToFalse(Expr term, std::ostream& os); - - void printSortDeclarations(std::ostream& os, std::ostream& paren) override; - void printTermDeclarations(std::ostream& os, std::ostream& paren) override; - void printDeferredDeclarations(std::ostream& os, - std::ostream& paren) override; - void printAliasingDeclarations(std::ostream& os, - std::ostream& paren, - const ProofLetMap& globalLetMap) override; - - void printConstantDisequalityProof(std::ostream& os, - Expr c1, - Expr c2, - const ProofLetMap& globalLetMap) override; - void printRewriteProof(std::ostream& os, - const Node& n1, - const Node& n2) override; -}; - -} // namespace proof - -}/* CVC4 namespace */ - -#endif /* CVC4__BITVECTOR__PROOF_H */ diff --git a/src/proof/clausal_bitvector_proof.cpp b/src/proof/clausal_bitvector_proof.cpp deleted file mode 100644 index 21e8056ca..000000000 --- a/src/proof/clausal_bitvector_proof.cpp +++ /dev/null @@ -1,412 +0,0 @@ -/********************* */ -/*! \file clausal_bitvector_proof.cpp - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Mathias Preiner, Andres Noetzli - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief Bitvector proof using the DRAT proof format - ** - ** Contains DRAT-specific printing logic. - **/ - -#include "cvc4_private.h" - -#include <algorithm> -#include <iostream> -#include <iterator> -#include <map> - -#include "options/bv_options.h" -#include "proof/clausal_bitvector_proof.h" -#include "proof/dimacs.h" -#include "proof/drat/drat_proof.h" -#include "proof/er/er_proof.h" -#include "proof/lfsc_proof_printer.h" -#include "proof/lrat/lrat_proof.h" -#include "prop/sat_solver_types.h" -#include "smt/smt_statistics_registry.h" -#include "theory/bv/theory_bv.h" - -#if CVC4_USE_DRAT2ER -#include "drat2er_options.h" -#include "drat_trim_interface.h" -#endif - -namespace CVC4 { - -namespace proof { - -ClausalBitVectorProof::ClausalBitVectorProof(theory::bv::TheoryBV* bv, - TheoryProofEngine* proofEngine) - : BitVectorProof(bv, proofEngine), - d_clauses(), - d_originalClauseIndices(), - d_binaryDratProof(), - d_coreClauseIndices(), - d_dratTranslationStatistics(), - d_dratOptimizationStatistics() -{ -} - -void ClausalBitVectorProof::attachToSatSolver(prop::SatSolver& sat_solver) -{ - sat_solver.setClausalProofLog(this); -} - -void ClausalBitVectorProof::initCnfProof(prop::CnfStream* cnfStream, - context::Context* cnf, - prop::SatVariable trueVar, - prop::SatVariable falseVar) -{ - Assert(d_cnfProof == nullptr); - d_cnfProof.reset(new LFSCCnfProof(cnfStream, cnf, "bb")); - - // Create a clause which forces the true variable to be true, and register it - int trueClauseId = ClauseId(ProofManager::currentPM()->nextId()); - // with the CNF proof - d_cnfProof->registerTrueUnitClause(trueClauseId); - // and with (this) bit-vector proof - prop::SatClause c{prop::SatLiteral(trueVar, false)}; - registerUsedClause(trueClauseId, c); - - // The same for false. - int falseClauseId = ClauseId(ProofManager::currentPM()->nextId()); - d_cnfProof->registerFalseUnitClause(falseClauseId); - c[0] = prop::SatLiteral(falseVar, true); - registerUsedClause(falseClauseId, c); -} - -void ClausalBitVectorProof::registerUsedClause(ClauseId id, - prop::SatClause& clause) -{ - prop::SatClause& emplaced_clause = - d_clauses.emplace(id, clause).first->second; - canonicalizeClause(emplaced_clause); - d_originalClauseIndices.push_back(id); -}; - -void ClausalBitVectorProof::calculateAtomsInBitblastingProof() -{ - optimizeDratProof(); - - // Debug dump of DRAT Proof - if (Debug.isOn("bv::clausal")) - { - std::string serializedDratProof = d_binaryDratProof.str(); - Debug("bv::clausal") << "option: " << options::bvOptimizeSatProof() - << std::endl; - Debug("bv::clausal") << "binary DRAT proof byte count: " - << serializedDratProof.size() << std::endl; - Debug("bv::clausal") << "clause count: " << d_coreClauseIndices.size() - << std::endl; - } - - // Empty any old record of which atoms were used - d_atomsInBitblastingProof.clear(); - Assert(d_atomsInBitblastingProof.size() == 0); - - // For each used clause, ask the CNF proof which atoms are used in it - for (const ClauseId usedIdx : d_coreClauseIndices) - { - d_cnfProof->collectAtoms(&d_clauses.at(usedIdx), d_atomsInBitblastingProof); - } -} - -struct SatClausePointerComparator -{ - inline bool operator()(const prop::SatClause* const& l, - const prop::SatClause* const& r) const - { - prop::SatClauseLessThan cmp; - return cmp(*l, *r); - } -}; - -void ClausalBitVectorProof::optimizeDratProof() -{ - TimerStat::CodeTimer optimizeDratProofTimer{ - d_dratOptimizationStatistics.d_totalTime}; - if (options::bvOptimizeSatProof() == options::BvOptimizeSatProof::PROOF - || options::bvOptimizeSatProof() == options::BvOptimizeSatProof::FORMULA) - { - Debug("bv::clausal") << "Optimizing DRAT" << std::endl; - std::string formulaFilename("cvc4-dimacs-XXXXXX"); - std::string dratFilename("cvc4-drat-XXXXXX"); - std::string optDratFilename("cvc4-optimized-drat-XXXXXX"); - std::string optFormulaFilename("cvc4-optimized-formula-XXXXXX"); - - { - std::unique_ptr<std::fstream> formStream = openTmpFile(&formulaFilename); - const int64_t startPos = static_cast<int64_t>(formStream->tellp()); - printDimacs(*formStream, d_clauses, d_originalClauseIndices); - d_dratOptimizationStatistics.d_initialFormulaSize.setData( - static_cast<int64_t>(formStream->tellp()) - startPos); - formStream->close(); - } - - { - std::unique_ptr<std::fstream> dratStream = openTmpFile(&dratFilename); - const int64_t startPos = static_cast<int64_t>(dratStream->tellp()); - (*dratStream) << d_binaryDratProof.str(); - d_dratOptimizationStatistics.d_initialDratSize.setData( - static_cast<int64_t>(dratStream->tellp()) - startPos); - dratStream->close(); - } - - std::unique_ptr<std::fstream> optDratStream = openTmpFile(&optDratFilename); - std::unique_ptr<std::fstream> optFormulaStream = - openTmpFile(&optFormulaFilename); - -#if CVC4_USE_DRAT2ER - { - TimerStat::CodeTimer runDratTimeOptimizationTimer{ - d_dratOptimizationStatistics.d_toolTime}; - int dratTrimExitCode = - drat2er::drat_trim::OptimizeWithDratTrim(formulaFilename, - dratFilename, - optFormulaFilename, - optDratFilename, - drat2er::options::QUIET); - AlwaysAssert(dratTrimExitCode == 0) - << "drat-trim exited with " << dratTrimExitCode; - } -#else - Unimplemented() - << "Proof production when using CryptoMiniSat requires drat2er.\n" - << "Run contrib/get-drat2er, reconfigure with --drat2er, and rebuild"; -#endif - - { - d_binaryDratProof.str(""); - Assert(d_binaryDratProof.str().size() == 0); - - const int64_t startPos = static_cast<int64_t>(d_binaryDratProof.tellp()); - std::ifstream lratStream(optDratFilename); - std::copy(std::istreambuf_iterator<char>(lratStream), - std::istreambuf_iterator<char>(), - std::ostreambuf_iterator<char>(d_binaryDratProof)); - d_dratOptimizationStatistics.d_optimizedDratSize.setData( - static_cast<int64_t>(d_binaryDratProof.tellp()) - startPos); - } - - if (options::bvOptimizeSatProof() == options::BvOptimizeSatProof::FORMULA) - { - std::ifstream optFormulaInStream{optFormulaFilename}; - const int64_t startPos = static_cast<int64_t>(optFormulaInStream.tellg()); - std::vector<prop::SatClause> core = parseDimacs(optFormulaInStream); - d_dratOptimizationStatistics.d_optimizedFormulaSize.setData( - static_cast<int64_t>(optFormulaInStream.tellg()) - startPos); - - CodeTimer clauseMatchingTimer{ - d_dratOptimizationStatistics.d_clauseMatchingTime}; - - // Now we need to compute the clause indices for the UNSAT core. This is a - // bit difficult because drat-trim may have reordered clauses, and/or - // removed duplicate literals. We use literal sets as the canonical clause - // form. - // - // TODO (aozdemir) It may be better to use a hash map instead of a tree - // map here. - std::map<const prop::SatClause*, ClauseId, SatClausePointerComparator> - cannonicalClausesToIndices; - for (const auto& kv : d_clauses) - { - cannonicalClausesToIndices[&kv.second] = kv.first; - } - - d_coreClauseIndices.clear(); - - for (prop::SatClause& coreClause : core) - { - canonicalizeClause(coreClause); - d_coreClauseIndices.push_back( - cannonicalClausesToIndices.at(&coreClause)); - } - Debug("bv::clausal") << "Optimizing the DRAT proof and the formula" - << std::endl; - } - else - { - Debug("bv::clausal") << "Optimizing the DRAT proof but not the formula" - << std::endl; - d_coreClauseIndices = d_originalClauseIndices; - } - - optFormulaStream->close(); - - Assert(d_coreClauseIndices.size() > 0); - remove(formulaFilename.c_str()); - remove(dratFilename.c_str()); - remove(optDratFilename.c_str()); - remove(optFormulaFilename.c_str()); - Debug("bv::clausal") << "Optimized DRAT" << std::endl; - } - else - { - Debug("bv::clausal") << "Not optimizing the formula or the DRAT proof" - << std::endl; - d_coreClauseIndices = d_originalClauseIndices; - } -} - -void ClausalBitVectorProof::canonicalizeClause(prop::SatClause& clause) -{ - std::sort(clause.begin(), clause.end()); - clause.erase(std::unique(clause.begin(), clause.end()), clause.end()); -} - -ClausalBitVectorProof::DratTranslationStatistics::DratTranslationStatistics() - : d_totalTime("proof::bv::dratTranslation::totalTime"), - d_toolTime("proof::bv::dratTranslation::toolTime") -{ - smtStatisticsRegistry()->registerStat(&d_totalTime); - smtStatisticsRegistry()->registerStat(&d_toolTime); -} - -ClausalBitVectorProof::DratTranslationStatistics::~DratTranslationStatistics() -{ - smtStatisticsRegistry()->unregisterStat(&d_totalTime); - smtStatisticsRegistry()->unregisterStat(&d_toolTime); -} - -ClausalBitVectorProof::DratOptimizationStatistics::DratOptimizationStatistics() - : d_totalTime("proof::bv::dratOptimization::totalTime"), - d_toolTime("proof::bv::dratOptimization::toolTime"), - d_clauseMatchingTime("proof::bv::dratOptimization::clauseMatchingTime"), - d_initialDratSize("proof::bv::dratOptimization::initialDratSize", 0), - d_optimizedDratSize("proof::bv::dratOptimization::optimizedDratSize", 0), - d_initialFormulaSize("proof::bv::dratOptimization::initialFormulaSize", - 0), - d_optimizedFormulaSize( - "proof::bv::dratOptimization::optimizedFormulaSize", 0) -{ - smtStatisticsRegistry()->registerStat(&d_totalTime); - smtStatisticsRegistry()->registerStat(&d_toolTime); - smtStatisticsRegistry()->registerStat(&d_clauseMatchingTime); - smtStatisticsRegistry()->registerStat(&d_initialDratSize); - smtStatisticsRegistry()->registerStat(&d_optimizedDratSize); - smtStatisticsRegistry()->registerStat(&d_initialFormulaSize); - smtStatisticsRegistry()->registerStat(&d_optimizedFormulaSize); -} - -ClausalBitVectorProof::DratOptimizationStatistics::~DratOptimizationStatistics() -{ - smtStatisticsRegistry()->unregisterStat(&d_totalTime); - smtStatisticsRegistry()->unregisterStat(&d_toolTime); - smtStatisticsRegistry()->unregisterStat(&d_clauseMatchingTime); - smtStatisticsRegistry()->unregisterStat(&d_initialDratSize); - smtStatisticsRegistry()->unregisterStat(&d_optimizedDratSize); - smtStatisticsRegistry()->unregisterStat(&d_initialFormulaSize); - smtStatisticsRegistry()->unregisterStat(&d_optimizedFormulaSize); -} - -void LfscClausalBitVectorProof::printTheoryLemmaProof(std::vector<Expr>& lemma, - std::ostream& os, - std::ostream& paren, - const ProofLetMap& map) -{ - Unreachable() << "Clausal bit-vector proofs should only be used in " - "combination with eager " - "bitblasting, which **does not use theory lemmas**"; -} - -void LfscClausalBitVectorProof::printBBDeclarationAndCnf(std::ostream& os, - std::ostream& paren, - ProofLetMap& letMap) -{ - os << "\n;; Bitblasting mappings\n"; - printBitblasting(os, paren); - - os << "\n;; BB-CNF mappings\n"; - d_cnfProof->printAtomMapping(d_atomsInBitblastingProof, os, paren, letMap); - - os << "\n;; BB-CNF proofs\n"; - for (const ClauseId id : d_coreClauseIndices) - { - d_cnfProof->printCnfProofForClause(id, &d_clauses.at(id), os, paren); - } -} - -void LfscDratBitVectorProof::printEmptyClauseProof(std::ostream& os, - std::ostream& paren) -{ - Assert(options::bitblastMode() == options::BitblastMode::EAGER) - << "the BV theory should only be proving bottom directly in the eager " - "bitblasting mode"; - - os << "\n;; Proof of input to SAT solver\n"; - os << "(@ proofOfSatInput "; - paren << ")"; - - LFSCProofPrinter::printSatInputProof(d_coreClauseIndices, os, "bb"); - - os << "\n;; DRAT Proof Value\n"; - os << "(@ dratProof "; - paren << ")"; - d_dratTranslationStatistics.d_totalTime.start(); - drat::DratProof pf = drat::DratProof::fromBinary(d_binaryDratProof.str()); - d_dratTranslationStatistics.d_totalTime.stop(); - pf.outputAsLfsc(os, 2); - os << "\n"; - - os << "\n;; Verification of DRAT Proof\n"; - os << "(drat_proof_of_bottom _ proofOfSatInput dratProof " - << "\n)"; -} - -void LfscLratBitVectorProof::printEmptyClauseProof(std::ostream& os, - std::ostream& paren) -{ - Assert(options::bitblastMode() == options::BitblastMode::EAGER) - << "the BV theory should only be proving bottom directly in the eager " - "bitblasting mode"; - - os << "\n;; Proof of input to SAT solver\n"; - os << "(@ proofOfCMap "; - paren << ")"; - LFSCProofPrinter::printCMapProof(d_coreClauseIndices, os, "bb"); - - os << "\n;; DRAT Proof Value\n"; - os << "(@ lratProof "; - paren << ")"; - d_dratTranslationStatistics.d_totalTime.start(); - lrat::LratProof pf = - lrat::LratProof::fromDratProof(d_clauses, - d_coreClauseIndices, - d_binaryDratProof.str(), - d_dratTranslationStatistics.d_toolTime); - d_dratTranslationStatistics.d_totalTime.stop(); - pf.outputAsLfsc(os); - os << "\n"; - - os << "\n;; Verification of DRAT Proof\n"; - os << "(lrat_proof_of_bottom _ proofOfCMap lratProof " - << "\n)"; -} - -void LfscErBitVectorProof::printEmptyClauseProof(std::ostream& os, - std::ostream& paren) -{ - Assert(options::bitblastMode() == options::BitblastMode::EAGER) - << "the BV theory should only be proving bottom directly in the eager " - "bitblasting mode"; - - d_dratTranslationStatistics.d_totalTime.start(); - er::ErProof pf = - er::ErProof::fromBinaryDratProof(d_clauses, - d_coreClauseIndices, - d_binaryDratProof.str(), - d_dratTranslationStatistics.d_toolTime); - d_dratTranslationStatistics.d_totalTime.stop(); - - pf.outputAsLfsc(os); -} - -} // namespace proof - -}; // namespace CVC4 diff --git a/src/proof/clausal_bitvector_proof.h b/src/proof/clausal_bitvector_proof.h deleted file mode 100644 index 28a53c90c..000000000 --- a/src/proof/clausal_bitvector_proof.h +++ /dev/null @@ -1,189 +0,0 @@ -/********************* */ -/*! \file clausal_bitvector_proof.h - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief Bitvector proof for clausal (DRAT/LRAT) formats - ** - ** An internal string stream is hooked up to CryptoMiniSat, which spits out a - ** binary DRAT proof. Depending on which kind of proof we're going to turn - ** that into, we process it in different ways. - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__PROOF__CLAUSAL_BITVECTOR_PROOF_H -#define CVC4__PROOF__CLAUSAL_BITVECTOR_PROOF_H - -#include <iostream> -#include <sstream> -#include <unordered_map> - -#include "expr/expr.h" -#include "proof/bitvector_proof.h" -#include "proof/drat/drat_proof.h" -#include "proof/lrat/lrat_proof.h" -#include "proof/theory_proof.h" -#include "prop/cnf_stream.h" -#include "prop/sat_solver_types.h" -#include "theory/bv/theory_bv.h" -#include "util/statistics_registry.h" - -namespace CVC4 { - -namespace proof { - -class ClausalBitVectorProof : public BitVectorProof -{ - public: - ClausalBitVectorProof(theory::bv::TheoryBV* bv, - TheoryProofEngine* proofEngine); - - ~ClausalBitVectorProof() = default; - - void attachToSatSolver(prop::SatSolver& sat_solver) override; - - void initCnfProof(prop::CnfStream* cnfStream, - context::Context* cnf, - prop::SatVariable trueVar, - prop::SatVariable falseVar) override; - - std::ostream& getDratOstream() { return d_binaryDratProof; } - - void registerUsedClause(ClauseId id, prop::SatClause& clause); - - void calculateAtomsInBitblastingProof() override; - - protected: - // A list of all clauses and their ids which are passed into the SAT solver - std::unordered_map<ClauseId, prop::SatClause> d_clauses{}; - std::vector<ClauseId> d_originalClauseIndices{}; - // Stores the proof recieved from the SAT solver. - std::ostringstream d_binaryDratProof{}; - std::vector<ClauseId> d_coreClauseIndices{}; - - struct DratTranslationStatistics - { - DratTranslationStatistics(); - ~DratTranslationStatistics(); - - // Total time spent doing translation (optimized binary DRAT -> in memory - // target format including IO, postprocessing, etc.) - TimerStat d_totalTime; - // Time that the external tool actually spent - TimerStat d_toolTime; - }; - - DratTranslationStatistics d_dratTranslationStatistics; - - private: - // Optimizes the DRAT proof stored in `d_binaryDratProof` and returns a list - // of clause actually needed to check that proof (a smaller UNSAT core) - void optimizeDratProof(); - - // Given reference to a SAT clause encoded as a vector of literals, puts the - // literals into a canonical order - static void canonicalizeClause(prop::SatClause& clause); - - struct DratOptimizationStatistics - { - DratOptimizationStatistics(); - ~DratOptimizationStatistics(); - - // Total time spent using drat-trim to optimize the DRAT proof/formula - // (including IO, etc.) - TimerStat d_totalTime; - // Time that drat-trim actually spent optimizing the DRAT proof/formula - TimerStat d_toolTime; - // Time that was spent matching clauses in drat-trim's output to clauses in - // its input - TimerStat d_clauseMatchingTime; - // Bytes in binary DRAT proof before optimization - IntStat d_initialDratSize; - // Bytes in binary DRAT proof after optimization - IntStat d_optimizedDratSize; - // Bytes in textual DIMACS bitblasted formula before optimization - IntStat d_initialFormulaSize; - // Bytes in textual DIMACS bitblasted formula after optimization - IntStat d_optimizedFormulaSize; - }; - - DratOptimizationStatistics d_dratOptimizationStatistics; -}; - -/** - * A representation of a clausal proof of a bitvector problem's UNSAT nature - */ -class LfscClausalBitVectorProof : public ClausalBitVectorProof -{ - public: - LfscClausalBitVectorProof(theory::bv::TheoryBV* bv, - TheoryProofEngine* proofEngine) - : ClausalBitVectorProof(bv, proofEngine) - { - } - - void printTheoryLemmaProof(std::vector<Expr>& lemma, - std::ostream& os, - std::ostream& paren, - const ProofLetMap& map) override; - void printBBDeclarationAndCnf(std::ostream& os, - std::ostream& paren, - ProofLetMap& letMap) override; -}; - -/** - * A DRAT proof for a bit-vector problem - */ -class LfscDratBitVectorProof : public LfscClausalBitVectorProof -{ - public: - LfscDratBitVectorProof(theory::bv::TheoryBV* bv, - TheoryProofEngine* proofEngine) - : LfscClausalBitVectorProof(bv, proofEngine) - { - } - - void printEmptyClauseProof(std::ostream& os, std::ostream& paren) override; -}; - -/** - * An LRAT proof for a bit-vector problem - */ -class LfscLratBitVectorProof : public LfscClausalBitVectorProof -{ - public: - LfscLratBitVectorProof(theory::bv::TheoryBV* bv, - TheoryProofEngine* proofEngine) - : LfscClausalBitVectorProof(bv, proofEngine) - { - } - - void printEmptyClauseProof(std::ostream& os, std::ostream& paren) override; -}; - -/** - * An Extended Resolution proof for a bit-vector problem - */ -class LfscErBitVectorProof : public LfscClausalBitVectorProof -{ - public: - LfscErBitVectorProof(theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine) - : LfscClausalBitVectorProof(bv, proofEngine) - { - } - - void printEmptyClauseProof(std::ostream& os, std::ostream& paren) override; -}; - -} // namespace proof - -} // namespace CVC4 - -#endif /* CVC4__PROOF__CLAUSAL_BITVECTOR_PROOF_H */ diff --git a/src/proof/clause_id.h b/src/proof/clause_id.h index b2d36c9cb..5d7ec94f6 100644 --- a/src/proof/clause_id.h +++ b/src/proof/clause_id.h @@ -28,6 +28,13 @@ namespace CVC4 { */ typedef unsigned ClauseId; +/** Reserved clauseId values used in the resolution proof. The represent, + * respectively, the empty clause, that adding the clause to the SAT solver was + * a no-op, and that an error occurred when trying to add. */ +const ClauseId ClauseIdEmpty(-1); +const ClauseId ClauseIdUndef(-2); +const ClauseId ClauseIdError(-3); + }/* CVC4 namespace */ #endif /* CVC4__PROOF__CLAUSE_ID_H */ diff --git a/src/proof/cnf_proof.cpp b/src/proof/cnf_proof.cpp index 677bf2f8c..258e2fdb2 100644 --- a/src/proof/cnf_proof.cpp +++ b/src/proof/cnf_proof.cpp @@ -19,8 +19,6 @@ #include "proof/clause_id.h" #include "proof/proof_manager.h" -#include "proof/proof_utils.h" -#include "proof/theory_proof.h" #include "prop/cnf_stream.h" #include "prop/minisat/minisat.h" #include "prop/sat_solver_types.h" @@ -32,11 +30,7 @@ CnfProof::CnfProof(prop::CnfStream* stream, 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) { @@ -46,86 +40,22 @@ CnfProof::CnfProof(prop::CnfStream* stream, CnfProof::~CnfProof() {} -bool CnfProof::isAssertion(Node node) { - return d_assertionToProofRule.find(node) != - d_assertionToProofRule.end(); -} - -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); -} - Node CnfProof::getAssertionForClause(ClauseId clause) { ClauseIdToNode::const_iterator it = d_clauseToAssertion.find(clause); Assert(it != d_clauseToAssertion.end() && !(*it).second.isNull()); return (*it).second; } -Node CnfProof::getDefinitionForClause(ClauseId clause) { - ClauseIdToNode::const_iterator it = d_clauseToDefinition.find(clause); - Assert(it != d_clauseToDefinition.end()); - return (*it).second; -} - -void CnfProof::registerConvertedClause(ClauseId clause, bool explanation) { +void CnfProof::registerConvertedClause(ClauseId clause) +{ 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; - } - Node current_assertion = getCurrentAssertion(); - Node current_expr = getCurrentDefinition(); - Debug("proof:cnf") << "CnfProof::registerConvertedClause " - << clause << " assertion = " << current_assertion - << clause << " definition = " << current_expr << std::endl; + Debug("proof:cnf") << "CnfProof::registerConvertedClause " << clause + << " assertion = " << current_assertion << std::endl; setClauseAssertion(clause, current_assertion); - setClauseDefinition(clause, current_expr); -} - -void CnfProof::registerTrueUnitClause(ClauseId clauseId) -{ - Node trueNode = NodeManager::currentNM()->mkConst<bool>(true); - pushCurrentAssertion(trueNode); - pushCurrentDefinition(trueNode); - registerConvertedClause(clauseId); - popCurrentAssertion(); - popCurrentDefinition(); - d_cnfStream->ensureLiteral(trueNode); - d_trueUnitClause = clauseId; -} - -void CnfProof::registerFalseUnitClause(ClauseId clauseId) -{ - Node falseNode = NodeManager::currentNM()->mkConst<bool>(false).notNode(); - pushCurrentAssertion(falseNode); - pushCurrentDefinition(falseNode); - registerConvertedClause(clauseId); - popCurrentAssertion(); - popCurrentDefinition(); - d_cnfStream->ensureLiteral(falseNode); - d_falseUnitClause = clauseId; } void CnfProof::setClauseAssertion(ClauseId clause, Node expr) { @@ -145,56 +75,15 @@ void CnfProof::setClauseAssertion(ClauseId clause, Node expr) { return; } - d_clauseToAssertion.insert (clause, expr); + 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); -} - -LemmaProofRecipe CnfProof::getProofRecipe(const std::set<Node> &lemma) { - Assert(d_lemmaToProofRecipe.find(lemma) != d_lemmaToProofRecipe.end()); - return d_lemmaToProofRecipe[lemma]; -} - -bool CnfProof::haveProofRecipe(const std::set<Node> &lemma) { - return d_lemmaToProofRecipe.find(lemma) != d_lemmaToProofRecipe.end(); -} - -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 CnfProof::pushCurrentAssertion(Node assertion) { +void CnfProof::pushCurrentAssertion(Node assertion, bool isInput) +{ Debug("proof:cnf") << "CnfProof::pushCurrentAssertion " << assertion << std::endl; - d_currentAssertionStack.push_back(assertion); + d_currentAssertionStack.push_back(std::pair<Node, bool>(assertion, isInput)); Debug("proof:cnf") << "CnfProof::pushCurrentAssertion " << "new stack size = " << d_currentAssertionStack.size() @@ -205,7 +94,7 @@ void CnfProof::popCurrentAssertion() { Assert(d_currentAssertionStack.size()); Debug("proof:cnf") << "CnfProof::popCurrentAssertion " - << d_currentAssertionStack.back() << std::endl; + << d_currentAssertionStack.back().first << std::endl; d_currentAssertionStack.pop_back(); @@ -216,740 +105,12 @@ void CnfProof::popCurrentAssertion() { Node CnfProof::getCurrentAssertion() { Assert(d_currentAssertionStack.size()); - return d_currentAssertionStack.back(); + return d_currentAssertionStack.back().first; } -void CnfProof::setProofRecipe(LemmaProofRecipe* proofRecipe) { - Assert(proofRecipe); - Assert(proofRecipe->getNumSteps() > 0); - d_lemmaToProofRecipe[proofRecipe->getBaseAssertions()] = *proofRecipe; -} - -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, - std::set<Node>& atoms) { - for (unsigned i = 0; i < clause->size(); ++i) { - prop::SatLiteral lit = clause->operator[](i); - prop::SatVariable var = lit.getSatVariable(); - TNode atom = getAtom(var); - if (atoms.find(atom) == atoms.end()) { - atoms.insert(atom); - } - } -} - -prop::SatLiteral CnfProof::getLiteral(TNode atom) { - return d_cnfStream->getLiteral(atom); -} - -bool CnfProof::hasLiteral(TNode atom) { - return d_cnfStream->hasLiteral(atom); -} - -void CnfProof::ensureLiteral(TNode atom, bool noPreregistration) { - d_cnfStream->ensureLiteral(atom, noPreregistration); -} - -void CnfProof::collectAtomsForClauses(const IdToSatClause& clauses, - std::set<Node>& atoms) { - IdToSatClause::const_iterator it = clauses.begin(); - for (; it != clauses.end(); ++it) { - const prop::SatClause* clause = it->second; - collectAtoms(clause, atoms); - } -} - -void CnfProof::collectAtomsAndRewritesForLemmas(const IdToSatClause& lemmaClauses, - std::set<Node>& atoms, - NodePairSet& rewrites) { - IdToSatClause::const_iterator it = lemmaClauses.begin(); - for (; it != lemmaClauses.end(); ++it) { - const prop::SatClause* clause = it->second; - - // TODO: just calculate the map from ID to recipe once, - // instead of redoing this over and over again - std::vector<Expr> clause_expr; - std::set<Node> clause_expr_nodes; - for(unsigned i = 0; i < clause->size(); ++i) { - prop::SatLiteral lit = (*clause)[i]; - Node node = getAtom(lit.getSatVariable()); - Expr atom = node.toExpr(); - if (atom.isConst()) { - Assert(atom == utils::mkTrue()); - continue; - } - clause_expr_nodes.insert(lit.isNegated() ? node.notNode() : node); - } - - LemmaProofRecipe recipe = getProofRecipe(clause_expr_nodes); - - for (unsigned i = 0; i < recipe.getNumSteps(); ++i) { - const LemmaProofRecipe::ProofStep* proofStep = recipe.getStep(i); - Node atom = proofStep->getLiteral(); - - if (atom == Node()) { - // The last proof step always has the empty node as its target... - continue; - } - - if (atom.getKind() == kind::NOT) { - atom = atom[0]; - } - - atoms.insert(atom); - } - - LemmaProofRecipe::RewriteIterator rewriteIt; - for (rewriteIt = recipe.rewriteBegin(); rewriteIt != recipe.rewriteEnd(); ++rewriteIt) { - rewrites.insert(NodePair(rewriteIt->first, rewriteIt->second)); - - // The unrewritten terms also need to have literals, so insert them into atoms - Node rewritten = rewriteIt->first; - if (rewritten.getKind() == kind::NOT) { - rewritten = rewritten[0]; - } - atoms.insert(rewritten); - } - } -} - -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); - } - } -} - -// Detects whether a clause has x v ~x for some x -// If so, returns the positive occurence's idx first, then the negative's -Maybe<std::pair<size_t, size_t>> CnfProof::detectTrivialTautology( - const prop::SatClause& clause) +bool CnfProof::getCurrentAssertionKind() { - // a map from a SatVariable to its previous occurence's polarity and location - std::map<prop::SatVariable, std::pair<bool, size_t>> varsToPolsAndIndices; - for (size_t i = 0; i < clause.size(); ++i) - { - prop::SatLiteral lit = clause[i]; - prop::SatVariable var = lit.getSatVariable(); - bool polarity = !lit.isNegated(); - - // Check if this var has already occured w/ opposite polarity - auto iter = varsToPolsAndIndices.find(var); - if (iter != varsToPolsAndIndices.end() && iter->second.first != polarity) - { - if (iter->second.first) - { - return Maybe<std::pair<size_t, size_t>>{ - std::make_pair(iter->second.second, i)}; - } - else - { - return Maybe<std::pair<size_t, size_t>>{ - std::make_pair(i, iter->second.second)}; - } - } - varsToPolsAndIndices[var] = std::make_pair(polarity, i); - } - return Maybe<std::pair<size_t, size_t>>{}; -} - -void LFSCCnfProof::printAtomMapping(const std::set<Node>& atoms, - std::ostream& os, - std::ostream& paren) { - std::set<Node>::const_iterator it = atoms.begin(); - std::set<Node>::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); - os << " (\\ " << ProofManager::getAtomName(var, d_name) << "\n"; - paren << ")))"; - } -} - -void LFSCCnfProof::printAtomMapping(const std::set<Node>& atoms, - std::ostream& os, - std::ostream& paren, - ProofLetMap &letMap) { - std::set<Node>::const_iterator it = atoms.begin(); - std::set<Node>::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(); - if (pe->printsAsBool(atom.toExpr())) os << "(p_app "; - pe->printBoundTerm(atom.toExpr(), os, letMap); - if (pe->printsAsBool(atom.toExpr())) os << ")"; - - os << " (\\ " << ProofManager::getVarName(var, d_name); - os << " (\\ " << 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 = getAtom(var); - children.push_back( lit.isNegated() ? atom.negate() : atom ); - childIndex[atom] = i; - childPol[atom] = !lit.isNegated(); - } - return children.size()==1 ? children[0] : - NodeManager::currentNM()->mkNode(kind::OR, children ); -} - -void LFSCCnfProof::printCnfProofForClause(ClauseId id, - const prop::SatClause* clause, - std::ostream& os, - std::ostream& paren) { - Debug("cnf-pf") << std::endl << std::endl << "LFSCCnfProof::printCnfProofForClause( " << id << " ) starting " - << std::endl; - - 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); - - // If the clause contains x v ~x, it's easy! - // - // It's important to check for this case, because our other logic for - // recording the location of variables in the clause assumes the clause is - // not tautological - Maybe<std::pair<size_t, size_t>> isTrivialTaut = - detectTrivialTautology(*clause); - if (isTrivialTaut.just()) - { - size_t posIndexInClause = isTrivialTaut.value().first; - size_t negIndexInClause = isTrivialTaut.value().second; - Trace("cnf-pf") << "; Indices " << posIndexInClause << " (+) and " - << negIndexInClause << " (-) make this clause a tautology" - << std::endl; - - std::string proofOfPos = - ProofManager::getLitName((*clause)[negIndexInClause], d_name); - std::string proofOfNeg = - ProofManager::getLitName((*clause)[posIndexInClause], d_name); - os << "(contra _ " << proofOfPos << " " << proofOfNeg << ")"; - } - else - { - 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); - - if (is_input) - { - Debug("cnf-pf") << std::endl - << "; base assertion is input. proof: " << os_base.str() - << std::endl; - } - - // 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(); - } - 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--) { - Trace("cnf-pf-debug") << "; base_assertion[" << j << "] is: " << base_assertion[j] - << ", and its kind is: " << base_assertion[j].getKind() << std::endl ; - - 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; - - Trace("cnf-pf-debug") << "; child " << j << " " - << ", child base: " << child_base - << ", child pol: " << child_pol - << ", childPol[child_base] " - << childPol[child_base] << ", base pol: " << base_pol << 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 ){ - - // Adding the below to catch a specific case where the first child of an IMPLIES is negative, - // in which case we need not_not introduction. - if (base_assertion.getKind() == kind::IMPLIES && !child_pol && base_pol) { - os_main << "(not_not_intro _ " << ProofManager::getLitName(lit, d_name) << ") "; - } else if (childPol[child_base] && base_pol) { - os_main << ProofManager::getLitName(lit, d_name) << " "; - }else{ - os_main << "(not_not_intro _ " << ProofManager::getLitName(lit, d_name) << ") "; - } - if( base_assertion.getKind()==kind::AND ){ - os_main << "(not_and_elim _ _ "; - os_paren << ")"; - } - 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; - 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]; - 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 _ "; - } - 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 << ")"; - } - 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 << ")"; - } - os_main << os_base.str() << os_paren.str(); - if( elimNn ){ - os_main << ")"; - } - break; - } - } - if( success ){ - os << "(contra _ "; - if( !e_pol ){ - os << ProofManager::getLitName(lit, d_name) << " " << os_main.str(); - }else{ - os << os_main.str() << " " << ProofManager::getLitName(lit, d_name); - } - os << ")"; - } - } - }else if( base_assertion.getKind()==kind::XOR || ( base_assertion.getKind()==kind::EQUAL && base_assertion[0].getType().isBoolean() ) ){ - //eliminate negation - int num_nots_2 = 0; - int num_nots_1 = 0; - Kind k; - if( !base_pol ){ - if( base_assertion.getKind()==kind::EQUAL ){ - num_nots_2 = 1; - } - k = kind::EQUAL; - }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::EQUAL) ){ - 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, d_name) << ") "; - }else{ - Trace("cnf-pf-debug") << "CALLING getlitname" << std::endl; - os_base_n << ProofManager::getLitName(lit1, d_name) << " "; - } - Assert(elimNum != 0); - os_base_n << "(" << ( k==kind::EQUAL ? "iff" : "xor" ) << "_elim_" << elimNum << " _ _ "; - if( !base_pol ){ - os_base_n << "(not_" << ( base_assertion.getKind()==kind::EQUAL ? "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 << ProofManager::getLitName(lit2, d_name); - } - }else{ - os << ProofManager::getLitName(lit2, d_name) << " " << os_base_n.str(); - } - os << ")"; - } - }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++; - } - } - 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, 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 << ")"; - } - }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(); - } - } - } - - 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) { - 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, d_name) <<" (\\ " << ProofManager::getLitName(lit, d_name) << " "; - paren << "))"; - } else { - 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; - } + return d_currentAssertionStack.back().second; } } /* CVC4 namespace */ diff --git a/src/proof/cnf_proof.h b/src/proof/cnf_proof.h index 56993583e..e437ef722 100644 --- a/src/proof/cnf_proof.h +++ b/src/proof/cnf_proof.h @@ -27,10 +27,8 @@ #include "context/cdhashmap.h" #include "proof/clause_id.h" -#include "proof/lemma_proof.h" #include "proof/sat_proof.h" #include "util/maybe.h" -#include "util/proof.h" namespace CVC4 { namespace prop { @@ -44,11 +42,11 @@ typedef std::unordered_map<Node, Node, NodeHashFunction> NodeToNode; typedef std::unordered_set<ClauseId> ClauseIdSet; typedef context::CDHashMap<ClauseId, Node> ClauseIdToNode; -typedef context::CDHashMap<Node, ProofRule, NodeHashFunction> NodeToProofRule; -typedef std::map<std::set<Node>, LemmaProofRecipe> LemmaToRecipe; typedef std::pair<Node, Node> NodePair; typedef std::set<NodePair> NodePairSet; +typedef std::unordered_set<Node, NodeHashFunction> NodeSet; + class CnfProof { protected: CVC4::prop::CnfStream* d_cnfStream; @@ -56,23 +54,9 @@ protected: /** 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; - - /** Map from lemma to the recipe for proving it **/ - LemmaToRecipe d_lemmaToProofRecipe; - - /** 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; + /** Top of stack is assertion currently being converted to CNF. Also saves + * whether it is input (rather than a lemma). **/ + std::vector<std::pair<Node, bool>> d_currentAssertionStack; /** Map from top-level fact to facts/assertion that it follows from **/ NodeToNode d_cnfDeps; @@ -84,132 +68,36 @@ protected: // The clause ID of the unit clause defining the false SAT literal. ClauseId d_falseUnitClause; - bool isDefinition(Node node); - - Node getDefinitionForClause(ClauseId clause); - std::string d_name; public: CnfProof(CVC4::prop::CnfStream* cnfStream, context::Context* ctx, const std::string& name); - - - Node getAtom(prop::SatVariable var); - prop::SatLiteral getLiteral(TNode node); - bool hasLiteral(TNode node); - void ensureLiteral(TNode node, bool noPreregistration = false); - - void collectAtoms(const prop::SatClause* clause, - std::set<Node>& atoms); - void collectAtomsForClauses(const IdToSatClause& clauses, - std::set<Node>& atoms); - void collectAtomsAndRewritesForLemmas(const IdToSatClause& lemmaClauses, - std::set<Node>& atoms, - NodePairSet& rewrites); - void collectAssertionsForClauses(const IdToSatClause& clauses, - NodeSet& assertions); + ~CnfProof(); /** 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); - - // The CNF proof has a special relationship to true and false. - // In particular, it need to know the identity of clauses defining - // canonical true and false literals in the underlying SAT solver. - void registerTrueUnitClause(ClauseId clauseId); - void registerFalseUnitClause(ClauseId clauseId); - inline ClauseId getTrueUnitClause() { return d_trueUnitClause; }; - inline ClauseId getFalseUnitClause() { return d_falseUnitClause; }; - - /** Clause is one of the clauses defining the node expression*/ - void setClauseDefinition(ClauseId clause, Node node); + void registerConvertedClause(ClauseId clause); /** 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 + /** Current assertion being converted and whether it is an input (rather than + * a lemma) */ + void pushCurrentAssertion(Node assertion, bool isInput = false); void popCurrentAssertion(); Node getCurrentAssertion(); - - void pushCurrentDefinition(Node assertion); // the current Tseitin definition being converted - void popCurrentDefinition(); - Node getCurrentDefinition(); + bool getCurrentAssertionKind(); /** * Checks whether the assertion stack is empty. */ bool isAssertionStackEmpty() const { return d_currentAssertionStack.empty(); } - void setProofRecipe(LemmaProofRecipe* proofRecipe); - LemmaProofRecipe getProofRecipe(const std::set<Node> &lemma); - bool haveProofRecipe(const std::set<Node> &lemma); - // 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); - - /** Virtual methods for printing things **/ - virtual void printAtomMapping(const std::set<Node>& atoms, - std::ostream& os, - std::ostream& paren) = 0; - virtual void printAtomMapping(const std::set<Node>& atoms, - std::ostream& os, - std::ostream& paren, - ProofLetMap &letMap) = 0; - - // Detects whether a clause has x v ~x for some x - // If so, returns the positive occurence's idx first, then the negative's - static Maybe<std::pair<size_t, size_t>> detectTrivialTautology( - const prop::SatClause& clause); - 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 { - 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, - context::Context* ctx, - const std::string& name) - : CnfProof(cnfStream, ctx, name) - {} - ~LFSCCnfProof() {} - - void printAtomMapping(const std::set<Node>& atoms, - std::ostream& os, - std::ostream& paren) override; - - void printAtomMapping(const std::set<Node>& atoms, - std::ostream& os, - std::ostream& paren, - ProofLetMap& letMap) override; - - void printClause(const prop::SatClause& clause, - std::ostream& os, - std::ostream& paren) override; - void printCnfProofForClause(ClauseId id, - const prop::SatClause* clause, - std::ostream& os, - std::ostream& paren) override; -};/* class LFSCCnfProof */ - } /* CVC4 namespace */ #endif /* CVC4__CNF_PROOF_H */ diff --git a/src/proof/dimacs.cpp b/src/proof/dimacs.cpp deleted file mode 100644 index d9d9f8c1c..000000000 --- a/src/proof/dimacs.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/********************* */ -/*! \file dimacs.cpp - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief DIMACS SAT Problem Format - ** - ** Defines serialization for SAT problems as DIMACS - **/ - -#include "proof/dimacs.h" - -#include "base/check.h" - -#include <iostream> - -namespace CVC4 { -namespace proof { - -// Prints the literal as a (+) or (-) int -// Not operator<< b/c that represents negation as ~ -std::ostream& textOut(std::ostream& o, const prop::SatLiteral& l) -{ - if (l.isNegated()) - { - o << "-"; - } - return o << l.getSatVariable() + 1; -} - -// Prints the clause as a space-separated list of ints -// Not operator<< b/c that represents negation as ~ -std::ostream& textOut(std::ostream& o, const prop::SatClause& c) -{ - for (const auto& l : c) - { - textOut(o, l) << " "; - } - return o << "0"; -} - -void printDimacs(std::ostream& o, - const std::unordered_map<ClauseId, prop::SatClause>& clauses, - const std::vector<ClauseId>& usedIndices) -{ - size_t maxVar = 0; - for (const ClauseId i : usedIndices) - { - const prop::SatClause& c = clauses.at(i); - for (const auto& l : c) - { - if (l.getSatVariable() + 1 > maxVar) - { - maxVar = l.getSatVariable() + 1; - } - } - } - o << "p cnf " << maxVar << " " << usedIndices.size() << '\n'; - for (const ClauseId i : usedIndices) - { - const prop::SatClause& c = clauses.at(i); - for (const auto& l : c) - { - if (l.isNegated()) - { - o << '-'; - } - o << l.getSatVariable() + 1 << " "; - } - o << "0\n"; - } -} - -std::vector<prop::SatClause> parseDimacs(std::istream& in) -{ - std::string tag; - uint64_t nVars; - uint64_t nClauses; - - in >> tag; - Assert(in.good()); - Assert(tag == "p"); - - in >> tag; - Assert(in.good()); - Assert(tag == "cnf"); - - in >> nVars; - Assert(nVars >= 0); - - in >> nClauses; - Assert(nClauses >= 0); - - std::vector<prop::SatClause> cnf; - for (uint64_t i = 0; i < nClauses; ++i) - { - cnf.emplace_back(); - int64_t lit; - in >> lit; - Assert(in.good()); - while (lit != 0) - { - cnf.back().emplace_back(std::abs(lit) - 1, lit < 0); - in >> lit; - Assert(static_cast<uint64_t>(std::abs(lit)) <= nVars); - Assert(in.good()); - } - } - - return cnf; -} - -} // namespace proof -} // namespace CVC4 diff --git a/src/proof/dimacs.h b/src/proof/dimacs.h deleted file mode 100644 index 405b33208..000000000 --- a/src/proof/dimacs.h +++ /dev/null @@ -1,69 +0,0 @@ -/********************* */ -/*! \file dimacs.h - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief DIMACS SAT Problem Format - ** - ** Defines serialization/deserialization for SAT problems as DIMACS - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__PROOF__DIMACS_H -#define CVC4__PROOF__DIMACS_H - -#include <iosfwd> -#include <memory> -#include <unordered_map> - -#include "proof/clause_id.h" -#include "prop/sat_solver_types.h" - -namespace CVC4 { -namespace proof { - -/** - * Prints the literal as a (+) or (-) int - * Not operator<< b/c that represents negation as ~ - * - * @param o where to print - * @param l the literal to print - * - * @return the original stream - */ -std::ostream& textOut(std::ostream& o, const prop::SatLiteral& l); - -/** - * Prints the clause as a space-separated list of ints - * Not operator<< b/c that represents literal negation as ~ - * - * @param o where to print - * @param c the clause to print - * - * @return the original stream - */ -std::ostream& textOut(std::ostream& o, const prop::SatClause& c); - -/** - * Prints a CNF formula in DIMACS format - * - * @param o where to print to - * @param usedClauses the CNF formula - */ -void printDimacs(std::ostream& o, - const std::unordered_map<ClauseId, prop::SatClause>& clauses, - const std::vector<ClauseId>& usedIndices); - -std::vector<prop::SatClause> parseDimacs(std::istream& i); - -} // namespace proof -} // namespace CVC4 - -#endif // CVC4__PROOF__DIMACS_H diff --git a/src/proof/drat/drat_proof.cpp b/src/proof/drat/drat_proof.cpp deleted file mode 100644 index ee9c42d77..000000000 --- a/src/proof/drat/drat_proof.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/********************* */ -/*! \file drat_proof.cpp - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief DRAT Proof Format - ** - ** Defines deserialization for DRAT proofs. - **/ - -#include "proof/drat/drat_proof.h" - -#include <algorithm> -#include <bitset> -#include <iostream> - -#include "proof/proof_manager.h" - -namespace CVC4 { -namespace proof { -namespace drat { - -// helper functions for parsing the binary DRAT format. - -/** - * Parses a binary literal which starts at `start` and must not go beyond `end` - * - * Leaves the iterator one past the last byte that is a part of the clause. - * - * If the literal overruns `end`, then raises a `InvalidDratProofException`. - */ -SatLiteral parse_binary_literal(std::string::const_iterator& start, - const std::string::const_iterator& proof_end) -{ - // lit is encoded as uint represented by a variable-length byte sequence - uint64_t literal_represented_as_uint = 0; - for (uint8_t shift = 0; start != proof_end; ++start, shift += 7) - { - // Check whether shift is so large that we're going to lose some - // information - if (shift + 7 >= 64) - { - throw InvalidDratProofException( - "While parsing a DRAT proof, encountered a literal that was too " - "long"); - } - unsigned char byte = *start; - // The MSB of the byte is an indicator of whether the sequence continues - bool continued = (byte >> 7) & 1; - uint64_t numeric_part = byte & 0x7f; - literal_represented_as_uint |= numeric_part << shift; - if (!continued) - { - // LSB of `literal_represented_as_uint` indicates negation. - bool negated = literal_represented_as_uint & 1; - // Rest is the literal number - SatVariable var_number = literal_represented_as_uint >> 1; - ++start; - // Internal clauses start at 0, external ones start at 1. - return SatLiteral(var_number - 1, negated); - } - } - throw InvalidDratProofException( - "Literal in DRAT proof was not done when " - "EOF was encountered"); -} - -/** - * Parses a binary clause which starts at `start` and must not go beyond `end` - * - * Leaves the iterator one past the last byte that is a part of the clause. - * That is, one past the null byte. - * - * If the clause overruns `end`, then raises a `InvalidDratProofException`. - */ -SatClause parse_binary_clause(std::string::const_iterator& start, - const std::string::const_iterator& proof_end) -{ - SatClause clause; - // A clause is a 0-terminated sequence of literals - while (start != proof_end) - { - // Is the clause done? - if (*start == 0) - { - ++start; - return clause; - } - else - { - // If not, parse another literal - clause.emplace_back(parse_binary_literal(start, proof_end)); - } - } - // We've overrun the end of the byte stream. - throw InvalidDratProofException( - "Clause in DRAT proof was not done when " - "EOF was encountered"); -} - -/** - * Writes this SAT literal in the textual DIMACS format. i.e. as a non-zero - * integer. - * - * Since internally +0 and -0 are valid literals, we add one to each - * literal's number (SAT variable) when outputtting it. - * - * @param os the stream to write to - * @param l the literal to write - */ -void outputLiteralAsDimacs(std::ostream& os, SatLiteral l) -{ - if (l.isNegated()) - { - os << '-'; - } - // add 1 to convert between internal literals and their DIMACS - // representaations. - os << l.getSatVariable() + 1; -} - -// DratInstruction implementation - -DratInstruction::DratInstruction(DratInstructionKind kind, SatClause clause) - : d_kind(kind), d_clause(clause) -{ - // All intialized -} - -void DratInstruction::outputAsText(std::ostream& os) const -{ - switch (d_kind) - { - case DratInstructionKind::ADDITION: - { - for (const SatLiteral& l : d_clause) - { - outputLiteralAsDimacs(os, l); - os << ' '; - } - os << '0' << std::endl; - break; - } - case DratInstructionKind::DELETION: - { - os << "d "; - for (const SatLiteral& l : d_clause) - { - outputLiteralAsDimacs(os, l); - os << ' '; - } - os << '0' << std::endl; - break; - } - default: - { - Unreachable() << "Unknown DRAT instruction kind"; - } - } -} - -// DratProof implementation - -DratProof::DratProof() : d_instructions() {} - -// See the "binary format" section of -// https://www.cs.utexas.edu/~marijn/drat-trim/ -DratProof DratProof::fromBinary(const std::string& s) -{ - DratProof proof; - if (Debug.isOn("pf::drat")) - { - Debug("pf::drat") << "Parsing binary DRAT proof" << std::endl; - Debug("pf::drat") << "proof length: " << s.length() << " bytes" - << std::endl; - Debug("pf::drat") << "proof as bytes: "; - for (char i : s) - { - if (i == 'a' || i == 'd') - { - Debug("pf::drat") << std::endl << " " << std::bitset<8>(i); - } - else - { - Debug("pf::drat") << " " << std::bitset<8>(i); - } - } - Debug("pf::drat") << std::endl << "parsing proof..." << std::endl; - } - - // For each instruction - for (auto i = s.cbegin(), end = s.cend(); i != end;) - { - switch (*i) - { - case 'a': - { - ++i; - proof.d_instructions.emplace_back(ADDITION, - parse_binary_clause(i, end)); - break; - } - case 'd': - { - ++i; - proof.d_instructions.emplace_back(DELETION, - parse_binary_clause(i, end)); - break; - } - default: - { - std::ostringstream errmsg; - errmsg << "Invalid instruction in Drat proof. Instruction bits: " - << std::bitset<8>(*i) - << ". Expected 'a' (01100001) or 'd' " - "(01100100)."; - throw InvalidDratProofException(errmsg.str()); - } - } - } - - if (Debug.isOn("pf::drat")) - { - Debug("pf::drat") << "Printing out DRAT in textual format:" << std::endl; - proof.outputAsText(Debug("pf::drat")); - } - - return proof; -}; - -const std::vector<DratInstruction>& DratProof::getInstructions() const -{ - return d_instructions; -}; - -void DratProof::outputAsText(std::ostream& os) const -{ - for (const DratInstruction& instruction : d_instructions) - { - instruction.outputAsText(os); - os << "\n"; - } -}; - -void DratProof::outputAsLfsc(std::ostream& os, uint8_t indentation) const -{ - for (const DratInstruction& i : d_instructions) - { - if (indentation > 0) - { - std::fill_n(std::ostream_iterator<char>(os), indentation, ' '); - } - os << "("; - switch (i.d_kind) - { - case ADDITION: - { - os << "DRATProofa "; - break; - } - case DELETION: - { - os << "DRATProofd "; - break; - } - default: - { - Unreachable() << "Unrecognized DRAT instruction kind"; - } - } - for (const SatLiteral& l : i.d_clause) - { - os << "(clc (" << (l.isNegated() ? "neg " : "pos ") - << ProofManager::getVarName(l.getSatVariable(), "bb") << ") "; - } - os << "cln"; - std::fill_n(std::ostream_iterator<char>(os), i.d_clause.size(), ')'); - os << "\n"; - } - os << "DRATProofn"; - std::fill_n(std::ostream_iterator<char>(os), d_instructions.size(), ')'); -} -} // namespace drat -} // namespace proof -} // namespace CVC4 diff --git a/src/proof/drat/drat_proof.h b/src/proof/drat/drat_proof.h deleted file mode 100644 index 1213c80c7..000000000 --- a/src/proof/drat/drat_proof.h +++ /dev/null @@ -1,140 +0,0 @@ -/********************* */ -/*! \file drat_proof.h - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief DRAT Proof Format - ** - ** Declares C++ types that represent a DRAT proof. - ** Defines serialization for these types. - ** - ** You can find an introduction to DRAT in the drat-trim paper: - ** http://www.cs.utexas.edu/~marijn/publications/drat-trim.pdf - ** - **/ - -#ifndef CVC4__PROOF__DRAT__DRAT_PROOF_H -#define CVC4__PROOF__DRAT__DRAT_PROOF_H - -#include "cvc4_private.h" -#include "prop/sat_solver.h" -#include "prop/sat_solver_types.h" - -namespace CVC4 { -namespace proof { -namespace drat { - -using CVC4::prop::SatClause; -using CVC4::prop::SatLiteral; -using CVC4::prop::SatVariable; - -class CVC4_PUBLIC InvalidDratProofException : public CVC4::Exception -{ - public: - InvalidDratProofException() : Exception("Invalid DRAT Proof") {} - - InvalidDratProofException(const std::string& msg) : Exception(msg) {} - - InvalidDratProofException(const char* msg) : Exception(msg) {} -}; /* class InvalidDratProofException */ - -enum DratInstructionKind -{ - ADDITION, - DELETION -}; - -struct DratInstruction -{ - DratInstruction(DratInstructionKind kind, SatClause clause); - - /** - * Write the DRAT instruction in textual format. - * The format is described in: - * http://www.cs.utexas.edu/~marijn/publications/drat-trim.pdf - * - * @param os the stream to write to - */ - void outputAsText(std::ostream& os) const; - - DratInstructionKind d_kind; - SatClause d_clause; -}; - -class DratProof -{ - public: - DratProof(const DratProof&) = default; - - DratProof(DratProof&&) = default; - - ~DratProof() = default; - - /** - * Parses a DRAT proof from the **binary format**. - * The format is described at: - * https://www.cs.utexas.edu/~marijn/drat-trim/#contact - * - * What do the standard authors mean by the format being "binary"? - * They just mean that proofs in this format should be understood as - * sequences of bytes, not sequences of ASCII/Unicode/your favorite character - * set characters. - * - * @param binaryProof a string containing the bytes of the binary proof. - * Even though the proof isn't text, it's safe to store it in a string - * because C++ strings don't make any gaurantees about the encoding of - * their contents. This makes them (effectively) just byte sequences. - * - * @return the parsed proof - */ - static DratProof fromBinary(const std::string& binaryProof); - - /** - * @return The instructions in this proof - */ - const std::vector<DratInstruction>& getInstructions() const; - - /** - * Write the DRAT proof in textual format. - * The format is described in: - * http://www.cs.utexas.edu/~marijn/publications/drat-trim.pdf - * - * @param os the stream to write to - */ - void outputAsText(std::ostream& os) const; - - /** - * Write the DRAT proof as an LFSC value - * The format is from the LFSC signature drat.plf - * - * Reads the current `ProofManager` to determine what the variables should be - * named. - * - * @param os the stream to write to - * @param indentation the number of spaces to indent each proof instruction - */ - void outputAsLfsc(std::ostream& os, uint8_t indentation) const; - - private: - /** - * Create an DRAT proof with no instructions. - */ - DratProof(); - - /** - * The instructions of the DRAT proof. - */ - std::vector<DratInstruction> d_instructions; -}; - -} // namespace drat -} // namespace proof -} // namespace CVC4 - -#endif // CVC4__PROOF__DRAT__DRAT_PROOF_H diff --git a/src/proof/er/er_proof.cpp b/src/proof/er/er_proof.cpp deleted file mode 100644 index 54b0fd879..000000000 --- a/src/proof/er/er_proof.cpp +++ /dev/null @@ -1,399 +0,0 @@ -/********************* */ -/*! \file er_proof.cpp - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Andres Noetzli, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief ER Proof Format - ** - ** Declares C++ types that represent an ER/TRACECHECK proof. - ** Defines serialization for these types. - ** - ** You can find details about the way ER is encoded in the TRACECHECK - ** format at these locations: - ** https://github.com/benjaminkiesl/drat2er - ** http://www.cs.utexas.edu/users/marijn/publications/ijcar18.pdf - **/ - -#include "proof/er/er_proof.h" - -#include <unistd.h> -#include <algorithm> -#include <fstream> -#include <iostream> -#include <iterator> -#include <sstream> -#include <unordered_set> - -#include "base/check.h" -#include "base/map_util.h" -#include "proof/dimacs.h" -#include "proof/lfsc_proof_printer.h" -#include "proof/proof_manager.h" - -#if CVC4_USE_DRAT2ER -#include "drat2er.h" -#include "drat2er_options.h" -#endif - -namespace CVC4 { -namespace proof { -namespace er { - -TraceCheckProof TraceCheckProof::fromText(std::istream& in) -{ - TraceCheckProof pf; - TraceCheckIdx idx = 0; - int64_t token = 0; - - // For each line of the proof, start with the idx - // If there is no idx, then you're done! - in >> idx; - for (; !in.eof(); in >> idx) - { - Assert(in.good()); - - // Then parse the clause (it's 0-terminated) - std::vector<prop::SatLiteral> clause; - in >> token; - for (; token != 0; in >> token) - { - clause.emplace_back(std::abs(token) - 1, token < 0); - } - - // Then parse the chain of literals (it's also 0-terminated) - std::vector<TraceCheckIdx> chain; - in >> token; - for (; token != 0; in >> token) - { - Assert(token > 0); - chain.push_back(token); - } - - // Add the line to the proof - pf.d_lines.emplace_back(idx, std::move(clause), std::move(chain)); - } - return pf; -} - -ErProof ErProof::fromBinaryDratProof( - const std::unordered_map<ClauseId, prop::SatClause>& clauses, - const std::vector<ClauseId>& usedIds, - const std::string& dratBinary, - TimerStat& toolTimer) -{ - std::string formulaFilename("cvc4-dimacs-XXXXXX"); - std::string dratFilename("cvc4-drat-XXXXXX"); - std::string tracecheckFilename("cvc4-tracecheck-er-XXXXXX"); - - // Write the formula - std::unique_ptr<std::fstream> formStream = openTmpFile(&formulaFilename); - printDimacs(*formStream, clauses, usedIds); - formStream->close(); - - // Write the (binary) DRAT proof - std::unique_ptr<std::fstream> dratStream = openTmpFile(&dratFilename); - (*dratStream) << dratBinary; - dratStream->close(); - - std::unique_ptr<std::fstream> tracecheckStream = - openTmpFile(&tracecheckFilename); - - // Invoke drat2er - { - CodeTimer blockTimer{toolTimer}; -#if CVC4_USE_DRAT2ER - drat2er::TransformDRATToExtendedResolution(formulaFilename, - dratFilename, - tracecheckFilename, - false, - drat2er::options::QUIET, - false); -#else - Unimplemented() - << "ER proof production requires drat2er.\n" - << "Run contrib/get-drat2er, reconfigure with --drat2er, and rebuild"; -#endif - } - - // Parse the resulting TRACECHECK proof into an ER proof. - TraceCheckProof pf = TraceCheckProof::fromText(*tracecheckStream); - ErProof proof(clauses, usedIds, std::move(pf)); - tracecheckStream->close(); - - remove(formulaFilename.c_str()); - remove(dratFilename.c_str()); - remove(tracecheckFilename.c_str()); - - return proof; -} - -ErProof::ErProof(const std::unordered_map<ClauseId, prop::SatClause>& clauses, - const std::vector<ClauseId>& usedIds, - TraceCheckProof&& tracecheck) - : d_inputClauseIds(), d_definitions(), d_tracecheck(tracecheck) -{ - // Step zero, save input clause Ids for future printing - d_inputClauseIds = usedIds; - - // Make a list of (idx, clause pairs), the used ones. - std::vector<std::pair<ClauseId, prop::SatClause>> usedClauses; - std::transform( - usedIds.begin(), - usedIds.end(), - std::back_inserter(usedClauses), - [&](const ClauseId& i) { return make_pair(i, clauses.at(i)); }); - - // Step one, verify the formula starts the proof - if (Configuration::isAssertionBuild()) - { - for (size_t i = 0, n = usedClauses.size(); i < n; ++i) - { - Assert(d_tracecheck.d_lines[i].d_idx = i + 1); - Assert(d_tracecheck.d_lines[i].d_chain.size() == 0); - std::unordered_set<prop::SatLiteral, prop::SatLiteralHashFunction> - traceCheckClause{d_tracecheck.d_lines[i].d_clause.begin(), - d_tracecheck.d_lines[i].d_clause.end()}; - std::unordered_set<prop::SatLiteral, prop::SatLiteralHashFunction> - originalClause{usedClauses[i].second.begin(), - usedClauses[i].second.end()}; - Assert(traceCheckClause == originalClause); - } - } - - // Step two, identify definitions. They correspond to lines that follow the - // input lines, are in bounds, and have no justifying chain. - for (size_t i = usedClauses.size(), n = d_tracecheck.d_lines.size(); - i < n && d_tracecheck.d_lines[i].d_chain.size() == 0;) - { - prop::SatClause c = d_tracecheck.d_lines[i].d_clause; - Assert(c.size() > 0); - Assert(!c[0].isNegated()); - - // Get the new variable of the definition -- the first variable of the - // first clause - prop::SatVariable newVar = c[0].getSatVariable(); - - // The rest of the literals in the clause of the 'other literals' of the def - std::vector<prop::SatLiteral> otherLiterals{++c.begin(), c.end()}; - - size_t nLinesForThisDef = 2 + otherLiterals.size(); - // Look at the negation of the second literal in the second clause to get - // the old literal - AlwaysAssert(d_tracecheck.d_lines.size() > i + 1) - << "Malformed definition in TRACECHECK proof from drat2er"; - d_definitions.emplace_back(newVar, - ~d_tracecheck.d_lines[i + 1].d_clause[1], - std::move(otherLiterals)); - - // Advance over the lines for this definition - i += nLinesForThisDef; - } -} - -void ErProof::outputAsLfsc(std::ostream& os) const -{ - // How many parens to close? - size_t parenCount = 0; - std::unordered_set<prop::SatVariable> newVariables; - - // Print Definitions - for (const ErDefinition& def : d_definitions) - { - os << "\n (decl_definition (" - << (def.d_oldLiteral.isNegated() ? "neg " : "pos ") - << ProofManager::getVarName(def.d_oldLiteral.getSatVariable(), "bb") - << ") "; - LFSCProofPrinter::printSatClause(def.d_otherLiterals, os, "bb"); - os << " (\\ er.v" << def.d_newVariable << " (\\ er.def" - << def.d_newVariable; - newVariables.insert(def.d_newVariable); - } - parenCount += 3 * d_definitions.size(); - - // Clausify Definitions - TraceCheckIdx firstDefClause = d_inputClauseIds.size() + 1; - for (const ErDefinition& def : d_definitions) - { - os << "\n (clausify_definition _ _ _ " - << "er.def" << def.d_newVariable << " _ (\\ er.c" << firstDefClause - << " (\\ er.c" << (firstDefClause + 1) << " (\\ er.cnf" - << def.d_newVariable; - - firstDefClause += 2 + def.d_otherLiterals.size(); - } - parenCount += 4 * d_definitions.size(); - - // Unroll proofs of CNF to proofs of clauses - firstDefClause = d_inputClauseIds.size() + 1; - for (const ErDefinition& def : d_definitions) - { - for (size_t i = 0, n = def.d_otherLiterals.size(); i < n; ++i) - { - // Compute the name of the CNF proof we're unrolling in this step - std::ostringstream previousCnfProof; - previousCnfProof << "er.cnf" << def.d_newVariable; - if (i != 0) - { - // For all but the first unrolling, the previous CNF has an unrolling - // number attached - previousCnfProof << ".u" << i; - } - - // Prove the first clause in the CNF - os << "\n (@ "; - os << "er.c" << (firstDefClause + 2 + i); - os << " (common_tail_cnf_prove_head _ _ _ " << previousCnfProof.str() - << ")"; - - // Prove the rest of the CNF - os << "\n (@ "; - os << "er.cnf" << def.d_newVariable << ".u" << (i + 1); - os << " (common_tail_cnf_prove_tail _ _ _ " << previousCnfProof.str() - << ")"; - } - parenCount += 2 * def.d_otherLiterals.size(); - - firstDefClause += 2 + def.d_otherLiterals.size(); - } - - // NB: At this point `firstDefClause` points to the first clause resulting - // from a resolution chain - - // Now, elaborate each resolution chain - for (size_t cId = firstDefClause, nLines = d_tracecheck.d_lines.size(); - cId <= nLines; - ++cId) - { - const std::vector<TraceCheckIdx>& chain = - d_tracecheck.d_lines[cId - 1].d_chain; - const std::vector<prop::SatLiteral> pivots = computePivotsForChain(chain); - Assert(chain.size() > 0); - Assert(chain.size() == pivots.size() + 1); - - os << "\n (satlem_simplify _ _ _ "; - parenCount += 1; - - // Print resolution openings (reverse order) - for (int64_t i = pivots.size() - 1; i >= 0; --i) - { - prop::SatLiteral pivot = pivots[i]; - os << "(" << (pivot.isNegated() ? 'Q' : 'R') << " _ _ "; - } - - // Print resolution start - writeIdForClauseProof(os, chain[0]); - os << " "; - - // Print resolution closings (forward order) - for (size_t i = 0, n = pivots.size(); i < n; ++i) - { - prop::SatVariable pivotVar = pivots[i].getSatVariable(); - TraceCheckIdx clauseId = chain[i + 1]; - writeIdForClauseProof(os, clauseId); - os << " "; - if (ContainsKey(newVariables, pivotVar)) - { - // This is a defined variable - os << "er.v" << pivotVar; - } - else - { - os << ProofManager::getVarName(pivotVar, "bb"); - } - os << ") "; - } - os << "(\\ er.c" << cId; - parenCount += 1; - } - - // Write proof of bottom - Assert(d_tracecheck.d_lines.back().d_clause.size() == 0) - << "The TRACECHECK proof from drat2er did not prove bottom."; - os << "\n er.c" << d_tracecheck.d_lines.back().d_idx - << " ; (holds cln)\n"; - - // Finally, close the parentheses! - std::fill_n(std::ostream_iterator<char>(os), parenCount, ')'); -} - -namespace { -/** - * Resolves two clauses - * - * @param dest one of the inputs, and the output too. **This is an input and - * output** - * @param src the other input - * - * @return the unique literal that was resolved on, with the polarization that - * it originally had in `dest`. - * - * For example, if dest = (1 3 -4 5) and src = (1 -3 5), then 3 is returned and - * after the call dest = (1 -4 5). - */ -prop::SatLiteral resolveModify( - std::unordered_set<prop::SatLiteral, prop::SatLiteralHashFunction>& dest, - const prop::SatClause& src) -{ - CVC4_UNUSED bool foundPivot = false; - prop::SatLiteral pivot(0, false); - - for (prop::SatLiteral lit : src) - { - auto negationLocation = dest.find(~lit); - if (negationLocation != dest.end()) - { -#ifdef CVC4_ASSERTIONS - Assert(!foundPivot); - foundPivot = true; -#endif - dest.erase(negationLocation); - pivot = ~lit; - } - dest.insert(lit); - } - - Assert(foundPivot); - return pivot; -} -} // namespace - -std::vector<prop::SatLiteral> ErProof::computePivotsForChain( - const std::vector<TraceCheckIdx>& chain) const -{ - std::vector<prop::SatLiteral> pivots; - - const prop::SatClause& first = d_tracecheck.d_lines[chain[0] - 1].d_clause; - std::unordered_set<prop::SatLiteral, prop::SatLiteralHashFunction> - runningClause{first.begin(), first.end()}; - - for (auto idx = ++chain.cbegin(), end = chain.cend(); idx != end; ++idx) - { - pivots.push_back( - resolveModify(runningClause, d_tracecheck.d_lines[*idx - 1].d_clause)); - } - return pivots; -} - -void ErProof::writeIdForClauseProof(std::ostream& o, TraceCheckIdx i) const -{ - if (i <= d_inputClauseIds.size()) - { - // This clause is an input clause! Ask the ProofManager for its name - o << ProofManager::getInputClauseName(d_inputClauseIds[i - 1], "bb"); - } - else - { - // This clause was introduced by a definition or resolution chain - o << "er.c" << i; - } -} - -} // namespace er -} // namespace proof -} // namespace CVC4 diff --git a/src/proof/er/er_proof.h b/src/proof/er/er_proof.h deleted file mode 100644 index 6f7239ef2..000000000 --- a/src/proof/er/er_proof.h +++ /dev/null @@ -1,218 +0,0 @@ -/********************* */ -/*! \file er_proof.h - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief ER Proof Format - ** - ** Declares C++ types that represent an ER/TRACECHECK proof. - ** Defines serialization for these types. - ** - ** You can find details about the way ER is encoded in the TRACECHECK - ** format at these locations: - ** https://github.com/benjaminkiesl/drat2er - ** http://www.cs.utexas.edu/users/marijn/publications/ijcar18.pdf - ** - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__PROOF__ER__ER_PROOF_H -#define CVC4__PROOF__ER__ER_PROOF_H - -#include <memory> -#include <unordered_map> -#include <vector> - -#include "proof/clause_id.h" -#include "prop/sat_solver_types.h" -#include "util/statistics_registry.h" - -namespace CVC4 { -namespace proof { -namespace er { - -/** - * A definition of the form: - * newVar <-> p v (~x_1 ^ ~x_2 ^ ... ^ ~x_n) - */ -struct ErDefinition -{ - ErDefinition(prop::SatVariable newVariable, - prop::SatLiteral oldLiteral, - std::vector<prop::SatLiteral>&& otherLiterals) - : d_newVariable(newVariable), - d_oldLiteral(oldLiteral), - d_otherLiterals(otherLiterals) - { - } - - // newVar - prop::SatVariable d_newVariable; - // p - prop::SatLiteral d_oldLiteral; - // A list of the x_i's - std::vector<prop::SatLiteral> d_otherLiterals; -}; - -// For representing a clause's index within a TRACECHECK proof. -using TraceCheckIdx = size_t; - -/** - * A single line in a TRACECHECK proof. - * - * Consists of the index of a new clause, the literals of that clause, and the - * indices for preceding clauses which can be combined in a resolution chain to - * produce this new clause. - */ -struct TraceCheckLine -{ - TraceCheckLine(TraceCheckIdx idx, - std::vector<prop::SatLiteral>&& clause, - std::vector<TraceCheckIdx>&& chain) - : d_idx(idx), d_clause(clause), d_chain(chain) - { - } - - // The index of the new clause - TraceCheckIdx d_idx; - // The new clause - std::vector<prop::SatLiteral> d_clause; - /** - * Indices of clauses which must be resolved to produce this new clause. - * While the TRACECHECK format does not specify the order, we require them to - * be in resolution-order. - */ - std::vector<TraceCheckIdx> d_chain; -}; - -/** - * A TRACECHECK proof -- just a list of lines - */ -struct TraceCheckProof -{ - static TraceCheckProof fromText(std::istream& in); - TraceCheckProof() : d_lines() {} - - // The lines of this proof. - std::vector<TraceCheckLine> d_lines; -}; - -/** - * An extended resolution proof. - * It supports resolution, along with extensions of the form - * - * newVar <-> p v (~x_1 ^ ~x_2 ^ ... ^ ~x_n) - */ -class ErProof -{ - public: - /** - * Construct an ER proof from a DRAT proof, using drat2er - * - * @param clauses A store of clauses that might be in our formula - * @param usedIds the ids of clauses that are actually in our formula - * @param dratBinary The DRAT proof from the SAT solver, as a binary stream - * - * @return the Er proof and a timer of the execution of drat2er - */ - static ErProof fromBinaryDratProof( - const std::unordered_map<ClauseId, prop::SatClause>& clauses, - const std::vector<ClauseId>& usedIds, - const std::string& dratBinary, - TimerStat& toolTimer - ); - - /** - * Construct an ER proof from a TRACECHECK ER proof - * - * This basically just identifies groups of lines which correspond to - * definitions, and extracts them. - * - * @param clauses A store of clauses that might be in our formula - * @param usedIds the ids of clauses that are actually in our formula - * @param tracecheck The TRACECHECK proof, as a stream. - */ - ErProof(const std::unordered_map<ClauseId, prop::SatClause>& clauses, - const std::vector<ClauseId>& usedIds, - TraceCheckProof&& tracecheck); - - /** - * Write the ER proof as an LFSC value of type (holds cln). - * The format is from the LFSC signature er.plf - * - * Reads the current `ProofManager` to determine what the variables should be - * named. - * - * @param os the stream to write to - */ - void outputAsLfsc(std::ostream& os) const; - - const std::vector<ClauseId>& getInputClauseIds() const - { - return d_inputClauseIds; - } - - const std::vector<ErDefinition>& getDefinitions() const - { - return d_definitions; - } - - const TraceCheckProof& getTraceCheckProof() const { return d_tracecheck; } - - private: - /** - * Creates an empty ErProof. - */ - ErProof() : d_inputClauseIds(), d_definitions(), d_tracecheck() {} - - /** - * Computes the pivots on the basis of which an in-order resolution chain is - * resolved. - * - * c0 c1 - * \ / Clauses c_i being resolved in a chain around - * v1 c2 pivots v_i. - * \ / - * v2 c3 - * \ / - * v3 c4 - * \ / - * v4 - * - * - * @param chain the chain, of N clause indices - * - * @return a list of N - 1 variables, the list ( v_i ) from i = 1 to N - 1 - */ - std::vector<prop::SatLiteral> computePivotsForChain( - const std::vector<TraceCheckIdx>& chain) const; - - /** - * Write the LFSC identifier for the proof of a clause - * - * @param o where to write to - * @param i the TRACECHECK index for the clause whose proof identifier to - * print - */ - void writeIdForClauseProof(std::ostream& o, TraceCheckIdx i) const; - - // A list of the Ids for the input clauses, in order. - std::vector<ClauseId> d_inputClauseIds; - // A list of new variable definitions, in order. - std::vector<ErDefinition> d_definitions; - // The underlying TRACECHECK proof. - TraceCheckProof d_tracecheck; -}; - -} // namespace er -} // namespace proof -} // namespace CVC4 - -#endif // CVC4__PROOF__ER__ER_PROOF_H diff --git a/src/proof/lemma_proof.cpp b/src/proof/lemma_proof.cpp deleted file mode 100644 index bdebb6cfc..000000000 --- a/src/proof/lemma_proof.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/********************* */ -/*! \file lemma_proof.cpp - ** \verbatim - ** Top contributors (to current version): - ** Guy Katz, Alex Ozdemir, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** A class for recoding the steps required in order to prove a theory lemma. - -**/ - -#include "proof/lemma_proof.h" -#include "theory/rewriter.h" - -namespace CVC4 { - -LemmaProofRecipe::ProofStep::ProofStep(theory::TheoryId theory, Node literalToProve) : - d_theory(theory), d_literalToProve(literalToProve) { -} - -theory::TheoryId LemmaProofRecipe::ProofStep::getTheory() const { - return d_theory; -} - -Node LemmaProofRecipe::ProofStep::getLiteral() const { - return d_literalToProve; -} - -void LemmaProofRecipe::ProofStep::addAssertion(const Node& assertion) { - d_assertions.insert(assertion); -} - -std::set<Node> LemmaProofRecipe::ProofStep::getAssertions() const { - return d_assertions; -} - -void LemmaProofRecipe::addStep(ProofStep& proofStep) { - d_proofSteps.push_back(proofStep); -} - -std::set<Node> LemmaProofRecipe::getMissingAssertionsForStep(unsigned index) const { - Assert(index < d_proofSteps.size()); - - std::set<Node> existingAssertions = getBaseAssertions(); - - // The literals for all the steps "before" (i.e. behind) the step indicated - // by the index are considered "existing" - size_t revIndex = d_proofSteps.size() - 1 - index; - for (size_t i = d_proofSteps.size() - 1; i != revIndex; --i) - { - existingAssertions.insert(d_proofSteps[i].getLiteral().negate()); - } - - std::set<Node> neededAssertions = d_proofSteps[revIndex].getAssertions(); - - std::set<Node> result; - std::set_difference(neededAssertions.begin(), neededAssertions.end(), - existingAssertions.begin(), existingAssertions.end(), - std::inserter(result, result.begin())); - return result; -} - -void LemmaProofRecipe::dump(const char *tag) const { - - if (d_proofSteps.size() == 1) { - Debug(tag) << std::endl << "[Simple lemma]" << std::endl << std::endl; - } - - if (d_originalLemma != Node()) { - Debug(tag) << std::endl << "Original lemma: " << d_originalLemma << std::endl << std::endl; - } - - unsigned count = 1; - Debug(tag) << "Base assertions:" << std::endl; - for (std::set<Node>::iterator baseIt = d_baseAssertions.begin(); - baseIt != d_baseAssertions.end(); - ++baseIt) { - Debug(tag) << "\t#" << count << ": " << "\t" << *baseIt << std::endl; - ++count; - } - - Debug(tag) << std::endl << std::endl << "Proof steps:" << std::endl; - - count = 1; - for (const auto& step : (*this)) { - Debug(tag) << "\tStep #" << count << ": " << "\t[" << step.getTheory() << "] "; - if (step.getLiteral() == Node()) { - Debug(tag) << "Contradiction"; - } else { - Debug(tag) << step.getLiteral(); - } - - Debug(tag) << std::endl; - - std::set<Node> missingAssertions = getMissingAssertionsForStep(count - 1); - for (std::set<Node>::const_iterator it = missingAssertions.begin(); it != missingAssertions.end(); ++it) { - Debug(tag) << "\t\t\tMissing assertion for step: " << *it << std::endl; - } - - Debug(tag) << std::endl; - ++count; - } - - if (!d_assertionToExplanation.empty()) { - Debug(tag) << std::endl << "Rewrites used:" << std::endl; - count = 1; - for (std::map<Node, Node>::const_iterator rewrite = d_assertionToExplanation.begin(); - rewrite != d_assertionToExplanation.end(); - ++rewrite) { - Debug(tag) << "\tRewrite #" << count << ":" << std::endl - << "\t\t" << rewrite->first - << std::endl << "\t\trewritten into" << std::endl - << "\t\t" << rewrite->second - << std::endl << std::endl; - ++count; - } - } -} - -void LemmaProofRecipe::addBaseAssertion(Node baseAssertion) { - d_baseAssertions.insert(baseAssertion); -} - -std::set<Node> LemmaProofRecipe::getBaseAssertions() const { - return d_baseAssertions; -} - -theory::TheoryId LemmaProofRecipe::getTheory() const { - Assert(d_proofSteps.size() > 0); - return d_proofSteps.back().getTheory(); -} - -void LemmaProofRecipe::addRewriteRule(Node assertion, Node explanation) { - if (d_assertionToExplanation.find(assertion) != d_assertionToExplanation.end()) { - Assert(d_assertionToExplanation[assertion] == explanation); - } - - d_assertionToExplanation[assertion] = explanation; -} - -bool LemmaProofRecipe::wasRewritten(Node assertion) const { - return d_assertionToExplanation.find(assertion) != d_assertionToExplanation.end(); -} - -Node LemmaProofRecipe::getExplanation(Node assertion) const { - Assert(d_assertionToExplanation.find(assertion) - != d_assertionToExplanation.end()); - return d_assertionToExplanation.find(assertion)->second; -} - -LemmaProofRecipe::RewriteIterator LemmaProofRecipe::rewriteBegin() const { - return d_assertionToExplanation.begin(); -} - -LemmaProofRecipe::RewriteIterator LemmaProofRecipe::rewriteEnd() const { - return d_assertionToExplanation.end(); -} - -LemmaProofRecipe::iterator LemmaProofRecipe::begin() { - return d_proofSteps.rbegin(); -} - -LemmaProofRecipe::iterator LemmaProofRecipe::end() { - return d_proofSteps.rend(); -} - -LemmaProofRecipe::const_iterator LemmaProofRecipe::begin() const { - return d_proofSteps.crbegin(); -} - -LemmaProofRecipe::const_iterator LemmaProofRecipe::end() const { - return d_proofSteps.crend(); -} - -bool LemmaProofRecipe::operator<(const LemmaProofRecipe& other) const { - return d_baseAssertions < other.d_baseAssertions; - } - -bool LemmaProofRecipe::simpleLemma() const { - return d_proofSteps.size() == 1; -} - -bool LemmaProofRecipe::compositeLemma() const { - return !simpleLemma(); -} - -const LemmaProofRecipe::ProofStep* LemmaProofRecipe::getStep(unsigned index) const { - Assert(index < d_proofSteps.size()); - - size_t revIndex = d_proofSteps.size() - 1 - index; - - return &d_proofSteps[revIndex]; -} - -LemmaProofRecipe::ProofStep* LemmaProofRecipe::getStep(unsigned index) { - Assert(index < d_proofSteps.size()); - - size_t revIndex = d_proofSteps.size() - 1 - index; - - return &d_proofSteps[revIndex]; -} - -unsigned LemmaProofRecipe::getNumSteps() const { - return d_proofSteps.size(); -} - -void LemmaProofRecipe::setOriginalLemma(Node lemma) { - d_originalLemma = lemma; -} - -Node LemmaProofRecipe::getOriginalLemma() const { - return d_originalLemma; -} - -std::ostream& operator<<(std::ostream& out, - const LemmaProofRecipe::ProofStep& step) -{ - out << "Proof Step("; - out << " lit = " << step.getLiteral() << ","; - out << " assertions = " << step.getAssertions() << ","; - out << " theory = " << step.getTheory(); - out << " )"; - return out; -} - -std::ostream& operator<<(std::ostream& out, const LemmaProofRecipe& recipe) -{ - out << "LemmaProofRecipe("; - out << "\n original lemma = " << recipe.getOriginalLemma(); - out << "\n actual clause = " << recipe.getBaseAssertions(); - out << "\n theory = " << recipe.getTheory(); - out << "\n steps = "; - for (const auto& step : recipe) - { - out << "\n " << step; - } - out << "\n rewrites = "; - for (LemmaProofRecipe::RewriteIterator i = recipe.rewriteBegin(), - end = recipe.rewriteEnd(); - i != end; - ++i) - { - out << "\n Rewrite(" << i->first << ", explanation = " << i->second - << ")"; - } - out << "\n)"; - return out; -} - -} /* namespace CVC4 */ diff --git a/src/proof/lemma_proof.h b/src/proof/lemma_proof.h deleted file mode 100644 index ffc6655a6..000000000 --- a/src/proof/lemma_proof.h +++ /dev/null @@ -1,115 +0,0 @@ -/********************* */ -/*! \file lemma_proof.h - ** \verbatim - ** Top contributors (to current version): - ** Guy Katz, Alex Ozdemir, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** A class for recoding the steps required in order to prove a theory lemma. - -**/ - -#include "cvc4_private.h" - -#ifndef CVC4__LEMMA_PROOF_H -#define CVC4__LEMMA_PROOF_H - -#include "expr/expr.h" -#include "proof/clause_id.h" -#include "prop/sat_solver_types.h" -#include "util/proof.h" -#include "expr/node.h" -#include <iosfwd> - -namespace CVC4 { - -class LemmaProofRecipe { -public: - class ProofStep { - public: - ProofStep(theory::TheoryId theory, Node literalToProve); - theory::TheoryId getTheory() const; - Node getLiteral() const; - void addAssertion(const Node& assertion); - std::set<Node> getAssertions() const; - - private: - theory::TheoryId d_theory; - Node d_literalToProve; - std::set<Node> d_assertions; - }; - - //* The lemma assertions and owner */ - void addBaseAssertion(Node baseAssertion); - std::set<Node> getBaseAssertions() const; - theory::TheoryId getTheory() const; - - //* Rewrite rules */ - using RewriteIterator = std::map<Node, Node>::const_iterator; - RewriteIterator rewriteBegin() const; - RewriteIterator rewriteEnd() const; - - // Steps iterator - // The default iterator for a LemmaProofRecipe - using iterator = std::vector<ProofStep>::reverse_iterator; - std::vector<ProofStep>::reverse_iterator begin(); - std::vector<ProofStep>::reverse_iterator end(); - - using const_iterator = std::vector<ProofStep>::const_reverse_iterator; - std::vector<ProofStep>::const_reverse_iterator begin() const; - std::vector<ProofStep>::const_reverse_iterator end() const; - - using difference_type = ptrdiff_t; - using size_type = size_t; - using value_type = ProofStep; - using pointer = ProofStep *; - using const_pointer = const ProofStep *; - using reference = ProofStep &; - using const_reference = const ProofStep &; - - void addRewriteRule(Node assertion, Node explanation); - bool wasRewritten(Node assertion) const; - Node getExplanation(Node assertion) const; - - //* Original lemma */ - void setOriginalLemma(Node lemma); - Node getOriginalLemma() const; - - //* Proof Steps */ - void addStep(ProofStep& proofStep); - const ProofStep* getStep(unsigned index) const; - ProofStep* getStep(unsigned index); - unsigned getNumSteps() const; - std::set<Node> getMissingAssertionsForStep(unsigned index) const; - bool simpleLemma() const; - bool compositeLemma() const; - - void dump(const char *tag) const; - bool operator<(const LemmaProofRecipe& other) const; - -private: - //* The list of assertions for this lemma */ - std::set<Node> d_baseAssertions; - - //* The various steps needed to derive the empty clause */ - // The "first" step is actually at the back. - std::vector<ProofStep> d_proofSteps; - - //* A map from assertions to their rewritten explanations (toAssert --> toExplain) */ - std::map<Node, Node> d_assertionToExplanation; - - //* The original lemma, as asserted by the owner theory solver */ - Node d_originalLemma; -}; - -std::ostream& operator<<(std::ostream & out, const LemmaProofRecipe::ProofStep & step); - -std::ostream& operator<<(std::ostream & out, const LemmaProofRecipe & recipe); - -} /* CVC4 namespace */ - -#endif /* CVC4__LEMMA_PROOF_H */ diff --git a/src/proof/lfsc_proof_printer.cpp b/src/proof/lfsc_proof_printer.cpp deleted file mode 100644 index 464083841..000000000 --- a/src/proof/lfsc_proof_printer.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/********************* */ -/*! \file lfsc_proof_printer.cpp - ** \verbatim - ** Top contributors (to current version): - ** Andres Noetzli, Alex Ozdemir, Liana Hadarean - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief Prints proofs in the LFSC format - ** - ** Prints proofs in the LFSC format. - **/ - -#include "proof/lfsc_proof_printer.h" - -#include <algorithm> -#include <iostream> -#include <iterator> - -#include "prop/bvminisat/core/Solver.h" -#include "prop/minisat/core/Solver.h" - -namespace CVC4 { -namespace proof { - -template <class Solver> -std::string LFSCProofPrinter::clauseName(TSatProof<Solver>* satProof, - ClauseId id) -{ - std::ostringstream os; - if (satProof->isInputClause(id)) - { - os << ProofManager::getInputClauseName(id, satProof->getName()); - } - else if (satProof->isLemmaClause(id)) - { - os << ProofManager::getLemmaClauseName(id, satProof->getName()); - } - else - { - os << ProofManager::getLearntClauseName(id, satProof->getName()); - } - return os.str(); -} - -template <class Solver> -void LFSCProofPrinter::printResolution(TSatProof<Solver>* satProof, - ClauseId id, - std::ostream& out, - std::ostream& paren) -{ - out << "(satlem_simplify _ _ _"; - paren << ")"; - - const ResChain<Solver>& res = satProof->getResolutionChain(id); - const 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 << " " << clauseName(satProof, start_id); - - for (unsigned i = 0; i < steps.size(); i++) - { - prop::SatVariable v = - prop::MinisatSatSolver::toSatVariable(var(steps[i].lit)); - out << " " << clauseName(satProof, steps[i].id) << " " - << ProofManager::getVarName(v, satProof->getName()) << ")"; - } - - if (id == satProof->getEmptyClauseId()) - { - out << " (\\ empty empty)"; - return; - } - - out << " (\\ " << clauseName(satProof, id) << "\n"; // bind to lemma name - paren << ")"; -} - -template <class Solver> -void LFSCProofPrinter::printAssumptionsResolution(TSatProof<Solver>* satProof, - ClauseId id, - std::ostream& out, - std::ostream& paren) -{ - Assert(satProof->isAssumptionConflict(id)); - // print the resolution proving the assumption conflict - printResolution(satProof, id, out, paren); - // resolve out assumptions to prove empty clause - out << "(satlem_simplify _ _ _ "; - const std::vector<typename Solver::TLit>& confl = - *(satProof->getAssumptionConflicts().at(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 << clauseName(satProof, 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, satProof->getName()) << ")"; - } - out << "(\\ e e)\n"; - paren << ")"; -} - -template <class Solver> -void LFSCProofPrinter::printResolutions(TSatProof<Solver>* satProof, - std::ostream& out, - std::ostream& paren) -{ - Debug("bv-proof") << "; print resolutions" << std::endl; - std::set<ClauseId>::iterator it = satProof->getSeenLearnt().begin(); - for (; it != satProof->getSeenLearnt().end(); ++it) - { - if (*it != satProof->getEmptyClauseId()) - { - Debug("bv-proof") << "; print resolution for " << *it << std::endl; - printResolution(satProof, *it, out, paren); - } - } - Debug("bv-proof") << "; done print resolutions" << std::endl; -} - -template <class Solver> -void LFSCProofPrinter::printResolutionEmptyClause(TSatProof<Solver>* satProof, - std::ostream& out, - std::ostream& paren) -{ - printResolution(satProof, satProof->getEmptyClauseId(), out, paren); -} - -void LFSCProofPrinter::printSatInputProof(const std::vector<ClauseId>& clauses, - std::ostream& out, - const std::string& namingPrefix) -{ - for (auto i = clauses.begin(), end = clauses.end(); i != end; ++i) - { - out << "\n (cnfc_proof _ _ _ " - << ProofManager::getInputClauseName(*i, namingPrefix) << " "; - } - out << "cnfn_proof"; - std::fill_n(std::ostream_iterator<char>(out), clauses.size(), ')'); -} - -void LFSCProofPrinter::printCMapProof(const std::vector<ClauseId>& clauses, - std::ostream& out, - const std::string& namingPrefix) -{ - for (size_t i = 0, n = clauses.size(); i < n; ++i) - { - out << "\n (CMapc_proof " << (i + 1) << " _ _ _ " - << ProofManager::getInputClauseName(clauses[i], namingPrefix) << " "; - } - out << "CMapn_proof"; - std::fill_n(std::ostream_iterator<char>(out), clauses.size(), ')'); -} - -void LFSCProofPrinter::printSatClause(const prop::SatClause& clause, - std::ostream& out, - const std::string& namingPrefix) -{ - for (auto i = clause.cbegin(); i != clause.cend(); ++i) - { - out << "(clc " << (i->isNegated() ? "(neg " : "(pos ") - << ProofManager::getVarName(i->getSatVariable(), namingPrefix) << ") "; - } - out << "cln"; - std::fill_n(std::ostream_iterator<char>(out), clause.size(), ')'); -} - -// Template specializations -template void LFSCProofPrinter::printAssumptionsResolution( - TSatProof<CVC4::Minisat::Solver>* satProof, - ClauseId id, - std::ostream& out, - std::ostream& paren); -template void LFSCProofPrinter::printResolutions( - TSatProof<CVC4::Minisat::Solver>* satProof, - std::ostream& out, - std::ostream& paren); -template void LFSCProofPrinter::printResolutionEmptyClause( - TSatProof<CVC4::Minisat::Solver>* satProof, - std::ostream& out, - std::ostream& paren); - -template void LFSCProofPrinter::printAssumptionsResolution( - TSatProof<CVC4::BVMinisat::Solver>* satProof, - ClauseId id, - std::ostream& out, - std::ostream& paren); -template void LFSCProofPrinter::printResolutions( - TSatProof<CVC4::BVMinisat::Solver>* satProof, - std::ostream& out, - std::ostream& paren); -template void LFSCProofPrinter::printResolutionEmptyClause( - TSatProof<CVC4::BVMinisat::Solver>* satProof, - std::ostream& out, - std::ostream& paren); -} // namespace proof -} // namespace CVC4 diff --git a/src/proof/lfsc_proof_printer.h b/src/proof/lfsc_proof_printer.h deleted file mode 100644 index 62547676f..000000000 --- a/src/proof/lfsc_proof_printer.h +++ /dev/null @@ -1,154 +0,0 @@ -/********************* */ -/*! \file lfsc_proof_printer.h - ** \verbatim - ** Top contributors (to current version): - ** Andres Noetzli, Alex Ozdemir, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief Prints proofs in the LFSC format - ** - ** Prints proofs in the LFSC format. - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__PROOF__LFSC_PROOF_PRINTER_H -#define CVC4__PROOF__LFSC_PROOF_PRINTER_H - -#include <iosfwd> -#include <string> -#include <vector> - -#include "proof/clause_id.h" -#include "proof/proof_manager.h" -#include "proof/sat_proof.h" -#include "proof/sat_proof_implementation.h" -#include "util/proof.h" - -namespace CVC4 { -namespace proof { - -class LFSCProofPrinter -{ - public: - /** - * Prints the resolution proof for an assumption conflict. - * - * @param satProof The record of the reasoning done by the SAT solver - * @param id The clause to print a proof for - * @param out The stream to print to - * @param paren A stream for the closing parentheses - */ - template <class Solver> - static void printAssumptionsResolution(TSatProof<Solver>* satProof, - ClauseId id, - std::ostream& out, - std::ostream& paren); - - /** - * Prints the resolution proofs for learned clauses that have been used to - * deduce unsat. - * - * @param satProof The record of the reasoning done by the SAT solver - * @param out The stream to print to - * @param paren A stream for the closing parentheses - */ - template <class Solver> - static void printResolutions(TSatProof<Solver>* satProof, - std::ostream& out, - std::ostream& paren); - - /** - * Prints the resolution proof for the empty clause. - * - * @param satProof The record of the reasoning done by the SAT solver - * @param out The stream to print to - * @param paren A stream for the closing parentheses - */ - template <class Solver> - static void printResolutionEmptyClause(TSatProof<Solver>* satProof, - std::ostream& out, - std::ostream& paren); - - /** - * The SAT solver is given a list of clauses. - * Assuming that each clause has alreay been individually proven, - * defines a proof of the input to the SAT solver. - * - * Prints an LFSC value corresponding to the proof, i.e. a value of type - * (cnf_holds ...) - * - * @param clauses The clauses to print a proof of - * @param out The stream to print to - * @param namingPrefix The prefix for LFSC names - */ - static void printSatInputProof(const std::vector<ClauseId>& clauses, - std::ostream& out, - const std::string& namingPrefix); - - /** - * The LRAT proof signature uses the concept of a _clause map_ (CMap), which - * represents an indexed collection of (conjoined) clauses. - * - * Specifically, the signatures rely on a proof that a CMap containing the - * clauses given to the SAT solver hold. - * - * Assuming that the individual clauses already have proofs, this function - * prints a proof of the CMap mapping 1 to the first clause, 2 to the second, - * and so on. - * - * That is, it prints a value of type (CMap_holds ...) - * - * @param clauses The clauses to print a proof of - * @param out The stream to print to - * @param namingPrefix The prefix for LFSC names - */ - static void printCMapProof(const std::vector<ClauseId>& clauses, - std::ostream& out, - const std::string& namingPrefix); - - /** - * Prints a clause - * - * @param clause The clause to print - * @param out The stream to print to - * @param namingPrefix The prefix for LFSC names - */ - static void printSatClause(const prop::SatClause& clause, - std::ostream& out, - const std::string& namingPrefix); - - private: - - /** - * Maps a clause id to a string identifier used in the LFSC proof. - * - * @param satProof The record of the reasoning done by the SAT solver - * @param id The clause to map to a string - */ - template <class Solver> - static std::string clauseName(TSatProof<Solver>* satProof, ClauseId id); - - /** - * Prints the resolution proof for a given clause. - * - * @param satProof The record of the reasoning done by the SAT solver - * @param id The clause to print a proof for - * @param out The stream to print to - * @param paren A stream for the closing parentheses - */ - template <class Solver> - static void printResolution(TSatProof<Solver>* satProof, - ClauseId id, - std::ostream& out, - std::ostream& paren); -}; - -} // namespace proof -} // namespace CVC4 - -#endif /* CVC4__PROOF__LFSC_PROOF_PRINTER_H */ diff --git a/src/proof/lrat/lrat_proof.cpp b/src/proof/lrat/lrat_proof.cpp deleted file mode 100644 index 69ffa623a..000000000 --- a/src/proof/lrat/lrat_proof.cpp +++ /dev/null @@ -1,343 +0,0 @@ -/********************* */ -/*! \file lrat_proof.cpp - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Andres Noetzli, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief DRAT Proof Format - ** - ** Defines deserialization for DRAT proofs. - **/ - -#include "proof/lrat/lrat_proof.h" - -#include <algorithm> -#include <cstdlib> -#include <fstream> -#include <iostream> -#include <memory> -#include <sstream> -#include <unordered_map> - -#include "base/check.h" -#include "base/output.h" -#include "proof/dimacs.h" -#include "proof/lfsc_proof_printer.h" -#include "util/utility.h" - -#if CVC4_USE_DRAT2ER -#include "drat2er_options.h" -#include "drat_trim_interface.h" -#endif - -namespace CVC4 { -namespace proof { -namespace lrat { - -using prop::SatClause; -using prop::SatLiteral; -using prop::SatVariable; - -namespace { - -// Prints the trace as a space-separated list of (+) ints with a space at the -// end. -std::ostream& operator<<(std::ostream& o, const LratUPTrace& trace) -{ - for (const auto& i : trace) - { - o << i << " "; - } - return o; -} - -/** - * Print a list of clause indices to go to while doing UP. - * - * i.e. a value of type Trace - * - * @param o where to print to - * @param trace the trace (list of clauses) to print - */ -void printTrace(std::ostream& o, const LratUPTrace& trace) -{ - for (ClauseIdx idx : trace) - { - o << "(Tracec " << idx << " "; - } - o << "Tracen"; - std::fill_n(std::ostream_iterator<char>(o), trace.size(), ')'); -} - -/** - * Print the RAT hints for a clause addition. - * - * i.e. prints an LFSC value of type RATHints - * - * @param o where to print to - * @param hints the RAT hints to print - */ -void printHints(std::ostream& o, - const std::vector<std::pair<ClauseIdx, LratUPTrace>>& hints) -{ - for (auto& hint : hints) - { - o << "\n (RATHintsc " << hint.first << " "; - printTrace(o, hint.second); - o << " "; - } - o << "RATHintsn"; - std::fill_n(std::ostream_iterator<char>(o), hints.size(), ')'); -} - -/** - * Print an index list - * - * i.e. prints an LFSC value of type CIList - * - * @param o where to print to - * @param indices the list of indices to print - */ -void printIndices(std::ostream& o, const std::vector<ClauseIdx>& indices) -{ - Assert(indices.size() > 0); - // Verify that the indices are sorted! - for (size_t i = 0, n = indices.size() - 1; i < n; ++i) - { - Assert(indices[i] < indices[i + 1]); - } - - for (ClauseIdx idx : indices) - { - o << "(CIListc " << idx << " "; - } - o << "CIListn"; - std::fill_n(std::ostream_iterator<char>(o), indices.size(), ')'); -} - -} // namespace - -// Prints the LRAT addition line in textual format - -LratProof LratProof::fromDratProof( - const std::unordered_map<ClauseId, prop::SatClause>& clauses, - const std::vector<ClauseId> usedIds, - const std::string& dratBinary, - TimerStat& toolTimer) -{ - std::ostringstream cmd; - std::string formulaFilename("cvc4-dimacs-XXXXXX"); - std::string dratFilename("cvc4-drat-XXXXXX"); - std::string lratFilename("cvc4-lrat-XXXXXX"); - - std::unique_ptr<std::fstream> formStream = openTmpFile(&formulaFilename); - printDimacs(*formStream, clauses, usedIds); - formStream->close(); - - std::unique_ptr<std::fstream> dratStream = openTmpFile(&dratFilename); - (*dratStream) << dratBinary; - dratStream->close(); - - std::unique_ptr<std::fstream> lratStream = openTmpFile(&lratFilename); - - { - CodeTimer blockTimer{toolTimer}; -#if CVC4_USE_DRAT2ER - drat2er::drat_trim::CheckAndConvertToLRAT( - formulaFilename, dratFilename, lratFilename, drat2er::options::QUIET); -#else - Unimplemented() - << "LRAT proof production requires drat2er.\n" - << "Run contrib/get-drat2er, reconfigure with --drat2er, and rebuild"; -#endif - } - - LratProof lrat(*lratStream); - remove(formulaFilename.c_str()); - remove(dratFilename.c_str()); - remove(lratFilename.c_str()); - return lrat; -} - -std::istream& operator>>(std::istream& in, SatLiteral& l) -{ - int64_t i; - in >> i; - l = SatLiteral(std::abs(i), i < 0); - return in; -} - -// This parser is implemented to parse the textual RAT format found in -// "Efficient Certified RAT Verification", by Cruz-Filipe et. All -LratProof::LratProof(std::istream& textualProof) -{ - for (size_t line = 0;; ++line) - { - // Read beginning of instruction. EOF indicates that we're done. - size_t clauseIdx; - textualProof >> clauseIdx; - if (textualProof.eof()) - { - return; - } - - // Read the first word of the instruction. A 'd' indicates deletion. - std::string first; - textualProof >> first; - Trace("pf::lrat") << "First word: " << first << std::endl; - Assert(textualProof.good()); - if (first == "d") - { - std::vector<ClauseIdx> clauses; - while (true) - { - ClauseIdx di; - textualProof >> di; - Assert(textualProof.good()); - if (di == 0) - { - break; - } - clauses.push_back(di); - } - if (clauses.size() > 0) - { - std::sort(clauses.begin(), clauses.end()); - std::unique_ptr<LratInstruction> instr( - new LratDeletion(clauseIdx, std::move(clauses))); - d_instructions.push_back(std::move(instr)); - } - } - else - { - // We need to reparse the first word as a literal to read the clause - // we're parsing. It ends with a 0; - std::istringstream firstS(first); - SatLiteral lit; - firstS >> lit; - Trace("pf::lrat") << "First lit: " << lit << std::endl; - Assert(!firstS.fail()) - << "Couldn't parse first literal from addition line"; - - SatClause clause; - for (; lit != 0; textualProof >> lit) - { - Assert(textualProof.good()); - clause.emplace_back(lit.getSatVariable() - 1, lit.isNegated()); - } - - // Now we read the AT UP trace. It ends at the first non-(+) # - std::vector<ClauseIdx> atTrace; - int64_t i; - textualProof >> i; - for (; i > 0; textualProof >> i) - { - Assert(textualProof.good()); - atTrace.push_back(i); - } - - // For each RAT hint... (each RAT hint starts with a (-)). - std::vector<std::pair<ClauseIdx, LratUPTrace>> resolvants; - for (; i<0; textualProof>> i) - { - Assert(textualProof.good()); - // Create an entry in the RAT hint list - resolvants.emplace_back(-i, std::vector<ClauseIdx>()); - - // Record the UP trace. It ends with a (-) or 0. - textualProof >> i; - for (; i > 0; textualProof >> i) - { - resolvants.back().second.push_back(i); - } - } - // Pairs compare based on the first element, so this sorts by the - // resolution target index - std::sort(resolvants.begin(), resolvants.end()); - std::unique_ptr<LratInstruction> instr( - new LratAddition(clauseIdx, - std::move(clause), - std::move(atTrace), - std::move(resolvants))); - d_instructions.push_back(std::move(instr)); - } - } -} - -void LratProof::outputAsLfsc(std::ostream& o) const -{ - std::ostringstream closeParen; - for (const auto& i : d_instructions) - { - i->outputAsLfsc(o, closeParen); - } - o << "LRATProofn"; - o << closeParen.str(); -} - -void LratAddition::outputAsText(std::ostream& o) const -{ - o << d_idxOfClause << " "; - textOut(o, d_clause) << " "; - o << d_atTrace; // Inludes a space at the end. - for (const auto& rat : d_resolvants) - { - o << "-" << rat.first << " "; - o << rat.second; // Includes a space at the end. - } - o << "0\n"; -} - -void LratAddition::outputAsLfsc(std::ostream& o, std::ostream& closeParen) const -{ - o << "\n (LRATProofa " << d_idxOfClause << " "; - closeParen << ")"; - LFSCProofPrinter::printSatClause(d_clause, o, "bb"); - o << " "; - printTrace(o, d_atTrace); - o << " "; - printHints(o, d_resolvants); - o << " "; -} - -void LratDeletion::outputAsText(std::ostream& o) const -{ - o << d_idxOfClause << " d "; - for (const auto& idx : d_clauses) - { - o << idx << " "; - } - o << "0\n"; -} - -void LratDeletion::outputAsLfsc(std::ostream& o, std::ostream& closeParen) const -{ - o << "\n (LRATProofd "; - closeParen << ")"; - printIndices(o, d_clauses); - o << " "; -} - -std::ostream& operator<<(std::ostream& o, const LratProof& p) -{ - for (const auto& instr : p.getInstructions()) - { - o << *instr; - } - return o; -} - -std::ostream& operator<<(std::ostream& o, const LratInstruction& i) -{ - i.outputAsText(o); - return o; -} - -} // namespace lrat -} // namespace proof -} // namespace CVC4 diff --git a/src/proof/lrat/lrat_proof.h b/src/proof/lrat/lrat_proof.h deleted file mode 100644 index 1c065a08e..000000000 --- a/src/proof/lrat/lrat_proof.h +++ /dev/null @@ -1,184 +0,0 @@ -/********************* */ -/*! \file lrat_proof.h - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief LRAT Proof Format - ** - ** Declares C++ types that represent a LRAT proof. - ** Defines serialization for these types. - ** - ** Represents an **abstract** LRAT proof. - ** Does **not** represent an LFSC LRAT proof, or an LRAT proof being used to - ** prove things about bit-vectors. - ** - ** Paper on LRAT: https://www.cs.utexas.edu/~marijn/publications/lrat.pdf - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__PROOF__LRAT__LRAT_PROOF_H -#define CVC4__PROOF__LRAT__LRAT_PROOF_H - -#include <iosfwd> -#include <string> -#include <unordered_map> -#include <utility> -#include <vector> - -#include "proof/clause_id.h" -// Included because we need operator<< for the SAT types -#include "prop/sat_solver.h" -#include "util/statistics_registry.h" - -namespace CVC4 { -namespace proof { -namespace lrat { - -// Refers to clause position within an LRAT proof -using ClauseIdx = size_t; - -// This is conceptually an Either<Addition,Deletion> -class LratInstruction -{ - public: - /** - * Write this LRAT instruction in textual format - * - * @param out the stream to write to - */ - virtual void outputAsText(std::ostream& out) const = 0; - /** - * Write this LRAT instruction as an LFSC value - * - * @param out the stream to write to - * @param closeParen the stream to write any closing parentheses to - * - */ - virtual void outputAsLfsc(std::ostream& o, - std::ostream& closeParen) const = 0; - virtual ~LratInstruction() = default; -}; - -class LratDeletion : public LratInstruction -{ - public: - LratDeletion(ClauseIdx idxOfClause, std::vector<ClauseIdx>&& clauses) - : d_idxOfClause(idxOfClause), d_clauses(clauses) - { - // Nothing left to do - } - - LratDeletion() = default; - - void outputAsText(std::ostream& out) const override; - void outputAsLfsc(std::ostream& o, std::ostream& closeParen) const override; - - private: - // This idx doesn't really matter, but it's in the format anyway, so we parse - // it. - ClauseIdx d_idxOfClause; - - // Clauses to delete - std::vector<ClauseIdx> d_clauses; -}; - -// A sequence of locations that will contain unit clauses during unit -// propegation -using LratUPTrace = std::vector<ClauseIdx>; - -class LratAddition : public LratInstruction -{ - public: - LratAddition(ClauseIdx idxOfClause, - prop::SatClause&& clause, - LratUPTrace&& atTrace, - std::vector<std::pair<ClauseIdx, LratUPTrace>> resolvants) - : d_idxOfClause(idxOfClause), - d_clause(clause), - d_atTrace(atTrace), - d_resolvants(resolvants) - { - // Nothing left to do - } - - void outputAsText(std::ostream& out) const override; - void outputAsLfsc(std::ostream& o, std::ostream& closeParen) const override; - - private: - // The idx for the new clause - ClauseIdx d_idxOfClause; - // The new clause - prop::SatClause d_clause; - // UP trace based on the negation of that clause - LratUPTrace d_atTrace; - - // Clauses that can resolve with `clause` on its first variable, - // together with a UP trace after that resolution. - // Used for RAT checks. - std::vector<std::pair<ClauseIdx, LratUPTrace>> d_resolvants; -}; - -class LratProof -{ - public: - /** - * @brief Construct an LRAT proof from a DRAT proof, using drat-trim - * - * @param clauses A store of clauses that might be in our formula - * @param usedIds the ids of clauses that are actually in our formula - * @param dratBinary The DRAT proof from the SAT solver, as a binary stream. - * - * @return an LRAT proof an a timer for how long it took to run drat-trim - */ - static LratProof fromDratProof( - const std::unordered_map<ClauseId, prop::SatClause>& clauses, - const std::vector<ClauseId> usedIds, - const std::string& dratBinary, - TimerStat& toolTimer); - /** - * @brief Construct an LRAT proof from its textual representation - * - * @param textualProof the textual encoding of the LRAT proof. See the paper - * in the file's header comment. - */ - LratProof(std::istream& textualProof); - - /** - * Construct a LRAT proof from an explicit instruction list - * - * @param instructions - */ - LratProof(std::vector<std::unique_ptr<LratInstruction>>&& instructions) - : d_instructions(std::move(instructions)) - { - // Nothing else - } - - const std::vector<std::unique_ptr<LratInstruction>>& getInstructions() const - { - return d_instructions; - } - - void outputAsLfsc(std::ostream& o) const; - - private: - // The instructions in the proof. Each is a deletion or addition. - std::vector<std::unique_ptr<LratInstruction>> d_instructions; -}; - -// Prints the LRAT proof in textual format -std::ostream& operator<<(std::ostream& o, const LratProof& p); -std::ostream& operator<<(std::ostream& o, const LratInstruction& i); - -} // namespace lrat -} // namespace proof -} // namespace CVC4 - -#endif diff --git a/src/proof/proof.h b/src/proof/proof.h deleted file mode 100644 index be5af32db..000000000 --- a/src/proof/proof.h +++ /dev/null @@ -1,70 +0,0 @@ -/********************* */ -/*! \file proof.h - ** \verbatim - ** Top contributors (to current version): - ** Tim King, Liana Hadarean, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief Proof macros - ** - ** Proof macros - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__PROOF__PROOF_H -#define CVC4__PROOF__PROOF_H - -#include "options/smt_options.h" - - -/* Do NOT use #ifdef CVC4_PROOF to check if proofs are enabled. - * We cannot assume users will use -DCVC4_PROOFS if they have a proofs build. - * The preferred way of checking that proofs are enabled is to use: - * #if IS_PROOFS_BUILD - * ... - * #endif - * - * The macro IS_PROOFS_BUILD is defined in base/configuration_private.h - * - * This has the effect of forcing that location to have included this header - * *before* performing this test. This includes C preprocessing expansion. - * This forces the inclusion of "cvc4_private.h". This is intentional! - * - * See bug 688 for more details: - * https://github.com/CVC4/CVC4/issues/907 - * - * If you want to check CVC4_PROOF, you should have a very good reason - * and should list the exceptions here: - * - Makefile.am - * - proof/proofs.h - * - base/configuration_private.h - */ - -#ifdef CVC4_PROOF -# 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 99e3010b4..3e6cc9c69 100644 --- a/src/proof/proof_manager.cpp +++ b/src/proof/proof_manager.cpp @@ -21,14 +21,10 @@ #include "context/context.h" #include "expr/node_visitor.h" #include "options/bv_options.h" -#include "options/proof_options.h" +#include "options/smt_options.h" #include "proof/clause_id.h" #include "proof/cnf_proof.h" -#include "proof/lfsc_proof_printer.h" -#include "proof/proof_utils.h" -#include "proof/resolution_bitvector_proof.h" #include "proof/sat_proof_implementation.h" -#include "proof/theory_proof.h" #include "smt/smt_engine.h" #include "smt/smt_engine_scope.h" #include "smt/smt_statistics_registry.h" @@ -39,36 +35,16 @@ #include "theory/uf/theory_uf.h" #include "theory/valuation.h" #include "util/hash.h" -#include "util/proof.h" namespace CVC4 { -std::string nodeSetToString(const std::set<Node>& nodes) { - std::ostringstream os; - std::set<Node>::const_iterator it; - for (it = nodes.begin(); it != nodes.end(); ++it) { - os << *it << " "; - } - return os.str(); -} - -std::string append(const std::string& str, uint64_t num) { - std::ostringstream os; - os << str << num; - return os.str(); -} - -ProofManager::ProofManager(context::Context* context, ProofFormat format) +ProofManager::ProofManager(context::Context* context) : d_context(context), d_satProof(nullptr), d_cnfProof(nullptr), - d_theoryProof(nullptr), - d_inputFormulas(), d_inputCoreFormulas(context), d_outputCoreFormulas(context), d_nextId(0), - d_fullProof(), - d_format(format), d_deps(context) { } @@ -78,19 +54,6 @@ ProofManager::~ProofManager() {} ProofManager* ProofManager::currentPM() { return smt::currentProofManager(); } -const Proof& ProofManager::getProof(SmtEngine* smt) -{ - if (!currentPM()->d_fullProof) - { - Assert(currentPM()->d_format == LFSC); - currentPM()->d_fullProof.reset(new LFSCProof( - smt, - getSatProof(), - static_cast<LFSCCnfProof*>(getCnfProof()), - static_cast<LFSCTheoryProofEngine*>(getTheoryProofEngine()))); - } - return *(currentPM()->d_fullProof); -} CoreSatProof* ProofManager::getSatProof() { @@ -104,45 +67,8 @@ CnfProof* ProofManager::getCnfProof() return currentPM()->d_cnfProof.get(); } -TheoryProofEngine* ProofManager::getTheoryProofEngine() -{ - Assert(currentPM()->d_theoryProof != NULL); - return currentPM()->d_theoryProof.get(); -} - -UFProof* ProofManager::getUfProof() { - Assert(options::proof()); - TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_UF); - return (UFProof*)pf; -} - -proof::ResolutionBitVectorProof* ProofManager::getBitVectorProof() -{ - Assert(options::proof()); - TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_BV); - return static_cast<proof::ResolutionBitVectorProof*>(pf); -} - -ArrayProof* ProofManager::getArrayProof() { - Assert(options::proof()); - TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_ARRAYS); - return (ArrayProof*)pf; -} - -ArithProof* ProofManager::getArithProof() { - Assert(options::proof()); - TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_ARITH); - return (ArithProof*)pf; -} - -SkolemizationManager* ProofManager::getSkolemizationManager() { - Assert(options::proof() || options::unsatCores()); - return &(currentPM()->d_skolemizationManager); -} - void ProofManager::initSatProof(Minisat::Solver* solver) { - Assert(d_format == LFSC); // Destroy old instance before initializing new one to avoid issues with // registering stats d_satProof.reset(); @@ -153,150 +79,22 @@ void ProofManager::initCnfProof(prop::CnfStream* cnfStream, context::Context* ctx) { Assert(d_satProof != nullptr); - Assert(d_format == LFSC); - d_cnfProof.reset(new LFSCCnfProof(cnfStream, ctx, "")); + d_cnfProof.reset(new CnfProof(cnfStream, ctx, "")); // 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_satProof->getTrueUnit()); d_cnfProof->popCurrentAssertion(); - d_cnfProof->popCurrentDefinition(); d_cnfProof->pushCurrentAssertion(false_node); - d_cnfProof->pushCurrentDefinition(false_node); d_cnfProof->registerConvertedClause(d_satProof->getFalseUnit()); d_cnfProof->popCurrentAssertion(); - d_cnfProof->popCurrentDefinition(); -} - -void ProofManager::initTheoryProofEngine() -{ - Assert(d_theoryProof == NULL); - Assert(d_format == LFSC); - d_theoryProof.reset(new LFSCTheoryProofEngine()); -} - -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::getPreprocessedAssertionName(Node node, - const std::string& prefix) { - if (currentPM()->d_assertionFilters.find(node) != currentPM()->d_assertionFilters.end()) { - return currentPM()->d_assertionFilters[node]; - } - - 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::getInputFormulaName(const Expr& expr) { - return currentPM()->d_inputFormulaToName[expr]; -} - -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(), prefix); -} - -std::string ProofManager::getLitName(TNode lit, - const std::string& prefix) { - std::string litName = getLitName(currentPM()->d_cnfProof->getLiteral(lit), prefix); - if (currentPM()->d_rewriteFilters.find(litName) != currentPM()->d_rewriteFilters.end()) { - return currentPM()->d_rewriteFilters[litName]; - } - - return litName; -} - -bool ProofManager::hasLitName(TNode lit) { - return currentPM()->d_cnfProof->hasLiteral(lit); -} - -std::string ProofManager::sanitize(TNode node) { - Assert(node.isVar() || node.isConst()); - - std::string name = node.toString(); - if (node.isVar()) { - std::replace(name.begin(), name.end(), ' ', '_'); - } else if (node.isConst()) { - name.erase(std::remove(name.begin(), name.end(), '('), name.end()); - name.erase(std::remove(name.begin(), name.end(), ')'), name.end()); - name.erase(std::remove(name.begin(), name.end(), ' '), name.end()); - name = "const" + name; - } - - return name; -} - -void ProofManager::traceDeps(TNode n, ExprSet* coreAssertions) { - 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; - coreAssertions->insert(n.toExpr()); - } else { - Debug("cores") << " -- NOT IN INPUT CORE LIST!" << std::endl; - if(d_deps.find(n) == d_deps.end()) { - if (options::allowEmptyDependencies()) { - Debug("cores") << " -- Could not track cause assertion. Failing silently." << std::endl; - return; - } - InternalError() - << "Cannot trace dependence information back to input assertion:\n`" - << n << "'"; - } - Assert(d_deps.find(n) != d_deps.end()); - std::vector<Node> deps = (*d_deps.find(n)).second; - for(std::vector<Node>::const_iterator i = deps.begin(); i != deps.end(); ++i) { - Debug("cores") << " + tracing deps: " << n << " -deps-on- " << *i << std::endl; - if( !(*i).isNull() ){ - traceDeps(*i, coreAssertions); - } - } - } -} void ProofManager::traceDeps(TNode n, CDExprSet* coreAssertions) { Debug("cores") << "trace deps " << n << std::endl; @@ -311,10 +109,6 @@ void ProofManager::traceDeps(TNode n, CDExprSet* coreAssertions) { } else { Debug("cores") << " -- NOT IN INPUT CORE LIST!" << std::endl; if(d_deps.find(n) == d_deps.end()) { - if (options::allowEmptyDependencies()) { - Debug("cores") << " -- Could not track cause assertion. Failing silently." << std::endl; - return; - } InternalError() << "Cannot trace dependence information back to input assertion:\n`" << n << "'"; @@ -345,16 +139,11 @@ void ProofManager::traceUnsatCore() { 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, &d_outputCoreFormulas); - } + Debug("cores") << "core input assertion " << node << "\n"; + // trace dependences back to actual assertions + // (this adds them to the unsat core) + traceDeps(node, &d_outputCoreFormulas); } } @@ -373,150 +162,32 @@ std::vector<Expr> ProofManager::extractUnsatCore() { return result; } -void ProofManager::constructSatProof() { - if (!d_satProof->proofConstructed()) { +void ProofManager::constructSatProof() +{ + if (!d_satProof->proofConstructed()) + { d_satProof->constructProof(); } } -void ProofManager::getLemmasInUnsatCore(theory::TheoryId theory, std::vector<Node> &lemmas) { - Assert(PROOF_ON()) << "Cannot compute unsat core when proofs are off"; - Assert(unsatCoreAvailable()) - << "Cannot get unsat core at this time. Mabye the input is SAT?"; - - constructSatProof(); - - IdToSatClause used_lemmas; - IdToSatClause used_inputs; - d_satProof->collectClausesUsed(used_inputs, used_lemmas); - - IdToSatClause::const_iterator it; - std::set<Node> seen; - - Debug("pf::lemmasUnsatCore") << "Dumping all lemmas in unsat core" << std::endl; - for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) { - std::set<Node> lemma = satClauseToNodeSet(it->second); - Debug("pf::lemmasUnsatCore") << nodeSetToString(lemma); - - // TODO: we should be able to drop the "haveProofRecipe" check. - // however, there are some rewrite issues with the arith solver, resulting - // in non-registered recipes. For now we assume no one is requesting arith lemmas. - LemmaProofRecipe recipe; - if (!getCnfProof()->haveProofRecipe(lemma)) { - Debug("pf::lemmasUnsatCore") << "\t[no recipe]" << std::endl; - continue; - } - - recipe = getCnfProof()->getProofRecipe(lemma); - Debug("pf::lemmasUnsatCore") << "\t[owner = " << recipe.getTheory() - << ", original = " << recipe.getOriginalLemma() << "]" << std::endl; - if (recipe.simpleLemma() && recipe.getTheory() == theory && seen.find(recipe.getOriginalLemma()) == seen.end()) { - lemmas.push_back(recipe.getOriginalLemma()); - seen.insert(recipe.getOriginalLemma()); - } - } -} - -std::set<Node> ProofManager::satClauseToNodeSet(prop::SatClause* clause) { - std::set<Node> result; - for (unsigned i = 0; i < clause->size(); ++i) { - prop::SatLiteral lit = (*clause)[i]; - Node node = getCnfProof()->getAtom(lit.getSatVariable()); - Expr atom = node.toExpr(); - if (atom != utils::mkTrue()) - result.insert(lit.isNegated() ? node.notNode() : node); - } - - return result; -} - -Node ProofManager::getWeakestImplicantInUnsatCore(Node lemma) { - Assert(PROOF_ON()) << "Cannot compute unsat core when proofs are off"; +void ProofManager::getLemmasInUnsatCore(std::vector<Node>& lemmas) +{ + Assert(options::unsatCores()) + << "Cannot compute unsat core when proofs are off"; Assert(unsatCoreAvailable()) << "Cannot get unsat core at this time. Mabye the input is SAT?"; - - // If we're doing aggressive minimization, work on all lemmas, not just conjunctions. - if (!options::aggressiveCoreMin() && (lemma.getKind() != kind::AND)) - return lemma; - constructSatProof(); - - NodeBuilder<> builder(kind::AND); - IdToSatClause used_lemmas; IdToSatClause used_inputs; d_satProof->collectClausesUsed(used_inputs, used_lemmas); - + Debug("pf::lemmasUnsatCore") << "Retrieving all lemmas in unsat core\n"; IdToSatClause::const_iterator it; - std::set<Node>::iterator lemmaIt; - - if (!options::aggressiveCoreMin()) { - for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) { - std::set<Node> currentLemma = satClauseToNodeSet(it->second); - - // TODO: we should be able to drop the "haveProofRecipe" check. - // however, there are some rewrite issues with the arith solver, resulting - // in non-registered recipes. For now we assume no one is requesting arith lemmas. - LemmaProofRecipe recipe; - if (!getCnfProof()->haveProofRecipe(currentLemma)) - continue; - - recipe = getCnfProof()->getProofRecipe(currentLemma); - if (recipe.getOriginalLemma() == lemma) { - for (lemmaIt = currentLemma.begin(); lemmaIt != currentLemma.end(); ++lemmaIt) { - builder << *lemmaIt; - - // Check that each conjunct appears in the original lemma. - bool found = false; - for (unsigned i = 0; i < lemma.getNumChildren(); ++i) { - if (lemma[i] == *lemmaIt) - found = true; - } - - if (!found) - return lemma; - } - } - } - } else { - // Aggressive mode - for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) { - std::set<Node> currentLemma = satClauseToNodeSet(it->second); - - // TODO: we should be able to drop the "haveProofRecipe" check. - // however, there are some rewrite issues with the arith solver, resulting - // in non-registered recipes. For now we assume no one is requesting arith lemmas. - LemmaProofRecipe recipe; - if (!getCnfProof()->haveProofRecipe(currentLemma)) - continue; - - recipe = getCnfProof()->getProofRecipe(currentLemma); - if (recipe.getOriginalLemma() == lemma) { - NodeBuilder<> disjunction(kind::OR); - for (lemmaIt = currentLemma.begin(); lemmaIt != currentLemma.end(); ++lemmaIt) { - disjunction << *lemmaIt; - } - - Node conjunct = (disjunction.getNumChildren() == 1) ? disjunction[0] : disjunction; - builder << conjunct; - } - } + for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) + { + Node lemma = d_cnfProof->getAssertionForClause(it->first); + Debug("pf::lemmasUnsatCore") << "Retrieved lemma " << lemma << "\n"; + lemmas.push_back(lemma); } - - AlwaysAssert(builder.getNumChildren() != 0); - - if (builder.getNumChildren() == 1) - return builder[0]; - - return builder; -} - -void ProofManager::addAssertion(Expr formula) { - Debug("proof:pm") << "assert: " << formula << std::endl; - d_inputFormulas.insert(formula); - std::ostringstream name; - name << "A" << d_inputFormulaToName.size(); - d_inputFormulaToName[formula] = name.str(); } void ProofManager::addCoreAssertion(Expr formula) { @@ -542,665 +213,4 @@ void ProofManager::addUnsatCore(Expr formula) { d_outputCoreFormulas.insert(formula); } -void ProofManager::addAssertionFilter(const Node& node, const std::string& rewritten) { - d_assertionFilters[node] = rewritten; -} - -void ProofManager::setLogic(const LogicInfo& logic) { - d_logic = logic; -} - -LFSCProof::LFSCProof(SmtEngine* smtEngine, - CoreSatProof* sat, - LFSCCnfProof* cnf, - LFSCTheoryProofEngine* theory) - : d_satProof(sat), - d_cnfProof(cnf), - d_theoryProof(theory), - d_smtEngine(smtEngine) -{} - -void LFSCProof::toStream(std::ostream& out, const ProofLetMap& map) const -{ - Unreachable(); -} - -void collectAtoms(TNode node, std::set<Node>& seen, CnfProof* cnfProof) -{ - Debug("pf::pm::atoms") << "collectAtoms: Colleting atoms from " << node - << "\n"; - if (seen.find(node) != seen.end()) - { - Debug("pf::pm::atoms") << "collectAtoms:\t already seen\n"; - return; - } - // if I have a SAT literal for a node, save it, unless this node is a - // negation, in which case its underlying will be collected downstream - if (cnfProof->hasLiteral(node) && node.getKind() != kind::NOT) - { - Debug("pf::pm::atoms") << "collectAtoms: has SAT literal, save\n"; - seen.insert(node); - } - for (unsigned i = 0; i < node.getNumChildren(); ++i) - { - Debug("pf::pm::atoms") << push; - collectAtoms(node[i], seen, cnfProof); - Debug("pf::pm::atoms") << pop; - } -} - -void LFSCProof::toStream(std::ostream& out) const -{ - TimerStat::CodeTimer proofProductionTimer( - ProofManager::currentPM()->getStats().d_proofProductionTime); - - IdToSatClause used_lemmas; - IdToSatClause used_inputs; - std::set<Node> atoms; - NodePairSet rewrites; - NodeSet used_assertions; - - { - CodeTimer skeletonProofTimer{ - ProofManager::currentPM()->getStats().d_skeletonProofTraceTime}; - Assert(!d_satProof->proofConstructed()); - - // Here we give our SAT solver a chance to flesh out the resolution proof. - // It proves bottom from a set of clauses. - d_satProof->constructProof(); - - // We ask the SAT solver which clauses are used in that proof. - // For a resolution proof, these are the leaves of the tree. - d_satProof->collectClausesUsed(used_inputs, used_lemmas); - - IdToSatClause::iterator it2; - Debug("pf::pm") << std::endl << "Used inputs: " << std::endl; - for (it2 = used_inputs.begin(); it2 != used_inputs.end(); ++it2) - { - Debug("pf::pm") << "\t input = " << *(it2->second) << std::endl; - } - Debug("pf::pm") << std::endl; - - Debug("pf::pm") << std::endl << "Used lemmas: " << std::endl; - for (it2 = used_lemmas.begin(); it2 != used_lemmas.end(); ++it2) - { - std::vector<Expr> clause_expr; - for (unsigned i = 0; i < it2->second->size(); ++i) - { - prop::SatLiteral lit = (*(it2->second))[i]; - Expr atom = d_cnfProof->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); - } - - Debug("pf::pm") << "\t lemma " << it2->first << " = " << *(it2->second) - << std::endl; - Debug("pf::pm") << "\t"; - for (unsigned i = 0; i < clause_expr.size(); ++i) - { - Debug("pf::pm") << clause_expr[i] << " "; - } - Debug("pf::pm") << std::endl; - } - Debug("pf::pm") << std::endl; - - // collecting assertions that lead to the clauses being asserted - d_cnfProof->collectAssertionsForClauses(used_inputs, used_assertions); - - NodeSet::iterator it3; - Debug("pf::pm") << std::endl << "Used assertions: " << std::endl; - for (it3 = used_assertions.begin(); it3 != used_assertions.end(); ++it3) - Debug("pf::pm") << "\t assertion = " << *it3 << std::endl; - - // collects the atoms in the clauses - d_cnfProof->collectAtomsAndRewritesForLemmas(used_lemmas, atoms, rewrites); - - if (!rewrites.empty()) - { - Debug("pf::pm") << std::endl << "Rewrites used in lemmas: " << std::endl; - NodePairSet::const_iterator rewriteIt; - for (rewriteIt = rewrites.begin(); rewriteIt != rewrites.end(); - ++rewriteIt) - { - Debug("pf::pm") << "\t" << rewriteIt->first << " --> " - << rewriteIt->second << std::endl; - } - Debug("pf::pm") << std::endl << "Rewrite printing done" << std::endl; - } - else - { - Debug("pf::pm") << "No rewrites in lemmas found" << std::endl; - } - - // The derived/unrewritten atoms may not have CNF literals required later - // on. If they don't, add them. - std::set<Node>::const_iterator it; - for (it = atoms.begin(); it != atoms.end(); ++it) - { - Debug("pf::pm") << "Ensure literal for atom: " << *it << std::endl; - if (!d_cnfProof->hasLiteral(*it)) - { - // For arithmetic: these literals are not normalized, causing an error - // in Arith. - if (theory::Theory::theoryOf(*it) == theory::THEORY_ARITH) - { - d_cnfProof->ensureLiteral( - *it, - true); // This disables preregistration with the theory solver. - } - else - { - d_cnfProof->ensureLiteral( - *it); // Normal method, with theory solver preregisteration. - } - } - } - - // From the clauses, compute the atoms (atomic theory predicates in - // assertions and lemmas). - d_cnfProof->collectAtomsForClauses(used_inputs, atoms); - d_cnfProof->collectAtomsForClauses(used_lemmas, atoms); - - // collects the atoms in the assertions - Debug("pf::pm") << std::endl - << "LFSCProof::toStream: Colleting atoms from assertions " - << used_assertions << "\n" - << push; - for (TNode used_assertion : used_assertions) - { - collectAtoms(used_assertion, atoms, d_cnfProof); - } - Debug("pf::pm") << pop; - - std::set<Node>::iterator atomIt; - Debug("pf::pm") << std::endl - << "Dumping atoms from lemmas, inputs and assertions: " - << std::endl - << std::endl; - for (atomIt = atoms.begin(); atomIt != atoms.end(); ++atomIt) - { - Debug("pf::pm") << "\tAtom: " << *atomIt << std::endl; - } - } - - smt::SmtScope scope(d_smtEngine); - ProofLetMap globalLetMap; - std::ostringstream paren; - { - CodeTimer declTimer{ - ProofManager::currentPM()->getStats().d_proofDeclarationsTime}; - out << "(check\n"; - paren << ")"; - out << " ;; Declarations\n"; - - // declare the theory atoms - Debug("pf::pm") << "LFSCProof::toStream: registering terms:" << std::endl; - for (std::set<Node>::const_iterator it = atoms.begin(); it != atoms.end(); ++it) - { - Debug("pf::pm") << "\tTerm: " << (*it).toExpr() << std::endl; - d_theoryProof->registerTerm((*it).toExpr()); - } - - Debug("pf::pm") << std::endl - << "Term registration done!" << std::endl - << std::endl; - - Debug("pf::pm") << std::endl - << "LFSCProof::toStream: starting to print assertions" - << std::endl; - - // print out all the original assertions - d_theoryProof->registerTermsFromAssertions(); - d_theoryProof->printSortDeclarations(out, paren); - d_theoryProof->printTermDeclarations(out, paren); - d_theoryProof->printAssertions(out, paren); - - Debug("pf::pm") << std::endl - << "LFSCProof::toStream: print assertions DONE" - << std::endl; - - out << "(: (holds cln)\n\n"; - paren << ")"; - - // Have the theory proofs print deferred declarations, e.g. for skolem - // variables. - out << " ;; Printing deferred declarations \n\n"; - d_theoryProof->printDeferredDeclarations(out, paren); - - out << "\n ;; Printing the global let map"; - d_theoryProof->finalizeBvConflicts(used_lemmas, out); - ProofManager::getBitVectorProof()->calculateAtomsInBitblastingProof(); - if (options::lfscLetification()) - { - ProofManager::currentPM()->printGlobalLetMap( - atoms, globalLetMap, out, paren); - } - - out << " ;; Printing aliasing declarations \n\n"; - d_theoryProof->printAliasingDeclarations(out, paren, globalLetMap); - - out << " ;; Rewrites for Lemmas \n"; - d_theoryProof->printLemmaRewrites(rewrites, out, paren); - - // print trust that input assertions are their preprocessed form - printPreprocessedAssertions(used_assertions, out, paren, globalLetMap); - } - - { - CodeTimer cnfProofTimer{ - ProofManager::currentPM()->getStats().d_cnfProofTime}; - // print mapping between theory atoms and internal SAT variables - out << ";; Printing mapping from preprocessed assertions into atoms \n"; - d_cnfProof->printAtomMapping(atoms, out, paren, globalLetMap); - - Debug("pf::pm") << std::endl - << "Printing cnf proof for clauses" << std::endl; - - 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); - } - } - - { - CodeTimer theoryLemmaTimer{ - ProofManager::currentPM()->getStats().d_theoryLemmaTime}; - Debug("pf::pm") << std::endl - << "Printing cnf proof for clauses DONE" << std::endl; - - Debug("pf::pm") << "Proof manager: printing theory lemmas" << std::endl; - d_theoryProof->printTheoryLemmas(used_lemmas, out, paren, globalLetMap); - Debug("pf::pm") << "Proof manager: printing theory lemmas DONE!" - << std::endl; - } - - { - CodeTimer finalProofTimer{ - ProofManager::currentPM()->getStats().d_finalProofTime}; - out << ";; Printing final unsat proof \n"; - if (options::bitblastMode() == options::BitblastMode::EAGER - && ProofManager::getBitVectorProof()) - { - ProofManager::getBitVectorProof()->printEmptyClauseProof(out, paren); - } - else - { - // print actual resolution proof - proof::LFSCProofPrinter::printResolutions(d_satProof, out, paren); - proof::LFSCProofPrinter::printResolutionEmptyClause( - d_satProof, out, paren); - } - } - - out << paren.str(); - out << "\n;;\n"; -} - -void LFSCProof::printPreprocessedAssertions(const NodeSet& assertions, - std::ostream& os, - std::ostream& paren, - ProofLetMap& globalLetMap) const -{ - os << "\n ;; In the preprocessor we trust \n"; - NodeSet::const_iterator it = assertions.begin(); - NodeSet::const_iterator end = assertions.end(); - - Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions starting" << std::endl; - - if (options::fewerPreprocessingHoles()) { - // Check for assertions that did not get rewritten, and update the printing filter. - checkUnrewrittenAssertion(assertions); - - // For the remaining assertions, bind them to input assertions. - for (; it != end; ++it) { - // Rewrite preprocessing step if it cannot be eliminated - if (!ProofManager::currentPM()->have_input_assertion((*it).toExpr())) { - os << "(th_let_pf _ (trust_f (iff "; - - Expr inputAssertion; - - if (((*it).isConst() && *it == NodeManager::currentNM()->mkConst<bool>(true)) || - ((*it).getKind() == kind::NOT && (*it)[0] == NodeManager::currentNM()->mkConst<bool>(false))) { - inputAssertion = NodeManager::currentNM()->mkConst<bool>(true).toExpr(); - } else { - // Figure out which input assertion led to this assertion - ExprSet inputAssertions; - ProofManager::currentPM()->traceDeps(*it, &inputAssertions); - - Debug("pf::pm") << "Original assertions for " << *it << " are: " << std::endl; - - ProofManager::assertions_iterator assertionIt; - for (assertionIt = inputAssertions.begin(); assertionIt != inputAssertions.end(); ++assertionIt) { - Debug("pf::pm") << "\t" << *assertionIt << std::endl; - } - - if (inputAssertions.size() == 0) { - Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Count NOT find the assertion that caused this PA. Picking an arbitrary one..." << std::endl; - // For now just use the first assertion... - inputAssertion = *(ProofManager::currentPM()->begin_assertions()); - } else { - if (inputAssertions.size() != 1) { - Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Attention: more than one original assertion was found. Picking just one." << std::endl; - } - inputAssertion = *inputAssertions.begin(); - } - } - - if (!ProofManager::currentPM()->have_input_assertion(inputAssertion)) { - // The thing returned by traceDeps does not appear in the input assertions... - Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Count NOT find the assertion that caused this PA. Picking an arbitrary one..." << std::endl; - // For now just use the first assertion... - inputAssertion = *(ProofManager::currentPM()->begin_assertions()); - } - - Debug("pf::pm") << "Original assertion for " << *it - << " is: " - << inputAssertion - << ", AKA " - << ProofManager::currentPM()->getInputFormulaName(inputAssertion) - << std::endl; - - ProofManager::currentPM()->getTheoryProofEngine()->printTheoryTerm(inputAssertion, os, globalLetMap); - os << " "; - ProofManager::currentPM()->printTrustedTerm(*it, os, globalLetMap); - os << "))"; - os << "(\\ "<< ProofManager::getPreprocessedAssertionName(*it, "") << "\n"; - paren << "))"; - - std::ostringstream rewritten; - - rewritten << "(or_elim_1 _ _ "; - rewritten << "(not_not_intro _ "; - rewritten << ProofManager::currentPM()->getInputFormulaName(inputAssertion); - rewritten << ") (iff_elim_1 _ _ "; - rewritten << ProofManager::getPreprocessedAssertionName(*it, ""); - rewritten << "))"; - - ProofManager::currentPM()->addAssertionFilter(*it, rewritten.str()); - } - } - } else { - for (; it != end; ++it) { - os << "(th_let_pf _ "; - - //TODO - os << "(trust_f "; - ProofManager::currentPM()->printTrustedTerm(*it, os, globalLetMap); - os << ") "; - - os << "(\\ "<< ProofManager::getPreprocessedAssertionName(*it, "") << "\n"; - paren << "))"; - } - } - - os << "\n"; -} - -void LFSCProof::checkUnrewrittenAssertion(const NodeSet& rewrites) const -{ - Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion starting" << std::endl; - - NodeSet::const_iterator rewrite; - for (rewrite = rewrites.begin(); rewrite != rewrites.end(); ++rewrite) { - Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: handling " << *rewrite << std::endl; - if (ProofManager::currentPM()->have_input_assertion((*rewrite).toExpr())) { - Assert( - ProofManager::currentPM()->have_input_assertion((*rewrite).toExpr())); - Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: this assertion was NOT rewritten!" << std::endl - << "\tAdding filter: " - << ProofManager::getPreprocessedAssertionName(*rewrite, "") - << " --> " - << ProofManager::currentPM()->getInputFormulaName((*rewrite).toExpr()) - << std::endl; - ProofManager::currentPM()->addAssertionFilter(*rewrite, - ProofManager::currentPM()->getInputFormulaName((*rewrite).toExpr())); - } else { - Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: this assertion WAS rewritten! " << *rewrite << std::endl; - } - } -} - -//---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) { - Trace("mgd-pm-mkop") << "MkOp : " << n << " " << n.getKind() << std::endl; - if(n.getKind() != kind::BUILTIN) { - return n; - } - - Node& op = d_ops[n]; - if(op.isNull()) { - Assert((n.getConst<Kind>() == kind::SELECT) - || (n.getConst<Kind>() == kind::STORE)); - - Debug("mgd-pm-mkop") << "making an op for " << n << "\n"; - - std::stringstream ss; - ss << n; - std::string s = ss.str(); - Debug("mgd-pm-mkop") << " : " << 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); - Debug("mgd-pm-mkop") << "typenode is: " << type << "\n"; - op = NodeManager::currentNM()->mkSkolem(s, type, " ignore", NodeManager::SKOLEM_NO_NOTIFY); - d_bops[op] = n; - } - Debug("mgd-pm-mkop") << "returning the op: " << op << "\n"; - return op; -} -//---end from Morgan--- - -bool ProofManager::wasPrinted(const Type& type) const { - return d_printedTypes.find(type) != d_printedTypes.end(); -} - -void ProofManager::markPrinted(const Type& type) { - d_printedTypes.insert(type); -} - -void ProofManager::addRewriteFilter(const std::string &original, const std::string &substitute) { - d_rewriteFilters[original] = substitute; -} - -bool ProofManager::haveRewriteFilter(TNode lit) { - std::string litName = getLitName(currentPM()->d_cnfProof->getLiteral(lit)); - return d_rewriteFilters.find(litName) != d_rewriteFilters.end(); -} - -void ProofManager::clearRewriteFilters() { - d_rewriteFilters.clear(); -} - -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; -} - -void ProofManager::registerRewrite(unsigned ruleId, Node original, Node result){ - Assert(currentPM()->d_theoryProof != NULL); - currentPM()->d_rewriteLog.push_back(RewriteLogEntry(ruleId, original, result)); -} - -void ProofManager::clearRewriteLog() { - Assert(currentPM()->d_theoryProof != NULL); - currentPM()->d_rewriteLog.clear(); -} - -std::vector<RewriteLogEntry> ProofManager::getRewriteLog() { - return currentPM()->d_rewriteLog; -} - -void ProofManager::dumpRewriteLog() const { - Debug("pf::rr") << "Dumpign rewrite log:" << std::endl; - - for (unsigned i = 0; i < d_rewriteLog.size(); ++i) { - Debug("pf::rr") << "\tRule " << d_rewriteLog[i].getRuleId() - << ": " - << d_rewriteLog[i].getOriginal() - << " --> " - << d_rewriteLog[i].getResult() << std::endl; - } -} - -void bind(Expr term, ProofLetMap& map, Bindings& letOrder) { - ProofLetMap::iterator it = map.find(term); - if (it != map.end()) - return; - - for (unsigned i = 0; i < term.getNumChildren(); ++i) - bind(term[i], map, letOrder); - - // Special case: chain operators. If we have and(a,b,c), it will be prineted as and(a,and(b,c)). - // The subterm and(b,c) may repeat elsewhere, so we need to bind it, too. - Kind k = term.getKind(); - if (((k == kind::OR) || (k == kind::AND)) && term.getNumChildren() > 2) { - Node currentExpression = term[term.getNumChildren() - 1]; - for (int i = term.getNumChildren() - 2; i >= 0; --i) { - NodeBuilder<> builder(k); - builder << term[i]; - builder << currentExpression.toExpr(); - currentExpression = builder; - bind(currentExpression.toExpr(), map, letOrder); - } - } else { - unsigned newId = ProofLetCount::newId(); - ProofLetCount letCount(newId); - map[term] = letCount; - letOrder.push_back(LetOrderElement(term, newId)); - } -} - -void ProofManager::printGlobalLetMap(std::set<Node>& atoms, - ProofLetMap& letMap, - std::ostream& out, - std::ostringstream& paren) { - Bindings letOrder; - std::set<Node>::const_iterator atom; - for (atom = atoms.begin(); atom != atoms.end(); ++atom) { - bind(atom->toExpr(), letMap, letOrder); - } - - // TODO: give each theory a chance to add atoms. For now, just query BV directly... - const std::set<Node>* additionalAtoms = ProofManager::getBitVectorProof()->getAtomsInBitblastingProof(); - for (atom = additionalAtoms->begin(); atom != additionalAtoms->end(); ++atom) { - bind(atom->toExpr(), letMap, letOrder); - } - - for (unsigned i = 0; i < letOrder.size(); ++i) { - Expr currentExpr = letOrder[i].expr; - unsigned letId = letOrder[i].id; - ProofLetMap::iterator it = letMap.find(currentExpr); - Assert(it != letMap.end()); - out << "\n(@ let" << letId << " "; - d_theoryProof->printBoundTerm(currentExpr, out, letMap); - paren << ")"; - it->second.increment(); - } - - out << std::endl << std::endl; -} - -void ProofManager::ensureLiteral(Node node) { - d_cnfProof->ensureLiteral(node); -} -void ProofManager::printTrustedTerm(Node term, - std::ostream& os, - ProofLetMap& globalLetMap) -{ - TheoryProofEngine* tpe = ProofManager::currentPM()->getTheoryProofEngine(); - if (tpe->printsAsBool(term)) os << "(p_app "; - tpe->printTheoryTerm(term.toExpr(), os, globalLetMap); - if (tpe->printsAsBool(term)) os << ")"; -} - -ProofManager::ProofManagerStatistics::ProofManagerStatistics() - : d_proofProductionTime("proof::ProofManager::proofProductionTime"), - d_theoryLemmaTime( - "proof::ProofManager::proofProduction::theoryLemmaTime"), - d_skeletonProofTraceTime( - "proof::ProofManager::proofProduction::skeletonProofTraceTime"), - d_proofDeclarationsTime( - "proof::ProofManager::proofProduction::proofDeclarationsTime"), - d_cnfProofTime("proof::ProofManager::proofProduction::cnfProofTime"), - d_finalProofTime("proof::ProofManager::proofProduction::finalProofTime") -{ - smtStatisticsRegistry()->registerStat(&d_proofProductionTime); - smtStatisticsRegistry()->registerStat(&d_theoryLemmaTime); - smtStatisticsRegistry()->registerStat(&d_skeletonProofTraceTime); - smtStatisticsRegistry()->registerStat(&d_proofDeclarationsTime); - smtStatisticsRegistry()->registerStat(&d_cnfProofTime); - smtStatisticsRegistry()->registerStat(&d_finalProofTime); -} - -ProofManager::ProofManagerStatistics::~ProofManagerStatistics() -{ - smtStatisticsRegistry()->unregisterStat(&d_proofProductionTime); - smtStatisticsRegistry()->unregisterStat(&d_theoryLemmaTime); - smtStatisticsRegistry()->unregisterStat(&d_skeletonProofTraceTime); - smtStatisticsRegistry()->unregisterStat(&d_proofDeclarationsTime); - smtStatisticsRegistry()->unregisterStat(&d_cnfProofTime); - smtStatisticsRegistry()->unregisterStat(&d_finalProofTime); -} - } /* CVC4 namespace */ diff --git a/src/proof/proof_manager.h b/src/proof/proof_manager.h index 45bde4dcb..3013c9b55 100644 --- a/src/proof/proof_manager.h +++ b/src/proof/proof_manager.h @@ -28,59 +28,27 @@ #include "context/cdhashset.h" #include "expr/node.h" #include "proof/clause_id.h" -#include "proof/proof.h" -#include "proof/proof_utils.h" -#include "proof/skolemization_manager.h" -#include "theory/logic_info.h" -#include "theory/substitutions.h" -#include "util/proof.h" #include "util/statistics_registry.h" 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; -const ClauseId ClauseIdEmpty(-1); -const ClauseId ClauseIdUndef(-2); -const ClauseId ClauseIdError(-3); - template <class Solver> class TSatProof; typedef TSatProof< CVC4::Minisat::Solver> CoreSatProof; class CnfProof; -class RewriterProof; -class TheoryProofEngine; -class TheoryProof; -class UFProof; -class ArithProof; -class ArrayProof; - -namespace proof { -class ResolutionBitVectorProof; -} - -template <class Solver> class LFSCSatProof; -typedef TSatProof<CVC4::Minisat::Solver> CoreSatProof; -class LFSCCnfProof; -class LFSCTheoryProofEngine; -class LFSCUFProof; -class LFSCRewriterProof; +typedef TSatProof<CVC4::Minisat::Solver> CoreSatProof; namespace prop { typedef uint64_t SatVariable; @@ -88,291 +56,72 @@ namespace prop { typedef std::vector<SatLiteral> SatClause; }/* CVC4::prop namespace */ -// different proof modes -enum ProofFormat { - LFSC, - NATIVE -};/* enum ProofFormat */ - -std::string append(const std::string& str, uint64_t num); - typedef std::unordered_map<ClauseId, prop::SatClause*> IdToSatClause; typedef context::CDHashSet<Expr, ExprHashFunction> CDExprSet; -typedef std::unordered_map<Node, std::vector<Node>, NodeHashFunction> NodeToNodes; typedef context::CDHashMap<Node, std::vector<Node>, NodeHashFunction> CDNodeToNodes; typedef std::unordered_set<ClauseId> IdHashSet; -enum ProofRule { - RULE_GIVEN, /* input assertion */ - RULE_DERIVED, /* a "macro" rule */ - RULE_RECONSTRUCT, /* prove equivalence using another method */ - RULE_TRUST, /* trust without evidence (escape hatch until proofs are fully supported) */ - 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 RewriteLogEntry { -public: - RewriteLogEntry(unsigned ruleId, Node original, Node result) - : d_ruleId(ruleId), d_original(original), d_result(result) { - } - - unsigned getRuleId() const { - return d_ruleId; - } - - Node getOriginal() const { - return d_original; - } - - Node getResult() const { - return d_result; - } - -private: - unsigned d_ruleId; - Node d_original; - Node d_result; -}; - class ProofManager { context::Context* d_context; std::unique_ptr<CoreSatProof> d_satProof; std::unique_ptr<CnfProof> d_cnfProof; - std::unique_ptr<TheoryProofEngine> d_theoryProof; // information that will need to be shared across proofs - ExprSet d_inputFormulas; - std::map<Expr, std::string> d_inputFormulaToName; CDExprSet d_inputCoreFormulas; CDExprSet d_outputCoreFormulas; - SkolemizationManager d_skolemizationManager; - int d_nextId; - std::unique_ptr<Proof> d_fullProof; - ProofFormat d_format; // used for now only in debug builds - CDNodeToNodes d_deps; - std::set<Type> d_printedTypes; - - std::map<std::string, std::string> d_rewriteFilters; - std::map<Node, std::string> d_assertionFilters; - - std::vector<RewriteLogEntry> d_rewriteLog; - -protected: - LogicInfo d_logic; - public: - ProofManager(context::Context* context, ProofFormat format = LFSC); - ~ProofManager(); - - static ProofManager* currentPM(); - - // initialization - void initSatProof(Minisat::Solver* solver); - void initCnfProof(CVC4::prop::CnfStream* cnfStream, context::Context* ctx); - void initTheoryProofEngine(); - - // getting various proofs - static const Proof& getProof(SmtEngine* smt); - static CoreSatProof* getSatProof(); - static CnfProof* getCnfProof(); - static TheoryProofEngine* getTheoryProofEngine(); - static TheoryProof* getTheoryProof( theory::TheoryId id ); - static UFProof* getUfProof(); - static proof::ResolutionBitVectorProof* getBitVectorProof(); - static ArrayProof* getArrayProof(); - static ArithProof* getArithProof(); - - static SkolemizationManager *getSkolemizationManager(); - - // iterators over data shared by proofs - typedef ExprSet::const_iterator assertions_iterator; - - // 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(); } - bool have_input_assertion(const Expr& assertion) { - return d_inputFormulas.find(assertion) != d_inputFormulas.end(); - } - - void ensureLiteral(Node node); - -//---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 getInputFormulaName(const Expr& expr); - - 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 = ""); - static bool hasLitName(TNode lit); - - // for SMT variable names that have spaces and other things - static std::string sanitize(TNode var); - - // wrap term with (p_app ... ) if the term is printed as a boolean, and print - // used for "trust" assertions - static void printTrustedTerm(Node term, - std::ostream& os, - ProofLetMap& globalLetMap); - - /** Add proof assertion - unlike 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); - - // trace dependences back to unsat core - void traceDeps(TNode n, ExprSet* coreAssertions); - void traceDeps(TNode n, CDExprSet* coreAssertions); - void traceUnsatCore(); - - typedef CDExprSet::const_iterator output_core_iterator; - - output_core_iterator begin_unsat_core() const { return d_outputCoreFormulas.begin(); } - output_core_iterator end_unsat_core() const { return d_outputCoreFormulas.end(); } - size_t size_unsat_core() const { return d_outputCoreFormulas.size(); } - std::vector<Expr> extractUnsatCore(); - - bool unsatCoreAvailable() const; - void getLemmasInUnsatCore(theory::TheoryId theory, std::vector<Node> &lemmas); - Node getWeakestImplicantInUnsatCore(Node lemma); - - int nextId() { return d_nextId++; } - - void setLogic(const LogicInfo& logic); - const std::string getLogic() const { return d_logic.getLogicString(); } - LogicInfo & getLogicInfo() { return d_logic; } - - void markPrinted(const Type& type); - bool wasPrinted(const Type& type) const; - - void addRewriteFilter(const std::string &original, const std::string &substitute); - void clearRewriteFilters(); - bool haveRewriteFilter(TNode lit); - - void addAssertionFilter(const Node& node, const std::string& rewritten); - - static void registerRewrite(unsigned ruleId, Node original, Node result); - static void clearRewriteLog(); - - std::vector<RewriteLogEntry> getRewriteLog(); - void dumpRewriteLog() const; + ProofManager(context::Context* context); + ~ProofManager(); - void printGlobalLetMap(std::set<Node>& atoms, - ProofLetMap& letMap, - std::ostream& out, - std::ostringstream& paren); - - struct ProofManagerStatistics - { - ProofManagerStatistics(); - ~ProofManagerStatistics(); + static ProofManager* currentPM(); - /** - * Time spent producing proofs (i.e. generating the proof from the logging - * information) - */ - TimerStat d_proofProductionTime; + // initialization + void initSatProof(Minisat::Solver* solver); + void initCnfProof(CVC4::prop::CnfStream* cnfStream, context::Context* ctx); - /** - * Time spent printing proofs of theory lemmas - */ - TimerStat d_theoryLemmaTime; + // getting various proofs + static CoreSatProof* getSatProof(); + static CnfProof* getCnfProof(); - /** - * Time spent tracing the proof of the boolean skeleton - * (e.g. figuring out which assertions are needed, etc.) - */ - TimerStat d_skeletonProofTraceTime; + /** Public unsat core methods **/ + void addCoreAssertion(Expr formula); - /** - * Time spent processing and printing declarations in the proof - */ - TimerStat d_proofDeclarationsTime; + void addDependence(TNode n, TNode dep); + void addUnsatCore(Expr formula); - /** - * Time spent printing the CNF proof - */ - TimerStat d_cnfProofTime; + // trace dependences back to unsat core + void traceDeps(TNode n, CDExprSet* coreAssertions); + void traceUnsatCore(); - /** - * Time spent printing the final proof of UNSAT - */ - TimerStat d_finalProofTime; + typedef CDExprSet::const_iterator output_core_iterator; - }; /* struct ProofManagerStatistics */ + output_core_iterator begin_unsat_core() const + { + return d_outputCoreFormulas.begin(); + } + output_core_iterator end_unsat_core() const + { + return d_outputCoreFormulas.end(); + } + size_t size_unsat_core() const { return d_outputCoreFormulas.size(); } + std::vector<Expr> extractUnsatCore(); - ProofManagerStatistics& getStats() { return d_stats; } + bool unsatCoreAvailable() const; + void getLemmasInUnsatCore(std::vector<Node>& lemmas); - private: - void constructSatProof(); - std::set<Node> satClauseToNodeSet(prop::SatClause* clause); + int nextId() { return d_nextId++; } - ProofManagerStatistics d_stats; +private: + void constructSatProof(); };/* class ProofManager */ -class LFSCProof : public Proof -{ - public: - LFSCProof(SmtEngine* smtEngine, - CoreSatProof* sat, - LFSCCnfProof* cnf, - LFSCTheoryProofEngine* theory); - ~LFSCProof() override {} - void toStream(std::ostream& out) const override; - void toStream(std::ostream& out, const ProofLetMap& map) const override; - - private: - // FIXME: hack until we get preprocessing - void printPreprocessedAssertions(const NodeSet& assertions, - std::ostream& os, - std::ostream& paren, - ProofLetMap& globalLetMap) const; - - void checkUnrewrittenAssertion(const NodeSet& assertions) const; - - CoreSatProof* d_satProof; - LFSCCnfProof* d_cnfProof; - LFSCTheoryProofEngine* d_theoryProof; - SmtEngine* d_smtEngine; -}; /* class LFSCProof */ - -std::ostream& operator<<(std::ostream& out, CVC4::ProofRule k); }/* CVC4 namespace */ diff --git a/src/proof/proof_output_channel.cpp b/src/proof/proof_output_channel.cpp deleted file mode 100644 index 88467aea6..000000000 --- a/src/proof/proof_output_channel.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/********************* */ -/*! \file proof_output_channel.cpp - ** \verbatim - ** Top contributors (to current version): - ** Guy Katz, Tim King, Liana Hadarean - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** [[ Add lengthier description here ]] - - ** \todo document this file - -**/ - -#include "proof/proof_output_channel.h" - -#include "base/check.h" -#include "theory/term_registration_visitor.h" -#include "theory/valuation.h" - -namespace CVC4 { - -ProofOutputChannel::ProofOutputChannel() : d_conflict(), d_proof(nullptr) {} -const Proof& ProofOutputChannel::getConflictProof() const -{ - Assert(hasConflict()); - return *d_proof; -} - -void ProofOutputChannel::conflict(TNode n, std::unique_ptr<Proof> pf) -{ - Trace("pf::tp") << "ProofOutputChannel: CONFLICT: " << n << std::endl; - Assert(!hasConflict()); - Assert(!d_proof); - d_conflict = n; - d_proof = std::move(pf); - Assert(hasConflict()); - Assert(d_proof); -} - -bool ProofOutputChannel::propagate(TNode x) { - Trace("pf::tp") << "ProofOutputChannel: got a propagation: " << x - << std::endl; - d_propagations.insert(x); - return true; -} - -theory::LemmaStatus ProofOutputChannel::lemma(TNode n, - ProofRule rule, - theory::LemmaProperty p) -{ - Trace("pf::tp") << "ProofOutputChannel: new lemma: " << n << std::endl; - // TODO(#1231): We should transition to supporting multiple lemmas. The - // following assertion cannot be enabled due to - // "test/regress/regress0/arrays/swap_t1_np_nf_ai_00005_007.cvc.smt". - // Assert( - // d_lemma.isNull()) << - // "Multiple calls to ProofOutputChannel::lemma() are not supported."; - d_lemma = n; - return theory::LemmaStatus(TNode::null(), 0); -} - -theory::LemmaStatus ProofOutputChannel::splitLemma(TNode, bool) { - AlwaysAssert(false); - return theory::LemmaStatus(TNode::null(), 0); -} - -void ProofOutputChannel::requirePhase(TNode n, bool b) { - Debug("pf::tp") << "ProofOutputChannel::requirePhase called" << std::endl; - Trace("pf::tp") << "requirePhase " << n << " " << b << std::endl; -} - -void ProofOutputChannel::setIncomplete() { - Debug("pf::tp") << "ProofOutputChannel::setIncomplete called" << std::endl; - AlwaysAssert(false); -} - - -MyPreRegisterVisitor::MyPreRegisterVisitor(theory::Theory* theory) - : d_theory(theory) - , d_visited() { -} - -bool MyPreRegisterVisitor::alreadyVisited(TNode current, TNode parent) { - return d_visited.find(current) != d_visited.end(); -} - -void MyPreRegisterVisitor::visit(TNode current, TNode parent) { - d_theory->preRegisterTerm(current); - d_visited.insert(current); -} - -void MyPreRegisterVisitor::start(TNode node) { -} - -void MyPreRegisterVisitor::done(TNode node) { -} - -} /* namespace CVC4 */ diff --git a/src/proof/proof_output_channel.h b/src/proof/proof_output_channel.h deleted file mode 100644 index b68abd44b..000000000 --- a/src/proof/proof_output_channel.h +++ /dev/null @@ -1,79 +0,0 @@ -/********************* */ -/*! \file proof_output_channel.h - ** \verbatim - ** Top contributors (to current version): - ** Tim King, Guy Katz, Liana Hadarean - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__PROOF_OUTPUT_CHANNEL_H -#define CVC4__PROOF_OUTPUT_CHANNEL_H - -#include <memory> -#include <set> -#include <unordered_set> - -#include "expr/node.h" -#include "theory/output_channel.h" -#include "theory/theory.h" -#include "util/proof.h" - -namespace CVC4 { - -class ProofOutputChannel : public theory::OutputChannel { - public: - ProofOutputChannel(); - ~ProofOutputChannel() override {} - - /** - * This may be called at most once per ProofOutputChannel. - * Requires that `n` and `pf` are non-null. - */ - void conflict(TNode n, std::unique_ptr<Proof> pf) override; - bool propagate(TNode x) override; - theory::LemmaStatus lemma(TNode n, - ProofRule rule, - theory::LemmaProperty p) override; - theory::LemmaStatus splitLemma(TNode, bool) override; - void requirePhase(TNode n, bool b) override; - void setIncomplete() override; - - /** Has conflict() has been called? */ - bool hasConflict() const { return !d_conflict.isNull(); } - - /** - * Returns the proof passed into the conflict() call. - * Requires hasConflict() to hold. - */ - const Proof& getConflictProof() const; - Node getLastLemma() const { return d_lemma; } - - private: - Node d_conflict; - std::unique_ptr<Proof> d_proof; - Node d_lemma; - std::set<Node> d_propagations; -}; /* class ProofOutputChannel */ - -class MyPreRegisterVisitor { - theory::Theory* d_theory; - std::unordered_set<TNode, TNodeHashFunction> d_visited; -public: - typedef void return_type; - MyPreRegisterVisitor(theory::Theory* theory); - bool alreadyVisited(TNode current, TNode parent); - void visit(TNode current, TNode parent); - void start(TNode node); - void done(TNode node); -}; /* class MyPreRegisterVisitor */ - -} /* CVC4 namespace */ - -#endif /* CVC4__PROOF_OUTPUT_CHANNEL_H */ diff --git a/src/proof/proof_utils.cpp b/src/proof/proof_utils.cpp deleted file mode 100644 index cad56db6a..000000000 --- a/src/proof/proof_utils.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/********************* */ -/*! \file proof_utils.cpp - ** \verbatim - ** Top contributors (to current version): - ** Liana Hadarean, Andrew Reynolds, Guy Katz - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** [[ Add lengthier description here ]] - - ** \todo document this file - -**/ - -#include "proof/proof_utils.h" -#include "theory/theory.h" - -namespace CVC4 { -namespace utils { - -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::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(); - } -} - -std::string toLFSCKindTerm(Expr node) { - Kind k = node.getKind(); - if( k==kind::EQUAL ){ - if( node[0].getType().isBoolean() ){ - return "iff"; - }else{ - return "="; - } - }else{ - return toLFSCKind( k ); - } -} - -} /* namespace CVC4::utils */ -} /* namespace CVC4 */ diff --git a/src/proof/proof_utils.h b/src/proof/proof_utils.h deleted file mode 100644 index e54edd8b7..000000000 --- a/src/proof/proof_utils.h +++ /dev/null @@ -1,229 +0,0 @@ -/********************* */ -/*! \file proof_utils.h - ** \verbatim - ** Top contributors (to current version): - ** Liana Hadarean, Guy Katz, Dejan Jovanovic - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** [[ Add lengthier description here ]] - - ** \todo document this file - -**/ - -#include "cvc4_private.h" - -#pragma once - -#include <set> -#include <sstream> -#include <unordered_set> -#include <vector> - -#include "expr/node_manager.h" - -namespace CVC4 { - -typedef std::unordered_set<Expr, ExprHashFunction> ExprSet; -typedef std::unordered_set<Node, NodeHashFunction> NodeSet; - -typedef std::pair<Node, Node> NodePair; -typedef std::set<NodePair> NodePairSet; - - -class ProofLetCount { -public: - static unsigned counter; - static void resetCounter() { counter = 0; } - static unsigned newId() { return ++counter; } - - unsigned count; - unsigned id; - ProofLetCount() - : count(0) - , id(-1) - {} - - void increment() { ++count; } - ProofLetCount(unsigned i) - : count(1) - , id(i) - {} - - ProofLetCount(const ProofLetCount& other) - : count(other.count) - , id (other.id) - {} - - bool operator==(const ProofLetCount &other) const { - return other.id == id && other.count == count; - } - - ProofLetCount& operator=(const ProofLetCount &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 std::vector<LetOrderElement> Bindings; - -namespace utils { - -std::string toLFSCKind(Kind kind); -std::string toLFSCKindTerm(Expr node); - -inline unsigned getExtractHigh(Expr node) { - return node.getOperator().getConst<BitVectorExtract>().d_high; -} - -inline unsigned getExtractLow(Expr node) { - return node.getOperator().getConst<BitVectorExtract>().d_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 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 = BitVector::mkOnes(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); -} - -} -} diff --git a/src/proof/resolution_bitvector_proof.cpp b/src/proof/resolution_bitvector_proof.cpp deleted file mode 100644 index d48789f71..000000000 --- a/src/proof/resolution_bitvector_proof.cpp +++ /dev/null @@ -1,523 +0,0 @@ -/********************* */ -/*! \file resolution_bitvector_proof.cpp - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Liana Hadarean, Guy Katz - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** [[ Add lengthier description here ]] - - ** \todo document this file - -**/ - -#include "proof/resolution_bitvector_proof.h" -#include "options/bv_options.h" -#include "options/proof_options.h" -#include "proof/array_proof.h" -#include "proof/bitvector_proof.h" -#include "proof/clause_id.h" -#include "proof/lfsc_proof_printer.h" -#include "proof/proof_output_channel.h" -#include "proof/proof_utils.h" -#include "proof/sat_proof_implementation.h" -#include "prop/bvminisat/bvminisat.h" -#include "prop/sat_solver_types.h" -#include "theory/bv/bitblast/bitblaster.h" -#include "theory/bv/theory_bv.h" -#include "theory/bv/theory_bv_rewrite_rules.h" - -#include <iostream> -#include <sstream> - -using namespace CVC4::theory; -using namespace CVC4::theory::bv; - -namespace CVC4 { - -namespace proof { - -ResolutionBitVectorProof::ResolutionBitVectorProof( - theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine) - : BitVectorProof(bv, proofEngine), - d_resolutionProof(), - d_isAssumptionConflict(false) -{ -} - -void ResolutionBitVectorProof::initSatProof(CVC4::BVMinisat::Solver* solver) -{ - Assert(d_resolutionProof == NULL); - d_resolutionProof.reset(new BVSatProof(solver, &d_fakeContext, "bb", true)); -} - -void ResolutionBitVectorProof::initCnfProof(prop::CnfStream* cnfStream, - context::Context* cnf, - prop::SatVariable trueVar, - prop::SatVariable falseVar) -{ - Assert(d_resolutionProof != NULL); - Assert(d_cnfProof == nullptr); - d_cnfProof.reset(new LFSCCnfProof(cnfStream, cnf, "bb")); - - d_cnfProof->registerTrueUnitClause(d_resolutionProof->getTrueUnit()); - d_cnfProof->registerFalseUnitClause(d_resolutionProof->getFalseUnit()); -} - -void ResolutionBitVectorProof::attachToSatSolver(prop::SatSolver& sat_solver) -{ - sat_solver.setResolutionProofLog(this); -} - -BVSatProof* ResolutionBitVectorProof::getSatProof() -{ - Assert(d_resolutionProof != NULL); - return d_resolutionProof.get(); -} - -void ResolutionBitVectorProof::startBVConflict( - CVC4::BVMinisat::Solver::TCRef cr) -{ - d_resolutionProof->startResChain(cr); -} - -void ResolutionBitVectorProof::startBVConflict( - CVC4::BVMinisat::Solver::TLit lit) -{ - d_resolutionProof->startResChain(lit); -} - -void ResolutionBitVectorProof::endBVConflict( - const CVC4::BVMinisat::Solver::TLitVec& confl) -{ - Debug("pf::bv") << "ResolutionBitVectorProof::endBVConflict called" - << std::endl; - - 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("pf::bv") << "Make conflict for " << conflict << std::endl; - - if (d_bbConflictMap.find(conflict) != d_bbConflictMap.end()) - { - Debug("pf::bv") << "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("pf::bv") << "ResolutionBitVectorProof::endBVConflict id" << clause_id - << " => " << conflict << "\n"; - d_isAssumptionConflict = false; -} - -void ResolutionBitVectorProof::finalizeConflicts(std::vector<Expr>& conflicts) -{ - if (options::bitblastMode() == options::BitblastMode::EAGER) - { - Debug("pf::bv") << "Construct full proof." << std::endl; - d_resolutionProof->constructProof(); - return; - } - - for (unsigned i = 0; i < conflicts.size(); ++i) - { - Expr confl = conflicts[i]; - Debug("pf::bv") << "Finalize conflict #" << i << ": " << confl << std::endl; - - // Special case: if the conflict has a (true) or a (not false) in it, it is - // trivial... - bool ignoreConflict = false; - if ((confl.isConst() && confl.getConst<bool>()) - || (confl.getKind() == kind::NOT && confl[0].isConst() - && !confl[0].getConst<bool>())) - { - ignoreConflict = true; - } - else if (confl.getKind() == kind::OR) - { - for (unsigned k = 0; k < confl.getNumChildren(); ++k) - { - if ((confl[k].isConst() && confl[k].getConst<bool>()) - || (confl[k].getKind() == kind::NOT && confl[k][0].isConst() - && !confl[k][0].getConst<bool>())) - { - ignoreConflict = true; - } - } - } - if (ignoreConflict) - { - Debug("pf::bv") << "Ignoring conflict due to (true) or (not false)" - << std::endl; - continue; - } - - if (d_bbConflictMap.find(confl) != d_bbConflictMap.end()) - { - ClauseId id = d_bbConflictMap[confl]; - d_resolutionProof->collectClauses(id); - } - else - { - // There is no exact match for our conflict, but maybe it is a subset of - // another conflict - ExprToClauseId::const_iterator it; - bool matchFound = false; - for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it) - { - Expr possibleMatch = it->first; - if (possibleMatch.getKind() != kind::OR) - { - // This is a single-node conflict. If this node is in the conflict - // we're trying to prove, we have a match. - for (unsigned k = 0; k < confl.getNumChildren(); ++k) - { - if (confl[k] == possibleMatch) - { - matchFound = true; - d_resolutionProof->collectClauses(it->second); - break; - } - } - } - else - { - if (possibleMatch.getNumChildren() > confl.getNumChildren()) continue; - - unsigned k = 0; - bool matching = true; - for (unsigned j = 0; j < possibleMatch.getNumChildren(); ++j) - { - // j is the index in possibleMatch - // k is the index in confl - while (k < confl.getNumChildren() && confl[k] != possibleMatch[j]) - { - ++k; - } - if (k == confl.getNumChildren()) - { - // We couldn't find a match for possibleMatch[j], so not a match - matching = false; - break; - } - } - - if (matching) - { - Debug("pf::bv") - << "Collecting info from a sub-conflict" << std::endl; - d_resolutionProof->collectClauses(it->second); - matchFound = true; - break; - } - } - } - - if (!matchFound) - { - Debug("pf::bv") << "Do not collect clauses for " << confl << std::endl - << "Dumping existing conflicts:" << std::endl; - - i = 0; - for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it) - { - ++i; - Debug("pf::bv") << "\tConflict #" << i << ": " << it->first - << std::endl; - } - - Unreachable(); - } - } - } -} - -void LfscResolutionBitVectorProof::printTheoryLemmaProof( - std::vector<Expr>& lemma, - std::ostream& os, - std::ostream& paren, - const ProofLetMap& map) -{ - Debug("pf::bv") - << "(pf::bv) LfscResolutionBitVectorProof::printTheoryLemmaProof called" - << std::endl; - Expr conflict = utils::mkSortedExpr(kind::OR, lemma); - Debug("pf::bv") << "\tconflict = " << conflict << std::endl; - - 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]; - proof::LFSCProofPrinter::printAssumptionsResolution( - d_resolutionProof.get(), lemma_id, os, lemma_paren); - os << lemma_paren.str(); - } - else - { - Debug("pf::bv") << "Found a non-recorded conflict. Looking for a matching " - "sub-conflict..." - << std::endl; - - bool matching; - - ExprToClauseId::const_iterator it; - unsigned i = 0; - for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it) - { - // Our conflict is sorted, and the records are also sorted. - ++i; - Expr possibleMatch = it->first; - - if (possibleMatch.getKind() != kind::OR) - { - // This is a single-node conflict. If this node is in the conflict we're - // trying to prove, we have a match. - matching = false; - - for (unsigned k = 0; k < conflict.getNumChildren(); ++k) - { - if (conflict[k] == possibleMatch) - { - matching = true; - break; - } - } - } - else - { - if (possibleMatch.getNumChildren() > conflict.getNumChildren()) - continue; - - unsigned k = 0; - - matching = true; - for (unsigned j = 0; j < possibleMatch.getNumChildren(); ++j) - { - // j is the index in possibleMatch - // k is the index in conflict - while (k < conflict.getNumChildren() - && conflict[k] != possibleMatch[j]) - { - ++k; - } - if (k == conflict.getNumChildren()) - { - // We couldn't find a match for possibleMatch[j], so not a match - matching = false; - break; - } - } - } - - if (matching) - { - Debug("pf::bv") << "Found a match with conflict #" << i << ": " - << std::endl - << possibleMatch << std::endl; - // The rest is just a copy of the usual handling, if a precise match is - // found. We only use the literals that appear in the matching conflict, - // though, and not in the original lemma - as these may not have even - // been bit blasted! - std::ostringstream lemma_paren; - - if (possibleMatch.getKind() == kind::OR) - { - for (const Expr& lit : possibleMatch) - { - 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 << ")"; - } - } - else - { - // The conflict only consists of one node, either positive or - // negative. - Expr lit = possibleMatch; - 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 << ")"; - } - - ClauseId lemma_id = it->second; - proof::LFSCProofPrinter::printAssumptionsResolution( - d_resolutionProof.get(), lemma_id, os, lemma_paren); - os << lemma_paren.str(); - - return; - } - } - - // We failed to find a matching sub conflict. The last hope is that the - // conflict has a FALSE assertion in it; this can happen in some corner - // cases, where the FALSE is the result of a rewrite. - - for (const Expr& lit : lemma) - { - if (lit.getKind() == kind::NOT && lit[0] == utils::mkFalse()) - { - Debug("pf::bv") << "Lemma has a (not false) literal" << std::endl; - os << "(clausify_false "; - os << ProofManager::getLitName(lit); - os << ")"; - return; - } - } - - Debug("pf::bv") << "Failed to find a matching sub-conflict..." << std::endl - << "Dumping existing conflicts:" << std::endl; - - i = 0; - for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it) - { - ++i; - Debug("pf::bv") << "\tConflict #" << i << ": " << it->first << std::endl; - } - - Unreachable(); - } -} - -void LfscResolutionBitVectorProof::calculateAtomsInBitblastingProof() -{ - // Collect the input clauses used - IdToSatClause used_lemmas; - IdToSatClause used_inputs; - d_resolutionProof->collectClausesUsed(used_inputs, used_lemmas); - d_cnfProof->collectAtomsForClauses(used_inputs, d_atomsInBitblastingProof); - Assert(used_lemmas.empty()); -} - -void LfscResolutionBitVectorProof::printBBDeclarationAndCnf(std::ostream& os, - std::ostream& paren, - ProofLetMap& letMap) -{ - // print mapping between theory atoms and internal SAT variables - os << std::endl << ";; BB atom mapping\n" << std::endl; - - std::set<Node>::iterator atomIt; - Debug("pf::bv") << std::endl - << "BV Dumping atoms from inputs: " << std::endl - << std::endl; - for (atomIt = d_atomsInBitblastingProof.begin(); - atomIt != d_atomsInBitblastingProof.end(); - ++atomIt) - { - Debug("pf::bv") << "\tAtom: " << *atomIt << std::endl; - } - Debug("pf::bv") << std::endl; - - // first print bit-blasting - printBitblasting(os, paren); - - // print CNF conversion proof for bit-blasted facts - IdToSatClause used_lemmas; - IdToSatClause used_inputs; - d_resolutionProof->collectClausesUsed(used_inputs, used_lemmas); - - d_cnfProof->printAtomMapping(d_atomsInBitblastingProof, os, paren, letMap); - os << std::endl << ";; Bit-blasting definitional clauses \n" << std::endl; - for (IdToSatClause::iterator it = used_inputs.begin(); - it != used_inputs.end(); - ++it) - { - d_cnfProof->printCnfProofForClause(it->first, it->second, os, paren); - } - - os << std::endl << " ;; Bit-blasting learned clauses \n" << std::endl; - proof::LFSCProofPrinter::printResolutions(d_resolutionProof.get(), os, paren); -} - -void LfscResolutionBitVectorProof::printEmptyClauseProof(std::ostream& os, - std::ostream& paren) -{ - Assert(options::bitblastMode() == options::BitblastMode::EAGER) - << "the BV theory should only be proving bottom directly in the eager " - "bitblasting mode"; - proof::LFSCProofPrinter::printResolutionEmptyClause( - d_resolutionProof.get(), os, paren); -} - -} // namespace proof - -} /* namespace CVC4 */ diff --git a/src/proof/resolution_bitvector_proof.h b/src/proof/resolution_bitvector_proof.h deleted file mode 100644 index a1b0b0d59..000000000 --- a/src/proof/resolution_bitvector_proof.h +++ /dev/null @@ -1,113 +0,0 @@ -/********************* */ -/*! \file resolution_bitvector_proof.h - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, Mathias Preiner, Liana Hadarean - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. 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__PROOF__RESOLUTION_BITVECTOR_PROOF_H -#define CVC4__PROOF__RESOLUTION_BITVECTOR_PROOF_H - -#include <iosfwd> - -#include "context/context.h" -#include "expr/expr.h" -#include "proof/bitvector_proof.h" -#include "proof/sat_proof.h" -#include "proof/theory_proof.h" -#include "prop/bvminisat/core/Solver.h" -#include "prop/cnf_stream.h" -#include "prop/sat_solver_types.h" -#include "theory/bv/bitblast/bitblaster.h" -#include "theory/bv/theory_bv.h" - -namespace CVC4 { - -typedef TSatProof<CVC4::BVMinisat::Solver> BVSatProof; - -namespace proof { - -/** - * Represents a bitvector proof which is backed by - * (a) bitblasting and - * (b) a resolution unsat proof. - * - * Contains tools for constructing BV conflicts - */ -class ResolutionBitVectorProof : public BitVectorProof -{ - public: - ResolutionBitVectorProof(theory::bv::TheoryBV* bv, - TheoryProofEngine* proofEngine); - - /** - * Create an (internal) SAT proof object - * Must be invoked before manipulating BV conflicts, - * or initializing a BNF proof - */ - void initSatProof(CVC4::BVMinisat::Solver* solver); - - BVSatProof* getSatProof(); - - void finalizeConflicts(std::vector<Expr>& conflicts) override; - - void startBVConflict(CVC4::BVMinisat::Solver::TCRef cr); - void startBVConflict(CVC4::BVMinisat::Solver::TLit lit); - void endBVConflict(const BVMinisat::Solver::TLitVec& confl); - - void markAssumptionConflict() { d_isAssumptionConflict = true; } - bool isAssumptionConflict() const { return d_isAssumptionConflict; } - - void initCnfProof(prop::CnfStream* cnfStream, - context::Context* cnf, - prop::SatVariable trueVar, - prop::SatVariable falseVar) override; - - protected: - void attachToSatSolver(prop::SatSolver& sat_solver) override; - - context::Context d_fakeContext; - - // The CNF formula that results from bit-blasting will need a proof. - // This is that proof. - std::unique_ptr<BVSatProof> d_resolutionProof; - - bool d_isAssumptionConflict; - -}; - -class LfscResolutionBitVectorProof : public ResolutionBitVectorProof -{ - public: - LfscResolutionBitVectorProof(theory::bv::TheoryBV* bv, - TheoryProofEngine* proofEngine) - : ResolutionBitVectorProof(bv, proofEngine) - { - } - void printTheoryLemmaProof(std::vector<Expr>& lemma, - std::ostream& os, - std::ostream& paren, - const ProofLetMap& map) override; - void printBBDeclarationAndCnf(std::ostream& os, - std::ostream& paren, - ProofLetMap& letMap) override; - void printEmptyClauseProof(std::ostream& os, std::ostream& paren) override; - void calculateAtomsInBitblastingProof() override; -}; - -} // namespace proof - -} // namespace CVC4 - -#endif /* CVC4__PROOF__RESOLUTIONBITVECTORPROOF_H */ diff --git a/src/proof/sat_proof.h b/src/proof/sat_proof.h index 83e4d3930..38aea0673 100644 --- a/src/proof/sat_proof.h +++ b/src/proof/sat_proof.h @@ -32,7 +32,6 @@ #include "expr/expr.h" #include "proof/clause_id.h" #include "proof/proof_manager.h" -#include "util/proof.h" #include "util/statistics_registry.h" // Forward declarations. diff --git a/src/proof/sat_proof_implementation.h b/src/proof/sat_proof_implementation.h index 897a5c452..7ce18ae4a 100644 --- a/src/proof/sat_proof_implementation.h +++ b/src/proof/sat_proof_implementation.h @@ -20,10 +20,7 @@ #define CVC4__SAT__PROOF_IMPLEMENTATION_H #include "proof/clause_id.h" -#include "proof/cnf_proof.h" #include "proof/sat_proof.h" -#include "prop/bvminisat/bvminisat.h" -#include "prop/bvminisat/core/Solver.h" #include "prop/minisat/core/Solver.h" #include "prop/minisat/minisat.h" #include "prop/sat_solver_types.h" @@ -712,11 +709,6 @@ void TSatProof<Solver>::registerResolution(ClauseId id, ResChain<Solver>* res) { Assert(checkResolution(id)); } - PSTATS(uint64_t resolutionSteps = - static_cast<uint64_t>(res.getSteps().size()); - d_statistics.d_resChainLengths << resolutionSteps; - d_statistics.d_avgChainLength.addEntry(resolutionSteps); - ++(d_statistics.d_numLearnedClauses);) } /// recording resolutions @@ -912,14 +904,6 @@ void TSatProof<Solver>::markDeleted(typename Solver::TCRef clause) { } } -// 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) { d_satProofConstructed = true; @@ -1002,9 +986,6 @@ void TSatProof<Solver>::collectClauses(ClauseId id) { const ResolutionChain& res = getResolutionChain(id); const typename ResolutionChain::ResSteps& steps = res.getSteps(); - PSTATS(d_statistics.d_usedResChainLengths - << ((uint64_t)steps.size()); - d_statistics.d_usedClauseGlue << ((uint64_t)d_glueMap[id]);); ClauseId start = res.getStart(); collectClauses(start); @@ -1018,8 +999,6 @@ 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> diff --git a/src/proof/simplify_boolean_node.cpp b/src/proof/simplify_boolean_node.cpp deleted file mode 100644 index 5f1943654..000000000 --- a/src/proof/simplify_boolean_node.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/********************* */ -/*! \file simplify_boolean_node.cpp - ** \verbatim - ** Top contributors (to current version): - ** Guy Katz, Liana Hadarean, Andrew Reynolds - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief Simplifying a boolean node, needed for constructing LFSC proofs. - ** - **/ - -#include "cvc4_private.h" - -#include "proof_manager.h" - -namespace CVC4 { - -inline static Node eqNode(TNode n1, TNode n2) { - return NodeManager::currentNM()->mkNode(kind::EQUAL, n1, n2); -} - -Node simplifyBooleanNode(const Node &n) { - if (n.isNull()) - return n; - - // Only simplify boolean nodes - if (!n.getType().isBoolean()) - return n; - - // Sometimes we get sent intermediate nodes that we shouldn't simplify. - // If a node doesn't have a literal, it's clearly intermediate - ignore. - if (!ProofManager::hasLitName(n)) - return n; - - // If we already simplified the node, ignore. - if (ProofManager::currentPM()->haveRewriteFilter(n.negate())) - return n; - - - std::string litName = ProofManager::getLitName(n.negate()); - Node falseNode = NodeManager::currentNM()->mkConst(false); - Node trueNode = NodeManager::currentNM()->mkConst(true); - Node simplified = n; - - // (not (= false b)), (not (= true b))) - if ((n.getKind() == kind::NOT) && (n[0].getKind() == kind::EQUAL) && - (n[0][0].getKind() == kind::BOOLEAN_TERM_VARIABLE || n[0][1].getKind() == kind::BOOLEAN_TERM_VARIABLE)) { - Node lhs = n[0][0]; - Node rhs = n[0][1]; - - if (lhs == falseNode) { - Assert(rhs != falseNode); - Assert(rhs.getKind() == kind::BOOLEAN_TERM_VARIABLE); - // (not (= false b)) --> true = b - - simplified = eqNode(trueNode, rhs); - - std::string simplifiedLitName = ProofManager::getLitName(simplified.negate()); - std::stringstream newLitName; - newLitName << "(pred_not_iff_f _ " << litName << ")"; - ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str()); - - } else if (rhs == falseNode) { - Assert(lhs != falseNode); - Assert(lhs.getKind() == kind::BOOLEAN_TERM_VARIABLE); - // (not (= b false)) --> b = true - - simplified = eqNode(lhs, trueNode); - std::string simplifiedLitName = ProofManager::getLitName(simplified.negate()); - std::stringstream newLitName; - newLitName << "(pred_not_iff_f_2 _ " << litName << ")"; - ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str()); - - } else if (lhs == trueNode) { - Assert(rhs != trueNode); - Assert(rhs.getKind() == kind::BOOLEAN_TERM_VARIABLE); - // (not (= true b)) --> b = false - - simplified = eqNode(falseNode, rhs); - std::string simplifiedLitName = ProofManager::getLitName(simplified.negate()); - std::stringstream newLitName; - newLitName << "(pred_not_iff_t _ " << litName << ")"; - ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str()); - - } else if (rhs == trueNode) { - Assert(lhs != trueNode); - Assert(lhs.getKind() == kind::BOOLEAN_TERM_VARIABLE); - // (not (= b true)) --> b = false - - simplified = eqNode(lhs, falseNode); - std::string simplifiedLitName = ProofManager::getLitName(simplified.negate()); - std::stringstream newLitName; - newLitName << "(pred_not_iff_t_2 _ " << litName << ")"; - ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str()); - } - - } else if ((n.getKind() == kind::EQUAL) && - (n[0].getKind() == kind::BOOLEAN_TERM_VARIABLE || n[1].getKind() == kind::BOOLEAN_TERM_VARIABLE)) { - Node lhs = n[0]; - Node rhs = n[1]; - - if (lhs == falseNode) { - Assert(rhs != falseNode); - Assert(rhs.getKind() == kind::BOOLEAN_TERM_VARIABLE); - // (= false b) - - std::stringstream newLitName; - newLitName << "(pred_iff_f _ " << litName << ")"; - ProofManager::currentPM()->addRewriteFilter(litName, newLitName.str()); - - } else if (rhs == falseNode) { - Assert(lhs != falseNode); - Assert(lhs.getKind() == kind::BOOLEAN_TERM_VARIABLE); - // (= b false)) - - std::stringstream newLitName; - newLitName << "(pred_iff_f_2 _ " << litName << ")"; - ProofManager::currentPM()->addRewriteFilter(litName, newLitName.str()); - - } else if (lhs == trueNode) { - Assert(rhs != trueNode); - Assert(rhs.getKind() == kind::BOOLEAN_TERM_VARIABLE); - // (= true b) - - std::stringstream newLitName; - newLitName << "(pred_iff_t _ " << litName << ")"; - ProofManager::currentPM()->addRewriteFilter(litName, newLitName.str()); - - } else if (rhs == trueNode) { - Assert(lhs != trueNode); - Assert(lhs.getKind() == kind::BOOLEAN_TERM_VARIABLE); - // (= b true) - - - std::stringstream newLitName; - newLitName << "(pred_iff_t_2 _ " << litName << ")"; - ProofManager::currentPM()->addRewriteFilter(litName, newLitName.str()); - } - - } else if ((n.getKind() == kind::NOT) && (n[0].getKind() == kind::BOOLEAN_TERM_VARIABLE)) { - // (not b) --> b = false - simplified = eqNode(n[0], falseNode); - std::string simplifiedLitName = ProofManager::getLitName(simplified.negate()); - std::stringstream newLitName; - newLitName << "(pred_eq_f _ " << litName << ")"; - ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str()); - - } else if (n.getKind() == kind::BOOLEAN_TERM_VARIABLE) { - // (b) --> b = true - simplified = eqNode(n, trueNode); - std::string simplifiedLitName = ProofManager::getLitName(simplified.negate()); - std::stringstream newLitName; - newLitName << "(pred_eq_t _ " << litName << ")"; - ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str()); - - } else if ((n.getKind() == kind::NOT) && (n[0].getKind() == kind::SELECT)) { - // not(a[x]) --> a[x] = false - simplified = eqNode(n[0], falseNode); - std::string simplifiedLitName = ProofManager::getLitName(simplified.negate()); - std::stringstream newLitName; - newLitName << "(pred_eq_f _ " << litName << ")"; - ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str()); - - } else if (n.getKind() == kind::SELECT) { - // a[x] --> a[x] = true - simplified = eqNode(n, trueNode); - std::string simplifiedLitName = ProofManager::getLitName(simplified.negate()); - std::stringstream newLitName; - newLitName << "(pred_eq_t _ " << litName << ")"; - ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str()); - } - - if (simplified != n) - Debug("pf::simplify") << "simplifyBooleanNode: " << n << " --> " << simplified << std::endl; - - return simplified; -} - -}/* CVC4 namespace */ diff --git a/src/proof/simplify_boolean_node.h b/src/proof/simplify_boolean_node.h deleted file mode 100644 index bb4fe2e47..000000000 --- a/src/proof/simplify_boolean_node.h +++ /dev/null @@ -1,27 +0,0 @@ -/********************* */ -/*! \file simplify_boolean_node.h - ** \verbatim - ** Top contributors (to current version): - ** Mathias Preiner, Guy Katz - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief Simplifying a boolean node, needed for constructing LFSC proofs. - ** - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__SIMPLIFY_BOOLEAN_NODE_H -#define CVC4__SIMPLIFY_BOOLEAN_NODE_H - -namespace CVC4 { - -Node simplifyBooleanNode(const Node &n); - -}/* CVC4 namespace */ - -#endif /* CVC4__SIMPLIFY_BOOLEAN_NODE_H */ diff --git a/src/proof/skolemization_manager.cpp b/src/proof/skolemization_manager.cpp deleted file mode 100644 index 1bb14598d..000000000 --- a/src/proof/skolemization_manager.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/********************* */ -/*! \file skolemization_manager.cpp - ** \verbatim - ** Top contributors (to current version): - ** Paul Meng, Tim King, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** [[ Add lengthier description here ]] - - ** \todo document this file - - **/ - -#include "proof/skolemization_manager.h" - -namespace CVC4 { - -void SkolemizationManager::registerSkolem(Node disequality, Node skolem) { - Debug("pf::pm") << "SkolemizationManager: registerSkolem: disequality = " << disequality << ", skolem = " << skolem << std::endl; - - if (isSkolem(skolem)) { - Assert(d_skolemToDisequality[skolem] == disequality); - return; - } - - d_disequalityToSkolem[disequality] = skolem; - d_skolemToDisequality[skolem] = disequality; -} - -bool SkolemizationManager::hasSkolem(Node disequality) { - return (d_disequalityToSkolem.find(disequality) != d_disequalityToSkolem.end()); -} - -Node SkolemizationManager::getSkolem(Node disequality) { - Debug("pf::pm") << "SkolemizationManager: getSkolem( "; - Assert(d_disequalityToSkolem.find(disequality) - != d_disequalityToSkolem.end()); - Debug("pf::pm") << disequality << " ) = " << d_disequalityToSkolem[disequality] << std::endl; - return d_disequalityToSkolem[disequality]; -} - -Node SkolemizationManager::getDisequality(Node skolem) { - Assert(d_skolemToDisequality.find(skolem) != d_skolemToDisequality.end()); - return d_skolemToDisequality[skolem]; -} - -bool SkolemizationManager::isSkolem(Node skolem) { - return (d_skolemToDisequality.find(skolem) != d_skolemToDisequality.end()); -} - -void SkolemizationManager::clear() { - Debug("pf::pm") << "SkolemizationManager: clear" << std::endl; - d_disequalityToSkolem.clear(); - d_skolemToDisequality.clear(); -} - -std::unordered_map<Node, Node, NodeHashFunction>::const_iterator SkolemizationManager::begin() { - return d_disequalityToSkolem.begin(); -} - -std::unordered_map<Node, Node, NodeHashFunction>::const_iterator SkolemizationManager::end() { - return d_disequalityToSkolem.end(); -} - -} /* CVC4 namespace */ diff --git a/src/proof/skolemization_manager.h b/src/proof/skolemization_manager.h deleted file mode 100644 index a2c61db4d..000000000 --- a/src/proof/skolemization_manager.h +++ /dev/null @@ -1,55 +0,0 @@ -/********************* */ -/*! \file skolemization_manager.h - ** \verbatim - ** Top contributors (to current version): - ** Guy Katz, Tim King, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** [[ Add lengthier description here ]] - - ** \todo document this file - - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__SKOLEMIZATION_MANAGER_H -#define CVC4__SKOLEMIZATION_MANAGER_H - -#include <iostream> -#include <unordered_map> - -#include "proof/proof.h" -#include "util/proof.h" -#include "expr/node.h" -#include "theory/logic_info.h" -#include "theory/substitutions.h" - -namespace CVC4 { - -class SkolemizationManager { -public: - void registerSkolem(Node disequality, Node skolem); - bool hasSkolem(Node disequality); - Node getSkolem(Node disequality); - Node getDisequality(Node skolem); - bool isSkolem(Node skolem); - void clear(); - - std::unordered_map<Node, Node, NodeHashFunction>::const_iterator begin(); - std::unordered_map<Node, Node, NodeHashFunction>::const_iterator end(); - -private: - std::unordered_map<Node, Node, NodeHashFunction> d_disequalityToSkolem; - std::unordered_map<Node, Node, NodeHashFunction> d_skolemToDisequality; -}; - -}/* CVC4 namespace */ - - - -#endif /* CVC4__SKOLEMIZATION_MANAGER_H */ diff --git a/src/proof/theory_proof.cpp b/src/proof/theory_proof.cpp deleted file mode 100644 index b47fd6a1e..000000000 --- a/src/proof/theory_proof.cpp +++ /dev/null @@ -1,1756 +0,0 @@ -/********************* */ -/*! \file theory_proof.cpp - ** \verbatim - ** Top contributors (to current version): - ** Guy Katz, Liana Hadarean, Yoni Zohar - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. 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 "base/check.h" -#include "context/context.h" -#include "expr/node_visitor.h" -#include "options/bv_options.h" -#include "options/proof_options.h" -#include "proof/arith_proof.h" -#include "proof/array_proof.h" -#include "proof/clausal_bitvector_proof.h" -#include "proof/clause_id.h" -#include "proof/cnf_proof.h" -#include "proof/proof_manager.h" -#include "proof/proof_output_channel.h" -#include "proof/proof_utils.h" -#include "proof/resolution_bitvector_proof.h" -#include "proof/sat_proof.h" -#include "proof/simplify_boolean_node.h" -#include "proof/uf_proof.h" -#include "prop/sat_solver_types.h" -#include "smt/smt_engine.h" -#include "smt/smt_engine_scope.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/theory_uf.h" -#include "theory/valuation.h" -#include "util/hash.h" -#include "util/proof.h" - -namespace CVC4 { - -using proof::LfscResolutionBitVectorProof; -using proof::ResolutionBitVectorProof; - -unsigned CVC4::ProofLetCount::counter = 0; -static unsigned LET_COUNT = 1; - -TheoryProofEngine::TheoryProofEngine() - : d_registrationCache() - , d_theoryProofTable() -{ - d_theoryProofTable[theory::THEORY_BOOL] = new LFSCBooleanProof(this); -} - -TheoryProofEngine::~TheoryProofEngine() { - TheoryProofTable::iterator it = d_theoryProofTable.begin(); - TheoryProofTable::iterator end = d_theoryProofTable.end(); - for (; it != end; ++it) { - delete it->second; - } -} - -void TheoryProofEngine::registerTheory(theory::Theory* th) { - if (th) { - theory::TheoryId id = th->getId(); - if(d_theoryProofTable.find(id) == d_theoryProofTable.end()) { - - Trace("pf::tp") << "TheoryProofEngine::registerTheory: " << id << std::endl; - - if (id == theory::THEORY_UF) { - d_theoryProofTable[id] = new LFSCUFProof((theory::uf::TheoryUF*)th, this); - return; - } - - if (id == theory::THEORY_BV) { - auto thBv = static_cast<theory::bv::TheoryBV*>(th); - if (options::bitblastMode() == options::BitblastMode::EAGER - && options::bvSatSolver() == options::SatSolverMode::CRYPTOMINISAT) - { - proof::BitVectorProof* bvp = nullptr; - switch (options::bvProofFormat()) - { - case options::BvProofFormat::DRAT: - { - bvp = new proof::LfscDratBitVectorProof(thBv, this); - break; - } - case options::BvProofFormat::LRAT: - { - bvp = new proof::LfscLratBitVectorProof(thBv, this); - break; - } - case options::BvProofFormat::ER: - { - bvp = new proof::LfscErBitVectorProof(thBv, this); - break; - } - default: - { - Unreachable() << "Invalid BvProofFormat"; - } - }; - d_theoryProofTable[id] = bvp; - } - else - { - proof::BitVectorProof* bvp = - new proof::LfscResolutionBitVectorProof(thBv, this); - d_theoryProofTable[id] = bvp; - } - return; - } - - if (id == theory::THEORY_ARRAYS) { - d_theoryProofTable[id] = new LFSCArrayProof((theory::arrays::TheoryArrays*)th, this); - return; - } - - if (id == theory::THEORY_ARITH) { - d_theoryProofTable[id] = new LFSCArithProof((theory::arith::TheoryArith*)th, this); - return; - } - - // TODO other theories - } - } -} - -void TheoryProofEngine::finishRegisterTheory(theory::Theory* th) { - if (th) { - theory::TheoryId id = th->getId(); - if (id == theory::THEORY_BV) { - theory::bv::TheoryBV* bv_th = static_cast<theory::bv::TheoryBV*>(th); - Assert(d_theoryProofTable.find(id) != d_theoryProofTable.end()); - proof::BitVectorProof* bvp = - static_cast<proof::BitVectorProof*>(d_theoryProofTable[id]); - bv_th->setProofLog(bvp); - return; - } - } -} - -TheoryProof* TheoryProofEngine::getTheoryProof(theory::TheoryId id) { - // The UF theory handles queries for the Builtin theory. - if (id == theory::THEORY_BUILTIN) { - Debug("pf::tp") << "TheoryProofEngine::getTheoryProof: BUILTIN --> UF" << std::endl; - id = theory::THEORY_UF; - } - - if (d_theoryProofTable.find(id) == d_theoryProofTable.end()) { - InternalError() - << "Error! Proofs not yet supported for the following theory: " << id - << std::endl; - } - - return d_theoryProofTable[id]; -} - -void TheoryProofEngine::markTermForFutureRegistration(Expr term, theory::TheoryId id) { - d_exprToTheoryIds[term].insert(id); -} - -void TheoryProofEngine::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap) { - Assert(c1.isConst()); - Assert(c2.isConst()); - - Assert(theory::Theory::theoryOf(c1) == theory::Theory::theoryOf(c2)); - getTheoryProof(theory::Theory::theoryOf(c1))->printConstantDisequalityProof(os, c1, c2, globalLetMap); -} - -void TheoryProofEngine::printTheoryTerm(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) -{ - this->printTheoryTermAsType(term, os, map, expectedType); -} - -TypeNode TheoryProofEngine::equalityType(const Expr& left, const Expr& right) -{ - // Ask the two theories what they think.. - TypeNode leftType = getTheoryProof(theory::Theory::theoryOf(left))->equalityType(left, right); - TypeNode rightType = getTheoryProof(theory::Theory::theoryOf(right))->equalityType(left, right); - - // Error if the disagree. - Assert(leftType.isNull() || rightType.isNull() || leftType == rightType) - << "TheoryProofEngine::equalityType(" << left << ", " << right << "):" << std::endl - << "theories disagree about the type of an equality:" << std::endl - << "\tleft: " << leftType << std::endl - << "\tright:" << rightType; - - return leftType.isNull() ? rightType : leftType; -} - -void TheoryProofEngine::registerTerm(Expr term) { - Debug("pf::tp::register") << "TheoryProofEngine::registerTerm: registering term: " << term << std::endl; - - if (d_registrationCache.count(term)) { - return; - } - - Debug("pf::tp::register") << "TheoryProofEngine::registerTerm: registering NEW term: " << term << std::endl; - - theory::TheoryId theory_id = theory::Theory::theoryOf(term); - - Debug("pf::tp::register") << "Term's theory( " << term << " ) = " << theory_id << std::endl; - - // 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) { - registerTerm(term[i]); - } - d_registrationCache.insert(term); - return; - } - - if (!supportedTheory(theory_id)) return; - - // Register the term with its owner theory - getTheoryProof(theory_id)->registerTerm(term); - - // A special case: the array theory needs to know of every skolem, even if - // it belongs to another theory (e.g., a BV skolem) - if (ProofManager::getSkolemizationManager()->isSkolem(term) && theory_id != theory::THEORY_ARRAYS) { - Debug("pf::tp::register") << "TheoryProofEngine::registerTerm: registering a non-array skolem: " << term << std::endl; - getTheoryProof(theory::THEORY_ARRAYS)->registerTerm(term); - } - - d_registrationCache.insert(term); -} - -theory::TheoryId TheoryProofEngine::getTheoryForLemma(const prop::SatClause* clause) { - ProofManager* pm = ProofManager::currentPM(); - - std::set<Node> nodes; - for(unsigned i = 0; i < clause->size(); ++i) { - prop::SatLiteral lit = (*clause)[i]; - Node node = pm->getCnfProof()->getAtom(lit.getSatVariable()); - Expr atom = node.toExpr(); - if (atom.isConst()) { - Assert(atom == utils::mkTrue()); - continue; - } - - nodes.insert(lit.isNegated() ? node.notNode() : node); - } - - // Ensure that the lemma is in the database. - Assert(pm->getCnfProof()->haveProofRecipe(nodes)); - return pm->getCnfProof()->getProofRecipe(nodes).getTheory(); -} - -void LFSCTheoryProofEngine::bind(Expr term, ProofLetMap& map, Bindings& let_order) { - ProofLetMap::iterator it = map.find(term); - if (it != map.end()) { - ProofLetCount& count = it->second; - count.increment(); - return; - } - for (unsigned i = 0; i < term.getNumChildren(); ++i) { - bind(term[i], map, let_order); - } - unsigned new_id = ProofLetCount::newId(); - map[term] = ProofLetCount(new_id); - let_order.push_back(LetOrderElement(term, new_id)); -} - -void LFSCTheoryProofEngine::printLetTerm(Expr term, std::ostream& os) { - ProofLetMap 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; - ProofLetMap::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; - } - - 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::printTheoryTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) -{ - 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, expectedType); - return; - } - // dispatch to proper theory - getTheoryProof(theory_id)->printOwnedTerm(term, os, map, expectedType); -} - -void LFSCTheoryProofEngine::printSort(Type type, std::ostream& os) { - if (type.isSort()) { - getTheoryProof(theory::THEORY_UF)->printOwnedSort(type, os); - return; - } - if (type.isBitVector()) { - getTheoryProof(theory::THEORY_BV)->printOwnedSort(type, os); - return; - } - - if (type.isArray()) { - getTheoryProof(theory::THEORY_ARRAYS)->printOwnedSort(type, os); - return; - } - - if (type.isInteger() || type.isReal()) { - getTheoryProof(theory::THEORY_ARITH)->printOwnedSort(type, os); - return; - } - - if (type.isBoolean()) { - getTheoryProof(theory::THEORY_BOOL)->printOwnedSort(type, os); - return; - } - - Unreachable(); -} - -void LFSCTheoryProofEngine::performExtraRegistrations() { - ExprToTheoryIds::const_iterator it; - for (it = d_exprToTheoryIds.begin(); it != d_exprToTheoryIds.end(); ++it) { - if (d_registrationCache.count(it->first)) { // Only register if the term appeared - TheoryIdSet::const_iterator theoryIt; - for (theoryIt = it->second.begin(); theoryIt != it->second.end(); ++theoryIt) { - Debug("pf::tp") << "\tExtra registration of term " << it->first - << " with theory: " << *theoryIt << std::endl; - Assert(supportedTheory(*theoryIt)); - getTheoryProof(*theoryIt)->registerTerm(it->first); - } - } - } -} - -void LFSCTheoryProofEngine::registerTermsFromAssertions() { - ProofManager::assertions_iterator it = ProofManager::currentPM()->begin_assertions(); - ProofManager::assertions_iterator end = ProofManager::currentPM()->end_assertions(); - - for(; it != end; ++it) { - registerTerm(*it); - } - - performExtraRegistrations(); -} - -void LFSCTheoryProofEngine::printAssertions(std::ostream& os, std::ostream& paren) { - Debug("pf::tp") << "LFSCTheoryProofEngine::printAssertions called" << std::endl << std::endl; - - ProofManager::assertions_iterator it = ProofManager::currentPM()->begin_assertions(); - ProofManager::assertions_iterator end = ProofManager::currentPM()->end_assertions(); - - for (; it != end; ++it) { - Debug("pf::tp") << "printAssertions: assertion is: " << *it << std::endl; - os << "(% " << ProofManager::currentPM()->getInputFormulaName(*it) << " (th_holds "; - - // Assertions appear before the global let map, so we use a dummpMap to avoid letification here. - ProofLetMap dummyMap; - - bool convertFromBool = (it->getType().isBoolean() && printsAsBool(*it)); - if (convertFromBool) os << "(p_app "; - printBoundTerm(*it, os, dummyMap); - if (convertFromBool) os << ")"; - - os << ")\n"; - paren << ")"; - } - - Debug("pf::tp") << "LFSCTheoryProofEngine::printAssertions done" << std::endl << std::endl; -} - -void LFSCTheoryProofEngine::printLemmaRewrites(NodePairSet& rewrites, - std::ostream& os, - std::ostream& paren) { - Debug("pf::tp") << "LFSCTheoryProofEngine::printLemmaRewrites called" << std::endl << std::endl; - - NodePairSet::const_iterator it; - - for (it = rewrites.begin(); it != rewrites.end(); ++it) { - Debug("pf::tp") << "printLemmaRewrites: " << it->first << " --> " << it->second << std::endl; - - Node n1 = it->first; - Node n2 = it->second; - Assert(n1.toExpr() == utils::mkFalse() - || theory::Theory::theoryOf(n1) == theory::Theory::theoryOf(n2)); - - std::ostringstream rewriteRule; - rewriteRule << ".lrr" << d_assertionToRewrite.size(); - - os << "(th_let_pf _ "; - getTheoryProof(theory::Theory::theoryOf(n1))->printRewriteProof(os, n1, n2); - os << "(\\ " << rewriteRule.str() << "\n"; - - d_assertionToRewrite[it->first] = rewriteRule.str(); - Debug("pf::tp") << "d_assertionToRewrite[" << it->first << "] = " << rewriteRule.str() << std::endl; - paren << "))"; - } - - Debug("pf::tp") << "LFSCTheoryProofEngine::printLemmaRewrites done" << std::endl << std::endl; -} - -void LFSCTheoryProofEngine::printSortDeclarations(std::ostream& os, std::ostream& paren) { - Debug("pf::tp") << "LFSCTheoryProofEngine::printSortDeclarations called" << std::endl << std::endl; - - TheoryProofTable::const_iterator it = d_theoryProofTable.begin(); - TheoryProofTable::const_iterator end = d_theoryProofTable.end(); - for (; it != end; ++it) { - it->second->printSortDeclarations(os, paren); - } - - Debug("pf::tp") << "LFSCTheoryProofEngine::printSortDeclarations done" << std::endl << std::endl; -} - -void LFSCTheoryProofEngine::printTermDeclarations(std::ostream& os, std::ostream& paren) { - Debug("pf::tp") << "LFSCTheoryProofEngine::printTermDeclarations called" << std::endl << std::endl; - - TheoryProofTable::const_iterator it = d_theoryProofTable.begin(); - TheoryProofTable::const_iterator end = d_theoryProofTable.end(); - for (; it != end; ++it) { - it->second->printTermDeclarations(os, paren); - } - - Debug("pf::tp") << "LFSCTheoryProofEngine::printTermDeclarations done" << std::endl << std::endl; -} - -void LFSCTheoryProofEngine::printDeferredDeclarations(std::ostream& os, std::ostream& paren) { - Debug("pf::tp") << "LFSCTheoryProofEngine::printDeferredDeclarations called" << std::endl; - - TheoryProofTable::const_iterator it = d_theoryProofTable.begin(); - TheoryProofTable::const_iterator end = d_theoryProofTable.end(); - for (; it != end; ++it) { - it->second->printDeferredDeclarations(os, paren); - } -} - -void LFSCTheoryProofEngine::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) { - Debug("pf::tp") << "LFSCTheoryProofEngine::printAliasingDeclarations called" << std::endl; - - TheoryProofTable::const_iterator it = d_theoryProofTable.begin(); - TheoryProofTable::const_iterator end = d_theoryProofTable.end(); - for (; it != end; ++it) { - it->second->printAliasingDeclarations(os, paren, globalLetMap); - } -} - -void LFSCTheoryProofEngine::dumpTheoryLemmas(const IdToSatClause& lemmas) { - Debug("pf::dumpLemmas") << "Dumping ALL theory lemmas" << std::endl << std::endl; - - ProofManager* pm = ProofManager::currentPM(); - for (IdToSatClause::const_iterator it = lemmas.begin(); it != lemmas.end(); ++it) { - ClauseId id = it->first; - Debug("pf::dumpLemmas") << "**** \tLemma ID = " << id << std::endl; - const prop::SatClause* clause = it->second; - std::set<Node> nodes; - for(unsigned i = 0; i < clause->size(); ++i) { - prop::SatLiteral lit = (*clause)[i]; - Node node = pm->getCnfProof()->getAtom(lit.getSatVariable()); - if (node.isConst()) { - Assert(node.toExpr() == utils::mkTrue()); - continue; - } - nodes.insert(lit.isNegated() ? node.notNode() : node); - } - - LemmaProofRecipe recipe = pm->getCnfProof()->getProofRecipe(nodes); - recipe.dump("pf::dumpLemmas"); - } - - Debug("pf::dumpLemmas") << "Theory lemma printing DONE" << std::endl << std::endl; -} - -// TODO: this function should be moved into the BV prover. -void LFSCTheoryProofEngine::finalizeBvConflicts(const IdToSatClause& lemmas, std::ostream& os) { - // BitVector theory is special case: must know all conflicts needed - // ahead of time for resolution proof lemmas - std::vector<Expr> bv_lemmas; - - for (IdToSatClause::const_iterator it = lemmas.begin(); it != lemmas.end(); ++it) { - const prop::SatClause* clause = it->second; - - std::vector<Expr> conflict; - std::set<Node> conflictNodes; - for(unsigned i = 0; i < clause->size(); ++i) { - prop::SatLiteral lit = (*clause)[i]; - Node node = ProofManager::currentPM()->getCnfProof()->getAtom(lit.getSatVariable()); - Expr atom = node.toExpr(); - - // The literals (true) and (not false) are omitted from conflicts - 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); - conflictNodes.insert(lit.isNegated() ? node.notNode() : node); - } - - LemmaProofRecipe recipe = ProofManager::currentPM()->getCnfProof()->getProofRecipe(conflictNodes); - - unsigned numberOfSteps = recipe.getNumSteps(); - - prop::SatClause currentClause = *clause; - std::vector<Expr> currentClauseExpr = conflict; - - for (unsigned i = 0; i < numberOfSteps; ++i) { - const LemmaProofRecipe::ProofStep* currentStep = recipe.getStep(i); - - if (currentStep->getTheory() != theory::THEORY_BV) { - continue; - } - - // If any rewrites took place, we need to update the conflict clause accordingly - std::set<Node> missingAssertions = recipe.getMissingAssertionsForStep(i); - std::map<Node, Node> explanationToMissingAssertion; - std::set<Node>::iterator assertionIt; - for (assertionIt = missingAssertions.begin(); - assertionIt != missingAssertions.end(); - ++assertionIt) { - Node negated = (*assertionIt).negate(); - explanationToMissingAssertion[recipe.getExplanation(negated)] = negated; - } - - currentClause = *clause; - currentClauseExpr = conflict; - - for (unsigned j = 0; j < i; ++j) { - // Literals already used in previous steps need to be negated - Node previousLiteralNode = recipe.getStep(j)->getLiteral(); - - // If this literal is the result of a rewrite, we need to translate it - if (explanationToMissingAssertion.find(previousLiteralNode) != - explanationToMissingAssertion.end()) { - previousLiteralNode = explanationToMissingAssertion[previousLiteralNode]; - } - - Node previousLiteralNodeNegated = previousLiteralNode.negate(); - prop::SatLiteral previousLiteralNegated = - ProofManager::currentPM()->getCnfProof()->getLiteral(previousLiteralNodeNegated); - - currentClause.push_back(previousLiteralNegated); - currentClauseExpr.push_back(previousLiteralNodeNegated.toExpr()); - } - - // If we're in the final step, the last literal is Null and should not be added. - // Otherwise, the current literal does NOT need to be negated - Node currentLiteralNode = currentStep->getLiteral(); - - if (currentLiteralNode != Node()) { - prop::SatLiteral currentLiteral = - ProofManager::currentPM()->getCnfProof()->getLiteral(currentLiteralNode); - - currentClause.push_back(currentLiteral); - currentClauseExpr.push_back(currentLiteralNode.toExpr()); - } - - bv_lemmas.push_back(utils::mkSortedExpr(kind::OR, currentClauseExpr)); - } - } - - proof::BitVectorProof* bv = ProofManager::getBitVectorProof(); - bv->finalizeConflicts(bv_lemmas); -} - -void LFSCTheoryProofEngine::printTheoryLemmas(const IdToSatClause& lemmas, - std::ostream& os, - std::ostream& paren, - ProofLetMap& map) { - os << " ;; Theory Lemmas \n"; - Debug("pf::tp") << "LFSCTheoryProofEngine::printTheoryLemmas: starting" << std::endl; - - if (Debug.isOn("pf::dumpLemmas")) { - dumpTheoryLemmas(lemmas); - } - - // finalizeBvConflicts(lemmas, os, paren, map); - ProofManager::getBitVectorProof()->printBBDeclarationAndCnf(os, paren, map); - - if (options::bitblastMode() == options::BitblastMode::EAGER) - { - Assert(lemmas.size() == 1); - // nothing more to do (no combination with eager so far) - return; - } - - ProofManager* pm = ProofManager::currentPM(); - Debug("pf::tp") << "LFSCTheoryProofEngine::printTheoryLemmas: printing lemmas..." << std::endl; - - for (IdToSatClause::const_iterator it = lemmas.begin(); it != lemmas.end(); ++it) { - ClauseId id = it->first; - const prop::SatClause* clause = it->second; - - Debug("pf::tp") << "LFSCTheoryProofEngine::printTheoryLemmas: printing lemma. ID = " - << id << std::endl; - - std::vector<Expr> clause_expr; - std::set<Node> clause_expr_nodes; - for(unsigned i = 0; i < clause->size(); ++i) { - prop::SatLiteral lit = (*clause)[i]; - Node node = pm->getCnfProof()->getAtom(lit.getSatVariable()); - Expr atom = node.toExpr(); - if (atom.isConst()) { - Assert(atom == utils::mkTrue()); - continue; - } - Expr expr_lit = lit.isNegated() ? atom.notExpr(): atom; - clause_expr.push_back(expr_lit); - clause_expr_nodes.insert(lit.isNegated() ? node.notNode() : node); - } - - LemmaProofRecipe recipe = pm->getCnfProof()->getProofRecipe(clause_expr_nodes); - - if (recipe.simpleLemma()) { - // In a simple lemma, there will be no propositional resolution in the end - - Debug("pf::tp") << "Simple lemma" << std::endl; - // Printing the clause as it appears in resolution proof - os << "(satlem _ _ "; - std::ostringstream clause_paren; - pm->getCnfProof()->printClause(*clause, os, clause_paren); - - // Find and handle missing assertions, due to rewrites - std::set<Node> missingAssertions = recipe.getMissingAssertionsForStep(0); - if (!missingAssertions.empty()) { - Debug("pf::tp") << "Have missing assertions for this simple lemma!" << std::endl; - } - - std::set<Node>::const_iterator missingAssertion; - for (missingAssertion = missingAssertions.begin(); - missingAssertion != missingAssertions.end(); - ++missingAssertion) { - - Debug("pf::tp") << "Working on missing assertion: " << *missingAssertion << std::endl; - Assert(recipe.wasRewritten(missingAssertion->negate())); - Node explanation = recipe.getExplanation(missingAssertion->negate()).negate(); - Debug("pf::tp") << "Found explanation: " << explanation << std::endl; - - // We have a missing assertion. - // rewriteIt->first is the assertion after the rewrite (the explanation), - // rewriteIt->second is the original assertion that needs to be fed into the theory. - - bool found = false; - unsigned k; - for (k = 0; k < clause_expr.size(); ++k) { - if (clause_expr[k] == explanation.toExpr()) { - found = true; - break; - } - } - - AlwaysAssert(found); - Debug("pf::tp") << "Replacing theory assertion " - << clause_expr[k] - << " with " - << *missingAssertion - << std::endl; - - clause_expr[k] = missingAssertion->toExpr(); - - std::ostringstream rewritten; - - if (missingAssertion->getKind() == kind::NOT && (*missingAssertion)[0].toExpr() == utils::mkFalse()) { - rewritten << "(or_elim_2 _ _ "; - rewritten << "(not_not_intro _ "; - rewritten << pm->getLitName(explanation); - rewritten << ") (iff_elim_2 _ _ "; - rewritten << d_assertionToRewrite[missingAssertion->negate()]; - rewritten << "))"; - } - else { - rewritten << "(or_elim_1 _ _ "; - rewritten << "(not_not_intro _ "; - rewritten << pm->getLitName(explanation); - rewritten << ") (iff_elim_1 _ _ "; - rewritten << d_assertionToRewrite[missingAssertion->negate()]; - rewritten << "))"; - } - - Debug("pf::tp") << "Setting a rewrite filter for this proof: " << std::endl - << pm->getLitName(*missingAssertion) << " --> " << rewritten.str() - << ", explanation = " << explanation - << std::endl << std::endl; - - pm->addRewriteFilter(pm->getLitName(*missingAssertion), rewritten.str()); - } - - // Query the appropriate theory for a proof of this clause - theory::TheoryId theory_id = getTheoryForLemma(clause); - Debug("pf::tp") << "Get theory lemma from " << theory_id << "..." << std::endl; - getTheoryProof(theory_id)->printTheoryLemmaProof(clause_expr, os, paren, map); - - // Turn rewrite filter OFF - pm->clearRewriteFilters(); - - Debug("pf::tp") << "Get theory lemma from " << theory_id << "... DONE!" << std::endl; - os << clause_paren.str(); - os << "( \\ " << pm->getLemmaClauseName(id) <<"\n"; - paren << "))"; - } else { // This is a composite lemma - - unsigned numberOfSteps = recipe.getNumSteps(); - prop::SatClause currentClause = *clause; - std::vector<Expr> currentClauseExpr = clause_expr; - - for (unsigned i = 0; i < numberOfSteps; ++i) { - const LemmaProofRecipe::ProofStep* currentStep = recipe.getStep(i); - - currentClause = *clause; - currentClauseExpr = clause_expr; - - for (unsigned j = 0; j < i; ++j) { - // Literals already used in previous steps need to be negated - Node previousLiteralNode = recipe.getStep(j)->getLiteral(); - Node previousLiteralNodeNegated = previousLiteralNode.negate(); - prop::SatLiteral previousLiteralNegated = - ProofManager::currentPM()->getCnfProof()->getLiteral(previousLiteralNodeNegated); - currentClause.push_back(previousLiteralNegated); - currentClauseExpr.push_back(previousLiteralNodeNegated.toExpr()); - } - - // If the current literal is NULL, can ignore (final step) - // Otherwise, the current literal does NOT need to be negated - Node currentLiteralNode = currentStep->getLiteral(); - if (currentLiteralNode != Node()) { - prop::SatLiteral currentLiteral = - ProofManager::currentPM()->getCnfProof()->getLiteral(currentLiteralNode); - - currentClause.push_back(currentLiteral); - currentClauseExpr.push_back(currentLiteralNode.toExpr()); - } - - os << "(satlem _ _ "; - std::ostringstream clause_paren; - - pm->getCnfProof()->printClause(currentClause, os, clause_paren); - - // query appropriate theory for proof of clause - theory::TheoryId theory_id = currentStep->getTheory(); - Debug("pf::tp") << "Get theory lemma from " << theory_id << "..." << std::endl; - - std::set<Node> missingAssertions = recipe.getMissingAssertionsForStep(i); - if (!missingAssertions.empty()) { - Debug("pf::tp") << "Have missing assertions for this step!" << std::endl; - } - - // Turn rewrite filter ON - std::set<Node>::const_iterator missingAssertion; - for (missingAssertion = missingAssertions.begin(); - missingAssertion != missingAssertions.end(); - ++missingAssertion) { - - Debug("pf::tp") << "Working on missing assertion: " << *missingAssertion << std::endl; - - Assert(recipe.wasRewritten(missingAssertion->negate())); - Node explanation = recipe.getExplanation(missingAssertion->negate()).negate(); - - Debug("pf::tp") << "Found explanation: " << explanation << std::endl; - - // We have a missing assertion. - // rewriteIt->first is the assertion after the rewrite (the explanation), - // rewriteIt->second is the original assertion that needs to be fed into the theory. - - bool found = false; - unsigned k; - for (k = 0; k < currentClauseExpr.size(); ++k) { - if (currentClauseExpr[k] == explanation.toExpr()) { - found = true; - break; - } - } - - AlwaysAssert(found); - - Debug("pf::tp") << "Replacing theory assertion " - << currentClauseExpr[k] - << " with " - << *missingAssertion - << std::endl; - - currentClauseExpr[k] = missingAssertion->toExpr(); - - std::ostringstream rewritten; - - if (missingAssertion->getKind() == kind::NOT && (*missingAssertion)[0].toExpr() == utils::mkFalse()) { - rewritten << "(or_elim_2 _ _ "; - rewritten << "(not_not_intro _ "; - rewritten << pm->getLitName(explanation); - rewritten << ") (iff_elim_2 _ _ "; - rewritten << d_assertionToRewrite[missingAssertion->negate()]; - rewritten << "))"; - } - else { - rewritten << "(or_elim_1 _ _ "; - rewritten << "(not_not_intro _ "; - rewritten << pm->getLitName(explanation); - rewritten << ") (iff_elim_1 _ _ "; - rewritten << d_assertionToRewrite[missingAssertion->negate()]; - rewritten << "))"; - } - - Debug("pf::tp") << "Setting a rewrite filter for this proof: " << std::endl - << pm->getLitName(*missingAssertion) << " --> " << rewritten.str() - << "explanation = " << explanation - << std::endl << std::endl; - - pm->addRewriteFilter(pm->getLitName(*missingAssertion), rewritten.str()); - } - - getTheoryProof(theory_id)->printTheoryLemmaProof(currentClauseExpr, os, paren, map); - - // Turn rewrite filter OFF - pm->clearRewriteFilters(); - - Debug("pf::tp") << "Get theory lemma from " << theory_id << "... DONE!" << std::endl; - os << clause_paren.str(); - os << "( \\ " << pm->getLemmaClauseName(id) << "s" << i <<"\n"; - paren << "))"; - } - - Assert(numberOfSteps >= 2); - - os << "(satlem_simplify _ _ _ "; - for (unsigned i = 0; i < numberOfSteps - 1; ++i) { - // Resolve step i with step i + 1 - if (recipe.getStep(i)->getLiteral().getKind() == kind::NOT) { - os << "(Q _ _ "; - } else { - os << "(R _ _ "; - } - - os << pm->getLemmaClauseName(id) << "s" << i; - os << " "; - } - - os << pm->getLemmaClauseName(id) << "s" << numberOfSteps - 1 << " "; - - prop::SatLiteral v; - for (int i = numberOfSteps - 2; i >= 0; --i) { - v = ProofManager::currentPM()->getCnfProof()->getLiteral(recipe.getStep(i)->getLiteral()); - os << ProofManager::getVarName(v.getSatVariable(), "") << ") "; - } - - os << "( \\ " << pm->getLemmaClauseName(id) << "\n"; - paren << "))"; - } - } -} - -void LFSCTheoryProofEngine::printBoundTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) -{ - Debug("pf::tp") << "LFSCTheoryProofEngine::printBoundTerm( " << term << " ) " << std::endl; - - // Since let-abbreviated terms are abbreviated with their default type, only - // use the let map if there is no expectedType or the expectedType matches - // the default. - if (expectedType.isNull() - || TypeNode::fromType(term.getType()) == expectedType) - { - ProofLetMap::const_iterator it = map.find(term); - if (it != map.end()) - { - unsigned id = it->second.id; - unsigned count = it->second.count; - - if (count > LET_COUNT) - { - os << "let" << id; - Debug("pf::tp::letmap") << "Using let map for " << term << std::endl; - return; - } - } - } - Debug("pf::tp::letmap") << "Skipping let map for " << term << std::endl; - - printTheoryTerm(term, os, map, expectedType); -} - -void LFSCTheoryProofEngine::printBoundFormula(Expr term, - std::ostream& os, - const ProofLetMap& map) -{ - Assert(term.getType().isBoolean() or term.getType().isPredicate()); - bool wrapWithBoolToPred = term.getType().isBoolean() and printsAsBool(term); - if (wrapWithBoolToPred) - { - os << "(p_app "; - } - printBoundTerm(term, os, map); - if (wrapWithBoolToPred) - { - os << ")"; - } -} - -void LFSCTheoryProofEngine::printCoreTerm(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) -{ - if (term.isVariable()) { - os << ProofManager::sanitize(term); - return; - } - - Kind k = term.getKind(); - - switch(k) { - case kind::ITE: { - TypeNode armType = expectedType.isNull() - ? TypeNode::fromType(term.getType()) - : expectedType; - bool useFormulaType = term.getType().isBoolean(); - Assert(term[1].getType().isSubtypeOf(term.getType())); - Assert(term[2].getType().isSubtypeOf(term.getType())); - os << (useFormulaType ? "(ifte " : "(ite _ "); - - printBoundFormula(term[0], os, map); - os << " "; - if (useFormulaType) - { - printBoundFormula(term[1], os, map); - } - else - { - printBoundTerm(term[1], os, map, armType); - } - os << " "; - if (useFormulaType) - { - printBoundFormula(term[2], os, map); - } - else - { - printBoundTerm(term[2], os, map, armType); - } - os << ")"; - return; - } - - case kind::EQUAL: { - bool booleanCase = term[0].getType().isBoolean(); - TypeNode armType = equalityType(term[0], term[1]); - - os << "("; - if (booleanCase) { - os << "iff "; - } else { - os << "= "; - printSort(term[0].getType(), os); - os << " "; - } - - if (booleanCase && printsAsBool(term[0])) os << "(p_app "; - printBoundTerm(term[0], os, map, armType); - if (booleanCase && printsAsBool(term[0])) os << ")"; - - os << " "; - - if (booleanCase && printsAsBool(term[1])) os << "(p_app "; - printBoundTerm(term[1], os, map, armType); - if (booleanCase && printsAsBool(term[1])) os << ") "; - os << ")"; - - return; - } - - case kind::DISTINCT: - { - // Distinct nodes can have any number of chidlren. - Assert(term.getNumChildren() >= 2); - TypeNode armType = equalityType(term[0], term[1]); - - if (term.getNumChildren() == 2) { - os << "(not (= "; - printSort(term[0].getType(), os); - os << " "; - printBoundTerm(term[0], os, map, armType); - os << " "; - printBoundTerm(term[1], os, map, armType); - os << "))"; - } else { - 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) { - for (unsigned j = i + 1; j < term.getNumChildren(); ++j) { - armType = equalityType(term[i], term[j]); - if ((i != 0) || (j != 1)) { - os << "(not (= "; - printSort(term[0].getType(), os); - os << " "; - printBoundTerm(term[i], os, map, armType); - os << " "; - printBoundTerm(term[j], os, map, armType); - os << ")))"; - } else { - os << "(not (= "; - printSort(term[0].getType(), os); - os << " "; - printBoundTerm(term[0], os, map, armType); - os << " "; - printBoundTerm(term[1], os, map, armType); - os << "))"; - } - } - } - } - return; - } - - default: Unhandled() << k; - } -} - -void TheoryProof::printTheoryLemmaProof(std::vector<Expr>& lemma, - std::ostream& os, - std::ostream& paren, - const ProofLetMap& map) { - // 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("pf::tp") << ";; 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(), - nullptr, - "replay::"); - } else if (d_theory->getId()==theory::THEORY_ARRAYS) { - th = new theory::arrays::TheoryArrays( - &fakeContext, - &fakeContext, - oc, - v, - ProofManager::currentPM()->getLogicInfo(), - nullptr, - "replay::"); - } else if (d_theory->getId() == theory::THEORY_ARITH) { - Trace("theory-proof-debug") << "Arith proofs currently not supported. Use 'trust'" << std::endl; - os << " (clausify_false trust)"; - return; - } else { - InternalError() << "can't generate theory-proof for " - << ProofManager::currentPM()->getLogic(); - } - // must perform initialization on the theory - if (th != nullptr) - { - // finish init, standalone version - th->finishInitStandalone(); - } - - Debug("pf::tp") << "TheoryProof::printTheoryLemmaProof - calling th->ProduceProofs()" << std::endl; - th->produceProofs(); - Debug("pf::tp") << "TheoryProof::printTheoryLemmaProof - th->ProduceProofs() DONE" << std::endl; - - MyPreRegisterVisitor preRegVisitor(th); - for (unsigned i=0; i<lemma.size(); i++) { - Node strippedLit = (lemma[i].getKind() == kind::NOT) ? lemma[i][0] : lemma[i]; - if (strippedLit.getKind() == kind::EQUAL || - d_theory->getId() == theory::Theory::theoryOf(strippedLit)) { - Node lit = Node::fromExpr( lemma[i] ).negate(); - Trace("pf::tp") << "; preregistering and asserting " << lit << std::endl; - NodeVisitor<MyPreRegisterVisitor>::run(preRegVisitor, lit); - th->assertFact(lit, false); - } - } - - Debug("pf::tp") << "TheoryProof::printTheoryLemmaProof - calling th->check()" << std::endl; - th->check(theory::Theory::EFFORT_FULL); - Debug("pf::tp") << "TheoryProof::printTheoryLemmaProof - th->check() DONE" << std::endl; - - if(!oc.hasConflict()) { - Trace("pf::tp") << "; conflict is null" << std::endl; - Node lastLemma = oc.getLastLemma(); - Assert(!lastLemma.isNull()); - Trace("pf::tp") << "; ++ but got lemma: " << lastLemma << std::endl; - - if (lastLemma.getKind() == kind::OR) { - Debug("pf::tp") << "OR lemma. Negating each child separately" << std::endl; - for (unsigned i = 0; i < lastLemma.getNumChildren(); ++i) { - if (lastLemma[i].getKind() == kind::NOT) { - Trace("pf::tp") << "; asserting fact: " << lastLemma[i][0] << std::endl; - th->assertFact(lastLemma[i][0], false); - } - else { - Trace("pf::tp") << "; asserting fact: " << lastLemma[i].notNode() << std::endl; - th->assertFact(lastLemma[i].notNode(), false); - } - } - } else { - Unreachable(); - - Assert(oc.getLastLemma().getKind() == kind::NOT); - Debug("pf::tp") << "NOT lemma" << std::endl; - Trace("pf::tp") << "; asserting fact: " << oc.getLastLemma()[0] - << std::endl; - th->assertFact(oc.getLastLemma()[0], false); - } - - // Trace("pf::tp") << "; ++ but got lemma: " << oc.d_lemma << std::endl; - // Trace("pf::tp") << "; asserting " << oc.d_lemma[1].negate() << std::endl; - // th->assertFact(oc.d_lemma[1].negate(), false); - - // - th->check(theory::Theory::EFFORT_FULL); - } else { - Debug("pf::tp") << "Calling oc.d_proof->toStream(os)" << std::endl; - oc.getConflictProof().toStream(os, map); - Debug("pf::tp") << "Calling oc.d_proof->toStream(os) -- DONE!" << std::endl; - } - - Debug("pf::tp") << "About to delete the theory solver used for proving the lemma... " << std::endl; - delete th; - Debug("pf::tp") << "About to delete the theory solver used for proving the lemma: DONE! " << std::endl; -} - -bool TheoryProofEngine::supportedTheory(theory::TheoryId id) { - return (id == theory::THEORY_ARRAYS || - id == theory::THEORY_ARITH || - id == theory::THEORY_BV || - id == theory::THEORY_UF || - id == theory::THEORY_BOOL); -} - -bool TheoryProofEngine::printsAsBool(const Node &n) { - if (!n.getType().isBoolean()) { - return false; - } - - theory::TheoryId theory_id = theory::Theory::theoryOf(n); - return getTheoryProof(theory_id)->printsAsBool(n); -} - -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]); - } -} - -theory::TheoryId BooleanProof::getTheoryId() { return theory::THEORY_BOOL; } -void LFSCBooleanProof::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap) { - Node falseNode = NodeManager::currentNM()->mkConst(false); - Node trueNode = NodeManager::currentNM()->mkConst(true); - - Assert(c1 == falseNode.toExpr() || c1 == trueNode.toExpr()); - Assert(c2 == falseNode.toExpr() || c2 == trueNode.toExpr()); - Assert(c1 != c2); - - if (c1 == trueNode.toExpr()) - os << "t_t_neq_f"; - else - os << "(negsymm _ _ _ t_t_neq_f)"; -} - -void LFSCBooleanProof::printOwnedTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) -{ - Assert(term.getType().isBoolean()); - if (term.isVariable()) { - os << ProofManager::sanitize(term); - return; - } - - Kind k = term.getKind(); - switch(k) { - case kind::OR: - case kind::AND: - if (options::lfscLetification() && term.getNumChildren() > 2) { - // If letification is on, the entire term is probably a let expression. - // However, we need to transform it from (and a b c) into (and a (and b c)) form first. - Node currentExpression = term[term.getNumChildren() - 1]; - for (int i = term.getNumChildren() - 2; i >= 0; --i) { - NodeBuilder<> builder(k); - builder << term[i]; - builder << currentExpression.toExpr(); - currentExpression = builder; - } - - // The let map should already have the current expression. - ProofLetMap::const_iterator it = map.find(currentExpression.toExpr()); - if (it != map.end()) { - unsigned id = it->second.id; - unsigned count = it->second.count; - - if (count > LET_COUNT) { - os << "let" << id; - break; - } - } - } - - // If letification is off or there were 2 children, same treatment as the other cases. - CVC4_FALLTHROUGH; - case kind::XOR: - 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) { - - if (printsAsBool(term[i])) os << "(p_app "; - d_proofEngine->printBoundTerm(term[i], os, map); - if (printsAsBool(term[i])) os << ")"; - - os << " "; - if(i < term.getNumChildren() - 2) { - os << "(" << utils::toLFSCKind(k) << " "; - paren << ")"; - } - } - os << paren.str() << ")"; - } else { - // this is for binary and unary operators - for (unsigned i = 0; i < term.getNumChildren(); ++i) { - os << " "; - if (printsAsBool(term[i])) os << "(p_app "; - d_proofEngine->printBoundTerm(term[i], os, map); - if (printsAsBool(term[i])) os << ")"; - } - os << ")"; - } - return; - - case kind::CONST_BOOLEAN: - os << (term.getConst<bool>() ? "true" : "false"); - return; - - default: Unhandled() << k; - } -} - -void LFSCBooleanProof::printOwnedSort(Type type, std::ostream& os) { - Assert(type.isBoolean()); - os << "Bool"; -} - -void LFSCBooleanProof::printSortDeclarations(std::ostream& os, std::ostream& paren) { - // Nothing to do here at this point. -} - -void LFSCBooleanProof::printTermDeclarations(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::printDeferredDeclarations(std::ostream& os, std::ostream& paren) { - // Nothing to do here at this point. -} - -void LFSCBooleanProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) { - // Nothing to do here at this point. -} - -void LFSCBooleanProof::printTheoryLemmaProof(std::vector<Expr>& lemma, - std::ostream& os, - std::ostream& paren, - const ProofLetMap& map) { - Unreachable() << "No boolean lemmas yet!"; -} - -bool LFSCBooleanProof::printsAsBool(const Node &n) -{ - Kind k = n.getKind(); - switch (k) { - case kind::BOOLEAN_TERM_VARIABLE: - case kind::VARIABLE: - return true; - - default: - return false; - } -} - -void TheoryProof::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap) { - // By default, we just print a trust statement. Specific theories can implement - // better proofs. - - os << "(trust_f (not (= _ "; - d_proofEngine->printBoundTerm(c1, os, globalLetMap); - os << " "; - d_proofEngine->printBoundTerm(c2, os, globalLetMap); - os << ")))"; -} - -void TheoryProof::printRewriteProof(std::ostream& os, const Node &n1, const Node &n2) { - // This is the default for a rewrite proof: just a trust statement. - ProofLetMap emptyMap; - os << "(trust_f (iff "; - d_proofEngine->printBoundTerm(n1.toExpr(), os, emptyMap); - os << " "; - d_proofEngine->printBoundTerm(n2.toExpr(), os, emptyMap); - os << "))"; -} - -void TheoryProof::printOwnedTerm(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) -{ - this->printOwnedTermAsType(term, os, map, expectedType); -} - -TypeNode TheoryProof::equalityType(const Expr& left, const Expr& right) -{ - Assert(left.getType() == right.getType()) - << "TheoryProof::equalityType(" << left << ", " << right << "):" << std::endl - << "types disagree:" << std::endl - << "\tleft: " << left.getType() << std::endl - << "\tright:" << right.getType(); - return TypeNode::fromType(left.getType()); -} - -bool TheoryProof::match(TNode n1, TNode n2) -{ - theory::TheoryId theoryId = this->getTheoryId(); - ProofManager* pm = ProofManager::currentPM(); - bool ufProof = (theoryId == theory::THEORY_UF); - Debug(ufProof ? "pf::uf" : "mgd") << "match " << n1 << " " << n2 << std::endl; - if (pm->hasOp(n1)) - { - n1 = pm->lookupOp(n1); - } - if (pm->hasOp(n2)) - { - n2 = pm->lookupOp(n2); - } - Debug(ufProof ? "pf::uf" : "mgd") << "+ match " << n1 << " " << n2 - << std::endl; - if (!ufProof) - { - Debug("pf::array") << "+ match: step 1" << std::endl; - } - if (n1 == n2) - { - return true; - } - - if (n1.getType().isFunction() && n2.hasOperator()) - { - if (pm->hasOp(n2.getOperator())) - { - return n1 == pm->lookupOp(n2.getOperator()); - } - else - { - return n1 == n2.getOperator(); - } - } - - if (n2.getType().isFunction() && n1.hasOperator()) - { - if (pm->hasOp(n1.getOperator())) - { - return n2 == pm->lookupOp(n1.getOperator()); - } - else - { - return n2 == n1.getOperator(); - } - } - - if (n1.hasOperator() && n2.hasOperator() - && n1.getOperator() != n2.getOperator()) - { - if (ufProof - || !((n1.getKind() == kind::SELECT - && n2.getKind() == kind::PARTIAL_SELECT_0) - || (n1.getKind() == kind::SELECT - && n2.getKind() == kind::PARTIAL_SELECT_1) - || (n1.getKind() == kind::PARTIAL_SELECT_1 - && n2.getKind() == kind::SELECT) - || (n1.getKind() == kind::PARTIAL_SELECT_1 - && n2.getKind() == kind::PARTIAL_SELECT_0) - || (n1.getKind() == kind::PARTIAL_SELECT_0 - && n2.getKind() == kind::SELECT) - || (n1.getKind() == kind::PARTIAL_SELECT_0 - && n2.getKind() == kind::PARTIAL_SELECT_1))) - { - return false; - } - } - - for (size_t i = 0; i < n1.getNumChildren() && i < n2.getNumChildren(); ++i) - { - if (n1[i] != n2[i]) - { - return false; - } - } - - return true; -} - -int TheoryProof::assertAndPrint( - const theory::eq::EqProof& pf, - const ProofLetMap& map, - std::shared_ptr<theory::eq::EqProof> subTrans, - theory::eq::EqProof::PrettyPrinter* pPrettyPrinter) -{ - theory::TheoryId theoryId = getTheoryId(); - int neg = -1; - Assert(theoryId == theory::THEORY_UF || theoryId == theory::THEORY_ARRAYS); - bool ufProof = (theoryId == theory::THEORY_UF); - std::string theoryName = theory::getStatsPrefix(theoryId); - pf.debug_print(("pf::" + theoryName).c_str(), 0, pPrettyPrinter); - Debug("pf::" + theoryName) << std::endl; - - Assert(pf.d_id == theory::eq::MERGED_THROUGH_TRANS); - Assert(!pf.d_node.isNull()); - Assert(pf.d_children.size() >= 2); - - subTrans->d_id = theory::eq::MERGED_THROUGH_TRANS; - subTrans->d_node = pf.d_node; - - size_t i = 0; - while (i < pf.d_children.size()) - { - // special treatment for uf and not for array - if (ufProof - || pf.d_children[i]->d_id != theory::eq::MERGED_THROUGH_CONGRUENCE) - { - pf.d_children[i]->d_node = simplifyBooleanNode(pf.d_children[i]->d_node); - } - - // 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 == theory::eq::MERGED_THROUGH_CONGRUENCE - && pf.d_children[i]->d_node.isNull()) - { - Debug("pf::" + theoryName) << "Handling congruence over equalities" - << std::endl; - - // Gather the sequence of consecutive congruence closures. - std::vector<std::shared_ptr<const theory::eq::EqProof>> - congruenceClosures; - unsigned count; - Debug("pf::" + theoryName) << "Collecting congruence sequence" - << std::endl; - for (count = 0; i + count < pf.d_children.size() - && pf.d_children[i + count]->d_id - == theory::eq::MERGED_THROUGH_CONGRUENCE - && pf.d_children[i + count]->d_node.isNull(); - ++count) - { - Debug("pf::" + theoryName) << "Found a congruence: " << std::endl; - pf.d_children[i + count]->debug_print( - ("pf::" + theoryName).c_str(), 0, pPrettyPrinter); - congruenceClosures.push_back(pf.d_children[i + count]); - } - - Debug("pf::" + theoryName) - << "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("pf::" + theoryName) << "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("pf::" + theoryName) << "Target does not appear after" - << std::endl; - targetAppearsAfter = false; - } - - // Flow changes between uf and array - if (ufProof) - { - // Assert that we have precisely at least one possible clause. - Assert(targetAppearsBefore || targetAppearsAfter); - - // If both are valid, assume the one after the sequence is correct - if (targetAppearsAfter && targetAppearsBefore) - { - targetAppearsBefore = false; - } - } - else - { // not a uf proof - // Assert that we have precisely one target clause. - Assert(targetAppearsBefore != targetAppearsAfter); - } - - // Begin breaking up the congruences and ordering the equalities - // correctly. - std::vector<std::shared_ptr<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 - != theory::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 - != theory::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 - != theory::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 - != theory::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; - } - } - - bool disequalityFound = (neg >= 0); - if (!disequalityFound) - { - Debug("pf::" + theoryName) - << "A disequality was NOT found. UNSAT due to merged constants" - << std::endl; - Debug("pf::" + theoryName) << "Proof for: " << pf.d_node << std::endl; - Assert(pf.d_node.getKind() == kind::EQUAL); - Assert(pf.d_node.getNumChildren() == 2); - Assert(pf.d_node[0].isConst() && pf.d_node[1].isConst()); - } - return neg; -} - -std::pair<Node, Node> TheoryProof::identicalEqualitiesPrinterHelper( - bool evenLengthSequence, - bool sequenceOver, - const theory::eq::EqProof& pf, - const ProofLetMap& map, - const std::string subproofStr, - std::stringstream* outStream, - Node n, - Node nodeAfterEqualitySequence) -{ - theory::TheoryId theoryId = getTheoryId(); - Assert(theoryId == theory::THEORY_UF || theoryId == theory::THEORY_ARRAYS); - bool ufProof = (theoryId == theory::THEORY_UF); - std::string theoryName = theory::getStatsPrefix(theoryId); - if (evenLengthSequence) - { - // If the length is even, we need to apply transitivity for the "correct" - // hand of the equality. - - Debug("pf::" + theoryName) << "Equality sequence of even length" - << std::endl; - Debug("pf::" + theoryName) << "n1 is: " << n << std::endl; - Debug("pf::" + theoryName) << "pf-d_node is: " << pf.d_node << std::endl; - Debug("pf::" + theoryName) << "Next node is: " << nodeAfterEqualitySequence - << std::endl; - - (*outStream) << "(trans _ _ _ _ "; - - // If the sequence is at the very end of the transitivity proof, use - // pf.d_node to guide us. - if (!sequenceOver) - { - if (match(n[0], pf.d_node[0])) - { - n = n[0].eqNode(n[0]); - (*outStream) << subproofStr << " (symm _ _ _ " << subproofStr << ")"; - } - else if (match(n[1], pf.d_node[1])) - { - n = n[1].eqNode(n[1]); - (*outStream) << " (symm _ _ _ " << subproofStr << ")" << subproofStr; - } - else - { - Debug("pf::" + theoryName) << "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. - if (!ufProof && nodeAfterEqualitySequence.getKind() == kind::NOT) - { - nodeAfterEqualitySequence = nodeAfterEqualitySequence[0]; - } - - Assert(nodeAfterEqualitySequence.getKind() == kind::EQUAL); - - if ((n[0] == nodeAfterEqualitySequence[0]) - || (n[0] == nodeAfterEqualitySequence[1])) - { - // Eliminate n[1] - (*outStream) << subproofStr << " (symm _ _ _ " << subproofStr << ")"; - n = n[0].eqNode(n[0]); - } - else if ((n[1] == nodeAfterEqualitySequence[0]) - || (n[1] == nodeAfterEqualitySequence[1])) - { - // Eliminate n[0] - (*outStream) << " (symm _ _ _ " << subproofStr << ")" << subproofStr; - n = n[1].eqNode(n[1]); - } - else - { - Debug("pf::" + theoryName) << "Error: even length sequence, but I " - "don't know which hand to keep!" - << std::endl; - Assert(false); - } - } - - (*outStream) << ")"; - } - else - { - Debug("pf::" + theoryName) << "Equality sequence length is odd!" - << std::endl; - (*outStream).str(subproofStr); - } - - Debug("pf::" + theoryName) << "Have proven: " << n << std::endl; - return std::make_pair<Node&, Node&>(n, nodeAfterEqualitySequence); -} - -} /* namespace CVC4 */ diff --git a/src/proof/theory_proof.h b/src/proof/theory_proof.h deleted file mode 100644 index dd5fe0326..000000000 --- a/src/proof/theory_proof.h +++ /dev/null @@ -1,510 +0,0 @@ -/********************* */ -/*! \file theory_proof.h - ** \verbatim - ** Top contributors (to current version): - ** Liana Hadarean, Guy Katz, Alex Ozdemir - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** [[ Add lengthier description here ]] - - ** \todo document this file - -**/ - -#include "cvc4_private.h" - -#ifndef CVC4__THEORY_PROOF_H -#define CVC4__THEORY_PROOF_H - -#include <iosfwd> -#include <unordered_map> -#include <unordered_set> - -#include "expr/expr.h" -#include "expr/type_node.h" -#include "proof/clause_id.h" -#include "proof/proof_utils.h" -#include "prop/sat_solver_types.h" -#include "theory/uf/equality_engine.h" -#include "util/proof.h" -namespace CVC4 { - -namespace theory { -class Theory; -} /* namespace CVC4::theory */ - -typedef std::unordered_map < ClauseId, prop::SatClause* > IdToSatClause; - -class TheoryProof; - -typedef std::unordered_set<Expr, ExprHashFunction > ExprSet; -typedef std::map<theory::TheoryId, TheoryProof* > TheoryProofTable; - -typedef std::set<theory::TheoryId> TheoryIdSet; -typedef std::map<Expr, TheoryIdSet> ExprToTheoryIds; - -class TheoryProofEngine { -protected: - ExprSet d_registrationCache; - TheoryProofTable d_theoryProofTable; - ExprToTheoryIds d_exprToTheoryIds; - - /** - * Returns whether the theory is currently supported in proof - * production mode. - */ - bool supportedTheory(theory::TheoryId id); -public: - - TheoryProofEngine(); - virtual ~TheoryProofEngine(); - - /** - * Print the theory term (could be an atom) by delegating to the proper theory. - * - * @param term - * @param os - */ - virtual void printLetTerm(Expr term, std::ostream& os) = 0; - - /** - * Print a term in some (core or non-core) theory - * - * @param term expression representing term - * @param os output stream - * @param expectedType The type that this is expected to have in a parent - * node. Null if there are no such requirements. This is useful for requesting - * type conversions from the theory. e.g. in (5.5 == 4) the right-hand-side - * should be converted to a real. - * - * The first version of this function has a default value for expectedType - * (null) The second version is virtual. - * - * They are split to avoid mixing virtual function and default argument - * values, which behave weirdly when combined. - */ - void printBoundTerm(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType = TypeNode()) - { - this->printBoundTermAsType(term, os, map, expectedType); - } - virtual void printBoundTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) = 0; - - /** - * Print the proof representation of the given sort. - * - * @param os - */ - virtual void printSort(Type type, std::ostream& os) = 0; - - /** - * Go over the assertions and register all terms with the theories. - * - * @param os - * @param paren closing parenthesis - */ - virtual void registerTermsFromAssertions() = 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 variable declarations that need to appear within the proof, - * e.g. skolemized variables. - * - * @param os - * @param paren closing parenthesis - */ - virtual void printDeferredDeclarations(std::ostream& os, std::ostream& paren) = 0; - - /** - * Print aliasing declarations. - * - * @param os - * @param paren closing parenthesis - */ - virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) = 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, ProofLetMap& map) = 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. - * This method can be invoked regardless of whether the "proof" option - * has been set. - * - * @param theory - */ - void registerTheory(theory::Theory* theory); - /** - * Additional configuration of the theory proof class for the given theory. - * This method should only be invoked when the "proof" option has been set. - * - * @param theory - */ - void finishRegisterTheory(theory::Theory* theory); - - theory::TheoryId getTheoryForLemma(const prop::SatClause* clause); - TheoryProof* getTheoryProof(theory::TheoryId id); - - void markTermForFutureRegistration(Expr term, theory::TheoryId id); - - void printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap); - - /** - * Print a term in some non-core theory - * - * @param term expression representing term - * @param os output stream - * @param expectedType The type that this is expected to have in a parent - * node. Null if there are no such requirements. This is useful for requesting - * type conversions from the theory. e.g. in (5.5 == 4) the right-hand-side - * should be converted to a real. - * - * The first version of this function has a default value for expectedType - * (null) The second version is virtual. - * - * They are split to avoid mixing virtual function and default argument - * values, which behave weirdly when combined. - */ - void printTheoryTerm(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType = TypeNode()); - virtual void printTheoryTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) = 0; - /** - * Calls `TheoryProof::equalityType` on the appropriate theory. - */ - TypeNode equalityType(const Expr& left, const Expr& right); - - bool printsAsBool(const Node &n); -}; - -class LFSCTheoryProofEngine : public TheoryProofEngine { - void bind(Expr term, ProofLetMap& map, Bindings& let_order); -public: - LFSCTheoryProofEngine() - : TheoryProofEngine() {} - - void printTheoryTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) override; - - void registerTermsFromAssertions() override; - void printSortDeclarations(std::ostream& os, std::ostream& paren); - void printTermDeclarations(std::ostream& os, std::ostream& paren); - void printCoreTerm(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType = TypeNode()); - void printLetTerm(Expr term, std::ostream& os) override; - void printBoundTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) override; - void printAssertions(std::ostream& os, std::ostream& paren) override; - void printLemmaRewrites(NodePairSet& rewrites, - std::ostream& os, - std::ostream& paren); - void printDeferredDeclarations(std::ostream& os, - std::ostream& paren) override; - void printAliasingDeclarations(std::ostream& os, - std::ostream& paren, - const ProofLetMap& globalLetMap) override; - void printTheoryLemmas(const IdToSatClause& lemmas, - std::ostream& os, - std::ostream& paren, - ProofLetMap& map) override; - void printSort(Type type, std::ostream& os) override; - - void performExtraRegistrations(); - - void finalizeBvConflicts(const IdToSatClause& lemmas, std::ostream& os); - -private: - static void dumpTheoryLemmas(const IdToSatClause& lemmas); - - // Prints this boolean term as a formula. - // If necessary, it prints a wrapper converting a `Bool`-sorted term to a - // formula. - void printBoundFormula(Expr term, std::ostream& os, const ProofLetMap& map); - - // TODO: this function should be moved into the BV prover. - - std::map<Node, std::string> d_assertionToRewrite; -}; - -class TheoryProof { -protected: - // Pointer to the theory for this proof - theory::Theory* d_theory; - TheoryProofEngine* d_proofEngine; - virtual theory::TheoryId getTheoryId() = 0; - - public: - TheoryProof(theory::Theory* th, TheoryProofEngine* proofEngine) - : d_theory(th) - , d_proofEngine(proofEngine) - {} - virtual ~TheoryProof() {}; - /** - * Print a term belonging some theory, not necessarily this one. - * - * @param term expresion representing term - * @param os output stream - */ - void printTerm(Expr term, std::ostream& os, const ProofLetMap& map) { - d_proofEngine->printBoundTerm(term, os, map); - } - /** - * Print a term belonging to THIS theory. - * - * @param term expression representing term - * @param os output stream - * @param expectedType The type that this is expected to have in a parent - * node. Null if there are no such requirements. This is useful for requesting - * type conversions from the theory. e.g. in (5.5 == 4) the right-hand-side - * should be converted to a real. - * - * The first version of this function has a default value for expectedType - * (null) The second version is virtual. - * - * They are split to avoid mixing virtual function and default argument - * values, which behave weirdly when combined. - */ - void printOwnedTerm(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType = TypeNode()); - - virtual void printOwnedTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) = 0; - - /** - * Return the type (at the SMT level, the sort) of an equality or disequality - * between `left` and `right`. - * - * The default implementation asserts that the two have the same type, and - * returns it. - * - * A theory may want to do something else. - * - * For example, the theory of arithmetic allows equalities between Reals and - * Integers. In this case the integer is upcast to a real, and the equality - * is over reals. - */ - virtual TypeNode equalityType(const Expr& left, const Expr& right); - - /** - * Print the proof representation of the given type that belongs to some theory. - * - * @param type - * @param os - */ - void printSort(Type type, std::ostream& os) { - d_proofEngine->printSort(type, os); - } - - // congrence matching term helper - bool match(TNode n1, TNode n2); - - /** - * Helper function for ProofUF::toStreamRecLFSC and - * ProofArray::toStreamRecLFSC - * Inputs: - * - pf: equality engine proof - * - map: A map for the let-expressions in the proof - * - subTrans: main transitivity proof part - * - pPrettyPrinter: optional pretty printer for sub-proofs - * returns: - * - the index of the contradicting node in pf. - * */ - int assertAndPrint( - const theory::eq::EqProof& pf, - const ProofLetMap& map, - std::shared_ptr<theory::eq::EqProof> subTrans, - theory::eq::EqProof::PrettyPrinter* pPrettyPrinter = nullptr); - - /** - * Helper function for ProofUF::toStreamRecLFSC and - * ProofArray::toStreamRecLFSC - * Inputs: - * - evenLengthSequence: true iff the length of the sequence - * of the identical equalities is even. - * - sequenceOver: have we reached the last equality of this sequence? - * - pf: equality engine proof - * - map: A map for the let-expressions in the proof - * - subproofStr: current stringstream content - * - outStream: output stream to which the proof is printed - * - n: transitivity sub-proof - * - nodeAfterEqualitySequence: The node after the identical sequence. - * Returns: - * A pair of nodes, that are the updated nodes n and nodeAfterEqualitySequence - * - */ - std::pair<Node, Node> identicalEqualitiesPrinterHelper( - bool evenLengthSequence, - bool sequenceOver, - const theory::eq::EqProof& pf, - const ProofLetMap& map, - const std::string subproofStr, - std::stringstream* outStream, - Node n, - Node nodeAfterEqualitySequence); - - /** - * Print the proof representation of the given type that belongs to THIS theory. - * - * @param type - * @param os - */ - virtual void printOwnedSort(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, - const ProofLetMap& map); - /** - * Print the sorts declarations for this theory. - * - * @param os - * @param paren - */ - virtual void printSortDeclarations(std::ostream& os, std::ostream& paren) = 0; - /** - * Print the term declarations for this theory. - * - * @param os - * @param paren - */ - virtual void printTermDeclarations(std::ostream& os, std::ostream& paren) = 0; - /** - * Print any deferred variable/sorts declarations for this theory - * (those that need to appear inside the actual proof). - * - * @param os - * @param paren - */ - virtual void printDeferredDeclarations(std::ostream& os, std::ostream& paren) = 0; - /** - * Print any aliasing declarations. - * - * @param os - * @param paren - */ - virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) = 0; - /** - * Register a term of this theory that appears in the proof. - * - * @param term - */ - virtual void registerTerm(Expr term) = 0; - /** - * Print a proof for the disequality of two constants that belong to this theory. - * - * @param term - */ - virtual void printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap); - /** - * Print a proof for the equivalence of n1 and n2. - * - * @param term - */ - virtual void printRewriteProof(std::ostream& os, const Node &n1, const Node &n2); - - /** - * Return whether this node, when serialized as an LFSC proof, has sort `Bool`. - * - * This is virtual because it ultimately, theories control the serialization - * of their proofs, so a theory will need to override this appropriately. - * - * This should only be called on nodes of type `Bool`. - */ - virtual bool printsAsBool(const Node &n) { - // Most nodes print as formulas, so this is the default. - return false; - } -}; - -class BooleanProof : public TheoryProof { -protected: - ExprSet d_declarations; // all the boolean variables - theory::TheoryId getTheoryId() override; - - public: - BooleanProof(TheoryProofEngine* proofEngine); - - void registerTerm(Expr term) override; -}; - -class LFSCBooleanProof : public BooleanProof { -public: - LFSCBooleanProof(TheoryProofEngine* proofEngine) - : BooleanProof(proofEngine) - {} - void printOwnedTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode ty) override; - void printOwnedSort(Type type, std::ostream& os) override; - void printTheoryLemmaProof(std::vector<Expr>& lemma, - std::ostream& os, - std::ostream& paren, - const ProofLetMap& map) override; - void printSortDeclarations(std::ostream& os, std::ostream& paren) override; - void printTermDeclarations(std::ostream& os, std::ostream& paren) override; - void printDeferredDeclarations(std::ostream& os, - std::ostream& paren) override; - void printAliasingDeclarations(std::ostream& os, - std::ostream& paren, - const ProofLetMap& globalLetMap) override; - - bool printsAsBool(const Node& n) override; - void printConstantDisequalityProof(std::ostream& os, - Expr c1, - Expr c2, - const ProofLetMap& globalLetMap) override; -}; - -} /* CVC4 namespace */ - -#endif /* CVC4__THEORY_PROOF_H */ diff --git a/src/proof/uf_proof.cpp b/src/proof/uf_proof.cpp deleted file mode 100644 index 74990ff44..000000000 --- a/src/proof/uf_proof.cpp +++ /dev/null @@ -1,759 +0,0 @@ -/********************* */ -/*! \file uf_proof.cpp - ** \verbatim - ** Top contributors (to current version): - ** Liana Hadarean, Guy Katz, Yoni Zohar - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** [[ Add lengthier description here ]] - - ** \todo document this file - -**/ -#include "proof/uf_proof.h" - -#include <stack> - -#include "proof/proof_manager.h" -#include "proof/simplify_boolean_node.h" -#include "theory/uf/theory_uf.h" - -namespace CVC4 { - -void ProofUF::toStream(std::ostream& out) const -{ - ProofLetMap map; - toStream(out, map); -} - -void ProofUF::toStream(std::ostream& out, const ProofLetMap& map) const -{ - Trace("theory-proof-debug") << "; Print UF proof..." << std::endl; - //AJR : carry this further? - toStreamLFSC(out, ProofManager::getUfProof(), *d_proof, map); -} - -void ProofUF::toStreamLFSC(std::ostream& out, - TheoryProof* tp, - const theory::eq::EqProof& pf, - const ProofLetMap& map) -{ - Debug("pf::uf") << "ProofUF::toStreamLFSC starting" << std::endl; - 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, - const theory::eq::EqProof& pf, - unsigned tb, - const ProofLetMap& map) -{ - Debug("pf::uf") << std::endl - << std::endl - << "toStreamRecLFSC called. tb = " << tb - << " . proof:" << std::endl; - if (tb == 0) - { - // Special case: false was an input, so the proof is just "false". - if (pf.d_id == theory::eq::MERGED_THROUGH_EQUALITY && - pf.d_node == NodeManager::currentNM()->mkConst(false)) { - out << "(clausify_false "; - out << ProofManager::getLitName(NodeManager::currentNM()->mkConst(false).notNode()); - out << ")" << std::endl; - return Node(); - } - - std::shared_ptr<theory::eq::EqProof> subTrans = - std::make_shared<theory::eq::EqProof>(); - - int neg = tp->assertAndPrint(pf, map, subTrans); - - Node n1; - std::stringstream ss, ss2; - Debug("pf::uf") << "\nsubtrans has " << subTrans->d_children.size() << " children\n"; - bool disequalityFound = (neg >= 0); - - if(!disequalityFound || subTrans->d_children.size() >= 2) { - n1 = toStreamRecLFSC(ss, tp, *subTrans, 1, map); - } else { - n1 = toStreamRecLFSC(ss, tp, *(subTrans->d_children[0]), 1, map); - Debug("pf::uf") << "\nsubTrans unique child " - << subTrans->d_children[0]->d_id - << " was proven\ngot: " << n1 << std::endl; - } - - Debug("pf::uf") << "\nhave proven: " << n1 << std::endl; - - out << "(clausify_false (contra _ "; - if (disequalityFound) { - Node n2 = pf.d_children[neg]->d_node; - Assert(n2.getKind() == kind::NOT); - - Debug("pf::uf") << "n2 is " << n2[0] << std::endl; - - if (n2[0].getNumChildren() > 0) - { - Debug("pf::uf") << "\nn2[0]: " << n2[0][0] << std::endl; - } - if (n1.getNumChildren() > 1) { Debug("pf::uf") << "n1[1]: " << n1[1] << std::endl; } - - if(n2[0].getKind() == kind::APPLY_UF) { - out << "(trans _ _ _ _ "; - - if (n1[0] == n2[0]) { - out << "(symm _ _ _ "; - out << ss.str(); - out << ") "; - } else { - Assert(n1[1] == n2[0]); - out << ss.str(); - } - out << "(pred_eq_f _ " << ProofManager::getLitName(n2[0]) << ")) t_t_neq_f))" << std::endl; - } else if (n2[0].getKind() == kind::BOOLEAN_TERM_VARIABLE) { - out << ss.str() << " " << ProofManager::getLitName(n2[0]) << "))"; - } 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; - } - } else { - Node n2 = pf.d_node; - Assert(n2.getKind() == kind::EQUAL); - Assert((n1[0] == n2[0] && n1[1] == n2[1]) - || (n1[1] == n2[0] && n1[0] == n2[1])); - - out << ss.str(); - out << " "; - ProofManager::getTheoryProofEngine()->printConstantDisequalityProof( - out, n1[0].toExpr(), n1[1].toExpr(), map); - out << "))" << std::endl; - } - - return Node(); - } - // TODO (#2965): improve this code, which is highly complicated. - switch(pf.d_id) { - case theory::eq::MERGED_THROUGH_CONGRUENCE: { - Debug("pf::uf") << "\nok, looking at congruence:\n"; - pf.debug_print("pf::uf"); - std::stack<const theory::eq::EqProof*> stk; - for (const theory::eq::EqProof* pf2 = &pf; - pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE; - pf2 = pf2->d_children[0].get()) { - 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 - != theory::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 == theory::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("pf::uf") << "\nok, in FIRST cong[" << stk.size() << "]" << "\n"; - pf2->debug_print("pf::uf"); - Debug("pf::uf") << "looking at " << pf2->d_node << "\n"; - Debug("pf::uf") << " " << n1 << "\n"; - Debug("pf::uf") << " " << n2 << "\n"; - int side = 0; - if (tp->match(pf2->d_node, n1[0])) - { - //if(tb == 1) { - Debug("pf::uf") << "SIDE IS 0\n"; - //} - side = 0; - } else { - //if(tb == 1) { - Debug("pf::uf") << "SIDE IS 1\n"; - //} - if (!tp->match(pf2->d_node, n1[1])) - { - Debug("pf::uf") << "IN BAD CASE, our first subproof is\n"; - pf2->d_children[0]->debug_print("pf::uf"); - } - Assert(tp->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("pf::uf") << "pf2->d_node " << pf2->d_node << std::endl; - Debug("pf::uf") << "b1.getNumChildren() " << b1.getNumChildren() << std::endl; - Debug("pf::uf") << "n1 " << n1 << std::endl; - Debug("pf::uf") << "n2 " << n2 << std::endl; - Debug("pf::uf") << "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("pf::uf") << "\nMORE TO DO\n"; - } - pf2 = stk.top(); - stk.pop(); - Assert(pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE); - out << " "; - ss.str(""); - n2 = toStreamRecLFSC(ss, tp, *(pf2->d_children[1]), tb + 1, map); - Debug("pf::uf") << "\nok, in cong[" << stk.size() << "]" << "\n"; - Debug("pf::uf") << "looking at " << pf2->d_node << "\n"; - Debug("pf::uf") << " " << n1 << "\n"; - Debug("pf::uf") << " " << n2 << "\n"; - Debug("pf::uf") << " " << b1 << "\n"; - Debug("pf::uf") << " " << 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("pf::uf") << "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("pf::uf") << "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 ? n1.eqNode(n2) : n2.eqNode(n1)); - if(tb == 1) { - Debug("pf::uf") << "\ncong proved: " << n << "\n"; - } - return n; - } - - case theory::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 pf.d_node.eqNode(pf.d_node); - } - case theory::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 theory::eq::MERGED_THROUGH_TRANS: { - Assert(!pf.d_node.isNull()); - Assert(pf.d_children.size() >= 2); - std::stringstream ss; - Debug("pf::uf") << "\ndoing trans proof[[\n"; - pf.debug_print("pf::uf"); - Debug("pf::uf") << "\n"; - - pf.d_children[0]->d_node = simplifyBooleanNode(pf.d_children[0]->d_node); - - Node n1 = toStreamRecLFSC(ss, tp, *(pf.d_children[0]), tb + 1, map); - Debug("pf::uf") << "\ndoing trans proof, got n1 " << n1 << "\n"; - if(tb == 1) { - Debug("pf::uf") << "\ntrans proof[0], got n1 " << n1 << "\n"; - } - - bool identicalEqualities = false; - bool evenLengthSequence; - std::stringstream dontCare; - Node nodeAfterEqualitySequence = - toStreamRecLFSC(dontCare, tp, *(pf.d_children[0]), tb + 1, map); - - std::map<size_t, Node> childToStream; - std::pair<Node, Node> nodePair; - for(size_t i = 1; i < pf.d_children.size(); ++i) { - std::stringstream ss1(ss.str()), ss2; - ss.str(""); - - pf.d_children[i]->d_node = simplifyBooleanNode(pf.d_children[i]->d_node); - - // It is possible that we've already converted the i'th child to stream. - // If so, - // use previously stored result. Otherwise, convert and store. - Node n2; - if (childToStream.find(i) != childToStream.end()) - n2 = childToStream[i]; - else - { - n2 = toStreamRecLFSC(ss2, tp, *(pf.d_children[i]), tb + 1, map); - childToStream[i] = n2; - } - - // 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) - { - 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("pf::uf") << "Detected identical equalities: " << std::endl - << "\t" << n1 << std::endl; - - if (!identicalEqualities) - { - // The sequence of identical equalities has started just now - identicalEqualities = true; - - Debug("pf::uf") - << "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 ignore; - nodeAfterEqualitySequence = - toStreamRecLFSC(ignore, 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; - } - - nodePair = - tp->identicalEqualitiesPrinterHelper(evenLengthSequence, - sequenceOver, - pf, - map, - ss1.str(), - &ss, - n1, - nodeAfterEqualitySequence); - n1 = nodePair.first; - nodeAfterEqualitySequence = nodePair.second; - } 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("pf::uf") << "\ndoing trans proof, got n2 " << n2 << "\n"; - if(tb == 1) { - Debug("pf::uf") << "\ntrans proof[" << i << "], got n2 " << n2 << "\n"; - Debug("pf::uf") << (n2.getKind() == kind::EQUAL) << "\n"; - - if ((n1.getNumChildren() >= 2) && (n2.getNumChildren() >= 2)) { - Debug("pf::uf") << n1[0].getId() << " " << n1[1].getId() << " / " << n2[0].getId() << " " << n2[1].getId() << "\n"; - Debug("pf::uf") << n1[0].getId() << " " << n1[0] << "\n"; - Debug("pf::uf") << n1[1].getId() << " " << n1[1] << "\n"; - Debug("pf::uf") << n2[0].getId() << " " << n2[0] << "\n"; - Debug("pf::uf") << n2[1].getId() << " " << n2[1] << "\n"; - Debug("pf::uf") << (n1[0] == n2[0]) << "\n"; - Debug("pf::uf") << (n1[1] == n2[1]) << "\n"; - Debug("pf::uf") << (n1[0] == n2[1]) << "\n"; - Debug("pf::uf") << (n1[1] == n2[0]) << "\n"; - } - } - - ss << "(trans _ _ _ _ "; - - if(n2.getKind() == kind::EQUAL && n1.getKind() == kind::EQUAL) - // Both elements of the transitivity rule are equalities/iffs - { - if(n1[0] == n2[0]) { - if(tb == 1) { Debug("pf::uf") << "case 1\n"; } - n1 = n1[1].eqNode(n2[1]); - ss << "(symm _ _ _ " << ss1.str() << ") " << ss2.str(); - } else if(n1[1] == n2[1]) { - if(tb == 1) { Debug("pf::uf") << "case 2\n"; } - n1 = n1[0].eqNode(n2[0]); - ss << ss1.str() << " (symm _ _ _ " << ss2.str() << ")"; - } else if(n1[0] == n2[1]) { - if(tb == 1) { Debug("pf::uf") << "case 3\n"; } - n1 = n2[0].eqNode(n1[1]); - ss << ss2.str() << " " << ss1.str(); - if(tb == 1) { Debug("pf::uf") << "++ proved " << n1 << "\n"; } - } else if(n1[1] == n2[0]) { - if(tb == 1) { Debug("pf::uf") << "case 4\n"; } - n1 = n1[0].eqNode(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("pf::uf",0); - //toStreamRec(Warning.getStream(), pf, 0); - Warning() << "\n\n"; - Unreachable(); - } - Debug("pf::uf") << "++ trans proof[" << i << "], now have " << n1 << std::endl; - } else if(n1.getKind() == kind::EQUAL) { - // n1 is an equality/iff, but n2 is a predicate - if(n1[0] == n2) { - n1 = n1[1].eqNode(NodeManager::currentNM()->mkConst(true)); - ss << "(symm _ _ _ " << ss1.str() << ") (pred_eq_t _ " << ss2.str() << ")"; - } else if(n1[1] == n2) { - n1 = n1[0].eqNode(NodeManager::currentNM()->mkConst(true)); - ss << ss1.str() << " (pred_eq_t _ " << ss2.str() << ")"; - } else { - Unreachable(); - } - } else if(n2.getKind() == kind::EQUAL) { - // n2 is an equality/iff, but n1 is a predicate - if(n2[0] == n1) { - n1 = n2[1].eqNode(NodeManager::currentNM()->mkConst(true)); - ss << "(symm _ _ _ " << ss2.str() << ") (pred_eq_t _ " << ss1.str() << ")"; - } else if(n2[1] == n1) { - n1 = n2[0].eqNode(NodeManager::currentNM()->mkConst(true)); - ss << ss2.str() << " (pred_eq_t _ " << ss1.str() << ")"; - } else { - Unreachable(); - } - } else { - // Both n1 and n2 are predicates. - // We want to prove b1 = b2, and we know that ((b1), (b2)) or ((not b1), (not b2)) - if (n1.getKind() == kind::NOT) { - Assert(n2.getKind() == kind::NOT); - Assert(pf.d_node[0] == n1[0] || pf.d_node[0] == n2[0]); - Assert(pf.d_node[1] == n1[0] || pf.d_node[1] == n2[0]); - Assert(n1[0].getKind() == kind::BOOLEAN_TERM_VARIABLE); - Assert(n2[0].getKind() == kind::BOOLEAN_TERM_VARIABLE); - - if (pf.d_node[0] == n1[0]) { - ss << "(false_preds_equal _ _ " << ss1.str() << " " << ss2.str() << ") "; - ss << "(pred_refl_neg _ " << ss2.str() << ")"; - } else { - ss << "(false_preds_equal _ _ " << ss2.str() << " " << ss1.str() << ") "; - ss << "(pred_refl_neg _ " << ss1.str() << ")"; - } - n1 = pf.d_node; - - } else if (n1.getKind() == kind::BOOLEAN_TERM_VARIABLE) { - Assert(n2.getKind() == kind::BOOLEAN_TERM_VARIABLE); - Assert(pf.d_node[0] == n1 || pf.d_node[0] == n2); - Assert(pf.d_node[1] == n1 || pf.d_node[2] == n2); - - if (pf.d_node[0] == n1) { - ss << "(true_preds_equal _ _ " << ss1.str() << " " << ss2.str() << ") "; - ss << "(pred_refl_pos _ " << ss2.str() << ")"; - } else { - ss << "(true_preds_equal _ _ " << ss2.str() << " " << ss1.str() << ") "; - ss << "(pred_refl_pos _ " << ss1.str() << ")"; - } - n1 = pf.d_node; - - } else { - - Unreachable(); - } - } - - ss << ")"; - } - out << ss.str(); - Debug("pf::uf") << "\n++ trans proof done, have proven " << n1 << std::endl; - return n1; - } - - default: - Assert(!pf.d_node.isNull()); - Assert(pf.d_children.empty()); - Debug("pf::uf") << "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) -{} - -theory::TheoryId UFProof::getTheoryId() { return theory::THEORY_UF; } -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); - - - if (term.getKind() == kind::BOOLEAN_TERM_VARIABLE) { - // Ensure cnf literals - Node asNode(term); - ProofManager::currentPM()->ensureLiteral( - asNode.eqNode(NodeManager::currentNM()->mkConst(true))); - ProofManager::currentPM()->ensureLiteral( - asNode.eqNode(NodeManager::currentNM()->mkConst(false))); - } - } - - // 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::printOwnedTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) -{ - Node node = Node::fromExpr(term); - Debug("pf::uf") << std::endl << "(pf::uf) LFSCUfProof::printOwnedTerm: term = " << node << std::endl; - - Assert(theory::Theory::theoryOf(node) == theory::THEORY_UF); - - if (node.getKind() == kind::VARIABLE || - node.getKind() == kind::SKOLEM || - node.getKind() == kind::BOOLEAN_TERM_VARIABLE) { - os << node; - return; - } - - Assert(node.getKind() == kind::APPLY_UF); - - if(node.getType().isBoolean()) { - os << "(p_app "; - } - Node func = node.getOperator(); - for (unsigned i = 0; i < term.getNumChildren(); ++i) { - os << "(apply _ _ "; - } - os << func << " "; - Assert(func.getType().isFunction()); - std::vector<TypeNode> argsTypes = node.getOperator().getType().getArgTypes(); - for (unsigned i = 0; i < node.getNumChildren(); ++i) { - - bool convertToBool = (node[i].getType().isBoolean() && !d_proofEngine->printsAsBool(node[i])); - if (convertToBool) os << "(f_to_b "; - d_proofEngine->printBoundTerm(term[i], os, map, argsTypes[i]); - if (convertToBool) os << ")"; - os << ")"; - } - if(term.getType().isBoolean()) { - os << ")"; - } -} - -void LFSCUFProof::printOwnedSort(Type type, std::ostream& os) { - Debug("pf::uf") << std::endl << "(pf::uf) LFSCArrayProof::printOwnedSort: type is: " << type << std::endl; - - Assert(type.isSort()); - os << type; -} - -void LFSCUFProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map) { - 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, map); -} - -void LFSCUFProof::printSortDeclarations(std::ostream& os, std::ostream& paren) { - for (TypeSet::const_iterator it = d_sorts.begin(); it != d_sorts.end(); ++it) { - if (!ProofManager::currentPM()->wasPrinted(*it)) { - os << "(% " << *it << " sort\n"; - paren << ")"; - ProofManager::currentPM()->markPrinted(*it); - } - } -} - -void LFSCUFProof::printTermDeclarations(std::ostream& os, std::ostream& paren) { - // declaring the terms - Debug("pf::uf") << "LFSCUFProof::printTermDeclarations called" << std::endl; - - 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 << " "; - d_proofEngine->printSort(arg_type, os); - if (i < args.size() - 2) { - os << " (arrow"; - fparen << ")"; - } - } - os << fparen.str() << "))\n"; - } else { - Assert(term.isVariable()); - os << type << ")\n"; - } - paren << ")"; - } - - Debug("pf::uf") << "LFSCUFProof::printTermDeclarations done" << std::endl; -} - -void LFSCUFProof::printDeferredDeclarations(std::ostream& os, std::ostream& paren) { - // Nothing to do here at this point. -} - -void LFSCUFProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) { - // Nothing to do here at this point. -} - -bool LFSCUFProof::printsAsBool(const Node &n) { - if (n.getKind() == kind::BOOLEAN_TERM_VARIABLE) - return true; - - return false; -} - -void LFSCUFProof::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap) { - Node falseNode = NodeManager::currentNM()->mkConst(false); - Node trueNode = NodeManager::currentNM()->mkConst(true); - - Assert(c1 == falseNode.toExpr() || c1 == trueNode.toExpr()); - Assert(c2 == falseNode.toExpr() || c2 == trueNode.toExpr()); - Assert(c1 != c2); - - if (c1 == trueNode.toExpr()) - os << "t_t_neq_f"; - else - os << "(symm _ _ _ t_t_neq_f)"; -} - -} /* namespace CVC4 */ diff --git a/src/proof/uf_proof.h b/src/proof/uf_proof.h deleted file mode 100644 index 647359a87..000000000 --- a/src/proof/uf_proof.h +++ /dev/null @@ -1,106 +0,0 @@ -/********************* */ -/*! \file uf_proof.h - ** \verbatim - ** Top contributors (to current version): - ** Mathias Preiner, Liana Hadarean, Tim King - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. 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 <memory> -#include <unordered_set> - -#include "expr/expr.h" -#include "proof/theory_proof.h" -#include "theory/uf/equality_engine.h" -#include "util/proof.h" - -namespace CVC4 { - -// proof object outputted by TheoryUF -class ProofUF : public Proof -{ - public: - ProofUF(std::shared_ptr<theory::eq::EqProof> pf) : d_proof(pf) {} - void toStream(std::ostream& out) const override; - void toStream(std::ostream& out, const ProofLetMap& map) const override; - - private: - static void toStreamLFSC(std::ostream& out, TheoryProof* tp, - const theory::eq::EqProof& pf, - const ProofLetMap& map); - static Node toStreamRecLFSC(std::ostream& out, TheoryProof* tp, - const theory::eq::EqProof& pf, unsigned tb, - const ProofLetMap& map); - - // it is simply an equality engine proof - std::shared_ptr<theory::eq::EqProof> d_proof; -}; - -namespace theory { -namespace uf { -class TheoryUF; -} -} - -typedef std::unordered_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 - theory::TheoryId getTheoryId() override; - - public: - UFProof(theory::uf::TheoryUF* uf, TheoryProofEngine* proofEngine); - - void registerTerm(Expr term) override; -}; - -class LFSCUFProof : public UFProof { -public: - LFSCUFProof(theory::uf::TheoryUF* uf, TheoryProofEngine* proofEngine) - : UFProof(uf, proofEngine) - {} - void printOwnedTermAsType(Expr term, - std::ostream& os, - const ProofLetMap& map, - TypeNode expectedType) override; - void printOwnedSort(Type type, std::ostream& os) override; - void printTheoryLemmaProof(std::vector<Expr>& lemma, - std::ostream& os, - std::ostream& paren, - const ProofLetMap& map) override; - void printSortDeclarations(std::ostream& os, std::ostream& paren) override; - void printTermDeclarations(std::ostream& os, std::ostream& paren) override; - void printDeferredDeclarations(std::ostream& os, - std::ostream& paren) override; - void printAliasingDeclarations(std::ostream& os, - std::ostream& paren, - const ProofLetMap& globalLetMap) override; - - bool printsAsBool(const Node& n) override; - - void printConstantDisequalityProof(std::ostream& os, - Expr c1, - Expr c2, - const ProofLetMap& globalLetMap) override; -}; - - -}/* CVC4 namespace */ - -#endif /* CVC4__UF__PROOF_H */ diff --git a/src/prop/bvminisat/bvminisat.cpp b/src/prop/bvminisat/bvminisat.cpp index c1aac33be..0b531c498 100644 --- a/src/prop/bvminisat/bvminisat.cpp +++ b/src/prop/bvminisat/bvminisat.cpp @@ -18,7 +18,6 @@ #include "prop/bvminisat/simp/SimpSolver.h" #include "proof/clause_id.h" -#include "proof/sat_proof.h" #include "util/statistics_registry.h" namespace CVC4 { @@ -66,7 +65,6 @@ ClauseId BVMinisatSatSolver::addClause(SatClause& clause, // } ClauseId clause_id = ClauseIdError; d_minisat->addClause(minisat_clause, clause_id); - THEORY_PROOF(Assert(clause_id != ClauseIdError);); return clause_id; } @@ -76,14 +74,14 @@ SatValue BVMinisatSatSolver::propagate() { void BVMinisatSatSolver::addMarkerLiteral(SatLiteral lit) { d_minisat->addMarkerLiteral(BVMinisat::var(toMinisatLit(lit))); - markUnremovable(lit); + markUnremovable(lit); } void BVMinisatSatSolver::explain(SatLiteral lit, std::vector<SatLiteral>& explanation) { std::vector<BVMinisat::Lit> minisat_explanation; d_minisat->explain(toMinisatLit(lit), minisat_explanation); for (unsigned i = 0; i < minisat_explanation.size(); ++i) { - explanation.push_back(toSatLiteral(minisat_explanation[i])); + explanation.push_back(toSatLiteral(minisat_explanation[i])); } } @@ -104,12 +102,6 @@ void BVMinisatSatSolver::popAssumption() { d_minisat->popAssumption(); } -void BVMinisatSatSolver::setResolutionProofLog( - proof::ResolutionBitVectorProof* bvp) -{ - d_minisat->setProofLog( bvp ); -} - SatVariable BVMinisatSatSolver::newVar(bool isTheoryAtom, bool preRegister, bool canErase){ return d_minisat->newVar(true, true, !canErase); } @@ -148,9 +140,7 @@ SatValue BVMinisatSatSolver::solve(long unsigned int& resource){ return result; } -bool BVMinisatSatSolver::ok() const { - return d_minisat->okay(); -} +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 @@ -160,11 +150,11 @@ void BVMinisatSatSolver::getUnsatCore(SatClause& unsatCore) { } SatValue BVMinisatSatSolver::value(SatLiteral l){ - return toSatLiteralValue(d_minisat->value(toMinisatLit(l))); + return toSatLiteralValue(d_minisat->value(toMinisatLit(l))); } SatValue BVMinisatSatSolver::modelValue(SatLiteral l){ - return toSatLiteralValue(d_minisat->modelValue(toMinisatLit(l))); + return toSatLiteralValue(d_minisat->modelValue(toMinisatLit(l))); } void BVMinisatSatSolver::unregisterVar(SatLiteral lit) { @@ -309,17 +299,3 @@ 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 01a0a518e..f93dc8048 100644 --- a/src/prop/bvminisat/bvminisat.h +++ b/src/prop/bvminisat/bvminisat.h @@ -21,8 +21,6 @@ #include <memory> #include "context/cdo.h" -#include "proof/clause_id.h" -#include "proof/resolution_bitvector_proof.h" #include "prop/bv_sat_solver_notify.h" #include "prop/bvminisat/simp/SimpSolver.h" #include "prop/sat_solver.h" @@ -57,8 +55,8 @@ class BVMinisatSatSolver : public BVSatSolverInterface, } }; - std::unique_ptr<BVMinisat::SimpSolver> d_minisat; - std::unique_ptr<MinisatNotify> d_minisatNotify; + std::unique_ptr<BVMinisat::SimpSolver> d_minisat; + std::unique_ptr<MinisatNotify> d_minisatNotify; unsigned d_assertionsCount; context::CDO<unsigned> d_assertionsRealCount; @@ -79,6 +77,7 @@ public: ClauseId addXorClause(SatClause& clause, bool rhs, bool removable) override { Unreachable() << "Minisat does not support native XOR reasoning"; + return ClauseIdError; } SatValue propagate() override; @@ -123,8 +122,6 @@ public: void popAssumption() override; - void setResolutionProofLog(proof::ResolutionBitVectorProof* bvp) override; - private: /* Disable the default constructor. */ BVMinisatSatSolver() = delete; diff --git a/src/prop/bvminisat/core/Solver.cc b/src/prop/bvminisat/core/Solver.cc index 84ab62fd8..f7ba14acd 100644 --- a/src/prop/bvminisat/core/Solver.cc +++ b/src/prop/bvminisat/core/Solver.cc @@ -29,11 +29,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include "base/output.h" #include "options/bv_options.h" #include "options/smt_options.h" -#include "proof/clause_id.h" -#include "proof/proof_manager.h" -#include "proof/resolution_bitvector_proof.h" -#include "proof/sat_proof.h" -#include "proof/sat_proof_implementation.h" #include "prop/bvminisat/mtl/Sort.h" #include "theory/interrupted.h" #include "util/utility.h" @@ -170,8 +165,7 @@ Solver::Solver(CVC4::context::Context* context) , conflict_budget(-1), propagation_budget(-1), - asynch_interrupt(false), - d_bvp(NULL) + asynch_interrupt(false) { // Create the constant variables varTrue = newVar(true, false); @@ -220,7 +214,7 @@ bool Solver::addClause_(vec<Lit>& ps, ClauseId& id) if (decisionLevel() > 0) { cancelUntil(0); } - + if (!ok) { id = ClauseIdUndef; return false; @@ -231,7 +225,7 @@ bool Solver::addClause_(vec<Lit>& ps, ClauseId& id) sort(ps); Lit p; int i, j; 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) { @@ -245,82 +239,30 @@ bool Solver::addClause_(vec<Lit>& ps, ClauseId& id) } if (value(ps[i]) == l_False) { - if (!THEORY_PROOF_ON()) - continue; - ++falseLiteralsCount; + continue; } ps[j++] = p = ps[i]; } - + ps.shrink(i - j); clause_added = true; - 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){ - if(d_bvp){ id = d_bvp->getSatProof()->registerUnitClause(ps[0], INPUT);} uncheckedEnqueue(ps[0]); 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; - } - - 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; } return ok; } @@ -338,9 +280,6 @@ void Solver::attachClause(CRef cr) { void Solver::detachClause(CRef cr, bool strict) { const Clause& clause = ca[cr]; - if (d_bvp) - { - d_bvp->getSatProof()->markDeleted(cr); } assert(clause.size() > 1); @@ -425,23 +364,24 @@ Lit Solver::pickBranchLit() return next == var_Undef ? lit_Undef : mkLit(next, rnd_pol ? drand(random_seed) < 0.5 : polarity[next]); } - /*_________________________________________________________________________________________________ | -| analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel : int&) -> [void] -| +| analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel : int&) -> +[void] +| | Description: | Analyze conflict and produce a reason clause. -| +| | Pre-conditions: | * 'out_learnt' is assumed to be cleared. | * Current decision level must be greater than root level. -| +| | Post-conditions: | * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'. -| * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision level of the -| rest of literals. There may be others from the same level though. -| +| * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision +level of the | rest of literals. There may be others from the same level +though. +| |________________________________________________________________________________________________@*/ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip) { @@ -454,8 +394,6 @@ 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) @@ -477,13 +415,6 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip out_learnt.push(q); } - if (level(var(q)) == 0) - { - if (d_bvp) - { - d_bvp->getSatProof()->resolveOutUnit(q); - } - } } // Select next clause to look at: @@ -493,10 +424,6 @@ 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; @@ -536,13 +463,6 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip // Literal is not redundant out_learnt[j++] = out_learnt[i1]; } - else - { - if (d_bvp) - { - d_bvp->getSatProof()->storeLitRedundant(out_learnt[i1]); - } - } } } }else if (ccmin_mode == 1){ @@ -640,10 +560,10 @@ bool Solver::litRedundant(Lit p, uint32_t abstract_levels) return true; } -/** +/** * Specialized analyzeFinal procedure where we test the consistency * of the assumptions before backtracking bellow the assumption level. - * + * * @param p the original uip (may be unit) * @param confl_clause the conflict clause * @param out_conflict the conflict in terms of assumptions we are building @@ -653,14 +573,14 @@ void Solver::analyzeFinal2(Lit p, CRef confl_clause, vec<Lit>& out_conflict) { assert (decisionLevel() == assumptions.size()); assert (level(var(p)) == assumptions.size()); - out_conflict.clear(); - + out_conflict.clear(); + Clause& cl = ca[confl_clause]; for (int i = 0; i < cl.size(); ++i) { seen[var(cl[i])] = 1; } - int end = options::proof() ? 0 : trail_lim[0]; + int end = trail_lim[0]; for (int i = trail.size() - 1; i >= end; i--) { Var x = var(trail[i]); if (seen[x]) { @@ -670,44 +590,31 @@ void Solver::analyzeFinal2(Lit p, CRef confl_clause, vec<Lit>& out_conflict) { 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& clause = ca[reason(x)]; - if(d_bvp){d_bvp->getSatProof()->addResolutionStep(trail[i],reason(x), sign(trail[i]));} for (int j = 1; j < clause.size(); j++) { if (level(var(clause[j])) > 0) seen[var(clause[j])] = 1; - if(d_bvp){ - if (level(var(clause[j])) == 0) - { - d_bvp->getSatProof()->resolveOutUnit(clause[j]); - seen[var(clause[j])] = - 0; // we don't need to resolve it out again - } - } } } seen[x] = 0; } - assert (seen[x] == 0); + assert(seen[x] == 0); } - assert (out_conflict.size()); + assert(out_conflict.size()); } /*_________________________________________________________________________________________________ | | analyzeFinal : (p : Lit) -> [void] -| +| | Description: -| Specialized analysis procedure to express the final conflict in terms of assumptions. -| Calculates the (possibly empty) set of assumptions that led to the assignment of 'p', and -| stores the result in 'out_conflict'. +| Specialized analysis procedure to express the final conflict in terms of +assumptions. | Calculates the (possibly empty) set of assumptions that led to +the assignment of 'p', and | stores the result in 'out_conflict'. |________________________________________________________________________________________________@*/ void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict) { @@ -716,22 +623,14 @@ void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict) out_conflict.push(p); } - 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()) { + if (decisionLevel() == 0) + { return; } seen[var(p)] = 1; - int end = options::proof() ? 0 : trail_lim[0]; - + int end = trail_lim[0]; + for (int i = trail.size()-1; i >= end; i--){ Var x = var(trail[i]); if (seen[x]) { @@ -744,26 +643,12 @@ void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict) } } else { Clause& clause = ca[reason(x)]; - 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 < clause.size(); j++) { if (level(var(clause[j])) > 0) { seen[var(clause[j])] = 1; } - if(d_bvp){ - if (level(var(clause[j])) == 0) - { - d_bvp->getSatProof()->resolveOutUnit(clause[j]); - } - } } } seen[x] = 0; @@ -805,10 +690,9 @@ 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()); } @@ -829,9 +713,9 @@ lbool Solver::assertAssumption(Lit p, bool propagate) { // run the propagation if (propagate) { only_bcp = true; - ccmin_mode = 0; + ccmin_mode = 0; lbool result = search(-1); - return result; + return result; } else { return l_True; } @@ -841,18 +725,16 @@ 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*] -| +| | Description: -| Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned, -| otherwise CRef_Undef. -| +| Propagates all enqueued facts. If a conflict arises, the conflicting clause +is returned, | otherwise CRef_Undef. +| | Post-conditions: | * the propagation queue is empty, even if there was a conflict. |________________________________________________________________________________________________@*/ @@ -920,20 +802,24 @@ CRef Solver::propagate() return confl; } - /*_________________________________________________________________________________________________ | | reduceDB : () -> [void] -| +| | Description: -| Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked -| clauses are clauses that are reason to some assignment. Binary clauses are never removed. +| Remove half of the learnt clauses, minus the clauses locked by the current +assignment. Locked | clauses are clauses that are reason to some assignment. +Binary clauses are never removed. |________________________________________________________________________________________________@*/ -struct reduceDB_lt { - ClauseAllocator& ca; - reduceDB_lt(ClauseAllocator& ca_) : ca(ca_) {} - bool operator () (CRef x, CRef y) { - return ca[x].size() > 2 && (ca[y].size() == 2 || ca[x].activity() < ca[y].activity()); } +struct reduceDB_lt +{ + ClauseAllocator& ca; + reduceDB_lt(ClauseAllocator& ca_) : ca(ca_) {} + bool operator()(CRef x, CRef y) + { + return ca[x].size() > 2 + && (ca[y].size() == 2 || ca[x].activity() < ca[y].activity()); + } }; void Solver::reduceDB() { @@ -963,14 +849,6 @@ void Solver::removeSatisfied(vec<CRef>& cs) Clause& clause = ca[cs[i]]; if (satisfied(clause)) { - if (locked(clause)) - { - // store a resolution of the literal clause propagated - if (d_bvp) - { - d_bvp->getSatProof()->storeUnitResolution(clause[0]); - } - } removeClause(cs[i]); } else @@ -989,14 +867,14 @@ void Solver::rebuildOrderHeap() order_heap.build(vs); } - /*_________________________________________________________________________________________________ | | simplify : [void] -> [bool] -| +| | Description: -| Simplify the clause database according to the current top-level assigment. Currently, the only -| thing done here is the removal of satisfied clauses, but more things can be put here. +| Simplify the clause database according to the current top-level assigment. +Currently, the only | thing done here is the removal of satisfied clauses, +but more things can be put here. |________________________________________________________________________________________________@*/ bool Solver::simplify() { @@ -1021,19 +899,19 @@ bool Solver::simplify() return true; } - /*_________________________________________________________________________________________________ | | search : (nof_conflicts : int) (params : const SearchParams&) -> [lbool] -| +| | Description: -| Search for a model the specified number of conflicts. +| Search for a model the specified number of conflicts. | NOTE! Use negative value for 'nof_conflicts' indicate infinity. -| +| | Output: -| 'l_True' if a partial assigment that is consistent with respect to the clauseset is found. If -| all variables are decision variables, this means that the clause set is satisfiable. 'l_False' -| if the clause set is unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached. +| 'l_True' if a partial assigment that is consistent with respect to the +clauseset is found. If | all variables are decision variables, this means +that the clause set is satisfiable. 'l_False' | if the clause set is +unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached. |________________________________________________________________________________________________@*/ lbool Solver::search(int nof_conflicts, UIP uip) { @@ -1051,7 +929,6 @@ lbool Solver::search(int nof_conflicts, UIP uip) if (decisionLevel() == 0) { // can this happen for bv? - if(d_bvp){ d_bvp->getSatProof()->finalizeProof(confl);} return l_False; } @@ -1067,59 +944,34 @@ 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( - std::unordered_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()); + 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; } if (!CVC4::options::bvEagerExplanations()) { - // check if uip leads to a conflict + // check if uip leads to a conflict if (backtrack_level < assumptions.size()) { cancelUntil(assumptions.size()); uncheckedEnqueue(p, cr); - + CRef new_confl = propagate(); if (new_confl != CRef_Undef) { // we have a conflict we now need to explain it - // 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; } } @@ -1127,8 +979,7 @@ lbool Solver::search(int nof_conflicts, UIP uip) cancelUntil(backtrack_level); uncheckedEnqueue(p, cr); - - + varDecayActivity(); claDecayActivity(); @@ -1138,10 +989,17 @@ lbool Solver::search(int nof_conflicts, UIP uip) max_learnts *= learntsize_inc; if (verbosity >= 1) - printf("| %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n", - (int)conflicts, - (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]), nClauses(), (int)clauses_literals, - (int)max_learnts, nLearnts(), (double)learnts_literals/nLearnts(), progressEstimate()*100); + printf("| %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n", + (int)conflicts, + (int)dec_vars + - (trail_lim.size() == 0 ? trail.size() + : trail_lim[0]), + nClauses(), + (int)clauses_literals, + (int)max_learnts, + nLearnts(), + (double)learnts_literals / nLearnts(), + progressEstimate() * 100); } }else{ @@ -1152,9 +1010,9 @@ lbool Solver::search(int nof_conflicts, UIP uip) withinBudget(ResourceManager::Resource::BvSatConflictsStep); } catch (const CVC4::theory::Interrupted& e) { - // do some clean-up and rethrow - cancelUntil(assumptions.size()); - throw e; + // do some clean-up and rethrow + cancelUntil(assumptions.size()); + throw e; } if ((decisionLevel() > assumptions.size() && nof_conflicts >= 0 @@ -1192,10 +1050,8 @@ 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{ @@ -1283,7 +1139,7 @@ lbool Solver::solve_() conflict.clear(); ccmin_mode = 0; - + if (!ok) return l_False; solves++; @@ -1324,31 +1180,20 @@ lbool Solver::solve_() //================================================================================================= // Bitvector propagations -// +// void Solver::explain(Lit p, std::vector<Lit>& explanation) { Debug("bvminisat::explain") << OUTPUT_TAG << "starting explain of " << p << std::endl; // 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; + return; } - + seen[var(p)] = 1; // if we are called at decisionLevel = 0 trail_lim is empty - int bottom = options::proof() ? 0 : trail_lim[0]; + int bottom = trail_lim[0]; for (int i = trail.size()-1; i >= bottom; i--){ Var x = var(trail[i]); if (seen[x]) { @@ -1358,21 +1203,12 @@ void Solver::explain(Lit p, std::vector<Lit>& explanation) { explanation.push_back(trail[i]); } else { Assert(level(x) == 0); - if(d_bvp){ d_bvp->getSatProof()->resolveOutUnit(~(trail[i])); } } - } else { Clause& clause = 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 < clause.size(); j++) { - if (level(var(clause[j])) > 0 || options::proof()) + if (level(var(clause[j])) > 0) { seen[var(clause[j])] = 1; } @@ -1382,28 +1218,11 @@ void Solver::explain(Lit p, std::vector<Lit>& explanation) { } } 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(proof::ResolutionBitVectorProof* 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: -// +// // FIXME: this needs to be rewritten completely. static Var mapVar(Var x, vec<Var>& map, Var& max) @@ -1454,7 +1273,7 @@ void Solver::toDimacs(FILE* f, const vec<Lit>& assumps) for (int i = 0; i < clauses.size(); i++) if (!satisfied(ca[clauses[i]])) cnt++; - + for (int i = 0; i < clauses.size(); i++) if (!satisfied(ca[clauses[i]])){ Clause& clause = ca[clauses[i]]; @@ -1494,8 +1313,7 @@ void Solver::relocAll(ClauseAllocator& to) Lit p = mkLit(v, s); // 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, d_bvp ? d_bvp->getSatProof() : NULL); + for (int j = 0; j < ws.size(); j++) ca.reloc(ws[j].cref, to); } // All reasons: @@ -1504,20 +1322,16 @@ 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, d_bvp ? d_bvp->getSatProof() : NULL); + ca.reloc(vardata[v].reason, to); } // All learnt: // - for (int i = 0; i < learnts.size(); i++) - ca.reloc(learnts[i], to, d_bvp ? d_bvp->getSatProof() : NULL); + for (int i = 0; i < learnts.size(); i++) ca.reloc(learnts[i], to); // All original: // - for (int i = 0; i < clauses.size(); i++) - ca.reloc(clauses[i], to, d_bvp ? d_bvp->getSatProof() : NULL); - - if(d_bvp){ d_bvp->getSatProof()->finishUpdateCRef(); } + for (int i = 0; i < clauses.size(); i++) ca.reloc(clauses[i], to); } @@ -1525,33 +1339,28 @@ void Solver::garbageCollect() { // Initialize the next region to a size corresponding to the estimated utilization degree. This // is not precise but should avoid some unnecessary reallocations for the new region: - ClauseAllocator to(ca.size() - ca.wasted()); - Debug("bvminisat") << " BVMinisat::Garbage collection \n"; + ClauseAllocator to(ca.size() - ca.wasted()); + Debug("bvminisat") << " BVMinisat::Garbage collection \n"; relocAll(to); if (verbosity >= 2) - printf("| Garbage collection: %12d bytes => %12d bytes |\n", - ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size); + printf( + "| Garbage collection: %12d bytes => %12d bytes |\n", + ca.size() * ClauseAllocator::Unit_Size, + to.size() * ClauseAllocator::Unit_Size); to.moveTo(ca); } -void ClauseAllocator::reloc(CRef& cr, - ClauseAllocator& to, - CVC4::TSatProof<Solver>* proof) +void ClauseAllocator::reloc(CRef& cr, ClauseAllocator& to) { - 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 (proof) - { - proof->updateCRef(old, cr); - } - - // Copy extra data-fields: - // (This could be cleaned-up. Generalize Clause-constructor to be applicable here instead?) + + // 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(); diff --git a/src/prop/bvminisat/core/Solver.h b/src/prop/bvminisat/core/Solver.h index 7fad72d6d..f2721c88d 100644 --- a/src/prop/bvminisat/core/Solver.h +++ b/src/prop/bvminisat/core/Solver.h @@ -25,7 +25,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include "context/context.h" #include "proof/clause_id.h" -#include "proof/sat_proof.h" #include "prop/bvminisat/core/SolverTypes.h" #include "prop/bvminisat/mtl/Alg.h" #include "prop/bvminisat/mtl/Heap.h" @@ -39,11 +38,6 @@ namespace BVMinisat { class Solver; } -// TODO (aozdemir) replace this forward declaration with an include -namespace proof { -class ResolutionBitVectorProof; -} - namespace BVMinisat { /** Interface for minisat callbacks */ @@ -71,11 +65,10 @@ 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 Clause TClause; typedef CRef TCRef; typedef vec<Lit> TLitVec; @@ -109,12 +102,17 @@ public: Var trueVar() const { return varTrue; } Var falseVar() const { return varFalse; } - - bool addClause (const vec<Lit>& ps, ClauseId& id); // 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, 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(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'. @@ -141,9 +139,9 @@ public: void toDimacs (const char* file, Lit p); void toDimacs (const char* file, Lit p, Lit q); void toDimacs (const char* file, Lit p, Lit q, Lit r); - + // Variable mode: - // + // void setPolarity (Var v, bool b); // Declare which polarity the decision heuristic should use for a variable. Requires mode 'polarity_user'. void setDecisionVar (Var v, bool b); // Declare if a variable should be eligible for selection in the decision heuristic. @@ -211,13 +209,12 @@ public: void addMarkerLiteral(Var var); - bool need_to_propagate; // true if we added new clauses, set to true in propagation + 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::proof::ResolutionBitVectorProof* bvp); - protected: // has a clause been added @@ -293,9 +290,6 @@ public: int64_t conflict_budget; // -1 means no budget. int64_t propagation_budget; // -1 means no budget. bool asynch_interrupt; - - //proof log - CVC4::proof::ResolutionBitVectorProof* d_bvp; // Main internal methods: // @@ -458,13 +452,15 @@ inline int Solver::nLearnts () const { return learnts.size(); } inline int Solver::nVars () const { return vardata.size(); } inline int Solver::nFreeVars () const { return (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]); } inline void Solver::setPolarity (Var v, bool b) { polarity[v] = b; } -inline void Solver::setDecisionVar(Var v, bool b) -{ - if ( b && !decision[v]) dec_vars++; - else if (!b && decision[v]) dec_vars--; +inline void Solver::setDecisionVar(Var v, bool b) +{ + if (b && !decision[v]) + dec_vars++; + else if (!b && decision[v]) + dec_vars--; - decision[v] = b; - insertVarOrder(v); + decision[v] = b; + insertVarOrder(v); } inline void Solver::setConfBudget(int64_t x){ conflict_budget = conflicts + x; } inline void Solver::setPropBudget(int64_t x){ propagation_budget = propagations + x; } diff --git a/src/prop/bvminisat/core/SolverTypes.h b/src/prop/bvminisat/core/SolverTypes.h index 302db104f..cf9ce7e15 100644 --- a/src/prop/bvminisat/core/SolverTypes.h +++ b/src/prop/bvminisat/core/SolverTypes.h @@ -86,15 +86,14 @@ struct LitHashFunction { const Lit lit_Undef = { -2 }; // }- Useful special constants. const Lit lit_Error = { -1 }; // } - //================================================================================================= // Lifted booleans: // -// NOTE: this implementation is optimized for the case when comparisons between values are mostly -// between one variable and one constant. Some care had to be taken to make sure that gcc -// does enough constant propagation to produce sensible code, and this appears to be somewhat -// fragile unfortunately. - +// NOTE: this implementation is optimized for the case when comparisons between +// values are mostly +// between one variable and one constant. Some care had to be taken to +// make sure that gcc does enough constant propagation to produce sensible +// code, and this appears to be somewhat fragile unfortunately. #ifndef l_True #define l_True (lbool((uint8_t)0)) // gcc does not do constant propagation if these are real constants. @@ -121,10 +120,12 @@ public: bool operator != (lbool b) const { return !(*this == b); } lbool operator ^ (bool b) const { return lbool((uint8_t)(value^(uint8_t)b)); } - lbool operator && (lbool b) const { - uint8_t sel = (this->value << 1) | (b.value << 3); - uint8_t v = (0xF7F755F4 >> sel) & 3; - return lbool(v); } + lbool operator&&(lbool b) const + { + uint8_t sel = (this->value << 1) | (b.value << 3); + uint8_t v = (0xF7F755F4 >> sel) & 3; + return lbool(v); + } lbool operator || (lbool b) const { uint8_t sel = (this->value << 1) | (b.value << 3); @@ -163,14 +164,14 @@ class Clause { header.reloced = 0; header.size = ps.size(); - for (int i = 0; i < ps.size(); i++) - data[i].lit = ps[i]; + for (int i = 0; i < ps.size(); i++) data[i].lit = ps[i]; if (header.has_extra){ if (header.learnt) - data[header.size].act = 0; - else - calcAbstraction(); } + data[header.size].act = 0; + else + calcAbstraction(); + } } public: @@ -256,9 +257,7 @@ class ClauseAllocator : public RegionAllocator<uint32_t> RegionAllocator<uint32_t>::free(clauseWord32Size(c.size(), c.has_extra())); } - void reloc(CRef& cr, - ClauseAllocator& to, - CVC4::TSatProof<Solver>* proof = NULL); + void reloc(CRef& cr, ClauseAllocator& to); }; @@ -275,7 +274,7 @@ class OccLists public: OccLists(const Deleted& d) : deleted(d) {} - + void init (const Idx& idx){ occs.growTo(toInt(idx)+1); dirty.growTo(toInt(idx)+1, 0); } // Vec& operator[](const Idx& idx){ return occs[toInt(idx)]; } Vec& operator[](const Idx& idx){ return occs[toInt(idx)]; } @@ -334,13 +333,12 @@ class CMap typedef Map<CRef, T, CRefHash> HashTable; HashTable map; - + public: // Size-operations: void clear () { map.clear(); } int size () const { return map.elems(); } - // Insert/Remove/Test mapping: void insert (CRef cr, const T& t){ map.insert(cr, t); } void growTo (CRef cr, const T& t){ map.insert(cr, t); } // NOTE: for compatibility @@ -363,15 +361,14 @@ class CMap printf(" --- size = %d, bucket_count = %d\n", size(), map.bucket_count()); } }; - /*_________________________________________________________________________________________________ | | subsumes : (other : const Clause&) -> Lit -| +| | Description: -| Checks if clause subsumes 'other', and at the same time, if it can be used to simplify 'other' -| by subsumption resolution. -| +| Checks if clause subsumes 'other', and at the same time, if it can be +used to simplify 'other' | by subsumption resolution. +| | Result: | lit_Error - No subsumption or simplification | lit_Undef - Clause subsumes 'other' diff --git a/src/prop/bvminisat/simp/SimpSolver.cc b/src/prop/bvminisat/simp/SimpSolver.cc index 6641310cc..9429e4ced 100644 --- a/src/prop/bvminisat/simp/SimpSolver.cc +++ b/src/prop/bvminisat/simp/SimpSolver.cc @@ -23,7 +23,6 @@ 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 "proof/clause_id.h" -#include "proof/proof.h" #include "prop/bvminisat/mtl/Sort.h" #include "prop/bvminisat/utils/System.h" @@ -64,7 +63,7 @@ SimpSolver::SimpSolver(CVC4::context::Context* context) asymm_lits(0), eliminated_vars(0), elimorder(1), - use_simplification(!PROOF_ON()), + use_simplification(true), occurs(ClauseDeleted(ca)), elim_heap(ElimLt(n_occ)), bwdsub_assigns(0), @@ -94,7 +93,7 @@ SimpSolver::SimpSolver(CVC4::context::Context* context) SimpSolver::~SimpSolver() { - // CVC4::StatisticsRegistry::unregisterStat(&total_eliminate_time); + // CVC4::StatisticsRegistry::unregisterStat(&total_eliminate_time); } @@ -111,7 +110,7 @@ Var SimpSolver::newVar(bool sign, bool dvar, bool freeze) { touched .push(0); elim_heap .insert(v); if (freeze) { - setFrozen(v, true); + setFrozen(v, true); } } return v; @@ -122,7 +121,7 @@ Var SimpSolver::newVar(bool sign, bool dvar, bool freeze) { lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp) { only_bcp = false; - + vec<Var> extra_frozen; lbool result = l_True; @@ -210,14 +209,15 @@ void SimpSolver::removeClause(CRef cr) const Clause& clause = ca[cr]; if (use_simplification) + { for (int i = 0; i < clause.size(); i++) { n_occ[toInt(clause[i])]--; updateElimHeap(var(clause[i])); occurs.smudge(var(clause[i])); } - - Solver::removeClause(cr); + } + Solver::removeClause(cr); } @@ -546,9 +546,10 @@ bool SimpSolver::eliminateVar(Var v) 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, clause_size) && - (++cnt > cls.size() + grow || (clause_lim != -1 && clause_size > clause_lim))) - return true; + if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) + && (++cnt > cls.size() + grow + || (clause_lim != -1 && clause_size > clause_lim))) + return true; // Delete and store old clauses: eliminated[v] = true; @@ -565,8 +566,7 @@ bool SimpSolver::eliminateVar(Var v) mkElimClause(elimclauses, ~mkLit(v)); } - for (int i = 0; i < cls.size(); i++) - removeClause(cls[i]); + for (int i = 0; i < cls.size(); i++) removeClause(cls[i]); // Produce clauses in cross product: vec<Lit>& resolvent = add_tmp; @@ -580,7 +580,7 @@ bool SimpSolver::eliminateVar(Var v) // Free occurs list for this variable: occurs[v].clear(true); - + // Free watchers lists for this variable, if possible: if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true); if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true); @@ -600,7 +600,7 @@ bool SimpSolver::substitute(Var v, Lit x) eliminated[v] = true; setDecisionVar(v, false); const vec<CRef>& cls = occurs.lookup(v); - + vec<Lit>& subst_clause = add_tmp; for (int i = 0; i < cls.size(); i++){ Clause& clause = ca[cls[i]]; @@ -643,7 +643,7 @@ bool SimpSolver::eliminate(bool turn_off_elim) { // CVC4::TimerStat::CodeTimer codeTimer(total_eliminate_time); - + if (!simplify()) return false; else if (!use_simplification) @@ -655,9 +655,12 @@ bool SimpSolver::eliminate(bool turn_off_elim) gatherTouchedClauses(); // printf(" ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns); - if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) && - !backwardSubsumptionCheck(true)){ - ok = false; goto cleanup; } + if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) + && !backwardSubsumptionCheck(true)) + { + ok = false; + goto cleanup; + } // Empty elim_heap and return immediately on user-interrupt: if (asynch_interrupt){ @@ -670,7 +673,7 @@ bool SimpSolver::eliminate(bool turn_off_elim) // printf(" ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), elim_heap.size()); for (int cnt = 0; !elim_heap.empty(); cnt++){ Var elim = elim_heap.removeMin(); - + if (asynch_interrupt) break; if (isEliminated(elim) || value(elim) != l_Undef) continue; @@ -720,8 +723,10 @@ bool SimpSolver::eliminate(bool turn_off_elim) } if (verbosity >= 1 && elimclauses.size() > 0) - printf("| Eliminated clauses: %10.2f Mb |\n", - double(elimclauses.size() * sizeof(uint32_t)) / (1024*1024)); + printf( + "| Eliminated clauses: %10.2f Mb " + " |\n", + double(elimclauses.size() * sizeof(uint32_t)) / (1024 * 1024)); return ok; @@ -772,15 +777,17 @@ void SimpSolver::garbageCollect() { // Initialize the next region to a size corresponding to the estimated utilization degree. This // is not precise but should avoid some unnecessary reallocations for the new region: - ClauseAllocator to(ca.size() - ca.wasted()); + ClauseAllocator to(ca.size() - ca.wasted()); cleanUpClauses(); to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields. relocAll(to); Solver::relocAll(to); if (verbosity >= 2) - printf("| Garbage collection: %12d bytes => %12d bytes |\n", - ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size); + printf( + "| Garbage collection: %12d bytes => %12d bytes |\n", + ca.size() * ClauseAllocator::Unit_Size, + to.size() * ClauseAllocator::Unit_Size); to.moveTo(ca); } diff --git a/src/prop/cadical.cpp b/src/prop/cadical.cpp index ca447cea8..7cc5b16cd 100644 --- a/src/prop/cadical.cpp +++ b/src/prop/cadical.cpp @@ -19,7 +19,6 @@ #ifdef CVC4_USE_CADICAL #include "base/check.h" -#include "proof/sat_proof.h" namespace CVC4 { namespace prop { diff --git a/src/prop/cnf_stream.cpp b/src/prop/cnf_stream.cpp index a6a4b6859..c46cd5136 100644 --- a/src/prop/cnf_stream.cpp +++ b/src/prop/cnf_stream.cpp @@ -83,22 +83,13 @@ void CnfStream::assertClause(TNode node, SatClause& c) { } } - if (PROOF_ON() && 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) - if (PROOF_ON() && d_cnfProof) + if (d_cnfProof && clause_id != ClauseIdError) { - if (clause_id != ClauseIdError) - { - d_cnfProof->registerConvertedClause(clause_id); - } - d_cnfProof->popCurrentDefinition(); - }; + d_cnfProof->registerConvertedClause(clause_id); + } } void CnfStream::assertClause(TNode node, SatLiteral a) { @@ -171,11 +162,17 @@ void TseitinCnfStream::ensureLiteral(TNode n, bool noPreregistration) { // non-empty and that we are not associating a bogus assertion with the // clause. This should be ok because we use the mapping back to assertions // for clauses from input assertions only. - PROOF(if (d_cnfProof) { d_cnfProof->pushCurrentAssertion(Node::null()); }); + if (d_cnfProof) + { + d_cnfProof->pushCurrentAssertion(Node::null()); + } lit = toCNF(n, false); - PROOF(if (d_cnfProof) { d_cnfProof->popCurrentAssertion(); }); + if (d_cnfProof) + { + d_cnfProof->popCurrentAssertion(); + } // Store backward-mappings // These may already exist @@ -547,7 +544,6 @@ void TseitinCnfStream::convertAndAssertAnd(TNode node, bool 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(if (d_cnfProof) d_cnfProof->setCnfDependence(*conjunct, node);); convertAndAssert(*conjunct, false); } } else { @@ -581,7 +577,6 @@ void TseitinCnfStream::convertAndAssertOr(TNode node, bool 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(if (d_cnfProof) d_cnfProof->setCnfDependence((*conjunct).negate(), node.negate());); convertAndAssert(*conjunct, true); } } @@ -658,8 +653,6 @@ void TseitinCnfStream::convertAndAssertImplies(TNode node, bool negated) { clause[1] = q; assertClause(node, clause); } else {// Construct the - 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); convertAndAssert(node[1], true); @@ -693,32 +686,23 @@ void TseitinCnfStream::convertAndAssertIte(TNode node, bool negated) { void TseitinCnfStream::convertAndAssert(TNode node, bool removable, bool negated, - ProofRule proof_id, - TNode from) { + bool input) +{ Debug("cnf") << "convertAndAssert(" << node << ", removable = " << (removable ? "true" : "false") << ", negated = " << (negated ? "true" : "false") << ")" << endl; d_removable = removable; - 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); - } - }); + if (d_cnfProof) + { + d_cnfProof->pushCurrentAssertion(negated ? node.notNode() : (Node)node, + input); + } convertAndAssert(node, negated); - PROOF - (if (d_cnfProof) { - d_cnfProof->popCurrentAssertion(); - }); + if (d_cnfProof) + { + d_cnfProof->popCurrentAssertion(); + } } void TseitinCnfStream::convertAndAssert(TNode node, bool negated) { diff --git a/src/prop/cnf_stream.h b/src/prop/cnf_stream.h index 40243e5b9..aec4257f2 100644 --- a/src/prop/cnf_stream.h +++ b/src/prop/cnf_stream.h @@ -186,10 +186,13 @@ class CnfStream { * @param node node to convert and assert * @param removable whether the sat solver can choose to remove the clauses * @param negated whether we are asserting the node negated + * @param input whether it is an input assertion (rather than a lemma). This + * information is only relevant for unsat core tracking. */ - virtual void convertAndAssert(TNode node, bool removable, bool negated, - ProofRule proof_id, - TNode from = TNode::null()) = 0; + virtual void convertAndAssert(TNode node, + bool removable, + bool negated, + bool input = false) = 0; /** * Get the node that is represented by the given SatLiteral. @@ -269,12 +272,13 @@ class TseitinCnfStream : public CnfStream { * @param node the formula to assert * @param removable is this something that can be erased * @param negated true if negated + * @param input whether it is an input assertion (rather than a lemma). This + * information is only relevant for unsat core tracking. */ void convertAndAssert(TNode node, bool removable, bool negated, - ProofRule rule, - TNode from = TNode::null()) override; + bool input = false) override; private: /** diff --git a/src/prop/cryptominisat.cpp b/src/prop/cryptominisat.cpp index cf23758f1..92817a70c 100644 --- a/src/prop/cryptominisat.cpp +++ b/src/prop/cryptominisat.cpp @@ -19,8 +19,6 @@ #include "prop/cryptominisat.h" #include "base/check.h" -#include "proof/clause_id.h" -#include "proof/sat_proof.h" #include <cryptominisat5/cryptominisat.h> @@ -87,8 +85,9 @@ void CryptoMinisatSolver::init() CryptoMinisatSolver::~CryptoMinisatSolver() {} ClauseId CryptoMinisatSolver::addXorClause(SatClause& clause, - bool rhs, - bool removable) { + bool rhs, + bool removable) +{ Debug("sat::cryptominisat") << "Add xor clause " << clause <<" = " << rhs << "\n"; if (!d_okay) { @@ -97,7 +96,7 @@ ClauseId CryptoMinisatSolver::addXorClause(SatClause& clause, } ++(d_statistics.d_xorClausesAdded); - + // ensure all sat literals have positive polarity by pushing // the negation on the result std::vector<CMSatVar> xor_clause; @@ -119,36 +118,19 @@ ClauseId CryptoMinisatSolver::addClause(SatClause& clause, bool removable){ } ++(d_statistics.d_clausesAdded); - + std::vector<CMSat::Lit> internal_clause; toInternalClause(clause, internal_clause); bool nowOkay = d_solver->add_clause(internal_clause); ClauseId freshId; - if (THEORY_PROOF_ON()) - { - freshId = ClauseId(ProofManager::currentPM()->nextId()); - // If this clause results in a conflict, then `nowOkay` may be false, but - // we still need to register this clause as used. Thus, we look at - // `d_okay` instead - if (d_bvp && d_okay) - { - d_bvp->registerUsedClause(freshId, clause); - } - } - else - { - freshId = ClauseIdError; - } + freshId = ClauseIdError; d_okay &= nowOkay; return freshId; } -bool CryptoMinisatSolver::ok() const { - return d_okay; -} - +bool CryptoMinisatSolver::ok() const { return d_okay; } SatVariable CryptoMinisatSolver::newVar(bool isTheoryAtom, bool preRegister, bool canErase){ d_solver->new_var(); @@ -208,19 +190,11 @@ SatValue CryptoMinisatSolver::value(SatLiteral l){ return toSatLiteralValue(value); } -SatValue CryptoMinisatSolver::modelValue(SatLiteral l){ - return value(l); -} +SatValue CryptoMinisatSolver::modelValue(SatLiteral l) { return value(l); } unsigned CryptoMinisatSolver::getAssertionLevel() const { Unreachable() << "No interface to get assertion level in Cryptominisat"; - return -1; -} - -void CryptoMinisatSolver::setClausalProofLog(proof::ClausalBitVectorProof* bvp) -{ - d_bvp = bvp; - d_solver->set_drat(&bvp->getDratOstream(), false); + return -1; } // Satistics for CryptoMinisatSolver diff --git a/src/prop/cryptominisat.h b/src/prop/cryptominisat.h index d60855654..6d3b351b0 100644 --- a/src/prop/cryptominisat.h +++ b/src/prop/cryptominisat.h @@ -21,7 +21,6 @@ #ifdef CVC4_USE_CRYPTOMINISAT -#include "proof/clausal_bitvector_proof.h" #include "prop/sat_solver.h" // Cryptominisat has name clashes with the other Minisat implementations since @@ -68,7 +67,6 @@ class CryptoMinisatSolver : public SatSolver SatValue modelValue(SatLiteral l) override; unsigned getAssertionLevel() const override; - void setClausalProofLog(proof::ClausalBitVectorProof* bvp) override; private: class Statistics @@ -97,7 +95,6 @@ class CryptoMinisatSolver : public SatSolver void init(); std::unique_ptr<CMSat::SATSolver> d_solver; - proof::ClausalBitVectorProof* d_bvp; unsigned d_numVariables; bool d_okay; SatVariable d_true; diff --git a/src/prop/kissat.cpp b/src/prop/kissat.cpp index 0440fcd4e..544a37a3e 100644 --- a/src/prop/kissat.cpp +++ b/src/prop/kissat.cpp @@ -19,7 +19,6 @@ #ifdef CVC4_USE_KISSAT #include "base/check.h" -#include "proof/sat_proof.h" namespace CVC4 { namespace prop { diff --git a/src/prop/minisat/core/Solver.cc b/src/prop/minisat/core/Solver.cc index f56f6a447..311224a03 100644 --- a/src/prop/minisat/core/Solver.cc +++ b/src/prop/minisat/core/Solver.cc @@ -30,6 +30,7 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include "options/prop_options.h" #include "options/smt_options.h" #include "proof/clause_id.h" +#include "proof/cnf_proof.h" #include "proof/proof_manager.h" #include "proof/sat_proof.h" #include "proof/sat_proof_implementation.h" @@ -217,7 +218,10 @@ Solver::Solver(CVC4::prop::TheoryProxy* proxy, propagation_budget(-1), asynch_interrupt(false) { - PROOF(ProofManager::currentPM()->initSatProof(this);) + if (options::unsatCores()) + { + ProofManager::currentPM()->initSatProof(this); + } // Create the constant variables varTrue = newVar(true, false, false); @@ -227,11 +231,11 @@ Solver::Solver(CVC4::prop::TheoryProxy* proxy, uncheckedEnqueue(mkLit(varTrue, false)); uncheckedEnqueue(mkLit(varFalse, true)); // FIXME: these should be axioms I believe - PROOF - ( - ProofManager::getSatProof()->registerTrueLit(mkLit(varTrue, false)); - ProofManager::getSatProof()->registerFalseLit(mkLit(varFalse, true)); - ); + if (options::unsatCores()) + { + ProofManager::getSatProof()->registerTrueLit(mkLit(varTrue, false)); + ProofManager::getSatProof()->registerFalseLit(mkLit(varFalse, true)); + } } @@ -390,15 +394,20 @@ CRef Solver::reason(Var x) { // FIXME: at some point will need more information about where this explanation // came from (ie. the theory/sharing) Debug("pf::sat") << "Minisat::Solver registering a THEORY_LEMMA (1)" << std::endl; - PROOF(ClauseId id = ProofManager::getSatProof()->registerClause( - real_reason, THEORY_LEMMA); - ProofManager::getCnfProof()->registerConvertedClause(id, true); - // explainPropagation() pushes the explanation on the assertion stack - // in CnfProof, so we need to pop it here. This is important because - // reason() may be called indirectly while adding a clause, which can - // lead to a wrong assertion being associated with the clause being - // added (see issue #2137). - ProofManager::getCnfProof()->popCurrentAssertion();); + if (options::unsatCores()) + { + ClauseId id = ProofManager::getSatProof()->registerClause(real_reason, + THEORY_LEMMA); + // map id to assertion, which may be required if looking for + // lemmas in unsat core + ProofManager::getCnfProof()->registerConvertedClause(id); + // explainPropagation() pushes the explanation on the assertion stack + // in CnfProof, so we need to pop it here. This is important because + // reason() may be called indirectly while adding a clause, which can + // lead to a wrong assertion being associated with the clause being + // added (see issue #2137). + ProofManager::getCnfProof()->popCurrentAssertion(); + } vardata[x] = VarData(real_reason, level(x), user_level(x), intro_level(x), trail_index(x)); clauses_removable.push(real_reason); attachClause(real_reason); @@ -441,9 +450,13 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id) } // If a literal is false at 0 level (both sat and user level) we also ignore it if (value(ps[i]) == l_False) { - if (!PROOF_ON() && level(var(ps[i])) == 0 && user_level(var(ps[i])) == 0) { + if (!options::unsatCores() && level(var(ps[i])) == 0 + && user_level(var(ps[i])) == 0) + { continue; - } else { + } + else + { // If we decide to keep it, we count it into the false literals falseLiteralsCount ++; } @@ -467,34 +480,46 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id) lemmas.push(); ps.copyTo(lemmas.last()); lemmas_removable.push(removable); - 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); + if (options::unsatCores()) + { + // Store the expression being converted to CNF until + // the clause is actually created + lemmas_cnf_assertion.push_back( + ProofManager::getCnfProof()->getCurrentAssertion()); + id = ClauseIdUndef; + } } else { assert(decisionLevel() == 0); // If all false, we're in conflict if (ps.size() == falseLiteralsCount) { - if(PROOF_ON()) { + if (options::unsatCores()) + { // Take care of false units here; otherwise, we need to // construct the clause below to give to the proof manager // as the final conflict. if(falseLiteralsCount == 1) { - PROOF( id = ProofManager::getSatProof()->storeUnitConflict(ps[0], INPUT); ) - PROOF( ProofManager::getSatProof()->finalizeProof(CVC4::Minisat::CRef_Lazy); ) + if (options::unsatCores()) + { + ClauseKind ck = + ProofManager::getCnfProof()->getCurrentAssertionKind() + ? INPUT + : THEORY_LEMMA; + id = ProofManager::getSatProof()->storeUnitConflict(ps[0], ck); + // map id to assertion, which may be required if looking for + // lemmas in unsat core + if (ck == THEORY_LEMMA) + { + ProofManager::getCnfProof()->registerConvertedClause(id); + } + ProofManager::getSatProof()->finalizeProof( + CVC4::Minisat::CRef_Lazy); + } return ok = false; } - } else { + } + else + { return ok = false; } } @@ -509,14 +534,23 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id) cr = ca.alloc(clauseLevel, ps, false); clauses_persistent.push(cr); - attachClause(cr); - - if(PROOF_ON()) { - PROOF( - id = ProofManager::getSatProof()->registerClause(cr, INPUT); - ) - if(ps.size() == falseLiteralsCount) { - PROOF( ProofManager::getSatProof()->finalizeProof(cr); ) + attachClause(cr); + + if (options::unsatCores()) + { + ClauseKind ck = ProofManager::getCnfProof()->getCurrentAssertionKind() + ? INPUT + : THEORY_LEMMA; + id = ProofManager::getSatProof()->registerClause(cr, ck); + // map id to assertion, which may be required if looking for + // lemmas in unsat core + if (ck == THEORY_LEMMA) + { + ProofManager::getCnfProof()->registerConvertedClause(id); + } + if (ps.size() == falseLiteralsCount) + { + ProofManager::getSatProof()->finalizeProof(cr); return ok = false; } } @@ -527,15 +561,25 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& 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" << std::endl; - PROOF( - if(ps.size() == 1) { - id = ProofManager::getSatProof()->registerUnitClause(ps[0], INPUT); - } - ); + Debug("cores") << "i'm registering a unit clause, maybe input" + << std::endl; + if (options::unsatCores() && ps.size() == 1) + { + ClauseKind ck = + ProofManager::getCnfProof()->getCurrentAssertionKind() + ? INPUT + : THEORY_LEMMA; + id = ProofManager::getSatProof()->registerUnitClause(ps[0], ck); + // map id to assertion, which may be required if looking for + // lemmas in unsat core + if (ck == THEORY_LEMMA) + { + ProofManager::getCnfProof()->registerConvertedClause(id); + } + } CRef confl = propagate(CHECK_WITHOUT_THEORY); if(! (ok = (confl == CRef_Undef)) ) { - if (PROOF_ON()) + if (options::unsatCores()) { if (ca[confl].size() == 1) { @@ -552,7 +596,10 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id) } return ok; } else { - PROOF(id = ClauseIdUndef;); + if (options::unsatCores()) + { + id = ClauseIdUndef; + } return ok; } } @@ -575,7 +622,10 @@ void Solver::attachClause(CRef cr) { void Solver::detachClause(CRef cr, bool strict) { const Clause& c = ca[cr]; - PROOF( ProofManager::getSatProof()->markDeleted(cr); ); + if (options::unsatCores()) + { + ProofManager::getSatProof()->markDeleted(cr); + } Debug("minisat") << "Solver::detachClause(" << c << ")" << std::endl; assert(c.size() > 1); @@ -826,7 +876,10 @@ int Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel) int max_resolution_level = 0; // Maximal level of the resolved clauses - PROOF( ProofManager::getSatProof()->startResChain(confl); ) + if (options::unsatCores()) + { + ProofManager::getSatProof()->startResChain(confl); + } do{ assert(confl != CRef_Undef); // (otherwise should be UIP) @@ -867,9 +920,9 @@ int Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel) } // FIXME: can we do it lazily if we actually need the proof? - if (level(var(q)) == 0) + if (options::unsatCores() && level(var(q)) == 0) { - PROOF(ProofManager::getSatProof()->resolveOutUnit(q);) + ProofManager::getSatProof()->resolveOutUnit(q); } } } @@ -881,8 +934,9 @@ int Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel) seen[var(p)] = 0; pathC--; - if ( pathC > 0 && confl != CRef_Undef ) { - PROOF( ProofManager::getSatProof()->addResolutionStep(p, confl, sign(p)); ) + if (options::unsatCores() && pathC > 0 && confl != CRef_Undef) + { + ProofManager::getSatProof()->addResolutionStep(p, confl, sign(p)); } }while (pathC > 0); @@ -905,7 +959,10 @@ int Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel) // Literal is not redundant out_learnt[j++] = out_learnt[i]; } else { - PROOF( ProofManager::getSatProof()->storeLitRedundant(out_learnt[i]); ) + if (options::unsatCores()) + { + ProofManager::getSatProof()->storeLitRedundant(out_learnt[i]); + } // Literal is redundant, to be safe, mark the level as current assertion level // TODO: maybe optimize max_resolution_level = std::max(max_resolution_level, user_level(var(out_learnt[i]))); @@ -1169,7 +1226,10 @@ void Solver::propagateTheory() { addClause(explanation, true, id); // explainPropagation() pushes the explanation on the assertion // stack in CnfProof, so we need to pop it here. - PROOF(ProofManager::getCnfProof()->popCurrentAssertion();) + if (options::unsatCores()) + { + ProofManager::getCnfProof()->popCurrentAssertion(); + } } } } @@ -1310,9 +1370,10 @@ void Solver::removeSatisfied(vec<CRef>& cs) for (i = j = 0; i < cs.size(); i++){ Clause& c = ca[cs[i]]; if (satisfied(c)) { - if (locked(c)) { + if (options::unsatCores() && locked(c)) + { // store a resolution of the literal c propagated - PROOF( ProofManager::getSatProof()->storeUnitResolution(c[0]); ) + ProofManager::getSatProof()->storeUnitResolution(c[0]); } removeClause(cs[i]); } @@ -1412,8 +1473,11 @@ lbool Solver::search(int nof_conflicts) conflicts++; conflictC++; if (decisionLevel() == 0) { - PROOF( ProofManager::getSatProof()->finalizeProof(confl); ) - return l_False; + if (options::unsatCores()) + { + ProofManager::getSatProof()->finalizeProof(confl); + } + return l_False; } // Analyze the conflict @@ -1425,8 +1489,10 @@ lbool Solver::search(int nof_conflicts) if (learnt_clause.size() == 1) { uncheckedEnqueue(learnt_clause[0]); - PROOF( ProofManager::getSatProof()->endResChain(learnt_clause[0]); ) - + if (options::unsatCores()) + { + ProofManager::getSatProof()->endResChain(learnt_clause[0]); + } } else { CRef cr = ca.alloc(assertionLevelOnly() ? assertionLevel : max_level, @@ -1436,15 +1502,12 @@ lbool Solver::search(int nof_conflicts) attachClause(cr); claBumpActivity(ca[cr]); uncheckedEnqueue(learnt_clause[0], cr); - PROOF(ClauseId id = - ProofManager::getSatProof()->registerClause(cr, LEARNT); - PSTATS(std::unordered_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);); + if (options::unsatCores()) + { + ClauseId id = + ProofManager::getSatProof()->registerClause(cr, LEARNT); + ProofManager::getSatProof()->endResChain(id); + } } varDecayActivity(); @@ -1469,25 +1532,33 @@ lbool Solver::search(int nof_conflicts) } } else { - - // If this was a final check, we are satisfiable - if (check_type == CHECK_FINAL) { - bool decisionEngineDone = d_proxy->isDecisionEngineDone(); - // Unless a lemma has added more stuff to the queues - if (!decisionEngineDone && - (!order_heap.empty() || qhead < trail.size()) ) { - check_type = CHECK_WITH_THEORY; - continue; - } else if (recheck) { - // There some additional stuff added, so we go for another full-check - continue; - } else { - // Yes, we're truly satisfiable - return l_True; - } - } else if (check_type == CHECK_FINAL_FAKE) { + // If this was a final check, we are satisfiable + if (check_type == CHECK_FINAL) + { + bool decisionEngineDone = d_proxy->isDecisionEngineDone(); + // Unless a lemma has added more stuff to the queues + if (!decisionEngineDone + && (!order_heap.empty() || qhead < trail.size())) + { check_type = CHECK_WITH_THEORY; + continue; + } + else if (recheck) + { + // There some additional stuff added, so we go for another + // full-check + continue; } + else + { + // Yes, we're truly satisfiable + return l_True; + } + } + else if (check_type == CHECK_FINAL_FAKE) + { + check_type = CHECK_WITH_THEORY; + } if ((nof_conflicts >= 0 && conflictC >= nof_conflicts) || !withinBudget(ResourceManager::Resource::SatConflictStep)) @@ -1744,7 +1815,10 @@ 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, NULLPROOF(ProofManager::getSatProof())); + ca.reloc(ws[j].cref, + to, + CVC4::options::unsatCores() ? ProofManager::getSatProof() + : nullptr); } // All reasons: @@ -1753,22 +1827,31 @@ void Solver::relocAll(ClauseAllocator& to) Var v = var(trail[i]); if (hasReasonClause(v) && (ca[reason(v)].reloced() || locked(ca[reason(v)]))) - ca.reloc( - vardata[v].d_reason, to, NULLPROOF(ProofManager::getSatProof())); + ca.reloc(vardata[v].d_reason, + to, + CVC4::options::unsatCores() ? ProofManager::getSatProof() + : nullptr); } // All learnt: // for (int i = 0; i < clauses_removable.size(); i++) ca.reloc( - clauses_removable[i], to, NULLPROOF(ProofManager::getSatProof())); + clauses_removable[i], + to, + CVC4::options::unsatCores() ? ProofManager::getSatProof() : nullptr); // All original: // for (int i = 0; i < clauses_persistent.size(); i++) ca.reloc( - clauses_persistent[i], to, NULLPROOF(ProofManager::getSatProof())); + clauses_persistent[i], + to, + CVC4::options::unsatCores() ? ProofManager::getSatProof() : nullptr); - PROOF(ProofManager::getSatProof()->finishUpdateCRef();) + if (options::unsatCores()) + { + ProofManager::getSatProof()->finishUpdateCRef(); + } } @@ -1874,7 +1957,7 @@ CRef Solver::updateLemmas() { // If it's an empty lemma, we have a conflict at zero level if (lemma.size() == 0) { - Assert(!PROOF_ON()); + Assert(!options::unsatCores()); conflict = CRef_Lazy; backtrackLevel = 0; Debug("minisat::lemmas") << "Solver::updateLemmas(): found empty clause" << std::endl; @@ -1904,7 +1987,8 @@ CRef Solver::updateLemmas() { // Last index in the trail int backtrack_index = trail.size(); - PROOF(Assert(lemmas.size() == (int)lemmas_cnf_assertion.size());); + Assert(!options::unsatCores() + || lemmas.size() == (int)lemmas_cnf_assertion.size()); // Attach all the clauses and enqueue all the propagations for (int j = 0; j < lemmas.size(); ++j) @@ -1928,15 +2012,16 @@ CRef Solver::updateLemmas() { } lemma_ref = ca.alloc(clauseLevel, lemma, removable); - PROOF(TNode cnf_assertion = lemmas_cnf_assertion[j].first; - TNode cnf_def = lemmas_cnf_assertion[j].second; - - Debug("pf::sat") - << "Minisat::Solver registering a THEORY_LEMMA (2)" << std::endl; - ClauseId id = ProofManager::getSatProof()->registerClause( - lemma_ref, THEORY_LEMMA); - ProofManager::getCnfProof()->setClauseAssertion(id, cnf_assertion); - ProofManager::getCnfProof()->setClauseDefinition(id, cnf_def);); + if (options::unsatCores()) + { + TNode cnf_assertion = lemmas_cnf_assertion[j]; + + Debug("pf::sat") << "Minisat::Solver registering a THEORY_LEMMA (2)" + << std::endl; + ClauseId id = ProofManager::getSatProof()->registerClause(lemma_ref, + THEORY_LEMMA); + ProofManager::getCnfProof()->setClauseAssertion(id, cnf_assertion); + } if (removable) { clauses_removable.push(lemma_ref); } else { @@ -1948,17 +2033,15 @@ CRef Solver::updateLemmas() { // If the lemma is propagating enqueue its literal (or set the conflict) if (conflict == CRef_Undef && value(lemma[0]) != l_True) { if (lemma.size() == 1 || (value(lemma[1]) == l_False && trail_index(var(lemma[1])) < backtrack_index)) { - if (PROOF_ON() && lemma.size() == 1) + if (options::unsatCores() && lemma.size() == 1) { - Node cnf_assertion = lemmas_cnf_assertion[j].first; - Node cnf_def = lemmas_cnf_assertion[j].second; + Node cnf_assertion = lemmas_cnf_assertion[j]; Debug("pf::sat") << "Minisat::Solver registering a THEORY_LEMMA (3) " << cnf_assertion << value(lemma[0]) << std::endl; ClauseId id = ProofManager::getSatProof()->registerUnitClause( lemma[0], THEORY_LEMMA); ProofManager::getCnfProof()->setClauseAssertion(id, cnf_assertion); - ProofManager::getCnfProof()->setClauseDefinition(id, cnf_def); } if (value(lemma[0]) == l_False) { @@ -1969,7 +2052,10 @@ 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); ); + if (options::unsatCores()) + { + ProofManager::getSatProof()->storeUnitConflict(lemma[0], LEARNT); + } } } else { Debug("minisat::lemmas") << "lemma size is " << lemma.size() << std::endl; @@ -1979,7 +2065,8 @@ CRef Solver::updateLemmas() { } } - PROOF(Assert(lemmas.size() == (int)lemmas_cnf_assertion.size());); + Assert(!options::unsatCores() + || lemmas.size() == (int)lemmas_cnf_assertion.size()); // Clear the lemmas lemmas.clear(); lemmas_cnf_assertion.clear(); diff --git a/src/prop/minisat/core/Solver.h b/src/prop/minisat/core/Solver.h index 508947456..a5f3664e8 100644 --- a/src/prop/minisat/core/Solver.h +++ b/src/prop/minisat/core/Solver.h @@ -63,7 +63,7 @@ public: typedef Var TVar; typedef Lit TLit; - typedef Clause TClause; + typedef Clause TClause; typedef CRef TCRef; typedef vec<Lit> TLitVec; @@ -98,7 +98,7 @@ public: vec<bool> lemmas_removable; /** Nodes being converted to CNF */ - std::vector<std::pair<CVC4::Node, CVC4::Node> > lemmas_cnf_assertion; + std::vector<CVC4::Node> lemmas_cnf_assertion; /** Do a another check if FULL_EFFORT was the last one */ bool recheck; @@ -203,7 +203,7 @@ public: lbool solve (Lit p, Lit q, Lit r); // Search for a model that respects three assumptions. bool okay () const; // FALSE means solver is in a conflicting state - void toDimacs (); + void toDimacs(); void toDimacs (FILE* f, const vec<Lit>& assumps); // Write CNF to file in DIMACS-format. void toDimacs (const char *file, const vec<Lit>& assumps); void toDimacs (FILE* f, Clause& c, vec<Var>& map, Var& max); diff --git a/src/prop/minisat/core/SolverTypes.h b/src/prop/minisat/core/SolverTypes.h index bbd6e17a2..b30d97aee 100644 --- a/src/prop/minisat/core/SolverTypes.h +++ b/src/prop/minisat/core/SolverTypes.h @@ -73,9 +73,14 @@ inline bool sign (Lit p) { return p.x & 1; } inline int var (Lit p) { return p.x >> 1; } // Mapping Literals to and from compact integers suitable for array indexing: -inline int toInt (Var v) { return v; } -inline int toInt (Lit p) { return p.x; } -inline Lit toLit (int i) { Lit p; p.x = i; return p; } +inline int toInt(Var v) { return v; } +inline int toInt(Lit p) { return p.x; } +inline Lit toLit(int i) +{ + Lit p; + p.x = i; + return p; +} //const Lit lit_Undef = mkLit(var_Undef, false); // }- Useful special constants. //const Lit lit_Error = mkLit(var_Undef, true ); // } @@ -83,20 +88,19 @@ inline Lit toLit (int i) { Lit p; p.x = i; return p; } const Lit lit_Undef = { -2 }; // }- Useful special constants. const Lit lit_Error = { -1 }; // } - //================================================================================================= // Lifted booleans: // -// NOTE: this implementation is optimized for the case when comparisons between values are mostly -// between one variable and one constant. Some care had to be taken to make sure that gcc -// does enough constant propagation to produce sensible code, and this appears to be somewhat -// fragile unfortunately. +// NOTE: this implementation is optimized for the case when comparisons between +// values are mostly +// between one variable and one constant. Some care had to be taken to +// make sure that gcc does enough constant propagation to produce sensible +// code, and this appears to be somewhat fragile unfortunately. /* - This is to avoid multiple definitions of l_True, l_False and l_Undef if using multiple copies of - Minisat. - IMPORTANT: if we you change the value of the constants so that it is not the same in all copies - of Minisat this breaks! + This is to avoid multiple definitions of l_True, l_False and l_Undef if using + multiple copies of Minisat. IMPORTANT: if we you change the value of the + constants so that it is not the same in all copies of Minisat this breaks! */ #ifndef l_True @@ -124,10 +128,12 @@ public: bool operator != (lbool b) const { return !(*this == b); } lbool operator ^ (bool b) const { return lbool((uint8_t)(value^(uint8_t)b)); } - lbool operator && (lbool b) const { - uint8_t sel = (this->value << 1) | (b.value << 3); - uint8_t v = (0xF7F755F4 >> sel) & 3; - return lbool(v); } + lbool operator&&(lbool b) const + { + uint8_t sel = (this->value << 1) | (b.value << 3); + uint8_t v = (0xF7F755F4 >> sel) & 3; + return lbool(v); + } lbool operator || (lbool b) const { uint8_t sel = (this->value << 1) | (b.value << 3); @@ -163,7 +169,7 @@ inline std::ostream& operator <<(std::ostream& out, Minisat::vec<Minisat::Lit>& } inline std::ostream& operator <<(std::ostream& out, Minisat::lbool val) { - std::string val_str; + std::string val_str; if( val == l_False ) { val_str = "0"; } else if (val == l_True ) { @@ -208,14 +214,14 @@ class Clause { header.size = ps.size(); header.level = level; - for (int i = 0; i < ps.size(); i++) - data[i].lit = ps[i]; + for (int i = 0; i < ps.size(); i++) data[i].lit = ps[i]; if (header.has_extra){ if (header.removable) - data[header.size].act = 0; - else - calcAbstraction(); } + data[header.size].act = 0; + else + calcAbstraction(); + } } public: @@ -321,7 +327,7 @@ class OccLists public: OccLists(const Deleted& d) : deleted(d) {} - + void init (const Idx& idx){ occs.growTo(toInt(idx)+1); dirty.growTo(toInt(idx)+1, 0); } void resizeTo (const Idx& idx); // Vec& operator[](const Idx& idx){ return occs[toInt(idx)]; } @@ -394,13 +400,12 @@ class CMap typedef Map<CRef, T, CRefHash> HashTable; HashTable map; - + public: // Size-operations: void clear () { map.clear(); } int size () const { return map.elems(); } - // Insert/Remove/Test mapping: void insert (CRef cr, const T& t){ map.insert(cr, t); } void growTo (CRef cr, const T& t){ map.insert(cr, t); } // NOTE: for compatibility @@ -423,15 +428,14 @@ class CMap printf(" --- size = %d, bucket_count = %d\n", size(), map.bucket_count()); } }; - /*_________________________________________________________________________________________________ | | subsumes : (other : const Clause&) -> Lit -| +| | Description: -| Checks if clause subsumes 'other', and at the same time, if it can be used to simplify 'other' -| by subsumption resolution. -| +| Checks if clause subsumes 'other', and at the same time, if it can be +used to simplify 'other' | by subsumption resolution. +| | Result: | lit_Error - No subsumption or simplification | lit_Undef - Clause subsumes 'other' diff --git a/src/prop/minisat/minisat.cpp b/src/prop/minisat/minisat.cpp index a4d2dce8a..25353e416 100644 --- a/src/prop/minisat/minisat.cpp +++ b/src/prop/minisat/minisat.cpp @@ -154,7 +154,7 @@ ClauseId MinisatSatSolver::addClause(SatClause& clause, bool removable) { return ClauseIdUndef; } d_minisat->addClause(minisat_clause, removable, clause_id); - PROOF(Assert(clause_id != ClauseIdError);); + Assert(!CVC4::options::unsatCores() || clause_id != ClauseIdError); return clause_id; } diff --git a/src/prop/minisat/simp/SimpSolver.cc b/src/prop/minisat/simp/SimpSolver.cc index 23f97b5d5..0ec8981ca 100644 --- a/src/prop/minisat/simp/SimpSolver.cc +++ b/src/prop/minisat/simp/SimpSolver.cc @@ -21,8 +21,8 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #include "prop/minisat/simp/SimpSolver.h" #include "options/prop_options.h" +#include "options/smt_options.h" #include "proof/clause_id.h" -#include "proof/proof.h" #include "prop/minisat/mtl/Sort.h" #include "prop/minisat/utils/System.h" @@ -47,25 +47,30 @@ static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of //================================================================================================= // Constructor/Destructor: - -SimpSolver::SimpSolver(CVC4::prop::TheoryProxy* proxy, CVC4::context::Context* context, bool enableIncremental) : - Solver(proxy, context, enableIncremental) - , grow (opt_grow) - , clause_lim (opt_clause_lim) - , subsumption_lim (opt_subsumption_lim) - , simp_garbage_frac (opt_simp_garbage_frac) - , use_asymm (opt_use_asymm) - , use_rcheck (opt_use_rcheck) - , use_elim (options::minisatUseElim() && !enableIncremental) - , merges (0) - , asymm_lits (0) - , eliminated_vars (0) - , elimorder (1) - , use_simplification (!enableIncremental && !PROOF_ON()) // TODO: turn off simplifications if proofs are on initially - , occurs (ClauseDeleted(ca)) - , elim_heap (ElimLt(n_occ)) - , bwdsub_assigns (0) - , n_touched (0) +SimpSolver::SimpSolver(CVC4::prop::TheoryProxy* proxy, + CVC4::context::Context* context, + bool enableIncremental) + : Solver(proxy, context, enableIncremental), + grow(opt_grow), + clause_lim(opt_clause_lim), + subsumption_lim(opt_subsumption_lim), + simp_garbage_frac(opt_simp_garbage_frac), + use_asymm(opt_use_asymm), + use_rcheck(opt_use_rcheck), + use_elim(options::minisatUseElim() && !enableIncremental), + merges(0), + asymm_lits(0), + eliminated_vars(0), + elimorder(1), + use_simplification( + !enableIncremental + && !options::unsatCores()) // TODO: turn off simplifications if + // proofs are on initially + , + occurs(ClauseDeleted(ca)), + elim_heap(ElimLt(n_occ)), + bwdsub_assigns(0), + n_touched(0) { if(options::minisatUseElim() && options::minisatUseElim.wasSetByUser() && @@ -117,8 +122,8 @@ Var SimpSolver::newVar(bool sign, bool dvar, bool isTheoryAtom, bool preRegister lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp) { if (options::minisatDumpDimacs()) { - toDimacs(); - return l_Undef; + toDimacs(); + return l_Undef; } assert(decisionLevel() == 0); @@ -533,9 +538,10 @@ bool SimpSolver::eliminateVar(Var v) 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, clause_size) && - (++cnt > cls.size() + grow || (clause_lim != -1 && clause_size > clause_lim))) - return true; + if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) + && (++cnt > cls.size() + grow + || (clause_lim != -1 && clause_size > clause_lim))) + return true; // Delete and store old clauses: eliminated[v] = true; @@ -552,10 +558,9 @@ bool SimpSolver::eliminateVar(Var v) mkElimClause(elimclauses, ~mkLit(v)); } - for (int i = 0; i < cls.size(); i++) - removeClause(cls[i]); + for (int i = 0; i < cls.size(); i++) removeClause(cls[i]); - ClauseId id = ClauseIdUndef; + ClauseId id = ClauseIdUndef; // Produce clauses in cross product: vec<Lit>& resolvent = add_tmp; for (int i = 0; i < pos.size(); i++) @@ -569,7 +574,7 @@ bool SimpSolver::eliminateVar(Var v) // Free occurs list for this variable: occurs[v].clear(true); - + // Free watchers lists for this variable, if possible: if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true); if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true); @@ -589,7 +594,7 @@ bool SimpSolver::substitute(Var v, Lit x) eliminated[v] = true; setDecisionVar(v, false); const vec<CRef>& cls = occurs.lookup(v); - + vec<Lit>& subst_clause = add_tmp; for (int i = 0; i < cls.size(); i++){ Clause& c = ca[cls[i]]; @@ -641,9 +646,12 @@ bool SimpSolver::eliminate(bool turn_off_elim) gatherTouchedClauses(); // printf(" ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns); - if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) && - !backwardSubsumptionCheck(true)){ - ok = false; goto cleanup; } + if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) + && !backwardSubsumptionCheck(true)) + { + ok = false; + goto cleanup; + } // Empty elim_heap and return immediately on user-interrupt: if (asynch_interrupt){ @@ -656,7 +664,7 @@ bool SimpSolver::eliminate(bool turn_off_elim) // printf(" ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), elim_heap.size()); for (int cnt = 0; !elim_heap.empty(); cnt++){ Var elim = elim_heap.removeMin(); - + if (asynch_interrupt) break; if (isEliminated(elim) || value(elim) != l_Undef) continue; @@ -706,8 +714,10 @@ bool SimpSolver::eliminate(bool turn_off_elim) } if (verbosity >= 1 && elimclauses.size() > 0) - printf("| Eliminated clauses: %10.2f Mb |\n", - double(elimclauses.size() * sizeof(uint32_t)) / (1024*1024)); + printf( + "| Eliminated clauses: %10.2f Mb " + " |\n", + double(elimclauses.size() * sizeof(uint32_t)) / (1024 * 1024)); return ok; } @@ -744,11 +754,11 @@ void SimpSolver::relocAll(ClauseAllocator& to) // for (int i = 0; i < subsumption_queue.size(); i++) ca.reloc(subsumption_queue[i], to); - // TODO reloc now takes the proof form the core solver + // TODO reloc now takes the proof form the core solver // Temporary clause: // ca.reloc(bwdsub_tmpunit, to); - // TODO reloc now takes the proof form the core solver + // TODO reloc now takes the proof form the core solver } @@ -756,15 +766,17 @@ void SimpSolver::garbageCollect() { // Initialize the next region to a size corresponding to the estimated utilization degree. This // is not precise but should avoid some unnecessary reallocations for the new region: - ClauseAllocator to(ca.size() - ca.wasted()); + ClauseAllocator to(ca.size() - ca.wasted()); cleanUpClauses(); to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields. relocAll(to); Solver::relocAll(to); if (verbosity >= 2) - printf("| Garbage collection: %12d bytes => %12d bytes |\n", - ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size); + printf( + "| Garbage collection: %12d bytes => %12d bytes |\n", + ca.size() * ClauseAllocator::Unit_Size, + to.size() * ClauseAllocator::Unit_Size); to.moveTo(ca); - // TODO: proof.finalizeUpdateId(); + // TODO: proof.finalizeUpdateId(); } diff --git a/src/prop/prop_engine.cpp b/src/prop/prop_engine.cpp index f74e52509..e71e681e5 100644 --- a/src/prop/prop_engine.cpp +++ b/src/prop/prop_engine.cpp @@ -99,17 +99,17 @@ PropEngine::PropEngine(TheoryEngine* te, d_decisionEngine->setSatSolver(d_satSolver); d_decisionEngine->setCnfStream(d_cnfStream); - PROOF ( - ProofManager::currentPM()->initCnfProof(d_cnfStream, userContext); - ); + if (options::unsatCores()) + { + ProofManager::currentPM()->initCnfProof(d_cnfStream, userContext); + } } void PropEngine::finishInit() { NodeManager* nm = NodeManager::currentNM(); - d_cnfStream->convertAndAssert(nm->mkConst(true), false, false, RULE_GIVEN); - d_cnfStream->convertAndAssert( - nm->mkConst(false).notNode(), false, false, RULE_GIVEN); + d_cnfStream->convertAndAssert(nm->mkConst(true), false, false); + d_cnfStream->convertAndAssert(nm->mkConst(false).notNode(), false, false); } PropEngine::~PropEngine() { @@ -126,18 +126,15 @@ void PropEngine::assertFormula(TNode node) { Assert(!d_inCheckSat) << "Sat solver in solve()!"; Debug("prop") << "assertFormula(" << node << ")" << endl; // Assert as non-removable - d_cnfStream->convertAndAssert(node, false, false, RULE_GIVEN); + d_cnfStream->convertAndAssert(node, false, false, true); } -void PropEngine::assertLemma(TNode node, bool negated, - bool removable, - ProofRule rule, - TNode from) { - //Assert(d_inCheckSat, "Sat solver should be in solve()!"); +void PropEngine::assertLemma(TNode node, bool negated, bool removable) +{ Debug("prop::lemmas") << "assertLemma(" << node << ")" << endl; // Assert as (possibly) removable - d_cnfStream->convertAndAssert(node, removable, negated, rule, from); + d_cnfStream->convertAndAssert(node, removable, negated); } void PropEngine::addAssertionsToDecisionEngine( diff --git a/src/prop/prop_engine.h b/src/prop/prop_engine.h index 9a2daee49..1df862568 100644 --- a/src/prop/prop_engine.h +++ b/src/prop/prop_engine.h @@ -103,11 +103,7 @@ class PropEngine * @param removable whether this lemma can be quietly removed based * on an activity heuristic (or not) */ - void assertLemma(TNode node, - bool negated, - bool removable, - ProofRule rule, - TNode from = TNode::null()); + void assertLemma(TNode node, bool negated, bool removable); /** * Pass a list of assertions from an AssertionPipeline to the decision engine. diff --git a/src/prop/sat_solver.h b/src/prop/sat_solver.h index d4b08ab71..1526e91b9 100644 --- a/src/prop/sat_solver.h +++ b/src/prop/sat_solver.h @@ -33,11 +33,6 @@ namespace CVC4 { -namespace proof { -class ClausalBitVectorProof; -class ResolutionBitVectorProof; -} // namespace proof - namespace prop { class TheoryProxy; @@ -58,7 +53,7 @@ public: /** Add a clause corresponding to rhs = l1 xor .. xor ln */ virtual ClauseId addXorClause(SatClause& clause, bool rhs, bool removable) = 0; - + /** * Create a new boolean variable in the solver. * @param isTheoryAtom is this a theory atom that needs to be asserted to theory @@ -84,6 +79,7 @@ public: virtual SatValue solve(const std::vector<SatLiteral>& assumptions) { Unimplemented() << "Solving under assumptions not implemented"; + return SAT_VALUE_UNKNOWN; }; /** Interrupt the solver */ @@ -101,10 +97,6 @@ public: /** Check if the solver is in an inconsistent state */ virtual bool ok() const = 0; - virtual void setResolutionProofLog(proof::ResolutionBitVectorProof* bvp) {} - - virtual void setClausalProofLog(proof::ClausalBitVectorProof* drat_proof) {} - };/* class SatSolver */ diff --git a/src/prop/theory_proxy.cpp b/src/prop/theory_proxy.cpp index 41da4546e..d0ba4ca71 100644 --- a/src/prop/theory_proxy.cpp +++ b/src/prop/theory_proxy.cpp @@ -76,22 +76,12 @@ void TheoryProxy::explainPropagation(SatLiteral l, SatClause& explanation) { TNode lNode = d_cnfStream->getNode(l); Debug("prop-explain") << "explainPropagation(" << lNode << ")" << std::endl; - LemmaProofRecipe* proofRecipe = NULL; - PROOF(proofRecipe = new LemmaProofRecipe;); + Node theoryExplanation = d_theoryEngine->getExplanation(lNode); - Node theoryExplanation = d_theoryEngine->getExplanationAndRecipe(lNode, proofRecipe); - - PROOF({ - ProofManager::getCnfProof()->pushCurrentAssertion(theoryExplanation); - ProofManager::getCnfProof()->setProofRecipe(proofRecipe); - - Debug("pf::sat") << "TheoryProxy::explainPropagation: setting lemma recipe to: " - << std::endl; - proofRecipe->dump("pf::sat"); - - delete proofRecipe; - proofRecipe = NULL; - }); + if (options::unsatCores()) + { + ProofManager::getCnfProof()->pushCurrentAssertion(theoryExplanation); + } Debug("prop-explain") << "explainPropagation() => " << theoryExplanation << std::endl; if (theoryExplanation.getKind() == kind::AND) { diff --git a/src/smt/assertions.cpp b/src/smt/assertions.cpp index ea3acf2d1..8019c383d 100644 --- a/src/smt/assertions.cpp +++ b/src/smt/assertions.cpp @@ -17,7 +17,6 @@ #include "expr/node_algorithm.h" #include "options/base_options.h" #include "options/language.h" -#include "options/proof_options.h" #include "options/smt_options.h" #include "proof/proof_manager.h" #include "smt/smt_engine.h" @@ -179,18 +178,23 @@ void Assertions::addFormula( } // Give it to proof manager - PROOF(if (inInput) { - // n is an input assertion - if (inUnsatCore || options::unsatCores() || options::dumpUnsatCores() - || options::checkUnsatCores() || options::fewerPreprocessingHoles()) + if (options::unsatCores()) + { + if (inInput) + { // n is an input assertion + if (inUnsatCore || options::unsatCores() || options::dumpUnsatCores() + || options::checkUnsatCores()) + { + ProofManager::currentPM()->addCoreAssertion(n.toExpr()); + } + } + else { - ProofManager::currentPM()->addCoreAssertion(n.toExpr()); + // n is the result of an unknown preprocessing step, add it to dependency + // map to null + ProofManager::currentPM()->addDependence(n, Node::null()); } - } else { - // n is the result of an unknown preprocessing step, add it to dependency - // map to null - ProofManager::currentPM()->addDependence(n, Node::null()); - }); + } // Add the normalized formula to the queue d_assertions.push_back(n, isAssumption); diff --git a/src/smt/assertions.h b/src/smt/assertions.h index c2a16db71..a74c58bd8 100644 --- a/src/smt/assertions.h +++ b/src/smt/assertions.h @@ -122,7 +122,8 @@ class Assertions * formula might be pushed out to the propositional layer * immediately, or it might be simplified and kept, or it might not * even be simplified. - * The arguments isInput and isAssumption are used for bookkeeping for proofs. + * The arguments isInput and isAssumption are used for bookkeeping for unsat + * cores. * The argument maybeHasFv should be set to true if the assertion may have * free variables. By construction, assertions from the smt2 parser are * guaranteed not to have free variables. However, other cases such as diff --git a/src/smt/command.cpp b/src/smt/command.cpp index 88f04f885..cb95cf348 100644 --- a/src/smt/command.cpp +++ b/src/smt/command.cpp @@ -2275,57 +2275,22 @@ void BlockModelValuesCommand::toStream(std::ostream& out, /* class GetProofCommand */ /* -------------------------------------------------------------------------- */ -GetProofCommand::GetProofCommand() : d_smtEngine(nullptr), d_result(nullptr) {} +GetProofCommand::GetProofCommand() {} void GetProofCommand::invoke(SmtEngine* smtEngine) { - try - { - d_smtEngine = smtEngine; - d_result = &smtEngine->getProof(); - d_commandStatus = CommandSuccess::instance(); - } - catch (RecoverableModalException& e) - { - d_commandStatus = new CommandRecoverableFailure(e.what()); - } - catch (UnsafeInterruptException& e) - { - d_commandStatus = new CommandInterrupted(); - } - catch (exception& e) - { - d_commandStatus = new CommandFailure(e.what()); - } -} - -const Proof& GetProofCommand::getResult() const { return *d_result; } -void GetProofCommand::printResult(std::ostream& out, uint32_t verbosity) const -{ - if (!ok()) - { - this->Command::printResult(out, verbosity); - } - else - { - smt::SmtScope scope(d_smtEngine); - d_result->toStream(out); - } + Unimplemented() << "Unimplemented get-proof\n"; } 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/command.h b/src/smt/command.h index a0e591269..9fbd1bf73 100644 --- a/src/smt/command.h +++ b/src/smt/command.h @@ -33,7 +33,6 @@ #include "expr/type.h" #include "expr/variable_type_map.h" #include "proof/unsat_core.h" -#include "util/proof.h" #include "util/result.h" #include "util/sexpr.h" @@ -1131,9 +1130,7 @@ class CVC4_PUBLIC GetProofCommand : public Command public: GetProofCommand(); - const Proof& getResult() const; void invoke(SmtEngine* smtEngine) override; - void printResult(std::ostream& out, uint32_t verbosity = 2) const override; Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) override; Command* clone() const override; @@ -1144,11 +1141,6 @@ class CVC4_PUBLIC GetProofCommand : public Command bool types = false, size_t dag = 1, OutputLanguage language = language::output::LANG_AUTO) const override; - - protected: - SmtEngine* d_smtEngine; - // d_result is owned by d_smtEngine. - const Proof* d_result; }; /* class GetProofCommand */ class CVC4_PUBLIC GetInstantiationsCommand : public Command diff --git a/src/smt/process_assertions.cpp b/src/smt/process_assertions.cpp index a69207512..33d092def 100644 --- a/src/smt/process_assertions.cpp +++ b/src/smt/process_assertions.cpp @@ -21,7 +21,6 @@ #include "options/arith_options.h" #include "options/base_options.h" #include "options/bv_options.h" -#include "options/proof_options.h" #include "options/quantifiers_options.h" #include "options/sep_options.h" #include "options/smt_options.h" @@ -147,12 +146,6 @@ bool ProcessAssertions::apply(Assertions& as) << endl; dumpAssertions("post-definition-expansion", assertions); - // save the assertions now - THEORY_PROOF( - for (size_t i = 0, nasserts = assertions.size(); i < nasserts; ++i) { - ProofManager::currentPM()->addAssertion(assertions[i].toExpr()); - }); - Debug("smt") << " assertions : " << assertions.size() << endl; if (options::globalNegate()) @@ -470,7 +463,7 @@ bool ProcessAssertions::simplifyAssertions(AssertionPipeline& assertions) if (options::simplificationMode() != options::SimplificationMode::NONE) { - if (!options::unsatCores() && !options::fewerPreprocessingHoles()) + if (!options::unsatCores()) { // Perform non-clausal simplification PreprocessingPassResult res = @@ -532,7 +525,7 @@ bool ProcessAssertions::simplifyAssertions(AssertionPipeline& assertions) if (options::repeatSimp() && options::simplificationMode() != options::SimplificationMode::NONE - && !options::unsatCores() && !options::fewerPreprocessingHoles()) + && !options::unsatCores()) { PreprocessingPassResult res = d_passes["non-clausal-simp"]->apply(&assertions); diff --git a/src/smt/set_defaults.cpp b/src/smt/set_defaults.cpp index 130f75894..6f00998d2 100644 --- a/src/smt/set_defaults.cpp +++ b/src/smt/set_defaults.cpp @@ -27,7 +27,6 @@ #include "options/open_ostream.h" #include "options/option_exception.h" #include "options/printer_options.h" -#include "options/proof_options.h" #include "options/prop_options.h" #include "options/quantifiers_options.h" #include "options/sep_options.h" @@ -72,11 +71,6 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) Notice() << "SmtEngine: setting unsatCores" << std::endl; options::unsatCores.set(true); } - if (options::checkProofs() || options::dumpProofs()) - { - Notice() << "SmtEngine: setting proof" << std::endl; - options::proof.set(true); - } if (options::bitvectorAigSimplifications.wasSetByUser()) { Notice() << "SmtEngine: setting bitvectorAig" << std::endl; @@ -254,12 +248,6 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) << std::endl; } } - // !!!!!!!!!!!!!!!! temporary, to support CI check for old proof system - if (options::proof()) - { - options::proofNew.set(false); - } - if (options::arraysExp()) { if (!logic.isQuantified()) @@ -316,11 +304,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) options::produceAssertions.set(true); } - // Disable options incompatible with incremental solving, unsat cores, and - // proofs or output an error if enabled explicitly. It is also currently - // incompatible with arithmetic, force the option off. - if (options::incrementalSolving() || options::unsatCores() - || options::proof()) + // Disable options incompatible with incremental solving, unsat cores or + // output an error if enabled explicitly. It is also currently incompatible + // with arithmetic, force the option off. + if (options::incrementalSolving() || options::unsatCores()) { if (options::unconstrainedSimp()) { @@ -328,10 +315,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) { throw OptionException( "unconstrained simplification not supported with unsat " - "cores/proofs/incremental solving"); + "cores/incremental solving"); } Notice() << "SmtEngine: turning off unconstrained simplification to " - "support unsat cores/proofs/incremental solving" + "support unsat cores/incremental solving" << std::endl; options::unconstrainedSimp.set(false); } @@ -353,17 +340,17 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) } } - if (options::incrementalSolving() || options::proof()) + if (options::incrementalSolving()) { if (options::sygusInference()) { if (options::sygusInference.wasSetByUser()) { throw OptionException( - "sygus inference not supported with proofs/incremental solving"); + "sygus inference not supported with incremental solving"); } Notice() << "SmtEngine: turning off sygus inference to support " - "proofs/incremental solving" + "incremental solving" << std::endl; options::sygusInference.set(false); } @@ -380,19 +367,18 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) options::bitvectorToBool.set(true); } - // Disable options incompatible with unsat cores and proofs or output an - // error if enabled explicitly - if (options::unsatCores() || options::proof()) + // Disable options incompatible with unsat cores or output an error if enabled + // explicitly + if (options::unsatCores()) { if (options::simplificationMode() != options::SimplificationMode::NONE) { if (options::simplificationMode.wasSetByUser()) { - throw OptionException( - "simplification not supported with unsat cores/proofs"); + throw OptionException("simplification not supported with unsat cores"); } Notice() << "SmtEngine: turning off simplification to support unsat " - "cores/proofs" + "cores" << std::endl; options::simplificationMode.set(options::SimplificationMode::NONE); } @@ -402,10 +388,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) if (options::pbRewrites.wasSetByUser()) { throw OptionException( - "pseudoboolean rewrites not supported with unsat cores/proofs"); + "pseudoboolean rewrites not supported with unsat cores"); } Notice() << "SmtEngine: turning off pseudoboolean rewrites to support " - "unsat cores/proofs" + "unsat cores" << std::endl; options::pbRewrites.set(false); } @@ -414,11 +400,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) { if (options::sortInference.wasSetByUser()) { - throw OptionException( - "sort inference not supported with unsat cores/proofs"); + throw OptionException("sort inference not supported with unsat cores"); } Notice() << "SmtEngine: turning off sort inference to support unsat " - "cores/proofs" + "cores" << std::endl; options::sortInference.set(false); } @@ -428,10 +413,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) if (options::preSkolemQuant.wasSetByUser()) { throw OptionException( - "pre-skolemization not supported with unsat cores/proofs"); + "pre-skolemization not supported with unsat cores"); } Notice() << "SmtEngine: turning off pre-skolemization to support unsat " - "cores/proofs" + "cores" << std::endl; options::preSkolemQuant.set(false); } @@ -441,11 +426,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) { if (options::bitvectorToBool.wasSetByUser()) { - throw OptionException( - "bv-to-bool not supported with unsat cores/proofs"); + throw OptionException("bv-to-bool not supported with unsat cores"); } Notice() << "SmtEngine: turning off bitvector-to-bool to support unsat " - "cores/proofs" + "cores" << std::endl; options::bitvectorToBool.set(false); } @@ -455,10 +439,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) if (options::boolToBitvector.wasSetByUser()) { throw OptionException( - "bool-to-bv != off not supported with unsat cores/proofs"); + "bool-to-bv != off not supported with unsat cores"); } Notice() << "SmtEngine: turning off bool-to-bv to support unsat " - "cores/proofs" + "cores" << std::endl; options::boolToBitvector.set(options::BoolToBVMode::OFF); } @@ -467,11 +451,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) { if (options::bvIntroducePow2.wasSetByUser()) { - throw OptionException( - "bv-intro-pow2 not supported with unsat cores/proofs"); + throw OptionException("bv-intro-pow2 not supported with unsat cores"); } Notice() << "SmtEngine: turning off bv-intro-pow2 to support " - "unsat-cores/proofs" + "unsat-cores" << std::endl; options::bvIntroducePow2.set(false); } @@ -480,11 +463,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) { if (options::repeatSimp.wasSetByUser()) { - throw OptionException( - "repeat-simp not supported with unsat cores/proofs"); + throw OptionException("repeat-simp not supported with unsat cores"); } Notice() << "SmtEngine: turning off repeat-simp to support unsat " - "cores/proofs" + "cores" << std::endl; options::repeatSimp.set(false); } @@ -493,19 +475,17 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) { if (options::globalNegate.wasSetByUser()) { - throw OptionException( - "global-negate not supported with unsat cores/proofs"); + throw OptionException("global-negate not supported with unsat cores"); } Notice() << "SmtEngine: turning off global-negate to support unsat " - "cores/proofs" + "cores" << std::endl; options::globalNegate.set(false); } if (options::bitvectorAig()) { - throw OptionException( - "bitblast-aig not supported with unsat cores/proofs"); + throw OptionException("bitblast-aig not supported with unsat cores"); } } else @@ -626,7 +606,7 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) if (!options::ufSymmetryBreaker.wasSetByUser()) { bool qf_uf_noinc = logic.isPure(THEORY_UF) && !logic.isQuantified() - && !options::incrementalSolving() && !options::proof() + && !options::incrementalSolving() && !options::unsatCores(); Trace("smt") << "setting uf symmetry breaker to " << qf_uf_noinc << std::endl; @@ -848,7 +828,7 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) // Do we need to track instantiations? // Needed for sygus due to single invocation techniques. if (options::cegqiNestedQE() - || (options::proof() && !options::trackInstLemmas.wasSetByUser()) + || (options::unsatCores() && !options::trackInstLemmas.wasSetByUser()) || is_sygus) { options::trackInstLemmas.set(true); @@ -1323,59 +1303,6 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver) options::arraysOptimizeLinear.set(false); } - if (options::proof()) - { - if (options::incrementalSolving()) - { - if (options::incrementalSolving.wasSetByUser()) - { - throw OptionException("--incremental is not supported with proofs"); - } - Warning() - << "SmtEngine: turning off incremental solving mode (not yet " - "supported with --proof, try --tear-down-incremental instead)" - << std::endl; - options::incrementalSolving.set(false); - } - if (logic > LogicInfo("QF_AUFBVLRA")) - { - throw OptionException( - "Proofs are only supported for sub-logics of QF_AUFBVLIA."); - } - if (options::bitvectorAlgebraicSolver()) - { - if (options::bitvectorAlgebraicSolver.wasSetByUser()) - { - throw OptionException( - "--bv-algebraic-solver is not supported with proofs"); - } - Notice() << "SmtEngine: turning off bv algebraic solver to support proofs" - << std::endl; - options::bitvectorAlgebraicSolver.set(false); - } - if (options::bitvectorEqualitySolver()) - { - if (options::bitvectorEqualitySolver.wasSetByUser()) - { - throw OptionException("--bv-eq-solver is not supported with proofs"); - } - Notice() << "SmtEngine: turning off bv eq solver to support proofs" - << std::endl; - options::bitvectorEqualitySolver.set(false); - } - if (options::bitvectorInequalitySolver()) - { - if (options::bitvectorInequalitySolver.wasSetByUser()) - { - throw OptionException( - "--bv-inequality-solver is not supported with proofs"); - } - Notice() << "SmtEngine: turning off bv ineq solver to support proofs" - << std::endl; - options::bitvectorInequalitySolver.set(false); - } - } - if (!options::bitvectorEqualitySolver()) { if (options::bvLazyRewriteExtf()) diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp index 955fe3e14..531dbff0d 100644 --- a/src/smt/smt_engine.cpp +++ b/src/smt/smt_engine.cpp @@ -62,7 +62,6 @@ #include "options/open_ostream.h" #include "options/option_exception.h" #include "options/printer_options.h" -#include "options/proof_options.h" #include "options/prop_options.h" #include "options/quantifiers_options.h" #include "options/sep_options.h" @@ -75,9 +74,7 @@ #include "preprocessing/preprocessing_pass_context.h" #include "preprocessing/preprocessing_pass_registry.h" #include "printer/printer.h" -#include "proof/proof.h" #include "proof/proof_manager.h" -#include "proof/theory_proof.h" #include "proof/unsat_core.h" #include "smt/abduction_solver.h" #include "smt/abstract_values.h" @@ -113,14 +110,9 @@ #include "theory/theory_model.h" #include "theory/theory_traits.h" #include "util/hash.h" -#include "util/proof.h" #include "util/random.h" #include "util/resource_manager.h" -#if (IS_LFSC_BUILD && IS_PROOFS_BUILD) -#include "lfscc.h" -#endif - using namespace std; using namespace CVC4; using namespace CVC4::smt; @@ -131,10 +123,6 @@ using namespace CVC4::theory; namespace CVC4 { -namespace proof { -extern const char* const plf_signatures; -} // namespace proof - namespace smt { }/* namespace CVC4::smt */ @@ -307,15 +295,6 @@ void SmtEngine::finishInit() d_abductSolver.reset(new AbductionSolver(this)); } - PROOF( ProofManager::currentPM()->setLogic(d_logic); ); - PROOF({ - TheoryEngine* te = d_smtSolver->getTheoryEngine(); - for (TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST; ++id) - { - ProofManager::currentPM()->getTheoryProofEngine()->finishRegisterTheory( - te->theoryOf(id)); - } - }); d_pp->finishInit(); AlwaysAssert(getPropEngine()->getAssertionLevel() == 0) @@ -1005,12 +984,6 @@ Result SmtEngine::checkSatInternal(const vector<Node>& assumptions, checkModel(); } } - // Check that UNSAT results generate a proof correctly. - if(options::checkProofs()) { - if(r.asSatisfiabilityResult().isSat() == Result::UNSAT) { - checkProof(); - } - } // Check that UNSAT results generate an unsat core correctly. if(options::checkUnsatCores()) { if(r.asSatisfiabilityResult().isSat() == Result::UNSAT) { @@ -1476,43 +1449,6 @@ Expr SmtEngine::getSepHeapExpr() { return getSepHeapAndNilExpr().first; } Expr SmtEngine::getSepNilExpr() { return getSepHeapAndNilExpr().second; } -void SmtEngine::checkProof() -{ -#if (IS_LFSC_BUILD && IS_PROOFS_BUILD) - - Chat() << "generating proof..." << endl; - - const Proof& pf = getProof(); - - Chat() << "checking proof..." << endl; - - std::string logicString = d_logic.getLogicString(); - - std::stringstream pfStream; - - pfStream << proof::plf_signatures << endl; - int64_t sizeBeforeProof = static_cast<int64_t>(pfStream.tellp()); - - pf.toStream(pfStream); - d_stats->d_proofsSize += - static_cast<int64_t>(pfStream.tellp()) - sizeBeforeProof; - - { - TimerStat::CodeTimer checkProofTimer(d_stats->d_lfscCheckProofTime); - lfscc_init(); - lfscc_check_file(pfStream, false, false, false, false, false, false, false); - } - // FIXME: we should actually call lfscc_cleanup here, but lfscc_cleanup - // segfaults on regress0/bv/core/bitvec7.smt - // lfscc_cleanup(); - -#else /* (IS_LFSC_BUILD && IS_PROOFS_BUILD) */ - Unreachable() - << "This version of CVC4 was built without proof support; cannot check " - "proofs."; -#endif /* (IS_LFSC_BUILD && IS_PROOFS_BUILD) */ -} - UnsatCore SmtEngine::getUnsatCoreInternal() { #if IS_PROOFS_BUILD @@ -1548,7 +1484,6 @@ void SmtEngine::checkUnsatCore() { coreChecker.setIsInternalSubsolver(); coreChecker.setLogic(getLogicInfo()); coreChecker.getOptions().set(options::checkUnsatCores, false); - coreChecker.getOptions().set(options::checkProofs, false); Notice() << "SmtEngine::checkUnsatCore(): pushing core assertions (size == " << core.size() << ")" << endl; for(UnsatCore::iterator i = core.begin(); i != core.end(); ++i) { @@ -1823,32 +1758,6 @@ UnsatCore SmtEngine::getUnsatCore() { return getUnsatCoreInternal(); } -// TODO(#1108): Simplify the error reporting of this method. -const Proof& SmtEngine::getProof() -{ - Trace("smt") << "SMT getProof()" << endl; - SmtScope smts(this); - finishInit(); - if(Dump.isOn("benchmark")) { - Dump("benchmark") << GetProofCommand(); - } -#if IS_PROOFS_BUILD - if(!options::proof()) { - throw ModalException("Cannot get a proof when produce-proofs option is off."); - } - if (d_state->getMode() != SmtMode::UNSAT) - { - throw RecoverableModalException( - "Cannot get a proof unless immediately preceded by UNSAT/ENTAILED " - "response."); - } - - return ProofManager::getProof(this); -#else /* IS_PROOFS_BUILD */ - throw ModalException("This build of CVC4 doesn't have proof support."); -#endif /* IS_PROOFS_BUILD */ -} - void SmtEngine::printInstantiations( std::ostream& out ) { SmtScope smts(this); finishInit(); diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h index 223478e5f..5aa2ba987 100644 --- a/src/smt/smt_engine.h +++ b/src/smt/smt_engine.h @@ -34,7 +34,6 @@ #include "smt/smt_mode.h" #include "theory/logic_info.h" #include "util/hash.h" -#include "util/proof.h" #include "util/result.h" #include "util/sexpr.h" #include "util/statistics.h" @@ -544,16 +543,6 @@ class CVC4_PUBLIC SmtEngine */ std::vector<std::pair<Expr, Expr> > getAssignment(); - /** - * Get the last proof (only if immediately preceded by an UNSAT or ENTAILED - * query). Only permitted if CVC4 was built with proof support and - * produce-proofs is on. - * - * The Proof object is owned by this SmtEngine until the SmtEngine is - * destroyed. - */ - const Proof& getProof(); - /** Print all instantiations made by the quantifiers module. */ void printInstantiations(std::ostream& out); @@ -921,11 +910,6 @@ class CVC4_PUBLIC SmtEngine }; /** - * Check that a generated proof (via getProof()) checks. - */ - void checkProof(); - - /** * Internal method to get an unsatisfiable core (only if immediately preceded * by an UNSAT or ENTAILED query). Only permitted if CVC4 was built with * unsat-core support and produce-unsat-cores is on. Does not dump the diff --git a/src/smt/smt_engine_scope.cpp b/src/smt/smt_engine_scope.cpp index 1e9c91767..cc86ae33c 100644 --- a/src/smt/smt_engine_scope.cpp +++ b/src/smt/smt_engine_scope.cpp @@ -20,7 +20,6 @@ #include "base/check.h" #include "base/configuration_private.h" #include "base/output.h" -#include "proof/proof.h" #include "smt/smt_engine.h" namespace CVC4 { diff --git a/src/smt/smt_engine_stats.cpp b/src/smt/smt_engine_stats.cpp index 9b25580d2..e36284714 100644 --- a/src/smt/smt_engine_stats.cpp +++ b/src/smt/smt_engine_stats.cpp @@ -25,9 +25,7 @@ SmtEngineStatistics::SmtEngineStatistics() d_cnfConversionTime("smt::SmtEngine::cnfConversionTime"), d_numAssertionsPre("smt::SmtEngine::numAssertionsPreITERemoval", 0), d_numAssertionsPost("smt::SmtEngine::numAssertionsPostITERemoval", 0), - d_proofsSize("smt::SmtEngine::proofsSize", 0), d_checkModelTime("smt::SmtEngine::checkModelTime"), - d_lfscCheckProofTime("smt::SmtEngine::lfscCheckProofTime"), d_checkUnsatCoreTime("smt::SmtEngine::checkUnsatCoreTime"), d_solveTime("smt::SmtEngine::solveTime"), d_pushPopTime("smt::SmtEngine::pushPopTime"), @@ -39,9 +37,7 @@ SmtEngineStatistics::SmtEngineStatistics() smtStatisticsRegistry()->registerStat(&d_cnfConversionTime); smtStatisticsRegistry()->registerStat(&d_numAssertionsPre); smtStatisticsRegistry()->registerStat(&d_numAssertionsPost); - smtStatisticsRegistry()->registerStat(&d_proofsSize); smtStatisticsRegistry()->registerStat(&d_checkModelTime); - smtStatisticsRegistry()->registerStat(&d_lfscCheckProofTime); smtStatisticsRegistry()->registerStat(&d_checkUnsatCoreTime); smtStatisticsRegistry()->registerStat(&d_solveTime); smtStatisticsRegistry()->registerStat(&d_pushPopTime); @@ -56,9 +52,7 @@ SmtEngineStatistics::~SmtEngineStatistics() smtStatisticsRegistry()->unregisterStat(&d_cnfConversionTime); smtStatisticsRegistry()->unregisterStat(&d_numAssertionsPre); smtStatisticsRegistry()->unregisterStat(&d_numAssertionsPost); - smtStatisticsRegistry()->unregisterStat(&d_proofsSize); smtStatisticsRegistry()->unregisterStat(&d_checkModelTime); - smtStatisticsRegistry()->unregisterStat(&d_lfscCheckProofTime); smtStatisticsRegistry()->unregisterStat(&d_checkUnsatCoreTime); smtStatisticsRegistry()->unregisterStat(&d_solveTime); smtStatisticsRegistry()->unregisterStat(&d_pushPopTime); diff --git a/src/smt/smt_engine_stats.h b/src/smt/smt_engine_stats.h index 3463a0371..5193d173c 100644 --- a/src/smt/smt_engine_stats.h +++ b/src/smt/smt_engine_stats.h @@ -36,12 +36,8 @@ struct SmtEngineStatistics IntStat d_numAssertionsPre; /** Number of assertions after ite removal */ IntStat d_numAssertionsPost; - /** Size of all proofs generated */ - IntStat d_proofsSize; /** time spent in checkModel() */ TimerStat d_checkModelTime; - /** time spent checking the proof with LFSC */ - TimerStat d_lfscCheckProofTime; /** time spent in checkUnsatCore() */ TimerStat d_checkUnsatCoreTime; /** time spent in PropEngine::checkSat() */ diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index a31d84587..706c18416 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -14,7 +14,6 @@ #include "smt/smt_solver.h" -#include "proof/theory_proof.h" #include "prop/prop_engine.h" #include "smt/assertions.h" #include "smt/preprocessor.h" @@ -58,11 +57,6 @@ void SmtSolver::finishInit(const LogicInfo& logicInfo) ++id) { theory::TheoryConstructor::addTheory(d_theoryEngine.get(), id); - // register with proof engine if applicable -#ifdef CVC4_PROOF - ProofManager::currentPM()->getTheoryProofEngine()->registerTheory( - d_theoryEngine->theoryOf(id)); -#endif } Trace("smt-debug") << "Making prop engine..." << std::endl; @@ -197,7 +191,7 @@ Result SmtSolver::checkSatisfiability(Assertions& as, // set the filename on the result Result r = Result(result, filename); - + // notify our state of the check-sat result d_state.notifyCheckSatResult(hasAssumptions, r); diff --git a/src/smt/term_formula_removal.cpp b/src/smt/term_formula_removal.cpp index 5da190a3d..74fcda668 100644 --- a/src/smt/term_formula_removal.cpp +++ b/src/smt/term_formula_removal.cpp @@ -19,7 +19,7 @@ #include "expr/node_algorithm.h" #include "expr/skolem_manager.h" -#include "options/proof_options.h" +#include "options/smt_options.h" #include "proof/proof_manager.h" using namespace std; @@ -45,16 +45,21 @@ theory::TrustNode RemoveTermFormulas::run( { Node itesRemoved = run(assertion, newAsserts, newSkolems, false, false); // In some calling contexts, not necessary to report dependence information. - if (reportDeps - && (options::unsatCores() || options::fewerPreprocessingHoles())) + if (reportDeps && options::unsatCores()) { // new assertions have a dependence on the node - PROOF(ProofManager::currentPM()->addDependence(itesRemoved, assertion);) + if (options::unsatCores()) + { + ProofManager::currentPM()->addDependence(itesRemoved, assertion); + } unsigned n = 0; while (n < newAsserts.size()) { - PROOF(ProofManager::currentPM()->addDependence(newAsserts[n].getProven(), - assertion);) + if (options::unsatCores()) + { + ProofManager::currentPM()->addDependence(newAsserts[n].getProven(), + assertion); + } ++n; } } @@ -380,7 +385,7 @@ Node RemoveTermFormulas::replace(TNode node, bool inQuant, bool inTerm) const { }else if( !inTerm && hasNestedTermChildren( node ) ){ // Remember if we're inside a term inTerm = true; - } + } vector<Node> newChildren; bool somethingChanged = false; @@ -402,13 +407,14 @@ Node RemoveTermFormulas::replace(TNode node, bool inQuant, bool inTerm) const { } } -// returns true if the children of node should be considered nested terms +// returns true if the children of node should be considered nested terms bool RemoveTermFormulas::hasNestedTermChildren( TNode node ) { - return theory::kindToTheoryId(node.getKind())!=theory::THEORY_BOOL && - node.getKind()!=kind::EQUAL && node.getKind()!=kind::SEP_STAR && - node.getKind()!=kind::SEP_WAND && node.getKind()!=kind::SEP_LABEL && - node.getKind()!=kind::BITVECTOR_EAGER_ATOM; - // dont' worry about FORALL or EXISTS (handled separately) + return theory::kindToTheoryId(node.getKind()) != theory::THEORY_BOOL + && node.getKind() != kind::EQUAL && node.getKind() != kind::SEP_STAR + && node.getKind() != kind::SEP_WAND + && node.getKind() != kind::SEP_LABEL + && node.getKind() != kind::BITVECTOR_EAGER_ATOM; + // dont' worry about FORALL or EXISTS (handled separately) } Node RemoveTermFormulas::getAxiomFor(Node n) diff --git a/src/theory/arith/callbacks.cpp b/src/theory/arith/callbacks.cpp index 758a337ba..f5f8a1a10 100644 --- a/src/theory/arith/callbacks.cpp +++ b/src/theory/arith/callbacks.cpp @@ -16,6 +16,8 @@ **/ #include "theory/arith/callbacks.h" + +#include "theory/arith/proof_macros.h" #include "theory/arith/theory_arith_private.h" namespace CVC4 { @@ -87,17 +89,17 @@ void FarkasConflictBuilder::reset(){ d_consequent = NullConstraint; d_constraints.clear(); d_consequentSet = false; - PROOF(d_farkas.clear()); + ARITH_PROOF(d_farkas.clear()); Assert(!underConstruction()); } /* Adds a constraint to the constraint under construction. */ void FarkasConflictBuilder::addConstraint(ConstraintCP c, const Rational& fc){ Assert( - !PROOF_ON() + !ARITH_PROOF_ON() || (!underConstruction() && d_constraints.empty() && d_farkas.empty()) || (underConstruction() && d_constraints.size() + 1 == d_farkas.size())); - Assert(PROOF_ON() || d_farkas.empty()); + Assert(ARITH_PROOF_ON() || d_farkas.empty()); Assert(c->isTrue()); if(d_consequent == NullConstraint){ @@ -105,17 +107,20 @@ void FarkasConflictBuilder::addConstraint(ConstraintCP c, const Rational& fc){ } else { d_constraints.push_back(c); } - PROOF(d_farkas.push_back(fc);); - Assert(!PROOF_ON() || d_constraints.size() + 1 == d_farkas.size()); - Assert(PROOF_ON() || d_farkas.empty()); + ARITH_PROOF(d_farkas.push_back(fc)); + Assert(!ARITH_PROOF_ON() || d_constraints.size() + 1 == d_farkas.size()); + Assert(ARITH_PROOF_ON() || d_farkas.empty()); } void FarkasConflictBuilder::addConstraint(ConstraintCP c, const Rational& fc, const Rational& mult){ Assert(!mult.isZero()); - if(PROOF_ON() && !mult.isOne()){ + if (ARITH_PROOF_ON() && !mult.isOne()) + { Rational prod = fc * mult; addConstraint(c, prod); - }else{ + } + else + { addConstraint(c, fc); } } @@ -132,7 +137,7 @@ void FarkasConflictBuilder::makeLastConsequent(){ ConstraintCP last = d_constraints.back(); d_constraints.back() = d_consequent; d_consequent = last; - PROOF( std::swap( d_farkas.front(), d_farkas.back() ) ); + ARITH_PROOF(std::swap(d_farkas.front(), d_farkas.back())); d_consequentSet = true; } @@ -145,14 +150,14 @@ ConstraintCP FarkasConflictBuilder::commitConflict(){ Assert(underConstruction()); Assert(!d_constraints.empty()); Assert( - !PROOF_ON() + !ARITH_PROOF_ON() || (!underConstruction() && d_constraints.empty() && d_farkas.empty()) || (underConstruction() && d_constraints.size() + 1 == d_farkas.size())); - Assert(PROOF_ON() || d_farkas.empty()); + Assert(ARITH_PROOF_ON() || d_farkas.empty()); Assert(d_consequentSet); ConstraintP not_c = d_consequent->getNegation(); - RationalVectorCP coeffs = NULLPROOF(&d_farkas); + RationalVectorCP coeffs = ARITH_NULLPROOF(&d_farkas); not_c->impliedByFarkas(d_constraints, coeffs, true ); reset(); diff --git a/src/theory/arith/constraint.cpp b/src/theory/arith/constraint.cpp index 6a04e70d1..081bc08a7 100644 --- a/src/theory/arith/constraint.cpp +++ b/src/theory/arith/constraint.cpp @@ -21,7 +21,6 @@ #include <unordered_set> #include "base/output.h" -#include "proof/proof.h" #include "smt/smt_statistics_registry.h" #include "theory/arith/arith_utilities.h" #include "theory/arith/normal_form.h" @@ -551,46 +550,49 @@ bool Constraint::hasTrichotomyProof() const { void Constraint::printProofTree(std::ostream& out, size_t depth) const { -#if IS_PROOFS_BUILD - const ConstraintRule& rule = getConstraintRule(); - out << std::string(2 * depth, ' ') << "* " << getVariable() << " ["; - if (hasLiteral()) + if (ARITH_PROOF_ON()) { - out << getLiteral(); - } - else - { - out << "NOLIT"; - }; - out << "]" << ' ' << getType() << ' ' << getValue() << " (" << getProofType() - << ")"; - if (getProofType() == FarkasAP) - { - out << " ["; - bool first = true; - for (const auto& coeff : *rule.d_farkasCoefficients) + const ConstraintRule& rule = getConstraintRule(); + out << std::string(2 * depth, ' ') << "* " << getVariable() << " ["; + if (hasLiteral()) { - if (not first) + out << getLiteral(); + } + else + { + out << "NOLIT"; + }; + out << "]" << ' ' << getType() << ' ' << getValue() << " (" + << getProofType() << ")"; + if (getProofType() == FarkasAP) + { + out << " ["; + bool first = true; + for (const auto& coeff : *rule.d_farkasCoefficients) { - out << ", "; + if (not first) + { + out << ", "; + } + first = false; + out << coeff; } - first = false; - out << coeff; + out << "]"; } - out << "]"; - } - out << endl; + out << endl; - for (AntecedentId i = rule.d_antecedentEnd; i != AntecedentIdSentinel; --i) { - ConstraintCP antecdent = d_database->getAntecedent(i); - if (antecdent == NullConstraint) { - break; + for (AntecedentId i = rule.d_antecedentEnd; i != AntecedentIdSentinel; --i) + { + ConstraintCP antecdent = d_database->getAntecedent(i); + if (antecdent == NullConstraint) + { + break; + } + antecdent->printProofTree(out, depth + 1); } - antecdent->printProofTree(out, depth + 1); + return; } -#else /* IS_PROOFS_BUILD */ out << "Cannot print proof. This is not a proof build." << endl; -#endif /* IS_PROOFS_BUILD */ } bool Constraint::sanityChecking(Node n) const { @@ -648,8 +650,7 @@ ConstraintCP ConstraintDatabase::getAntecedent (AntecedentId p) const { void ConstraintRule::print(std::ostream& out) const { - - RationalVectorCP coeffs = NULLPROOF(d_farkasCoefficients); + RationalVectorCP coeffs = ARITH_NULLPROOF(d_farkasCoefficients); out << "{ConstraintRule, "; out << d_constraint << std::endl; out << "d_proofType= " << d_proofType << ", " << std::endl; @@ -658,7 +659,7 @@ void ConstraintRule::print(std::ostream& out) const { if (d_constraint != NullConstraint && d_antecedentEnd != AntecedentIdSentinel) { const ConstraintDatabase& database = d_constraint->getDatabase(); - + size_t coeffIterator = (coeffs != RationalVectorCPSentinel) ? coeffs->size()-1 : 0; AntecedentId p = d_antecedentEnd; // must have at least one antecedent @@ -700,9 +701,11 @@ bool Constraint::wellFormedFarkasProof() const { ConstraintCP antecedent = d_database->d_antecedents[p]; if(antecedent == NullConstraint) { return false; } -#if IS_PROOFS_BUILD - if(!PROOF_ON()){ return cr.d_farkasCoefficients == RationalVectorCPSentinel; } - Assert(PROOF_ON()); + if (!ARITH_PROOF_ON()) + { + return cr.d_farkasCoefficients == RationalVectorCPSentinel; + } + Assert(ARITH_PROOF_ON()); if(cr.d_farkasCoefficients == RationalVectorCPSentinel){ return false; } if(cr.d_farkasCoefficients->size() < 2){ return false; } @@ -755,7 +758,7 @@ bool Constraint::wellFormedFarkasProof() const { default: return false; } - + if(coeffIterator == coeffBegin){ return false; } --coeffIterator; --p; @@ -800,10 +803,6 @@ bool Constraint::wellFormedFarkasProof() const { // 0 = lhs <= rhs < 0 return (lhs.isNull() || (Constant::isMember(lhs) && Constant(lhs).isZero())) && rhs.sgn() < 0; - -#else /* IS_PROOFS_BUILD */ - return true; -#endif /* IS_PROOFS_BUILD */ } ConstraintP Constraint::makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r){ @@ -860,7 +859,6 @@ ConstraintDatabase::ConstraintDatabase(context::Context* satContext, context::Co , d_one(1) , d_negOne(-1) { - } SortedConstraintMap& ConstraintDatabase::getVariableSCM(ArithVar v) const{ @@ -1109,7 +1107,7 @@ ConstraintP ConstraintDatabase::addLiteral(TNode literal){ return isNot ? hit->getNegation(): hit; }else{ Comparison negCmp = Comparison::parseNormalForm(negationNode); - + ConstraintType negType = Constraint::constraintTypeOfComparison(negCmp); DeltaRational negDR = negCmp.normalizedDeltaRational(); @@ -1213,7 +1211,8 @@ void Constraint::impliedByUnate(ConstraintCP imp, bool nowInConflict){ AntecedentId antecedentEnd = d_database->d_antecedents.size() - 1; RationalVectorP coeffs; - if(PROOF_ON()){ + if (ARITH_PROOF_ON()) + { std::pair<int, int> sgns = unateFarkasSigns(getNegation(), imp); Rational first(sgns.first); @@ -1222,10 +1221,11 @@ void Constraint::impliedByUnate(ConstraintCP imp, bool nowInConflict){ coeffs = new RationalVector(); coeffs->push_back(first); coeffs->push_back(second); - } else { + } + else + { coeffs = RationalVectorPSentinel; } - // no need to delete coeffs the memory is owned by ConstraintRule d_database->pushConstraintRule(ConstraintRule(this, FarkasAP, antecedentEnd, coeffs)); @@ -1233,7 +1233,7 @@ void Constraint::impliedByUnate(ConstraintCP imp, bool nowInConflict){ if(Debug.isOn("constraint::conflictCommit") && inConflict()){ Debug("constraint::conflictCommit") << "inConflict@impliedByUnate " << this << std::endl; } - + if(Debug.isOn("constraints::wffp") && !wellFormedFarkasProof()){ getConstraintRule().print(Debug("constraints::wffp")); } @@ -1343,7 +1343,7 @@ void Constraint::impliedByIntHole(const ConstraintCPVec& b, bool nowInConflict){ * coeffs != RationalVectorSentinal, * coeffs->size() = a.size() + 1, * for i in [0,a.size) : coeff[i] corresponds to a[i], and - * coeff.back() corresponds to the current constraint. + * coeff.back() corresponds to the current constraint. */ void Constraint::impliedByFarkas(const ConstraintCPVec& a, RationalVectorCP coeffs, bool nowInConflict){ Debug("constraints::pf") << "impliedByFarkas(" << this; @@ -1359,10 +1359,9 @@ void Constraint::impliedByFarkas(const ConstraintCPVec& a, RationalVectorCP coef Assert(negationHasProof() == nowInConflict); Assert(allHaveProof(a)); - Assert(PROOF_ON() == (coeffs != RationalVectorCPSentinel)); - // !PROOF_ON() => coeffs == RationalVectorCPSentinel - // PROOF_ON() => coeffs->size() == a.size() + 1 - Assert(!PROOF_ON() || coeffs->size() == a.size() + 1); + Assert(ARITH_PROOF_ON() == (coeffs != RationalVectorCPSentinel)); + Assert(!ARITH_PROOF_ON() || coeffs->size() == a.size() + 1); + Assert(a.size() >= 1); d_database->d_antecedents.push_back(NullConstraint); @@ -1374,10 +1373,13 @@ void Constraint::impliedByFarkas(const ConstraintCPVec& a, RationalVectorCP coef AntecedentId antecedentEnd = d_database->d_antecedents.size() - 1; RationalVectorCP coeffsCopy; - if(PROOF_ON()){ + if (ARITH_PROOF_ON()) + { Assert(coeffs != RationalVectorCPSentinel); coeffsCopy = new RationalVector(*coeffs); - } else { + } + else + { coeffsCopy = RationalVectorCPSentinel; } d_database->pushConstraintRule(ConstraintRule(this, FarkasAP, antecedentEnd, coeffsCopy)); diff --git a/src/theory/arith/constraint.h b/src/theory/arith/constraint.h index b32616a04..3caccdebd 100644 --- a/src/theory/arith/constraint.h +++ b/src/theory/arith/constraint.h @@ -75,9 +75,9 @@ #ifndef CVC4__THEORY__ARITH__CONSTRAINT_H #define CVC4__THEORY__ARITH__CONSTRAINT_H -#include <unordered_map> #include <list> #include <set> +#include <unordered_map> #include <vector> #include "base/configuration_private.h" @@ -85,12 +85,12 @@ #include "context/cdqueue.h" #include "context/context.h" #include "expr/node.h" -#include "proof/proof.h" #include "theory/arith/arithvar.h" #include "theory/arith/callbacks.h" #include "theory/arith/congruence_manager.h" #include "theory/arith/constraint_forward.h" #include "theory/arith/delta_rational.h" +#include "theory/arith/proof_macros.h" namespace CVC4 { namespace theory { @@ -252,11 +252,11 @@ struct PerVariableDatabase{ } }; - /** * If proofs are on, there is a vector of rationals for farkas coefficients. - * This is the owner of the memory for the vector, and calls delete upon cleanup. - * + * This is the owner of the memory for the vector, and calls delete upon + * cleanup. + * */ struct ConstraintRule { ConstraintP d_constraint; @@ -302,17 +302,13 @@ struct ConstraintRule { * We do however use all of the constraints by requiring non-zero * coefficients. */ -#if IS_PROOFS_BUILD RationalVectorCP d_farkasCoefficients; -#endif /* IS_PROOFS_BUILD */ ConstraintRule() : d_constraint(NullConstraint) , d_proofType(NoAP) , d_antecedentEnd(AntecedentIdSentinel) { -#if IS_PROOFS_BUILD d_farkasCoefficients = RationalVectorCPSentinel; -#endif /* IS_PROOFS_BUILD */ } ConstraintRule(ConstraintP con, ArithProofType pt) @@ -320,18 +316,14 @@ struct ConstraintRule { , d_proofType(pt) , d_antecedentEnd(AntecedentIdSentinel) { -#if IS_PROOFS_BUILD d_farkasCoefficients = RationalVectorCPSentinel; -#endif /* IS_PROOFS_BUILD */ } ConstraintRule(ConstraintP con, ArithProofType pt, AntecedentId antecedentEnd) : d_constraint(con) , d_proofType(pt) , d_antecedentEnd(antecedentEnd) { -#if IS_PROOFS_BUILD d_farkasCoefficients = RationalVectorCPSentinel; -#endif /* IS_PROOFS_BUILD */ } ConstraintRule(ConstraintP con, ArithProofType pt, AntecedentId antecedentEnd, RationalVectorCP coeffs) @@ -339,10 +331,8 @@ struct ConstraintRule { , d_proofType(pt) , d_antecedentEnd(antecedentEnd) { - Assert(PROOF_ON() || coeffs == RationalVectorCPSentinel); -#if IS_PROOFS_BUILD + Assert(ARITH_PROOF_ON() || coeffs == RationalVectorCPSentinel); d_farkasCoefficients = coeffs; -#endif /* IS_PROOFS_BUILD */ } void print(std::ostream& out) const; @@ -750,7 +740,7 @@ class Constraint { /** * If the constraint - * canBePropagated() and + * canBePropagated() and * !assertedToTheTheory(), * the constraint is added to the database's propagation queue. * @@ -789,9 +779,11 @@ class Constraint { ConstraintP constraint = crp->d_constraint; Assert(constraint->d_crid != ConstraintRuleIdSentinel); constraint->d_crid = ConstraintRuleIdSentinel; - - PROOF(if (crp->d_farkasCoefficients != RationalVectorCPSentinel) { - delete crp->d_farkasCoefficients; + ARITH_PROOF({ + if (crp->d_farkasCoefficients != RationalVectorCPSentinel) + { + delete crp->d_farkasCoefficients; + } }); } }; @@ -876,10 +868,11 @@ class Constraint { return getConstraintRule().d_antecedentEnd; } - inline RationalVectorCP getFarkasCoefficients() const { - return NULLPROOF(getConstraintRule().d_farkasCoefficients); + inline RationalVectorCP getFarkasCoefficients() const + { + return ARITH_NULLPROOF(getConstraintRule().d_farkasCoefficients); } - + void debugPrint() const; /** @@ -1051,8 +1044,7 @@ private: * The index in this list is the proper ordering of the proofs. */ ConstraintRuleList d_constraintProofs; - - + /** * Contains the exact list of constraints that can be used for propagation. */ @@ -1100,9 +1092,9 @@ private: const Rational d_one; const Rational d_negOne; - + friend class Constraint; - + public: ConstraintDatabase( context::Context* satContext, @@ -1209,7 +1201,7 @@ public: /** AntecendentID must be in range. */ ConstraintCP getAntecedent(AntecedentId p) const; - + private: /** returns true if cons is now in conflict. */ bool handleUnateProp(ConstraintP ant, ConstraintP cons); diff --git a/src/theory/arith/linear_equality.cpp b/src/theory/arith/linear_equality.cpp index 7eb2f3f9e..3c4f678a2 100644 --- a/src/theory/arith/linear_equality.cpp +++ b/src/theory/arith/linear_equality.cpp @@ -510,11 +510,11 @@ void LinearEqualityModule::propagateBasicFromRow(ConstraintP c){ RowIndex ridx = d_tableau.basicToRowIndex(basic); ConstraintCPVec bounds; - RationalVectorP coeffs = NULLPROOF(new RationalVector()); + RationalVectorP coeffs = ARITH_NULLPROOF(new RationalVector()); propagateRow(bounds, ridx, upperBound, c, coeffs); c->impliedByFarkas(bounds, coeffs, false); c->tryToPropagate(); - + if(coeffs != RationalVectorPSentinel) { delete coeffs; } } @@ -524,9 +524,9 @@ void LinearEqualityModule::propagateBasicFromRow(ConstraintP c){ * The proof is in terms of the other constraints and the negation of c, ~c. * * A row has the form: - * sum a_i * x_i = 0 + * sum a_i * x_i = 0 * or - * sx + sum r y + sum q z = 0 + * sx + sum r y + sum q z = 0 * where r > 0 and q < 0. * * If rowUp, we are proving c @@ -555,7 +555,7 @@ void LinearEqualityModule::propagateRow(ConstraintCPVec& into, RowIndex ridx, bo Assert(farkas->empty()); farkas->push_back(Rational(0)); } - + ArithVar v = c->getVariable(); Debug("arith::propagateRow") << "LinearEqualityModule::propagateRow(" << ridx << ", " << rowUp << ", " << v << ") start" << endl; @@ -563,7 +563,7 @@ void LinearEqualityModule::propagateRow(ConstraintCPVec& into, RowIndex ridx, bo const Rational& multiple = rowUp ? d_one : d_negOne; Debug("arith::propagateRow") << "multiple: " << multiple << endl; - + Tableau::RowIterator iter = d_tableau.ridRowIterator(ridx); for(; !iter.atEnd(); ++iter){ const Tableau::Entry& entry = *iter; @@ -595,8 +595,8 @@ void LinearEqualityModule::propagateRow(ConstraintCPVec& into, RowIndex ridx, bo if(farkas != RationalVectorPSentinel){ Assert(farkas->front().isZero()); Rational multAij = multiple * a_ij; - Debug("arith::propagateRow") << "("<<multAij<<") "; - farkas->front() = multAij; + Debug("arith::propagateRow") << "(" << multAij << ") "; + farkas->front() = multAij; } Debug("arith::propagateRow") << c << endl; @@ -605,10 +605,10 @@ void LinearEqualityModule::propagateRow(ConstraintCPVec& into, RowIndex ridx, bo ConstraintCP bound = selectUb ? d_variables.getUpperBoundConstraint(nonbasic) : d_variables.getLowerBoundConstraint(nonbasic); - + if(farkas != RationalVectorPSentinel){ Rational multAij = multiple * a_ij; - Debug("arith::propagateRow") << "("<<multAij<<") "; + Debug("arith::propagateRow") << "(" << multAij << ") "; farkas->push_back(multAij); } Assert(bound != NullConstraint); @@ -678,7 +678,7 @@ ConstraintP LinearEqualityModule::weakestExplanation(bool aboveUpper, DeltaRatio * If !aboveUpper, then the conflict is with the constraint c : x_b >= l_b. * * A row has the form: - * -x_b sum a_i * x_i = 0 + * -x_b sum a_i * x_i = 0 * or * -x_b + sum r y + sum q z = 0, * x_b = sum r y + sum q z @@ -724,7 +724,7 @@ ConstraintCP LinearEqualityModule::minimallyWeakConflict(bool aboveUpper, ArithV Assert(assignment < d_variables.getLowerBound(basicVar)); surplus = d_variables.getLowerBound(basicVar) - assignment; } - + bool anyWeakenings = false; for(Tableau::RowIterator i = d_tableau.basicRowIterator(basicVar); !i.atEnd(); ++i){ const Tableau::Entry& entry = *i; diff --git a/src/theory/arith/nl/nl_model.cpp b/src/theory/arith/nl/nl_model.cpp index cc10d6659..cfa153a56 100644 --- a/src/theory/arith/nl/nl_model.cpp +++ b/src/theory/arith/nl/nl_model.cpp @@ -16,6 +16,7 @@ #include "expr/node_algorithm.h" #include "options/arith_options.h" +#include "options/smt_options.h" #include "options/theory_options.h" #include "theory/arith/arith_msum.h" #include "theory/arith/arith_utilities.h" diff --git a/src/theory/arith/theory_arith.cpp b/src/theory/arith/theory_arith.cpp index ea751ca74..762634ce7 100644 --- a/src/theory/arith/theory_arith.cpp +++ b/src/theory/arith/theory_arith.cpp @@ -41,7 +41,6 @@ TheoryArith::TheoryArith(context::Context* c, d_internal( new TheoryArithPrivate(*this, c, u, out, valuation, logicInfo, pnm)), d_ppRewriteTimer("theory::arith::ppRewriteTimer"), - d_proofRecorder(nullptr), d_astate(*d_internal, c, u, valuation) { smtStatisticsRegistry()->registerStat(&d_ppRewriteTimer); diff --git a/src/theory/arith/theory_arith.h b/src/theory/arith/theory_arith.h index bfe30db61..6adf8f66a 100644 --- a/src/theory/arith/theory_arith.h +++ b/src/theory/arith/theory_arith.h @@ -18,7 +18,6 @@ #pragma once #include "expr/node.h" -#include "proof/arith_proof_recorder.h" #include "theory/arith/arith_state.h" #include "theory/arith/theory_arith_private_forward.h" #include "theory/theory.h" @@ -41,11 +40,6 @@ class TheoryArith : public Theory { TimerStat d_ppRewriteTimer; - /** - * @brief Where to store Farkas proofs of lemmas - */ - proof::ArithProofRecorder * d_proofRecorder; - public: TheoryArith(context::Context* c, context::UserContext* u, @@ -110,11 +104,6 @@ class TheoryArith : public Theory { std::pair<bool, Node> entailmentCheck(TNode lit) override; - void setProofRecorder(proof::ArithProofRecorder* proofRecorder) - { - d_proofRecorder = proofRecorder; - } - private: /** The state object wrapping TheoryArithPrivate */ ArithState d_astate; diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp index 7f521e2f9..8a780116c 100644 --- a/src/theory/arith/theory_arith_private.cpp +++ b/src/theory/arith/theory_arith_private.cpp @@ -624,7 +624,7 @@ bool TheoryArithPrivate::AssertLower(ConstraintP constraint){ ConstraintP ubc = d_partialModel.getUpperBoundConstraint(x_i); ConstraintP negation = constraint->getNegation(); negation->impliedByUnate(ubc, true); - + raiseConflict(constraint); ++(d_statistics.d_statAssertLowerConflicts); @@ -757,7 +757,7 @@ bool TheoryArithPrivate::AssertUpper(ConstraintP constraint){ if(d_partialModel.greaterThanUpperBound(x_i, c_i) ){ // \upperbound(x_i) <= c_i return false; //sat } - + // cmpToLb = \lowerbound(x_i).cmp(c_i) int cmpToLB = d_partialModel.cmpToLowerBound(x_i, c_i); if( cmpToLB < 0 ){ // \upperbound(x_i) < \lowerbound(x_i) @@ -802,7 +802,7 @@ bool TheoryArithPrivate::AssertUpper(ConstraintP constraint){ ++(d_statistics.d_statDisequalityConflicts); raiseConflict(eq); return true; - } + } } }else if(cmpToLB > 0){ // l <= x <= u and l < u @@ -1291,8 +1291,10 @@ void TheoryArithPrivate::setupVariableList(const VarList& vl){ }else{ if (d_nonlinearExtension == nullptr) { - if( vlNode.getKind()==kind::EXPONENTIAL || vlNode.getKind()==kind::SINE || - vlNode.getKind()==kind::COSINE || vlNode.getKind()==kind::TANGENT ){ + if (vlNode.getKind() == kind::EXPONENTIAL + || vlNode.getKind() == kind::SINE || vlNode.getKind() == kind::COSINE + || vlNode.getKind() == kind::TANGENT) + { d_nlIncomplete = true; } } @@ -1737,7 +1739,6 @@ ConstraintP TheoryArithPrivate::constraintFromFactQueue(){ } else { Debug("arith::constraint") << "already has proof: " << constraint->externalExplainByAssertions() << endl; } - if(Debug.isOn("arith::negatedassumption") && inConflict){ ConstraintP negation = constraint->getNegation(); @@ -1905,7 +1906,7 @@ void TheoryArithPrivate::outputConflicts(){ Debug("arith::conflict") << "outputting conflicts" << std::endl; Assert(anyConflict()); static unsigned int conflicts = 0; - + if(!conflictQueueEmpty()){ Assert(!d_conflicts.empty()); for(size_t i = 0, i_end = d_conflicts.size(); i < i_end; ++i){ @@ -1923,35 +1924,6 @@ void TheoryArithPrivate::outputConflicts(){ ++conflicts; Debug("arith::conflict") << "d_conflicts[" << i << "] " << conflict << " has proof: " << hasProof << endl; - PROOF(if (d_containing.d_proofRecorder && confConstraint->hasFarkasProof() - && pf.d_farkasCoefficients->size() - == conflict.getNumChildren()) { - // The Farkas coefficients and the children of `conflict` seem to be in - // opposite orders... There is some relevant documentation in the - // comment for the d_farkasCoefficients field in "constraint.h" - // - // Anyways, we reverse the children in `conflict` here. - NodeBuilder<> conflictInFarkasCoefficientOrder(kind::AND); - for (size_t j = 0, nchildren = conflict.getNumChildren(); j < nchildren; - ++j) - { - conflictInFarkasCoefficientOrder - << conflict[conflict.getNumChildren() - j - 1]; - } - - if (Debug.isOn("arith::pf::tree")) { - confConstraint->printProofTree(Debug("arith::pf::tree")); - confConstraint->getNegation()->printProofTree(Debug("arith::pf::tree")); - } - - Assert(conflict.getNumChildren() == pf.d_farkasCoefficients->size()); - if (confConstraint->hasSimpleFarkasProof() - && confConstraint->getNegation()->isPossiblyTightenedAssumption()) - { - d_containing.d_proofRecorder->saveFarkasCoefficients( - conflictInFarkasCoefficientOrder, pf.d_farkasCoefficients); - } - }) if(Debug.isOn("arith::normalize::external")){ conflict = flattenAndSort(conflict); Debug("arith::conflict") << "(normalized to) " << conflict << endl; @@ -2190,7 +2162,6 @@ std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(const D return make_pair(imp, added); } } - ConstraintP newc = d_constraintDatabase.getConstraint(v, t, dr); d_replayConstraints.push_back(newc); @@ -2337,7 +2308,7 @@ void TheoryArithPrivate::tryBranchCut(ApproximateSimplex* approx, int nid, Branc // ConstraintCPVec& back = conflicts.back(); // back.push_back(conflicting); // back.push_back(negConflicting); - + // // remove the floor/ceiling contraint implied by bcneg // Constraint::assertionFringe(back); } @@ -2375,14 +2346,15 @@ void TheoryArithPrivate::replayAssert(ConstraintP c) { }else{ Debug("approx::replayAssert") << "replayAssert " << c << " has explanation" << endl; } - Debug("approx::replayAssert") << "replayAssertion " << c << endl; + Debug("approx::replayAssert") << "replayAssertion " << c << endl; if(inConflict){ raiseConflict(c); }else{ assertionCases(c); } }else{ - Debug("approx::replayAssert") << "replayAssert " << c << " already asserted" << endl; + Debug("approx::replayAssert") + << "replayAssert " << c << " already asserted" << endl; } } @@ -2551,7 +2523,7 @@ std::vector<ConstraintCPVec> TheoryArithPrivate::replayLogRec(ApproximateSimplex SimplexDecisionProcedure& simplex = selectSimplex(true); simplex.findModel(false); - // can change d_qflraStatus + // can change d_qflraStatus d_linEq.stopTrackingBoundCounts(); d_partialModel.startQueueingBoundCounts(); @@ -3101,13 +3073,13 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){ << " " << useApprox << " " << safeToCallApprox() << endl; - + bool noPivotLimitPass1 = noPivotLimit && !useApprox; d_qflraStatus = simplex.findModel(noPivotLimitPass1); Debug("TheoryArithPrivate::solveRealRelaxation") << "solveRealRelaxation()" << " pass1 " << d_qflraStatus << endl; - + if(d_qflraStatus == Result::SAT_UNKNOWN && useApprox && safeToCallApprox()){ // pass2: fancy-final static const int32_t relaxationLimit = 10000; @@ -3275,7 +3247,6 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){ // if(!useFancyFinal){ // d_qflraStatus = simplex.findModel(noPivotLimit); // }else{ - // if(d_qflraStatus == Result::SAT_UNKNOWN){ // //Message() << "got sat unknown" << endl; @@ -3711,7 +3682,7 @@ Node TheoryArithPrivate::branchIntegerVariable(ArithVar x) const { Integer ceil_d = d.ceiling(); Rational f = r - floor_d; // Multiply by -1 to get abs value. - Rational c = (r - ceil_d) * (-1); + Rational c = (r - ceil_d) * (-1); Integer nearest = (c > f) ? floor_d : ceil_d; // Prioritize trying a simple rounding of the real solution first, @@ -4651,7 +4622,6 @@ bool TheoryArithPrivate::tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, b ConstraintP implied = d_constraintDatabase.getBestImpliedBound(v, t, bound); if(implied != NullConstraint){ - return rowImplicationCanBeApplied(ridx, rowUp, implied); } } @@ -4699,9 +4669,8 @@ bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, C if( !assertedToTheTheory && canBePropagated && !hasProof ){ ConstraintCPVec explain; - - PROOF(d_farkasBuffer.clear()); - RationalVectorP coeffs = NULLPROOF(&d_farkasBuffer); + ARITH_PROOF(d_farkasBuffer.clear()); + RationalVectorP coeffs = ARITH_NULLPROOF(&d_farkasBuffer); // After invoking `propegateRow`: // * coeffs[0] is for implied @@ -4716,38 +4685,6 @@ bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, C } Node implication = implied->externalImplication(explain); Node clause = flattenImplication(implication); - PROOF(if (d_containing.d_proofRecorder - && coeffs != RationalVectorCPSentinel - && coeffs->size() == clause.getNumChildren()) { - Debug("arith::prop") << "implied : " << implied << std::endl; - Debug("arith::prop") << "implication: " << implication << std::endl; - Debug("arith::prop") << "coeff len: " << coeffs->size() << std::endl; - Debug("arith::prop") << "exp : " << explain << std::endl; - Debug("arith::prop") << "clause : " << clause << std::endl; - Debug("arith::prop") - << "clause len: " << clause.getNumChildren() << std::endl; - Debug("arith::prop") << "exp len: " << explain.size() << std::endl; - // Using the information from the above comment we assemble a conflict - // AND in coefficient order - NodeBuilder<> conflictInFarkasCoefficientOrder(kind::AND); - conflictInFarkasCoefficientOrder << implication[1].negate(); - for (const Node& antecedent : implication[0]) - { - Debug("arith::prop") << " ante: " << antecedent << std::endl; - conflictInFarkasCoefficientOrder << antecedent; - } - - Assert(coeffs != RationalVectorPSentinel); - Assert(conflictInFarkasCoefficientOrder.getNumChildren() - == coeffs->size()); - if (std::all_of(explain.begin(), explain.end(), [](ConstraintCP c) { - return c->isAssumption() || c->hasIntTightenProof(); - })) - { - d_containing.d_proofRecorder->saveFarkasCoefficients( - conflictInFarkasCoefficientOrder, coeffs); - } - }) outputLemma(clause); }else{ Assert(!implied->negationHasProof()); diff --git a/src/theory/arrays/array_proof_reconstruction.cpp b/src/theory/arrays/array_proof_reconstruction.cpp deleted file mode 100644 index abc4857e8..000000000 --- a/src/theory/arrays/array_proof_reconstruction.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/********************* */ -/*! \file array_proof_reconstruction.cpp - ** \verbatim - ** Top contributors (to current version): - ** Guy Katz, Tim King - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** [[ Add lengthier description here ]] - - ** \todo document this file - -**/ - -#include "theory/arrays/array_proof_reconstruction.h" - -#include <memory> - -namespace CVC4 { -namespace theory { -namespace arrays { - -ArrayProofReconstruction::ArrayProofReconstruction(const eq::EqualityEngine* equalityEngine) - : d_equalityEngine(equalityEngine) { -} - -void ArrayProofReconstruction::setRowMergeTag(unsigned tag) { - d_reasonRow = tag; -} - -void ArrayProofReconstruction::setRow1MergeTag(unsigned tag) { - d_reasonRow1 = tag; -} - -void ArrayProofReconstruction::setExtMergeTag(unsigned tag) { - d_reasonExt = tag; -} - -void ArrayProofReconstruction::notify( - unsigned reasonType, Node reason, Node a, Node b, - std::vector<TNode>& equalities, eq::EqProof* proof) const { - Debug("pf::array") << "ArrayProofReconstruction::notify( " - << reason << ", " << a << ", " << b << std::endl; - - - if (reasonType == d_reasonExt) { - if (proof) { - // Todo: here we assume that a=b is an assertion. We should probably call - // explain() recursively, to explain this. - std::shared_ptr<eq::EqProof> childProof = std::make_shared<eq::EqProof>(); - childProof->d_node = reason; - proof->d_children.push_back(childProof); - } - } - - else if (reasonType == d_reasonRow) { - // ROW rules mean that (i==k) OR ((a[i]:=t)[k] == a[k]) - // The equality here will be either (i == k) because ((a[i]:=t)[k] != a[k]), - // or ((a[i]:=t)[k] == a[k]) because (i != k). - - if (proof) { - if (a.getKind() == kind::SELECT) { - // This is the case of ((a[i]:=t)[k] == a[k]) because (i != k). - - // The edge is ((a[i]:=t)[k], a[k]), or (a[k], (a[i]:=t)[k]). This flag should be - // false in the first case and true in the second case. - bool currentNodeIsUnchangedArray; - - Assert(a.getNumChildren() == 2); - Assert(b.getNumChildren() == 2); - - if (a[0].getKind() == kind::VARIABLE || a[0].getKind() == kind::SKOLEM) { - currentNodeIsUnchangedArray = true; - } else if (b[0].getKind() == kind::VARIABLE || b[0].getKind() == kind::SKOLEM) { - currentNodeIsUnchangedArray = false; - } else { - Assert(a[0].getKind() == kind::STORE); - Assert(b[0].getKind() == kind::STORE); - - if (a[0][0] == b[0]) { - currentNodeIsUnchangedArray = false; - } else if (b[0][0] == a[0]) { - currentNodeIsUnchangedArray = true; - } else { - Unreachable(); - } - } - - Node indexOne = currentNodeIsUnchangedArray ? a[1] : a[0][1]; - Node indexTwo = currentNodeIsUnchangedArray ? b[0][1] : b[1]; - - // Some assertions to ensure that the theory of arrays behaves as expected - Assert(a[1] == b[1]); - if (currentNodeIsUnchangedArray) { - Assert(a[0] == b[0][0]); - } else { - Assert(a[0][0] == b[0]); - } - - Debug("pf::ee") << "Getting explanation for ROW guard: " - << indexOne << " != " << indexTwo << std::endl; - - std::shared_ptr<eq::EqProof> childProof = - std::make_shared<eq::EqProof>(); - d_equalityEngine->explainEquality(indexOne, indexTwo, false, equalities, - childProof.get()); - - // It could be that the guard condition is a constant disequality. In - // this case, we need to change it to a different format. - bool haveNegChild = false; - for (unsigned i = 0; i < childProof->d_children.size(); ++i) { - if (childProof->d_children[i]->d_node.getKind() == kind::NOT) - haveNegChild = true; - } - - if ((childProof->d_children.size() != 0) && - (childProof->d_id == theory::eq::MERGED_THROUGH_CONSTANTS || !haveNegChild)) { - // The proof has two children, explaining why each index is a (different) constant. - Assert(childProof->d_children.size() == 2); - - Node constantOne, constantTwo; - // Each subproof explains why one of the indices is constant. - - if (childProof->d_children[0]->d_id == theory::eq::MERGED_THROUGH_REFLEXIVITY) { - constantOne = childProof->d_children[0]->d_node; - } else { - Assert(childProof->d_children[0]->d_node.getKind() == kind::EQUAL); - if ((childProof->d_children[0]->d_node[0] == indexOne) || - (childProof->d_children[0]->d_node[0] == indexTwo)) { - constantOne = childProof->d_children[0]->d_node[1]; - } else { - constantOne = childProof->d_children[0]->d_node[0]; - } - } - - if (childProof->d_children[1]->d_id == theory::eq::MERGED_THROUGH_REFLEXIVITY) { - constantTwo = childProof->d_children[1]->d_node; - } else { - Assert(childProof->d_children[1]->d_node.getKind() == kind::EQUAL); - if ((childProof->d_children[1]->d_node[0] == indexOne) || - (childProof->d_children[1]->d_node[0] == indexTwo)) { - constantTwo = childProof->d_children[1]->d_node[1]; - } else { - constantTwo = childProof->d_children[1]->d_node[0]; - } - } - - std::shared_ptr<eq::EqProof> constantDisequalityProof = - std::make_shared<eq::EqProof>(); - constantDisequalityProof->d_id = theory::eq::MERGED_THROUGH_CONSTANTS; - constantDisequalityProof->d_node = - NodeManager::currentNM()->mkNode(kind::EQUAL, constantOne, constantTwo).negate(); - - // Middle is where we need to insert the new disequality - std::vector<std::shared_ptr<eq::EqProof>>::iterator middle = - childProof->d_children.begin(); - ++middle; - - childProof->d_children.insert(middle, constantDisequalityProof); - - childProof->d_id = theory::eq::MERGED_THROUGH_TRANS; - childProof->d_node = - NodeManager::currentNM()->mkNode(kind::EQUAL, indexOne, indexTwo).negate(); - } - - proof->d_children.push_back(childProof); - } else { - // This is the case of (i == k) because ((a[i]:=t)[k] != a[k]), - - Node indexOne = a; - Node indexTwo = b; - - Debug("pf::ee") << "The two indices are: " << indexOne << ", " << indexTwo << std::endl - << "The reason for the edge is: " << reason << std::endl; - - Assert(reason.getNumChildren() == 2); - Debug("pf::ee") << "Getting explanation for ROW guard: " << reason[1] << std::endl; - - std::shared_ptr<eq::EqProof> childProof = - std::make_shared<eq::EqProof>(); - d_equalityEngine->explainEquality(reason[1][0], reason[1][1], false, - equalities, childProof.get()); - proof->d_children.push_back(childProof); - } - } - - } - - else if (reasonType == d_reasonRow1) { - // No special handling required at this time - } -} - -}/* CVC4::theory::arrays namespace */ -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ diff --git a/src/theory/arrays/array_proof_reconstruction.h b/src/theory/arrays/array_proof_reconstruction.h deleted file mode 100644 index a73b5dd08..000000000 --- a/src/theory/arrays/array_proof_reconstruction.h +++ /dev/null @@ -1,59 +0,0 @@ -/********************* */ -/*! \file array_proof_reconstruction.h - ** \verbatim - ** Top contributors (to current version): - ** Paul Meng, Mathias Preiner, Tim King - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. See the file COPYING in the top-level source - ** directory for licensing information.\endverbatim - ** - ** \brief Array-specific proof construction logic to be used during the - ** equality engine's path reconstruction - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__THEORY__ARRAYS__ARRAY_PROOF_RECONSTRUCTION_H -#define CVC4__THEORY__ARRAYS__ARRAY_PROOF_RECONSTRUCTION_H - -#include "theory/uf/equality_engine.h" - -namespace CVC4 { -namespace theory { -namespace arrays { - -/** - * A callback class to be invoked whenever the equality engine traverses - * an "array-owned" edge during path reconstruction. - */ - -class ArrayProofReconstruction : public eq::PathReconstructionNotify { -public: - ArrayProofReconstruction(const eq::EqualityEngine* equalityEngine); - - void notify(unsigned reasonType, Node reason, Node a, Node b, - std::vector<TNode>& equalities, - eq::EqProof* proof) const override; - - void setRowMergeTag(unsigned tag); - void setRow1MergeTag(unsigned tag); - void setExtMergeTag(unsigned tag); - -private: - /** Merge tag for ROW applications */ - unsigned d_reasonRow; - /** Merge tag for ROW1 applications */ - unsigned d_reasonRow1; - /** Merge tag for EXT applications */ - unsigned d_reasonExt; - - const eq::EqualityEngine* d_equalityEngine; -}; /* class ArrayProofReconstruction */ - -}/* CVC4::theory::arrays namespace */ -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ - -#endif /* CVC4__THEORY__ARRAYS__ARRAY_PROOF_RECONSTRUCTION_H */ diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp index 3adcd4f49..603dc9639 100644 --- a/src/theory/arrays/theory_arrays.cpp +++ b/src/theory/arrays/theory_arrays.cpp @@ -23,9 +23,6 @@ #include "expr/node_algorithm.h" #include "options/arrays_options.h" #include "options/smt_options.h" -#include "proof/array_proof.h" -#include "proof/proof_manager.h" -#include "proof/theory_proof.h" #include "smt/command.h" #include "smt/logic_exception.h" #include "smt/smt_statistics_registry.h" @@ -111,7 +108,6 @@ TheoryArrays::TheoryArrays(context::Context* c, d_readTableContext(new context::Context()), d_arrayMerges(c), d_inCheckModel(false), - d_proofReconstruction(nullptr), d_dstrat(new TheoryArraysDecisionStrategy(this)), d_dstratInit(false) { @@ -183,22 +179,6 @@ void TheoryArrays::finishInit() { d_equalityEngine->addFunctionKind(kind::ARR_TABLE_FUN); } - - d_proofReconstruction.reset(new ArrayProofReconstruction(d_equalityEngine)); - d_reasonRow = d_equalityEngine->getFreshMergeReasonType(); - d_reasonRow1 = d_equalityEngine->getFreshMergeReasonType(); - d_reasonExt = d_equalityEngine->getFreshMergeReasonType(); - - d_proofReconstruction->setRowMergeTag(d_reasonRow); - d_proofReconstruction->setRow1MergeTag(d_reasonRow1); - d_proofReconstruction->setExtMergeTag(d_reasonExt); - - d_equalityEngine->addPathReconstructionTrigger(d_reasonRow, - d_proofReconstruction.get()); - d_equalityEngine->addPathReconstructionTrigger(d_reasonRow1, - d_proofReconstruction.get()); - d_equalityEngine->addPathReconstructionTrigger(d_reasonExt, - d_proofReconstruction.get()); } ///////////////////////////////////////////////////////////////////////////// @@ -440,37 +420,6 @@ bool TheoryArrays::propagateLit(TNode literal) }/* TheoryArrays::propagate(TNode) */ -void TheoryArrays::explain(TNode literal, std::vector<TNode>& assumptions, - eq::EqProof* proof) { - // Do the work - bool polarity = literal.getKind() != kind::NOT; - TNode atom = polarity ? literal : literal[0]; - //eq::EqProof * eqp = new eq::EqProof; - // eq::EqProof * eqp = NULL; - if (atom.getKind() == kind::EQUAL) { - d_equalityEngine->explainEquality( - atom[0], atom[1], polarity, assumptions, proof); - } else { - d_equalityEngine->explainPredicate(atom, polarity, assumptions, proof); - } - if (Debug.isOn("pf::array")) - { - if (proof) - { - Debug("pf::array") << " Proof is : " << std::endl; - proof->debug_print("pf::array"); - } - - Debug("pf::array") << "Array: explain( " << literal << " ):" << std::endl - << "\t"; - for (unsigned i = 0; i < assumptions.size(); ++i) - { - Debug("pf::array") << assumptions[i] << " "; - } - Debug("pf::array") << std::endl; - } -} - TNode TheoryArrays::weakEquivGetRep(TNode node) { TNode pointer; while (true) { @@ -795,7 +744,8 @@ void TheoryArrays::preRegisterTermInternal(TNode node) } // Apply RIntro1 Rule - d_equalityEngine->assertEquality(ni.eqNode(v), true, d_true, d_reasonRow1); + d_equalityEngine->assertEquality( + ni.eqNode(v), true, d_true, theory::eq::MERGED_THROUGH_ROW1); d_infoMap.addStore(node, node); d_infoMap.addInStore(a, node); @@ -864,19 +814,32 @@ void TheoryArrays::preRegisterTerm(TNode node) } } -TrustNode TheoryArrays::explain(TNode literal) +void TheoryArrays::explain(TNode literal, Node& explanation) { - Node explanation = explain(literal, NULL); - return TrustNode::mkTrustPropExp(literal, explanation, nullptr); -} - -Node TheoryArrays::explain(TNode literal, eq::EqProof* proof) { ++d_numExplain; Debug("arrays") << spaces(getSatContext()->getLevel()) << "TheoryArrays::explain(" << literal << ")" << std::endl; std::vector<TNode> assumptions; - explain(literal, assumptions, proof); - return mkAnd(assumptions); + // Do the work + bool polarity = literal.getKind() != kind::NOT; + TNode atom = polarity ? literal : literal[0]; + if (atom.getKind() == kind::EQUAL) + { + d_equalityEngine->explainEquality( + atom[0], atom[1], polarity, assumptions, nullptr); + } + else + { + d_equalityEngine->explainPredicate(atom, polarity, assumptions, nullptr); + } + explanation = mkAnd(assumptions); +} + +TrustNode TheoryArrays::explain(TNode literal) +{ + Node explanation; + explain(literal, explanation); + return TrustNode::mkTrustPropExp(literal, explanation, nullptr); } ///////////////////////////////////////////////////////////////////////////// @@ -1329,49 +1292,20 @@ void TheoryArrays::check(Effort e) { TNode k; // k is the skolem for this disequality. - if (!d_proofsEnabled) { - Debug("pf::array") << "Check: kind::NOT: array theory making a skolem" << std::endl; - - // If not in replay mode, generate a fresh skolem variable - k = getSkolem(fact, - "array_ext_index", - indexType, - "an extensional lemma index variable from the theory of arrays", - false); - - // Register this skolem for the proof replay phase - PROOF(ProofManager::getSkolemizationManager()->registerSkolem(fact, k)); - } else { - if (!ProofManager::getSkolemizationManager()->hasSkolem(fact)) { - // In the solution pass we didn't need this skolem. Therefore, we don't need it - // in this reply pass, either. - break; - } - - // Reuse the same skolem as in the solution pass - k = ProofManager::getSkolemizationManager()->getSkolem(fact); - Debug("pf::array") << "Skolem = " << k << std::endl; - } - + Debug("pf::array") + << "Check: kind::NOT: array theory making a skolem" + << std::endl; + k = getSkolem( + fact, + "array_ext_index", + indexType, + "an extensional lemma index variable from the theory of arrays", + false); Node ak = nm->mkNode(kind::SELECT, fact[0][0], k); Node bk = nm->mkNode(kind::SELECT, fact[0][1], k); Node eq = ak.eqNode(bk); Node lemma = fact[0].orNode(eq.notNode()); - // In solve mode we don't care if ak and bk are registered. If they aren't, they'll be registered - // when we output the lemma. However, in replay need the lemma to be propagated, and so we - // preregister manually. - if (d_proofsEnabled) { - if (!d_equalityEngine->hasTerm(ak)) - { - preRegisterTermInternal(ak); - } - if (!d_equalityEngine->hasTerm(bk)) - { - preRegisterTermInternal(bk); - } - } - if (options::arraysPropagate() > 0 && d_equalityEngine->hasTerm(ak) && d_equalityEngine->hasTerm(bk)) { @@ -1381,17 +1315,16 @@ void TheoryArrays::check(Effort e) { << "\teq = " << eq << std::endl << "\treason = " << fact << std::endl; - d_equalityEngine->assertEquality(eq, false, fact, d_reasonExt); + d_equalityEngine->assertEquality( + eq, false, fact, theory::eq::MERGED_THROUGH_EXT); ++d_numProp; } - if (!d_proofsEnabled) { - // If this is the solution pass, generate the lemma. Otherwise, don't generate it - - // as this is the lemma that we're reproving... - Trace("arrays-lem")<<"Arrays::addExtLemma " << lemma <<"\n"; - d_out->lemma(lemma); - ++d_numExt; - } + // If this is the solution pass, generate the lemma. Otherwise, + // don't generate it - as this is the lemma that we're reproving... + Trace("arrays-lem") << "Arrays::addExtLemma " << lemma << "\n"; + d_out->lemma(lemma); + ++d_numExt; } else { Debug("pf::array") << "Check: kind::NOT: array theory NOT making a skolem" << std::endl; d_modelConstraints.push_back(fact); @@ -1480,7 +1413,7 @@ void TheoryArrays::check(Effort e) { lemma = mkAnd(conjunctions, true); // LSH FIXME: which kind of arrays lemma is this Trace("arrays-lem") << "Arrays::addExtLemma " << lemma <<"\n"; - d_out->lemma(lemma, RULE_INVALID, LemmaProperty::SEND_ATOMS); + d_out->lemma(lemma, LemmaProperty::SEND_ATOMS); d_readTableContext->pop(); Trace("arrays") << spaces(getSatContext()->getLevel()) << "Arrays::check(): done" << endl; return; @@ -1908,7 +1841,8 @@ void TheoryArrays::propagate(RowLemmaType lem) if (!bjExists) { preRegisterTermInternal(bj); } - d_equalityEngine->assertEquality(aj_eq_bj, true, reason, d_reasonRow); + d_equalityEngine->assertEquality( + aj_eq_bj, true, reason, theory::eq::MERGED_THROUGH_ROW); ++d_numProp; return; } @@ -1919,7 +1853,8 @@ void TheoryArrays::propagate(RowLemmaType lem) (aj.isConst() && bj.isConst()) ? d_true : aj.eqNode(bj).notNode(); Node i_eq_j = i.eqNode(j); d_permRef.push_back(reason); - d_equalityEngine->assertEquality(i_eq_j, true, reason, d_reasonRow); + d_equalityEngine->assertEquality( + i_eq_j, true, reason, theory::eq::MERGED_THROUGH_ROW); ++d_numProp; return; } @@ -1971,19 +1906,18 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem) && !d_equalityEngine->areDisequal(i, j, false)) { Node i_eq_j; - if (!d_proofsEnabled) { - i_eq_j = d_valuation.ensureLiteral(i.eqNode(j)); // TODO: think about this - } else { - i_eq_j = i.eqNode(j); - } - + i_eq_j = d_valuation.ensureLiteral(i.eqNode(j)); // TODO: think about this +#if 0 + i_eq_j = i.eqNode(j); +#endif getOutputChannel().requirePhase(i_eq_j, true); d_decisionRequests.push(i_eq_j); } // TODO: maybe add triggers here - if ((options::arraysEagerLemmas() || bothExist) && !d_proofsEnabled) { + if (options::arraysEagerLemmas() || bothExist) + { // Make sure that any terms introduced by rewriting are appropriately stored in the equality database Node aj2 = Rewriter::rewrite(aj); if (aj != aj2) { @@ -2162,23 +2096,11 @@ bool TheoryArrays::dischargeLemmas() void TheoryArrays::conflict(TNode a, TNode b) { Debug("pf::array") << "TheoryArrays::Conflict called" << std::endl; - std::shared_ptr<eq::EqProof> proof = d_proofsEnabled ? - std::make_shared<eq::EqProof>() : nullptr; - d_conflictNode = explain(a.eqNode(b), proof.get()); + explain(a.eqNode(b), d_conflictNode); if (!d_inCheckModel) { - std::unique_ptr<ProofArray> proof_array; - - if (d_proofsEnabled) { - proof->debug_print("pf::array"); - proof_array.reset(new ProofArray(proof, - /*row=*/d_reasonRow, - /*row1=*/d_reasonRow1, - /*ext=*/d_reasonExt)); - } - - d_out->conflict(d_conflictNode, std::move(proof_array)); + d_out->conflict(d_conflictNode); } d_conflict = true; diff --git a/src/theory/arrays/theory_arrays.h b/src/theory/arrays/theory_arrays.h index 9044b9950..8fdbde0ab 100644 --- a/src/theory/arrays/theory_arrays.h +++ b/src/theory/arrays/theory_arrays.h @@ -26,7 +26,6 @@ #include "context/cdhashset.h" #include "context/cdqueue.h" #include "theory/arrays/array_info.h" -#include "theory/arrays/array_proof_reconstruction.h" #include "theory/arrays/theory_arrays_rewriter.h" #include "theory/theory.h" #include "theory/uf/equality_engine.h" @@ -129,15 +128,6 @@ class TheoryArrays : public Theory { /** conflicts in setModelVal */ IntStat d_numSetModelValConflicts; - // Merge reason types - - /** Merge tag for ROW applications */ - unsigned d_reasonRow; - /** Merge tag for ROW1 applications */ - unsigned d_reasonRow1; - /** Merge tag for EXT applications */ - unsigned d_reasonExt; - public: TheoryArrays(context::Context* c, context::UserContext* u, @@ -215,9 +205,8 @@ class TheoryArrays : public Theory { /** Should be called to propagate the literal. */ bool propagateLit(TNode literal); - /** Explain why this literal is true by adding assumptions */ - void explain(TNode literal, std::vector<TNode>& assumptions, - eq::EqProof* proof); + /** Explain why this literal is true by building an explanation */ + void explain(TNode literal, Node& exp); /** For debugging only- checks invariants about when things are preregistered*/ context::CDHashSet<Node, NodeHashFunction > d_isPreRegistered; @@ -227,7 +216,6 @@ class TheoryArrays : public Theory { public: void preRegisterTerm(TNode n) override; - Node explain(TNode n, eq::EqProof* proof); TrustNode explain(TNode n) override; ///////////////////////////////////////////////////////////////////////////// @@ -446,9 +434,6 @@ class TheoryArrays : public Theory { bool d_inCheckModel; int d_topLevel; - /** An equality-engine callback for proof reconstruction */ - std::unique_ptr<ArrayProofReconstruction> d_proofReconstruction; - /** * The decision strategy for the theory of arrays, which calls the * getNextDecisionEngineRequest function below. diff --git a/src/theory/bv/bitblast/aig_bitblaster.h b/src/theory/bv/bitblast/aig_bitblaster.h index 1e1b5bab4..fef45cdf5 100644 --- a/src/theory/bv/bitblast/aig_bitblaster.h +++ b/src/theory/bv/bitblast/aig_bitblaster.h @@ -89,12 +89,6 @@ class AigBitblaster : public TBitblaster<Abc_Obj_t*> prop::SatSolver* getSatSolver() override { return d_satSolver.get(); } - void setProofLog(proof::BitVectorProof* bvp) override - { - // Proofs are currently not supported with ABC - Unimplemented(); - } - class Statistics { public: diff --git a/src/theory/bv/bitblast/bitblaster.h b/src/theory/bv/bitblast/bitblaster.h index defc66b74..74e3c3f56 100644 --- a/src/theory/bv/bitblast/bitblaster.h +++ b/src/theory/bv/bitblast/bitblaster.h @@ -24,8 +24,8 @@ #include <vector> #include "expr/node.h" -#include "proof/bitvector_proof.h" #include "prop/bv_sat_solver_notify.h" +#include "prop/sat_solver.h" #include "prop/sat_solver_types.h" #include "smt/smt_engine_scope.h" #include "theory/bv/bitblast/bitblast_strategies_template.h" @@ -64,7 +64,6 @@ class TBitblaster // sat solver used for bitblasting and associated CnfStream std::unique_ptr<context::Context> d_nullContext; std::unique_ptr<prop::CnfStream> d_cnfStream; - proof::BitVectorProof* d_bvp; void initAtomBBStrategies(); void initTermBBStrategies(); @@ -91,7 +90,6 @@ class TBitblaster bool hasBBTerm(TNode node) const; void getBBTerm(TNode node, Bits& bits) const; virtual void storeBBTerm(TNode term, const Bits& bits); - virtual void setProofLog(proof::BitVectorProof* bvp); /** * Return a constant representing the value of a in the model. @@ -186,8 +184,7 @@ TBitblaster<T>::TBitblaster() : d_termCache(), d_modelCache(), d_nullContext(new context::Context()), - d_cnfStream(), - d_bvp(nullptr) + d_cnfStream() { initAtomBBStrategies(); initTermBBStrategies(); @@ -218,20 +215,6 @@ void TBitblaster<T>::invalidateModelCache() } template <class T> -void TBitblaster<T>::setProofLog(proof::BitVectorProof* bvp) -{ - if (THEORY_PROOF_ON()) - { - d_bvp = bvp; - prop::SatSolver* satSolver = getSatSolver(); - bvp->attachToSatSolver(*satSolver); - prop::SatVariable t = satSolver->trueVar(); - prop::SatVariable f = satSolver->falseVar(); - bvp->initCnfProof(d_cnfStream.get(), d_nullContext.get(), t, f); - } -} - -template <class T> Node TBitblaster<T>::getTermModel(TNode node, bool fullModel) { if (d_modelCache.find(node) != d_modelCache.end()) return d_modelCache[node]; diff --git a/src/theory/bv/bitblast/eager_bitblaster.cpp b/src/theory/bv/bitblast/eager_bitblaster.cpp index 4acd1d2f8..627a17bc5 100644 --- a/src/theory/bv/bitblast/eager_bitblaster.cpp +++ b/src/theory/bv/bitblast/eager_bitblaster.cpp @@ -72,7 +72,7 @@ EagerBitblaster::EagerBitblaster(TheoryBV* theory_bv, context::Context* c) d_bitblastingRegistrar.get(), d_nullContext.get(), rm, - options::proof(), + false, "EagerBitblaster")); } @@ -87,8 +87,7 @@ void EagerBitblaster::bbFormula(TNode node) } else { - d_cnfStream->convertAndAssert( - node, false, false, RULE_INVALID, TNode::null()); + d_cnfStream->convertAndAssert(node, false, false); } } @@ -116,10 +115,7 @@ void EagerBitblaster::bbAtom(TNode node) ? d_atomBBStrategies[normalized.getKind()](normalized, this) : normalized; - if (!options::proof()) - { - atom_bb = Rewriter::rewrite(atom_bb); - } + atom_bb = Rewriter::rewrite(atom_bb); // asserting that the atom is true iff the definition holds Node atom_definition = @@ -127,21 +123,14 @@ void EagerBitblaster::bbAtom(TNode node) AlwaysAssert(options::bitblastMode() == options::BitblastMode::EAGER); storeBBAtom(node, atom_bb); - d_cnfStream->convertAndAssert( - atom_definition, false, false, RULE_INVALID, TNode::null()); + d_cnfStream->convertAndAssert(atom_definition, false, false); } void EagerBitblaster::storeBBAtom(TNode atom, Node atom_bb) { - 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)); } diff --git a/src/theory/bv/bitblast/eager_bitblaster.h b/src/theory/bv/bitblast/eager_bitblaster.h index a8b7ccbe5..da9488d43 100644 --- a/src/theory/bv/bitblast/eager_bitblaster.h +++ b/src/theory/bv/bitblast/eager_bitblaster.h @@ -23,8 +23,6 @@ #include "theory/bv/bitblast/bitblaster.h" -#include "proof/bitvector_proof.h" -#include "proof/resolution_bitvector_proof.h" #include "prop/cnf_stream.h" #include "prop/sat_solver.h" diff --git a/src/theory/bv/bitblast/lazy_bitblaster.cpp b/src/theory/bv/bitblast/lazy_bitblaster.cpp index 83e286f10..3109d6ed7 100644 --- a/src/theory/bv/bitblast/lazy_bitblaster.cpp +++ b/src/theory/bv/bitblast/lazy_bitblaster.cpp @@ -19,7 +19,6 @@ #include "theory/bv/bitblast/lazy_bitblaster.h" #include "options/bv_options.h" -#include "proof/proof_manager.h" #include "prop/cnf_stream.h" #include "prop/sat_solver.h" #include "prop/sat_solver_factory.h" @@ -84,7 +83,7 @@ TLazyBitblaster::TLazyBitblaster(context::Context* c, d_nullRegistrar.get(), d_nullContext.get(), rm, - options::proof(), + false, "LazyBitblaster")); d_satSolverNotify.reset( @@ -161,8 +160,7 @@ void TLazyBitblaster::bbAtom(TNode node) Assert(!atom_bb.isNull()); Node atom_definition = nm->mkNode(kind::EQUAL, node, atom_bb); storeBBAtom(node, atom_bb); - d_cnfStream->convertAndAssert( - atom_definition, false, false, RULE_INVALID, TNode::null()); + d_cnfStream->convertAndAssert(atom_definition, false, false); return; } @@ -173,28 +171,19 @@ void TLazyBitblaster::bbAtom(TNode node) ? d_atomBBStrategies[normalized.getKind()](normalized, this) : normalized; - if (!options::proof()) - { - atom_bb = Rewriter::rewrite(atom_bb); - } + atom_bb = Rewriter::rewrite(atom_bb); // asserting that the atom is true iff the definition holds Node atom_definition = nm->mkNode(kind::EQUAL, node, atom_bb); storeBBAtom(node, atom_bb); - d_cnfStream->convertAndAssert( - atom_definition, false, false, RULE_INVALID, TNode::null()); + d_cnfStream->convertAndAssert(atom_definition, false, false); } void TLazyBitblaster::storeBBAtom(TNode atom, Node atom_bb) { - // 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)); } diff --git a/src/theory/bv/bitblast/lazy_bitblaster.h b/src/theory/bv/bitblast/lazy_bitblaster.h index a355d42c4..bc930aec4 100644 --- a/src/theory/bv/bitblast/lazy_bitblaster.h +++ b/src/theory/bv/bitblast/lazy_bitblaster.h @@ -19,7 +19,6 @@ #ifndef CVC4__THEORY__BV__BITBLAST__LAZY_BITBLASTER_H #define CVC4__THEORY__BV__BITBLAST__LAZY_BITBLASTER_H -#include "proof/resolution_bitvector_proof.h" #include "theory/bv/bitblast/bitblaster.h" #include "context/cdhashmap.h" diff --git a/src/theory/bv/bv_eager_solver.cpp b/src/theory/bv/bv_eager_solver.cpp index 36aa72da3..d1490374d 100644 --- a/src/theory/bv/bv_eager_solver.cpp +++ b/src/theory/bv/bv_eager_solver.cpp @@ -33,8 +33,7 @@ EagerBitblastSolver::EagerBitblastSolver(context::Context* c, TheoryBV* bv) d_bitblaster(), d_aigBitblaster(), d_useAig(options::bitvectorAig()), - d_bv(bv), - d_bvp(nullptr) + d_bv(bv) { } @@ -55,10 +54,6 @@ void EagerBitblastSolver::initialize() { #endif } else { d_bitblaster.reset(new EagerBitblaster(d_bv, d_context)); - THEORY_PROOF(if (d_bvp) { - d_bitblaster->setProofLog(d_bvp); - d_bvp->setBitblaster(d_bitblaster.get()); - }); } } @@ -127,11 +122,6 @@ bool EagerBitblastSolver::collectModelInfo(TheoryModel* m, bool fullModel) return d_bitblaster->collectModelInfo(m, fullModel); } -void EagerBitblastSolver::setProofLog(proof::BitVectorProof* bvp) -{ - d_bvp = bvp; -} - } // namespace bv } // namespace theory } // namespace CVC4 diff --git a/src/theory/bv/bv_eager_solver.h b/src/theory/bv/bv_eager_solver.h index 6182832e9..e0b55c23b 100644 --- a/src/theory/bv/bv_eager_solver.h +++ b/src/theory/bv/bv_eager_solver.h @@ -23,7 +23,6 @@ #include <vector> #include "expr/node.h" -#include "proof/resolution_bitvector_proof.h" #include "theory/bv/theory_bv.h" #include "theory/theory_model.h" @@ -48,7 +47,6 @@ class EagerBitblastSolver { bool isInitialized(); void initialize(); bool collectModelInfo(theory::TheoryModel* m, bool fullModel); - void setProofLog(proof::BitVectorProof* bvp); private: context::CDHashSet<Node, NodeHashFunction> d_assertionSet; @@ -61,7 +59,6 @@ class EagerBitblastSolver { bool d_useAig; TheoryBV* d_bv; - proof::BitVectorProof* d_bvp; }; // class EagerBitblastSolver } // namespace bv diff --git a/src/theory/bv/bv_subtheory.h b/src/theory/bv/bv_subtheory.h index 725b61f95..f4b88b719 100644 --- a/src/theory/bv/bv_subtheory.h +++ b/src/theory/bv/bv_subtheory.h @@ -25,10 +25,6 @@ namespace CVC4 { -namespace proof { -class BitVectorProof; -} - namespace theory { class TheoryModel; @@ -72,7 +68,6 @@ class SubtheorySolver { SubtheorySolver(context::Context* c, TheoryBV* bv) : d_context(c), d_bv(bv), - d_bvp(nullptr), d_assertionQueue(c), d_assertionIndex(c, 0) {} virtual ~SubtheorySolver() {} @@ -93,7 +88,7 @@ class SubtheorySolver { return res; } virtual void assertFact(TNode fact) { d_assertionQueue.push_back(fact); } - virtual void setProofLog(proof::BitVectorProof* bvp) {} + AssertionQueue::const_iterator assertionsBegin() { return d_assertionQueue.begin(); } @@ -107,8 +102,6 @@ class SubtheorySolver { /** The bit-vector theory */ TheoryBV* d_bv; - /** proof log */ - proof::ResolutionBitVectorProof* d_bvp; AssertionQueue d_assertionQueue; context::CDO<uint32_t> d_assertionIndex; }; /* class SubtheorySolver */ diff --git a/src/theory/bv/bv_subtheory_bitblast.cpp b/src/theory/bv/bv_subtheory_bitblast.cpp index 8f87bc4b8..28c70a5b8 100644 --- a/src/theory/bv/bv_subtheory_bitblast.cpp +++ b/src/theory/bv/bv_subtheory_bitblast.cpp @@ -18,7 +18,6 @@ #include "decision/decision_attributes.h" #include "options/bv_options.h" #include "options/decision_options.h" -#include "proof/proof_manager.h" #include "smt/smt_statistics_registry.h" #include "theory/bv/abstraction.h" #include "theory/bv/bitblast/lazy_bitblaster.h" @@ -276,12 +275,6 @@ void BitblastSolver::setConflict(TNode conflict) { d_bv->setConflict(final_conflict); } -void BitblastSolver::setProofLog(proof::BitVectorProof* bvp) -{ - d_bitblaster->setProofLog( bvp ); - bvp->setBitblaster(d_bitblaster.get()); -} - }/* 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 a2b099609..60ef08d93 100644 --- a/src/theory/bv/bv_subtheory_bitblast.h +++ b/src/theory/bv/bv_subtheory_bitblast.h @@ -24,10 +24,6 @@ namespace CVC4 { -namespace proof { -class ResolutionBitVectorProof; -} - namespace theory { namespace bv { @@ -79,7 +75,6 @@ public: void bitblastQueue(); void setAbstraction(AbstractionModule* module); uint64_t computeAtomWeight(TNode atom); - void setProofLog(proof::BitVectorProof* bvp) override; }; } /* namespace CVC4::theory::bv */ diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp index 1696d6185..d6492f177 100644 --- a/src/theory/bv/theory_bv.cpp +++ b/src/theory/bv/theory_bv.cpp @@ -18,8 +18,6 @@ #include "expr/node_algorithm.h" #include "options/bv_options.h" #include "options/smt_options.h" -#include "proof/proof_manager.h" -#include "proof/theory_proof.h" #include "smt/smt_statistics_registry.h" #include "theory/bv/abstraction.h" #include "theory/bv/bv_eager_solver.h" @@ -83,19 +81,19 @@ TheoryBV::TheoryBV(context::Context* c, return; } - if (options::bitvectorEqualitySolver() && !options::proof()) + if (options::bitvectorEqualitySolver()) { d_subtheories.emplace_back(new CoreSolver(c, this, d_extTheory.get())); d_subtheoryMap[SUB_CORE] = d_subtheories.back().get(); } - if (options::bitvectorInequalitySolver() && !options::proof()) + if (options::bitvectorInequalitySolver()) { d_subtheories.emplace_back(new InequalitySolver(c, u, this)); d_subtheoryMap[SUB_INEQUALITY] = d_subtheories.back().get(); } - if (options::bitvectorAlgebraicSolver() && !options::proof()) + if (options::bitvectorAlgebraicSolver()) { d_subtheories.emplace_back(new AlgebraicSolver(c, this)); d_subtheoryMap[SUB_ALGEBRAIC] = d_subtheories.back().get(); @@ -230,8 +228,11 @@ TrustNode TheoryBV::expandDefinition(Node node) TNode num = node[0], den = node[1]; Node den_eq_0 = nm->mkNode(kind::EQUAL, den, utils::mkZero(width)); - Node divTotalNumDen = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL : - kind::BITVECTOR_UREM_TOTAL, num, den); + Node divTotalNumDen = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV + ? kind::BITVECTOR_UDIV_TOTAL + : kind::BITVECTOR_UREM_TOTAL, + num, + den); Node divByZero = getBVDivByZero(node.getKind(), width); Node divByZeroNum = nm->mkNode(kind::APPLY_UF, divByZero, num); ret = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen); @@ -327,7 +328,7 @@ void TheoryBV::check(Effort e) if (done() && e<Theory::EFFORT_FULL) { return; } - + //last call : do reductions on extended bitvector functions if (e == Theory::EFFORT_LAST_CALL) { std::vector<Node> nred = d_extTheory->getActive(); @@ -410,7 +411,7 @@ void TheoryBV::check(Effort e) break; } } - + //check extended functions if (Theory::fullEffort(e)) { //do inferences (adds external lemmas) TODO: this can be improved to add internal inferences @@ -431,7 +432,9 @@ void TheoryBV::check(Effort e) if( doExtfReductions( nred ) ){ return; } - }else{ + } + else + { d_needsLastCallCheck = true; } } @@ -726,11 +729,13 @@ TrustNode TheoryBV::ppRewrite(TNode t) } else if (RewriteRule<UltPlusOne>::applies(t)) { Node result = RewriteRule<UltPlusOne>::run<false>(t); res = Rewriter::rewrite(result); - } else if( res.getKind() == kind::EQUAL && - ((res[0].getKind() == kind::BITVECTOR_PLUS && - RewriteRule<ConcatToMult>::applies(res[1])) || - (res[1].getKind() == kind::BITVECTOR_PLUS && - RewriteRule<ConcatToMult>::applies(res[0])))) { + } + else if (res.getKind() == kind::EQUAL + && ((res[0].getKind() == kind::BITVECTOR_PLUS + && RewriteRule<ConcatToMult>::applies(res[1])) + || (res[1].getKind() == kind::BITVECTOR_PLUS + && RewriteRule<ConcatToMult>::applies(res[0])))) + { Node mult = RewriteRule<ConcatToMult>::applies(res[0])? RewriteRule<ConcatToMult>::run<false>(res[0]) : RewriteRule<ConcatToMult>::run<true>(res[1]); @@ -743,9 +748,13 @@ TrustNode TheoryBV::ppRewrite(TNode t) } else { res = t; } - } else if (RewriteRule<SignExtendEqConst>::applies(t)) { + } + else if (RewriteRule<SignExtendEqConst>::applies(t)) + { res = RewriteRule<SignExtendEqConst>::run<false>(t); - } else if (RewriteRule<ZeroExtendEqConst>::applies(t)) { + } + else if (RewriteRule<ZeroExtendEqConst>::applies(t)) + { res = RewriteRule<ZeroExtendEqConst>::run<false>(t); } else if (RewriteRule<NormalizeEqPlusNeg>::applies(t)) @@ -960,20 +969,6 @@ bool TheoryBV::applyAbstraction(const std::vector<Node>& assertions, std::vector return changed; } -void TheoryBV::setProofLog(proof::BitVectorProof* bvp) -{ - if (options::bitblastMode() == options::BitblastMode::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()) diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h index c6e9282f4..2f63f1a52 100644 --- a/src/theory/bv/theory_bv.h +++ b/src/theory/bv/theory_bv.h @@ -32,12 +32,7 @@ #include "util/hash.h" #include "util/statistics_registry.h" -// Forward declarations, needed because the BV theory and the BV Proof classes -// are cyclically dependent namespace CVC4 { -namespace proof { -class BitVectorProof; -} namespace theory { @@ -123,8 +118,6 @@ class TheoryBV : public Theory { bool applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions); - void setProofLog(proof::BitVectorProof* bvp); - private: class Statistics { @@ -197,7 +190,7 @@ class TheoryBV : public Theory { std::unique_ptr<EagerBitblastSolver> d_eagerSolver; std::unique_ptr<AbstractionModule> d_abstractionModule; bool d_calledPreregister; - + //for extended functions bool d_needsLastCallCheck; context::CDHashSet<Node, NodeHashFunction> d_extf_range_infer; @@ -225,7 +218,7 @@ class TheoryBV : public Theory { * (ite ((_ extract 1 0) x) 1 0) */ bool doExtfReductions( std::vector< Node >& terms ); - + bool wasPropagatedBySubtheory(TNode literal) const { return d_propagatedBy.find(literal) != d_propagatedBy.end(); } @@ -266,7 +259,11 @@ class TheoryBV : public Theory { void sendConflict(); - void lemma(TNode node) { d_out->lemma(node, RULE_CONFLICT); d_lemmasAdded = true; } + void lemma(TNode node) + { + d_out->lemma(node); + d_lemmasAdded = true; + } void checkForLemma(TNode node); diff --git a/src/theory/combination_engine.cpp b/src/theory/combination_engine.cpp index e1317cf29..f1e977fe3 100644 --- a/src/theory/combination_engine.cpp +++ b/src/theory/combination_engine.cpp @@ -113,7 +113,7 @@ eq::EqualityEngineNotify* CombinationEngine::getModelEqualityEngineNotify() void CombinationEngine::sendLemma(TrustNode trn, TheoryId atomsTo) { - d_te.lemma(trn.getNode(), RULE_INVALID, false, LemmaProperty::NONE, atomsTo); + d_te.lemma(trn.getNode(), false, LemmaProperty::NONE, atomsTo); } void CombinationEngine::resetRound() diff --git a/src/theory/engine_output_channel.cpp b/src/theory/engine_output_channel.cpp index a271d6d9c..b6d9a19db 100644 --- a/src/theory/engine_output_channel.cpp +++ b/src/theory/engine_output_channel.cpp @@ -14,10 +14,6 @@ #include "theory/engine_output_channel.h" -#include "proof/cnf_proof.h" -#include "proof/lemma_proof.h" -#include "proof/proof_manager.h" -#include "proof/theory_proof.h" #include "prop/prop_engine.h" #include "smt/smt_statistics_registry.h" #include "theory/theory_engine.h" @@ -71,9 +67,7 @@ void EngineOutputChannel::safePoint(ResourceManager::Resource r) } } -theory::LemmaStatus EngineOutputChannel::lemma(TNode lemma, - ProofRule rule, - LemmaProperty p) +theory::LemmaStatus EngineOutputChannel::lemma(TNode lemma, LemmaProperty p) { Debug("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" @@ -81,151 +75,15 @@ theory::LemmaStatus EngineOutputChannel::lemma(TNode lemma, ++d_statistics.lemmas; d_engine->d_outputChannelUsed = true; - PROOF({ - bool preprocess = isLemmaPropertyPreprocess(p); - registerLemmaRecipe(lemma, lemma, preprocess, d_theory); - }); - TrustNode tlem = TrustNode::mkTrustLemma(lemma); theory::LemmaStatus result = d_engine->lemma( tlem.getNode(), - rule, false, p, isLemmaPropertySendAtoms(p) ? d_theory : theory::THEORY_LAST); return result; } -void EngineOutputChannel::registerLemmaRecipe(Node lemma, - Node originalLemma, - bool preprocess, - theory::TheoryId theoryId) -{ - // During CNF conversion, conjunctions will be broken down into - // multiple lemmas. In order for the recipes to match, we have to do - // the same here. - NodeManager* nm = NodeManager::currentNM(); - - if (preprocess) lemma = d_engine->preprocess(lemma); - - bool negated = (lemma.getKind() == NOT); - Node nnLemma = negated ? lemma[0] : lemma; - - switch (nnLemma.getKind()) - { - case AND: - if (!negated) - { - for (unsigned i = 0; i < nnLemma.getNumChildren(); ++i) - registerLemmaRecipe(nnLemma[i], originalLemma, false, theoryId); - } - else - { - NodeBuilder<> builder(OR); - for (unsigned i = 0; i < nnLemma.getNumChildren(); ++i) - builder << nnLemma[i].negate(); - - Node disjunction = - (builder.getNumChildren() == 1) ? builder[0] : builder; - registerLemmaRecipe(disjunction, originalLemma, false, theoryId); - } - break; - - case EQUAL: - if (nnLemma[0].getType().isBoolean()) - { - if (!negated) - { - registerLemmaRecipe(nm->mkNode(OR, nnLemma[0], nnLemma[1].negate()), - originalLemma, - false, - theoryId); - registerLemmaRecipe(nm->mkNode(OR, nnLemma[0].negate(), nnLemma[1]), - originalLemma, - false, - theoryId); - } - else - { - registerLemmaRecipe(nm->mkNode(OR, nnLemma[0], nnLemma[1]), - originalLemma, - false, - theoryId); - registerLemmaRecipe( - nm->mkNode(OR, nnLemma[0].negate(), nnLemma[1].negate()), - originalLemma, - false, - theoryId); - } - } - break; - - case ITE: - if (!negated) - { - registerLemmaRecipe(nm->mkNode(OR, nnLemma[0].negate(), nnLemma[1]), - originalLemma, - false, - theoryId); - registerLemmaRecipe(nm->mkNode(OR, nnLemma[0], nnLemma[2]), - originalLemma, - false, - theoryId); - } - else - { - registerLemmaRecipe( - nm->mkNode(OR, nnLemma[0].negate(), nnLemma[1].negate()), - originalLemma, - false, - theoryId); - registerLemmaRecipe(nm->mkNode(OR, nnLemma[0], nnLemma[2].negate()), - originalLemma, - false, - theoryId); - } - break; - - default: break; - } - - // Theory lemmas have one step that proves the empty clause - LemmaProofRecipe proofRecipe; - Node emptyNode; - LemmaProofRecipe::ProofStep proofStep(theoryId, emptyNode); - - // Remember the original lemma, so we can report this later when asked to - proofRecipe.setOriginalLemma(originalLemma); - - // Record the assertions and rewrites - Node rewritten; - if (lemma.getKind() == OR) - { - for (unsigned i = 0; i < lemma.getNumChildren(); ++i) - { - rewritten = theory::Rewriter::rewrite(lemma[i]); - if (rewritten != lemma[i]) - { - proofRecipe.addRewriteRule(lemma[i].negate(), rewritten.negate()); - } - proofStep.addAssertion(lemma[i]); - proofRecipe.addBaseAssertion(rewritten); - } - } - else - { - rewritten = theory::Rewriter::rewrite(lemma); - if (rewritten != lemma) - { - proofRecipe.addRewriteRule(lemma.negate(), rewritten.negate()); - } - proofStep.addAssertion(lemma); - proofRecipe.addBaseAssertion(rewritten); - } - proofRecipe.addStep(proofStep); - ProofManager::getCnfProof()->setProofRecipe(&proofRecipe); -} - theory::LemmaStatus EngineOutputChannel::splitLemma(TNode lemma, bool removable) { Debug("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" @@ -238,7 +96,7 @@ theory::LemmaStatus EngineOutputChannel::splitLemma(TNode lemma, bool removable) TrustNode tlem = TrustNode::mkTrustLemma(lemma); LemmaProperty p = removable ? LemmaProperty::REMOVABLE : LemmaProperty::NONE; theory::LemmaStatus result = - d_engine->lemma(tlem.getNode(), RULE_SPLIT, false, p, d_theory); + d_engine->lemma(tlem.getNode(), false, p, d_theory); return result; } @@ -251,13 +109,11 @@ bool EngineOutputChannel::propagate(TNode literal) return d_engine->propagate(literal, d_theory); } -void EngineOutputChannel::conflict(TNode conflictNode, - std::unique_ptr<Proof> proof) +void EngineOutputChannel::conflict(TNode conflictNode) { Trace("theory::conflict") << "EngineOutputChannel<" << d_theory << ">::conflict(" << conflictNode << ")" << std::endl; - Assert(!proof); // Theory shouldn't be producing proofs yet ++d_statistics.conflicts; d_engine->d_outputChannelUsed = true; TrustNode tConf = TrustNode::mkTrustConflict(conflictNode); @@ -274,7 +130,7 @@ void EngineOutputChannel::demandRestart() Trace("theory::restart") << "EngineOutputChannel<" << d_theory << ">::restart(" << restartVar << ")" << std::endl; ++d_statistics.restartDemands; - lemma(restartVar, RULE_INVALID, LemmaProperty::REMOVABLE); + lemma(restartVar, LemmaProperty::REMOVABLE); } void EngineOutputChannel::requirePhase(TNode n, bool phase) @@ -329,7 +185,6 @@ LemmaStatus EngineOutputChannel::trustedLemma(TrustNode plem, LemmaProperty p) // now, call the normal interface for lemma return d_engine->lemma( plem.getNode(), - RULE_INVALID, false, p, isLemmaPropertySendAtoms(p) ? d_theory : theory::THEORY_LAST); diff --git a/src/theory/engine_output_channel.h b/src/theory/engine_output_channel.h index 3e959898f..99f812ed4 100644 --- a/src/theory/engine_output_channel.h +++ b/src/theory/engine_output_channel.h @@ -45,12 +45,10 @@ class EngineOutputChannel : public theory::OutputChannel void safePoint(ResourceManager::Resource r) override; - void conflict(TNode conflictNode, - std::unique_ptr<Proof> pf = nullptr) override; + void conflict(TNode conflictNode) override; bool propagate(TNode literal) override; theory::LemmaStatus lemma(TNode lemma, - ProofRule rule, LemmaProperty p = LemmaProperty::NONE) override; theory::LemmaStatus splitLemma(TNode lemma, bool removable = false) override; diff --git a/src/theory/ext_theory.h b/src/theory/ext_theory.h index 420932bfe..2721bc89e 100644 --- a/src/theory/ext_theory.h +++ b/src/theory/ext_theory.h @@ -36,6 +36,7 @@ #include <map> #include <set> +#include "context/cdhashmap.h" #include "context/cdhashset.h" #include "context/context.h" #include "expr/node.h" diff --git a/src/theory/output_channel.cpp b/src/theory/output_channel.cpp index c918438ee..ad60dbe0e 100644 --- a/src/theory/output_channel.cpp +++ b/src/theory/output_channel.cpp @@ -93,11 +93,6 @@ TNode LemmaStatus::getRewrittenLemma() const { return d_rewrittenLemma; } unsigned LemmaStatus::getLevel() const { return d_level; } -LemmaStatus OutputChannel::lemma(TNode n, LemmaProperty p) -{ - return lemma(n, RULE_INVALID, p); -} - LemmaStatus OutputChannel::split(TNode n) { return splitLemma(n.orNode(n.notNode())); diff --git a/src/theory/output_channel.h b/src/theory/output_channel.h index 0fd610c58..23d7d8784 100644 --- a/src/theory/output_channel.h +++ b/src/theory/output_channel.h @@ -22,11 +22,9 @@ #include <memory> #include "expr/proof_node.h" -#include "proof/proof_manager.h" #include "smt/logic_exception.h" #include "theory/interrupted.h" #include "theory/trust_node.h" -#include "util/proof.h" #include "util/resource_manager.h" namespace CVC4 { @@ -135,10 +133,8 @@ class OutputChannel { * 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, std::unique_ptr<Proof> pf = nullptr) = 0; + virtual void conflict(TNode n) = 0; /** * Propagate a theory literal. @@ -153,19 +149,11 @@ class OutputChannel { * 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 p The properties of the lemma * @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, - ProofRule rule, - LemmaProperty p = LemmaProperty::NONE) = 0; - - /** - * Variant of the lemma function that does not require providing a proof rule. - */ - virtual LemmaStatus lemma(TNode n, LemmaProperty p = LemmaProperty::NONE); + virtual LemmaStatus lemma(TNode n, LemmaProperty p = LemmaProperty::NONE) = 0; /** * Request a split on a new theory atom. This is equivalent to diff --git a/src/theory/quantifiers/fun_def_process.cpp b/src/theory/quantifiers/fun_def_process.cpp index 2c5eab94c..eb87db4de 100644 --- a/src/theory/quantifiers/fun_def_process.cpp +++ b/src/theory/quantifiers/fun_def_process.cpp @@ -14,13 +14,15 @@ ** This class implements pre-process steps for admissible recursive function definitions (Reynolds et al IJCAR2016) **/ +#include "theory/quantifiers/fun_def_process.h" + #include <vector> -#include "theory/quantifiers/fun_def_process.h" +#include "options/smt_options.h" +#include "proof/proof_manager.h" #include "theory/quantifiers/quantifiers_attributes.h" #include "theory/quantifiers/term_database.h" #include "theory/quantifiers/term_util.h" -#include "proof/proof_manager.h" using namespace CVC4; using namespace std; @@ -86,7 +88,10 @@ void FunDefFmf::simplify( std::vector< Node >& assertions ) { Trace("fmf-fun-def") << " to " << std::endl; Node new_q = NodeManager::currentNM()->mkNode( FORALL, bvl, bd ); new_q = Rewriter::rewrite( new_q ); - PROOF( ProofManager::currentPM()->addDependence(new_q, assertions[i]); ); + if (options::unsatCores()) + { + ProofManager::currentPM()->addDependence(new_q, assertions[i]); + } assertions[i] = new_q; Trace("fmf-fun-def") << " " << assertions[i] << std::endl; fd_assertions.push_back( i ); @@ -120,7 +125,10 @@ void FunDefFmf::simplify( std::vector< Node >& assertions ) { << std::endl; Trace("fmf-fun-def-rewrite") << " to " << std::endl; Trace("fmf-fun-def-rewrite") << " " << n << std::endl; - PROOF(ProofManager::currentPM()->addDependence(n, assertions[i]);); + if (options::unsatCores()) + { + ProofManager::currentPM()->addDependence(n, assertions[i]); + } assertions[i] = n; } } @@ -175,8 +183,12 @@ Node FunDefFmf::simplifyFormula( Node n, bool pol, bool hasPol, std::vector< Nod c = simplifyFormula( n[i], newPol, newHasPol, cconstraints, hd, false, visited, visited_cons ); if( branch_pos ){ // if at a branching position, the other constraints don't matter if this is satisfied - Node bcons = cconstraints.empty() ? NodeManager::currentNM()->mkConst( true ) : - ( cconstraints.size()==1 ? cconstraints[0] : NodeManager::currentNM()->mkNode( AND, cconstraints ) ); + Node bcons = cconstraints.empty() + ? NodeManager::currentNM()->mkConst(true) + : (cconstraints.size() == 1 + ? cconstraints[0] + : NodeManager::currentNM()->mkNode( + AND, cconstraints)); branch_constraints.push_back( bcons ); Trace("fmf-fun-def-debug2") << "Branching constraint at arg " << i << " is " << bcons << std::endl; } @@ -201,10 +213,14 @@ Node FunDefFmf::simplifyFormula( Node n, bool pol, bool hasPol, std::vector< Nod // in the default case, we care about all conditions branch_cond = constraints.size()==1 ? constraints[0] : NodeManager::currentNM()->mkNode( AND, constraints ); for( unsigned i=0; i<n.getNumChildren(); i++ ){ - // if this child holds with forcing polarity (true child of OR or false child of AND), - // then we only care about its associated recursive conditions - branch_cond = NodeManager::currentNM()->mkNode( kind::ITE, - ( n.getKind()==OR ? n[i] : n[i].negate() ), branch_constraints[i], branch_cond ); + // if this child holds with forcing polarity (true child of OR or + // false child of AND), then we only care about its associated + // recursive conditions + branch_cond = NodeManager::currentNM()->mkNode( + kind::ITE, + (n.getKind() == OR ? n[i] : n[i].negate()), + branch_constraints[i], + branch_cond); } } Trace("fmf-fun-def-debug2") << "Made branching condition " << branch_cond << std::endl; diff --git a/src/theory/quantifiers/instantiate.cpp b/src/theory/quantifiers/instantiate.cpp index 77b61e9dd..04b6e0dda 100644 --- a/src/theory/quantifiers/instantiate.cpp +++ b/src/theory/quantifiers/instantiate.cpp @@ -16,6 +16,8 @@ #include "expr/node_algorithm.h" #include "options/quantifiers_options.h" +#include "options/smt_options.h" +#include "proof/proof_manager.h" #include "smt/smt_statistics_registry.h" #include "theory/quantifiers/cegqi/inst_strategy_cegqi.h" #include "theory/quantifiers/first_order_model.h" @@ -577,18 +579,21 @@ void Instantiate::getInstantiatedQuantifiedFormulas(std::vector<Node>& qs) bool Instantiate::getUnsatCoreLemmas(std::vector<Node>& active_lemmas) { // only if unsat core available - if (options::proof()) + if (options::unsatCores()) { if (!ProofManager::currentPM()->unsatCoreAvailable()) { return false; } } + else + { + return false; + } Trace("inst-unsat-core") << "Get instantiations in unsat core..." << std::endl; - ProofManager::currentPM()->getLemmasInUnsatCore(theory::THEORY_QUANTIFIERS, - active_lemmas); + ProofManager::currentPM()->getLemmasInUnsatCore(active_lemmas); if (Trace.isOn("inst-unsat-core")) { Trace("inst-unsat-core") << "Quantifiers lemmas in unsat core: " @@ -602,27 +607,6 @@ bool Instantiate::getUnsatCoreLemmas(std::vector<Node>& active_lemmas) return true; } -bool Instantiate::getUnsatCoreLemmas(std::vector<Node>& active_lemmas, - std::map<Node, Node>& weak_imp) -{ - if (getUnsatCoreLemmas(active_lemmas)) - { - for (unsigned i = 0, size = active_lemmas.size(); i < size; ++i) - { - Node n = ProofManager::currentPM()->getWeakestImplicantInUnsatCore( - active_lemmas[i]); - if (n != active_lemmas[i]) - { - Trace("inst-unsat-core") << " weaken : " << active_lemmas[i] << " -> " - << n << std::endl; - } - weak_imp[active_lemmas[i]] = n; - } - return true; - } - return false; -} - void Instantiate::getInstantiationTermVectors( Node q, std::vector<std::vector<Node> >& tvecs) { diff --git a/src/theory/quantifiers/instantiate.h b/src/theory/quantifiers/instantiate.h index cb40bbbbc..8b1e0f7fc 100644 --- a/src/theory/quantifiers/instantiate.h +++ b/src/theory/quantifiers/instantiate.h @@ -268,21 +268,6 @@ class Instantiate : public QuantifiersUtil * This method returns false if the unsat core is not available. */ bool getUnsatCoreLemmas(std::vector<Node>& active_lemmas); - /** get unsat core lemmas - * - * If this method returns true, then it appends to active_lemmas all lemmas - * that are in the unsat core that originated from the theory of quantifiers. - * This method returns false if the unsat core is not available. - * - * It also computes a weak implicant for each of these lemmas. For each lemma - * L in active_lemmas, this is a formula L' such that: - * L => L' - * and replacing L by L' in the unsat core results in a set that is still - * unsatisfiable. The map weak_imp stores this formula for each formula in - * active_lemmas. - */ - bool getUnsatCoreLemmas(std::vector<Node>& active_lemmas, - std::map<Node, Node>& weak_imp); /** get explanation for instantiation lemmas * * diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp index cb7a4d055..2e69080e7 100644 --- a/src/theory/quantifiers_engine.cpp +++ b/src/theory/quantifiers_engine.cpp @@ -217,7 +217,7 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c, if (options::sygus() || options::sygusInst()) { d_sygus_tdb.reset(new quantifiers::TermDbSygus(c, this)); - } + } d_util.push_back(d_instantiate.get()); @@ -580,7 +580,7 @@ void QuantifiersEngine::check( Theory::Effort e ){ if( d_hasAddedLemma ){ return; } - + double clSet = 0; if( Trace.isOn("quant-engine") ){ clSet = double(clock())/double(CLOCKS_PER_SEC); @@ -805,7 +805,7 @@ void QuantifiersEngine::check( Theory::Effort e ){ Trace("quant-engine") << ", added lemma = " << d_hasAddedLemma; Trace("quant-engine") << std::endl; } - + Trace("quant-engine-debug2") << "Finished quantifiers engine check." << std::endl; }else{ Trace("quant-engine-debug2") << "Quantifiers Engine does not need check." << std::endl; @@ -1035,7 +1035,7 @@ bool QuantifiersEngine::removeLemma( Node lem ) { void QuantifiersEngine::addRequirePhase( Node lit, bool req ){ d_phase_req_waiting[lit] = req; } - + void QuantifiersEngine::markRelevant( Node q ) { d_model->markRelevant( q ); } @@ -1048,9 +1048,10 @@ bool QuantifiersEngine::theoryEngineNeedsCheck() const return d_te->needCheck(); } -void QuantifiersEngine::setConflict() { - d_conflict = true; - d_conflict_c = true; +void QuantifiersEngine::setConflict() +{ + d_conflict = true; + d_conflict_c = true; } bool QuantifiersEngine::getInstWhenNeedsCheck( Theory::Effort e ) { @@ -1123,10 +1124,6 @@ bool QuantifiersEngine::getUnsatCoreLemmas( std::vector< Node >& active_lemmas ) return d_instantiate->getUnsatCoreLemmas(active_lemmas); } -bool QuantifiersEngine::getUnsatCoreLemmas( std::vector< Node >& active_lemmas, std::map< Node, Node >& weak_imp ) { - return d_instantiate->getUnsatCoreLemmas(active_lemmas, weak_imp); -} - void QuantifiersEngine::getInstantiationTermVectors( Node q, std::vector< std::vector< Node > >& tvecs ) { d_instantiate->getInstantiationTermVectors(q, tvecs); } diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h index eca108587..6afc4f925 100644 --- a/src/theory/quantifiers_engine.h +++ b/src/theory/quantifiers_engine.h @@ -265,8 +265,6 @@ public: Node getInstantiatedConjunction(Node q); /** get unsat core lemmas */ bool getUnsatCoreLemmas(std::vector<Node>& active_lemmas); - bool getUnsatCoreLemmas(std::vector<Node>& active_lemmas, - std::map<Node, Node>& weak_imp); /** get explanation for instantiation lemmas */ void getExplanationForInstLemmas(const std::vector<Node>& lems, std::map<Node, Node>& quant, @@ -317,7 +315,7 @@ public: ~Statistics(); };/* class QuantifiersEngine::Statistics */ Statistics d_statistics; - + private: /** reference to theory engine object */ TheoryEngine* d_te; diff --git a/src/theory/sort_inference.cpp b/src/theory/sort_inference.cpp index 144f5b54d..feb266a20 100644 --- a/src/theory/sort_inference.cpp +++ b/src/theory/sort_inference.cpp @@ -24,7 +24,6 @@ #include "options/quantifiers_options.h" #include "options/smt_options.h" #include "options/uf_options.h" -#include "proof/proof_manager.h" #include "theory/rewriter.h" #include "theory/quantifiers/quant_util.h" diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp index a752958b2..084e2ac91 100644 --- a/src/theory/strings/theory_strings_preprocess.cpp +++ b/src/theory/strings/theory_strings_preprocess.cpp @@ -19,6 +19,7 @@ #include <stdint.h> #include "expr/kind.h" +#include "options/smt_options.h" #include "options/strings_options.h" #include "proof/proof_manager.h" #include "smt/logic_exception.h" @@ -972,7 +973,10 @@ void StringsPreprocess::processAssertions( std::vector< Node > &vec_node ){ : NodeManager::currentNM()->mkNode(kind::AND, asserts); if( res!=vec_node[i] ){ res = Rewriter::rewrite( res ); - PROOF( ProofManager::currentPM()->addDependence( res, vec_node[i] ); ); + if (options::unsatCores()) + { + ProofManager::currentPM()->addDependence(res, vec_node[i]); + } vec_node[i] = res; } } diff --git a/src/theory/theory.cpp b/src/theory/theory.cpp index d69c6edc5..3c603051c 100644 --- a/src/theory/theory.cpp +++ b/src/theory/theory.cpp @@ -23,6 +23,7 @@ #include "base/check.h" #include "expr/node_algorithm.h" +#include "options/smt_options.h" #include "options/theory_options.h" #include "smt/smt_statistics_registry.h" #include "theory/ext_theory.h" @@ -81,8 +82,7 @@ Theory::Theory(TheoryId id, d_equalityEngine(nullptr), d_allocEqualityEngine(nullptr), d_theoryState(nullptr), - d_inferManager(nullptr), - d_proofsEnabled(false) + d_inferManager(nullptr) { smtStatisticsRegistry()->registerStat(&d_checkTime); smtStatisticsRegistry()->registerStat(&d_computeCareGraphTime); @@ -296,12 +296,12 @@ void Theory::computeCareGraph() { switch (d_valuation.getEqualityStatus(a, b)) { case EQUALITY_TRUE_AND_PROPAGATED: case EQUALITY_FALSE_AND_PROPAGATED: - // If we know about it, we should have propagated it, so we can skip - break; + // If we know about it, we should have propagated it, so we can skip + break; default: - // Let's split on it - addCarePair(a, b); - break; + // Let's split on it + addCarePair(a, b); + break; } } } diff --git a/src/theory/theory.h b/src/theory/theory.h index 039fdebf1..176d4b672 100644 --- a/src/theory/theory.h +++ b/src/theory/theory.h @@ -246,11 +246,6 @@ class Theory { * the equality engine are used properly. */ TheoryInferenceManager* d_inferManager; - /** - * Whether proofs are enabled - * - */ - bool d_proofsEnabled; /** * Returns the next assertion in the assertFact() queue. @@ -581,6 +576,7 @@ class Theory { Unimplemented() << "Theory " << identify() << " propagated a node but doesn't implement the " "Theory::explain() interface!"; + return TrustNode::null(); } //--------------------------------- check @@ -824,15 +820,13 @@ class Theory { * * @return true iff facts have been asserted to this theory. */ - bool hasFacts() { - return !d_facts.empty(); - } + bool hasFacts() { return !d_facts.empty(); } /** Return total number of facts asserted to this theory */ size_t numAssertions() { return d_facts.size(); } - + typedef context::CDList<TNode>::const_iterator shared_terms_iterator; /** @@ -917,7 +911,7 @@ class Theory { /* is extended function reduced */ virtual bool isExtfReduced( int effort, Node n, Node on, std::vector< Node >& exp ) { return n.isConst(); } - + /** * Get reduction for node * If return value is not 0, then n is reduced. @@ -927,9 +921,6 @@ class Theory { * and return value should be <0. */ virtual int getReduction( int effort, Node n, Node& nr ) { return 0; } - - /** Turn on proof-production mode. */ - void produceProofs() { d_proofsEnabled = true; } };/* class Theory */ std::ostream& operator<<(std::ostream& os, theory::Theory::Effort level); diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp index c61879b6d..6837d4be5 100644 --- a/src/theory/theory_engine.cpp +++ b/src/theory/theory_engine.cpp @@ -28,14 +28,9 @@ #include "expr/node_visitor.h" #include "options/bv_options.h" #include "options/options.h" -#include "options/proof_options.h" #include "options/quantifiers_options.h" #include "options/theory_options.h" #include "preprocessing/assertion_pipeline.h" -#include "proof/cnf_proof.h" -#include "proof/lemma_proof.h" -#include "proof/proof_manager.h" -#include "proof/theory_proof.h" #include "smt/logic_exception.h" #include "smt/term_formula_removal.h" #include "theory/arith/arith_ite_utils.h" @@ -256,10 +251,6 @@ TheoryEngine::TheoryEngine(context::Context* context, d_true = NodeManager::currentNM()->mkConst<bool>(true); d_false = NodeManager::currentNM()->mkConst<bool>(false); -#ifdef CVC4_PROOF - ProofManager::currentPM()->initTheoryProofEngine(); -#endif - smtStatisticsRegistry()->registerStat(&d_arithSubstitutionsAdded); } @@ -1150,23 +1141,6 @@ bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) { assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ theory); } } else { - // We could be propagating a unit-clause lemma. In this case, we need to provide a - // recipe. - // TODO: Consider putting this someplace else? This is the only refence to the proof - // manager in this class. - - PROOF({ - LemmaProofRecipe proofRecipe; - proofRecipe.addBaseAssertion(literal); - - Node emptyNode; - LemmaProofRecipe::ProofStep proofStep(theory, emptyNode); - proofStep.addAssertion(literal); - proofRecipe.addStep(proofStep); - - ProofManager::getCnfProof()->setProofRecipe(&proofRecipe); - }); - // Just send off to the SAT solver Assert(d_propEngine->isSatLiteral(literal)); assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory); @@ -1309,65 +1283,31 @@ static Node mkExplanation(const std::vector<NodeTheoryPair>& explanation) { return conjunction; } -Node TheoryEngine::getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRecipe) { - Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << "): current propagation index = " << d_propagationMapTimestamp << endl; +Node TheoryEngine::getExplanation(TNode node) +{ + Debug("theory::explain") << "TheoryEngine::getExplanation(" << node + << "): current propagation index = " + << d_propagationMapTimestamp << endl; bool polarity = node.getKind() != kind::NOT; TNode atom = polarity ? node : node[0]; // If we're not in shared mode, explanations are simple - if (!d_logicInfo.isSharingEnabled()) { - Debug("theory::explain") << "TheoryEngine::getExplanation: sharing is NOT enabled. " - << " Responsible theory is: " - << theoryOf(atom)->getId() << std::endl; + if (!d_logicInfo.isSharingEnabled()) + { + Debug("theory::explain") + << "TheoryEngine::getExplanation: sharing is NOT enabled. " + << " Responsible theory is: " << theoryOf(atom)->getId() << std::endl; TrustNode texplanation = theoryOf(atom)->explain(node); Node explanation = texplanation.getNode(); - Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl; - PROOF({ - if(proofRecipe) { - Node emptyNode; - LemmaProofRecipe::ProofStep proofStep(theoryOf(atom)->getId(), emptyNode); - proofStep.addAssertion(node); - proofRecipe->addBaseAssertion(node); - - if (explanation.getKind() == kind::AND) { - // If the explanation is a conjunction, the recipe for the corresponding lemma is - // the negation of its conjuncts. - Node flat = flattenAnd(explanation); - for (unsigned i = 0; i < flat.getNumChildren(); ++i) { - if (flat[i].isConst() && flat[i].getConst<bool>()) { - ++ i; - continue; - } - if (flat[i].getKind() == kind::NOT && - flat[i][0].isConst() && !flat[i][0].getConst<bool>()) { - ++ i; - continue; - } - Debug("theory::explain") << "TheoryEngine::getExplanationAndRecipe: adding recipe assertion: " - << flat[i].negate() << std::endl; - proofStep.addAssertion(flat[i].negate()); - proofRecipe->addBaseAssertion(flat[i].negate()); - } - } else { - // The recipe for proving it is by negating it. "True" is not an acceptable reason. - if (!((explanation.isConst() && explanation.getConst<bool>()) || - (explanation.getKind() == kind::NOT && - explanation[0].isConst() && !explanation[0].getConst<bool>()))) { - proofStep.addAssertion(explanation.negate()); - proofRecipe->addBaseAssertion(explanation.negate()); - } - } - - proofRecipe->addStep(proofStep); - } - }); - + Debug("theory::explain") << "TheoryEngine::getExplanation(" << node + << ") => " << explanation << endl; return explanation; } - Debug("theory::explain") << "TheoryEngine::getExplanation: sharing IS enabled" << std::endl; + Debug("theory::explain") << "TheoryEngine::getExplanation: sharing IS enabled" + << std::endl; // Initial thing to explain NodeTheoryPair toExplain(node, THEORY_SAT_SOLVER, d_propagationMapTimestamp); @@ -1378,33 +1318,20 @@ Node TheoryEngine::getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRe << "TheoryEngine::getExplanation: explainer for node " << nodeExplainerPair.d_node << " is theory: " << nodeExplainerPair.d_theory << std::endl; - TheoryId explainer = nodeExplainerPair.d_theory; // Create the workplace for explanations std::vector<NodeTheoryPair> explanationVector; explanationVector.push_back(d_propagationMap[toExplain]); // Process the explanation - if (proofRecipe) { - Node emptyNode; - LemmaProofRecipe::ProofStep proofStep(explainer, emptyNode); - proofStep.addAssertion(node); - proofRecipe->addStep(proofStep); - proofRecipe->addBaseAssertion(node); - } - - getExplanation(explanationVector, proofRecipe); + getExplanation(explanationVector); Node explanation = mkExplanation(explanationVector); - Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl; + Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " + << explanation << endl; return explanation; } -Node TheoryEngine::getExplanation(TNode node) { - LemmaProofRecipe *dontCareRecipe = NULL; - return getExplanationAndRecipe(node, dontCareRecipe); -} - struct AtomsCollect { std::vector<TNode> d_atoms; @@ -1504,7 +1431,6 @@ void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::The } theory::LemmaStatus TheoryEngine::lemma(TNode node, - ProofRule rule, bool negated, theory::LemmaProperty p, theory::TheoryId atomsTo) @@ -1567,8 +1493,7 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node, // assert lemmas to prop engine for (size_t i = 0, lsize = lemmas.size(); i < lsize; ++i) { - d_propEngine->assertLemma( - lemmas[i], i == 0 && negated, removable, rule, node); + d_propEngine->assertLemma(lemmas[i], i == 0 && negated, removable); } // WARNING: Below this point don't assume lemmas[0] to be not negated. @@ -1611,23 +1536,6 @@ void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) { << CheckSatCommand(conflict.toExpr()); } - LemmaProofRecipe* proofRecipe = NULL; - PROOF({ - proofRecipe = new LemmaProofRecipe; - Node emptyNode; - LemmaProofRecipe::ProofStep proofStep(theoryId, emptyNode); - - if (conflict.getKind() == kind::AND) { - for (unsigned i = 0; i < conflict.getNumChildren(); ++i) { - proofStep.addAssertion(conflict[i].negate()); - } - } else { - proofStep.addAssertion(conflict.negate()); - } - - proofRecipe->addStep(proofStep); - }); - // In the multiple-theories case, we need to reconstruct the conflict if (d_logicInfo.isSharingEnabled()) { // Create the workplace for explanations @@ -1635,67 +1543,29 @@ void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) { explanationVector.push_back(NodeTheoryPair(conflict, theoryId, d_propagationMapTimestamp)); // Process the explanation - getExplanation(explanationVector, proofRecipe); - PROOF(ProofManager::getCnfProof()->setProofRecipe(proofRecipe)); + getExplanation(explanationVector); Node fullConflict = mkExplanation(explanationVector); Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << "): full = " << fullConflict << endl; Assert(properConflict(fullConflict)); lemma(fullConflict, - RULE_CONFLICT, true, LemmaProperty::REMOVABLE, THEORY_LAST); } else { // When only one theory, the conflict should need no processing Assert(properConflict(conflict)); - PROOF({ - if (conflict.getKind() == kind::AND) { - // If the conflict is a conjunction, the corresponding lemma is derived by negating - // its conjuncts. - for (unsigned i = 0; i < conflict.getNumChildren(); ++i) { - if (conflict[i].isConst() && conflict[i].getConst<bool>()) { - ++ i; - continue; - } - if (conflict[i].getKind() == kind::NOT && - conflict[i][0].isConst() && !conflict[i][0].getConst<bool>()) { - ++ i; - continue; - } - proofRecipe->getStep(0)->addAssertion(conflict[i].negate()); - proofRecipe->addBaseAssertion(conflict[i].negate()); - } - } else { - proofRecipe->getStep(0)->addAssertion(conflict.negate()); - proofRecipe->addBaseAssertion(conflict.negate()); - } - - ProofManager::getCnfProof()->setProofRecipe(proofRecipe); - }); - - lemma(conflict, RULE_CONFLICT, true, LemmaProperty::REMOVABLE, THEORY_LAST); + lemma(conflict, true, LemmaProperty::REMOVABLE, THEORY_LAST); } - - PROOF({ - delete proofRecipe; - proofRecipe = NULL; - }); } -void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector, LemmaProofRecipe* proofRecipe) { +void TheoryEngine::getExplanation( + std::vector<NodeTheoryPair>& explanationVector) +{ Assert(explanationVector.size() > 0); unsigned i = 0; // Index of the current literal we are processing unsigned j = 0; // Index of the last literal we are keeping - std::unique_ptr<std::set<Node>> inputAssertions = nullptr; - PROOF({ - if (proofRecipe) - { - inputAssertions.reset( - new std::set<Node>(proofRecipe->getStep(0)->getAssertions())); - } - }); // cache of nodes we have already explained by some theory std::unordered_map<Node, size_t, NodeHashFunction> cache; @@ -1768,22 +1638,6 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector explanationVector.push_back((*find).second); ++i; - PROOF({ - if (toExplain.d_node != (*find).second.d_node) - { - Debug("pf::explain") - << "TheoryEngine::getExplanation: Rewrite alert! toAssert = " - << toExplain.d_node << ", toExplain = " << (*find).second.d_node - << std::endl; - - if (proofRecipe) - { - proofRecipe->addRewriteRule(toExplain.d_node, - (*find).second.d_node); - } - } - }) - continue; } } @@ -1814,59 +1668,10 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector explanationVector.push_back(newExplain); ++ i; - - PROOF({ - if (proofRecipe && inputAssertions) - { - // If we're expanding the target node of the explanation (this is the - // first expansion...), we don't want to add it as a separate proof - // step. It is already part of the assertions. - if (!ContainsKey(*inputAssertions, toExplain.d_node)) - { - LemmaProofRecipe::ProofStep proofStep(toExplain.d_theory, - toExplain.d_node); - if (explanation.getKind() == kind::AND) - { - Node flat = flattenAnd(explanation); - for (unsigned k = 0; k < flat.getNumChildren(); ++k) - { - // If a true constant or a negation of a false constant we can - // ignore it - if (!((flat[k].isConst() && flat[k].getConst<bool>()) - || (flat[k].getKind() == kind::NOT && flat[k][0].isConst() - && !flat[k][0].getConst<bool>()))) - { - proofStep.addAssertion(flat[k].negate()); - } - } - } - else - { - if (!((explanation.isConst() && explanation.getConst<bool>()) - || (explanation.getKind() == kind::NOT - && explanation[0].isConst() - && !explanation[0].getConst<bool>()))) - { - proofStep.addAssertion(explanation.negate()); - } - } - proofRecipe->addStep(proofStep); - } - } - }); } // Keep only the relevant literals explanationVector.resize(j); - - PROOF({ - if (proofRecipe) { - // The remaining literals are the base of the proof - for (unsigned k = 0; k < explanationVector.size(); ++k) { - proofRecipe->addBaseAssertion(explanationVector[k].d_node.negate()); - } - } - }); } void TheoryEngine::setUserAttribute(const std::string& attr, diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h index b1543ad0b..167bd6d75 100644 --- a/src/theory/theory_engine.h +++ b/src/theory/theory_engine.h @@ -53,7 +53,6 @@ namespace CVC4 { class ResourceManager; -class LemmaProofRecipe; /** * A pair of a theory and a node. This is used to mark the flow of @@ -292,7 +291,6 @@ class TheoryEngine { * @param p the properties of the lemma. */ theory::LemmaStatus lemma(TNode node, - ProofRule rule, bool negated, theory::LemmaProperty p, theory::TheoryId atomsTo); @@ -442,14 +440,13 @@ class TheoryEngine { bool markPropagation(TNode assertion, TNode originalAssertions, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId); /** - * Computes the explanation by travarsing the propagation graph and + * Computes the explanation by traversing the propagation graph and * asking relevant theories to explain the propagations. Initially * the explanation vector should contain only the element (node, theory) * where the node is the one to be explained, and the theory is the - * theory that sent the literal. The lemmaProofRecipe will contain a list - * of the explanation steps required to produce the original node. + * theory that sent the literal. */ - void getExplanation(std::vector<NodeTheoryPair>& explanationVector, LemmaProofRecipe* lemmaProofRecipe); + void getExplanation(std::vector<NodeTheoryPair>& explanationVector); public: /** @@ -570,12 +567,6 @@ class TheoryEngine { Node getExplanation(TNode node); /** - * Returns an explanation of the node propagated to the SAT solver and the theory - * that propagated it. - */ - Node getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRecipe); - - /** * Get the pointer to the model object used by this theory engine. */ theory::TheoryModel* getModel(); @@ -687,14 +678,15 @@ class TheoryEngine { /** * Get instantiation methods * first inputs forall x.q[x] and returns ( q[a], ..., q[z] ) - * second inputs forall x.q[x] and returns ( a, ..., z ) - * third and fourth return mappings e.g. forall x.q1[x] -> ( q1[a]...q1[z] ) , ... , forall x.qn[x] -> ( qn[a]...qn[z] ) + * second inputs forall x.q[x] and returns ( a, ..., z ) + * third and fourth return mappings e.g. forall x.q1[x] -> ( q1[a]...q1[z] ) + * , ... , forall x.qn[x] -> ( qn[a]...qn[z] ) */ void getInstantiations( Node q, std::vector< Node >& insts ); void getInstantiationTermVectors( Node q, std::vector< std::vector< Node > >& tvecs ); void getInstantiations( std::map< Node, std::vector< Node > >& insts ); void getInstantiationTermVectors( std::map< Node, std::vector< std::vector< Node > > >& insts ); - + /** * Get instantiated conjunction, returns q[t1] ^ ... ^ q[tn] where t1...tn are current set of instantiations for q. * Can be used for quantifier elimination when satisfiable and q[t1] ^ ... ^ q[tn] |= q @@ -726,7 +718,7 @@ private: public: /** Set user attribute. - * + * * This function is called when an attribute is set by a user. In SMT-LIBv2 * this is done via the syntax (! n :attr) */ @@ -736,7 +728,7 @@ private: const std::string& str_value); /** Handle user attribute. - * + * * Associates theory t with the attribute attr. Theory t will be * notified whenever an attribute of name attr is set. */ diff --git a/src/theory/theory_test_utils.h b/src/theory/theory_test_utils.h index 2593b11a6..965e99338 100644 --- a/src/theory/theory_test_utils.h +++ b/src/theory/theory_test_utils.h @@ -27,7 +27,6 @@ #include "expr/node.h" #include "theory/interrupted.h" #include "theory/output_channel.h" -#include "util/proof.h" #include "util/resource_manager.h" #include "util/unsafe_interrupt_exception.h" @@ -69,17 +68,14 @@ public: ~TestOutputChannel() override {} void safePoint(ResourceManager::Resource r) override {} - void conflict(TNode n, std::unique_ptr<Proof> pf) override - { - push(CONFLICT, n); - } + void conflict(TNode n) override { push(CONFLICT, n); } bool propagate(TNode n) override { push(PROPAGATE, n); return true; } - LemmaStatus lemma(TNode n, ProofRule rule, LemmaProperty p) override + LemmaStatus lemma(TNode n, LemmaProperty p) override { push(LEMMA, n); return LemmaStatus(Node::null(), 0); diff --git a/src/theory/uf/eq_proof.cpp b/src/theory/uf/eq_proof.cpp index 513cf2f39..d7b615ffa 100644 --- a/src/theory/uf/eq_proof.cpp +++ b/src/theory/uf/eq_proof.cpp @@ -21,33 +21,20 @@ namespace CVC4 { namespace theory { namespace eq { -void EqProof::debug_print(const char* c, - unsigned tb, - PrettyPrinter* prettyPrinter) const +void EqProof::debug_print(const char* c, unsigned tb) const { std::stringstream ss; - debug_print(ss, tb, prettyPrinter); + debug_print(ss, tb); Debug(c) << ss.str(); } -void EqProof::debug_print(std::ostream& os, - unsigned tb, - PrettyPrinter* prettyPrinter) const +void EqProof::debug_print(std::ostream& os, unsigned tb) const { for (unsigned i = 0; i < tb; i++) { os << " "; } - - if (prettyPrinter) - { - os << prettyPrinter->printTag(d_id); - } - else - { - os << static_cast<MergeReasonType>(d_id); - } - os << "("; + os << d_id << "("; if (d_children.empty() && d_node.isNull()) { os << ")"; @@ -66,7 +53,7 @@ void EqProof::debug_print(std::ostream& os, for (unsigned i = 0; i < size; ++i) { os << std::endl; - d_children[i]->debug_print(os, tb + 1, prettyPrinter); + d_children[i]->debug_print(os, tb + 1); if (i < size - 1) { for (unsigned j = 0; j < tb + 1; ++j) @@ -850,8 +837,7 @@ Node EqProof::addToProof( << ", returning " << it->second << "\n"; return it->second; } - Trace("eqproof-conv") << "EqProof::addToProof: adding step for " - << static_cast<MergeReasonType>(d_id) + Trace("eqproof-conv") << "EqProof::addToProof: adding step for " << d_id << " with conclusion " << d_node << "\n"; // Assumption if (d_id == MERGED_THROUGH_EQUALITY) @@ -976,12 +962,10 @@ Node EqProof::addToProof( { Assert(!d_node.isNull() && d_node.getKind() == kind::EQUAL && d_node[1].isConst()) - << ". Conclusion " << d_node << " from " - << static_cast<MergeReasonType>(d_id) + << ". Conclusion " << d_node << " from " << d_id << " was expected to be (= (f t1 ... tn) c)\n"; Assert(!assumptions.count(d_node)) - << "Conclusion " << d_node << " from " - << static_cast<MergeReasonType>(d_id) << " is an assumption\n"; + << "Conclusion " << d_node << " from " << d_id << " is an assumption\n"; // The step has the form // [(= t1 c1)] ... [(= tn cn)] // ------------------------ diff --git a/src/theory/uf/eq_proof.h b/src/theory/uf/eq_proof.h index 492252baa..72368c8c9 100644 --- a/src/theory/uf/eq_proof.h +++ b/src/theory/uf/eq_proof.h @@ -35,36 +35,21 @@ namespace eq { class EqProof { public: - /** A custom pretty printer used for custom rules being those in - * MergeReasonType. */ - class PrettyPrinter - { - public: - virtual ~PrettyPrinter() {} - virtual std::string printTag(unsigned tag) = 0; - }; - EqProof() : d_id(MERGED_THROUGH_REFLEXIVITY) {} /** The proof rule for concluding d_node */ - unsigned d_id; + MergeReasonType d_id; /** The conclusion of this EqProof */ Node d_node; /** The proofs of the premises for deriving d_node with d_id */ std::vector<std::shared_ptr<EqProof>> d_children; /** - * Debug print this proof on debug trace c with tabulation tb and pretty - * printer prettyPrinter. + * Debug print this proof on debug trace c with tabulation tb. */ - void debug_print(const char* c, - unsigned tb = 0, - PrettyPrinter* prettyPrinter = nullptr) const; + void debug_print(const char* c, unsigned tb = 0) const; /** - * Debug print this proof on output stream os with tabulation tb and pretty - * printer prettyPrinter. + * Debug print this proof on output stream os with tabulation tb. */ - void debug_print(std::ostream& os, - unsigned tb = 0, - PrettyPrinter* prettyPrinter = nullptr) const; + void debug_print(std::ostream& os, unsigned tb = 0) const; /** Add to proof * diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp index dd142edf4..c97c99776 100644 --- a/src/theory/uf/equality_engine.cpp +++ b/src/theory/uf/equality_engine.cpp @@ -103,8 +103,6 @@ void EqualityEngine::init() { d_trueId = getNodeId(d_true); d_falseId = getNodeId(d_false); - - d_freshMergeReasonType = eq::NUMBER_OF_MERGE_REASONS; } EqualityEngine::~EqualityEngine() { @@ -1100,7 +1098,7 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, getExplanation(t1Id, t2Id, equalities, cache, eqp); } else { if (eqp) { - eqp->d_id = eq::MERGED_THROUGH_TRANS; + eqp->d_id = MERGED_THROUGH_TRANS; eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t2Id]).notNode(); } @@ -1137,12 +1135,13 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, Debug("pf::ee") << "Child proof is:" << std::endl; eqpc->debug_print("pf::ee", 1); } - if (eqpc->d_id == eq::MERGED_THROUGH_TRANS) { + if (eqpc->d_id == MERGED_THROUGH_TRANS) + { std::vector<std::shared_ptr<EqProof>> orderedChildren; bool nullCongruenceFound = false; for (const auto& child : eqpc->d_children) { - if (child->d_id == eq::MERGED_THROUGH_CONGRUENCE + if (child->d_id == MERGED_THROUGH_CONGRUENCE && child->d_node.isNull()) { nullCongruenceFound = true; @@ -1382,35 +1381,24 @@ void EqualityEngine::getExplanation( #endif // If the nodes are the same, we're done - if (t1Id == t2Id){ - if( eqp ) { - if (options::proofNew()) - { - // ignore equalities between function symbols, i.e. internal nullary - // non-constant nodes. - // - // Note that this is robust for HOL because in that case function - // symbols are not internal nodes - if (d_isInternal[t1Id] && d_nodes[t1Id].getNumChildren() == 0 - && !d_isConstant[t1Id]) - { - eqp->d_node = Node::null(); - } - else - { - Assert(d_nodes[t1Id].getKind() != kind::BUILTIN); - eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t1Id]); - } - } - else if ((d_nodes[t1Id].getKind() == kind::BUILTIN) - && (d_nodes[t1Id].getConst<Kind>() == kind::SELECT)) + if (t1Id == t2Id) + { + if (eqp) + { + // ignore equalities between function symbols, i.e. internal nullary + // non-constant nodes. + // + // Note that this is robust for HOL because in that case function + // symbols are not internal nodes + if (d_isInternal[t1Id] && d_nodes[t1Id].getNumChildren() == 0 + && !d_isConstant[t1Id]) { - std::vector<Node> no_children; - eqp->d_node = NodeManager::currentNM()->mkNode(kind::PARTIAL_SELECT_0, no_children); + eqp->d_node = Node::null(); } else { - eqp->d_node = ProofManager::currentPM()->mkOp(d_nodes[t1Id]); + Assert(d_nodes[t1Id].getKind() != kind::BUILTIN); + eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t1Id]); } } return; @@ -1466,7 +1454,8 @@ void EqualityEngine::getExplanation( // The current node currentNode = bfsQueue[currentIndex].d_nodeId; EqualityNodeId edgeNode = d_equalityEdges[currentEdge].getNodeId(); - unsigned reasonType = d_equalityEdges[currentEdge].getReasonType(); + MergeReasonType reasonType = static_cast<MergeReasonType>( + d_equalityEdges[currentEdge].getReasonType()); Node reason = d_equalityEdges[currentEdge].getReason(); Debug("equality") @@ -1482,8 +1471,9 @@ void EqualityEngine::getExplanation( << edge.getNodeId() << "} " << d_nodes[edge.getNodeId()] << ")" << std::endl; Debug("equality") - << d_name << " reason type = " - << static_cast<MergeReasonType>(reasonType) << std::endl; + << d_name + << " reason type = " << reasonType + << "\n"; std::shared_ptr<EqProof> eqpc;; // Make child proof if a proof is being constructed @@ -1518,63 +1508,21 @@ void EqualityEngine::getExplanation( { eqpc->d_children.push_back(eqpc1); eqpc->d_children.push_back(eqpc2); - if (options::proofNew()) + // build conclusion if ids correspond to non-internal nodes or + // if non-internal nodes can be retrieved from them (in the + // case of n-ary applications), otherwise leave conclusion as + // null. This is only done for congruence kinds, since + // congruence is not used otherwise. + Kind k = d_nodes[currentNode].getKind(); + if (d_congruenceKinds[k]) { - // build conclusion if ids correspond to non-internal nodes or - // if non-internal nodes can be retrieved from them (in the - // case of n-ary applications), otherwise leave conclusion as - // null. This is only done for congruence kinds, since - // congruence is not used otherwise. - Kind k = d_nodes[currentNode].getKind(); - if (d_congruenceKinds[k]) - { - buildEqConclusion(currentNode, edgeNode, eqpc.get()); - } - else - { - Assert(k == kind::EQUAL) - << "not an internal node " << d_nodes[currentNode] - << " with non-congruence with " << k << "\n"; - } - } - else if (d_nodes[currentNode].getKind() == kind::EQUAL) - { - //leave node null for now - eqpc->d_node = Node::null(); + buildEqConclusion(currentNode, edgeNode, eqpc.get()); } else { - if (d_nodes[f1.d_a].getKind() == kind::APPLY_UF - || d_nodes[f1.d_a].getKind() == kind::SELECT - || d_nodes[f1.d_a].getKind() == kind::STORE) - { - eqpc->d_node = d_nodes[f1.d_a]; - } - else - { - if (d_nodes[f1.d_a].getKind() == kind::BUILTIN - && d_nodes[f1.d_a].getConst<Kind>() == kind::SELECT) - { - eqpc->d_node = NodeManager::currentNM()->mkNode( - kind::PARTIAL_SELECT_1, d_nodes[f1.d_b]); - // The first child is a PARTIAL_SELECT_0. - // Give it a child so that we know what kind of (read) it is, when we dump to LFSC. - Assert(eqpc->d_children[0]->d_node.getKind() - == kind::PARTIAL_SELECT_0); - Assert(eqpc->d_children[0]->d_children.size() == 0); - - eqpc->d_children[0]->d_node = - NodeManager::currentNM()->mkNode( - kind::PARTIAL_SELECT_0, d_nodes[f1.d_b]); - } - else - { - eqpc->d_node = NodeManager::currentNM()->mkNode( - kind::PARTIAL_APPLY_UF, - ProofManager::currentPM()->mkOp(d_nodes[f1.d_a]), - d_nodes[f1.d_b]); - } - } + Assert(k == kind::EQUAL) + << "not an internal node " << d_nodes[currentNode] + << " with non-congruence with " << k << "\n"; } } Debug("equality") << pop; @@ -1608,7 +1556,7 @@ void EqualityEngine::getExplanation( // Get the node we interpreted TNode interpreted; - if (eqpc && options::proofNew()) + if (eqpc) { // build the conclusion f(c1, ..., cn) = c if (d_nodes[currentNode].isConst()) @@ -1661,24 +1609,19 @@ void EqualityEngine::getExplanation( Debug("equality") << d_name << "::eq::getExplanation(): adding: " << reason << std::endl; Debug("equality") - << d_name << "::eq::getExplanation(): reason type = " - << static_cast<MergeReasonType>(reasonType) << std::endl; + << d_name + << "::eq::getExplanation(): reason type = " << reasonType + << "\n"; Node a = d_nodes[currentNode]; Node b = d_nodes[d_equalityEdges[currentEdge].getNodeId()]; if (eqpc) { - //apply proof reconstruction processing (when eqpc is non-null) - if (d_pathReconstructionTriggers.find(reasonType) != d_pathReconstructionTriggers.end()) { - d_pathReconstructionTriggers.find(reasonType) - ->second->notify(reasonType, reason, a, b, equalities, - eqpc.get()); - } if (reasonType == MERGED_THROUGH_EQUALITY) { // in the new proof infrastructure we can assume that "theory // assumptions", which are a consequence of theory reasoning // on other assumptions, are externally justified. In this // case we can use (= a b) directly as the conclusion here. - eqpc->d_node = !options::proofNew() ? reason : b.eqNode(a); + eqpc->d_node = b.eqNode(a); } else { // The LFSC translator prefers (not (= a b)) over (= (= a b) false) @@ -1722,20 +1665,12 @@ void EqualityEngine::getExplanation( } else { eqp->d_id = MERGED_THROUGH_TRANS; eqp->d_children.insert( eqp->d_children.end(), eqp_trans.begin(), eqp_trans.end() ); - if (options::proofNew()) - { - // build conclusion in case of equality between non-internal - // nodes or of n-ary congruence kinds, otherwise leave as - // null. The latter is necessary for the overall handling of - // congruence proofs involving n-ary kinds, see - // EqProof::reduceNestedCongruence for more details. - buildEqConclusion(t1Id, t2Id, eqp); - } - else - { - eqp->d_node = NodeManager::currentNM()->mkNode( - kind::EQUAL, d_nodes[t1Id], d_nodes[t2Id]); - } + // build conclusion in case of equality between non-internal + // nodes or of n-ary congruence kinds, otherwise leave as + // null. The latter is necessary for the overall handling of + // congruence proofs involving n-ary kinds, see + // EqProof::reduceNestedCongruence for more details. + buildEqConclusion(t1Id, t2Id, eqp); } if (Debug.isOn("pf::ee")) { @@ -2218,18 +2153,6 @@ size_t EqualityEngine::getSize(TNode t) { return getEqualityNode(getEqualityNode(t).getFind()).getSize(); } - -void EqualityEngine::addPathReconstructionTrigger(unsigned trigger, const PathReconstructionNotify* notify) { - // Currently we can only inform one callback per trigger - Assert(d_pathReconstructionTriggers.find(trigger) - == d_pathReconstructionTriggers.end()); - d_pathReconstructionTriggers[trigger] = notify; -} - -unsigned EqualityEngine::getFreshMergeReasonType() { - return d_freshMergeReasonType++; -} - std::string EqualityEngine::identify() const { return d_name; } void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag) diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h index 19a10eba8..f8444965f 100644 --- a/src/theory/uf/equality_engine.h +++ b/src/theory/uf/equality_engine.h @@ -43,26 +43,10 @@ namespace CVC4 { namespace theory { namespace eq { - -class EqProof; class EqClassesIterator; class EqClassIterator; /** - * An interface for equality engine notifications during equality path reconstruction. - * Can be used to add theory-specific logic for, e.g., proof construction. - */ -class PathReconstructionNotify { -public: - - virtual ~PathReconstructionNotify() {} - - virtual void notify(unsigned reasonType, Node reason, Node a, Node b, - std::vector<TNode>& equalities, - EqProof* proof) const = 0; -}; - -/** * Class for keeping an incremental congruence closure over a set of terms. It provides * notifications via an EqualityEngineNotify object. */ @@ -152,9 +136,6 @@ private: /** The map of kinds with operators to be considered external (for higher-order) */ KindMap d_congruenceKindsExtOperators; - /** Objects that need to be notified during equality path reconstruction */ - std::map<unsigned, const PathReconstructionNotify*> d_pathReconstructionTriggers; - /** Map from nodes to their ids */ std::unordered_map<TNode, EqualityNodeId, TNodeHashFunction> d_nodeIds; @@ -196,9 +177,6 @@ private: /** Memory for the use-list nodes */ std::vector<UseListNode> d_useListNodes; - /** A fresh merge reason type to return upon request */ - unsigned d_freshMergeReasonType; - /** * We keep a list of asserted equalities. Not among original terms, but * among the class representatives. @@ -861,16 +839,6 @@ private: */ bool consistent() const { return !d_done; } - /** - * Marks an object for merge type based notification during equality path reconstruction. - */ - void addPathReconstructionTrigger(unsigned trigger, const PathReconstructionNotify* notify); - - /** - * Returns a fresh merge reason type tag for the client to use. - */ - unsigned getFreshMergeReasonType(); - /** Identify this equality engine (for debugging, etc..) */ std::string identify() const; }; diff --git a/src/theory/uf/equality_engine_types.h b/src/theory/uf/equality_engine_types.h index 14cd80436..cceffa51d 100644 --- a/src/theory/uf/equality_engine_types.h +++ b/src/theory/uf/equality_engine_types.h @@ -63,20 +63,26 @@ static const EqualityEdgeId null_edge = (EqualityEdgeId)(-1); * or a merge of an equality to false due to both sides being * (different) constants. */ -enum MergeReasonType { - /** Terms were merged due to application of congruence closure */ +enum MergeReasonType +{ + /** Terms were merged due to congruence */ MERGED_THROUGH_CONGRUENCE, - /** Terms were merged due to application of pure equality */ + /** Terms were merged due to an assumption */ MERGED_THROUGH_EQUALITY, - /** Equality was merged to true, due to both sides of equality being in the same class */ + /** Terms were merged due to reflexivity */ MERGED_THROUGH_REFLEXIVITY, - /** Equality was merged to false, due to both sides of equality being a constant */ + /** Terms were merged due to theory reasoning */ MERGED_THROUGH_CONSTANTS, - /** (for proofs only) Equality was merged due to transitivity */ + /** Terms were merged due to transitivity */ MERGED_THROUGH_TRANS, - - /** Reason types beyond this constant are theory specific reasons */ - NUMBER_OF_MERGE_REASONS + // TEMPORARY RULES WHILE WE DON'T MIGRATE TO PROOF_NEW + + /** Terms were merged due to arrays read-over-write */ + MERGED_THROUGH_ROW, + /** Terms were merged due to arrays read-over-write (1) */ + MERGED_THROUGH_ROW1, + /** Terms were merged due to extensionality */ + MERGED_THROUGH_EXT, }; inline std::ostream& operator << (std::ostream& out, MergeReasonType reason) { @@ -90,13 +96,13 @@ inline std::ostream& operator << (std::ostream& out, MergeReasonType reason) { case MERGED_THROUGH_REFLEXIVITY: out << "reflexivity"; break; - case MERGED_THROUGH_CONSTANTS: - out << "constants disequal"; - break; + case MERGED_THROUGH_CONSTANTS: out << "theory constants"; break; case MERGED_THROUGH_TRANS: out << "transitivity"; break; - + case MERGED_THROUGH_ROW: out << "read-over-write"; break; + case MERGED_THROUGH_ROW1: out << "read-over-write (1)"; break; + case MERGED_THROUGH_EXT: out << "extensionality"; break; default: out << "[theory]"; break; diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp index f94cc36af..3d90637e2 100644 --- a/src/theory/uf/theory_uf.cpp +++ b/src/theory/uf/theory_uf.cpp @@ -25,9 +25,6 @@ #include "options/smt_options.h" #include "options/theory_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/cardinality_extension.h" @@ -288,39 +285,30 @@ bool TheoryUF::propagateLit(TNode literal) return ok; }/* TheoryUF::propagate(TNode) */ -void TheoryUF::explain(TNode literal, std::vector<TNode>& assumptions, eq::EqProof* pf) { +void TheoryUF::explain(TNode literal, Node& exp) +{ + Debug("uf") << "TheoryUF::explain(" << literal << ")" << std::endl; + std::vector<TNode> assumptions; // Do the work bool polarity = literal.getKind() != kind::NOT; TNode atom = polarity ? literal : literal[0]; - if (atom.getKind() == kind::EQUAL) { + if (atom.getKind() == kind::EQUAL) + { d_equalityEngine->explainEquality( - atom[0], atom[1], polarity, assumptions, pf); - } else { - d_equalityEngine->explainPredicate(atom, polarity, assumptions, pf); - } - if( pf ){ - Debug("pf::uf") << std::endl; - pf->debug_print("pf::uf"); + atom[0], atom[1], polarity, assumptions, nullptr); } - - Debug("pf::uf") << "UF: explain( " << literal << " ):" << std::endl << "\t"; - for (unsigned i = 0; i < assumptions.size(); ++i) { - Debug("pf::uf") << assumptions[i] << " "; + else + { + d_equalityEngine->explainPredicate(atom, polarity, assumptions, nullptr); } - Debug("pf::uf") << std::endl; + exp = mkAnd(assumptions); } TrustNode TheoryUF::explain(TNode literal) { - Node exp = explain(literal, NULL); - return TrustNode::mkTrustPropExp(literal, exp, nullptr); -} - -Node TheoryUF::explain(TNode literal, eq::EqProof* pf) { - Debug("uf") << "TheoryUF::explain(" << literal << ")" << std::endl; - std::vector<TNode> assumptions; - explain(literal, assumptions, pf); - return mkAnd(assumptions); + Node explanation; + explain(literal, explanation); + return TrustNode::mkTrustPropExp(literal, explanation, nullptr); } bool TheoryUF::collectModelValues(TheoryModel* m, const std::set<Node>& termSet) @@ -662,12 +650,11 @@ void TheoryUF::computeCareGraph() { << std::endl; }/* TheoryUF::computeCareGraph() */ -void TheoryUF::conflict(TNode a, TNode b) { - std::shared_ptr<eq::EqProof> pf = - d_proofsEnabled ? std::make_shared<eq::EqProof>() : nullptr; - Node conf = explain(a.eqNode(b), pf.get()); - std::unique_ptr<ProofUF> puf(d_proofsEnabled ? new ProofUF(pf) : nullptr); - d_out->conflict(conf, std::move(puf)); +void TheoryUF::conflict(TNode a, TNode b) +{ + Node conf; + explain(a.eqNode(b), conf); + d_out->conflict(conf); d_state.notifyInConflict(); } diff --git a/src/theory/uf/theory_uf.h b/src/theory/uf/theory_uf.h index 2bfd7e16c..41f2ba9d5 100644 --- a/src/theory/uf/theory_uf.h +++ b/src/theory/uf/theory_uf.h @@ -112,17 +112,6 @@ private: */ bool propagateLit(TNode literal); - /** - * Explain why this literal is true by adding assumptions - * with proof (if "pf" is non-NULL). - */ - 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); - /** All the function terms that the theory has seen */ context::CDList<TNode> d_functionsTerms; @@ -202,6 +191,9 @@ private: CardinalityExtension* getCardinalityExtension() const { return d_thss.get(); } private: + /** Explain why this literal is true by building an explanation */ + void explain(TNode literal, Node& exp); + bool areCareDisequal(TNode x, TNode y); void addCarePairs(const TNodeTrie* t1, const TNodeTrie* t2, diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 09bbfc518..0977714c2 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -26,7 +26,6 @@ libcvc4_add_sources( ostream_util.h poly_util.cpp poly_util.h - proof.h random.cpp random.h resource_manager.cpp diff --git a/src/util/proof.h b/src/util/proof.h deleted file mode 100644 index c89a3b0a6..000000000 --- a/src/util/proof.h +++ /dev/null @@ -1,44 +0,0 @@ -/********************* */ -/*! \file proof.h - ** \verbatim - ** Top contributors (to current version): - ** Tim King, Morgan Deters, Mathias Preiner - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS - ** in the top-level source directory) and their institutional affiliations. - ** All rights reserved. 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_public.h" - -#ifndef CVC4__PROOF_H -#define CVC4__PROOF_H - -#include <iosfwd> -#include <unordered_map> - -namespace CVC4 { - -class Expr; -class ProofLetCount; -struct ExprHashFunction; - -typedef std::unordered_map<Expr, ProofLetCount, ExprHashFunction> ProofLetMap; - -class CVC4_PUBLIC Proof -{ - public: - virtual ~Proof() {} - virtual void toStream(std::ostream& out) const = 0; - virtual void toStream(std::ostream& out, const ProofLetMap& map) const = 0; -};/* class Proof */ - -}/* CVC4 namespace */ - -#endif /* CVC4__PROOF_H */ |