From: Haniel Barbosa Date: Tue, 1 Sep 2020 22:08:23 +0000 (-0300) Subject: Removes old proof code (#4964) X-Git-Tag: cvc5-1.0.0~2924 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=8ad308b;p=cvc5.git Removes old proof code (#4964) This deletes much of the old proof code. Basically everything but the minimal necessary infra-structure for producing unsat cores. That includes dependency tracking in preprocessing, the prop engine proof and the unsat core computation code in the old proof manager. These should also go once we fully integrate into master the new proof infrastructure. It also cleans interfaces that were using old-proof-code-specific constructs (such as LemmaProofRecipe). When possible or when it made sense standalone local proof production code was kept, but deactivated (such is in the equality engine and in the arithmetic solver). --- 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 @@ -2,44 +2,6 @@ id = "BV" name = "Bitvector theory" header = "options/bv_options.h" -[[option]] - name = "bvProofFormat" - category = "expert" - long = "bv-proof-format=MODE" - type = "BvProofFormat" - default = "ER" - predicates = ["checkSatSolverEnabled"] - 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"] - 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" 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 @@ -130,24 +130,6 @@ header = "options/smt_options.h" name = "values" 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" @@ -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& 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 -#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::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 #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(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(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(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(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 #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 -#include - -#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 subTrans = - std::make_shared(); - 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> 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> 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 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()); - } 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()); - } 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 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(); - 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(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(); - 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 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(); - 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(); - // 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& 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 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 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 -#include - -#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 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 d_proof; -}; - -namespace theory { -namespace arith { -class TheoryArith; -} -} - -typedef std::unordered_set TypeSet; - - -class ArithProof : public TheoryProof { -protected: - // std::map 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& 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 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 -#include - -#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 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& conflict) const -{ - return d_lemmasToFarkasCoefficients.find(conflict) - != d_lemmasToFarkasCoefficients.end(); -} - -std::pair -ArithProofRecorder::getFarkasCoefficients(const std::set& 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 -#include - -#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& 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 getFarkasCoefficients( - const std::set& conflict) const; - - protected: - // For each lemma, save the Farkas coefficients of that lemma - std::map, std::pair> - 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 - -#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 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 subTrans = - std::make_shared(); - - 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 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()); - } 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()); - } 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 childToStream; - - std::pair 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 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& 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 -#include - -#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 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 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 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 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& 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* 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().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().d_repeatAmount; - os << amount <<" _ "; - } - if (term.getKind() == kind::BITVECTOR_SIGN_EXTEND) { - unsigned amount = - term.getOperator().getConst().d_signExtendAmount; - os << amount <<" _ "; - } - - if (term.getKind() == kind::BITVECTOR_ZERO_EXTEND) { - unsigned amount = - term.getOperator().getConst().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::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_"<().d_repeatAmount; - os << amount; - } - if (term.getKind() == kind::BITVECTOR_SIGN_EXTEND) { - unsigned amount = - term.getOperator().getConst().d_signExtendAmount; - os << amount; - } - - if (term.getKind() == kind::BITVECTOR_ZERO_EXTEND) { - unsigned amount = - term.getOperator().getConst().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 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::const_iterator it = d_bbTerms.begin(); - std::vector::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::const_iterator it = d_bbTerms.begin(); - std::vector::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(); - 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()) { - 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* 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 -#include -#include -#include - -#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 TBitblaster; -} -} // namespace theory -} // namespace CVC4 - -namespace CVC4 { - -namespace proof { - -typedef std::unordered_set ExprSet; -typedef std::unordered_map ExprToClauseId; -typedef std::unordered_map ExprToId; -typedef std::unordered_map ExprToExpr; -typedef std::unordered_map 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 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* 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 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 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 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* 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* 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& conflicts){}; - - private: - ExprToString d_exprToVariableName; - - ExprToString d_assignedAliases; - std::map 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 -#include -#include -#include - -#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 formStream = openTmpFile(&formulaFilename); - const int64_t startPos = static_cast(formStream->tellp()); - printDimacs(*formStream, d_clauses, d_originalClauseIndices); - d_dratOptimizationStatistics.d_initialFormulaSize.setData( - static_cast(formStream->tellp()) - startPos); - formStream->close(); - } - - { - std::unique_ptr dratStream = openTmpFile(&dratFilename); - const int64_t startPos = static_cast(dratStream->tellp()); - (*dratStream) << d_binaryDratProof.str(); - d_dratOptimizationStatistics.d_initialDratSize.setData( - static_cast(dratStream->tellp()) - startPos); - dratStream->close(); - } - - std::unique_ptr optDratStream = openTmpFile(&optDratFilename); - std::unique_ptr 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(d_binaryDratProof.tellp()); - std::ifstream lratStream(optDratFilename); - std::copy(std::istreambuf_iterator(lratStream), - std::istreambuf_iterator(), - std::ostreambuf_iterator(d_binaryDratProof)); - d_dratOptimizationStatistics.d_optimizedDratSize.setData( - static_cast(d_binaryDratProof.tellp()) - startPos); - } - - if (options::bvOptimizeSatProof() == options::BvOptimizeSatProof::FORMULA) - { - std::ifstream optFormulaInStream{optFormulaFilename}; - const int64_t startPos = static_cast(optFormulaInStream.tellg()); - std::vector core = parseDimacs(optFormulaInStream); - d_dratOptimizationStatistics.d_optimizedFormulaSize.setData( - static_cast(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 - 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& 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 -#include -#include - -#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 d_clauses{}; - std::vector d_originalClauseIndices{}; - // Stores the proof recieved from the SAT solver. - std::ostringstream d_binaryDratProof{}; - std::vector 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& 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(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(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 &lemma) { - Assert(d_lemmaToProofRecipe.find(lemma) != d_lemmaToProofRecipe.end()); - return d_lemmaToProofRecipe[lemma]; -} - -bool CnfProof::haveProofRecipe(const std::set &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(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& 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& 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& 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 clause_expr; - std::set 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> CnfProof::detectTrivialTautology( - const prop::SatClause& clause) +bool CnfProof::getCurrentAssertionKind() { - // a map from a SatVariable to its previous occurence's polarity and location - std::map> 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::make_pair(iter->second.second, i)}; - } - else - { - return Maybe>{ - std::make_pair(i, iter->second.second)}; - } - } - varsToPolsAndIndices[var] = std::make_pair(polarity, i); - } - return Maybe>{}; -} - -void LFSCCnfProof::printAtomMapping(const std::set& atoms, - std::ostream& os, - std::ostream& paren) { - std::set::const_iterator it = atoms.begin(); - std::set::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& atoms, - std::ostream& os, - std::ostream& paren, - ProofLetMap &letMap) { - std::set::const_iterator it = atoms.begin(); - std::set::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& childIndex, - std::map& 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> 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 childIndex; - std::map 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::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 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 NodeToNode; typedef std::unordered_set ClauseIdSet; typedef context::CDHashMap ClauseIdToNode; -typedef context::CDHashMap NodeToProofRule; -typedef std::map, LemmaProofRecipe> LemmaToRecipe; typedef std::pair NodePair; typedef std::set NodePairSet; +typedef std::unordered_set 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 d_currentAssertionStack; - - /** Top of stack is top-level fact currently being converted to CNF **/ - std::vector 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> 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& atoms); - void collectAtomsForClauses(const IdToSatClause& clauses, - std::set& atoms); - void collectAtomsAndRewritesForLemmas(const IdToSatClause& lemmaClauses, - std::set& 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 &lemma); - bool haveProofRecipe(const std::set &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& atoms, - std::ostream& os, - std::ostream& paren) = 0; - virtual void printAtomMapping(const std::set& 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> 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& childIndex, - std::map& 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& atoms, - std::ostream& os, - std::ostream& paren) override; - - void printAtomMapping(const std::set& 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 - -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& clauses, - const std::vector& 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 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 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(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 -#include -#include - -#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& clauses, - const std::vector& usedIndices); - -std::vector 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 -#include -#include - -#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& 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(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(os), i.d_clause.size(), ')'); - os << "\n"; - } - os << "DRATProofn"; - std::fill_n(std::ostream_iterator(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& 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 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 -#include -#include -#include -#include -#include -#include - -#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 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 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& clauses, - const std::vector& 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 formStream = openTmpFile(&formulaFilename); - printDimacs(*formStream, clauses, usedIds); - formStream->close(); - - // Write the (binary) DRAT proof - std::unique_ptr dratStream = openTmpFile(&dratFilename); - (*dratStream) << dratBinary; - dratStream->close(); - - std::unique_ptr 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& clauses, - const std::vector& 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> 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 - traceCheckClause{d_tracecheck.d_lines[i].d_clause.begin(), - d_tracecheck.d_lines[i].d_clause.end()}; - std::unordered_set - 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 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 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& chain = - d_tracecheck.d_lines[cId - 1].d_chain; - const std::vector 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(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& 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 ErProof::computePivotsForChain( - const std::vector& chain) const -{ - std::vector pivots; - - const prop::SatClause& first = d_tracecheck.d_lines[chain[0] - 1].d_clause; - std::unordered_set - 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 -#include -#include - -#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&& 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 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&& clause, - std::vector&& chain) - : d_idx(idx), d_clause(clause), d_chain(chain) - { - } - - // The index of the new clause - TraceCheckIdx d_idx; - // The new clause - std::vector 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 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 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& clauses, - const std::vector& 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& clauses, - const std::vector& 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& getInputClauseIds() const - { - return d_inputClauseIds; - } - - const std::vector& 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 computePivotsForChain( - const std::vector& 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 d_inputClauseIds; - // A list of new variable definitions, in order. - std::vector 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 LemmaProofRecipe::ProofStep::getAssertions() const { - return d_assertions; -} - -void LemmaProofRecipe::addStep(ProofStep& proofStep) { - d_proofSteps.push_back(proofStep); -} - -std::set LemmaProofRecipe::getMissingAssertionsForStep(unsigned index) const { - Assert(index < d_proofSteps.size()); - - std::set 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 neededAssertions = d_proofSteps[revIndex].getAssertions(); - - std::set 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::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 missingAssertions = getMissingAssertionsForStep(count - 1); - for (std::set::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::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 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 - -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 getAssertions() const; - - private: - theory::TheoryId d_theory; - Node d_literalToProve; - std::set d_assertions; - }; - - //* The lemma assertions and owner */ - void addBaseAssertion(Node baseAssertion); - std::set getBaseAssertions() const; - theory::TheoryId getTheory() const; - - //* Rewrite rules */ - using RewriteIterator = std::map::const_iterator; - RewriteIterator rewriteBegin() const; - RewriteIterator rewriteEnd() const; - - // Steps iterator - // The default iterator for a LemmaProofRecipe - using iterator = std::vector::reverse_iterator; - std::vector::reverse_iterator begin(); - std::vector::reverse_iterator end(); - - using const_iterator = std::vector::const_reverse_iterator; - std::vector::const_reverse_iterator begin() const; - std::vector::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 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 d_baseAssertions; - - //* The various steps needed to derive the empty clause */ - // The "first" step is actually at the back. - std::vector d_proofSteps; - - //* A map from assertions to their rewritten explanations (toAssert --> toExplain) */ - std::map 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 -#include -#include - -#include "prop/bvminisat/core/Solver.h" -#include "prop/minisat/core/Solver.h" - -namespace CVC4 { -namespace proof { - -template -std::string LFSCProofPrinter::clauseName(TSatProof* 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 -void LFSCProofPrinter::printResolution(TSatProof* satProof, - ClauseId id, - std::ostream& out, - std::ostream& paren) -{ - out << "(satlem_simplify _ _ _"; - paren << ")"; - - const ResChain& res = satProof->getResolutionChain(id); - const typename ResChain::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 -void LFSCProofPrinter::printAssumptionsResolution(TSatProof* 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& confl = - *(satProof->getAssumptionConflicts().at(id)); - - Assert(confl.size()); - - for (unsigned i = 0; i < confl.size(); ++i) - { - prop::SatLiteral lit = toSatLiteral(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(confl[i]); - prop::SatVariable v = lit.getSatVariable(); - out << "unit" << v << " "; - out << ProofManager::getVarName(v, satProof->getName()) << ")"; - } - out << "(\\ e e)\n"; - paren << ")"; -} - -template -void LFSCProofPrinter::printResolutions(TSatProof* satProof, - std::ostream& out, - std::ostream& paren) -{ - Debug("bv-proof") << "; print resolutions" << std::endl; - std::set::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 -void LFSCProofPrinter::printResolutionEmptyClause(TSatProof* satProof, - std::ostream& out, - std::ostream& paren) -{ - printResolution(satProof, satProof->getEmptyClauseId(), out, paren); -} - -void LFSCProofPrinter::printSatInputProof(const std::vector& 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(out), clauses.size(), ')'); -} - -void LFSCProofPrinter::printCMapProof(const std::vector& 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(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(out), clause.size(), ')'); -} - -// Template specializations -template void LFSCProofPrinter::printAssumptionsResolution( - TSatProof* satProof, - ClauseId id, - std::ostream& out, - std::ostream& paren); -template void LFSCProofPrinter::printResolutions( - TSatProof* satProof, - std::ostream& out, - std::ostream& paren); -template void LFSCProofPrinter::printResolutionEmptyClause( - TSatProof* satProof, - std::ostream& out, - std::ostream& paren); - -template void LFSCProofPrinter::printAssumptionsResolution( - TSatProof* satProof, - ClauseId id, - std::ostream& out, - std::ostream& paren); -template void LFSCProofPrinter::printResolutions( - TSatProof* satProof, - std::ostream& out, - std::ostream& paren); -template void LFSCProofPrinter::printResolutionEmptyClause( - TSatProof* 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 -#include -#include - -#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 - static void printAssumptionsResolution(TSatProof* 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 - static void printResolutions(TSatProof* 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 - static void printResolutionEmptyClause(TSatProof* 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& 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& 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 - static std::string clauseName(TSatProof* 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 - static void printResolution(TSatProof* 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 -#include -#include -#include -#include -#include -#include - -#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(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>& hints) -{ - for (auto& hint : hints) - { - o << "\n (RATHintsc " << hint.first << " "; - printTrace(o, hint.second); - o << " "; - } - o << "RATHintsn"; - std::fill_n(std::ostream_iterator(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& 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(o), indices.size(), ')'); -} - -} // namespace - -// Prints the LRAT addition line in textual format - -LratProof LratProof::fromDratProof( - const std::unordered_map& clauses, - const std::vector 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 formStream = openTmpFile(&formulaFilename); - printDimacs(*formStream, clauses, usedIds); - formStream->close(); - - std::unique_ptr dratStream = openTmpFile(&dratFilename); - (*dratStream) << dratBinary; - dratStream->close(); - - std::unique_ptr 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 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 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 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> resolvants; - for (; i<0; textualProof>> i) - { - Assert(textualProof.good()); - // Create an entry in the RAT hint list - resolvants.emplace_back(-i, std::vector()); - - // 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 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 -#include -#include -#include -#include - -#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 -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&& 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 d_clauses; -}; - -// A sequence of locations that will contain unit clauses during unit -// propegation -using LratUPTrace = std::vector; - -class LratAddition : public LratInstruction -{ - public: - LratAddition(ClauseIdx idxOfClause, - prop::SatClause&& clause, - LratUPTrace&& atTrace, - std::vector> 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> 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& clauses, - const std::vector 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>&& instructions) - : d_instructions(std::move(instructions)) - { - // Nothing else - } - - const std::vector>& 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> 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& nodes) { - std::ostringstream os; - std::set::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(getCnfProof()), - static_cast(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(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(true); Node false_node = NodeManager::currentNM()->mkConst(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(true)) || - (n.getKind() == kind::NOT && n[0] == NodeManager::currentNM()->mkConst(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 deps = (*d_deps.find(n)).second; - for(std::vector::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 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 &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 seen; - - Debug("pf::lemmasUnsatCore") << "Dumping all lemmas in unsat core" << std::endl; - for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) { - std::set 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 ProofManager::satClauseToNodeSet(prop::SatClause* clause) { - std::set 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& 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::iterator lemmaIt; - - if (!options::aggressiveCoreMin()) { - for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) { - std::set 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 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& 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 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 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::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::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::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(true)) || - ((*it).getKind() == kind::NOT && (*it)[0] == NodeManager::currentNM()->mkConst(false))) { - inputAssertion = NodeManager::currentNM()->mkConst(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::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::SELECT) - || (n.getConst() == 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 v; - v.push_back(NodeManager::currentNM()->integerType()); - if(n.getConst() == kind::SELECT) { - v.push_back(NodeManager::currentNM()->integerType()); - v.push_back(NodeManager::currentNM()->integerType()); - } else if(n.getConst() == 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 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& atoms, - ProofLetMap& letMap, - std::ostream& out, - std::ostringstream& paren) { - Bindings letOrder; - std::set::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* 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 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 LFSCSatProof; -typedef TSatProof CoreSatProof; -class LFSCCnfProof; -class LFSCTheoryProofEngine; -class LFSCUFProof; -class LFSCRewriterProof; +typedef TSatProof CoreSatProof; namespace prop { typedef uint64_t SatVariable; @@ -88,291 +56,72 @@ namespace prop { typedef std::vector 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 IdToSatClause; typedef context::CDHashSet CDExprSet; -typedef std::unordered_map, NodeHashFunction> NodeToNodes; typedef context::CDHashMap, NodeHashFunction> CDNodeToNodes; typedef std::unordered_set 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 d_satProof; std::unique_ptr d_cnfProof; - std::unique_ptr d_theoryProof; // information that will need to be shared across proofs - ExprSet d_inputFormulas; - std::map d_inputFormulaToName; CDExprSet d_inputCoreFormulas; CDExprSet d_outputCoreFormulas; - SkolemizationManager d_skolemizationManager; - int d_nextId; - std::unique_ptr d_fullProof; - ProofFormat d_format; // used for now only in debug builds - CDNodeToNodes d_deps; - std::set d_printedTypes; - - std::map d_rewriteFilters; - std::map d_assertionFilters; - - std::vector 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 d_ops; - std::map 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 extractUnsatCore(); - - bool unsatCoreAvailable() const; - void getLemmasInUnsatCore(theory::TheoryId theory, std::vector &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 getRewriteLog(); - void dumpRewriteLog() const; + ProofManager(context::Context* context); + ~ProofManager(); - void printGlobalLetMap(std::set& 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 extractUnsatCore(); - ProofManagerStatistics& getStats() { return d_stats; } + bool unsatCoreAvailable() const; + void getLemmasInUnsatCore(std::vector& lemmas); - private: - void constructSatProof(); - std::set 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 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 -#include -#include - -#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 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 d_proof; - Node d_lemma; - std::set d_propagations; -}; /* class ProofOutputChannel */ - -class MyPreRegisterVisitor { - theory::Theory* d_theory; - std::unordered_set 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 -#include -#include -#include - -#include "expr/node_manager.h" - -namespace CVC4 { - -typedef std::unordered_set ExprSet; -typedef std::unordered_set NodeSet; - -typedef std::pair NodePair; -typedef std::set 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 Bindings; - -namespace utils { - -std::string toLFSCKind(Kind kind); -std::string toLFSCKindTerm(Expr node); - -inline unsigned getExtractHigh(Expr node) { - return node.getOperator().getConst().d_high; -} - -inline unsigned getExtractLow(Expr node) { - return node.getOperator().getConst().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(true); -} - -inline Expr mkFalse() { - return NodeManager::currentNM()->toExprManager()->mkConst(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& children) { - return NodeManager::currentNM()->toExprManager()->mkExpr(k, children); -} - - -inline Expr mkOnes(unsigned size) { - BitVector val = BitVector::mkOnes(size); - return NodeManager::currentNM()->toExprManager()->mkConst(val); -} - -inline Expr mkConst(unsigned size, unsigned int value) { - BitVector val(size, value); - return NodeManager::currentNM()->toExprManager()->mkConst(val); -} - -inline Expr mkConst(const BitVector& value) { - return NodeManager::currentNM()->toExprManager()->mkConst(value); -} - -inline Expr mkOr(const std::vector& nodes) { - std::set 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::const_iterator it = all.begin(); - std::set::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& conjunctions) { - std::set 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::const_iterator it = all.begin(); - std::set::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& children) { - std::set 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::const_iterator it = all.begin(); - std::set::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().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 -#include - -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_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& 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()) - || (confl.getKind() == kind::NOT && confl[0].isConst() - && !confl[0].getConst())) - { - ignoreConflict = true; - } - else if (confl.getKind() == kind::OR) - { - for (unsigned k = 0; k < confl.getNumChildren(); ++k) - { - if ((confl[k].isConst() && confl[k].getConst()) - || (confl[k].getKind() == kind::NOT && confl[k][0].isConst() - && !confl[k][0].getConst())) - { - 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& 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::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 - -#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 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& 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 d_resolutionProof; - - bool d_isAssumptionConflict; - -}; - -class LfscResolutionBitVectorProof : public ResolutionBitVectorProof -{ - public: - LfscResolutionBitVectorProof(theory::bv::TheoryBV* bv, - TheoryProofEngine* proofEngine) - : ResolutionBitVectorProof(bv, proofEngine) - { - } - void printTheoryLemmaProof(std::vector& 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::registerResolution(ClauseId id, ResChain* res) { Assert(checkResolution(id)); } - PSTATS(uint64_t resolutionSteps = - static_cast(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::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 void TSatProof::constructProof(ClauseId conflict) { d_satProofConstructed = true; @@ -1002,9 +986,6 @@ void TSatProof::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::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 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::const_iterator SkolemizationManager::begin() { - return d_disequalityToSkolem.begin(); -} - -std::unordered_map::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 -#include - -#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::const_iterator begin(); - std::unordered_map::const_iterator end(); - -private: - std::unordered_map d_disequalityToSkolem; - std::unordered_map 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(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(th); - Assert(d_theoryProofTable.find(id) != d_theoryProofTable.end()); - proof::BitVectorProof* bvp = - static_cast(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 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" <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 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 bv_lemmas; - - for (IdToSatClause::const_iterator it = lemmas.begin(); it != lemmas.end(); ++it) { - const prop::SatClause* clause = it->second; - - std::vector conflict; - std::set 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 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 missingAssertions = recipe.getMissingAssertionsForStep(i); - std::map explanationToMissingAssertion; - std::set::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 clause_expr; - std::set 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 missingAssertions = recipe.getMissingAssertionsForStep(0); - if (!missingAssertions.empty()) { - Debug("pf::tp") << "Have missing assertions for this simple lemma!" << std::endl; - } - - std::set::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 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 missingAssertions = recipe.getMissingAssertionsForStep(i); - if (!missingAssertions.empty()) { - Debug("pf::tp") << "Have missing assertions for this step!" << std::endl; - } - - // Turn rewrite filter ON - std::set::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& 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; igetId() == theory::Theory::theoryOf(strippedLit)) { - Node lit = Node::fromExpr( lemma[i] ).negate(); - Trace("pf::tp") << "; preregistering and asserting " << lit << std::endl; - NodeVisitor::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() ? "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& 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 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> - 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> 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 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(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 -#include -#include - -#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 ExprSet; -typedef std::map TheoryProofTable; - -typedef std::set TheoryIdSet; -typedef std::map 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 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 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 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& 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& 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 - -#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 subTrans = - std::make_shared(); - - 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 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()); - } 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()); - } 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 childToStream; - std::pair 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 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& 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 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 -#include - -#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 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 d_proof; -}; - -namespace theory { -namespace uf { -class TheoryUF; -} -} - -typedef std::unordered_set 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& 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& explanation) { std::vector 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 #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 d_minisat; - std::unique_ptr d_minisatNotify; + std::unique_ptr d_minisat; + std::unique_ptr d_minisatNotify; unsigned d_assertionsCount; context::CDO 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& ps, ClauseId& id) if (decisionLevel() > 0) { cancelUntil(0); } - + if (!ok) { id = ClauseIdUndef; return false; @@ -231,7 +225,7 @@ bool Solver::addClause_(vec& 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& 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&) (out_btlevel : int&) -> [void] -| +| analyze : (confl : Clause*) (out_learnt : vec&) (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& out_learnt, int& out_btlevel, UIP uip) { @@ -454,8 +394,6 @@ void Solver::analyze(CRef confl, vec& 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& 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& 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& 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& 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& 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& out_conflict) { @@ -716,22 +623,14 @@ void Solver::analyzeFinal(Lit p, vec& 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& 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& 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 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& 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 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& 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& explanation) { } } seen[var(p)] = 0; - - if(d_bvp){ - vec 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& map, Var& max) @@ -1454,7 +1273,7 @@ void Solver::toDimacs(FILE* f, const vec& 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& 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* 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 TLitVec; @@ -109,12 +102,17 @@ public: Var trueVar() const { return varTrue; } Var falseVar() const { return varFalse; } - - bool addClause (const vec& ps, ClauseId& id); // Add a clause to the solver. + bool addClause(const vec& 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& 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& 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 RegionAllocator::free(clauseWord32Size(c.size(), c.has_extra())); } - void reloc(CRef& cr, - ClauseAllocator& to, - CVC4::TSatProof* 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 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 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& 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& cls = occurs.lookup(v); - + vec& 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 @@ -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 xor_clause; @@ -119,36 +118,19 @@ ClauseId CryptoMinisatSolver::addClause(SatClause& clause, bool removable){ } ++(d_statistics.d_clausesAdded); - + std::vector 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 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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 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& 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 TLitVec; @@ -98,7 +98,7 @@ public: vec lemmas_removable; /** Nodes being converted to CNF */ - std::vector > lemmas_cnf_assertion; + std::vector 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& assumps); // Write CNF to file in DIMACS-format. void toDimacs (const char *file, const vec& assumps); void toDimacs (FILE* f, Clause& c, vec& 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& } 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 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& 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& cls = occurs.lookup(v); - + vec& 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& 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& 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(pfStream.tellp()); - - pf.toStream(pfStream); - d_stats->d_proofsSize += - static_cast(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 > 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); @@ -920,11 +909,6 @@ class CVC4_PUBLIC SmtEngine return d_statisticsRegistry.get(); }; - /** - * 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 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 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 #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 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 #include #include +#include #include #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") << "("<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") << "("<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 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 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 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 - -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& 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 childProof = std::make_shared(); - 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 childProof = - std::make_shared(); - 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 constantDisequalityProof = - std::make_shared(); - 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>::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 childProof = - std::make_shared(); - 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& 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& 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 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 proof = d_proofsEnabled ? - std::make_shared() : nullptr; - d_conflictNode = explain(a.eqNode(b), proof.get()); + explain(a.eqNode(b), d_conflictNode); if (!d_inCheckModel) { - std::unique_ptr 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& 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 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 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 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 #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 d_nullContext; std::unique_ptr 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::TBitblaster() : d_termCache(), d_modelCache(), d_nullContext(new context::Context()), - d_cnfStream(), - d_bvp(nullptr) + d_cnfStream() { initAtomBBStrategies(); initTermBBStrategies(); @@ -217,20 +214,6 @@ void TBitblaster::invalidateModelCache() d_modelCache.clear(); } -template -void TBitblaster::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 Node TBitblaster::getTermModel(TNode node, bool fullModel) { 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 #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 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 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 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::applies(t)) { Node result = RewriteRule::run(t); res = Rewriter::rewrite(result); - } else if( res.getKind() == kind::EQUAL && - ((res[0].getKind() == kind::BITVECTOR_PLUS && - RewriteRule::applies(res[1])) || - (res[1].getKind() == kind::BITVECTOR_PLUS && - RewriteRule::applies(res[0])))) { + } + else if (res.getKind() == kind::EQUAL + && ((res[0].getKind() == kind::BITVECTOR_PLUS + && RewriteRule::applies(res[1])) + || (res[1].getKind() == kind::BITVECTOR_PLUS + && RewriteRule::applies(res[0])))) + { Node mult = RewriteRule::applies(res[0])? RewriteRule::run(res[0]) : RewriteRule::run(res[1]); @@ -743,9 +748,13 @@ TrustNode TheoryBV::ppRewrite(TNode t) } else { res = t; } - } else if (RewriteRule::applies(t)) { + } + else if (RewriteRule::applies(t)) + { res = RewriteRule::run(t); - } else if (RewriteRule::applies(t)) { + } + else if (RewriteRule::applies(t)) + { res = RewriteRule::run(t); } else if (RewriteRule::applies(t)) @@ -960,20 +969,6 @@ bool TheoryBV::applyAbstraction(const std::vector& 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& assertions, std::vector& new_assertions); - void setProofLog(proof::BitVectorProof* bvp); - private: class Statistics { @@ -197,7 +190,7 @@ class TheoryBV : public Theory { std::unique_ptr d_eagerSolver; std::unique_ptr d_abstractionModule; bool d_calledPreregister; - + //for extended functions bool d_needsLastCallCheck; context::CDHashSet 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) +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 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 #include +#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 #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 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 -#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; imkNode( 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& qs) bool Instantiate::getUnsatCoreLemmas(std::vector& 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& active_lemmas) return true; } -bool Instantiate::getUnsatCoreLemmas(std::vector& active_lemmas, - std::map& 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 >& 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& 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& active_lemmas, - std::map& 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& active_lemmas); - bool getUnsatCoreLemmas(std::vector& active_lemmas, - std::map& weak_imp); /** get explanation for instantiation lemmas */ void getExplanationForInstLemmas(const std::vector& lems, std::map& 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 #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::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(true); d_false = NodeManager::currentNM()->mkConst(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& 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()) { - ++ i; - continue; - } - if (flat[i].getKind() == kind::NOT && - flat[i][0].isConst() && !flat[i][0].getConst()) { - ++ 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()) || - (explanation.getKind() == kind::NOT && - explanation[0].isConst() && !explanation[0].getConst()))) { - 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 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 d_atoms; @@ -1504,7 +1431,6 @@ void TheoryEngine::ensureLemmaAtoms(const std::vector& 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()) { - ++ i; - continue; - } - if (conflict[i].getKind() == kind::NOT && - conflict[i][0].isConst() && !conflict[i][0].getConst()) { - ++ 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& explanationVector, LemmaProofRecipe* proofRecipe) { +void TheoryEngine::getExplanation( + std::vector& 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> inputAssertions = nullptr; - PROOF({ - if (proofRecipe) - { - inputAssertions.reset( - new std::set(proofRecipe->getStep(0)->getAssertions())); - } - }); // cache of nodes we have already explained by some theory std::unordered_map cache; @@ -1768,22 +1638,6 @@ void TheoryEngine::getExplanation(std::vector& 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& 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()) - || (flat[k].getKind() == kind::NOT && flat[k][0].isConst() - && !flat[k][0].getConst()))) - { - proofStep.addAssertion(flat[k].negate()); - } - } - } - else - { - if (!((explanation.isConst() && explanation.getConst()) - || (explanation.getKind() == kind::NOT - && explanation[0].isConst() - && !explanation[0].getConst()))) - { - 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& explanationVector, LemmaProofRecipe* lemmaProofRecipe); + void getExplanation(std::vector& explanationVector); public: /** @@ -569,12 +566,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. */ @@ -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 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(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(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(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(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> 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> 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::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 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( + 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(reasonType) << std::endl; + << d_name + << " reason type = " << reasonType + << "\n"; std::shared_ptr 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::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(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,25 +43,9 @@ 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& 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 d_pathReconstructionTriggers; - /** Map from nodes to their ids */ std::unordered_map d_nodeIds; @@ -196,9 +177,6 @@ private: /** Memory for the use-list nodes */ std::vector 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& assumptions, eq::EqProof* pf) { +void TheoryUF::explain(TNode literal, Node& exp) +{ + Debug("uf") << "TheoryUF::explain(" << literal << ")" << std::endl; + std::vector 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 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& termSet) @@ -662,12 +650,11 @@ void TheoryUF::computeCareGraph() { << std::endl; }/* TheoryUF::computeCareGraph() */ -void TheoryUF::conflict(TNode a, TNode b) { - std::shared_ptr pf = - d_proofsEnabled ? std::make_shared() : nullptr; - Node conf = explain(a.eqNode(b), pf.get()); - std::unique_ptr 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& 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 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 -#include - -namespace CVC4 { - -class Expr; -class ProofLetCount; -struct ExprHashFunction; - -typedef std::unordered_map 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 */ diff --git a/test/regress/CMakeLists.txt b/test/regress/CMakeLists.txt index 4de32a426..1a33ee3a5 100644 --- a/test/regress/CMakeLists.txt +++ b/test/regress/CMakeLists.txt @@ -622,7 +622,6 @@ set(regress_0_tests regress0/nl/very-easy-sat.smt2 regress0/nl/very-simple-unsat.smt2 regress0/options/invalid_dump.smt2 - regress0/options/invalid_option_inc_proofs.smt2 regress0/opt-abd-no-use.smt2 regress0/parallel-let.smt2 regress0/parser/as.smt2 @@ -872,7 +871,7 @@ set(regress_0_tests regress0/seq/seq-nth.smt2 regress0/seq/seq-nth-uf.smt2 regress0/seq/seq-nth-uf-z.smt2 - regress0/seq/seq-nth-undef.smt2 + regress0/seq/seq-nth-undef.smt2 regress0/seq/seq-rewrites.smt2 regress0/sets/abt-min.smt2 regress0/sets/abt-te-exh.smt2 diff --git a/test/regress/regress0/bug217.smt2 b/test/regress/regress0/bug217.smt2 index 30c87333e..4d2e828b5 100644 --- a/test/regress/regress0/bug217.smt2 +++ b/test/regress/regress0/bug217.smt2 @@ -1,4 +1,3 @@ -; COMMAND-LINE: --fewer-preprocessing-holes ; EXPECT: unsat (set-logic QF_UF) (set-info :status unsat) diff --git a/test/regress/regress0/options/invalid_option_inc_proofs.smt2 b/test/regress/regress0/options/invalid_option_inc_proofs.smt2 deleted file mode 100644 index f63dbd27f..000000000 --- a/test/regress/regress0/options/invalid_option_inc_proofs.smt2 +++ /dev/null @@ -1,6 +0,0 @@ -; REQUIRES: proof -; COMMAND-LINE: --incremental --proof -; EXPECT: (error "Error in option parsing: --incremental is not supported with proofs") -; EXIT: 1 -(set-logic QF_BV) -(check-sat) diff --git a/test/regress/regress1/bv/bench_38.delta.smt2 b/test/regress/regress1/bv/bench_38.delta.smt2 index 760614348..3f809716a 100644 --- a/test/regress/regress1/bv/bench_38.delta.smt2 +++ b/test/regress/regress1/bv/bench_38.delta.smt2 @@ -1,4 +1,4 @@ -; COMMAND-LINE: --fewer-preprocessing-holes --check-proof --quiet +; COMMAND-LINE: --quiet ; EXPECT: unsat (set-logic QF_BV) (declare-fun x () (_ BitVec 4)) diff --git a/test/regress/regress1/non-fatal-errors.smt2 b/test/regress/regress1/non-fatal-errors.smt2 index 1e1865883..ec3d02927 100644 --- a/test/regress/regress1/non-fatal-errors.smt2 +++ b/test/regress/regress1/non-fatal-errors.smt2 @@ -2,11 +2,10 @@ ; EXPECT: success ; EXPECT: success ; EXPECT: success +; EXPECT: unsupported ; EXPECT: success ; EXPECT: success ; EXPECT: success -; EXPECT: success -; EXPECT: (error "") ; EXPECT: (error "") ; EXPECT: (error "") ; EXPECT: (error "") @@ -22,7 +21,6 @@ (declare-fun p () Bool) (get-unsat-core) (get-value (p)) -(get-proof) (get-model) (get-assignment) (assert true) diff --git a/test/regress/regress1/quantifiers/dump-inst-proof.smt2 b/test/regress/regress1/quantifiers/dump-inst-proof.smt2 index 9edc4df2b..f900e78a9 100644 --- a/test/regress/regress1/quantifiers/dump-inst-proof.smt2 +++ b/test/regress/regress1/quantifiers/dump-inst-proof.smt2 @@ -1,5 +1,5 @@ ; REQUIRES: proof -; COMMAND-LINE: --dump-instantiations --proof --print-inst-full +; COMMAND-LINE: --dump-instantiations --produce-unsat-cores --print-inst-full ; EXPECT: unsat ; EXPECT: (instantiations (forall ((x Int)) (or (P x) (Q x)) ) ; EXPECT: ( 2 ) @@ -21,7 +21,7 @@ (assert (forall ((x Int)) (or (not (S x)) (not (Q x))))) (assert (and (not (R 0)) (not (R 10)) (not (S 1)) (not (P 2)))) (assert (S 2)) -; This tests that --proof minimizes the instantiations printed out. -; This regression should require only the 2 instantiations above, but -; may try more. +; This tests that --produce-unsat-cores minimizes the instantiations +; printed out. This regression should require only the 2 +; instantiations above, but may try more. (check-sat) diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index bd7c1ea22..bd7029c54 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -107,7 +107,6 @@ add_subdirectory(expr) add_subdirectory(main) add_subdirectory(parser) add_subdirectory(prop) -add_subdirectory(proof) add_subdirectory(theory) add_subdirectory(preprocessing) add_subdirectory(util) diff --git a/test/unit/proof/CMakeLists.txt b/test/unit/proof/CMakeLists.txt deleted file mode 100644 index 315c78d6f..000000000 --- a/test/unit/proof/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -#-----------------------------------------------------------------------------# -# Add unit tests - -cvc4_add_unit_test_black(drat_proof_black proof) -cvc4_add_unit_test_black(er_proof_black proof) -cvc4_add_unit_test_black(lrat_proof_black proof) -cvc4_add_unit_test_black(lfsc_proof_printer_black proof) diff --git a/test/unit/proof/drat_proof_black.h b/test/unit/proof/drat_proof_black.h deleted file mode 100644 index 4b593a588..000000000 --- a/test/unit/proof/drat_proof_black.h +++ /dev/null @@ -1,187 +0,0 @@ -/********************* */ -/*! \file drat_proof_black.h - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, 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 Black box testing of the DRAT proof class - ** - ** In particular, tests DRAT binary parsing. - **/ - -#include - -#include - -#include "proof/drat/drat_proof.h" - -using namespace CVC4::proof::drat; - -class DratProofBlack : public CxxTest::TestSuite -{ - public: - void setUp() override {} - void tearDown() override {} - - void testParseOneAdd(); - void testParseOneMediumAdd(); - void testParseOneBigAdd(); - void testParseLiteralIsTooBig(); - void testParseLiteralOverflow(); - void testParseClauseOverflow(); - - void testParseTwo(); - - void testOutputTwoAsText(); - void testOutputTwoAsLfsc(); -}; - -void DratProofBlack::testParseOneAdd() -{ - // a 1; - std::string input("a\x02\x00", 3); - DratProof proof = DratProof::fromBinary(input); - - TS_ASSERT_EQUALS(proof.getInstructions()[0].d_kind, ADDITION); - TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause.size(), 1); - TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause[0], - SatLiteral(0, false)); -} - -void DratProofBlack::testParseOneMediumAdd() -{ - // a -255; - std::string input("a\xff\x01\x00", 4); - DratProof proof = DratProof::fromBinary(input); - - TS_ASSERT_EQUALS(proof.getInstructions()[0].d_kind, ADDITION); - TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause.size(), 1); - TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause[0], - SatLiteral(126, true)); -} - -void DratProofBlack::testParseOneBigAdd() -{ - // a -2199023255551; - std::string input("a\xff\xff\xff\xff\xff\x7f\x00", 8); - DratProof proof = DratProof::fromBinary(input); - - TS_ASSERT_EQUALS(proof.getInstructions()[0].d_kind, ADDITION); - TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause.size(), 1); - TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause[0], - SatLiteral(2199023255550, true)); -} - -void DratProofBlack::testParseLiteralIsTooBig() -{ - std::string input("a\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x7f\x00", - 14); - TS_ASSERT_THROWS(DratProof::fromBinary(input), InvalidDratProofException&); -} - -void DratProofBlack::testParseLiteralOverflow() -{ - std::string input("a\x80", 2); - TS_ASSERT_THROWS(DratProof::fromBinary(input), InvalidDratProofException&); -} - -void DratProofBlack::testParseClauseOverflow() -{ - std::string input("a\x80\x01", 3); - TS_ASSERT_THROWS(DratProof::fromBinary(input), InvalidDratProofException&); -} - -void DratProofBlack::testParseTwo() -{ - // d -63 -8193 - // 129 -8191 - std::string input("\x64\x7f\x83\x80\x01\x00\x61\x82\x02\xff\x7f\x00", 12); - DratProof proof = DratProof::fromBinary(input); - - TS_ASSERT_EQUALS(proof.getInstructions()[0].d_kind, DELETION); - TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause.size(), 2); - TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause[0], - SatLiteral(62, true)); - TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause[1], - SatLiteral(8192, true)); - - TS_ASSERT_EQUALS(proof.getInstructions()[1].d_kind, ADDITION); - TS_ASSERT_EQUALS(proof.getInstructions()[1].d_clause.size(), 2); - TS_ASSERT_EQUALS(proof.getInstructions()[1].d_clause[0], - SatLiteral(128, false)); - TS_ASSERT_EQUALS(proof.getInstructions()[1].d_clause[1], - SatLiteral(8190, true)); -} - -void DratProofBlack::testOutputTwoAsText() -{ - // d -63 -8193 - // 129 -8191 - std::string input("\x64\x7f\x83\x80\x01\x00\x61\x82\x02\xff\x7f\x00", 12); - DratProof proof = DratProof::fromBinary(input); - - std::ostringstream output; - proof.outputAsText(output); - - std::istringstream tokens(output.str()); - std::string token; - - tokens >> token; - TS_ASSERT_EQUALS(token, "d"); - - tokens >> token; - TS_ASSERT_EQUALS(token, "-63"); - - tokens >> token; - TS_ASSERT_EQUALS(token, "-8193"); - - tokens >> token; - TS_ASSERT_EQUALS(token, "0"); - - tokens >> token; - TS_ASSERT_EQUALS(token, "129"); - - tokens >> token; - TS_ASSERT_EQUALS(token, "-8191"); - - tokens >> token; - TS_ASSERT_EQUALS(token, "0"); -} - -void DratProofBlack::testOutputTwoAsLfsc() -{ - // d -63 -8193 - // 129 -8191 - std::string input("\x64\x7f\x83\x80\x01\x00\x61\x82\x02\xff\x7f\x00", 12); - DratProof proof = DratProof::fromBinary(input); - std::ostringstream lfsc; - proof.outputAsLfsc(lfsc, 2); - std::ostringstream lfscWithoutWhitespace; - for (char c : lfsc.str()) - { - if (!std::isspace(c)) - { - lfscWithoutWhitespace << c; - } - } - std::string expectedLfsc = - "(DRATProofd (clc (neg bb.v62) (clc (neg bb.v8192) cln))" - "(DRATProofa (clc (pos bb.v128) (clc (neg bb.v8190) cln))" - "DRATProofn))"; - std::ostringstream expectedLfscWithoutWhitespace; - for (char c : expectedLfsc) - { - if (!std::isspace(c)) - { - expectedLfscWithoutWhitespace << c; - } - } - - TS_ASSERT_EQUALS(lfscWithoutWhitespace.str(), - expectedLfscWithoutWhitespace.str()); -} diff --git a/test/unit/proof/er_proof_black.h b/test/unit/proof/er_proof_black.h deleted file mode 100644 index d9178e34e..000000000 --- a/test/unit/proof/er_proof_black.h +++ /dev/null @@ -1,464 +0,0 @@ -/********************* */ -/*! \file er_proof_black.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 Black box testing of the ER proof class - ** - ** In particular, tests TRACECHECK parsing and ER LFSC output. - **/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "base/configuration_private.h" -#include "proof/clause_id.h" -#include "proof/er/er_proof.h" -#include "prop/sat_solver_types.h" -#include "utils.h" - -#if IS_LFSC_BUILD -#include "lfscc.h" - -namespace CVC4 { -namespace proof { -extern const char* const plf_signatures; -} // namespace proof -} // namespace CVC4 -#endif - - -using namespace CVC4; -using namespace CVC4::proof::er; -using namespace CVC4::prop; - -class ErProofBlack : public CxxTest::TestSuite -{ - public: - void setUp() override {} - void tearDown() override {} - - void testTraceCheckParse1Line(); - void testTraceCheckParse5Lines(); - void testErTraceCheckParse(); - void testErTraceCheckOutput(); - void testErTraceCheckOutputMedium(); -}; - -/** - * @brief Add a new clause to the clause store and list of used clauses - * - * @param clauses the clause store - * @param usedIds the used clauses - * @param id the id of the new clause - * @param clause the clause itself - */ -void addClause(std::unordered_map& clauses, - std::vector& usedIds, - ClauseId id, - SatClause&& clause) -{ - clauses.emplace(id, std::move(clause)); - usedIds.push_back(id); -} - -void ErProofBlack::testTraceCheckParse1Line() -{ - std::string tracecheckText = "1 -2 3 0 4 2 0\n"; - std::istringstream stream(tracecheckText); - TraceCheckProof pf = TraceCheckProof::fromText(stream); - TS_ASSERT_EQUALS(pf.d_lines.size(), 1); - - TS_ASSERT_EQUALS(pf.d_lines[0].d_idx, 1); - TS_ASSERT_EQUALS(pf.d_lines[0].d_clause.size(), 2); - TS_ASSERT_EQUALS(pf.d_lines[0].d_clause[0], SatLiteral(1, true)); - TS_ASSERT_EQUALS(pf.d_lines[0].d_clause[1], SatLiteral(2, false)); - TS_ASSERT_EQUALS(pf.d_lines[0].d_chain.size(), 2); - TS_ASSERT_EQUALS(pf.d_lines[0].d_chain[0], 4); - TS_ASSERT_EQUALS(pf.d_lines[0].d_chain[1], 2); -} - -void ErProofBlack::testTraceCheckParse5Lines() -{ - std::string tracecheckText = - "1 1 -2 3 0 0\n" - "2 -1 0 0\n" - "3 2 0 0\n" - "4 -3 0 0\n" - "5 0 1 2 4 3 0\n"; - std::istringstream stream(tracecheckText); - TraceCheckProof pf = TraceCheckProof::fromText(stream); - TS_ASSERT_EQUALS(pf.d_lines.size(), 5); - - TS_ASSERT_EQUALS(pf.d_lines[0].d_idx, 1); - TS_ASSERT_EQUALS(pf.d_lines[4].d_idx, 5); - - TS_ASSERT_EQUALS(pf.d_lines[0].d_clause.size(), 3); - TS_ASSERT_EQUALS(pf.d_lines[0].d_clause[0], SatLiteral(0, false)); - TS_ASSERT_EQUALS(pf.d_lines[0].d_clause[1], SatLiteral(1, true)); - TS_ASSERT_EQUALS(pf.d_lines[0].d_clause[2], SatLiteral(2, false)); - TS_ASSERT_EQUALS(pf.d_lines[0].d_chain.size(), 0); - - TS_ASSERT_EQUALS(pf.d_lines[4].d_chain.size(), 4); - TS_ASSERT_EQUALS(pf.d_lines[4].d_chain[0], 1); - TS_ASSERT_EQUALS(pf.d_lines[4].d_chain[1], 2); - TS_ASSERT_EQUALS(pf.d_lines[4].d_chain[2], 4); - TS_ASSERT_EQUALS(pf.d_lines[4].d_chain[3], 3); - TS_ASSERT_EQUALS(pf.d_lines[4].d_clause.size(), 0); -} - -void ErProofBlack::testErTraceCheckParse() -{ - std::string tracecheckText = - "1 1 2 -3 0 0\n" - "2 -1 -2 3 0 0\n" - "3 2 3 -4 0 0\n" - "4 -2 -3 4 0 0\n" - "5 -1 -3 -4 0 0\n" - "6 1 3 4 0 0\n" - "7 -1 2 4 0 0\n" - "8 1 -2 -4 0 0\n" - "9 5 0 0\n" - "10 5 1 0 0\n" - "11 4 5 2 0 10 7 0\n" - "12 -4 5 -3 0 10 5 0\n" - "13 3 5 -2 0 10 2 0\n" - "14 -2 -4 0 2 5 8 0\n" - "15 4 3 0 7 2 6 0\n" - "16 2 -3 0 7 5 1 0\n" - "17 2 0 3 15 16 0\n" - "18 0 4 15 14 17 0\n"; - std::istringstream stream(tracecheckText); - TraceCheckProof tc = TraceCheckProof::fromText(stream); - - std::unordered_map clauses; - std::vector usedIds; - addClause( - clauses, - usedIds, - 1, - std::vector{ - SatLiteral(0, false), SatLiteral(1, false), SatLiteral(2, true)}); - addClause( - clauses, - usedIds, - 2, - std::vector{ - SatLiteral(0, true), SatLiteral(1, true), SatLiteral(2, false)}); - addClause( - clauses, - usedIds, - 3, - std::vector{ - SatLiteral(1, false), SatLiteral(2, false), SatLiteral(3, true)}); - addClause( - clauses, - usedIds, - 4, - std::vector{ - SatLiteral(1, true), SatLiteral(2, true), SatLiteral(3, false)}); - addClause(clauses, - usedIds, - 5, - std::vector{ - SatLiteral(0, true), SatLiteral(2, true), SatLiteral(3, true)}); - addClause( - clauses, - usedIds, - 6, - std::vector{ - SatLiteral(0, false), SatLiteral(2, false), SatLiteral(3, false)}); - addClause( - clauses, - usedIds, - 7, - std::vector{ - SatLiteral(0, true), SatLiteral(1, false), SatLiteral(3, false)}); - addClause( - clauses, - usedIds, - 8, - std::vector{ - SatLiteral(0, false), SatLiteral(1, true), SatLiteral(3, true)}); - ErProof pf(clauses, usedIds, std::move(tc)); - - TS_ASSERT_EQUALS(pf.getInputClauseIds()[0], 1); - TS_ASSERT_EQUALS(pf.getInputClauseIds()[7], 8); - - TS_ASSERT_EQUALS(pf.getDefinitions().size(), 1) - TS_ASSERT_EQUALS(pf.getDefinitions()[0].d_newVariable, SatVariable(4)); - TS_ASSERT_EQUALS(pf.getDefinitions()[0].d_oldLiteral, SatLiteral(0, true)); - TS_ASSERT_EQUALS(pf.getDefinitions()[0].d_otherLiterals.size(), 0); - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines.size(), 18); - - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines[0].d_idx, 1); - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines[16].d_idx, 17); - - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines[0].d_clause.size(), 3); - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines[0].d_clause[0], - SatLiteral(0, false)); - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines[0].d_clause[1], - SatLiteral(1, false)); - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines[0].d_clause[2], - SatLiteral(2, true)); - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines[0].d_chain.size(), 0); - - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines[16].d_clause.size(), 1); - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines[16].d_clause[0], - SatLiteral(1, false)); - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines[16].d_chain.size(), 3); - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines[16].d_chain[0], 3); - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines[16].d_chain[1], 15); - TS_ASSERT_EQUALS(pf.getTraceCheckProof().d_lines[16].d_chain[2], 16); -} - -void ErProofBlack::testErTraceCheckOutput() -{ - std::string tracecheckText = - "1 1 2 -3 0 0\n" - "2 -1 -2 3 0 0\n" - "3 2 3 -4 0 0\n" - "4 -2 -3 4 0 0\n" - "5 -1 -3 -4 0 0\n" - "6 1 3 4 0 0\n" - "7 -1 2 4 0 0\n" - "8 1 -2 -4 0 0\n" - "9 5 0 0\n" - "10 5 1 0 0\n" - "11 4 5 2 0 10 7 0\n" - "12 -4 5 -3 0 10 5 0\n" - "13 3 5 -2 0 10 2 0\n" - "14 -2 -4 0 2 5 8 0\n" - "15 4 3 0 7 2 6 0\n" - "16 2 -3 0 7 5 1 0\n" - "17 2 0 3 15 16 0\n" - "18 0 4 15 14 17 0\n"; - std::istringstream stream(tracecheckText); - TraceCheckProof tc = TraceCheckProof::fromText(stream); - - std::unordered_map clauses; - std::vector usedIds; - addClause( - clauses, - usedIds, - 1, - std::vector{ - SatLiteral(0, false), SatLiteral(1, false), SatLiteral(2, true)}); - addClause( - clauses, - usedIds, - 2, - std::vector{ - SatLiteral(0, true), SatLiteral(1, true), SatLiteral(2, false)}); - addClause( - clauses, - usedIds, - 3, - std::vector{ - SatLiteral(1, false), SatLiteral(2, false), SatLiteral(3, true)}); - addClause( - clauses, - usedIds, - 4, - std::vector{ - SatLiteral(1, true), SatLiteral(2, true), SatLiteral(3, false)}); - addClause(clauses, - usedIds, - 5, - std::vector{ - SatLiteral(0, true), SatLiteral(2, true), SatLiteral(3, true)}); - addClause( - clauses, - usedIds, - 6, - std::vector{ - SatLiteral(0, false), SatLiteral(2, false), SatLiteral(3, false)}); - addClause( - clauses, - usedIds, - 7, - std::vector{ - SatLiteral(0, true), SatLiteral(1, false), SatLiteral(3, false)}); - addClause( - clauses, - usedIds, - 8, - std::vector{ - SatLiteral(0, false), SatLiteral(1, true), SatLiteral(3, true)}); - ErProof pf(clauses, usedIds, std::move(tc)); - - std::ostringstream lfsc; - pf.outputAsLfsc(lfsc); - - std::string out = R"EOF( - (decl_definition - (neg bb.v0) - cln - (\ er.v4 - (\ er.def4 - (clausify_definition _ _ _ er.def4 _ - (\ er.c9 - (\ er.c10 - (\ er.cnf4 - (satlem_simplify _ _ _ - (R _ _ er.c10 bb.pb7 bb.v0) (\ er.c11 - (satlem_simplify _ _ _ - (R _ _ er.c10 bb.pb5 bb.v0) (\ er.c12 - (satlem_simplify _ _ _ - (R _ _ er.c10 bb.pb2 bb.v0) (\ er.c13 - (satlem_simplify _ _ _ - (Q _ _ (R _ _ bb.pb2 bb.pb5 bb.v2) bb.pb8 bb.v0) (\ er.c14 - (satlem_simplify _ _ _ - (Q _ _ (R _ _ bb.pb7 bb.pb2 bb.v1) bb.pb6 bb.v0) (\ er.c15 - (satlem_simplify _ _ _ - (Q _ _ (R _ _ bb.pb7 bb.pb5 bb.v3) bb.pb1 bb.v0) (\ er.c16 - (satlem_simplify _ _ _ - (R _ _ (Q _ _ bb.pb3 er.c15 bb.v3) er.c16 bb.v2) (\ er.c17 - (satlem_simplify _ _ _ - (Q _ _ (R _ _ (Q _ _ bb.pb4 er.c15 bb.v2) er.c14 bb.v3) - er.c17 bb.v1) (\ er.c18 - er.c18 ; (holds cln) - )))))))))))))))) - ))) - ) - )) - ) - )EOF"; - - TS_ASSERT_EQUALS(filterWhitespace(lfsc.str()), filterWhitespace(out)); -} - -/** - * This proof has been specially constructed to stress-test the proof - * machinery, while still being short. It's a bit meandering... - */ -void ErProofBlack::testErTraceCheckOutputMedium() -{ - std::string tracecheckText = - "1 1 2 -3 0 0\n" - "2 -1 -2 3 0 0\n" - "3 2 3 -4 0 0\n" - "4 -2 -3 4 0 0\n" - "5 -1 -3 -4 0 0\n" - "6 1 3 4 0 0\n" - "7 -1 2 4 0 0\n" - "8 1 -2 -4 0 0\n" - - "9 5 2 4 0 0\n" // Definition with 2 other variables - "10 5 1 0 0\n" - "11 2 -5 -1 0 0\n" - "12 4 -5 -1 0 0\n" - - "13 6 0 0\n" // Definition with no other variables - "14 6 -3 0 0\n" - - "15 -3 4 0 11 1 10 7 4 0\n" // Chain w/ both def. and input clauses - - "16 -2 -4 0 2 5 8 0\n" // The useful bit of the proof - "17 4 3 0 7 2 6 0\n" - "18 2 -3 0 7 5 1 0\n" - "19 2 0 3 17 18 0\n" - "20 0 4 17 16 19 0\n"; - - std::istringstream stream(tracecheckText); - TraceCheckProof tc = TraceCheckProof::fromText(stream); - - std::unordered_map clauses; - std::vector usedIds; - addClause( - clauses, - usedIds, - 1, - std::vector{ - SatLiteral(0, false), SatLiteral(1, false), SatLiteral(2, true)}); - addClause( - clauses, - usedIds, - 2, - std::vector{ - SatLiteral(0, true), SatLiteral(1, true), SatLiteral(2, false)}); - addClause( - clauses, - usedIds, - 3, - std::vector{ - SatLiteral(1, false), SatLiteral(2, false), SatLiteral(3, true)}); - addClause( - clauses, - usedIds, - 4, - std::vector{ - SatLiteral(1, true), SatLiteral(2, true), SatLiteral(3, false)}); - addClause(clauses, - usedIds, - 5, - std::vector{ - SatLiteral(0, true), SatLiteral(2, true), SatLiteral(3, true)}); - addClause( - clauses, - usedIds, - 6, - std::vector{ - SatLiteral(0, false), SatLiteral(2, false), SatLiteral(3, false)}); - addClause( - clauses, - usedIds, - 7, - std::vector{ - SatLiteral(0, true), SatLiteral(1, false), SatLiteral(3, false)}); - addClause( - clauses, - usedIds, - 8, - std::vector{ - SatLiteral(0, false), SatLiteral(1, true), SatLiteral(3, true)}); - ErProof pf(clauses, usedIds, std::move(tc)); - - std::ostringstream actual_pf_body; - pf.outputAsLfsc(actual_pf_body); - -#if IS_LFSC_BUILD - std::string pf_header = R"EOF( - (check - (% bb.v0 var - (% bb.v1 var - (% bb.v2 var - (% bb.v3 var - (% bb.pb1 (holds (clc (pos bb.v0) (clc (pos bb.v1) (clc (neg bb.v2) cln)))) - (% bb.pb2 (holds (clc (neg bb.v0) (clc (neg bb.v1) (clc (pos bb.v2) cln)))) - (% bb.pb3 (holds (clc (pos bb.v1) (clc (pos bb.v2) (clc (neg bb.v3) cln)))) - (% bb.pb4 (holds (clc (neg bb.v1) (clc (neg bb.v2) (clc (pos bb.v3) cln)))) - (% bb.pb5 (holds (clc (neg bb.v0) (clc (neg bb.v2) (clc (neg bb.v3) cln)))) - (% bb.pb6 (holds (clc (pos bb.v0) (clc (pos bb.v2) (clc (pos bb.v3) cln)))) - (% bb.pb7 (holds (clc (neg bb.v0) (clc (pos bb.v1) (clc (pos bb.v3) cln)))) - (% bb.pb8 (holds (clc (pos bb.v0) (clc (neg bb.v1) (clc (neg bb.v3) cln)))) - (: (holds cln) - )EOF"; - - std::string pf_footer = R"EOF( - ) - )))))))) - )))) - ) - )EOF"; - - std::stringstream actual_pf; - actual_pf << proof::plf_signatures << pf_header << actual_pf_body.str() << pf_footer; - - lfscc_init(); - lfscc_check_file(actual_pf, false, false, false, false, false, false, false); -#endif -} diff --git a/test/unit/proof/lfsc_proof_printer_black.h b/test/unit/proof/lfsc_proof_printer_black.h deleted file mode 100644 index 74fda4996..000000000 --- a/test/unit/proof/lfsc_proof_printer_black.h +++ /dev/null @@ -1,118 +0,0 @@ -/********************* */ -/*! \file lfsc_proof_printer_black.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 Black box testing of LFSC proof printing - **/ - -#include - -#include "proof/lfsc_proof_printer.h" -#include "prop/sat_solver_types.h" -#include "proof/clause_id.h" - -using namespace CVC4::proof; -using namespace CVC4::prop; - -class LfscProofPrinterBlack : public CxxTest::TestSuite -{ - public: - void setUp() override {} - void tearDown() override {} - - void testPrintClause(); - void testPrintSatInputProof(); - void testPrintCMapProof(); -}; - -void LfscProofPrinterBlack::testPrintClause() -{ - SatClause clause{ - SatLiteral(0, false), SatLiteral(1, true), SatLiteral(3, false)}; - std::ostringstream lfsc; - - LFSCProofPrinter::printSatClause(clause, lfsc, ""); - - std::string expectedLfsc = - "(clc (pos .v0) " - "(clc (neg .v1) " - "(clc (pos .v3) " - "cln)))"; - - TS_ASSERT_EQUALS(lfsc.str(), expectedLfsc); -} - -void LfscProofPrinterBlack::testPrintSatInputProof() -{ - std::vector ids{2, 40, 3}; - std::ostringstream lfsc; - - LFSCProofPrinter::printSatInputProof(ids, lfsc, ""); - - std::string expectedLfsc = - "(cnfc_proof _ _ _ .pb2 " - "(cnfc_proof _ _ _ .pb40 " - "(cnfc_proof _ _ _ .pb3 " - "cnfn_proof)))"; - - std::ostringstream lfscWithoutWhitespace; - for (char c : lfsc.str()) - { - if (!std::isspace(c)) - { - lfscWithoutWhitespace << c; - } - } - std::ostringstream expectedLfscWithoutWhitespace; - for (char c : expectedLfsc) - { - if (!std::isspace(c)) - { - expectedLfscWithoutWhitespace << c; - } - } - - TS_ASSERT_EQUALS(lfscWithoutWhitespace.str(), - expectedLfscWithoutWhitespace.str()); -} - -void LfscProofPrinterBlack::testPrintCMapProof() -{ - std::vector ids{2, 40, 3}; - std::ostringstream lfsc; - - LFSCProofPrinter::printCMapProof(ids, lfsc, ""); - - std::string expectedLfsc = - "(CMapc_proof 1 _ _ _ .pb2 " - "(CMapc_proof 2 _ _ _ .pb40 " - "(CMapc_proof 3 _ _ _ .pb3 " - "CMapn_proof)))"; - - std::ostringstream lfscWithoutWhitespace; - for (char c : lfsc.str()) - { - if (!std::isspace(c)) - { - lfscWithoutWhitespace << c; - } - } - std::ostringstream expectedLfscWithoutWhitespace; - for (char c : expectedLfsc) - { - if (!std::isspace(c)) - { - expectedLfscWithoutWhitespace << c; - } - } - - TS_ASSERT_EQUALS(lfscWithoutWhitespace.str(), - expectedLfscWithoutWhitespace.str()); -} diff --git a/test/unit/proof/lrat_proof_black.h b/test/unit/proof/lrat_proof_black.h deleted file mode 100644 index 8d91fee33..000000000 --- a/test/unit/proof/lrat_proof_black.h +++ /dev/null @@ -1,97 +0,0 @@ -/********************* */ -/*! \file lrat_proof_black.h - ** \verbatim - ** Top contributors (to current version): - ** Alex Ozdemir, 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 Black box testing of the LRAT proof class - ** - ** In particular, tests LRAT LFSC output. - **/ - -#include - -#include - -#include "proof/lrat/lrat_proof.h" -#include "prop/sat_solver_types.h" -#include "utils.h" - -using namespace CVC4; -using namespace CVC4::proof::lrat; -using namespace CVC4::prop; - -class LratProofBlack : public CxxTest::TestSuite -{ - public: - void setUp() override {} - void tearDown() override {} - - void testOutputAsLfsc(); -}; - -void LratProofBlack::testOutputAsLfsc() -{ - std::vector> instructions; - - // 6 d 1 2 - std::vector clausesToDelete{1, 2}; - std::unique_ptr deletion = std::unique_ptr( - new LratDeletion(6, std::move(clausesToDelete))); - instructions.push_back(std::move(deletion)); - - // 7 1 2 0 5 2 0 - std::vector firstAddedClause{SatLiteral(1, false), - SatLiteral(2, false)}; - LratUPTrace firstTrace{5, 2}; - std::vector> firstHints; - std::unique_ptr add1 = - std::unique_ptr(new LratAddition( - 7, std::move(firstAddedClause), std::move(firstTrace), firstHints)); - instructions.push_back(std::move(add1)); - - // 8 2 0 -1 3 -5 2 0 - std::vector secondAddedClause{SatLiteral(2, false)}; - LratUPTrace secondTrace; - std::vector> secondHints; - LratUPTrace secondHints0Trace{3}; - secondHints.emplace_back(1, secondHints0Trace); - LratUPTrace secondHints1Trace{2}; - secondHints.emplace_back(5, secondHints1Trace); - std::unique_ptr add2 = std::unique_ptr( - new LratAddition(8, - std::move(secondAddedClause), - std::move(secondTrace), - secondHints)); - instructions.push_back(std::move(add2)); - - LratProof proof(std::move(instructions)); - - std::ostringstream lfsc; - proof.outputAsLfsc(lfsc); - - // 6 d 1 2 - // 7 1 2 0 5 2 0 - // 8 2 0 -1 3 -5 2 0 - std::string expectedLfsc = - "(LRATProofd (CIListc 1 (CIListc 2 CIListn)) " - "(LRATProofa 7 " - " (clc (pos bb.v1) (clc (pos bb.v2) cln))" - " (Tracec 5 (Tracec 2 Tracen))" - " RATHintsn " - "(LRATProofa 8 " - " (clc (pos bb.v2) cln)" - " Tracen " - " (RATHintsc 1 (Tracec 3 Tracen)" - " (RATHintsc 5 (Tracec 2 Tracen)" - " RATHintsn)) " - "LRATProofn)))"; - - TS_ASSERT_EQUALS(filterWhitespace(lfsc.str()), - filterWhitespace(expectedLfsc)); -} diff --git a/test/unit/proof/utils.h b/test/unit/proof/utils.h deleted file mode 100644 index 3db6e2171..000000000 --- a/test/unit/proof/utils.h +++ /dev/null @@ -1,34 +0,0 @@ -/********************* */ -/*! \file utils.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 Utilities for proof testing - **/ - -#include -#include -#include -#include - -/** - * Creates a new stream with whitespace removed. - * - * @param s the source string - * - * @return a string without whitespace - */ -std::string filterWhitespace(const std::string& s) -{ - std::string out; - std::copy_if(s.cbegin(), s.cend(), std::inserter(out, out.end()), [](char c) { - return !std::isspace(c); - }); - return out; -} diff --git a/test/unit/prop/cnf_stream_white.h b/test/unit/prop/cnf_stream_white.h index f0253fdbf..33fc15674 100644 --- a/test/unit/prop/cnf_stream_white.h +++ b/test/unit/prop/cnf_stream_white.h @@ -174,8 +174,8 @@ class CnfStreamWhite : public CxxTest::TestSuite { Node a = d_nodeManager->mkVar(d_nodeManager->booleanType()); Node b = d_nodeManager->mkVar(d_nodeManager->booleanType()); Node c = d_nodeManager->mkVar(d_nodeManager->booleanType()); - d_cnfStream->convertAndAssert(d_nodeManager->mkNode(kind::AND, a, b, c), - false, false, RULE_INVALID, Node::null()); + d_cnfStream->convertAndAssert( + d_nodeManager->mkNode(kind::AND, a, b, c), false, false); TS_ASSERT(d_satSolver->addClauseCalled()); } @@ -189,26 +189,27 @@ class CnfStreamWhite : public CxxTest::TestSuite { Node f = d_nodeManager->mkVar(d_nodeManager->booleanType()); d_cnfStream->convertAndAssert( d_nodeManager->mkNode( - kind::IMPLIES, d_nodeManager->mkNode(kind::AND, a, b), + kind::IMPLIES, + d_nodeManager->mkNode(kind::AND, a, b), d_nodeManager->mkNode( - kind::EQUAL, d_nodeManager->mkNode(kind::OR, c, d), + kind::EQUAL, + d_nodeManager->mkNode(kind::OR, c, d), d_nodeManager->mkNode(kind::NOT, d_nodeManager->mkNode(kind::XOR, e, f)))), - false, false, RULE_INVALID, Node::null()); + false, + false); TS_ASSERT(d_satSolver->addClauseCalled()); } void testTrue() { NodeManagerScope nms(d_nodeManager); - d_cnfStream->convertAndAssert(d_nodeManager->mkConst(true), false, false, - RULE_INVALID, Node::null()); + d_cnfStream->convertAndAssert(d_nodeManager->mkConst(true), false, false); TS_ASSERT(d_satSolver->addClauseCalled()); } void testFalse() { NodeManagerScope nms(d_nodeManager); - d_cnfStream->convertAndAssert(d_nodeManager->mkConst(false), false, false, - RULE_INVALID, Node::null()); + d_cnfStream->convertAndAssert(d_nodeManager->mkConst(false), false, false); TS_ASSERT(d_satSolver->addClauseCalled()); } @@ -216,8 +217,8 @@ class CnfStreamWhite : public CxxTest::TestSuite { NodeManagerScope nms(d_nodeManager); Node a = d_nodeManager->mkVar(d_nodeManager->booleanType()); Node b = d_nodeManager->mkVar(d_nodeManager->booleanType()); - d_cnfStream->convertAndAssert(d_nodeManager->mkNode(kind::EQUAL, a, b), false, - false, RULE_INVALID, Node::null()); + d_cnfStream->convertAndAssert( + d_nodeManager->mkNode(kind::EQUAL, a, b), false, false); TS_ASSERT(d_satSolver->addClauseCalled()); } @@ -225,33 +226,16 @@ class CnfStreamWhite : public CxxTest::TestSuite { NodeManagerScope nms(d_nodeManager); Node a = d_nodeManager->mkVar(d_nodeManager->booleanType()); Node b = d_nodeManager->mkVar(d_nodeManager->booleanType()); - d_cnfStream->convertAndAssert(d_nodeManager->mkNode(kind::IMPLIES, a, b), - false, false, RULE_INVALID, Node::null()); + d_cnfStream->convertAndAssert( + d_nodeManager->mkNode(kind::IMPLIES, a, b), false, false); TS_ASSERT(d_satSolver->addClauseCalled()); } - // ITEs should be removed before going to CNF - // void testIte() { - // NodeManagerScope nms(d_nodeManager); - // d_cnfStream->convertAndAssert( - // d_nodeManager->mkNode( - // kind::EQUAL, - // d_nodeManager->mkNode( - // kind::ITE, - // d_nodeManager->mkVar(d_nodeManager->booleanType()), - // d_nodeManager->mkVar(d_nodeManager->integerType()), - // d_nodeManager->mkVar(d_nodeManager->integerType()) - // ), - // d_nodeManager->mkVar(d_nodeManager->integerType()) - // ), false, false, RULE_INVALID, Node::null()); - // - //} - void testNot() { NodeManagerScope nms(d_nodeManager); Node a = d_nodeManager->mkVar(d_nodeManager->booleanType()); - d_cnfStream->convertAndAssert(d_nodeManager->mkNode(kind::NOT, a), false, - false, RULE_INVALID, Node::null()); + d_cnfStream->convertAndAssert( + d_nodeManager->mkNode(kind::NOT, a), false, false); TS_ASSERT(d_satSolver->addClauseCalled()); } @@ -260,8 +244,8 @@ class CnfStreamWhite : public CxxTest::TestSuite { Node a = d_nodeManager->mkVar(d_nodeManager->booleanType()); Node b = d_nodeManager->mkVar(d_nodeManager->booleanType()); Node c = d_nodeManager->mkVar(d_nodeManager->booleanType()); - d_cnfStream->convertAndAssert(d_nodeManager->mkNode(kind::OR, a, b, c), - false, false, RULE_INVALID, Node::null()); + d_cnfStream->convertAndAssert( + d_nodeManager->mkNode(kind::OR, a, b, c), false, false); TS_ASSERT(d_satSolver->addClauseCalled()); } @@ -269,10 +253,10 @@ class CnfStreamWhite : public CxxTest::TestSuite { NodeManagerScope nms(d_nodeManager); Node a = d_nodeManager->mkVar(d_nodeManager->booleanType()); Node b = d_nodeManager->mkVar(d_nodeManager->booleanType()); - d_cnfStream->convertAndAssert(a, false, false, RULE_INVALID, Node::null()); + d_cnfStream->convertAndAssert(a, false, false); TS_ASSERT(d_satSolver->addClauseCalled()); d_satSolver->reset(); - d_cnfStream->convertAndAssert(b, false, false, RULE_INVALID, Node::null()); + d_cnfStream->convertAndAssert(b, false, false); TS_ASSERT(d_satSolver->addClauseCalled()); } @@ -280,8 +264,8 @@ class CnfStreamWhite : public CxxTest::TestSuite { NodeManagerScope nms(d_nodeManager); Node a = d_nodeManager->mkVar(d_nodeManager->booleanType()); Node b = d_nodeManager->mkVar(d_nodeManager->booleanType()); - d_cnfStream->convertAndAssert(d_nodeManager->mkNode(kind::XOR, a, b), false, - false, RULE_INVALID, Node::null()); + d_cnfStream->convertAndAssert( + d_nodeManager->mkNode(kind::XOR, a, b), false, false); TS_ASSERT(d_satSolver->addClauseCalled()); } diff --git a/test/unit/theory/theory_engine_white.h b/test/unit/theory/theory_engine_white.h index a67d0aeb2..ae4264aa2 100644 --- a/test/unit/theory/theory_engine_white.h +++ b/test/unit/theory/theory_engine_white.h @@ -41,7 +41,6 @@ #include "theory/theory_rewriter.h" #include "theory/valuation.h" #include "util/integer.h" -#include "util/proof.h" #include "util/rational.h" using namespace CVC4; @@ -55,13 +54,9 @@ using namespace CVC4::theory::bv; using namespace std; class FakeOutputChannel : public OutputChannel { - void conflict(TNode n, std::unique_ptr pf) override - { - Unimplemented(); - } + void conflict(TNode n) override { Unimplemented(); } bool propagate(TNode n) override { Unimplemented(); } LemmaStatus lemma(TNode n, - ProofRule rule, LemmaProperty p = LemmaProperty::NONE) override { Unimplemented(); diff --git a/test/unit/theory/theory_white.h b/test/unit/theory/theory_white.h index 9693000a3..e90bd56a2 100644 --- a/test/unit/theory/theory_white.h +++ b/test/unit/theory/theory_white.h @@ -26,7 +26,6 @@ #include "smt/smt_engine_scope.h" #include "theory/theory.h" #include "theory/theory_engine.h" -#include "util/proof.h" #include "util/resource_manager.h" using namespace CVC4; @@ -48,10 +47,7 @@ class TestOutputChannel : public OutputChannel { ~TestOutputChannel() override {} void safePoint(ResourceManager::Resource r) override {} - void conflict(TNode n, std::unique_ptr pf) override - { - push(CONFLICT, n); - } + void conflict(TNode n) override { push(CONFLICT, n); } bool propagate(TNode n) override { push(PROPAGATE, n); @@ -59,7 +55,6 @@ class TestOutputChannel : public OutputChannel { } LemmaStatus lemma(TNode n, - ProofRule rule, LemmaProperty p = LemmaProperty::NONE) override { push(LEMMA, n); @@ -298,7 +293,7 @@ class TheoryBlack : public CxxTest::TestSuite { void testOutputChannel() { Node n = atom0.orNode(atom1); - d_outputChannel.lemma(n, RULE_INVALID); + d_outputChannel.lemma(n); d_outputChannel.split(atom0); Node s = atom0.orNode(atom0.notNode()); TS_ASSERT_EQUALS(d_outputChannel.d_callHistory.size(), 2u);