From 57a02fd0c7faa7a87b8619d52cf519e033633c1d Mon Sep 17 00:00:00 2001 From: Andres Noetzli Date: Mon, 31 Aug 2020 11:48:42 -0700 Subject: [CI] Fix Cython installation (#4983) Cython has been causing issues recently, see e.g. https://github.com/CVC4/CVC4/pull/4982/checks?check_run_id=1052433862. It looks like the issue is that globally installed packages can't be found by Python (maybe the global site-package directories changed/are not included in the search paths anymore?). This commit changes the installation of Cython to install it locally to the user instead of globally. It also adds `bin` in the user base directory to `PATH` s.t. CMake is able to find the `cython` binary. --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00fa15bc5..d7909b961 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -90,12 +90,12 @@ jobs: python3 -m pip install pexpect echo "::add-path::/usr/local/opt/ccache/libexec" - # Note: We install Cython with sudo since cmake can't find Cython otherwise. - name: Install Cython if: matrix.python-bindings && runner.os == 'Linux' run: | - sudo python3 -m pip install \ - Cython==0.29 --install-option="--no-cython-compile" + python3 -m pip install \ + Cython==0.29.* --install-option="--no-cython-compile" + echo "::add-path::$(python3 -m site --user-base)/bin" - name: Install Cython (macOS) if: matrix.python-bindings && runner.os == 'macOS' -- cgit v1.2.3 From 7b3b19f73ceb2168ced48d07a590c0f3be82a8d4 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Mon, 31 Aug 2020 14:24:27 -0500 Subject: Simplify interface for computing relevant terms. (#4966) This is a followup to #4945 which simplifies the contract for computeRelevantTerms. --- src/theory/arith/theory_arith_private.cpp | 4 +-- src/theory/arrays/theory_arrays.cpp | 23 ++++----------- src/theory/arrays/theory_arrays.h | 8 +++--- src/theory/bv/bitblast/lazy_bitblaster.cpp | 3 +- src/theory/bv/bv_subtheory_algebraic.cpp | 3 +- src/theory/bv/bv_subtheory_core.cpp | 3 +- src/theory/datatypes/theory_datatypes.cpp | 23 ++------------- src/theory/datatypes/theory_datatypes.h | 10 +++---- src/theory/fp/theory_fp.cpp | 3 +- src/theory/sets/theory_sets.cpp | 5 ++-- src/theory/sets/theory_sets.h | 3 +- src/theory/sets/theory_sets_private.cpp | 12 ++------ src/theory/sets/theory_sets_private.h | 2 +- src/theory/strings/theory_strings.cpp | 3 +- src/theory/theory.cpp | 22 ++++++++------ src/theory/theory.h | 46 +++++++++++++++--------------- 16 files changed, 73 insertions(+), 100 deletions(-) diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp index 8ca99d369..9a8ca733a 100644 --- a/src/theory/arith/theory_arith_private.cpp +++ b/src/theory/arith/theory_arith_private.cpp @@ -4140,8 +4140,8 @@ bool TheoryArithPrivate::collectModelInfo(TheoryModel* m) Debug("arith::collectModelInfo") << "collectModelInfo() begin " << endl; std::set termSet; - d_containing.computeRelevantTerms(termSet); - + const std::set& irrKinds = m->getIrrelevantKinds(); + d_containing.computeAssertedTerms(termSet, irrKinds, true); // Delta lasts at least the duration of the function call const Rational& delta = d_partialModel.getDelta(); diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp index b4a234748..3adcd4f49 100644 --- a/src/theory/arrays/theory_arrays.cpp +++ b/src/theory/arrays/theory_arrays.cpp @@ -1090,19 +1090,11 @@ void TheoryArrays::computeCareGraph() // MODEL GENERATION ///////////////////////////////////////////////////////////////////////////// -bool TheoryArrays::collectModelInfo(TheoryModel* m) +bool TheoryArrays::collectModelValues(TheoryModel* m, + const std::set& termSet) { - // Compute terms appearing in assertions and shared terms, and also - // include additional reads due to the RIntro1 and RIntro2 rules. - std::set termSet; - computeRelevantTerms(termSet); - - // Send the equality engine information to the model - if (!m->assertEqualityEngine(d_equalityEngine, &termSet)) - { - return false; - } - + // termSet contains terms appearing in assertions and shared terms, and also + // includes additional reads due to the RIntro1 and RIntro2 rules. NodeManager* nm = NodeManager::currentNM(); // Compute arrays that we need to produce representatives for std::vector arrays; @@ -2263,13 +2255,8 @@ TrustNode TheoryArrays::expandDefinition(Node node) return TrustNode::null(); } -void TheoryArrays::computeRelevantTerms(std::set& termSet, - bool includeShared) +void TheoryArrays::computeRelevantTerms(std::set& termSet) { - // include all standard terms - std::set irrKinds; - computeRelevantTermsInternal(termSet, irrKinds, includeShared); - NodeManager* nm = NodeManager::currentNM(); // make sure RIntro1 reads are included in the relevant set of reads eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine); diff --git a/src/theory/arrays/theory_arrays.h b/src/theory/arrays/theory_arrays.h index 8cbf826c1..9044b9950 100644 --- a/src/theory/arrays/theory_arrays.h +++ b/src/theory/arrays/theory_arrays.h @@ -264,7 +264,8 @@ class TheoryArrays : public Theory { ///////////////////////////////////////////////////////////////////////////// public: - bool collectModelInfo(TheoryModel* m) override; + bool collectModelValues(TheoryModel* m, + const std::set& termSet) override; ///////////////////////////////////////////////////////////////////////////// // NOTIFICATIONS @@ -480,11 +481,10 @@ class TheoryArrays : public Theory { Node getNextDecisionRequest(); /** - * Compute relevant terms. This includes additional select nodes for the + * Compute relevant terms. This includes select nodes for the * RIntro1 and RIntro2 rules. */ - void computeRelevantTerms(std::set& termSet, - bool includeShared = true) override; + void computeRelevantTerms(std::set& termSet) override; };/* class TheoryArrays */ }/* CVC4::theory::arrays namespace */ diff --git a/src/theory/bv/bitblast/lazy_bitblaster.cpp b/src/theory/bv/bitblast/lazy_bitblaster.cpp index c3a305952..83e286f10 100644 --- a/src/theory/bv/bitblast/lazy_bitblaster.cpp +++ b/src/theory/bv/bitblast/lazy_bitblaster.cpp @@ -540,7 +540,8 @@ Node TLazyBitblaster::getModelFromSatSolver(TNode a, bool fullModel) { bool TLazyBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) { std::set termSet; - d_bv->computeRelevantTerms(termSet); + const std::set& irrKinds = m->getIrrelevantKinds(); + d_bv->computeAssertedTerms(termSet, irrKinds, true); for (std::set::const_iterator it = termSet.begin(); it != termSet.end(); ++it) { TNode var = *it; diff --git a/src/theory/bv/bv_subtheory_algebraic.cpp b/src/theory/bv/bv_subtheory_algebraic.cpp index e5a416a1b..80a6aeb86 100644 --- a/src/theory/bv/bv_subtheory_algebraic.cpp +++ b/src/theory/bv/bv_subtheory_algebraic.cpp @@ -715,7 +715,8 @@ bool AlgebraicSolver::collectModelInfo(TheoryModel* model, bool fullModel) Debug("bitvector-model") << "AlgebraicSolver::collectModelInfo\n"; AlwaysAssert(!d_quickSolver->inConflict()); set termSet; - d_bv->computeRelevantTerms(termSet); + const std::set& irrKinds = model->getIrrelevantKinds(); + d_bv->computeAssertedTerms(termSet, irrKinds, true); // collect relevant terms that the bv theory abstracts to variables // (variables and parametric terms such as select apply_uf) diff --git a/src/theory/bv/bv_subtheory_core.cpp b/src/theory/bv/bv_subtheory_core.cpp index d8f376a74..38c5cb482 100644 --- a/src/theory/bv/bv_subtheory_core.cpp +++ b/src/theory/bv/bv_subtheory_core.cpp @@ -354,7 +354,8 @@ bool CoreSolver::collectModelInfo(TheoryModel* m, bool fullModel) } } set termSet; - d_bv->computeRelevantTerms(termSet); + const std::set& irrKinds = m->getIrrelevantKinds(); + d_bv->computeAssertedTerms(termSet, irrKinds, true); if (!m->assertEqualityEngine(d_equalityEngine, &termSet)) { return false; diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp index a98c77a5d..4c8fa87ba 100644 --- a/src/theory/datatypes/theory_datatypes.cpp +++ b/src/theory/datatypes/theory_datatypes.cpp @@ -1483,7 +1483,8 @@ void TheoryDatatypes::computeCareGraph(){ Trace("dt-cg-summary") << "...done, # pairs = " << n_pairs << std::endl; } -bool TheoryDatatypes::collectModelInfo(TheoryModel* m) +bool TheoryDatatypes::collectModelValues(TheoryModel* m, + const std::set& termSet) { Trace("dt-cmi") << "Datatypes : Collect model info " << d_equalityEngine->consistent() << std::endl; @@ -1491,17 +1492,6 @@ bool TheoryDatatypes::collectModelInfo(TheoryModel* m) printModelDebug( "dt-model" ); Trace("dt-model") << std::endl; - std::set termSet; - - // Compute terms appearing in assertions and shared terms, and in inferred equalities - computeRelevantTerms(termSet); - - //combine the equality engine - if (!m->assertEqualityEngine(d_equalityEngine, &termSet)) - { - return false; - } - //get all constructors eq::EqClassesIterator eqccs_i = eq::EqClassesIterator(d_equalityEngine); std::vector< Node > cons; @@ -2218,15 +2208,8 @@ Node TheoryDatatypes::mkAnd( std::vector< TNode >& assumptions ) { } } -void TheoryDatatypes::computeRelevantTerms(std::set& termSet, - bool includeShared) +void TheoryDatatypes::computeRelevantTerms(std::set& termSet) { - // Compute terms appearing in assertions and shared terms - std::set irrKinds; - // testers are not relevant for model construction - irrKinds.insert(APPLY_TESTER); - computeRelevantTermsInternal(termSet, irrKinds, includeShared); - Trace("dt-cmi") << "Have " << termSet.size() << " relevant terms..." << std::endl; diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h index 0d5df098d..211653125 100644 --- a/src/theory/datatypes/theory_datatypes.h +++ b/src/theory/datatypes/theory_datatypes.h @@ -288,7 +288,8 @@ private: TrustNode ppRewrite(TNode n) override; void notifySharedTerm(TNode t) override; EqualityStatus getEqualityStatus(TNode a, TNode b) override; - bool collectModelInfo(TheoryModel* m) override; + bool collectModelValues(TheoryModel* m, + const std::set& termSet) override; void shutdown() override {} std::string identify() const override { @@ -347,11 +348,10 @@ private: TNode getRepresentative( TNode a ); /** - * Compute relevant terms. In addition to all terms in assertions and shared - * terms, this includes datatypes in non-singleton equivalence classes. + * Compute relevant terms. This includes datatypes in non-singleton + * equivalence classes. */ - void computeRelevantTerms(std::set& termSet, - bool includeShared = true) override; + void computeRelevantTerms(std::set& termSet) override; /** sygus symmetry breaking utility */ std::unique_ptr d_sygusExtension; diff --git a/src/theory/fp/theory_fp.cpp b/src/theory/fp/theory_fp.cpp index 4c59b1c06..5eb9e576d 100644 --- a/src/theory/fp/theory_fp.cpp +++ b/src/theory/fp/theory_fp.cpp @@ -1023,7 +1023,8 @@ bool TheoryFp::collectModelInfo(TheoryModel* m) { std::set relevantTerms; // Work out which variables are needed - computeRelevantTerms(relevantTerms); + const std::set& irrKinds = m->getIrrelevantKinds(); + computeAssertedTerms(relevantTerms, irrKinds); // this override behavior to not assert equality engine return collectModelValues(m, relevantTerms); } diff --git a/src/theory/sets/theory_sets.cpp b/src/theory/sets/theory_sets.cpp index 63ebacc23..0bf2ed2ea 100644 --- a/src/theory/sets/theory_sets.cpp +++ b/src/theory/sets/theory_sets.cpp @@ -98,9 +98,10 @@ void TheorySets::check(Effort e) { d_internal->check(e); } -bool TheorySets::collectModelInfo(TheoryModel* m) +bool TheorySets::collectModelValues(TheoryModel* m, + const std::set& termSet) { - return d_internal->collectModelInfo(m); + return d_internal->collectModelValues(m, termSet); } void TheorySets::computeCareGraph() { diff --git a/src/theory/sets/theory_sets.h b/src/theory/sets/theory_sets.h index a7fb31dab..a826a43af 100644 --- a/src/theory/sets/theory_sets.h +++ b/src/theory/sets/theory_sets.h @@ -60,7 +60,8 @@ class TheorySets : public Theory void notifySharedTerm(TNode) override; void check(Effort) override; - bool collectModelInfo(TheoryModel* m) override; + bool collectModelValues(TheoryModel* m, + const std::set& termSet) override; void computeCareGraph() override; TrustNode explain(TNode) override; EqualityStatus getEqualityStatus(TNode a, TNode b) override; diff --git a/src/theory/sets/theory_sets_private.cpp b/src/theory/sets/theory_sets_private.cpp index 3c9414606..78824636a 100644 --- a/src/theory/sets/theory_sets_private.cpp +++ b/src/theory/sets/theory_sets_private.cpp @@ -1258,18 +1258,10 @@ std::string traceElements(const Node& set) } // namespace -bool TheorySetsPrivate::collectModelInfo(TheoryModel* m) +bool TheorySetsPrivate::collectModelValues(TheoryModel* m, + const std::set& termSet) { Trace("sets-model") << "Set collect model info" << std::endl; - set termSet; - // Compute terms appearing in assertions and shared terms - d_external.computeRelevantTerms(termSet); - - // Assert equalities and disequalities to the model - if (!m->assertEqualityEngine(d_equalityEngine, &termSet)) - { - return false; - } NodeManager* nm = NodeManager::currentNM(); std::map mvals; diff --git a/src/theory/sets/theory_sets_private.h b/src/theory/sets/theory_sets_private.h index af780eadc..387d56de9 100644 --- a/src/theory/sets/theory_sets_private.h +++ b/src/theory/sets/theory_sets_private.h @@ -176,7 +176,7 @@ class TheorySetsPrivate { void check(Theory::Effort); - bool collectModelInfo(TheoryModel* m); + bool collectModelValues(TheoryModel* m, const std::set& termSet); void computeCareGraph(); diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp index 0de0cc33c..846f9240d 100644 --- a/src/theory/strings/theory_strings.cpp +++ b/src/theory/strings/theory_strings.cpp @@ -260,7 +260,8 @@ bool TheoryStrings::collectModelInfo(TheoryModel* m) std::set termSet; // Compute terms appearing in assertions and shared terms - computeRelevantTerms(termSet); + const std::set& irrKinds = m->getIrrelevantKinds(); + computeAssertedTerms(termSet, irrKinds); // assert the (relevant) portion of the equality engine to the model if (!m->assertEqualityEngine(d_equalityEngine, &termSet)) { diff --git a/src/theory/theory.cpp b/src/theory/theory.cpp index 66541a63e..d69c6edc5 100644 --- a/src/theory/theory.cpp +++ b/src/theory/theory.cpp @@ -359,8 +359,15 @@ std::unordered_set Theory::currentlySharedTerms() cons bool Theory::collectModelInfo(TheoryModel* m) { + // NOTE: the computation of termSet will be moved to model manager + // and passed as an argument to collectModelInfo. std::set termSet; // Compute terms appearing in assertions and shared terms + TheoryModel* tm = d_valuation.getModel(); + Assert(tm != nullptr); + const std::set& irrKinds = tm->getIrrelevantKinds(); + computeAssertedTerms(termSet, irrKinds, true); + // Compute additional relevant terms (theory-specific) computeRelevantTerms(termSet); // if we are using an equality engine, assert it to the model if (d_equalityEngine != nullptr) @@ -375,7 +382,7 @@ bool Theory::collectModelInfo(TheoryModel* m) } void Theory::collectTerms(TNode n, - set& irrKinds, + const std::set& irrKinds, set& termSet) const { if (termSet.find(n) != termSet.end()) { @@ -396,13 +403,11 @@ void Theory::collectTerms(TNode n, } } -void Theory::computeRelevantTermsInternal(std::set& termSet, - std::set& irrKinds, - bool includeShared) const +void Theory::computeAssertedTerms(std::set& termSet, + const std::set& irrKinds, + bool includeShared) const { // Collect all terms appearing in assertions - irrKinds.insert(kind::EQUAL); - irrKinds.insert(kind::NOT); context::CDList::const_iterator assert_it = facts_begin(), assert_it_end = facts_end(); for (; assert_it != assert_it_end; ++assert_it) @@ -424,10 +429,9 @@ void Theory::computeRelevantTermsInternal(std::set& termSet, } } -void Theory::computeRelevantTerms(std::set& termSet, bool includeShared) +void Theory::computeRelevantTerms(std::set& termSet) { - std::set irrKinds; - computeRelevantTermsInternal(termSet, irrKinds, includeShared); + // by default, there are no additional relevant terms } bool Theory::collectModelValues(TheoryModel* m, const std::set& termSet) diff --git a/src/theory/theory.h b/src/theory/theory.h index c5fcf362c..039fdebf1 100644 --- a/src/theory/theory.h +++ b/src/theory/theory.h @@ -182,27 +182,11 @@ class Theory { context::CDList d_sharedTerms; //---------------------------------- private collect model info - /** - * Scans the current set of assertions and shared terms top-down - * until a theory-leaf is reached, and adds all terms found to - * termSet. This is used by collectModelInfo to delimit the set of - * terms that should be used when constructing a model. - * - * irrKinds: The kinds of terms that appear in assertions that should *not* - * be included in termSet. Note that the kinds EQUAL and NOT are always - * treated as irrelevant kinds. - * - * includeShared: Whether to include shared terms in termSet. Notice that - * shared terms are not influenced by irrKinds. - */ - void computeRelevantTermsInternal(std::set& termSet, - std::set& irrKinds, - bool includeShared = true) const; /** * Helper function for computeRelevantTerms */ void collectTerms(TNode n, - std::set& irrKinds, + const std::set& irrKinds, std::set& termSet) const; //---------------------------------- end private collect model info @@ -688,13 +672,29 @@ class Theory { */ virtual bool collectModelInfo(TheoryModel* m); /** - * Same as above, but with empty irrKinds. This version can be overridden - * by the theory, e.g. by restricting or extending the set of terms returned - * by computeRelevantTermsInternal, which is called by default with no - * irrKinds. + * Scans the current set of assertions and shared terms top-down + * until a theory-leaf is reached, and adds all terms found to + * termSet. This is used by collectModelInfo to delimit the set of + * terms that should be used when constructing a model. + * + * @param irrKinds The kinds of terms that appear in assertions that should *not* + * be included in termSet. Note that the kinds EQUAL and NOT are always + * treated as irrelevant kinds. + * + * @param includeShared Whether to include shared terms in termSet. Notice that + * shared terms are not influenced by irrKinds. + * + * TODO (project #39): this method will be deleted. The version in + * model manager will be used. + */ + void computeAssertedTerms(std::set& termSet, + const std::set& irrKinds, + bool includeShared = true) const; + /** + * Compute terms that are not necessarily part of the assertions or + * shared terms that should be considered relevant, add them to termSet. */ - virtual void computeRelevantTerms(std::set& termSet, - bool includeShared = true); + virtual void computeRelevantTerms(std::set& termSet); /** * Collect model values, after equality information is added to the model. * The argument termSet is the set of relevant terms returned by -- cgit v1.2.3 From 52bab1414d41a4beb301f3c8a4165fa972f71a93 Mon Sep 17 00:00:00 2001 From: Gereon Kremer Date: Mon, 31 Aug 2020 21:59:39 +0200 Subject: Fix --ackermann in the presence on syntactically different but possibly equal selects (#4981) The implementation of --ackermann mishandled selects in a subtle way: If select is applied to two syntactically different arrays (that may be semantically equal), the ackermann preprocessing failed to generate the "all arguments equal implies terms equal" lemmas. The problem is that we used the first argument (that is: the array) as lookup to identify terms that need to be considered for these lemmas. Instead we now use their operator (select) just like for uninterpreted function applications. Fixes #4957 . Also adds a regression. --- src/preprocessing/passes/ackermann.cpp | 16 +++++++--------- test/regress/CMakeLists.txt | 1 + test/regress/regress0/arrays/bug4957.smt2 | 6 ++++++ 3 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 test/regress/regress0/arrays/bug4957.smt2 diff --git a/src/preprocessing/passes/ackermann.cpp b/src/preprocessing/passes/ackermann.cpp index 31c92a09f..ab9c2482b 100644 --- a/src/preprocessing/passes/ackermann.cpp +++ b/src/preprocessing/passes/ackermann.cpp @@ -70,11 +70,14 @@ void addLemmaForPair(TNode args1, } else { - Assert(args1.getKind() == kind::SELECT && args1[0] == func); - Assert(args2.getKind() == kind::SELECT && args2[0] == func); + Assert(args1.getKind() == kind::SELECT && args1.getOperator() == func); + Assert(args2.getKind() == kind::SELECT && args2.getOperator() == func); Assert(args1.getNumChildren() == 2); Assert(args2.getNumChildren() == 2); - args_eq = nm->mkNode(kind::EQUAL, args1[1], args2[1]); + args_eq = nm->mkNode(Kind::AND, + nm->mkNode(kind::EQUAL, args1[0], args2[0]), + nm->mkNode(kind::EQUAL, args1[1], args2[1]) + ); } Node func_eq = nm->mkNode(kind::EQUAL, args1, args2); Node lemma = nm->mkNode(kind::IMPLIES, args_eq, func_eq); @@ -153,7 +156,7 @@ void collectFunctionsAndLemmas(FunctionToArgsMap& fun_to_args, if (seen.find(term) == seen.end()) { TNode func; - if (term.getKind() == kind::APPLY_UF) + if (term.getKind() == kind::APPLY_UF || term.getKind() == kind::SELECT) { storeFunctionAndAddLemmas(term.getOperator(), term, @@ -163,11 +166,6 @@ void collectFunctionsAndLemmas(FunctionToArgsMap& fun_to_args, nm, vec); } - else if (term.getKind() == kind::SELECT) - { - storeFunctionAndAddLemmas( - term[0], term, fun_to_args, fun_to_skolem, assertions, nm, vec); - } else { AlwaysAssert(term.getKind() != kind::STORE) diff --git a/test/regress/CMakeLists.txt b/test/regress/CMakeLists.txt index 0caeafb36..4de32a426 100644 --- a/test/regress/CMakeLists.txt +++ b/test/regress/CMakeLists.txt @@ -59,6 +59,7 @@ set(regress_0_tests regress0/arrays/bug272.minimized.smtv1.smt2 regress0/arrays/bug272.smtv1.smt2 regress0/arrays/bug3020.smt2 + regress0/arrays/bug4957.smt2 regress0/arrays/bug637.delta.smt2 regress0/arrays/constarr.cvc regress0/arrays/constarr.smt2 diff --git a/test/regress/regress0/arrays/bug4957.smt2 b/test/regress/regress0/arrays/bug4957.smt2 new file mode 100644 index 000000000..f82ae1932 --- /dev/null +++ b/test/regress/regress0/arrays/bug4957.smt2 @@ -0,0 +1,6 @@ +; COMMAND-LINE: --ackermann --no-check-unsat-cores +; EXPECT: unsat +(set-logic QF_ALIA) +(declare-fun a () (Array Int Int)) +(assert (distinct (select a 0) (select (ite false a a) 0))) +(check-sat) -- cgit v1.2.3 From 09b3b246ad0328a163b0e3825531ccf82ea4013d Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Mon, 31 Aug 2020 15:34:36 -0500 Subject: (new theory) Update TheoryStrings to new standard (#4963) This updates theory of strings to the new standard. This makes strings use the standard template for check and collectModelInfo. It also updates its inference manager to the standard and makes use of assertFactInternal for processing internal facts. This now enables preNotifyFact and notifyFact to be defined in TheoryStrings instead of inside inference manager, which is clearer and eliminates some dependencies within inference manager. Note that the inference manager of strings for now inherits from TheoryInferenceManager. Further standardization will make it inherit from the new InferenceManagerBuffered class. This design will be merged into proof-new, which also has significant changes to strings inference manager. --- src/theory/strings/inference_manager.cpp | 111 ++++----------------------- src/theory/strings/inference_manager.h | 35 ++------- src/theory/strings/theory_strings.cpp | 124 ++++++++++++++++++------------- src/theory/strings/theory_strings.h | 28 ++++--- 4 files changed, 108 insertions(+), 190 deletions(-) diff --git a/src/theory/strings/inference_manager.cpp b/src/theory/strings/inference_manager.cpp index dce038fbf..811c040f3 100644 --- a/src/theory/strings/inference_manager.cpp +++ b/src/theory/strings/inference_manager.cpp @@ -28,19 +28,17 @@ namespace CVC4 { namespace theory { namespace strings { -InferenceManager::InferenceManager(context::Context* c, - context::UserContext* u, +InferenceManager::InferenceManager(Theory& t, SolverState& s, TermRegistry& tr, ExtTheory& e, - OutputChannel& out, - SequencesStatistics& statistics) - : d_state(s), + SequencesStatistics& statistics, + ProofNodeManager* pnm) + : TheoryInferenceManager(t, s, pnm), + d_state(s), d_termReg(tr), d_extt(e), - d_out(out), - d_statistics(statistics), - d_keep(c) + d_statistics(statistics) { NodeManager* nm = NodeManager::currentNM(); d_zero = nm->mkConst(Rational(0)); @@ -49,14 +47,6 @@ InferenceManager::InferenceManager(context::Context* c, d_false = nm->mkConst(false); } -void InferenceManager::sendAssumption(TNode lit) -{ - bool polarity = lit.getKind() != kind::NOT; - TNode atom = polarity ? lit : lit[0]; - // assert pending fact - assertPendingFact(atom, polarity, lit); -} - bool InferenceManager::sendInternalInference(std::vector& exp, Node conc, Inference infer) @@ -299,7 +289,7 @@ void InferenceManager::doPendingFacts() TNode atom = polarity ? fact : fact[0]; // no double negation or double (conjunctive) conclusions Assert(atom.getKind() != NOT && atom.getKind() != AND); - assertPendingFact(atom, polarity, exp); + assertInternalFact(atom, polarity, exp); } } else @@ -308,13 +298,8 @@ void InferenceManager::doPendingFacts() TNode atom = polarity ? facts : facts[0]; // no double negation or double (conjunctive) conclusions Assert(atom.getKind() != NOT && atom.getKind() != AND); - assertPendingFact(atom, polarity, exp); + assertInternalFact(atom, polarity, exp); } - // Must reference count the equality and its explanation, which is not done - // by the equality engine. Notice that we do not need to do this for - // external assertions, which enter as facts through sendAssumption. - d_keep.insert(facts); - d_keep.insert(exp); i++; } d_pending.clear(); @@ -392,68 +377,6 @@ void InferenceManager::doPendingLemmas() d_pendingReqPhase.clear(); } -void InferenceManager::assertPendingFact(Node atom, bool polarity, Node exp) -{ - eq::EqualityEngine* ee = d_state.getEqualityEngine(); - Trace("strings-pending") << "Assert pending fact : " << atom << " " - << polarity << " from " << exp << std::endl; - Assert(atom.getKind() != OR) << "Infer error: a split."; - if (atom.getKind() == EQUAL) - { - // we must ensure these terms are registered - Trace("strings-pending-debug") << " Register term" << std::endl; - for (const Node& t : atom) - { - // terms in the equality engine are already registered, hence skip - // currently done for only string-like terms, but this could potentially - // be avoided. - if (!ee->hasTerm(t) && t.getType().isStringLike()) - { - d_termReg.registerTerm(t, 0); - } - } - Trace("strings-pending-debug") << " Now assert equality" << std::endl; - ee->assertEquality(atom, polarity, exp); - Trace("strings-pending-debug") << " Finished assert equality" << std::endl; - } - else - { - ee->assertPredicate(atom, polarity, exp); - if (atom.getKind() == STRING_IN_REGEXP) - { - if (polarity && atom[1].getKind() == REGEXP_CONCAT) - { - Node eqc = ee->getRepresentative(atom[0]); - d_state.addEndpointsToEqcInfo(atom, atom[1], eqc); - } - } - } - // process the conflict - if (!d_state.isInConflict()) - { - Node pc = d_state.getPendingConflict(); - if (!pc.isNull()) - { - std::vector a; - a.push_back(pc); - Trace("strings-pending") - << "Process pending conflict " << pc << std::endl; - Node conflictNode = mkExplain(a); - d_state.notifyInConflict(); - Trace("strings-conflict") - << "CONFLICT: Eager prefix : " << conflictNode << std::endl; - ++(d_statistics.d_conflictsEagerPrefix); - d_out.conflict(conflictNode); - } - } - Trace("strings-pending-debug") << " Now collect terms" << std::endl; - // Collect extended function terms in the atom. Notice that we must register - // all extended functions occurring in assertions and shared terms. We - // make a similar call to registerTermRec in TheoryStrings::addSharedTerm. - d_extt.registerTermRec(atom); - Trace("strings-pending-debug") << " Finished collect terms" << std::endl; -} - bool InferenceManager::hasProcessed() const { return d_state.isInConflict() || !d_pendingLem.empty() || !d_pending.empty(); @@ -475,7 +398,6 @@ Node InferenceManager::mkExplain(const std::vector& a, { utils::flattenOp(AND, ac, aconj); } - eq::EqualityEngine* ee = d_state.getEqualityEngine(); for (const Node& apc : aconj) { if (std::find(noExplain.begin(), noExplain.end(), apc) != noExplain.end()) @@ -492,12 +414,12 @@ Node InferenceManager::mkExplain(const std::vector& a, Debug("strings-explain") << "Add to explanation " << apc << std::endl; if (apc.getKind() == NOT && apc[0].getKind() == EQUAL) { - Assert(ee->hasTerm(apc[0][0])); - Assert(ee->hasTerm(apc[0][1])); + Assert(d_ee->hasTerm(apc[0][0])); + Assert(d_ee->hasTerm(apc[0][1])); // ensure that we are ready to explain the disequality - AlwaysAssert(ee->areDisequal(apc[0][0], apc[0][1], true)); + AlwaysAssert(d_ee->areDisequal(apc[0][0], apc[0][1], true)); } - Assert(apc.getKind() != EQUAL || ee->areEqual(apc[0], apc[1])); + Assert(apc.getKind() != EQUAL || d_ee->areEqual(apc[0], apc[1])); // now, explain explain(apc, antec_exp); } @@ -522,7 +444,6 @@ void InferenceManager::explain(TNode literal, { Debug("strings-explain") << "Explain " << literal << " " << d_state.isInConflict() << std::endl; - eq::EqualityEngine* ee = d_state.getEqualityEngine(); bool polarity = literal.getKind() != NOT; TNode atom = polarity ? literal : literal[0]; std::vector tassumptions; @@ -530,14 +451,14 @@ void InferenceManager::explain(TNode literal, { if (atom[0] != atom[1]) { - Assert(ee->hasTerm(atom[0])); - Assert(ee->hasTerm(atom[1])); - ee->explainEquality(atom[0], atom[1], polarity, tassumptions); + Assert(d_ee->hasTerm(atom[0])); + Assert(d_ee->hasTerm(atom[1])); + d_ee->explainEquality(atom[0], atom[1], polarity, tassumptions); } } else { - ee->explainPredicate(atom, polarity, tassumptions); + d_ee->explainPredicate(atom, polarity, tassumptions); } for (const TNode a : tassumptions) { diff --git a/src/theory/strings/inference_manager.h b/src/theory/strings/inference_manager.h index 016891737..dc46f1683 100644 --- a/src/theory/strings/inference_manager.h +++ b/src/theory/strings/inference_manager.h @@ -29,6 +29,7 @@ #include "theory/strings/sequences_stats.h" #include "theory/strings/solver_state.h" #include "theory/strings/term_registry.h" +#include "theory/theory_inference_manager.h" #include "theory/uf/equality_engine.h" namespace CVC4 { @@ -65,28 +66,20 @@ namespace strings { * theory of strings, e.g. sendPhaseRequirement, setIncomplete, and * with the extended theory object e.g. markCongruent. */ -class InferenceManager +class InferenceManager : public TheoryInferenceManager { typedef context::CDHashSet NodeSet; typedef context::CDHashMap NodeNodeMap; public: - InferenceManager(context::Context* c, - context::UserContext* u, + InferenceManager(Theory& t, SolverState& s, TermRegistry& tr, ExtTheory& e, - OutputChannel& out, - SequencesStatistics& statistics); + SequencesStatistics& statistics, + ProofNodeManager* pnm); ~InferenceManager() {} - /** send assumption - * - * This is called when a fact is asserted to TheoryStrings. It adds lit - * to the equality engine maintained by this class immediately. - */ - void sendAssumption(TNode lit); - /** send internal inferences * * This is called when we have inferred exp => conc, where exp is a set @@ -292,23 +285,12 @@ class InferenceManager // ------------------------------------------------- end extended theory private: - /** assert pending fact - * - * This asserts atom with polarity to the equality engine of this class, - * where exp is the explanation of why (~) atom holds. - * - * This call may trigger further initialization steps involving the terms - * of atom, including calls to registerTerm. - */ - void assertPendingFact(Node atom, bool polarity, Node exp); /** Reference to the solver state of the theory of strings. */ SolverState& d_state; /** Reference to the term registry of theory of strings */ TermRegistry& d_termReg; /** the extended theory object for the theory of strings */ ExtTheory& d_extt; - /** A reference to the output channel of the theory of strings. */ - OutputChannel& d_out; /** Reference to the statistics for the theory of strings/sequences. */ SequencesStatistics& d_statistics; @@ -326,13 +308,6 @@ class InferenceManager std::map d_pendingReqPhase; /** A list of pending lemmas to be sent on the output channel. */ std::vector d_pendingLem; - /** - * The keep set of this class. This set is maintained to ensure that - * facts and their explanations are ref-counted. Since facts and their - * explanations are SAT-context-dependent, this set is also - * SAT-context-dependent. - */ - NodeSet d_keep; }; } // namespace strings diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp index 846f9240d..3e60cbc44 100644 --- a/src/theory/strings/theory_strings.cpp +++ b/src/theory/strings/theory_strings.cpp @@ -46,7 +46,7 @@ TheoryStrings::TheoryStrings(context::Context* c, d_state(c, u, d_valuation), d_termReg(d_state, out, d_statistics, nullptr), d_extTheory(this), - d_im(c, u, d_state, d_termReg, d_extTheory, out, d_statistics), + d_im(*this, d_state, d_termReg, d_extTheory, d_statistics, pnm), d_rewriter(&d_statistics.d_rewrites), d_bsolver(d_state, d_im), d_csolver(d_state, d_im, d_termReg, d_bsolver), @@ -83,6 +83,8 @@ TheoryStrings::TheoryStrings(context::Context* c, } // use the state object as the official theory state d_theoryState = &d_state; + // use the inference manager as the official inference manager + d_inferManager = &d_im; } TheoryStrings::~TheoryStrings() { @@ -165,23 +167,6 @@ void TheoryStrings::notifySharedTerm(TNode t) Debug("strings") << "TheoryStrings::notifySharedTerm() finished" << std::endl; } -EqualityStatus TheoryStrings::getEqualityStatus(TNode a, TNode b) { - if (d_equalityEngine->hasTerm(a) && d_equalityEngine->hasTerm(b)) - { - if (d_equalityEngine->areEqual(a, b)) - { - // The terms are implied to be equal - return EQUALITY_TRUE; - } - if (d_equalityEngine->areDisequal(a, b, false)) - { - // The terms are implied to be dis-equal - return EQUALITY_FALSE; - } - } - return EQUALITY_UNKNOWN; -} - bool TheoryStrings::propagateLit(TNode literal) { Debug("strings-propagate") @@ -252,24 +237,10 @@ void TheoryStrings::presolve() { // MODEL GENERATION ///////////////////////////////////////////////////////////////////////////// -bool TheoryStrings::collectModelInfo(TheoryModel* m) +bool TheoryStrings::collectModelValues(TheoryModel* m, + const std::set& termSet) { - Trace("strings-model") << "TheoryStrings : Collect model info" << std::endl; - Trace("strings-model") << "TheoryStrings : assertEqualityEngine." << std::endl; - - std::set termSet; - - // Compute terms appearing in assertions and shared terms - const std::set& irrKinds = m->getIrrelevantKinds(); - computeAssertedTerms(termSet, irrKinds); - // assert the (relevant) portion of the equality engine to the model - if (!m->assertEqualityEngine(d_equalityEngine, &termSet)) - { - Unreachable() - << "TheoryStrings::collectModelInfo: failed to assert equality engine" - << std::endl; - return false; - } + Trace("strings-model") << "TheoryStrings : Collect model values" << std::endl; std::map > repSet; // Generate model @@ -654,25 +625,68 @@ TrustNode TheoryStrings::expandDefinition(Node node) return TrustNode::null(); } -void TheoryStrings::check(Effort e) { - if (done() && ehasTerm(t) && t.getType().isStringLike()) + { + d_termReg.registerTerm(t, 0); + } + } } + return false; +} - TimerStat::CodeTimer checkTimer(d_checkTime); - - // Trace("strings-process") << "Theory of strings, check : " << e << std::endl; - Trace("strings-check-debug") - << "Theory of strings, check : " << e << std::endl; - while (!done() && !d_state.isInConflict()) +void TheoryStrings::notifyFact(TNode atom, + bool polarity, + TNode fact, + bool isInternal) +{ + if (atom.getKind() == STRING_IN_REGEXP) { - // Get all the assertions - Assertion assertion = get(); - TNode fact = assertion.d_assertion; - - Trace("strings-assertion") << "get assertion: " << fact << endl; - d_im.sendAssumption(fact); + if (polarity && atom[1].getKind() == REGEXP_CONCAT) + { + Node eqc = d_equalityEngine->getRepresentative(atom[0]); + d_state.addEndpointsToEqcInfo(atom, atom[1], eqc); + } } + // process pending conflicts due to reasoning about endpoints + if (!d_state.isInConflict()) + { + Node pc = d_state.getPendingConflict(); + if (!pc.isNull()) + { + std::vector a; + a.push_back(pc); + Trace("strings-pending") + << "Process pending conflict " << pc << std::endl; + Node conflictNode = d_im.mkExplain(a); + Trace("strings-conflict") + << "CONFLICT: Eager prefix : " << conflictNode << std::endl; + ++(d_statistics.d_conflictsEagerPrefix); + d_im.conflict(conflictNode); + return; + } + } + Trace("strings-pending-debug") << " Now collect terms" << std::endl; + // Collect extended function terms in the atom. Notice that we must register + // all extended functions occurring in assertions and shared terms. We + // make a similar call to registerTermRec in TheoryStrings::addSharedTerm. + d_extTheory.registerTermRec(atom); + Trace("strings-pending-debug") << " Finished collect terms" << std::endl; +} + +void TheoryStrings::postCheck(Effort e) +{ d_im.doPendingFacts(); Assert(d_strat.isStrategyInit()); @@ -681,8 +695,10 @@ void TheoryStrings::check(Effort e) { { Trace("strings-check-debug") << "Theory of strings " << e << " effort check " << std::endl; - if(Trace.isOn("strings-eqc")) { - for( unsigned t=0; t<2; t++ ) { + if (Trace.isOn("strings-eqc")) + { + for (unsigned t = 0; t < 2; t++) + { eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator(d_equalityEngine); Trace("strings-eqc") << (t==0 ? "STRINGS:" : "OTHER:") << std::endl; while( !eqcs2_i.isFinished() ){ @@ -726,7 +742,9 @@ void TheoryStrings::check(Effort e) { ++(d_statistics.d_strategyRuns); Trace("strings-check") << " * Run strategy..." << std::endl; runStrategy(e); - // flush the facts + // Send the facts *and* the lemmas. We send lemmas regardless of whether + // we send facts since some lemmas cannot be dropped. Other lemmas are + // otherwise avoided by aborting the strategy when a fact is ready. addedFact = d_im.hasPendingFact(); addedLemma = d_im.hasPendingLemma(); d_im.doPendingFacts(); diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h index f4aa0675c..0f59e73dc 100644 --- a/src/theory/strings/theory_strings.h +++ b/src/theory/strings/theory_strings.h @@ -97,27 +97,33 @@ class TheoryStrings : public Theory { void shutdown() override {} /** add shared term */ void notifySharedTerm(TNode n) override; - /** get equality status */ - EqualityStatus getEqualityStatus(TNode a, TNode b) override; /** preregister term */ void preRegisterTerm(TNode n) override; /** Expand definition */ TrustNode expandDefinition(Node n) override; - /** Check at effort e */ - void check(Effort e) override; - /** needs check last effort */ + //--------------------------------- standard check + /** Do we need a check call at last call effort? */ bool needsCheckLastEffort() override; + bool preNotifyFact(TNode atom, + bool pol, + TNode fact, + bool isPrereg, + bool isInternal) override; + void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override; + /** Post-check, called after the fact queue of the theory is processed. */ + void postCheck(Effort level) override; + //--------------------------------- end standard check + /** propagate method */ + bool propagateLit(TNode literal); /** Conflict when merging two constants */ void conflict(TNode a, TNode b); /** called when a new equivalence class is created */ void eqNotifyNewClass(TNode t); /** preprocess rewrite */ TrustNode ppRewrite(TNode atom) override; - /** - * Get all relevant information in this theory regarding the current - * model. Return false if a contradiction is discovered. - */ - bool collectModelInfo(TheoryModel* m) override; + /** Collect model values in m based on the relevant terms given by termSet */ + bool collectModelValues(TheoryModel* m, + const std::set& termSet) override; private: /** NotifyClass for equality engine */ @@ -171,8 +177,6 @@ class TheoryStrings : public Theory { /** The solver state of the theory of strings */ SolverState& d_state; };/* class TheoryStrings::NotifyClass */ - /** propagate method */ - bool propagateLit(TNode literal); /** compute care graph */ void computeCareGraph() override; /** -- cgit v1.2.3 From fa05eb5599e2ac0b2d4c1e0e943fee6353b52430 Mon Sep 17 00:00:00 2001 From: FabianWolff Date: Tue, 1 Sep 2020 05:20:57 +0200 Subject: Fix spelling errors (#4977) Signed-off-by: Fabian Wolff --- proofs/signatures/drat.plf | 2 +- proofs/signatures/lrat.plf | 12 ++++++------ proofs/signatures/th_lira.plf | 4 ++-- src/api/cvc4cpp.cpp | 8 ++++---- src/parser/cvc/Cvc.g | 2 +- src/prop/bvminisat/simp/SimpSolver.cc | 2 +- src/prop/bvminisat/simp/SimpSolver.h | 2 +- src/prop/minisat/simp/SimpSolver.cc | 2 +- src/prop/minisat/simp/SimpSolver.h | 2 +- src/smt/smt_engine.cpp | 2 +- src/smt/smt_engine.h | 2 +- src/smt/sygus_solver.h | 2 +- src/theory/arith/theory_arith_private.cpp | 2 +- src/theory/quantifiers_engine.cpp | 2 +- src/util/string.cpp | 6 +++--- src/util/string.h | 4 ++-- 16 files changed, 28 insertions(+), 28 deletions(-) diff --git a/proofs/signatures/drat.plf b/proofs/signatures/drat.plf index ad3c8ec8d..20795901f 100644 --- a/proofs/signatures/drat.plf +++ b/proofs/signatures/drat.plf @@ -354,7 +354,7 @@ ; Helper for `is_operational_drat_proof` which takes a UP model for the working ; formula. The UP model is important for determining which clause deletions ; actually are executed in operational DRAT. Passing the UP model along -; prevents it from being fully recomputed everytime. +; prevents it from being fully recomputed every time. (program is_operational_drat_proof_h ((f cnf) (up_model clause) (pf DRATProof)) bool (match pf (DRATProofn (cnf_has_bottom f)) diff --git a/proofs/signatures/lrat.plf b/proofs/signatures/lrat.plf index b5d46be43..c10f8d6c8 100644 --- a/proofs/signatures/lrat.plf +++ b/proofs/signatures/lrat.plf @@ -101,7 +101,7 @@ ((pos v2) ff) ((neg v2) (ifequal v1 v2 tt ff)))))) -; Remove **all** occurences of a literal from clause +; Remove **all** occurrences of a literal from clause (program clause_remove_all ((l lit) (c clause)) clause (match c (cln cln) @@ -180,7 +180,7 @@ (CMapc ci c (CMap_remove_many is cs')))))))) ; Given a map of clauses and a literal, return all indices in the map -; corresponsing to clauses that could resolve against that literal. i.e. for x, +; corresponding to clauses that could resolve against that literal. i.e. for x, ; return the indices of all clauses containing x. (program collect_resolution_targets_w_lit ((cs CMap) (l lit)) CIList (match cs @@ -260,14 +260,14 @@ (fail Unit) (ifmarked2 v unit (do (markvar2 v) unit)))))) -; Unmarks the variable within a satified literal to render it neither satified nor falsified +; Unmarks the variable within a satisfied literal to render it neither satisfied nor falsified ; fails if the literal is not already satisfied (program lit_un_mk_sat ((l lit)) Unit (match l ((pos v) (ifmarked1 v (do (markvar1 v) unit) (fail Unit))) ((neg v) (ifmarked2 v (do (markvar2 v) unit) (fail Unit))))) -; Unmarks the variable within a falsified literal to render it neither satified nor falsified +; Unmarks the variable within a falsified literal to render it neither satisfied nor falsified ; fails if the literal is not already falsified (program lit_un_mk_unsat ((l lit)) Unit (match l @@ -348,7 +348,7 @@ ; The return type for verifying that a clause is unit and modifying the global ; assignment to satisfy it (declare MarkResult type) -; The clause is unit, and this is the (previoiusly floating) literal that is now satified. +; The clause is unit, and this is the (previoiusly floating) literal that is now satisfied. (declare MRUnit (! l lit MarkResult)) ; The clause was unsat! (declare MRUnsat MarkResult) @@ -357,7 +357,7 @@ ; The clause had multiple floating literals. (declare MRNotUnit MarkResult) -; Determine wether this clause is sat, unsat, unit, or not unit, and if it is +; Determine whether this clause is sat, unsat, unit, or not unit, and if it is ; unit, it modifies the global assignment to satisfy the clause, and returns ; the literal that was made SAT by the new mark. ; diff --git a/proofs/signatures/th_lira.plf b/proofs/signatures/th_lira.plf index af326bf27..e3f6df112 100644 --- a/proofs/signatures/th_lira.plf +++ b/proofs/signatures/th_lira.plf @@ -128,7 +128,7 @@ (default (fail (term Int))) )) -; This function negates linear interger terms---sums of terms of the form +; This function negates linear integer terms---sums of terms of the form ; recognized by `negate_linear_monomial_int_term`. (program negate_linear_int_term ((t (term Int))) (term Int) (match t @@ -339,7 +339,7 @@ ; the statement that `a` satisfies `b` for all inputs (declare bounded_aff (! a aff (! b bound formula))) -; Sum of two bounds (the bound satisfied by the sum of two functions satifying +; Sum of two bounds (the bound satisfied by the sum of two functions satisfying ; the input bounds) (program bound_add ((b bound) (b2 bound)) bound (match b diff --git a/src/api/cvc4cpp.cpp b/src/api/cvc4cpp.cpp index 51ecea9f2..c14bed6aa 100644 --- a/src/api/cvc4cpp.cpp +++ b/src/api/cvc4cpp.cpp @@ -3044,10 +3044,10 @@ Term Solver::mkCharFromStrHelper(const std::string& s) const CVC4_API_CHECK(s.find_first_not_of("0123456789abcdefABCDEF", 0) == std::string::npos && s.size() <= 5 && s.size() > 0) - << "Unexpected string for hexidecimal character " << s; + << "Unexpected string for hexadecimal character " << s; uint32_t val = static_cast(std::stoul(s, 0, 16)); CVC4_API_CHECK(val < String::num_codes()) - << "Not a valid code point for hexidecimal character " << s; + << "Not a valid code point for hexadecimal character " << s; std::vector cpts; cpts.push_back(val); return mkValHelper(CVC4::String(cpts)); @@ -5506,7 +5506,7 @@ Term Solver::getSynthSolution(Term term) const std::map map; CVC4_API_CHECK(d_smtEngine->getSynthSolutions(map)) - << "The solver is not in a state immediately preceeded by a " + << "The solver is not in a state immediately preceded by a " "successful call to checkSynth"; std::map::const_iterator it = map.find(*term.d_node); @@ -5535,7 +5535,7 @@ std::vector Solver::getSynthSolutions( std::map map; CVC4_API_CHECK(d_smtEngine->getSynthSolutions(map)) - << "The solver is not in a state immediately preceeded by a " + << "The solver is not in a state immediately preceded by a " "successful call to checkSynth"; std::vector synthSolution; diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g index 091b5a22b..865776dcd 100644 --- a/src/parser/cvc/Cvc.g +++ b/src/parser/cvc/Cvc.g @@ -2481,7 +2481,7 @@ fragment DOT:; fragment DOTDOT:; /** - * Matches the hexidecimal digits (0-9, a-f, A-F) + * Matches the hexadecimal digits (0-9, a-f, A-F) */ fragment HEX_DIGIT : DIGIT | 'a'..'f' | 'A'..'F'; diff --git a/src/prop/bvminisat/simp/SimpSolver.cc b/src/prop/bvminisat/simp/SimpSolver.cc index b003342c6..6641310cc 100644 --- a/src/prop/bvminisat/simp/SimpSolver.cc +++ b/src/prop/bvminisat/simp/SimpSolver.cc @@ -538,7 +538,7 @@ bool SimpSolver::eliminateVar(Var v) for (int i = 0; i < cls.size(); i++) (find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]); - // Check wether the increase in number of clauses stays within the allowed ('grow'). Moreover, no + // Check whether the increase in number of clauses stays within the allowed ('grow'). Moreover, no // clause must exceed the limit on the maximal clause size (if it is set): // int cnt = 0; diff --git a/src/prop/bvminisat/simp/SimpSolver.h b/src/prop/bvminisat/simp/SimpSolver.h index 9d3a51c02..9907b8d72 100644 --- a/src/prop/bvminisat/simp/SimpSolver.h +++ b/src/prop/bvminisat/simp/SimpSolver.h @@ -54,7 +54,7 @@ class SimpSolver : public Solver { Lit r, ClauseId& id); // Add a ternary clause to the solver. bool addClause_(vec& ps, ClauseId& id); - bool substitute(Var v, Lit x); // Replace all occurences of v with x (may + bool substitute(Var v, Lit x); // Replace all occurrences of v with x (may // cause a contradiction). // Variable mode: diff --git a/src/prop/minisat/simp/SimpSolver.cc b/src/prop/minisat/simp/SimpSolver.cc index a101a0c2d..23f97b5d5 100644 --- a/src/prop/minisat/simp/SimpSolver.cc +++ b/src/prop/minisat/simp/SimpSolver.cc @@ -525,7 +525,7 @@ bool SimpSolver::eliminateVar(Var v) for (int i = 0; i < cls.size(); i++) (find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]); - // Check wether the increase in number of clauses stays within the allowed ('grow'). Moreover, no + // Check whether the increase in number of clauses stays within the allowed ('grow'). Moreover, no // clause must exceed the limit on the maximal clause size (if it is set): // int cnt = 0; diff --git a/src/prop/minisat/simp/SimpSolver.h b/src/prop/minisat/simp/SimpSolver.h index 335075f09..c13ee5583 100644 --- a/src/prop/minisat/simp/SimpSolver.h +++ b/src/prop/minisat/simp/SimpSolver.h @@ -55,7 +55,7 @@ class SimpSolver : public Solver { bool addClause (Lit p, Lit q, bool removable, ClauseId& id); // Add a binary clause to the solver. bool addClause (Lit p, Lit q, Lit r, bool removable, ClauseId& id); // Add a ternary clause to the solver. bool addClause_(vec& ps, bool removable, ClauseId& id); - bool substitute(Var v, Lit x); // Replace all occurences of v with x (may cause a contradiction). + bool substitute(Var v, Lit x); // Replace all occurrences of v with x (may cause a contradiction). // Variable mode: // diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp index 98e865478..955fe3e14 100644 --- a/src/smt/smt_engine.cpp +++ b/src/smt/smt_engine.cpp @@ -891,7 +891,7 @@ theory::TheoryModel* SmtEngine::getAvailableModel(const char* c) const std::stringstream ss; ss << "Cannot " << c << " since model is not available. Perhaps the most recent call to " - "check-sat was interupted?"; + "check-sat was interrupted?"; throw RecoverableModalException(ss.str().c_str()); } diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h index 99c4a67d3..223478e5f 100644 --- a/src/smt/smt_engine.h +++ b/src/smt/smt_engine.h @@ -566,7 +566,7 @@ class CVC4_PUBLIC SmtEngine /** * Get synth solution. * - * This method returns true if we are in a state immediately preceeded by + * This method returns true if we are in a state immediately preceded by * a successful call to checkSynth. * * This method adds entries to solMap that map functions-to-synthesize with diff --git a/src/smt/sygus_solver.h b/src/smt/sygus_solver.h index 468535da1..621bea9f3 100644 --- a/src/smt/sygus_solver.h +++ b/src/smt/sygus_solver.h @@ -116,7 +116,7 @@ class SygusSolver /** * Get synth solution. * - * This method returns true if we are in a state immediately preceeded by + * This method returns true if we are in a state immediately preceded by * a successful call to checkSynth. * * This method adds entries to sol_map that map functions-to-synthesize with diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp index 9a8ca733a..7f521e2f9 100644 --- a/src/theory/arith/theory_arith_private.cpp +++ b/src/theory/arith/theory_arith_private.cpp @@ -4372,7 +4372,7 @@ bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound //We are only going to recreate the functionality for now. //In the future this can be improved to generate a temporary constraint //if none exists. - //Experiment with doing this everytime or only when the new constraint + //Experiment with doing this every time or only when the new constraint //implies an unknown fact. ConstraintType t = upperBound ? UpperBound : LowerBound; diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp index dd59628c1..cb7a4d055 100644 --- a/src/theory/quantifiers_engine.cpp +++ b/src/theory/quantifiers_engine.cpp @@ -575,7 +575,7 @@ void QuantifiersEngine::check( Theory::Effort e ){ Trace("quant-engine-debug2") << "Quantifiers Engine call to check, level = " << e << ", needsCheck=" << needsCheck << std::endl; if( needsCheck ){ - //flush previous lemmas (for instance, if was interupted), or other lemmas to process + //flush previous lemmas (for instance, if was interrupted), or other lemmas to process flushLemmas(); if( d_hasAddedLemma ){ return; diff --git a/src/util/string.cpp b/src/util/string.cpp index 44c4d3e4b..a1a40df8a 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -131,7 +131,7 @@ std::vector String::toInternal(const std::string& s, ++i; // are we an escape sequence? bool isEscapeSequence = true; - // the string corresponding to the hexidecimal code point + // the string corresponding to the hexadecimal code point std::stringstream hexString; // is the slash followed by a 'u'? Could be last character. if (i >= s.size() || s[i] != 'u') @@ -195,7 +195,7 @@ std::vector String::toInternal(const std::string& s, } if (!isEnd) { - // if we were interupted before ending, then this is not a valid + // if we were interrupted before ending, then this is not a valid // escape sequence isEscapeSequence = false; } @@ -210,7 +210,7 @@ std::vector String::toInternal(const std::string& s, if (val > num_codes()) { // Failed due to being out of range. This can happen for strings of - // the form \ u { d_4 d_3 d_2 d_1 d_0 } where d_4 is a hexidecimal not + // the form \ u { d_4 d_3 d_2 d_1 d_0 } where d_4 is a hexadecimal not // in the range [0-2]. isEscapeSequence = false; } diff --git a/src/util/string.h b/src/util/string.h index ca458232f..fb4a1208c 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -58,7 +58,7 @@ class CVC4_PUBLIC String { * \u{d_2 d_1 d_0} * \u{d_3 d_2 d_1 d_0} * \u{d_4 d_3 d_2 d_1 d_0} - * where d_0 ... d_4 are hexidecimal digits, to the appropriate character. + * where d_0 ... d_4 are hexadecimal digits, to the appropriate character. * * If useEscSequences is false, then the characters of the constructed * CVC4::String correspond one-to-one with the input string. @@ -213,7 +213,7 @@ class CVC4_PUBLIC String { * This is true for code points between 48 ('0') and 57 ('9'). */ static bool isDigit(unsigned character); - /** is the unsigned a hexidecimal digit? + /** is the unsigned a hexadecimal digit? * * This is true for code points between 48 ('0') and 57 ('9'), code points * between 65 ('A') and 70 ('F) and code points between 97 ('a') and 102 ('f). -- cgit v1.2.3 From 9b7f2b6b541f192acf2dc525076a4aa0e995be14 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Mon, 31 Aug 2020 23:35:57 -0500 Subject: Add the inference manager for datatypes (#4968) This is in preparation for converting datatypes to the new standard. It adds a specialized version of inference manager buffered that datatypes uses. This required adding several utility methods to its base classes. A follow up PR will connect this to TheoryDatatypes. --- src/CMakeLists.txt | 2 + src/theory/datatypes/inference_manager.cpp | 128 +++++++++++++++++++++++++++++ src/theory/datatypes/inference_manager.h | 77 +++++++++++++++++ src/theory/inference_manager_buffered.cpp | 6 ++ src/theory/inference_manager_buffered.h | 6 ++ src/theory/theory_inference_manager.cpp | 68 +++++++++++++-- src/theory/theory_inference_manager.h | 75 +++++++++++++++-- 7 files changed, 349 insertions(+), 13 deletions(-) create mode 100644 src/theory/datatypes/inference_manager.cpp create mode 100644 src/theory/datatypes/inference_manager.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 06bc9917f..2a7fd11a8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -471,6 +471,8 @@ libcvc4_add_sources( theory/combination_engine.h theory/datatypes/datatypes_rewriter.cpp theory/datatypes/datatypes_rewriter.h + theory/datatypes/inference_manager.cpp + theory/datatypes/inference_manager.h theory/datatypes/sygus_datatype_utils.cpp theory/datatypes/sygus_datatype_utils.h theory/datatypes/sygus_extension.cpp diff --git a/src/theory/datatypes/inference_manager.cpp b/src/theory/datatypes/inference_manager.cpp new file mode 100644 index 000000000..42cad0b65 --- /dev/null +++ b/src/theory/datatypes/inference_manager.cpp @@ -0,0 +1,128 @@ +/********************* */ +/*! \file inference_manager.cpp + ** \verbatim + ** Top contributors (to current version): + ** 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 Datatypes inference manager + **/ + +#include "theory/datatypes/inference_manager.h" + +#include "expr/dtype.h" +#include "options/datatypes_options.h" +#include "theory/theory.h" + +using namespace CVC4::kind; + +namespace CVC4 { +namespace theory { +namespace datatypes { + +InferenceManager::InferenceManager(Theory& t, + TheoryState& state, + ProofNodeManager* pnm) + : InferenceManagerBuffered(t, state, pnm) +{ + d_true = NodeManager::currentNM()->mkConst(true); +} + +bool InferenceManager::mustCommunicateFact(Node n, Node exp) const +{ + Trace("dt-lemma-debug") << "Compute for " << exp << " => " << n << std::endl; + bool addLemma = false; + if (options::dtInferAsLemmas() && exp != d_true) + { + addLemma = true; + } + else if (n.getKind() == EQUAL) + { + TypeNode tn = n[0].getType(); + if (!tn.isDatatype()) + { + addLemma = true; + } + else + { + const DType& dt = tn.getDType(); + addLemma = dt.involvesExternalType(); + } + } + else if (n.getKind() == LEQ || n.getKind() == OR) + { + addLemma = true; + } + if (addLemma) + { + Trace("dt-lemma-debug") << "Communicate " << n << std::endl; + return true; + } + Trace("dt-lemma-debug") << "Do not need to communicate " << n << std::endl; + return false; +} + +void InferenceManager::process() +{ + // process pending lemmas, used infrequently, only for definitional lemmas + doPendingLemmas(); + // now process the pending facts + size_t i = 0; + NodeManager* nm = NodeManager::currentNM(); + while (!d_theoryState.isInConflict() && i < d_pendingFact.size()) + { + std::pair& pfact = d_pendingFact[i]; + const Node& fact = pfact.first; + const Node& exp = pfact.second; + Trace("datatypes-debug") + << "Assert fact (#" << (i + 1) << "/" << d_pendingFact.size() << ") " + << fact << " with explanation " << exp << std::endl; + // check to see if we have to communicate it to the rest of the system + if (mustCommunicateFact(fact, exp)) + { + Node lem = fact; + if (exp.isNull() || exp == d_true) + { + Trace("dt-lemma-debug") << "Trivial explanation." << std::endl; + } + else + { + Trace("dt-lemma-debug") << "Get explanation..." << std::endl; + std::vector assumptions; + explain(exp, assumptions); + if (!assumptions.empty()) + { + std::vector children; + for (const TNode& assumption : assumptions) + { + children.push_back(assumption.negate()); + } + children.push_back(fact); + lem = nm->mkNode(OR, children); + } + } + Trace("dt-lemma") << "Datatypes lemma : " << lem << std::endl; + lemma(lem); + } + else + { + // assert the internal fact + bool polarity = fact.getKind() != NOT; + TNode atom = polarity ? fact : fact[0]; + assertInternalFact(atom, polarity, exp); + } + Trace("datatypes-debug") << "Finished fact " << fact + << ", now = " << d_theoryState.isInConflict() + << " " << d_pendingFact.size() << std::endl; + i++; + } + d_pendingFact.clear(); +} + +} // namespace datatypes +} // namespace theory +} // namespace CVC4 diff --git a/src/theory/datatypes/inference_manager.h b/src/theory/datatypes/inference_manager.h new file mode 100644 index 000000000..786cd8129 --- /dev/null +++ b/src/theory/datatypes/inference_manager.h @@ -0,0 +1,77 @@ +/********************* */ +/*! \file inference_manager.h + ** \verbatim + ** Top contributors (to current version): + ** 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 Datatypes inference manager + **/ + +#include "cvc4_private.h" + +#ifndef CVC4__THEORY__DATATYPES__INFERENCE_MANAGER_H +#define CVC4__THEORY__DATATYPES__INFERENCE_MANAGER_H + +#include "context/cdhashmap.h" +#include "expr/node.h" +#include "theory/inference_manager_buffered.h" + +namespace CVC4 { +namespace theory { +namespace datatypes { + +/** + * The datatypes inference manager. The main unique features of this inference + * manager are: + * (1) Explicit caching of lemmas, + * (2) A custom process() method with relies on a policy determining which + * facts must be sent as lemmas (mustCommunicateFact). + * (3) Methods for tracking when lemmas and facts have been processed. + */ +class InferenceManager : public InferenceManagerBuffered +{ + typedef context::CDHashSet NodeSet; + + public: + InferenceManager(Theory& t, TheoryState& state, ProofNodeManager* pnm); + ~InferenceManager() {} + /** + * Process the current lemmas and facts. This is a custom method that can + * be seen as overriding the behavior of calling both doPendingLemmas and + * doPendingFacts. It determines whether facts should be sent as lemmas + * or processed internally. + */ + void process(); + + protected: + /** + * Must communicate fact method. + * The datatypes decision procedure makes "internal" inferences : + * (1) Unification : C( t1...tn ) = C( s1...sn ) => ti = si + * (2) Label : ~is_C1(t) ... ~is_C{i-1}(t) ~is_C{i+1}(t) ... ~is_Cn(t) => + * is_Ci( t ) + * (3) Instantiate : is_C( t ) => t = C( sel_1( t ) ... sel_n( t ) ) + * (4) collapse selector : S( C( t1...tn ) ) = t' + * (5) collapse term size : size( C( t1...tn ) ) = 1 + size( t1 ) + ... + + * size( tn ) + * (6) non-negative size : 0 <= size(t) + * This method returns true if the fact must be sent out as a lemma. If it + * returns false, then we assert the fact internally. We may need to + * communicate outwards if the conclusions involve other theories. Also + * communicate (6) and OR conclusions. + */ + bool mustCommunicateFact(Node n, Node exp) const; + /** Common node */ + Node d_true; +}; + +} // namespace datatypes +} // namespace theory +} // namespace CVC4 + +#endif diff --git a/src/theory/inference_manager_buffered.cpp b/src/theory/inference_manager_buffered.cpp index adbcc3033..14f6c4f4a 100644 --- a/src/theory/inference_manager_buffered.cpp +++ b/src/theory/inference_manager_buffered.cpp @@ -117,6 +117,12 @@ void InferenceManagerBuffered::doPendingPhaseRequirements() } d_pendingReqPhase.clear(); } +void InferenceManagerBuffered::clearPendingFacts() { d_pendingFact.clear(); } +void InferenceManagerBuffered::clearPendingLemmas() { d_pendingLem.clear(); } +void InferenceManagerBuffered::clearPendingPhaseRequirements() +{ + d_pendingReqPhase.clear(); +} } // namespace theory } // namespace CVC4 diff --git a/src/theory/inference_manager_buffered.h b/src/theory/inference_manager_buffered.h index bb46ef566..596a346de 100644 --- a/src/theory/inference_manager_buffered.h +++ b/src/theory/inference_manager_buffered.h @@ -145,6 +145,12 @@ class InferenceManagerBuffered : public TheoryInferenceManager * phase requirements and clears d_pendingReqPhase. */ void doPendingPhaseRequirements(); + /** Clear pending facts, without processing */ + void clearPendingFacts(); + /** Clear pending lemmas, without processing */ + void clearPendingLemmas(); + /** Clear pending phase requirements, without processing */ + void clearPendingPhaseRequirements(); protected: /** A set of pending lemmas */ diff --git a/src/theory/theory_inference_manager.cpp b/src/theory/theory_inference_manager.cpp index a42c33814..20c1fbf37 100644 --- a/src/theory/theory_inference_manager.cpp +++ b/src/theory/theory_inference_manager.cpp @@ -30,7 +30,10 @@ TheoryInferenceManager::TheoryInferenceManager(Theory& t, d_out(t.getOutputChannel()), d_ee(nullptr), d_pnm(pnm), - d_keep(t.getSatContext()) + d_keep(t.getSatContext()), + d_lemmasSent(t.getUserContext()), + d_numCurrentLemmas(0), + d_numCurrentFacts(0) { } @@ -47,6 +50,12 @@ void TheoryInferenceManager::setEqualityEngine(eq::EqualityEngine* ee) } } +void TheoryInferenceManager::reset() +{ + d_numCurrentLemmas = 0; + d_numCurrentFacts = 0; +} + void TheoryInferenceManager::conflictEqConstantMerge(TNode a, TNode b) { if (!d_theoryState.isInConflict()) @@ -125,15 +134,41 @@ TrustNode TheoryInferenceManager::explainConflictEqConstantMerge(TNode a, << " mkTrustedConflictEqConstantMerge"; } -LemmaStatus TheoryInferenceManager::lemma(TNode lem, LemmaProperty p) +bool TheoryInferenceManager::lemma(TNode lem, LemmaProperty p, bool doCache) +{ + TrustNode tlem = TrustNode::mkTrustLemma(lem, nullptr); + return trustedLemma(tlem, p, doCache); +} + +bool TheoryInferenceManager::trustedLemma(const TrustNode& tlem, + LemmaProperty p, + bool doCache) +{ + if (doCache) + { + if (!cacheLemma(tlem.getNode(), p)) + { + return false; + } + } + d_numCurrentLemmas++; + d_out.trustedLemma(tlem, p); + return true; +} + +bool TheoryInferenceManager::hasCachedLemma(TNode lem, LemmaProperty p) +{ + return d_lemmasSent.find(lem) != d_lemmasSent.end(); +} + +uint32_t TheoryInferenceManager::numAddedLemmas() const { - return d_out.lemma(lem, p); + return d_numCurrentLemmas; } -LemmaStatus TheoryInferenceManager::trustedLemma(const TrustNode& tlem, - LemmaProperty p) +bool TheoryInferenceManager::hasAddedLemma() const { - return d_out.trustedLemma(tlem, p); + return d_numCurrentLemmas != 0; } void TheoryInferenceManager::assertInternalFact(TNode atom, bool pol, TNode exp) @@ -178,6 +213,7 @@ void TheoryInferenceManager::processInternalFact(TNode atom, Assert(d_ee != nullptr); Trace("infer-manager") << "TheoryInferenceManager::assertInternalFact: " << expn << std::endl; + d_numCurrentFacts++; // Now, assert the fact. How to do so depends on whether proofs are enabled. // If no proof production, or no proof rule was given if (d_pfee == nullptr || id == PfRule::UNKNOWN) @@ -244,5 +280,25 @@ Node TheoryInferenceManager::mkExplain(TNode n) return NodeManager::currentNM()->mkAnd(assumptions); } +uint32_t TheoryInferenceManager::numAddedFacts() const +{ + return d_numCurrentFacts; +} + +bool TheoryInferenceManager::hasAddedFact() const +{ + return d_numCurrentFacts != 0; +} + +bool TheoryInferenceManager::cacheLemma(TNode lem, LemmaProperty p) +{ + if (d_lemmasSent.find(lem) != d_lemmasSent.end()) + { + return false; + } + d_lemmasSent.insert(lem); + return true; +} + } // namespace theory } // namespace CVC4 diff --git a/src/theory/theory_inference_manager.h b/src/theory/theory_inference_manager.h index af8e817b4..d5c0fe1b2 100644 --- a/src/theory/theory_inference_manager.h +++ b/src/theory/theory_inference_manager.h @@ -71,13 +71,23 @@ class TheoryInferenceManager */ TheoryInferenceManager(Theory& t, TheoryState& state, ProofNodeManager* pnm); virtual ~TheoryInferenceManager() {} - //--------------------------------------- initialization /** * Set equality engine, ee is a pointer to the official equality engine * of theory. */ void setEqualityEngine(eq::EqualityEngine* ee); - //--------------------------------------- end initialization + /** + * Reset, which resets counters regarding the number of added lemmas and + * internal facts. This method should be manually called by the theory at + * the appropriate time for the purpose of tracking the usage of this + * inference manager. + * + * For example, some theories implement an internal checking loop that + * repeats while new facts are added. The theory should call reset at the + * beginning of this loop and repeat its strategy while hasAddedFact is true. + */ + void reset(); + //--------------------------------------- propagations /** * T-propagate literal lit, possibly encountered by equality engine, * returns false if we are in conflict. @@ -94,6 +104,7 @@ class TheoryInferenceManager * Theory, if it exists. */ virtual TrustNode explainLit(TNode lit); + //--------------------------------------- conflicts /** * Raise conflict, called when constants a and b merge. Sends the conflict * on the output channel corresponding to the equality engine's explanation @@ -114,11 +125,39 @@ class TheoryInferenceManager * been provided in a custom way. */ void trustedConflict(TrustNode tconf); - /** Send lemma lem with property p on the output channel. */ - LemmaStatus lemma(TNode lem, LemmaProperty p = LemmaProperty::NONE); - /** Send (trusted) lemma lem with property p on the output channel. */ - LemmaStatus trustedLemma(const TrustNode& tlem, - LemmaProperty p = LemmaProperty::NONE); + //--------------------------------------- lemmas + /** + * Send (trusted) lemma lem with property p on the output channel. + * + * @param tlem The trust node containing the lemma and its proof generator. + * @param p The property of the lemma + * @param doCache If true, we send the lemma only if it has not already been + * cached (see cacheLemma), and add it to the cache during this call. + * @return true if the lemma was sent on the output channel. + */ + bool trustedLemma(const TrustNode& tlem, + LemmaProperty p = LemmaProperty::NONE, + bool doCache = true); + /** + * Send lemma lem with property p on the output channel. Same as above, with + * a node instead of a trust node. + */ + bool lemma(TNode lem, + LemmaProperty p = LemmaProperty::NONE, + bool doCache = true); + /** + * Has this inference manager cached and sent the given lemma (in this user + * context)? This method can be overridden by the particular manager. If not, + * this returns true if lem is in the cache d_lemmasSent maintained by this + * class. Notice that the default cache in this base class is not dependent + * on the lemma property. + */ + virtual bool hasCachedLemma(TNode lem, LemmaProperty p); + /** The number of lemmas we have sent since the last call to reset */ + uint32_t numAddedLemmas() const; + /** Have we added a lemma since the last call to reset? */ + bool hasAddedLemma() const; + //--------------------------------------- internal facts /** * Assert internal fact. This is recommended method for asserting "internal" * facts into the equality engine of the theory. In particular, this method @@ -163,6 +202,10 @@ class TheoryInferenceManager bool pol, const std::vector& exp, ProofGenerator* pg); + /** The number of internal facts we have added since the last call to reset */ + uint32_t numAddedFacts() const; + /** Have we added a internal fact since the last call to reset? */ + bool hasAddedFact() const; protected: /** @@ -192,6 +235,15 @@ class TheoryInferenceManager * conjunctions), return the explanation as a conjunction. */ Node mkExplain(TNode n); + /** + * Cache that lemma lem is being sent with property p. Return true if it + * did not already exist in the cache maintained by this class. If this + * method is not overridden, then we use the d_lemmasSent cache maintained + * by this class, which notice is not dependent on lemma property. If + * the lemma property should be taken into account, the manager should + * override this method to take the lemma property into account as needed. + */ + virtual bool cacheLemma(TNode lem, LemmaProperty p); /** The theory object */ Theory& d_theory; /** Reference to the state of theory */ @@ -211,6 +263,15 @@ class TheoryInferenceManager * SAT-context-dependent. */ NodeSet d_keep; + /** + * A cache of all lemmas sent, which is a user-context-dependent set of + * nodes. Notice that this cache does not depedent on lemma property. + */ + NodeSet d_lemmasSent; + /** The number of lemmas sent since the last call to reset. */ + uint32_t d_numCurrentLemmas; + /** The number of internal facts added since the last call to reset. */ + uint32_t d_numCurrentFacts; }; } // namespace theory -- cgit v1.2.3 From a276c5259782f867584bdd5e6e5cd50adc3c5dae Mon Sep 17 00:00:00 2001 From: FabianWolff Date: Tue, 1 Sep 2020 07:44:18 +0200 Subject: 'fix-install-headers.sh' should respect DESTDIR environment variable (#4978) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using CMake with Unix Makefiles, one can invoke `make install` as ``` make install DESTDIR=/a/b/c ``` so that the files will be installed into `$DESTDIR$CMAKE_INSTALL_PREFIX` (see the [documentation](https://cmake.org/cmake/help/latest/envvar/DESTDIR.html) for details). This currently doesn't work with the `fix-install-headers.sh` script: ``` [...] -- Installing: /<>/debian/tmp/usr/include/cvc4/util/integer.h -- Installing: /<>/debian/tmp/usr/include/cvc4/util/rational.h find: ‘/usr/include/cvc4/’: No such file or directory ``` Here, `CMAKE_INSTALL_PREFIX` is `/usr` but `DESTDIR` is `/<>/debian/tmp/`. This commit makes the script consider `DESTDIR` (if it is not set, then `$DESTDIR` will be empty and nothing changes) to fix this issue. Signed-off-by: Fabian Wolff --- src/fix-install-headers.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fix-install-headers.sh b/src/fix-install-headers.sh index 39d8bc663..7f9fa5d5b 100755 --- a/src/fix-install-headers.sh +++ b/src/fix-install-headers.sh @@ -2,6 +2,7 @@ set -e -o pipefail -dir=$1 +dir="$DESTDIR$1" + find "$dir/include/cvc4/" -type f \ -exec sed -i'' -e 's/include.*"\(.*\)"/include /' {} + -- cgit v1.2.3 From 58f059a967ccb968f127b2d56f69c20700a943fb Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Tue, 1 Sep 2020 10:57:51 -0700 Subject: Add arithmetic-specific, runtime, proof-macros. (#4992) We'll use this to gate farkas-coefficient machinery after we remove the old proof-macros. I've changed the macros slightly from the proof-new branch: I removed the dependence on options::proof() (no longer wanted) and options::unsatCores() (I had copied this from the original proof macros, but it's not needed either, since we're in a theory). --- src/theory/arith/proof_macros.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/theory/arith/proof_macros.h diff --git a/src/theory/arith/proof_macros.h b/src/theory/arith/proof_macros.h new file mode 100644 index 000000000..6cc1b3b15 --- /dev/null +++ b/src/theory/arith/proof_macros.h @@ -0,0 +1,34 @@ +/********************* */ +/*! \file proof_macros.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 Macros which run code when the old or new proof system is enabled, + ** or unsat cores are enabled. + **/ + +#include "cvc4_private.h" + +#ifndef CVC4__THEORY__ARITH__PROOF_MACROS_H +#define CVC4__THEORY__ARITH__PROOF_MACROS_H + +#include "options/smt_options.h" + +#define ARITH_PROOF(x) \ + if (CVC4::options::proofNew()) \ + { \ + x; \ + } +#define ARITH_NULLPROOF(x) \ + (CVC4::options::proofNew()) \ + ? x \ + : NULL +#define ARITH_PROOF_ON() CVC4::options::proofNew() + +#endif // CVC4__THEORY__ARITH__PROOF_MACROS_H -- cgit v1.2.3 From 56b6eabba4202b8fb848c97b04e12f622eba411f Mon Sep 17 00:00:00 2001 From: Aina Niemetz Date: Tue, 1 Sep 2020 13:07:11 -0700 Subject: CMS: Update to version 5.8.0. (#4991) --- contrib/get-cryptominisat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/get-cryptominisat b/contrib/get-cryptominisat index 2b85e1a91..476d1ff10 100755 --- a/contrib/get-cryptominisat +++ b/contrib/get-cryptominisat @@ -3,7 +3,7 @@ source "$(dirname "$0")/get-script-header.sh" CMS_DIR="$DEPS_DIR/cryptominisat5" -version="5.6.3" +version="5.8.0" check_dep_dir "$CMS_DIR" setup_dep \ -- cgit v1.2.3 From 2add221570239ded0e9865be22d1cb1b4e7ef0b1 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Tue, 1 Sep 2020 15:50:58 -0500 Subject: Add TheoryInference base class (#4990) This introduces a TheoryInference base class, which is a generalization and cleaner version of the former Lemma object. This changes the name of Lemma -> SimpleTheoryLemma, and makes the callback responsible for calling the inference manager. This PR also updates the datatypes inference manager to use the new style. This required adding some additional interfaces to TheoryInferenceManager. --- src/CMakeLists.txt | 2 + src/theory/datatypes/inference_manager.cpp | 99 ++++++++++++--------------- src/theory/datatypes/inference_manager.h | 59 +++++++++------- src/theory/inference_manager_buffered.cpp | 49 +++++++------ src/theory/inference_manager_buffered.h | 56 ++++----------- src/theory/theory_inference.cpp | 63 +++++++++++++++++ src/theory/theory_inference.h | 106 +++++++++++++++++++++++++++++ src/theory/theory_inference_manager.cpp | 83 +++++++++++++++++++++- src/theory/theory_inference_manager.h | 72 +++++++++++++++++++- 9 files changed, 438 insertions(+), 151 deletions(-) create mode 100644 src/theory/theory_inference.cpp create mode 100644 src/theory/theory_inference.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2a7fd11a8..052479624 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -827,6 +827,8 @@ libcvc4_add_sources( theory/theory_engine_proof_generator.h theory/theory_id.cpp theory/theory_id.h + theory/theory_inference.cpp + theory/theory_inference.h theory/theory_inference_manager.cpp theory/theory_inference_manager.h theory/theory_model.cpp diff --git a/src/theory/datatypes/inference_manager.cpp b/src/theory/datatypes/inference_manager.cpp index 42cad0b65..3dc16355b 100644 --- a/src/theory/datatypes/inference_manager.cpp +++ b/src/theory/datatypes/inference_manager.cpp @@ -24,20 +24,20 @@ namespace CVC4 { namespace theory { namespace datatypes { -InferenceManager::InferenceManager(Theory& t, - TheoryState& state, - ProofNodeManager* pnm) - : InferenceManagerBuffered(t, state, pnm) +DatatypesInference::DatatypesInference(Node conc, Node exp, ProofGenerator* pg) + : SimpleTheoryInternalFact(conc, exp, pg) { - d_true = NodeManager::currentNM()->mkConst(true); + // false is not a valid explanation + Assert(d_exp.isNull() || !d_exp.isConst() || d_exp.getConst()); } -bool InferenceManager::mustCommunicateFact(Node n, Node exp) const +bool DatatypesInference::mustCommunicateFact(Node n, Node exp) { Trace("dt-lemma-debug") << "Compute for " << exp << " => " << n << std::endl; bool addLemma = false; - if (options::dtInferAsLemmas() && exp != d_true) + if (options::dtInferAsLemmas() && !exp.isConst()) { + // all units are lemmas addLemma = true; } else if (n.getKind() == EQUAL) @@ -66,61 +66,46 @@ bool InferenceManager::mustCommunicateFact(Node n, Node exp) const return false; } -void InferenceManager::process() +bool DatatypesInference::process(TheoryInferenceManager* im) { - // process pending lemmas, used infrequently, only for definitional lemmas - doPendingLemmas(); - // now process the pending facts - size_t i = 0; - NodeManager* nm = NodeManager::currentNM(); - while (!d_theoryState.isInConflict() && i < d_pendingFact.size()) + // check to see if we have to communicate it to the rest of the system + if (mustCommunicateFact(d_conc, d_exp)) { - std::pair& pfact = d_pendingFact[i]; - const Node& fact = pfact.first; - const Node& exp = pfact.second; - Trace("datatypes-debug") - << "Assert fact (#" << (i + 1) << "/" << d_pendingFact.size() << ") " - << fact << " with explanation " << exp << std::endl; - // check to see if we have to communicate it to the rest of the system - if (mustCommunicateFact(fact, exp)) - { - Node lem = fact; - if (exp.isNull() || exp == d_true) - { - Trace("dt-lemma-debug") << "Trivial explanation." << std::endl; - } - else - { - Trace("dt-lemma-debug") << "Get explanation..." << std::endl; - std::vector assumptions; - explain(exp, assumptions); - if (!assumptions.empty()) - { - std::vector children; - for (const TNode& assumption : assumptions) - { - children.push_back(assumption.negate()); - } - children.push_back(fact); - lem = nm->mkNode(OR, children); - } - } - Trace("dt-lemma") << "Datatypes lemma : " << lem << std::endl; - lemma(lem); - } - else + // send it as an (explained) lemma + std::vector exp; + if (!d_exp.isNull() && !d_exp.isConst()) { - // assert the internal fact - bool polarity = fact.getKind() != NOT; - TNode atom = polarity ? fact : fact[0]; - assertInternalFact(atom, polarity, exp); + exp.push_back(d_exp); } - Trace("datatypes-debug") << "Finished fact " << fact - << ", now = " << d_theoryState.isInConflict() - << " " << d_pendingFact.size() << std::endl; - i++; + return im->lemmaExp(d_conc, exp, {}); } - d_pendingFact.clear(); + // assert the internal fact + bool polarity = d_conc.getKind() != NOT; + TNode atom = polarity ? d_conc : d_conc[0]; + im->assertInternalFact(atom, polarity, d_exp); + return true; +} + +InferenceManager::InferenceManager(Theory& t, + TheoryState& state, + ProofNodeManager* pnm) + : InferenceManagerBuffered(t, state, pnm) +{ +} + +void InferenceManager::addPendingInference(Node conc, + Node exp, + ProofGenerator* pg) +{ + d_pendingFact.push_back(std::make_shared(conc, exp, pg)); +} + +void InferenceManager::process() +{ + // process pending lemmas, used infrequently, only for definitional lemmas + doPendingLemmas(); + // now process the pending facts + doPendingFacts(); } } // namespace datatypes diff --git a/src/theory/datatypes/inference_manager.h b/src/theory/datatypes/inference_manager.h index 786cd8129..0dda3259e 100644 --- a/src/theory/datatypes/inference_manager.h +++ b/src/theory/datatypes/inference_manager.h @@ -26,29 +26,14 @@ namespace theory { namespace datatypes { /** - * The datatypes inference manager. The main unique features of this inference - * manager are: - * (1) Explicit caching of lemmas, - * (2) A custom process() method with relies on a policy determining which - * facts must be sent as lemmas (mustCommunicateFact). - * (3) Methods for tracking when lemmas and facts have been processed. + * A custom inference class. The main feature of this class is that it + * dynamically decides whether to process itself as a fact or as a lemma, + * based on the mustCommunicateFact method below. */ -class InferenceManager : public InferenceManagerBuffered +class DatatypesInference : public SimpleTheoryInternalFact { - typedef context::CDHashSet NodeSet; - public: - InferenceManager(Theory& t, TheoryState& state, ProofNodeManager* pnm); - ~InferenceManager() {} - /** - * Process the current lemmas and facts. This is a custom method that can - * be seen as overriding the behavior of calling both doPendingLemmas and - * doPendingFacts. It determines whether facts should be sent as lemmas - * or processed internally. - */ - void process(); - - protected: + DatatypesInference(Node conc, Node exp, ProofGenerator* pg); /** * Must communicate fact method. * The datatypes decision procedure makes "internal" inferences : @@ -65,9 +50,37 @@ class InferenceManager : public InferenceManagerBuffered * communicate outwards if the conclusions involve other theories. Also * communicate (6) and OR conclusions. */ - bool mustCommunicateFact(Node n, Node exp) const; - /** Common node */ - Node d_true; + static bool mustCommunicateFact(Node n, Node exp); + /** + * Process this fact, possibly as a fact or as a lemma, depending on the + * above method. + */ + bool process(TheoryInferenceManager* im) override; +}; + +/** + * The datatypes inference manager, which uses the above class for + * inferences. + */ +class InferenceManager : public InferenceManagerBuffered +{ + typedef context::CDHashSet NodeSet; + + public: + InferenceManager(Theory& t, TheoryState& state, ProofNodeManager* pnm); + ~InferenceManager() {} + /** + * Add pending inference, which may be processed as either a fact or + * a lemma based on mustCommunicateFact in DatatypesInference above. + */ + void addPendingInference(Node conc, Node exp, ProofGenerator* pg = nullptr); + /** + * Process the current lemmas and facts. This is a custom method that can + * be seen as overriding the behavior of calling both doPendingLemmas and + * doPendingFacts. It determines whether facts should be sent as lemmas + * or processed internally. + */ + void process(); }; } // namespace datatypes diff --git a/src/theory/inference_manager_buffered.cpp b/src/theory/inference_manager_buffered.cpp index 14f6c4f4a..a1cb9c4e9 100644 --- a/src/theory/inference_manager_buffered.cpp +++ b/src/theory/inference_manager_buffered.cpp @@ -49,18 +49,30 @@ void InferenceManagerBuffered::addPendingLemma(Node lem, LemmaProperty p, ProofGenerator* pg) { - d_pendingLem.push_back(std::make_shared(lem, p, pg)); + // make the simple theory lemma + d_pendingLem.push_back(std::make_shared(lem, p, pg)); } -void InferenceManagerBuffered::addPendingLemma(std::shared_ptr lemma) +void InferenceManagerBuffered::addPendingLemma( + std::shared_ptr lemma) { d_pendingLem.emplace_back(std::move(lemma)); } -void InferenceManagerBuffered::addPendingFact(Node fact, Node exp) +void InferenceManagerBuffered::addPendingFact(Node conc, + Node exp, + ProofGenerator* pg) { - Assert(fact.getKind() != AND && fact.getKind() != OR); - d_pendingFact.push_back(std::pair(fact, exp)); + // make a simple theory internal fact + Assert(conc.getKind() != AND && conc.getKind() != OR); + d_pendingFact.push_back( + std::make_shared(conc, exp, pg)); +} + +void InferenceManagerBuffered::addPendingFact( + std::shared_ptr fact) +{ + d_pendingFact.emplace_back(std::move(fact)); } void InferenceManagerBuffered::addPendingPhaseRequirement(Node lit, bool pol) @@ -75,14 +87,9 @@ void InferenceManagerBuffered::doPendingFacts() size_t i = 0; while (!d_theoryState.isInConflict() && i < d_pendingFact.size()) { - std::pair& pfact = d_pendingFact[i]; - Node fact = pfact.first; - Node exp = pfact.second; - bool polarity = fact.getKind() != NOT; - TNode atom = polarity ? fact : fact[0]; - // no double negation or conjunctive conclusions - Assert(atom.getKind() != NOT && atom.getKind() != AND); - assertInternalFact(atom, polarity, exp); + // process this fact, which notice may enqueue more pending facts in this + // loop. + d_pendingFact[i]->process(this); i++; } d_pendingFact.clear(); @@ -90,20 +97,10 @@ void InferenceManagerBuffered::doPendingFacts() void InferenceManagerBuffered::doPendingLemmas() { - // process all the pending lemmas - for (const std::shared_ptr& plem : d_pendingLem) + for (const std::shared_ptr& plem : d_pendingLem) { - if (!plem->notifySend()) - { - // the lemma indicated that it should not be sent after all - continue; - } - Node lem = plem->d_node; - LemmaProperty p = plem->d_property; - ProofGenerator* pg = plem->d_pg; - Assert(!lem.isNull()); - // send (trusted) lemma on the output channel with property p - trustedLemma(TrustNode::mkTrustLemma(lem, pg), p); + // process this lemma + plem->process(this); } d_pendingLem.clear(); } diff --git a/src/theory/inference_manager_buffered.h b/src/theory/inference_manager_buffered.h index 596a346de..e6e7822c5 100644 --- a/src/theory/inference_manager_buffered.h +++ b/src/theory/inference_manager_buffered.h @@ -19,44 +19,12 @@ #include "context/cdhashmap.h" #include "expr/node.h" +#include "theory/theory_inference.h" #include "theory/theory_inference_manager.h" namespace CVC4 { namespace theory { -/** - * A lemma base class. This class is an abstract data structure for storing - * pending lemmas in the inference manager below. - */ -class Lemma -{ - public: - Lemma(Node n, LemmaProperty p, ProofGenerator* pg) - : d_node(n), d_property(p), d_pg(pg) - { - } - virtual ~Lemma() {} - /** - * Called just before this lemma is sent on the output channel. The purpose - * of this callback is to do any specific process of the lemma, e.g. take - * debug statistics, cache, etc. - * - * @return true if the lemma should be sent on the output channel. - */ - virtual bool notifySend() { return true; } - /** The lemma to send */ - Node d_node; - /** The lemma property (see OutputChannel::lemma) */ - LemmaProperty d_property; - /** - * The proof generator for this lemma, which if non-null, is wrapped in a - * TrustNode to be set on the output channel via trustedLemma at the time - * the lemma is sent. This proof generator must be able to provide a proof - * for d_node in the remainder of the user context. - */ - ProofGenerator* d_pg; -}; - /** * The buffered inference manager. This class implements standard methods * for buffering facts, lemmas and phase requirements. @@ -92,21 +60,25 @@ class InferenceManagerBuffered : public TheoryInferenceManager ProofGenerator* pg = nullptr); /** * Add pending lemma, where lemma can be a (derived) class of the - * above one. Pending lemmas are sent to the output channel using - * doPendingLemmas. + * theory inference base class. */ - void addPendingLemma(std::shared_ptr lemma); + void addPendingLemma(std::shared_ptr lemma); /** * Add pending fact, which adds a fact on the pending fact queue. It must * be the case that: - * (1) exp => fact is valid, + * (1) exp => conc is valid, * (2) exp is a literal (or conjunction of literals) that holds in the * equality engine of the theory. * * Pending facts are sent to the equality engine of this class using * doPendingFacts. */ - void addPendingFact(Node fact, Node exp); + void addPendingFact(Node conc, Node exp, ProofGenerator* pg = nullptr); + /** + * Add pending fact, where fact can be a (derived) class of the + * theory inference base class. + */ + void addPendingFact(std::shared_ptr fact); /** Add pending phase requirement * * This method is called to indicate this class should send a phase @@ -153,10 +125,10 @@ class InferenceManagerBuffered : public TheoryInferenceManager void clearPendingPhaseRequirements(); protected: - /** A set of pending lemmas */ - std::vector> d_pendingLem; - /** A set of pending facts, paired with their explanations */ - std::vector> d_pendingFact; + /** A set of pending inferences to be processed as lemmas */ + std::vector> d_pendingLem; + /** A set of pending inferences to be processed as facts */ + std::vector> d_pendingFact; /** A map from literals to their pending phase requirement */ std::map d_pendingReqPhase; }; diff --git a/src/theory/theory_inference.cpp b/src/theory/theory_inference.cpp new file mode 100644 index 000000000..618dc640b --- /dev/null +++ b/src/theory/theory_inference.cpp @@ -0,0 +1,63 @@ +/********************* */ +/*! \file theory_inference.cpp + ** \verbatim + ** Top contributors (to current version): + ** 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 The theory inference utility + **/ + +#include "theory/theory_inference.h" + +#include "theory/theory_inference_manager.h" + +using namespace CVC4::kind; + +namespace CVC4 { +namespace theory { + +SimpleTheoryLemma::SimpleTheoryLemma(Node n, + LemmaProperty p, + ProofGenerator* pg) + : d_node(n), d_property(p), d_pg(pg) +{ +} + +bool SimpleTheoryLemma::process(TheoryInferenceManager* im) +{ + Assert(!d_node.isNull()); + // send (trusted) lemma on the output channel with property p + return im->trustedLemma(TrustNode::mkTrustLemma(d_node, d_pg), d_property); +} + +SimpleTheoryInternalFact::SimpleTheoryInternalFact(Node conc, + Node exp, + ProofGenerator* pg) + : d_conc(conc), d_exp(exp), d_pg(pg) +{ +} + +bool SimpleTheoryInternalFact::process(TheoryInferenceManager* im) +{ + bool polarity = d_conc.getKind() != NOT; + TNode atom = polarity ? d_conc : d_conc[0]; + // no double negation or conjunctive conclusions + Assert(atom.getKind() != NOT && atom.getKind() != AND); + if (d_pg != nullptr) + { + im->assertInternalFact(atom, polarity, {d_exp}, d_pg); + } + else + { + im->assertInternalFact(atom, polarity, d_exp); + } + return true; +} + +} // namespace theory +} // namespace CVC4 diff --git a/src/theory/theory_inference.h b/src/theory/theory_inference.h new file mode 100644 index 000000000..8d98051bf --- /dev/null +++ b/src/theory/theory_inference.h @@ -0,0 +1,106 @@ +/********************* */ +/*! \file theory_inference.h + ** \verbatim + ** Top contributors (to current version): + ** 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 The theory inference utility + **/ + +#include "cvc4_private.h" + +#ifndef CVC4__THEORY__THEORY_INFERENCE_H +#define CVC4__THEORY__THEORY_INFERENCE_H + +#include "expr/node.h" +#include "theory/output_channel.h" + +namespace CVC4 { +namespace theory { + +class TheoryInferenceManager; + +/** + * A theory inference base class. This class is an abstract data structure for + * storing pending lemmas or facts in the buffered inference manager. It can + * be seen a single use object capturing instructions for making a single + * call to TheoryInferenceManager for lemmas or facts. + */ +class TheoryInference +{ + public: + virtual ~TheoryInference() {} + /** + * Called by the provided inference manager to process this inference. This + * method should make call(s) to inference manager to process this + * inference, as well as processing any specific side effects. This method + * typically makes a single call to the provided inference manager e.g. + * d_im->trustedLemma or d_im->assertFactInternal. Notice it is the sole + * responsibility of this class to make this call; the inference manager + * does not call itself otherwise when processing pending inferences. + * + * @return true if the inference was successfully processed by the inference + * manager. This method for instance returns false if it corresponds to a + * lemma that was already cached by im and hence was discarded. + */ + virtual bool process(TheoryInferenceManager* im) = 0; +}; + +/** + * A simple theory lemma with no side effects. Makes a single call to + * trustedLemma in its process method. + */ +class SimpleTheoryLemma : public TheoryInference +{ + public: + SimpleTheoryLemma(Node n, LemmaProperty p, ProofGenerator* pg); + virtual ~SimpleTheoryLemma() {} + /** + * Send the lemma using inference manager im, return true if the lemma was + * sent. + */ + virtual bool process(TheoryInferenceManager* im) override; + /** The lemma to send */ + Node d_node; + /** The lemma property (see OutputChannel::lemma) */ + LemmaProperty d_property; + /** + * The proof generator for this lemma, which if non-null, is wrapped in a + * TrustNode to be set on the output channel via trustedLemma at the time + * the lemma is sent. This proof generator must be able to provide a proof + * for d_node in the remainder of the user context. + */ + ProofGenerator* d_pg; +}; + +/** + * A simple internal fact with no side effects. Makes a single call to + * assertFactInternal in its process method. + */ +class SimpleTheoryInternalFact : public TheoryInference +{ + public: + SimpleTheoryInternalFact(Node conc, Node exp, ProofGenerator* pg); + virtual ~SimpleTheoryInternalFact() {} + /** + * Send the lemma using inference manager im, return true if the lemma was + * sent. + */ + virtual bool process(TheoryInferenceManager* im) override; + /** The lemma to send */ + Node d_conc; + /** The explanation */ + Node d_exp; + /** The proof generator */ + ProofGenerator* d_pg; +}; + +} // namespace theory +} // namespace CVC4 + +#endif diff --git a/src/theory/theory_inference_manager.cpp b/src/theory/theory_inference_manager.cpp index 20c1fbf37..3abe530f1 100644 --- a/src/theory/theory_inference_manager.cpp +++ b/src/theory/theory_inference_manager.cpp @@ -84,6 +84,27 @@ void TheoryInferenceManager::trustedConflict(TrustNode tconf) } } +void TheoryInferenceManager::conflictExp(PfRule id, + const std::vector& exp, + const std::vector& args) +{ + if (!d_theoryState.isInConflict()) + { + if (d_pfee != nullptr) + { + // use proof equality engine to construct the trust node + TrustNode tconf = d_pfee->assertConflict(id, exp, args); + d_out.trustedConflict(tconf); + } + else + { + // version without proofs + Node conf = mkExplainPartial(exp, {}); + conflict(conf); + } + } +} + bool TheoryInferenceManager::propagateLit(TNode lit) { // If already in conflict, no more propagation @@ -123,7 +144,7 @@ TrustNode TheoryInferenceManager::explainConflictEqConstantMerge(TNode a, Node lit = a.eqNode(b); if (d_pfee != nullptr) { - return d_pfee->explain(lit); + return d_pfee->assertConflict(lit); } if (d_ee != nullptr) { @@ -156,6 +177,45 @@ bool TheoryInferenceManager::trustedLemma(const TrustNode& tlem, return true; } +bool TheoryInferenceManager::lemmaExp(Node conc, + PfRule id, + const std::vector& exp, + const std::vector& noExplain, + const std::vector& args, + LemmaProperty p, + bool doCache) +{ + if (d_pfee != nullptr) + { + // make the trust node from the proof equality engine + TrustNode trn = d_pfee->assertLemma(conc, id, exp, noExplain, args); + return trustedLemma(trn, p, doCache); + } + // otherwise, not using proofs, explain and send lemma + Node ant = mkExplainPartial(exp, noExplain); + Node lem = NodeManager::currentNM()->mkNode(kind::IMPLIES, ant, conc); + return lemma(lem, p, doCache); +} + +bool TheoryInferenceManager::lemmaExp(Node conc, + const std::vector& exp, + const std::vector& noExplain, + ProofGenerator* pg, + LemmaProperty p, + bool doCache) +{ + if (d_pfee != nullptr) + { + // make the trust node from the proof equality engine + TrustNode trn = d_pfee->assertLemma(conc, exp, noExplain, pg); + return trustedLemma(trn, p, doCache); + } + // otherwise, not using proofs, explain and send lemma + Node ant = mkExplainPartial(exp, noExplain); + Node lem = NodeManager::currentNM()->mkNode(kind::IMPLIES, ant, conc); + return lemma(lem, p, doCache); +} + bool TheoryInferenceManager::hasCachedLemma(TNode lem, LemmaProperty p) { return d_lemmasSent.find(lem) != d_lemmasSent.end(); @@ -280,6 +340,27 @@ Node TheoryInferenceManager::mkExplain(TNode n) return NodeManager::currentNM()->mkAnd(assumptions); } +Node TheoryInferenceManager::mkExplainPartial( + const std::vector& exp, const std::vector& noExplain) +{ + std::vector assumps; + for (const Node& e : exp) + { + if (std::find(noExplain.begin(), noExplain.end(), e) != noExplain.end()) + { + if (std::find(assumps.begin(), assumps.end(), e) == assumps.end()) + { + // a non-explained literal + assumps.push_back(e); + } + continue; + } + // otherwise, explain it + explain(e, assumps); + } + return NodeManager::currentNM()->mkAnd(assumps); +} + uint32_t TheoryInferenceManager::numAddedFacts() const { return d_numCurrentFacts; diff --git a/src/theory/theory_inference_manager.h b/src/theory/theory_inference_manager.h index d5c0fe1b2..2ddcd0985 100644 --- a/src/theory/theory_inference_manager.h +++ b/src/theory/theory_inference_manager.h @@ -125,6 +125,16 @@ class TheoryInferenceManager * been provided in a custom way. */ void trustedConflict(TrustNode tconf); + /** + * Explain and send conflict from contradictory facts. This method is called + * when the proof rule id with premises exp and arguments args concludes + * false. This method sends a trusted conflict corresponding to the official + * equality engine's explanation of literals in exp, with the proof equality + * engine as the proof generator (if it exists). + */ + void conflictExp(PfRule id, + const std::vector& exp, + const std::vector& args); //--------------------------------------- lemmas /** * Send (trusted) lemma lem with property p on the output channel. @@ -145,6 +155,56 @@ class TheoryInferenceManager bool lemma(TNode lem, LemmaProperty p = LemmaProperty::NONE, bool doCache = true); + /** + * Explained lemma. This should be called when + * ( exp => conc ) + * is a valid theory lemma. This method adds a lemma where part of exp + * is replaced by its explanation according to the official equality engine + * of the theory. + * + * In particular, this method adds a lemma on the output channel of the form + * ( ^_{e in exp \ noExplain} EXPLAIN(e) ^ noExplain ) => conc + * where EXPLAIN(e) returns the explanation of literal e according to the + * official equality engine of the theory. Note that noExplain is the *subset* + * of exp that should not be explained. + * + * @param conc The conclusion of the lemma + * @param id The proof rule concluding conc + * @param exp The set of (all) literals that imply conc + * @param noExplain The subset of exp that should not be explained by the + * equality engine + * @param args The arguments to the proof step concluding conc + * @param p The property of the lemma + * @param doCache Whether to check and add the lemma to the cache + * @return true if the lemma was sent on the output channel. + */ + bool lemmaExp(Node conc, + PfRule id, + const std::vector& exp, + const std::vector& noExplain, + const std::vector& args, + LemmaProperty p = LemmaProperty::NONE, + bool doCache = true); + /** + * Same as above, but where pg can provide a proof of conc from free + * assumptions in exp. It is required to do so in the remainder of the user + * context when this method returns true. + * + * @param conc The conclusion of the lemma + * @param exp The set of (all) literals that imply conc + * @param noExplain The subset of exp that should not be explained by the + * equality engine + * @param pg If non-null, the proof generator who can provide a proof of conc. + * @param p The property of the lemma + * @param doCache Whether to check and add the lemma to the cache + * @return true if the lemma was sent on the output channel. + */ + bool lemmaExp(Node conc, + const std::vector& exp, + const std::vector& noExplain, + ProofGenerator* pg = nullptr, + LemmaProperty p = LemmaProperty::NONE, + bool doCache = true); /** * Has this inference manager cached and sent the given lemma (in this user * context)? This method can be overridden by the particular manager. If not, @@ -194,8 +254,8 @@ class TheoryInferenceManager * @param atom The atom of the fact to assert * @param pol Its polarity * @param exp Its explanation, interpreted as a conjunction - * @param pg The proof generator for this step. It must be the case that pf - * can provide a proof concluding (~) atom from free asumptions in exp in + * @param pg The proof generator for this step. If non-null, pg must be able + * to provide a proof concluding (~) atom from free asumptions in exp in * the remainder of the current SAT context. */ void assertInternalFact(TNode atom, @@ -235,6 +295,14 @@ class TheoryInferenceManager * conjunctions), return the explanation as a conjunction. */ Node mkExplain(TNode n); + /** + * Explain the set of formulas in exp using the official equality engine of + * the theory. We ask the equality engine to explain literals in exp + * that do not occur in noExplain, and return unchanged those that occur in + * noExplain. Note the vector noExplain should be a subset of exp. + */ + Node mkExplainPartial(const std::vector& exp, + const std::vector& noExplain); /** * Cache that lemma lem is being sent with property p. Return true if it * did not already exist in the cache maintained by this class. If this -- cgit v1.2.3 From 62ec0666dd4d409ee85603ae94d7ab1a2b4c9dcc Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Tue, 1 Sep 2020 16:22:54 -0500 Subject: (new theory) Update TheoryDatatypes to the new standard (#4986) Updates it to use the new inference manager as well as updating its check to the standard callbacks. --- src/theory/datatypes/inference_manager.cpp | 13 ++ src/theory/datatypes/inference_manager.h | 5 + src/theory/datatypes/theory_datatypes.cpp | 364 ++++++++--------------------- src/theory/datatypes/theory_datatypes.h | 55 ++--- 4 files changed, 133 insertions(+), 304 deletions(-) diff --git a/src/theory/datatypes/inference_manager.cpp b/src/theory/datatypes/inference_manager.cpp index 3dc16355b..762cdfd8b 100644 --- a/src/theory/datatypes/inference_manager.cpp +++ b/src/theory/datatypes/inference_manager.cpp @@ -108,6 +108,19 @@ void InferenceManager::process() doPendingFacts(); } +bool InferenceManager::sendLemmas(const std::vector& lemmas) +{ + bool ret = false; + for (const Node& lem : lemmas) + { + if (lemma(lem)) + { + ret = true; + } + } + return ret; +} + } // namespace datatypes } // namespace theory } // namespace CVC4 diff --git a/src/theory/datatypes/inference_manager.h b/src/theory/datatypes/inference_manager.h index 0dda3259e..0dfdfb281 100644 --- a/src/theory/datatypes/inference_manager.h +++ b/src/theory/datatypes/inference_manager.h @@ -81,6 +81,11 @@ class InferenceManager : public InferenceManagerBuffered * or processed internally. */ void process(); + /** + * Send lemmas with property NONE on the output channel immediately. + * Returns true if any lemma was sent. + */ + bool sendLemmas(const std::vector& lemmas); }; } // namespace datatypes diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp index 4c8fa87ba..78b6d81c2 100644 --- a/src/theory/datatypes/theory_datatypes.cpp +++ b/src/theory/datatypes/theory_datatypes.cpp @@ -47,22 +47,18 @@ TheoryDatatypes::TheoryDatatypes(Context* c, const LogicInfo& logicInfo, ProofNodeManager* pnm) : Theory(THEORY_DATATYPES, c, u, out, valuation, logicInfo, pnm), - d_infer(c), - d_infer_exp(c), d_term_sk(u), d_notify(*this), d_labels(c), d_selector_apps(c), - d_conflict(c, false), - d_addedLemma(false), - d_addedFact(false), d_collectTermsCache(c), d_collectTermsCacheU(u), d_functionTerms(c), d_singleton_eq(u), d_lemmas_produced_c(u), d_sygusExtension(nullptr), - d_state(c, u, valuation) + d_state(c, u, valuation), + d_im(*this, d_state, pnm) { d_true = NodeManager::currentNM()->mkConst( true ); @@ -71,6 +67,7 @@ TheoryDatatypes::TheoryDatatypes(Context* c, // indicate we are using the default theory state object d_theoryState = &d_state; + d_inferManager = &d_im; } TheoryDatatypes::~TheoryDatatypes() { @@ -156,64 +153,43 @@ TNode TheoryDatatypes::getEqcConstructor( TNode r ) { } } -void TheoryDatatypes::check(Effort e) { - if (done() && e lemmas; + std::vector lemmas; d_sygusExtension->check(lemmas); - doSendLemmas( lemmas ); + d_im.sendLemmas(lemmas); return; } - - TimerStat::CodeTimer checkTimer(d_checkTime); - - Trace("datatypes-check") << "Check effort " << e << std::endl; - while(!done() && !d_conflict) { - // Get all the assertions - Assertion assertion = get(); - TNode fact = assertion.d_assertion; - Trace("datatypes-assert") << "Assert " << fact << std::endl; - - TNode atom CVC4_UNUSED = fact.getKind() == kind::NOT ? fact[0] : fact; - - // extra debug check to make sure that the rewriter did its job correctly - Assert(atom.getKind() != kind::EQUAL - || (atom[0].getKind() != kind::TUPLE_UPDATE - && atom[1].getKind() != kind::TUPLE_UPDATE - && atom[0].getKind() != kind::RECORD_UPDATE - && atom[1].getKind() != kind::RECORD_UPDATE)) - << "tuple/record escaped into datatypes decision procedure; should " - "have been rewritten away"; - - //assert the fact - assertFact( fact, fact ); - flushPendingFacts(); - } - - if( e == EFFORT_FULL && !d_conflict && !d_addedLemma && !d_valuation.needCheck() ) { + else if (level == EFFORT_FULL && !d_state.isInConflict() + && !d_im.hasAddedLemma() && !d_valuation.needCheck()) + { //check for cycles - Assert(d_pending.empty()); + Assert(!d_im.hasPendingFact()); do { - d_addedFact = false; + d_im.reset(); Trace("datatypes-proc") << "Check cycles..." << std::endl; checkCycles(); Trace("datatypes-proc") << "...finish check cycles" << std::endl; - flushPendingFacts(); - if( d_conflict || d_addedLemma ){ + d_im.process(); + if (d_state.isInConflict() || d_im.hasAddedLemma()) + { return; } - }while( d_addedFact ); - + } while (d_im.hasAddedFact()); + //check for splits - Trace("datatypes-debug") << "Check for splits " << e << endl; + Trace("datatypes-debug") << "Check for splits " << endl; do { - d_addedFact = false; + d_im.reset(); std::map< TypeNode, Node > rec_singletons; eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine); while( !eqcs_i.isFinished() ){ @@ -265,7 +241,7 @@ void TheoryDatatypes::check(Effort e) { assumptions.push_back(assumption); Node lemma = assumptions.size()==1 ? assumptions[0] : NodeManager::currentNM()->mkNode( OR, assumptions ); Trace("dt-singleton") << "*************Singleton equality lemma " << lemma << std::endl; - doSendLemma( lemma ); + d_im.lemma(lemma); } } }else{ @@ -279,8 +255,6 @@ void TheoryDatatypes::check(Effort e) { //all other cases std::vector< bool > pcons; getPossibleCons( eqc, n, pcons ); - //std::map< int, bool > sel_apps; - //getSelectorsForCons( n, sel_apps ); //check if we do not need to resolve the constructor type for this equivalence class. // this is if there are no selectors for this equivalence class, and its possible values are infinite, // then do not split. @@ -322,10 +296,8 @@ void TheoryDatatypes::check(Effort e) { //this may not be necessary? //if only one constructor, then this term must be this constructor Node t = utils::mkTester(n, 0, dt); - d_pending.push_back( t ); - d_pending_exp[ t ] = d_true; + d_im.addPendingInference(t, d_true); Trace("datatypes-infer") << "DtInfer : 1-cons (full) : " << t << std::endl; - d_infer.push_back( t ); }else{ Assert(consIndex != -1 || dt.isSygus()); if( options::dtBinarySplit() && consIndex!=-1 ){ @@ -335,14 +307,13 @@ void TheoryDatatypes::check(Effort e) { NodeBuilder<> nb(kind::OR); nb << test << test.notNode(); Node lemma = nb; - doSendLemma( lemma ); + d_im.lemma(lemma); d_out->requirePhase( test, true ); }else{ Trace("dt-split") << "*************Split for constructors on " << n << endl; Node lemma = utils::mkSplit(n, dt); Trace("dt-split-debug") << "Split lemma is : " << lemma << std::endl; - d_out->lemma(lemma, LemmaProperty::SEND_ATOMS); - d_addedLemma = true; + d_im.lemma(lemma, LemmaProperty::SEND_ATOMS, false); } if( !options::dtBlastSplits() ){ break; @@ -358,29 +329,32 @@ void TheoryDatatypes::check(Effort e) { } ++eqcs_i; } - if (d_addedLemma) + if (d_im.hasAddedLemma()) { // clear pending facts: we added a lemma, so internal inferences are // no longer necessary - d_pending.clear(); - d_pending_exp.clear(); + d_im.clearPendingFacts(); } else { // we did not add a lemma, process internal inferences. This loop // will repeat. Trace("datatypes-debug") << "Flush pending facts..." << std::endl; - flushPendingFacts(); + d_im.process(); } - }while( !d_conflict && !d_addedLemma && d_addedFact ); - Trace("datatypes-debug") << "Finished, conflict=" << d_conflict << ", lemmas=" << d_addedLemma << std::endl; - if( !d_conflict ){ + } while (!d_state.isInConflict() && !d_im.hasAddedLemma() + && d_im.hasAddedFact()); + Trace("datatypes-debug") + << "Finished, conflict=" << d_state.isInConflict() + << ", lemmas=" << d_im.hasAddedLemma() << std::endl; + if (!d_state.isInConflict()) + { Trace("dt-model-debug") << std::endl; printModelDebug("dt-model-debug"); } } - Trace("datatypes-check") << "Finished check effort " << e << std::endl; + Trace("datatypes-check") << "Finished check effort " << level << std::endl; if( Debug.isOn("datatypes") || Debug.isOn("datatypes-split") ) { Notice() << "TheoryDatatypes::check(): done" << endl; } @@ -390,100 +364,17 @@ bool TheoryDatatypes::needsCheckLastEffort() { return d_sygusExtension != nullptr; } -void TheoryDatatypes::flushPendingFacts(){ - //pending lemmas: used infrequently, only for definitional lemmas - if( !d_pending_lem.empty() ){ - int i = 0; - while( i<(int)d_pending_lem.size() ){ - doSendLemma( d_pending_lem[i] ); - i++; - } - d_pending_lem.clear(); - } - int i = 0; - while( !d_conflict && i<(int)d_pending.size() ){ - Node fact = d_pending[i]; - Node exp = d_pending_exp[ fact ]; - Trace("datatypes-debug") << "Assert fact (#" << (i+1) << "/" << d_pending.size() << ") " << fact << " with explanation " << exp << std::endl; - //check to see if we have to communicate it to the rest of the system - if( mustCommunicateFact( fact, exp ) ){ - Node lem = fact; - if( exp.isNull() || exp==d_true ){ - Trace("dt-lemma-debug") << "Trivial explanation." << std::endl; - }else{ - Trace("dt-lemma-debug") << "Get explanation..." << std::endl; - std::vector< TNode > assumptions; - //if( options::dtRExplainLemmas() ){ - explain( exp, assumptions ); - //}else{ - // ee_exp = exp; - //} - //Trace("dt-lemma-debug") << "Explanation : " << ee_exp << std::endl; - if( assumptions.empty() ){ - lem = fact; - }else{ - std::vector< Node > children; - for (const TNode& assumption : assumptions) - { - children.push_back(assumption.negate()); - } - children.push_back( fact ); - lem = NodeManager::currentNM()->mkNode( OR, children ); - } - } - Trace("dt-lemma") << "Datatypes lemma : " << lem << std::endl; - doSendLemma( lem ); - }else{ - assertFact( fact, exp ); - d_addedFact = true; - } - Trace("datatypes-debug") << "Finished fact " << fact << ", now = " << d_conflict << " " << d_pending.size() << std::endl; - i++; - } - d_pending.clear(); - d_pending_exp.clear(); -} - -bool TheoryDatatypes::doSendLemma( Node lem ) { - if( d_lemmas_produced_c.find( lem )==d_lemmas_produced_c.end() ){ - Trace("dt-lemma-send") << "TheoryDatatypes::doSendLemma : " << lem << std::endl; - d_lemmas_produced_c[lem] = true; - d_out->lemma( lem ); - d_addedLemma = true; - return true; - }else{ - Trace("dt-lemma-send") << "TheoryDatatypes::doSendLemma : duplicate : " - << lem << std::endl; - return false; - } -} -bool TheoryDatatypes::doSendLemmas( std::vector< Node >& lemmas ){ - bool ret = false; - for (const Node& lem : lemmas) - { - bool cret = doSendLemma(lem); - ret = ret || cret; - } - lemmas.clear(); - return ret; -} - -void TheoryDatatypes::assertFact( Node fact, Node exp) +void TheoryDatatypes::notifyFact(TNode atom, + bool polarity, + TNode fact, + bool isInternal) { - Trace("datatypes-debug") << "TheoryDatatypes::assertFact : " << fact << std::endl; - bool polarity = fact.getKind() != kind::NOT; - TNode atom = polarity ? fact : fact[0]; - if (atom.getKind() == kind::EQUAL) { - d_equalityEngine->assertEquality(atom, polarity, exp); - }else{ - d_equalityEngine->assertPredicate(atom, polarity, exp); - } // could be sygus-specific if (d_sygusExtension) { std::vector< Node > lemmas; d_sygusExtension->assertFact(atom, polarity, lemmas); - doSendLemmas( lemmas ); + d_im.sendLemmas(lemmas); } //add to tester if applicable Node t_arg; @@ -493,28 +384,37 @@ void TheoryDatatypes::assertFact( Node fact, Node exp) Trace("dt-tester") << "Assert tester : " << atom << " for " << t_arg << std::endl; Node rep = getRepresentative( t_arg ); EqcInfo* eqc = getOrMakeEqcInfo( rep, true ); - addTester( tindex, fact, eqc, rep, t_arg ); + Node tst = + isInternal ? (polarity ? Node(atom) : atom.notNode()) : Node(fact); + addTester(tindex, tst, eqc, rep, t_arg); Trace("dt-tester") << "Done assert tester." << std::endl; Trace("dt-tester") << "Done pending merges." << std::endl; - if( !d_conflict && polarity ){ + if (!d_state.isInConflict() && polarity) + { if (d_sygusExtension) { Trace("dt-tester") << "Assert tester to sygus : " << atom << std::endl; - //Assert( !d_sygus_util->d_conflict ); std::vector< Node > lemmas; d_sygusExtension->assertTester(tindex, t_arg, atom, lemmas); Trace("dt-tester") << "Done assert tester to sygus." << std::endl; - doSendLemmas( lemmas ); + d_im.sendLemmas(lemmas); } } }else{ Trace("dt-tester-debug") << "Assert (non-tester) : " << atom << std::endl; } Trace("datatypes-debug") << "TheoryDatatypes::assertFact : finished " << fact << std::endl; + // now, flush pending facts if this wasn't an internal call + if (!isInternal) + { + d_im.process(); + } } -void TheoryDatatypes::preRegisterTerm(TNode n) { - Debug("datatypes-prereg") << "TheoryDatatypes::preRegisterTerm() " << n << endl; +void TheoryDatatypes::preRegisterTerm(TNode n) +{ + Debug("datatypes-prereg") + << "TheoryDatatypes::preRegisterTerm() " << n << endl; collectTerms( n ); switch (n.getKind()) { case kind::EQUAL: @@ -530,12 +430,11 @@ void TheoryDatatypes::preRegisterTerm(TNode n) { { std::vector< Node > lemmas; d_sygusExtension->preRegisterTerm(n, lemmas); - doSendLemmas( lemmas ); + d_im.sendLemmas(lemmas); } - // d_equalityEngine->addTriggerTerm(n, THEORY_DATATYPES); break; } - flushPendingFacts(); + d_im.process(); } TrustNode TheoryDatatypes::expandDefinition(Node n) @@ -699,21 +598,13 @@ TrustNode TheoryDatatypes::ppRewrite(TNode in) return TrustNode::null(); } -void TheoryDatatypes::notifySharedTerm(TNode t) -{ - Debug("datatypes") << "TheoryDatatypes::notifySharedTerm(): " << t << " " - << t.getType().isBoolean() << endl; - d_equalityEngine->addTriggerTerm(t, THEORY_DATATYPES); - Debug("datatypes") << "TheoryDatatypes::notifySharedTerm() finished" - << std::endl; -} - bool TheoryDatatypes::propagateLit(TNode literal) { Debug("dt::propagate") << "TheoryDatatypes::propagateLit(" << literal << ")" << std::endl; // If already in conflict, no more propagation - if (d_conflict) { + if (d_state.isInConflict()) + { Debug("dt::propagate") << "TheoryDatatypes::propagateLit(" << literal << "): already in conflict" << std::endl; return false; @@ -723,7 +614,7 @@ bool TheoryDatatypes::propagateLit(TNode literal) bool ok = d_out->propagate(literal); if (!ok) { Trace("dt-conflict") << "CONFLICT: Eq engine propagate conflict " << std::endl; - d_conflict = true; + d_state.notifyInConflict(); } return ok; } @@ -805,7 +696,7 @@ void TheoryDatatypes::conflict(TNode a, TNode b){ d_conflictNode = explainLit(eq); Trace("dt-conflict") << "CONFLICT: Eq engine conflict : " << d_conflictNode << std::endl; d_out->conflict( d_conflictNode ); - d_conflict = true; + d_state.notifyInConflict(); } /** called when a new equivalance class is created */ @@ -826,7 +717,8 @@ void TheoryDatatypes::eqNotifyMerge(TNode t1, TNode t2) } void TheoryDatatypes::merge( Node t1, Node t2 ){ - if( !d_conflict ){ + if (!d_state.isInConflict()) + { TNode trep1 = t1; TNode trep2 = t2; Trace("datatypes-debug") << "Merge " << t1 << " " << t2 << std::endl; @@ -855,7 +747,7 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){ d_conflictNode = explainLit(unifEq); Trace("dt-conflict") << "CONFLICT: Clash conflict : " << d_conflictNode << std::endl; d_out->conflict( d_conflictNode ); - d_conflict = true; + d_state.notifyInConflict(); return; } else @@ -864,22 +756,10 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){ for( int i=0; i<(int)cons1.getNumChildren(); i++ ) { if( !areEqual( cons1[i], cons2[i] ) ){ Node eq = cons1[i].eqNode( cons2[i] ); - d_pending.push_back( eq ); - d_pending_exp[ eq ] = unifEq; + d_im.addPendingInference(eq, unifEq); Trace("datatypes-infer") << "DtInfer : cons-inj : " << eq << " by " << unifEq << std::endl; - d_infer.push_back( eq ); - d_infer_exp.push_back( unifEq ); } } -/* - for( unsigned i=0; id_inst << " " << eqc2->d_inst << std::endl; @@ -889,7 +769,8 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){ Trace("datatypes-debug") << " must check if it is okay to set the constructor." << std::endl; checkInst = true; addConstructor( eqc2->d_constructor.get(), eqc1, t1 ); - if( d_conflict ){ + if (d_state.isInConflict()) + { return; } } @@ -916,7 +797,8 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){ Node t_arg = d_labels_args[t2][i]; unsigned tindex = d_labels_tindex[t2][i]; addTester( tindex, t, eqc1, t1, t_arg ); - if( d_conflict ){ + if (d_state.isInConflict()) + { Trace("datatypes-debug") << " conflict!" << std::endl; return; } @@ -940,7 +822,8 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){ if( checkInst ){ Trace("datatypes-debug") << " checking instantiate" << std::endl; instantiate( eqc1, t1 ); - if( d_conflict ){ + if (d_state.isInConflict()) + { return; } } @@ -979,6 +862,8 @@ int TheoryDatatypes::getLabelIndex( EqcInfo* eqc, Node n ){ return -1; }else{ int tindex = utils::isTester(lbl); + Trace("datatypes-debug") << "Label of " << n << " is " << lbl + << " with tindex " << tindex << std::endl; Assert(tindex != -1); return tindex; } @@ -1033,9 +918,7 @@ Node TheoryDatatypes::getTermSkolemFor( Node n ) { d_term_sk[n] = k; Node eq = k.eqNode( n ); Trace("datatypes-infer") << "DtInfer : ref : " << eq << std::endl; - d_pending_lem.push_back( eq ); - //doSendLemma( eq ); - //d_pending_exp[ eq ] = d_true; + d_im.addPendingLemma(eq); return k; }else{ return (*it).second; @@ -1051,6 +934,7 @@ void TheoryDatatypes::addTester( Trace("datatypes-debug") << "Add tester : " << t << " to eqc(" << n << ")" << std::endl; Debug("datatypes-labels") << "Add tester " << t << " " << n << " " << eqc << std::endl; bool tpolarity = t.getKind()!=NOT; + Assert((tpolarity ? t : t[0]).getKind() == APPLY_TESTER); Node j, jt; bool makeConflict = false; int prevTIndex = getLabelIndex(eqc, n); @@ -1068,7 +952,7 @@ void TheoryDatatypes::addTester( d_conflictNode = mkAnd( assumptions ); Trace("dt-conflict") << "CONFLICT: Tester eq conflict : " << d_conflictNode << std::endl; d_out->conflict( d_conflictNode ); - d_conflict = true; + d_state.notifyInConflict(); return; }else{ makeConflict = true; @@ -1122,16 +1006,8 @@ void TheoryDatatypes::addTester( Debug("datatypes-labels") << "Labels at " << n_lbl << " / " << dt.getNumConstructors() << std::endl; if( tpolarity ){ instantiate( eqc, n ); - for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++) - { - if( i!=ttindex && neg_testers.find( i )==neg_testers.end() ){ - Assert(n.getKind() != APPLY_CONSTRUCTOR); - Node infer = utils::mkTester(n, i, dt).negate(); - Trace("datatypes-infer") << "DtInfer : neg label : " << infer << " by " << t << std::endl; - d_infer.push_back( infer ); - d_infer_exp.push_back( t ); - } - } + // We could propagate is-C1(x) => not is-C2(x) here for all other + // constructors, but empirically this hurts performance. }else{ //check if we have reached the maximum number of testers // in this case, add the positive tester @@ -1167,18 +1043,15 @@ void TheoryDatatypes::addTester( ? NodeManager::currentNM()->mkConst(false) : utils::mkTester(t_arg, testerIndex, dt); Node t_concl_exp = ( nb.getNumChildren() == 1 ) ? nb.getChild( 0 ) : nb; - d_pending.push_back( t_concl ); - d_pending_exp[ t_concl ] = t_concl_exp; + d_im.addPendingInference(t_concl, t_concl_exp); Trace("datatypes-infer") << "DtInfer : label : " << t_concl << " by " << t_concl_exp << std::endl; - d_infer.push_back( t_concl ); - d_infer_exp.push_back( t_concl_exp ); return; } } } } if( makeConflict ){ - d_conflict = true; + d_state.notifyInConflict(); Debug("datatypes-labels") << "Explain " << j << " " << t << std::endl; std::vector< TNode > assumptions; explain( j, assumptions ); @@ -1245,7 +1118,7 @@ void TheoryDatatypes::addConstructor( Node c, EqcInfo* eqc, Node n ){ d_conflictNode = mkAnd( assumptions ); Trace("dt-conflict") << "CONFLICT: Tester merge eq conflict : " << d_conflictNode << std::endl; d_out->conflict( d_conflictNode ); - d_conflict = true; + d_state.notifyInConflict(); return; } } @@ -1332,10 +1205,7 @@ void TheoryDatatypes::collapseSelector( Node s, Node c ) { Trace("datatypes-infer") << "DtInfer : collapse sel"; //Trace("datatypes-infer") << ( wrong ? " wrong" : ""); Trace("datatypes-infer") << " : " << eq << " by " << peq << std::endl; - d_pending.push_back( eq ); - d_pending_exp[eq] = peq; - d_infer.push_back( eq ); - d_infer_exp.push_back(peq); + d_im.addPendingInference(eq, peq); } } } @@ -1486,7 +1356,7 @@ void TheoryDatatypes::computeCareGraph(){ bool TheoryDatatypes::collectModelValues(TheoryModel* m, const std::set& termSet) { - Trace("dt-cmi") << "Datatypes : Collect model info " + Trace("dt-cmi") << "Datatypes : Collect model values " << d_equalityEngine->consistent() << std::endl; Trace("dt-model") << std::endl; printModelDebug( "dt-model" ); @@ -1639,7 +1509,7 @@ Node TheoryDatatypes::getSingletonLemma( TypeNode tn, bool pol ) { Node v2 = NodeManager::currentNM()->mkSkolem( "k2", tn ); a = v1.eqNode( v2 ).negate(); //send out immediately as lemma - doSendLemma( a ); + d_im.lemma(a); Trace("dt-singleton") << "******** assert " << a << " to avoid singleton cardinality for type " << tn << std::endl; } d_singleton_lemma[index][tn] = a; @@ -1697,7 +1567,7 @@ void TheoryDatatypes::collectTerms( Node n ) { Node lem = nm->mkNode(LEQ, d_zero, n); Trace("datatypes-infer") << "DtInfer : size geq zero : " << lem << std::endl; - d_pending_lem.push_back(lem); + d_im.addPendingLemma(lem); } else if (nk == DT_HEIGHT_BOUND && n[1].getConst().isZero()) { @@ -1722,7 +1592,7 @@ void TheoryDatatypes::collectTerms( Node n ) { : nm->mkNode(OR, children)); } Trace("datatypes-infer") << "DtInfer : zero height : " << lem << std::endl; - d_pending_lem.push_back(lem); + d_im.addPendingLemma(lem); } } @@ -1751,6 +1621,7 @@ Node TheoryDatatypes::getInstantiateCons(Node n, const DType& dt, int index) } void TheoryDatatypes::instantiate( EqcInfo* eqc, Node n ){ + Trace("datatypes-debug") << "Instantiate: " << n << std::endl; //add constructor to equivalence class if not done so already int index = getLabelIndex( eqc, n ); if (index == -1 || eqc->d_inst) @@ -1781,13 +1652,10 @@ void TheoryDatatypes::instantiate( EqcInfo* eqc, Node n ){ eq = tt.eqNode(tt_cons); Debug("datatypes-inst") << "DtInstantiate : " << eqc << " " << eq << std::endl; - d_pending.push_back(eq); - d_pending_exp[eq] = exp; + d_im.addPendingInference(eq, exp); Trace("datatypes-infer-debug") << "inst : " << eqc << " " << n << std::endl; Trace("datatypes-infer") << "DtInfer : instantiate : " << eq << " by " << exp << std::endl; - d_infer.push_back(eq); - d_infer_exp.push_back(exp); } void TheoryDatatypes::checkCycles() { @@ -1822,7 +1690,7 @@ void TheoryDatatypes::checkCycles() { d_conflictNode = mkAnd( expl ); Trace("dt-conflict") << "CONFLICT: Cycle conflict : " << d_conflictNode << std::endl; d_out->conflict( d_conflictNode ); - d_conflict = true; + d_state.notifyInConflict(); return; } } @@ -1872,11 +1740,8 @@ void TheoryDatatypes::checkCycles() { Trace("dt-cdt") << std::endl; Node eq = part_out[i][0].eqNode( part_out[i][j] ); Node eqExp = mkAnd( exp ); - d_pending.push_back( eq ); - d_pending_exp[ eq ] = eqExp; + d_im.addPendingInference(eq, eqExp); Trace("datatypes-infer") << "DtInfer : cdt-bisimilar : " << eq << " by " << eqExp << std::endl; - d_infer.push_back( eq ); - d_infer_exp.push_back( eqExp ); } } } @@ -2051,39 +1916,6 @@ Node TheoryDatatypes::searchForCycle( TNode n, TNode on, } } -bool TheoryDatatypes::mustCommunicateFact( Node n, Node exp ){ - //the datatypes decision procedure makes "internal" inferences apart from the equality engine : - // (1) Unification : C( t1...tn ) = C( s1...sn ) => ti = si - // (2) Label : ~is_C1( t ) ... ~is_C{i-1}( t ) ~is_C{i+1}( t ) ... ~is_Cn( t ) => is_Ci( t ) - // (3) Instantiate : is_C( t ) => t = C( sel_1( t ) ... sel_n( t ) ) - // (4) collapse selector : S( C( t1...tn ) ) = t' - // (5) collapse term size : size( C( t1...tn ) ) = 1 + size( t1 ) + ... + size( tn ) - // (6) non-negative size : 0 <= size( t ) - //We may need to communicate outwards if the conclusions involve other theories. Also communicate (6) and OR conclusions. - Trace("dt-lemma-debug") << "Compute for " << exp << " => " << n << std::endl; - bool addLemma = false; - if( options::dtInferAsLemmas() && exp!=d_true ){ - addLemma = true; - }else if( n.getKind()==EQUAL ){ - TypeNode tn = n[0].getType(); - if( !tn.isDatatype() ){ - addLemma = true; - }else{ - const DType& dt = tn.getDType(); - addLemma = dt.involvesExternalType(); - } - }else if( n.getKind()==LEQ || n.getKind()==OR ){ - addLemma = true; - } - if( addLemma ){ - Trace("dt-lemma-debug") << "Communicate " << n << std::endl; - return true; - }else{ - Trace("dt-lemma-debug") << "Do not need to communicate " << n << std::endl; - return false; - } -} - bool TheoryDatatypes::hasTerm(TNode a) { return d_equalityEngine->hasTerm(a); } bool TheoryDatatypes::areEqual( TNode a, TNode b ){ @@ -2250,8 +2082,6 @@ void TheoryDatatypes::computeRelevantTerms(std::set& termSet) } ++eqcs_i; } - Trace("dt-cmi") << "After adding non-singletons, has " << termSet.size() - << " relevant terms..." << std::endl; } std::pair TheoryDatatypes::entailmentCheck(TNode lit) diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h index 211653125..37a4f81f7 100644 --- a/src/theory/datatypes/theory_datatypes.h +++ b/src/theory/datatypes/theory_datatypes.h @@ -26,6 +26,7 @@ #include "expr/attribute.h" #include "expr/node_trie.h" #include "theory/datatypes/datatypes_rewriter.h" +#include "theory/datatypes/inference_manager.h" #include "theory/datatypes/sygus_extension.h" #include "theory/theory.h" #include "theory/uf/equality_engine.h" @@ -43,9 +44,6 @@ class TheoryDatatypes : public Theory { typedef context::CDHashMap BoolMap; typedef context::CDHashMap NodeMap; - /** inferences */ - NodeList d_infer; - NodeList d_infer_exp; Node d_true; Node d_zero; /** mkAnd */ @@ -70,6 +68,7 @@ class TheoryDatatypes : public Theory { TNode t2, bool value) override { + AlwaysAssert(tag == THEORY_DATATYPES); Debug("dt") << "NotifyClass::eqNotifyTriggerTermMerge(" << tag << ", " << t1 << ", " << t2 << ")" << std::endl; if (value) { return d_dt.propagateLit(t1.eqNode(t2)); @@ -169,20 +168,6 @@ private: /** selector apps for eqch equivalence class */ NodeUIntMap d_selector_apps; std::map< Node, std::vector< Node > > d_selector_apps_data; - /** Are we in conflict */ - context::CDO d_conflict; - /** added lemma - * - * This flag is set to true during a full effort check if this theory - * called d_out->lemma(...). - */ - bool d_addedLemma; - /** added fact - * - * This flag is set to true during a full effort check if this theory - * added an internal fact to its equality engine. - */ - bool d_addedFact; /** The conflict node */ Node d_conflictNode; /** @@ -195,10 +180,6 @@ private: * collectTerms(...) on. */ BoolMap d_collectTermsCacheU; - /** pending assertions/merges */ - std::vector< Node > d_pending_lem; - std::vector< Node > d_pending; - std::map< Node, Node > d_pending_exp; /** All the function terms that the theory has seen */ context::CDList d_functionTerms; /** counter for forcing assignments (ensures fairness) */ @@ -218,12 +199,6 @@ private: /** assert fact */ void assertFact( Node fact, Node exp ); - /** flush pending facts */ - void flushPendingFacts(); - - /** do send lemma */ - bool doSendLemma( Node lem ); - bool doSendLemmas( std::vector< Node >& lem ); /** get or make eqc info */ EqcInfo* getOrMakeEqcInfo( TNode n, bool doMake = false ); @@ -263,9 +238,10 @@ private: /** finish initialization */ void finishInit() override; //--------------------------------- end initialization - /** propagate */ bool propagateLit(TNode literal); + /** Conflict when merging two constants */ + void conflict(TNode a, TNode b); /** explain */ void addAssumptions( std::vector& assumptions, std::vector& tassumptions ); void explainEquality( TNode a, TNode b, bool polarity, std::vector& assumptions ); @@ -274,23 +250,25 @@ private: TrustNode explain(TNode literal) override; Node explainLit(TNode literal); Node explain( std::vector< Node >& lits ); - /** Conflict when merging two constants */ - void conflict(TNode a, TNode b); /** called when a new equivalance class is created */ void eqNotifyNewClass(TNode t); /** called when two equivalance classes have merged */ void eqNotifyMerge(TNode t1, TNode t2); - void check(Effort e) override; + //--------------------------------- standard check + /** Do we need a check call at last call effort? */ bool needsCheckLastEffort() override; + /** Pre-check, called before the fact queue of the theory is processed. */ + bool preCheck(Effort level) override; + /** Post-check, called after the fact queue of the theory is processed. */ + void postCheck(Effort level) override; + /** Notify fact */ + void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override; + //--------------------------------- end standard check void preRegisterTerm(TNode n) override; TrustNode expandDefinition(Node n) override; TrustNode ppRewrite(TNode n) override; - void notifySharedTerm(TNode t) override; EqualityStatus getEqualityStatus(TNode a, TNode b) override; - bool collectModelValues(TheoryModel* m, - const std::set& termSet) override; - void shutdown() override {} std::string identify() const override { return std::string("TheoryDatatypes"); @@ -337,8 +315,6 @@ private: Node getInstantiateCons(Node n, const DType& dt, int index); /** check instantiate */ void instantiate( EqcInfo* eqc, Node n ); - /** must communicate fact */ - bool mustCommunicateFact( Node n, Node exp ); private: //equality queries bool hasTerm( TNode a ); @@ -347,6 +323,9 @@ private: bool areCareDisequal( TNode x, TNode y ); TNode getRepresentative( TNode a ); + /** Collect model values in m based on the relevant terms given by termSet */ + bool collectModelValues(TheoryModel* m, + const std::set& termSet) override; /** * Compute relevant terms. This includes datatypes in non-singleton * equivalence classes. @@ -360,6 +339,8 @@ private: DatatypesRewriter d_rewriter; /** A (default) theory state object */ TheoryState d_state; + /** The inference manager */ + InferenceManager d_im; };/* class TheoryDatatypes */ }/* CVC4::theory::datatypes namespace */ -- cgit v1.2.3 From 8ad308b23c705e73507a42d2425289e999d47f86 Mon Sep 17 00:00:00 2001 From: Haniel Barbosa Date: Tue, 1 Sep 2020 19:08:23 -0300 Subject: 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). --- src/CMakeLists.txt | 40 - src/options/bv_options.toml | 38 - src/options/options.h | 2 - src/options/options_public_functions.cpp | 8 - src/options/proof_options.toml | 35 - src/options/smt_options.toml | 22 +- src/preprocessing/assertion_pipeline.cpp | 20 +- src/preprocessing/passes/ite_simp.cpp | 3 +- src/preprocessing/passes/miplib_trick.cpp | 14 +- src/preprocessing/passes/non_clausal_simp.cpp | 21 +- src/preprocessing/passes/quantifier_macros.cpp | 45 +- src/proof/arith_proof.cpp | 1207 -------------- src/proof/arith_proof.h | 217 --- src/proof/arith_proof_recorder.cpp | 89 - src/proof/arith_proof_recorder.h | 107 -- src/proof/array_proof.cpp | 1350 --------------- src/proof/array_proof.h | 121 -- src/proof/bitvector_proof.cpp | 792 --------- src/proof/bitvector_proof.h | 280 ---- src/proof/clausal_bitvector_proof.cpp | 412 ----- src/proof/clausal_bitvector_proof.h | 189 --- src/proof/clause_id.h | 7 + src/proof/cnf_proof.cpp | 863 +--------- src/proof/cnf_proof.h | 134 +- src/proof/dimacs.cpp | 120 -- src/proof/dimacs.h | 69 - src/proof/drat/drat_proof.cpp | 291 ---- src/proof/drat/drat_proof.h | 140 -- src/proof/er/er_proof.cpp | 399 ----- src/proof/er/er_proof.h | 218 --- src/proof/lemma_proof.cpp | 254 --- src/proof/lemma_proof.h | 115 -- src/proof/lfsc_proof_printer.cpp | 217 --- src/proof/lfsc_proof_printer.h | 154 -- src/proof/lrat/lrat_proof.cpp | 343 ---- src/proof/lrat/lrat_proof.h | 184 -- src/proof/proof.h | 70 - src/proof/proof_manager.cpp | 1032 +----------- src/proof/proof_manager.h | 317 +--- src/proof/proof_output_channel.cpp | 102 -- src/proof/proof_output_channel.h | 79 - src/proof/proof_utils.cpp | 126 -- src/proof/proof_utils.h | 229 --- src/proof/resolution_bitvector_proof.cpp | 523 ------ src/proof/resolution_bitvector_proof.h | 113 -- src/proof/sat_proof.h | 1 - src/proof/sat_proof_implementation.h | 21 - src/proof/simplify_boolean_node.cpp | 183 -- src/proof/simplify_boolean_node.h | 27 - src/proof/skolemization_manager.cpp | 69 - src/proof/skolemization_manager.h | 55 - src/proof/theory_proof.cpp | 1756 -------------------- src/proof/theory_proof.h | 510 ------ src/proof/uf_proof.cpp | 759 --------- src/proof/uf_proof.h | 106 -- src/prop/bvminisat/bvminisat.cpp | 34 +- src/prop/bvminisat/bvminisat.h | 9 +- src/prop/bvminisat/core/Solver.cc | 403 ++--- src/prop/bvminisat/core/Solver.h | 50 +- src/prop/bvminisat/core/SolverTypes.h | 49 +- src/prop/bvminisat/simp/SimpSolver.cc | 55 +- src/prop/cadical.cpp | 1 - src/prop/cnf_stream.cpp | 60 +- src/prop/cnf_stream.h | 14 +- src/prop/cryptominisat.cpp | 44 +- src/prop/cryptominisat.h | 3 - src/prop/kissat.cpp | 1 - src/prop/minisat/core/Solver.cc | 313 ++-- src/prop/minisat/core/Solver.h | 6 +- src/prop/minisat/core/SolverTypes.h | 64 +- src/prop/minisat/minisat.cpp | 2 +- src/prop/minisat/simp/SimpSolver.cc | 96 +- src/prop/prop_engine.cpp | 23 +- src/prop/prop_engine.h | 6 +- src/prop/sat_solver.h | 12 +- src/prop/theory_proxy.cpp | 20 +- src/smt/assertions.cpp | 26 +- src/smt/assertions.h | 3 +- src/smt/command.cpp | 39 +- src/smt/command.h | 8 - src/smt/process_assertions.cpp | 11 +- src/smt/set_defaults.cpp | 139 +- src/smt/smt_engine.cpp | 91 - src/smt/smt_engine.h | 16 - src/smt/smt_engine_scope.cpp | 1 - src/smt/smt_engine_stats.cpp | 6 - src/smt/smt_engine_stats.h | 4 - src/smt/smt_solver.cpp | 8 +- src/smt/term_formula_removal.cpp | 32 +- src/theory/arith/callbacks.cpp | 29 +- src/theory/arith/constraint.cpp | 114 +- src/theory/arith/constraint.h | 48 +- src/theory/arith/linear_equality.cpp | 24 +- src/theory/arith/nl/nl_model.cpp | 1 + src/theory/arith/theory_arith.cpp | 1 - src/theory/arith/theory_arith.h | 11 - src/theory/arith/theory_arith_private.cpp | 99 +- src/theory/arrays/array_proof_reconstruction.cpp | 199 --- src/theory/arrays/array_proof_reconstruction.h | 59 - src/theory/arrays/theory_arrays.cpp | 182 +- src/theory/arrays/theory_arrays.h | 19 +- src/theory/bv/bitblast/aig_bitblaster.h | 6 - src/theory/bv/bitblast/bitblaster.h | 21 +- src/theory/bv/bitblast/eager_bitblaster.cpp | 19 +- src/theory/bv/bitblast/eager_bitblaster.h | 2 - src/theory/bv/bitblast/lazy_bitblaster.cpp | 19 +- src/theory/bv/bitblast/lazy_bitblaster.h | 1 - src/theory/bv/bv_eager_solver.cpp | 12 +- src/theory/bv/bv_eager_solver.h | 3 - src/theory/bv/bv_subtheory.h | 9 +- src/theory/bv/bv_subtheory_bitblast.cpp | 7 - src/theory/bv/bv_subtheory_bitblast.h | 5 - src/theory/bv/theory_bv.cpp | 57 +- src/theory/bv/theory_bv.h | 17 +- src/theory/combination_engine.cpp | 2 +- src/theory/engine_output_channel.cpp | 153 +- src/theory/engine_output_channel.h | 4 +- src/theory/ext_theory.h | 1 + src/theory/output_channel.cpp | 5 - src/theory/output_channel.h | 16 +- src/theory/quantifiers/fun_def_process.cpp | 36 +- src/theory/quantifiers/instantiate.cpp | 32 +- src/theory/quantifiers/instantiate.h | 15 - src/theory/quantifiers_engine.cpp | 19 +- src/theory/quantifiers_engine.h | 4 +- src/theory/sort_inference.cpp | 1 - src/theory/strings/theory_strings_preprocess.cpp | 6 +- src/theory/theory.cpp | 14 +- src/theory/theory.h | 17 +- src/theory/theory_engine.cpp | 241 +-- src/theory/theory_engine.h | 26 +- src/theory/theory_test_utils.h | 8 +- src/theory/uf/eq_proof.cpp | 32 +- src/theory/uf/eq_proof.h | 25 +- src/theory/uf/equality_engine.cpp | 167 +- src/theory/uf/equality_engine.h | 32 - src/theory/uf/equality_engine_types.h | 32 +- src/theory/uf/theory_uf.cpp | 51 +- src/theory/uf/theory_uf.h | 14 +- src/util/CMakeLists.txt | 1 - src/util/proof.h | 44 - test/regress/CMakeLists.txt | 3 +- test/regress/regress0/bug217.smt2 | 1 - .../options/invalid_option_inc_proofs.smt2 | 6 - test/regress/regress1/bv/bench_38.delta.smt2 | 2 +- test/regress/regress1/non-fatal-errors.smt2 | 4 +- .../regress1/quantifiers/dump-inst-proof.smt2 | 8 +- test/unit/CMakeLists.txt | 1 - test/unit/proof/CMakeLists.txt | 7 - test/unit/proof/drat_proof_black.h | 187 --- test/unit/proof/er_proof_black.h | 464 ------ test/unit/proof/lfsc_proof_printer_black.h | 118 -- test/unit/proof/lrat_proof_black.h | 97 -- test/unit/proof/utils.h | 34 - test/unit/prop/cnf_stream_white.h | 60 +- test/unit/theory/theory_engine_white.h | 7 +- test/unit/theory/theory_white.h | 9 +- 157 files changed, 1222 insertions(+), 17995 deletions(-) delete mode 100644 src/proof/arith_proof.cpp delete mode 100644 src/proof/arith_proof.h delete mode 100644 src/proof/arith_proof_recorder.cpp delete mode 100644 src/proof/arith_proof_recorder.h delete mode 100644 src/proof/array_proof.cpp delete mode 100644 src/proof/array_proof.h delete mode 100644 src/proof/bitvector_proof.cpp delete mode 100644 src/proof/bitvector_proof.h delete mode 100644 src/proof/clausal_bitvector_proof.cpp delete mode 100644 src/proof/clausal_bitvector_proof.h delete mode 100644 src/proof/dimacs.cpp delete mode 100644 src/proof/dimacs.h delete mode 100644 src/proof/drat/drat_proof.cpp delete mode 100644 src/proof/drat/drat_proof.h delete mode 100644 src/proof/er/er_proof.cpp delete mode 100644 src/proof/er/er_proof.h delete mode 100644 src/proof/lemma_proof.cpp delete mode 100644 src/proof/lemma_proof.h delete mode 100644 src/proof/lfsc_proof_printer.cpp delete mode 100644 src/proof/lfsc_proof_printer.h delete mode 100644 src/proof/lrat/lrat_proof.cpp delete mode 100644 src/proof/lrat/lrat_proof.h delete mode 100644 src/proof/proof.h delete mode 100644 src/proof/proof_output_channel.cpp delete mode 100644 src/proof/proof_output_channel.h delete mode 100644 src/proof/proof_utils.cpp delete mode 100644 src/proof/proof_utils.h delete mode 100644 src/proof/resolution_bitvector_proof.cpp delete mode 100644 src/proof/resolution_bitvector_proof.h delete mode 100644 src/proof/simplify_boolean_node.cpp delete mode 100644 src/proof/simplify_boolean_node.h delete mode 100644 src/proof/skolemization_manager.cpp delete mode 100644 src/proof/skolemization_manager.h delete mode 100644 src/proof/theory_proof.cpp delete mode 100644 src/proof/theory_proof.h delete mode 100644 src/proof/uf_proof.cpp delete mode 100644 src/proof/uf_proof.h delete mode 100644 src/theory/arrays/array_proof_reconstruction.cpp delete mode 100644 src/theory/arrays/array_proof_reconstruction.h delete mode 100644 src/util/proof.h delete mode 100644 test/regress/regress0/options/invalid_option_inc_proofs.smt2 delete mode 100644 test/unit/proof/CMakeLists.txt delete mode 100644 test/unit/proof/drat_proof_black.h delete mode 100644 test/unit/proof/er_proof_black.h delete mode 100644 test/unit/proof/lfsc_proof_printer_black.h delete mode 100644 test/unit/proof/lrat_proof_black.h delete mode 100644 test/unit/proof/utils.h 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); -- cgit v1.2.3 From 3830d80ce312e8633b9de6311b809bd9418ddd4a Mon Sep 17 00:00:00 2001 From: Andres Noetzli Date: Tue, 1 Sep 2020 23:37:14 -0700 Subject: [API] Fix Python Examples (#4943) When testing the API examples, Python examples were not included. This commit changes that and fixes multiple minor issues that came up once the tests were enabled: - It adds `Solver::supportsFloatingPoint()` as an API method that returns whether CVC4 is configured to support floating-point numbers or not (this is useful for failing gracefully when floating-point support is not available, e.g. in the case of our floating-point example). - It updates the `expections.py` example to use the new API. - It fixes the `sygus-fun.py` example. The example was passing a _set_ of non-terminals to `Solver::mkSygusGrammar()` but the order in which the non-terminals are passed in matters because the first non-terminal is considered to be the starting terminal. The commit also updates the documentation of that function. - It fixes the Python API for datatypes. The `__getitem__` function had a typo and the `datatypes.py` example was crashing as a result. --- CMakeLists.txt | 1 + cmake/CVC4Config.cmake.in | 5 +- examples/api/python/CMakeLists.txt | 15 ++++- examples/api/python/exceptions.py | 34 +++++------ examples/api/python/floating_point.py | 9 ++- examples/api/python/sygus-fun.py | 6 +- src/api/cvc4cpp.cpp | 18 +++++- src/api/cvc4cpp.h | 12 +++- src/api/python/cvc4.pxd | 3 +- src/api/python/cvc4.pxi | 13 +++-- src/parser/smt2/smt2.cpp | 2 +- src/theory/logic_info.cpp | 8 ++- .../regress1/quantifiers/issue3481-unsat1.smt2 | 2 +- test/regress/regress1/quantifiers/issue3481.smt2 | 2 +- test/unit/api/python/test_sort.py | 30 ++++++---- test/unit/api/solver_black.h | 65 ++++++++++++++++++---- 16 files changed, 167 insertions(+), 58 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b1d1e292..02933762b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -571,6 +571,7 @@ add_subdirectory(src) add_subdirectory(test) if(BUILD_BINDINGS_PYTHON) + set(BUILD_BINDINGS_PYTHON_VERSION ${PYTHON_VERSION_MAJOR}) add_subdirectory(src/api/python) endif() diff --git a/cmake/CVC4Config.cmake.in b/cmake/CVC4Config.cmake.in index 76535762d..7f6a80995 100644 --- a/cmake/CVC4Config.cmake.in +++ b/cmake/CVC4Config.cmake.in @@ -1,7 +1,8 @@ @PACKAGE_INIT@ -set(CVC4_BINDINGS_JAVA @BUILD_SWIG_BINDINGS_JAVA@) -set(CVC4_BINDINGS_PYTHON @BUILD_SWIG_BINDINGS_PYTHON@) +set(CVC4_BINDINGS_JAVA @BUILD_BINDINGS_JAVA@) +set(CVC4_BINDINGS_PYTHON @BUILD_BINDINGS_PYTHON@) +set(CVC4_BINDINGS_PYTHON_VERSION @BUILD_BINDINGS_PYTHON_VERSION@) if(NOT TARGET CVC4::cvc4) include(${CMAKE_CURRENT_LIST_DIR}/CVC4Targets.cmake) diff --git a/examples/api/python/CMakeLists.txt b/examples/api/python/CMakeLists.txt index e3966fa2d..0da960513 100644 --- a/examples/api/python/CMakeLists.txt +++ b/examples/api/python/CMakeLists.txt @@ -1,9 +1,22 @@ set(EXAMPLES_API_PYTHON + bitvectors_and_arrays + bitvectors + combination + datatypes exceptions + extract + floating_point + helloworld + linear_arith sequences + sets + strings + sygus-fun + sygus-grammar + sygus-inv ) -find_package(PythonInterp REQUIRED) +find_package(PythonInterp ${CVC4_BINDINGS_PYTHON_VERSION} REQUIRED) # Find Python bindings in the corresponding python-*/site-packages directory. # Lookup Python module directory and store path in PYTHON_MODULE_PATH. diff --git a/examples/api/python/exceptions.py b/examples/api/python/exceptions.py index 780f75bf7..27f068011 100644 --- a/examples/api/python/exceptions.py +++ b/examples/api/python/exceptions.py @@ -16,40 +16,40 @@ ## A simple demonstration of catching CVC4 execptions with the legacy Python ## API. -import CVC4 +import pycvc4 +from pycvc4 import kinds import sys def main(): - em = CVC4.ExprManager() - smt = CVC4.SmtEngine(em) + slv = pycvc4.Solver() - smt.setOption("produce-models", CVC4.SExpr("true")) + slv.setOption("produce-models", "true") # Setting an invalid option try: - smt.setOption("non-existing", CVC4.SExpr("true")) + slv.setOption("non-existing", "true") return 1 - except CVC4.Exception as e: - print(e.toString()) + except: + pass # Creating a term with an invalid type try: - integer = em.integerType() - x = em.mkVar("x", integer) - invalidExpr = em.mkExpr(CVC4.AND, x, x) - smt.checkSat(invalidExpr) + integer = slv.getIntegerSort() + x = slv.mkConst("x", integer) + invalidTerm = em.mkTerm(AND, x, x) + slv.checkSat(invalidTerm) return 1 - except CVC4.Exception as e: - print(e.toString()) + except: + pass # Asking for a model after unsat result try: - smt.checkSat(em.mkBoolConst(False)) - smt.getModel() + slv.checkSat(slv.mkBoolean(False)) + slv.getModel() return 1 - except CVC4.Exception as e: - print(e.toString()) + except: + pass return 0 diff --git a/examples/api/python/floating_point.py b/examples/api/python/floating_point.py index c92666c0b..6fb595e34 100755 --- a/examples/api/python/floating_point.py +++ b/examples/api/python/floating_point.py @@ -20,8 +20,15 @@ from pycvc4 import kinds if __name__ == "__main__": slv = pycvc4.Solver() + + if not slv.supportsFloatingPoint(): + # CVC4 must be built with SymFPU to support the theory of + # floating-point numbers + print("CVC4 was not built with floating-point support.") + exit() + slv.setOption("produce-models", "true") - slv.setLogic("FP") + slv.setLogic("QF_FP") # single 32-bit precision fp32 = slv.mkFloatingPointSort(8, 24) diff --git a/examples/api/python/sygus-fun.py b/examples/api/python/sygus-fun.py index 0f53bd343..25090bd8f 100644 --- a/examples/api/python/sygus-fun.py +++ b/examples/api/python/sygus-fun.py @@ -53,7 +53,7 @@ if __name__ == "__main__": leq = slv.mkTerm(kinds.Leq, start, start) # create the grammar object - g = slv.mkSygusGrammar({x, y}, {start, start_bool}) + g = slv.mkSygusGrammar([x, y], [start, start_bool]) # bind each non-terminal to its rules g.addRules(start, {zero, one, x, y, plus, minus, ite}) @@ -61,8 +61,8 @@ if __name__ == "__main__": # declare the functions-to-synthesize. Optionally, provide the grammar # constraints - max = slv.synthFun("max", {x, y}, integer, g) - min = slv.synthFun("min", {x, y}, integer) + max = slv.synthFun("max", [x, y], integer, g) + min = slv.synthFun("min", [x, y], integer) # declare universal variables. varX = slv.mkSygusVar(integer, "x") diff --git a/src/api/cvc4cpp.cpp b/src/api/cvc4cpp.cpp index c14bed6aa..6c39bfb91 100644 --- a/src/api/cvc4cpp.cpp +++ b/src/api/cvc4cpp.cpp @@ -3240,6 +3240,14 @@ void Solver::checkMkTerm(Kind kind, uint32_t nchildren) const << " children (the one under construction has " << nchildren << ")"; } +/* Solver Configuration */ +/* -------------------------------------------------------------------------- */ + +bool Solver::supportsFloatingPoint() const +{ + return Configuration::isBuiltWithSymFPU(); +} + /* Sorts Handling */ /* -------------------------------------------------------------------------- */ @@ -3285,9 +3293,11 @@ Sort Solver::getStringSort(void) const CVC4_API_SOLVER_TRY_CATCH_END; } -Sort Solver::getRoundingmodeSort(void) const +Sort Solver::getRoundingModeSort(void) const { CVC4_API_SOLVER_TRY_CATCH_BEGIN; + CVC4_API_CHECK(Configuration::isBuiltWithSymFPU()) + << "Expected CVC4 to be compiled with SymFPU support"; return Sort(this, d_exprMgr->roundingModeType()); CVC4_API_SOLVER_TRY_CATCH_END; } @@ -3323,6 +3333,8 @@ Sort Solver::mkBitVectorSort(uint32_t size) const Sort Solver::mkFloatingPointSort(uint32_t exp, uint32_t sig) const { CVC4_API_SOLVER_TRY_CATCH_BEGIN; + CVC4_API_CHECK(Configuration::isBuiltWithSymFPU()) + << "Expected CVC4 to be compiled with SymFPU support"; CVC4_API_ARG_CHECK_EXPECTED(exp > 0, exp) << "exponent size > 0"; CVC4_API_ARG_CHECK_EXPECTED(sig > 0, sig) << "significand size > 0"; @@ -3803,6 +3815,8 @@ Term Solver::mkNegZero(uint32_t exp, uint32_t sig) const Term Solver::mkRoundingMode(RoundingMode rm) const { CVC4_API_SOLVER_TRY_CATCH_BEGIN; + CVC4_API_CHECK(Configuration::isBuiltWithSymFPU()) + << "Expected CVC4 to be compiled with SymFPU support"; return mkValHelper(s_rmodes.at(rm)); CVC4_API_SOLVER_TRY_CATCH_END; } @@ -5396,7 +5410,7 @@ Term Solver::synthFunHelper(const std::string& symbol, { CVC4_API_CHECK(g->d_ntSyms[0].d_node->getType().toType() == *sort.d_type) << "Invalid Start symbol for Grammar g, Expected Start's sort to be " - << *sort.d_type; + << *sort.d_type << " but found " << g->d_ntSyms[0].d_node->getType(); } Type funType = varTypes.empty() diff --git a/src/api/cvc4cpp.h b/src/api/cvc4cpp.h index 0c322d7da..d92660920 100644 --- a/src/api/cvc4cpp.h +++ b/src/api/cvc4cpp.h @@ -2152,6 +2152,12 @@ class CVC4_PUBLIC Solver Solver(const Solver&) = delete; Solver& operator=(const Solver&) = delete; + /* .................................................................... */ + /* Solver Configuration */ + /* .................................................................... */ + + bool supportsFloatingPoint() const; + /* .................................................................... */ /* Sorts Handling */ /* .................................................................... */ @@ -2184,7 +2190,7 @@ class CVC4_PUBLIC Solver /** * @return sort RoundingMode */ - Sort getRoundingmodeSort() const; + Sort getRoundingModeSort() const; /** * @return sort String @@ -3169,7 +3175,9 @@ class CVC4_PUBLIC Solver Term mkSygusVar(Sort sort, const std::string& symbol = std::string()) const; /** - * Create a Sygus grammar. + * Create a Sygus grammar. The first non-terminal is treated as the starting + * non-terminal, so the order of non-terminals matters. + * * @param boundVars the parameters to corresponding synth-fun/synth-inv * @param ntSymbols the pre-declaration of the non-terminal symbols * @return the grammar diff --git a/src/api/python/cvc4.pxd b/src/api/python/cvc4.pxd index 16d64b85e..841fbb44d 100644 --- a/src/api/python/cvc4.pxd +++ b/src/api/python/cvc4.pxd @@ -116,11 +116,12 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api": cdef cppclass Solver: Solver(Options*) except + + bint supportsFloatingPoint() except + Sort getBooleanSort() except + Sort getIntegerSort() except + Sort getRealSort() except + Sort getRegExpSort() except + - Sort getRoundingmodeSort() except + + Sort getRoundingModeSort() except + Sort getStringSort() except + Sort mkArraySort(Sort indexSort, Sort elemSort) except + Sort mkBitVectorSort(uint32_t size) except + diff --git a/src/api/python/cvc4.pxi b/src/api/python/cvc4.pxi index a51307d21..3caead057 100644 --- a/src/api/python/cvc4.pxi +++ b/src/api/python/cvc4.pxi @@ -21,7 +21,8 @@ from cvc4 cimport Grammar as c_Grammar from cvc4 cimport Sort as c_Sort from cvc4 cimport SortHashFunction as c_SortHashFunction from cvc4 cimport ROUND_NEAREST_TIES_TO_EVEN, ROUND_TOWARD_POSITIVE -from cvc4 cimport ROUND_TOWARD_ZERO, ROUND_NEAREST_TIES_TO_AWAY +from cvc4 cimport ROUND_TOWARD_NEGATIVE, ROUND_TOWARD_ZERO +from cvc4 cimport ROUND_NEAREST_TIES_TO_AWAY from cvc4 cimport Term as c_Term from cvc4 cimport TermHashFunction as c_TermHashFunction @@ -88,7 +89,7 @@ cdef class Datatype: if isinstance(index, int) and index >= 0: dc.cdc = self.cd[( index)] elif isinstance(index, str): - dc.cdc = self.cd[( name.encode())] + dc.cdc = self.cd[( index.encode())] else: raise ValueError("Expecting a non-negative integer or string") return dc @@ -395,6 +396,9 @@ cdef class Solver: def __dealloc__(self): del self.csolver + def supportsFloatingPoint(self): + return self.csolver.supportsFloatingPoint() + def getBooleanSort(self): cdef Sort sort = Sort(self) sort.csort = self.csolver.getBooleanSort() @@ -415,9 +419,9 @@ cdef class Solver: sort.csort = self.csolver.getRegExpSort() return sort - def getRoundingmodeSort(self): + def getRoundingModeSort(self): cdef Sort sort = Sort(self) - sort.csort = self.csolver.getRoundingmodeSort() + sort.csort = self.csolver.getRoundingModeSort() return sort def getStringSort(self): @@ -1457,6 +1461,7 @@ cdef class Term: cdef __rounding_modes = { ROUND_NEAREST_TIES_TO_EVEN: "RoundNearestTiesToEven", ROUND_TOWARD_POSITIVE: "RoundTowardPositive", + ROUND_TOWARD_NEGATIVE: "RoundTowardNegative", ROUND_TOWARD_ZERO: "RoundTowardZero", ROUND_NEAREST_TIES_TO_AWAY: "RoundNearestTiesToAway" } diff --git a/src/parser/smt2/smt2.cpp b/src/parser/smt2/smt2.cpp index 1e5d2155a..c4899c8a8 100644 --- a/src/parser/smt2/smt2.cpp +++ b/src/parser/smt2/smt2.cpp @@ -718,7 +718,7 @@ Command* Smt2::setLogic(std::string name, bool fromCommand) } if (d_logic.isTheoryEnabled(theory::THEORY_FP)) { - defineType("RoundingMode", d_solver->getRoundingmodeSort()); + defineType("RoundingMode", d_solver->getRoundingModeSort()); defineType("Float16", d_solver->mkFloatingPointSort(5, 11)); defineType("Float32", d_solver->mkFloatingPointSort(8, 24)); defineType("Float64", d_solver->mkFloatingPointSort(11, 53)); diff --git a/src/theory/logic_info.cpp b/src/theory/logic_info.cpp index 9805f602e..878815811 100644 --- a/src/theory/logic_info.cpp +++ b/src/theory/logic_info.cpp @@ -23,6 +23,7 @@ #include #include "base/check.h" +#include "base/configuration.h" #include "expr/kind.h" using namespace std; @@ -43,7 +44,12 @@ LogicInfo::LogicInfo() d_higherOrder(true), d_locked(false) { - for(TheoryId id = THEORY_FIRST; id < THEORY_LAST; ++id) { + for (TheoryId id = THEORY_FIRST; id < THEORY_LAST; ++id) + { + if (id == THEORY_FP && !Configuration::isBuiltWithSymFPU()) + { + continue; + } enableTheory(id); } } diff --git a/test/regress/regress1/quantifiers/issue3481-unsat1.smt2 b/test/regress/regress1/quantifiers/issue3481-unsat1.smt2 index fb7ff5485..9cf535dc7 100644 --- a/test/regress/regress1/quantifiers/issue3481-unsat1.smt2 +++ b/test/regress/regress1/quantifiers/issue3481-unsat1.smt2 @@ -2,7 +2,7 @@ ; EXPECT: unsat ;; produced by cvc4_16.drv ;; -(set-logic AUFBVFPDTNIRA) +(set-logic AUFBVDTNIRA) (set-info :smt-lib-version 2.6) ;;; generated by SMT-LIB2 driver ;;; SMT-LIB2 driver: bit-vectors, common part diff --git a/test/regress/regress1/quantifiers/issue3481.smt2 b/test/regress/regress1/quantifiers/issue3481.smt2 index fe8c84d62..3d9bfe981 100644 --- a/test/regress/regress1/quantifiers/issue3481.smt2 +++ b/test/regress/regress1/quantifiers/issue3481.smt2 @@ -3,7 +3,7 @@ ;; produced by cvc4_16.drv ;; (set-info :smt-lib-version 2.6) -(set-logic AUFBVFPDTNIRA) +(set-logic AUFBVDTNIRA) ;;; generated by SMT-LIB2 driver ;;; SMT-LIB2 driver: bit-vectors, common part ;;; SMT-LIB2: integer arithmetic diff --git a/test/unit/api/python/test_sort.py b/test/unit/api/python/test_sort.py index cd40fc807..5fdb49f48 100644 --- a/test/unit/api/python/test_sort.py +++ b/test/unit/api/python/test_sort.py @@ -223,21 +223,31 @@ def testGetBVSize(): def testGetFPExponentSize(): solver = pycvc4.Solver() - fpSort = solver.mkFloatingPointSort(4, 8) - fpSort.getFPExponentSize() - setSort = solver.mkSetSort(solver.getIntegerSort()) - with pytest.raises(Exception): - setSort.getFPExponentSize() + if solver.supportsFloatingPoint(): + fpSort = solver.mkFloatingPointSort(4, 8) + fpSort.getFPExponentSize() + setSort = solver.mkSetSort(solver.getIntegerSort()) + + with pytest.raises(Exception): + setSort.getFPExponentSize() + else: + with pytest.raises(Exception): + solver.mkFloatingPointSort(4, 8) def testGetFPSignificandSize(): solver = pycvc4.Solver() - fpSort = solver.mkFloatingPointSort(4, 8) - fpSort.getFPSignificandSize() - setSort = solver.mkSetSort(solver.getIntegerSort()) - with pytest.raises(Exception): - setSort.getFPSignificandSize() + if solver.supportsFloatingPoint(): + fpSort = solver.mkFloatingPointSort(4, 8) + fpSort.getFPSignificandSize() + setSort = solver.mkSetSort(solver.getIntegerSort()) + + with pytest.raises(Exception): + setSort.getFPSignificandSize() + else: + with pytest.raises(Exception): + solver.mkFloatingPointSort(4, 8) def testGetDatatypeParamSorts(): solver = pycvc4.Solver() diff --git a/test/unit/api/solver_black.h b/test/unit/api/solver_black.h index 9837d6b00..11dbbb7ae 100644 --- a/test/unit/api/solver_black.h +++ b/test/unit/api/solver_black.h @@ -27,12 +27,14 @@ class SolverBlack : public CxxTest::TestSuite void setUp() override; void tearDown() override; + void testSupportsFloatingPoint(); + void testGetBooleanSort(); void testGetIntegerSort(); void testGetNullSort(); void testGetRealSort(); void testGetRegExpSort(); - void testGetRoundingmodeSort(); + void testGetRoundingModeSort(); void testGetStringSort(); void testMkArraySort(); @@ -169,6 +171,20 @@ void SolverBlack::setUp() { d_solver.reset(new Solver()); } void SolverBlack::tearDown() { d_solver.reset(nullptr); } +void SolverBlack::testSupportsFloatingPoint() +{ + if (d_solver->supportsFloatingPoint()) + { + TS_ASSERT_THROWS_NOTHING( + d_solver->mkRoundingMode(ROUND_NEAREST_TIES_TO_EVEN)); + } + else + { + TS_ASSERT_THROWS(d_solver->mkRoundingMode(ROUND_NEAREST_TIES_TO_EVEN), + CVC4ApiException&); + } +} + void SolverBlack::testGetBooleanSort() { TS_ASSERT_THROWS_NOTHING(d_solver->getBooleanSort()); @@ -199,9 +215,16 @@ void SolverBlack::testGetStringSort() TS_ASSERT_THROWS_NOTHING(d_solver->getStringSort()); } -void SolverBlack::testGetRoundingmodeSort() +void SolverBlack::testGetRoundingModeSort() { - TS_ASSERT_THROWS_NOTHING(d_solver->getRoundingmodeSort()); + if (d_solver->supportsFloatingPoint()) + { + TS_ASSERT_THROWS_NOTHING(d_solver->getRoundingModeSort()); + } + else + { + TS_ASSERT_THROWS(d_solver->getRoundingModeSort(), CVC4ApiException&); + } } void SolverBlack::testMkArraySort() @@ -210,15 +233,20 @@ void SolverBlack::testMkArraySort() Sort intSort = d_solver->getIntegerSort(); Sort realSort = d_solver->getRealSort(); Sort bvSort = d_solver->mkBitVectorSort(32); - Sort fpSort = d_solver->mkFloatingPointSort(3, 5); TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(boolSort, boolSort)); TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(intSort, intSort)); TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(realSort, realSort)); TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(bvSort, bvSort)); - TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(fpSort, fpSort)); TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(boolSort, intSort)); TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(realSort, bvSort)); - TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(bvSort, fpSort)); + + if (d_solver->supportsFloatingPoint()) + { + Sort fpSort = d_solver->mkFloatingPointSort(3, 5); + TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(fpSort, fpSort)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(bvSort, fpSort)); + } + Solver slv; TS_ASSERT_THROWS(slv.mkArraySort(boolSort, boolSort), CVC4ApiException&); } @@ -231,9 +259,16 @@ void SolverBlack::testMkBitVectorSort() void SolverBlack::testMkFloatingPointSort() { - TS_ASSERT_THROWS_NOTHING(d_solver->mkFloatingPointSort(4, 8)); - TS_ASSERT_THROWS(d_solver->mkFloatingPointSort(0, 8), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver->mkFloatingPointSort(4, 0), CVC4ApiException&); + if (d_solver->supportsFloatingPoint()) + { + TS_ASSERT_THROWS_NOTHING(d_solver->mkFloatingPointSort(4, 8)); + TS_ASSERT_THROWS(d_solver->mkFloatingPointSort(0, 8), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkFloatingPointSort(4, 0), CVC4ApiException&); + } + else + { + TS_ASSERT_THROWS(d_solver->mkFloatingPointSort(4, 8), CVC4ApiException&); + } } void SolverBlack::testMkDatatypeSort() @@ -480,8 +515,16 @@ void SolverBlack::testMkBoolean() void SolverBlack::testMkRoundingMode() { - TS_ASSERT_THROWS_NOTHING( - d_solver->mkRoundingMode(RoundingMode::ROUND_TOWARD_ZERO)); + if (CVC4::Configuration::isBuiltWithSymFPU()) + { + TS_ASSERT_THROWS_NOTHING( + d_solver->mkRoundingMode(RoundingMode::ROUND_TOWARD_ZERO)); + } + else + { + TS_ASSERT_THROWS(d_solver->mkRoundingMode(RoundingMode::ROUND_TOWARD_ZERO), + CVC4ApiException&); + } } void SolverBlack::testMkUninterpretedConst() -- cgit v1.2.3 From 78917e16f6521b0e8a074f3649fc6adf37614617 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Wed, 2 Sep 2020 08:17:39 -0500 Subject: (new theory) Update TheorySets to the new interface (#4951) This updates the theory of sets to the new interface (see #4929). --- src/theory/sets/theory_sets.cpp | 41 ++++--- src/theory/sets/theory_sets.h | 17 ++- src/theory/sets/theory_sets_private.cpp | 199 +++++++++++++------------------- src/theory/sets/theory_sets_private.h | 15 ++- 4 files changed, 124 insertions(+), 148 deletions(-) diff --git a/src/theory/sets/theory_sets.cpp b/src/theory/sets/theory_sets.cpp index 0bf2ed2ea..cb42f09d5 100644 --- a/src/theory/sets/theory_sets.cpp +++ b/src/theory/sets/theory_sets.cpp @@ -67,12 +67,12 @@ void TheorySets::finishInit() d_valuation.setUnevaluatedKind(WITNESS); // functions we are doing congruence over - d_equalityEngine->addFunctionKind(kind::SINGLETON); - d_equalityEngine->addFunctionKind(kind::UNION); - d_equalityEngine->addFunctionKind(kind::INTERSECTION); - d_equalityEngine->addFunctionKind(kind::SETMINUS); - d_equalityEngine->addFunctionKind(kind::MEMBER); - d_equalityEngine->addFunctionKind(kind::SUBSET); + d_equalityEngine->addFunctionKind(SINGLETON); + d_equalityEngine->addFunctionKind(UNION); + d_equalityEngine->addFunctionKind(INTERSECTION); + d_equalityEngine->addFunctionKind(SETMINUS); + d_equalityEngine->addFunctionKind(MEMBER); + d_equalityEngine->addFunctionKind(SUBSET); // relation operators d_equalityEngine->addFunctionKind(PRODUCT); d_equalityEngine->addFunctionKind(JOIN); @@ -88,14 +88,20 @@ void TheorySets::finishInit() d_internal->finishInit(); } -void TheorySets::notifySharedTerm(TNode n) { d_internal->addSharedTerm(n); } +void TheorySets::postCheck(Effort level) { d_internal->postCheck(level); } -void TheorySets::check(Effort e) { - if (done() && e < Theory::EFFORT_FULL) { - return; - } - TimerStat::CodeTimer checkTimer(d_checkTime); - d_internal->check(e); +bool TheorySets::preNotifyFact( + TNode atom, bool polarity, TNode fact, bool isPrereg, bool isInternal) +{ + return d_internal->preNotifyFact(atom, polarity, fact); +} + +void TheorySets::notifyFact(TNode atom, + bool polarity, + TNode fact, + bool isInternal) +{ + d_internal->notifyFact(atom, polarity, fact); } bool TheorySets::collectModelValues(TheoryModel* m, @@ -114,15 +120,12 @@ TrustNode TheorySets::explain(TNode node) return TrustNode::mkTrustPropExp(node, exp, nullptr); } -EqualityStatus TheorySets::getEqualityStatus(TNode a, TNode b) { - return d_internal->getEqualityStatus(a, b); -} - Node TheorySets::getModelValue(TNode node) { return Node::null(); } -void TheorySets::preRegisterTerm(TNode node) { +void TheorySets::preRegisterTerm(TNode node) +{ d_internal->preRegisterTerm(node); } @@ -158,7 +161,7 @@ Theory::PPAssertStatus TheorySets::ppAssert(TNode in, SubstitutionMap& outSubsti Theory::PPAssertStatus status = Theory::PP_ASSERT_STATUS_UNSOLVED; // this is based off of Theory::ppAssert - if (in.getKind() == kind::EQUAL) + if (in.getKind() == EQUAL) { if (in[0].isVar() && isLegalElimination(in[0], in[1])) { diff --git a/src/theory/sets/theory_sets.h b/src/theory/sets/theory_sets.h index a826a43af..7787c0f9b 100644 --- a/src/theory/sets/theory_sets.h +++ b/src/theory/sets/theory_sets.h @@ -58,13 +58,23 @@ class TheorySets : public Theory void finishInit() override; //--------------------------------- end initialization - void notifySharedTerm(TNode) override; - void check(Effort) override; + //--------------------------------- standard check + /** Post-check, called after the fact queue of the theory is processed. */ + void postCheck(Effort level) override; + /** Pre-notify fact, return true if processed. */ + bool preNotifyFact(TNode atom, + bool pol, + TNode fact, + bool isPrereg, + bool isInternal) override; + /** Notify fact */ + void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override; + //--------------------------------- end standard check + /** Collect model values in m based on the relevant terms given by termSet */ bool collectModelValues(TheoryModel* m, const std::set& termSet) override; void computeCareGraph() override; TrustNode explain(TNode) override; - EqualityStatus getEqualityStatus(TNode a, TNode b) override; Node getModelValue(TNode) override; std::string identify() const override { return "THEORY_SETS"; } void preRegisterTerm(TNode node) override; @@ -72,6 +82,7 @@ class TheorySets : public Theory PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions) override; void presolve() override; bool isEntailed(Node n, bool pol); + private: /** Functions to handle callbacks from equality engine */ class NotifyClass : public eq::EqualityEngineNotify diff --git a/src/theory/sets/theory_sets_private.cpp b/src/theory/sets/theory_sets_private.cpp index 78824636a..c432c8039 100644 --- a/src/theory/sets/theory_sets_private.cpp +++ b/src/theory/sets/theory_sets_private.cpp @@ -276,74 +276,21 @@ bool TheorySetsPrivate::assertFact(Node fact, Node exp) << ", exp = " << exp << std::endl; bool polarity = fact.getKind() != kind::NOT; TNode atom = polarity ? fact : fact[0]; - if (!d_state.isEntailed(atom, polarity)) + if (d_state.isEntailed(atom, polarity)) { - if (atom.getKind() == kind::EQUAL) - { - d_equalityEngine->assertEquality(atom, polarity, exp); - } - else - { - d_equalityEngine->assertPredicate(atom, polarity, exp); - } - if (!d_state.isInConflict()) - { - if (atom.getKind() == kind::MEMBER && polarity) - { - // check if set has a value, if so, we can propagate - Node r = d_equalityEngine->getRepresentative(atom[1]); - EqcInfo* e = getOrMakeEqcInfo(r, true); - if (e) - { - Node s = e->d_singleton; - if (!s.isNull()) - { - Node pexp = NodeManager::currentNM()->mkNode( - kind::AND, atom, atom[1].eqNode(s)); - d_keep.insert(pexp); - if (s.getKind() == kind::SINGLETON) - { - if (s[0] != atom[0]) - { - Trace("sets-prop") - << "Propagate mem-eq : " << pexp << std::endl; - Node eq = s[0].eqNode(atom[0]); - d_keep.insert(eq); - assertFact(eq, pexp); - } - } - else - { - Trace("sets-prop") - << "Propagate mem-eq conflict : " << pexp << std::endl; - d_im.conflict(pexp); - } - } - } - // add to membership list - NodeIntMap::iterator mem_i = d_members.find(r); - int n_members = 0; - if (mem_i != d_members.end()) - { - n_members = (*mem_i).second; - } - d_members[r] = n_members + 1; - if (n_members < (int)d_members_data[r].size()) - { - d_members_data[r][n_members] = atom; - } - else - { - d_members_data[r].push_back(atom); - } - } - } - return true; + return false; + } + if (atom.getKind() == kind::EQUAL) + { + d_equalityEngine->assertEquality(atom, polarity, exp); } else { - return false; + d_equalityEngine->assertPredicate(atom, polarity, exp); } + // call the notify new fact method + notifyFact(atom, polarity, exp); + return true; } void TheorySetsPrivate::fullEffortReset() @@ -950,26 +897,10 @@ void TheorySetsPrivate::checkReduceComprehensions() } } -/**************************** TheorySetsPrivate *****************************/ -/**************************** TheorySetsPrivate *****************************/ -/**************************** TheorySetsPrivate *****************************/ +//--------------------------------- standard check -void TheorySetsPrivate::check(Theory::Effort level) +void TheorySetsPrivate::postCheck(Theory::Effort level) { - Trace("sets-check") << "Sets check effort " << level << std::endl; - if (level == Theory::EFFORT_LAST_CALL) - { - return; - } - while (!d_external.done() && !d_state.isInConflict()) - { - // Get all the assertions - Assertion assertion = d_external.get(); - TNode fact = assertion.d_assertion; - Trace("sets-assert") << "Assert from input " << fact << std::endl; - // assert the fact - assertFact(fact, fact); - } Trace("sets-check") << "Sets finished assertions effort " << level << std::endl; // invoke full effort check, relations check @@ -989,18 +920,75 @@ void TheorySetsPrivate::check(Theory::Effort level) } } Trace("sets-check") << "Sets finish Check effort " << level << std::endl; -} /* TheorySetsPrivate::check() */ +} -/************************ Sharing ************************/ -/************************ Sharing ************************/ -/************************ Sharing ************************/ +bool TheorySetsPrivate::preNotifyFact(TNode atom, bool polarity, TNode fact) +{ + // use entailment check (is this necessary?) + return d_state.isEntailed(atom, polarity); +} -void TheorySetsPrivate::addSharedTerm(TNode n) +void TheorySetsPrivate::notifyFact(TNode atom, bool polarity, TNode fact) { - Debug("sets") << "[sets] TheorySetsPrivate::addSharedTerm( " << n << ")" - << std::endl; - d_equalityEngine->addTriggerTerm(n, THEORY_SETS); + if (d_state.isInConflict()) + { + return; + } + if (atom.getKind() == kind::MEMBER && polarity) + { + // check if set has a value, if so, we can propagate + Node r = d_equalityEngine->getRepresentative(atom[1]); + EqcInfo* e = getOrMakeEqcInfo(r, true); + if (e) + { + Node s = e->d_singleton; + if (!s.isNull()) + { + Node pexp = NodeManager::currentNM()->mkNode( + kind::AND, atom, atom[1].eqNode(s)); + d_keep.insert(pexp); + if (s.getKind() == kind::SINGLETON) + { + if (s[0] != atom[0]) + { + Trace("sets-prop") << "Propagate mem-eq : " << pexp << std::endl; + Node eq = s[0].eqNode(atom[0]); + d_keep.insert(eq); + // triggers an internal inference + assertFact(eq, pexp); + } + } + else + { + Trace("sets-prop") + << "Propagate mem-eq conflict : " << pexp << std::endl; + d_im.conflict(pexp); + } + } + } + // add to membership list + NodeIntMap::iterator mem_i = d_members.find(r); + int n_members = 0; + if (mem_i != d_members.end()) + { + n_members = (*mem_i).second; + } + d_members[r] = n_members + 1; + if (n_members < (int)d_members_data[r].size()) + { + d_members_data[r][n_members] = atom; + } + else + { + d_members_data[r].push_back(atom); + } + } } +//--------------------------------- end standard check + +/************************ Sharing ************************/ +/************************ Sharing ************************/ +/************************ Sharing ************************/ void TheorySetsPrivate::addCarePairs(TNodeTrie* t1, TNodeTrie* t2, @@ -1193,37 +1181,6 @@ bool TheorySetsPrivate::isCareArg(Node n, unsigned a) } } -EqualityStatus TheorySetsPrivate::getEqualityStatus(TNode a, TNode b) -{ - Assert(d_equalityEngine->hasTerm(a) && d_equalityEngine->hasTerm(b)); - if (d_equalityEngine->areEqual(a, b)) - { - // The terms are implied to be equal - return EQUALITY_TRUE; - } - if (d_equalityEngine->areDisequal(a, b, false)) - { - // The terms are implied to be dis-equal - return EQUALITY_FALSE; - } - return EQUALITY_UNKNOWN; - /* - Node aModelValue = d_external.d_valuation.getModelValue(a); - if(aModelValue.isNull()) { return EQUALITY_UNKNOWN; } - Node bModelValue = d_external.d_valuation.getModelValue(b); - if(bModelValue.isNull()) { return EQUALITY_UNKNOWN; } - if( aModelValue == bModelValue ) { - // The term are true in current model - return EQUALITY_TRUE_IN_MODEL; - } else { - return EQUALITY_FALSE_IN_MODEL; - } - */ - // } - // //TODO: can we be more precise sometimes? - // return EQUALITY_UNKNOWN; -} - /******************** Model generation ********************/ /******************** Model generation ********************/ /******************** Model generation ********************/ @@ -1261,7 +1218,7 @@ std::string traceElements(const Node& set) bool TheorySetsPrivate::collectModelValues(TheoryModel* m, const std::set& termSet) { - Trace("sets-model") << "Set collect model info" << std::endl; + Trace("sets-model") << "Set collect model values" << std::endl; NodeManager* nm = NodeManager::currentNM(); std::map mvals; diff --git a/src/theory/sets/theory_sets_private.h b/src/theory/sets/theory_sets_private.h index 387d56de9..0df1eabc5 100644 --- a/src/theory/sets/theory_sets_private.h +++ b/src/theory/sets/theory_sets_private.h @@ -172,18 +172,23 @@ class TheorySetsPrivate { */ void finishInit(); + //--------------------------------- standard check + /** Post-check, called after the fact queue of the theory is processed. */ + void postCheck(Theory::Effort level); + /** Preprocess fact, return true if processed. */ + bool preNotifyFact(TNode atom, bool polarity, TNode fact); + /** Notify new fact */ + void notifyFact(TNode atom, bool polarity, TNode fact); + //--------------------------------- end standard check + + /** Collect model values in m based on the relevant terms given by termSet */ void addSharedTerm(TNode); - - void check(Theory::Effort); - bool collectModelValues(TheoryModel* m, const std::set& termSet); void computeCareGraph(); Node explain(TNode); - EqualityStatus getEqualityStatus(TNode a, TNode b); - void preRegisterTerm(TNode node); /** expandDefinition -- cgit v1.2.3 From 02e682821028bc704c57a762dadeb6f82bb70ebf Mon Sep 17 00:00:00 2001 From: Gereon Kremer Date: Wed, 2 Sep 2020 15:48:12 +0200 Subject: Add ArithLemma and arith::InferenceManager (#4960) This PR adds a new ArithLemma that is essentiall NlLemma, but derived from the new theory::Lemma and meant to be used all across the arithmetic theory. Also, based on theory::InferenceManagerBuffered this PR adds arith::InferenceManager that shall become the sole interface between the arithmetic theory and the OutputChannel. --- src/CMakeLists.txt | 4 + src/theory/arith/arith_lemma.cpp | 28 +++++ src/theory/arith/arith_lemma.h | 61 +++++++++++ src/theory/arith/inference_manager.cpp | 143 ++++++++++++++++++++++++++ src/theory/arith/inference_manager.h | 116 +++++++++++++++++++++ src/theory/arith/nl/cad_solver.cpp | 2 +- src/theory/arith/nl/nl_lemma_utils.cpp | 12 ++- src/theory/arith/nl/nl_lemma_utils.h | 30 ++++-- src/theory/arith/nl/nl_model.cpp | 2 +- src/theory/arith/nl/nl_solver.cpp | 2 +- src/theory/arith/nl/nonlinear_extension.cpp | 23 +++-- src/theory/arith/nl/nonlinear_extension.h | 5 +- src/theory/arith/nl/transcendental_solver.cpp | 4 +- src/theory/inference_manager_buffered.cpp | 8 ++ src/theory/inference_manager_buffered.h | 7 +- 15 files changed, 414 insertions(+), 33 deletions(-) create mode 100644 src/theory/arith/arith_lemma.cpp create mode 100644 src/theory/arith/arith_lemma.h create mode 100644 src/theory/arith/inference_manager.cpp create mode 100644 src/theory/arith/inference_manager.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7a383d0c8..2da04ce66 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -251,6 +251,8 @@ libcvc4_add_sources( theory/arith/approx_simplex.h theory/arith/arith_ite_utils.cpp theory/arith/arith_ite_utils.h + theory/arith/arith_lemma.cpp + theory/arith/arith_lemma.h theory/arith/arith_msum.cpp theory/arith/arith_msum.h theory/arith/arith_rewriter.cpp @@ -287,6 +289,8 @@ libcvc4_add_sources( theory/arith/fc_simplex.h theory/arith/infer_bounds.cpp theory/arith/infer_bounds.h + theory/arith/inference_manager.cpp + theory/arith/inference_manager.h theory/arith/linear_equality.cpp theory/arith/linear_equality.h theory/arith/matrix.cpp diff --git a/src/theory/arith/arith_lemma.cpp b/src/theory/arith/arith_lemma.cpp new file mode 100644 index 000000000..9bd4df255 --- /dev/null +++ b/src/theory/arith/arith_lemma.cpp @@ -0,0 +1,28 @@ +/********************* */ +/*! \file arith_lemma.cpp + ** \verbatim + ** Top contributors (to current version): + ** Gereon Kremer + ** 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 ArithLemma class, derived from Lemma. + **/ + +#include "theory/arith/arith_lemma.h" + +namespace CVC4 { +namespace theory { +namespace arith { + +std::ostream& operator<<(std::ostream& out, const ArithLemma& al) +{ + return out << al.d_node; +} + +} // namespace arith +} // namespace theory +} // namespace CVC4 diff --git a/src/theory/arith/arith_lemma.h b/src/theory/arith/arith_lemma.h new file mode 100644 index 000000000..a06cb83f3 --- /dev/null +++ b/src/theory/arith/arith_lemma.h @@ -0,0 +1,61 @@ +/********************* */ +/*! \file arith_lemma.h + ** \verbatim + ** Top contributors (to current version): + ** Gereon Kremer + ** 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 ArithLemma class, derived from Lemma. + **/ + +#ifndef CVC4__THEORY__ARITH__ARITH_LEMMA_H +#define CVC4__THEORY__ARITH__ARITH_LEMMA_H + +#include +#include + +#include "expr/node.h" +#include "theory/arith/nl/inference.h" +#include "theory/inference_manager_buffered.h" +#include "theory/output_channel.h" +#include "theory/theory_inference.h" + +namespace CVC4 { +namespace theory { +namespace arith { + +/** + * The data structure for a single lemma to process by the arithmetic theory, + * derived from theory::SimpleTheoryLemma. + * + * This also includes the inference type that produced this lemma. + */ +class ArithLemma : public SimpleTheoryLemma +{ + public: + ArithLemma(Node n, + LemmaProperty p, + ProofGenerator* pg, + nl::Inference inf = nl::Inference::UNKNOWN) + : SimpleTheoryLemma(n, p, pg), d_inference(inf) + { + } + virtual ~ArithLemma() {} + + /** The inference id for the lemma */ + nl::Inference d_inference; +}; +/** + * Writes an arithmetic lemma to a stream. + */ +std::ostream& operator<<(std::ostream& out, const ArithLemma& al); + +} // namespace arith +} // namespace theory +} // namespace CVC4 + +#endif /* CVC4__THEORY__ARITH__ARITH_LEMMA_H */ diff --git a/src/theory/arith/inference_manager.cpp b/src/theory/arith/inference_manager.cpp new file mode 100644 index 000000000..f026aa374 --- /dev/null +++ b/src/theory/arith/inference_manager.cpp @@ -0,0 +1,143 @@ +/********************* */ +/*! \file inference_manager.cpp + ** \verbatim + ** Top contributors (to current version): + ** Gereon Kremer + ** 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 Implementation of the inference manager for the theory of strings. + **/ + +#include "theory/arith/inference_manager.h" + +#include "options/arith_options.h" +#include "theory/arith/theory_arith.h" +#include "theory/rewriter.h" + +namespace CVC4 { +namespace theory { +namespace arith { + +InferenceManager::InferenceManager(TheoryArith& ta, + ArithState& astate, + ProofNodeManager* pnm) + : InferenceManagerBuffered(ta, astate, pnm), d_lemmasPp(ta.getUserContext()) +{ +} + +void InferenceManager::addPendingArithLemma(std::shared_ptr lemma, + bool isWaiting) +{ + lemma->d_node = Rewriter::rewrite(lemma->d_node); + if (hasCachedLemma(lemma->d_node, lemma->d_property)) + { + return; + } + if (isEntailedFalse(*lemma)) + { + if (isWaiting) + { + d_waitingLem.clear(); + } + else + { + d_pendingLem.clear(); + d_theoryState.notifyInConflict(); + } + } + if (isWaiting) + { + d_waitingLem.emplace_back(std::move(lemma)); + } + else + { + addPendingLemma(std::move(lemma)); + } +} +void InferenceManager::addPendingArithLemma(const ArithLemma& lemma, + bool isWaiting) +{ + addPendingArithLemma(std::make_shared(lemma), isWaiting); +} +void InferenceManager::addPendingArithLemma(const Node& lemma, + nl::Inference inftype, + bool isWaiting) +{ + addPendingArithLemma(std::make_shared( + lemma, LemmaProperty::NONE, nullptr, inftype), + isWaiting); +} + +void InferenceManager::flushWaitingLemmas() +{ + for (auto& lem : d_waitingLem) + { + addPendingLemma(std::move(lem)); + } + d_waitingLem.clear(); +} + +void InferenceManager::addConflict(const Node& conf, nl::Inference inftype) +{ + conflict(Rewriter::rewrite(conf)); +} + +std::size_t InferenceManager::numWaitingLemmas() const +{ + return d_waitingLem.size(); +} + +bool InferenceManager::hasCachedLemma(TNode lem, LemmaProperty p) +{ + if (isLemmaPropertyPreprocess(p)) + { + return d_lemmasPp.find(lem) != d_lemmasPp.end(); + } + return TheoryInferenceManager::hasCachedLemma(lem, p); +} + +bool InferenceManager::cacheLemma(TNode lem, LemmaProperty p) +{ + if (isLemmaPropertyPreprocess(p)) + { + if (d_lemmasPp.find(lem) != d_lemmasPp.end()) + { + return false; + } + d_lemmasPp.insert(lem); + return true; + } + return TheoryInferenceManager::cacheLemma(lem, p); +} + +bool InferenceManager::isEntailedFalse(const ArithLemma& lem) +{ + if (options::nlExtEntailConflicts()) + { + Node ch_lemma = lem.d_node.negate(); + ch_lemma = Rewriter::rewrite(ch_lemma); + Trace("arith-inf-manager") << "InferenceManager::Check entailment of " + << ch_lemma << "..." << std::endl; + + std::pair et = d_theory.getValuation().entailmentCheck( + options::TheoryOfMode::THEORY_OF_TYPE_BASED, ch_lemma); + Trace("arith-inf-manager") << "entailment test result : " << et.first << " " + << et.second << std::endl; + if (et.first) + { + Trace("arith-inf-manager") + << "*** Lemma entailed to be in conflict : " << lem.d_node + << std::endl; + return true; + } + } + return false; +} + +} // namespace arith +} // namespace theory +} // namespace CVC4 diff --git a/src/theory/arith/inference_manager.h b/src/theory/arith/inference_manager.h new file mode 100644 index 000000000..3b7190826 --- /dev/null +++ b/src/theory/arith/inference_manager.h @@ -0,0 +1,116 @@ +/********************* */ +/*! \file inference_manager.h + ** \verbatim + ** Top contributors (to current version): + ** Gereon Kremer + ** 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 Customized inference manager for the theory of nonlinear arithmetic + **/ + +#include "cvc4_private.h" + +#ifndef CVC4__THEORY__ARITH__INFERENCE_MANAGER_H +#define CVC4__THEORY__ARITH__INFERENCE_MANAGER_H + +#include +#include + +#include "theory/arith/arith_lemma.h" +#include "theory/arith/arith_state.h" +#include "theory/arith/nl/inference.h" +#include "theory/arith/nl/nl_lemma_utils.h" +#include "theory/inference_manager_buffered.h" + +namespace CVC4 { +namespace theory { +namespace arith { + +class TheoryArith; + +/** + * A specialized variant of the InferenceManagerBuffered, tailored to the + * arithmetic theory. + * + * It adds some convenience methods to send ArithLemma and adds a mechanism for + * waiting lemmas that can be flushed into the pending lemmas of the this + * buffered inference manager. + * It also extends the caching mechanism of TheoryInferenceManager to cache + * preprocessing lemmas and non-preprocessing lemmas separately. For the former, + * it uses the cache provided by the TheoryInferenceManager base class. + */ +class InferenceManager : public InferenceManagerBuffered +{ + using NodeSet = context::CDHashSet; + + public: + InferenceManager(TheoryArith& ta, ArithState& astate, ProofNodeManager* pnm); + + /** + * Add a lemma as pending lemma to the this inference manager. + * If isWaiting is true, the lemma is first stored as waiting lemma and only + * added as pending lemma when calling flushWaitingLemmas. + */ + void addPendingArithLemma(std::shared_ptr lemma, + bool isWaiting = false); + /** + * Add a lemma as pending lemma to the this inference manager. + * If isWaiting is true, the lemma is first stored as waiting lemma and only + * added as pending lemma when calling flushWaitingLemmas. + */ + void addPendingArithLemma(const ArithLemma& lemma, bool isWaiting = false); + /** + * Add a lemma as pending lemma to the this inference manager. + * If isWaiting is true, the lemma is first stored as waiting lemma and only + * added as pending lemma when calling flushWaitingLemmas. + */ + void addPendingArithLemma(const Node& lemma, + nl::Inference inftype, + bool isWaiting = false); + + /** + * Flush all waiting lemmas to the this inference manager (as pending + * lemmas). To actually send them, call doPendingLemmas() afterwards. + */ + void flushWaitingLemmas(); + + /** Add a conflict to the this inference manager. */ + void addConflict(const Node& conf, nl::Inference inftype); + + /** Returns the number of pending lemmas. */ + std::size_t numWaitingLemmas() const; + + /** Checks whether the given lemma is already present in the cache. */ + virtual bool hasCachedLemma(TNode lem, LemmaProperty p) override; + + protected: + /** + * Adds the given lemma to the cache. Returns true if it has not been in the + * cache yet. + */ + virtual bool cacheLemma(TNode lem, LemmaProperty p) override; + + private: + /** + * Checks whether the lemma is entailed to be false. In this case, it is a + * conflict. + */ + bool isEntailedFalse(const ArithLemma& lem); + + /** The waiting lemmas. */ + std::vector> d_waitingLem; + + /** cache of all preprocessed lemmas sent on the output channel + * (user-context-dependent) */ + NodeSet d_lemmasPp; +}; + +} // namespace arith +} // namespace theory +} // namespace CVC4 + +#endif diff --git a/src/theory/arith/nl/cad_solver.cpp b/src/theory/arith/nl/cad_solver.cpp index b1f0894fb..ac939c341 100644 --- a/src/theory/arith/nl/cad_solver.cpp +++ b/src/theory/arith/nl/cad_solver.cpp @@ -95,7 +95,7 @@ std::vector CadSolver::checkFull() { lems.emplace_back(nm->mkNode(Kind::OR, mis), Inference::CAD_CONFLICT); } - Trace("nl-cad") << "UNSAT with MIS: " << lems.back().d_lemma << std::endl; + Trace("nl-cad") << "UNSAT with MIS: " << lems.back().d_node << std::endl; } return lems; #else diff --git a/src/theory/arith/nl/nl_lemma_utils.cpp b/src/theory/arith/nl/nl_lemma_utils.cpp index 49eec186e..58a552815 100644 --- a/src/theory/arith/nl/nl_lemma_utils.cpp +++ b/src/theory/arith/nl/nl_lemma_utils.cpp @@ -15,20 +15,26 @@ #include "theory/arith/nl/nl_lemma_utils.h" #include "theory/arith/nl/nl_model.h" +#include "theory/arith/nl/nonlinear_extension.h" namespace CVC4 { namespace theory { namespace arith { namespace nl { -LemmaProperty NlLemma::getLemmaProperty() const +bool NlLemma::process(TheoryInferenceManager* im) { - return d_preprocess ? LemmaProperty::PREPROCESS : LemmaProperty::NONE; + bool res = ArithLemma::process(im); + if (d_nlext != nullptr) + { + d_nlext->processSideEffect(*this); + } + return res; } std::ostream& operator<<(std::ostream& out, NlLemma& n) { - out << n.d_lemma; + out << n.d_node; return out; } diff --git a/src/theory/arith/nl/nl_lemma_utils.h b/src/theory/arith/nl/nl_lemma_utils.h index f40857fda..c6c22c3c6 100644 --- a/src/theory/arith/nl/nl_lemma_utils.h +++ b/src/theory/arith/nl/nl_lemma_utils.h @@ -17,7 +17,9 @@ #include #include + #include "expr/node.h" +#include "theory/arith/arith_lemma.h" #include "theory/arith/nl/inference.h" #include "theory/output_channel.h" @@ -27,6 +29,7 @@ namespace arith { namespace nl { class NlModel; +class NonlinearExtension; /** * The data structure for a single lemma to process by the non-linear solver, @@ -39,19 +42,24 @@ class NlModel; * - A set of secant points to record (for transcendental secant plane * inferences). */ -struct NlLemma +class NlLemma : public ArithLemma { - NlLemma(Node lem, Inference id = Inference::UNKNOWN) - : d_id(id), d_lemma(lem), d_preprocess(false) + public: + NlLemma(Node n, + LemmaProperty p, + ProofGenerator* pg, + nl::Inference inf = nl::Inference::UNKNOWN) + : ArithLemma(n, p, pg, inf) + { + } + NlLemma(Node n, nl::Inference inf = nl::Inference::UNKNOWN) + : ArithLemma(n, LemmaProperty::NONE, nullptr, inf) { } ~NlLemma() {} - /** The inference id for the lemma */ - Inference d_id; - /** The lemma */ - Node d_lemma; - /** Whether to preprocess the lemma */ - bool d_preprocess; + + bool process(TheoryInferenceManager* im) override; + /** secant points to add * * A member (tf, d, c) in this vector indicates that point c should be added @@ -62,8 +70,8 @@ struct NlLemma * Cimatti et al., CADE 2017. */ std::vector > d_secantPoint; - /** get lemma property (preprocess or none) */ - LemmaProperty getLemmaProperty() const; + + NonlinearExtension* d_nlext; }; /** * Writes a non-linear lemma to a stream. diff --git a/src/theory/arith/nl/nl_model.cpp b/src/theory/arith/nl/nl_model.cpp index cfa153a56..fbc38fbc2 100644 --- a/src/theory/arith/nl/nl_model.cpp +++ b/src/theory/arith/nl/nl_model.cpp @@ -326,7 +326,7 @@ bool NlModel::checkModel(const std::vector& assertions, Node v = cb.first; Node pred = nm->mkNode(AND, nm->mkNode(GEQ, v, l), nm->mkNode(GEQ, u, v)); pred = nm->mkNode(OR, mg.negate(), pred); - lemmas.push_back(pred); + lemmas.emplace_back(pred); } } return true; diff --git a/src/theory/arith/nl/nl_solver.cpp b/src/theory/arith/nl/nl_solver.cpp index 521539674..6c20eec76 100644 --- a/src/theory/arith/nl/nl_solver.cpp +++ b/src/theory/arith/nl/nl_solver.cpp @@ -843,7 +843,7 @@ std::vector NlSolver::checkMonomialMagnitude(unsigned c) std::vector nr_lemmas; for (unsigned i = 0; i < lemmas.size(); i++) { - if (r_lemmas.find(lemmas[i].d_lemma) == r_lemmas.end()) + if (r_lemmas.find(lemmas[i].d_node) == r_lemmas.end()) { nr_lemmas.push_back(lemmas[i]); } diff --git a/src/theory/arith/nl/nonlinear_extension.cpp b/src/theory/arith/nl/nonlinear_extension.cpp index 8535396e7..ada6aa11a 100644 --- a/src/theory/arith/nl/nonlinear_extension.cpp +++ b/src/theory/arith/nl/nonlinear_extension.cpp @@ -166,9 +166,9 @@ void NonlinearExtension::sendLemmas(const std::vector& out) { for (const NlLemma& nlem : out) { - Node lem = nlem.d_lemma; - LemmaProperty p = nlem.getLemmaProperty(); - Trace("nl-ext-lemma") << "NonlinearExtension::Lemma : " << nlem.d_id + Node lem = nlem.d_node; + LemmaProperty p = nlem.d_property; + Trace("nl-ext-lemma") << "NonlinearExtension::Lemma : " << nlem.d_inference << " : " << lem << std::endl; d_containing.getOutputChannel().lemma(lem, p); // process the side effect @@ -182,7 +182,7 @@ void NonlinearExtension::sendLemmas(const std::vector& out) { d_lemmas.insert(lem); } - d_stats.d_inferences << nlem.d_id; + d_stats.d_inferences << nlem.d_inference; } } @@ -210,14 +210,15 @@ void NonlinearExtension::computeRelevantAssertions( unsigned NonlinearExtension::filterLemma(NlLemma lem, std::vector& out) { Trace("nl-ext-lemma-debug") - << "NonlinearExtension::Lemma pre-rewrite : " << lem.d_lemma << std::endl; - lem.d_lemma = Rewriter::rewrite(lem.d_lemma); + << "NonlinearExtension::Lemma pre-rewrite : " << lem.d_node << std::endl; + lem.d_node = Rewriter::rewrite(lem.d_node); // get the proper cache - NodeSet& lcache = lem.d_preprocess ? d_lemmasPp : d_lemmas; - if (lcache.find(lem.d_lemma) != lcache.end()) + NodeSet& lcache = + isLemmaPropertyPreprocess(lem.d_property) ? d_lemmasPp : d_lemmas; + if (lcache.find(lem.d_node) != lcache.end()) { Trace("nl-ext-lemma-debug") - << "NonlinearExtension::Lemma duplicate : " << lem.d_lemma << std::endl; + << "NonlinearExtension::Lemma duplicate : " << lem.d_node << std::endl; return 0; } out.emplace_back(lem); @@ -232,7 +233,7 @@ unsigned NonlinearExtension::filterLemmas(std::vector& lemmas, // check if any are entailed to be false for (const NlLemma& lem : lemmas) { - Node ch_lemma = lem.d_lemma.negate(); + Node ch_lemma = lem.d_node.negate(); ch_lemma = Rewriter::rewrite(ch_lemma); Trace("nl-ext-et-debug") << "Check entailment of " << ch_lemma << "..." << std::endl; @@ -243,7 +244,7 @@ unsigned NonlinearExtension::filterLemmas(std::vector& lemmas, if (et.first) { Trace("nl-ext-et") << "*** Lemma entailed to be in conflict : " - << lem.d_lemma << std::endl; + << lem.d_node << std::endl; // return just this lemma if (filterLemma(lem, out) > 0) { diff --git a/src/theory/arith/nl/nonlinear_extension.h b/src/theory/arith/nl/nonlinear_extension.h index ee58a9e2e..d035b1056 100644 --- a/src/theory/arith/nl/nonlinear_extension.h +++ b/src/theory/arith/nl/nonlinear_extension.h @@ -172,6 +172,9 @@ class NonlinearExtension */ void presolve(); + /** Process side effect se */ + void processSideEffect(const NlLemma& se); + private: /** Model-based refinement * @@ -274,8 +277,6 @@ class NonlinearExtension * Send lemmas in out on the output channel of theory of arithmetic. */ void sendLemmas(const std::vector& out); - /** Process side effect se */ - void processSideEffect(const NlLemma& se); /** cache of all lemmas sent on the output channel (user-context-dependent) */ NodeSet d_lemmas; diff --git a/src/theory/arith/nl/transcendental_solver.cpp b/src/theory/arith/nl/transcendental_solver.cpp index 321818b94..b2ef16459 100644 --- a/src/theory/arith/nl/transcendental_solver.cpp +++ b/src/theory/arith/nl/transcendental_solver.cpp @@ -212,8 +212,8 @@ void TranscendentalSolver::initLastCall(const std::vector& assertions, // note we must do preprocess on this lemma Trace("nl-ext-lemma") << "NonlinearExtension::Lemma : purify : " << lem << std::endl; - NlLemma nlem(lem, Inference::T_PURIFY_ARG); - nlem.d_preprocess = true; + NlLemma nlem( + lem, LemmaProperty::PREPROCESS, nullptr, Inference::T_PURIFY_ARG); lems.emplace_back(nlem); } diff --git a/src/theory/inference_manager_buffered.cpp b/src/theory/inference_manager_buffered.cpp index a1cb9c4e9..df01b4e93 100644 --- a/src/theory/inference_manager_buffered.cpp +++ b/src/theory/inference_manager_buffered.cpp @@ -121,5 +121,13 @@ void InferenceManagerBuffered::clearPendingPhaseRequirements() d_pendingReqPhase.clear(); } + + std::size_t InferenceManagerBuffered::numPendingLemmas() const { + return d_pendingLem.size(); + } + std::size_t InferenceManagerBuffered::numPendingFacts() const { + return d_pendingFact.size(); + } + } // namespace theory } // namespace CVC4 diff --git a/src/theory/inference_manager_buffered.h b/src/theory/inference_manager_buffered.h index e6e7822c5..762b7d4e0 100644 --- a/src/theory/inference_manager_buffered.h +++ b/src/theory/inference_manager_buffered.h @@ -35,7 +35,7 @@ class InferenceManagerBuffered : public TheoryInferenceManager InferenceManagerBuffered(Theory& t, TheoryState& state, ProofNodeManager* pnm); - ~InferenceManagerBuffered() {} + virtual ~InferenceManagerBuffered() {} /** * Have we processed an inference during this call to check? In particular, * this returns true if we have a pending fact or lemma, or have encountered @@ -124,6 +124,11 @@ class InferenceManagerBuffered : public TheoryInferenceManager /** Clear pending phase requirements, without processing */ void clearPendingPhaseRequirements(); + /** Returns the number of pending lemmas. */ + std::size_t numPendingLemmas() const; + /** Returns the number of pending facts. */ + std::size_t numPendingFacts() const; + protected: /** A set of pending inferences to be processed as lemmas */ std::vector> d_pendingLem; -- cgit v1.2.3 From 1e93736643667d7b8e4ff9fa5f86596ce1ec31d3 Mon Sep 17 00:00:00 2001 From: Gereon Kremer Date: Wed, 2 Sep 2020 17:21:03 +0200 Subject: Use std::unique_ptr instead of std::shared_ptr for inference manager (#5003) We now use std::unique_ptr instead of std::shared_ptr when storing TheoryInference objects. --- src/theory/arith/inference_manager.cpp | 13 +++++++------ src/theory/arith/inference_manager.h | 4 ++-- src/theory/datatypes/inference_manager.cpp | 2 +- src/theory/inference_manager_buffered.cpp | 11 +++++------ src/theory/inference_manager_buffered.h | 8 ++++---- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/theory/arith/inference_manager.cpp b/src/theory/arith/inference_manager.cpp index f026aa374..bb0bb494e 100644 --- a/src/theory/arith/inference_manager.cpp +++ b/src/theory/arith/inference_manager.cpp @@ -29,7 +29,7 @@ InferenceManager::InferenceManager(TheoryArith& ta, { } -void InferenceManager::addPendingArithLemma(std::shared_ptr lemma, +void InferenceManager::addPendingArithLemma(std::unique_ptr lemma, bool isWaiting) { lemma->d_node = Rewriter::rewrite(lemma->d_node); @@ -55,20 +55,21 @@ void InferenceManager::addPendingArithLemma(std::shared_ptr lemma, } else { - addPendingLemma(std::move(lemma)); + d_pendingLem.emplace_back(std::move(lemma)); } } void InferenceManager::addPendingArithLemma(const ArithLemma& lemma, bool isWaiting) { - addPendingArithLemma(std::make_shared(lemma), isWaiting); + addPendingArithLemma(std::unique_ptr(new ArithLemma(lemma)), + isWaiting); } void InferenceManager::addPendingArithLemma(const Node& lemma, nl::Inference inftype, bool isWaiting) { - addPendingArithLemma(std::make_shared( - lemma, LemmaProperty::NONE, nullptr, inftype), + addPendingArithLemma(std::unique_ptr(new ArithLemma( + lemma, LemmaProperty::NONE, nullptr, inftype)), isWaiting); } @@ -76,7 +77,7 @@ void InferenceManager::flushWaitingLemmas() { for (auto& lem : d_waitingLem) { - addPendingLemma(std::move(lem)); + d_pendingLem.emplace_back(std::move(lem)); } d_waitingLem.clear(); } diff --git a/src/theory/arith/inference_manager.h b/src/theory/arith/inference_manager.h index 3b7190826..1c0678e60 100644 --- a/src/theory/arith/inference_manager.h +++ b/src/theory/arith/inference_manager.h @@ -55,7 +55,7 @@ class InferenceManager : public InferenceManagerBuffered * If isWaiting is true, the lemma is first stored as waiting lemma and only * added as pending lemma when calling flushWaitingLemmas. */ - void addPendingArithLemma(std::shared_ptr lemma, + void addPendingArithLemma(std::unique_ptr lemma, bool isWaiting = false); /** * Add a lemma as pending lemma to the this inference manager. @@ -102,7 +102,7 @@ class InferenceManager : public InferenceManagerBuffered bool isEntailedFalse(const ArithLemma& lem); /** The waiting lemmas. */ - std::vector> d_waitingLem; + std::vector> d_waitingLem; /** cache of all preprocessed lemmas sent on the output channel * (user-context-dependent) */ diff --git a/src/theory/datatypes/inference_manager.cpp b/src/theory/datatypes/inference_manager.cpp index 762cdfd8b..1faf71aa9 100644 --- a/src/theory/datatypes/inference_manager.cpp +++ b/src/theory/datatypes/inference_manager.cpp @@ -97,7 +97,7 @@ void InferenceManager::addPendingInference(Node conc, Node exp, ProofGenerator* pg) { - d_pendingFact.push_back(std::make_shared(conc, exp, pg)); + d_pendingFact.emplace_back(new DatatypesInference(conc, exp, pg)); } void InferenceManager::process() diff --git a/src/theory/inference_manager_buffered.cpp b/src/theory/inference_manager_buffered.cpp index df01b4e93..8d7dd2abc 100644 --- a/src/theory/inference_manager_buffered.cpp +++ b/src/theory/inference_manager_buffered.cpp @@ -50,11 +50,11 @@ void InferenceManagerBuffered::addPendingLemma(Node lem, ProofGenerator* pg) { // make the simple theory lemma - d_pendingLem.push_back(std::make_shared(lem, p, pg)); + d_pendingLem.emplace_back(new SimpleTheoryLemma(lem, p, pg)); } void InferenceManagerBuffered::addPendingLemma( - std::shared_ptr lemma) + std::unique_ptr lemma) { d_pendingLem.emplace_back(std::move(lemma)); } @@ -65,12 +65,11 @@ void InferenceManagerBuffered::addPendingFact(Node conc, { // make a simple theory internal fact Assert(conc.getKind() != AND && conc.getKind() != OR); - d_pendingFact.push_back( - std::make_shared(conc, exp, pg)); + d_pendingFact.emplace_back(new SimpleTheoryInternalFact(conc, exp, pg)); } void InferenceManagerBuffered::addPendingFact( - std::shared_ptr fact) + std::unique_ptr fact) { d_pendingFact.emplace_back(std::move(fact)); } @@ -97,7 +96,7 @@ void InferenceManagerBuffered::doPendingFacts() void InferenceManagerBuffered::doPendingLemmas() { - for (const std::shared_ptr& plem : d_pendingLem) + for (const std::unique_ptr& plem : d_pendingLem) { // process this lemma plem->process(this); diff --git a/src/theory/inference_manager_buffered.h b/src/theory/inference_manager_buffered.h index 762b7d4e0..62c3c9b55 100644 --- a/src/theory/inference_manager_buffered.h +++ b/src/theory/inference_manager_buffered.h @@ -62,7 +62,7 @@ class InferenceManagerBuffered : public TheoryInferenceManager * Add pending lemma, where lemma can be a (derived) class of the * theory inference base class. */ - void addPendingLemma(std::shared_ptr lemma); + void addPendingLemma(std::unique_ptr lemma); /** * Add pending fact, which adds a fact on the pending fact queue. It must * be the case that: @@ -78,7 +78,7 @@ class InferenceManagerBuffered : public TheoryInferenceManager * Add pending fact, where fact can be a (derived) class of the * theory inference base class. */ - void addPendingFact(std::shared_ptr fact); + void addPendingFact(std::unique_ptr fact); /** Add pending phase requirement * * This method is called to indicate this class should send a phase @@ -131,9 +131,9 @@ class InferenceManagerBuffered : public TheoryInferenceManager protected: /** A set of pending inferences to be processed as lemmas */ - std::vector> d_pendingLem; + std::vector> d_pendingLem; /** A set of pending inferences to be processed as facts */ - std::vector> d_pendingFact; + std::vector> d_pendingFact; /** A map from literals to their pending phase requirement */ std::map d_pendingReqPhase; }; -- cgit v1.2.3 From 8d10d1053a0616d8e791219f651b22c10f9039bf Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Wed, 2 Sep 2020 10:56:53 -0500 Subject: (new theory) Update TheoryArrays to the new standard (#5000) This includes using the standard d_conflict flag in TheoryState and splitting its check into 3 callbacks. It also deletes some unused code and eliminates an assertion (line 791 of theory_arrays.cpp) which doesn't hold in a central architecture. Further work on standardization for arrays will add an InferenceManager to guard its uses of asserting facts to equality engine (both for proofs and configurable theory combination). FYI @barrettcw --- src/CMakeLists.txt | 2 - src/theory/arrays/static_fact_manager.cpp | 170 ------------------- src/theory/arrays/static_fact_manager.h | 116 ------------- src/theory/arrays/theory_arrays.cpp | 265 ++++++++++++------------------ src/theory/arrays/theory_arrays.h | 20 ++- 5 files changed, 121 insertions(+), 452 deletions(-) delete mode 100644 src/theory/arrays/static_fact_manager.cpp delete mode 100644 src/theory/arrays/static_fact_manager.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2da04ce66..0ad9526a5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -354,8 +354,6 @@ libcvc4_add_sources( theory/arith/type_enumerator.h theory/arrays/array_info.cpp theory/arrays/array_info.h - theory/arrays/static_fact_manager.cpp - theory/arrays/static_fact_manager.h theory/arrays/theory_arrays.cpp theory/arrays/theory_arrays.h theory/arrays/theory_arrays_rewriter.cpp diff --git a/src/theory/arrays/static_fact_manager.cpp b/src/theory/arrays/static_fact_manager.cpp deleted file mode 100644 index d2f4b75c9..000000000 --- a/src/theory/arrays/static_fact_manager.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/********************* */ -/*! \file static_fact_manager.cpp - ** \verbatim - ** Top contributors (to current version): - ** Clark Barrett, 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 Path-compressing, backtrackable union-find using an undo - ** stack. Refactored from the UF union-find. - ** - ** Path-compressing, backtrackable union-find using an undo stack - ** rather than storing items in a CDMap<>. - **/ - -#include - -#include "base/check.h" -#include "expr/node.h" -#include "theory/arrays/static_fact_manager.h" - -using namespace std; - -namespace CVC4 { -namespace theory { -namespace arrays { - -bool StaticFactManager::areEq(TNode a, TNode b) { - return (find(a) == find(b)); -} - -bool StaticFactManager::areDiseq(TNode a, TNode b) { - Node af = find(a); - Node bf = find(b); - Node left, right; - unsigned i; - for (i = 0; i < d_diseq.size(); ++i) { - left = find(d_diseq[i][0]); - right = find(d_diseq[i][1]); - if ((left == af && right == bf) || - (left == bf && right == af)) { - return true; - } - } - return false; -} - -void StaticFactManager::addDiseq(TNode eq) { - Assert(eq.getKind() == kind::EQUAL); - d_diseq.push_back(eq); -} - -void StaticFactManager::addEq(TNode eq) { - Assert(eq.getKind() == kind::EQUAL); - Node a = find(eq[0]); - Node b = find(eq[1]); - - if( a == b) { - return; - } - - /* - * take care of the congruence closure part - */ - - // make "a" the one with shorter diseqList - // CNodeTNodesMap::iterator deq_ia = d_disequalities.find(a); - // CNodeTNodesMap::iterator deq_ib = d_disequalities.find(b); - - // if(deq_ia != d_disequalities.end()) { - // if(deq_ib == d_disequalities.end() || - // (*deq_ia).second->size() > (*deq_ib).second->size()) { - // TNode tmp = a; - // a = b; - // b = tmp; - // } - // } - // a = find(a); - // b = find(b); - - - // b becomes the canon of a - setCanon(a, b); - - // deq_ia = d_disequalities.find(a); - // map alreadyDiseqs; - // if(deq_ia != d_disequalities.end()) { - // /* - // * Collecting the disequalities of b, no need to check for conflicts - // * since the representative of b does not change and we check all the things - // * in a's class when we look at the diseq list of find(a) - // */ - - // CNodeTNodesMap::iterator deq_ib = d_disequalities.find(b); - // if(deq_ib != d_disequalities.end()) { - // CTNodeListAlloc* deq = (*deq_ib).second; - // for(CTNodeListAlloc::const_iterator j = deq->begin(); j!=deq->end(); - // j++) { - // TNode deqn = *j; - // TNode s = deqn[0]; - // TNode t = deqn[1]; - // TNode sp = find(s); - // TNode tp = find(t); - // Assert(sp == b || tp == b); - // if(sp == b) { - // alreadyDiseqs[tp] = deqn; - // } else { - // alreadyDiseqs[sp] = deqn; - // } - // } - // } - - // /* - // * Looking for conflicts in the a disequality list. Note - // * that at this point a and b are already merged. Also has - // * the side effect that it adds them to the list of b (which - // * became the canonical representative) - // */ - - // CTNodeListAlloc* deqa = (*deq_ia).second; - // for(CTNodeListAlloc::const_iterator i = deqa->begin(); i!= deqa->end(); - // i++) { - // TNode deqn = (*i); - // Assert(deqn.getKind() == kind::EQUAL || deqn.getKind() == - // kind::IFF); TNode s = deqn[0]; TNode t = deqn[1]; TNode sp = find(s); - // TNode tp = find(t); - - // if(find(s) == find(t)) { - // d_conflict = deqn; - // return; - // } - // Assert( sp == b || tp == b); - - // // make sure not to add duplicates - - // if(sp == b) { - // if(alreadyDiseqs.find(tp) == alreadyDiseqs.end()) { - // appendToDiseqList(b, deqn); - // alreadyDiseqs[tp] = deqn; - // } - // } else { - // if(alreadyDiseqs.find(sp) == alreadyDiseqs.end()) { - // appendToDiseqList(b, deqn); - // alreadyDiseqs[sp] = deqn; - // } - // } - - // } - // } - - // // TODO: check for equality propagations - // // a and b are find(a) and find(b) here - // checkPropagations(a,b); - - // if(a.getType().isArray()) { - // checkRowLemmas(a,b); - // checkRowLemmas(b,a); - // // note the change in order, merge info adds the list of - // // the 2nd argument to the first - // d_infoMap.mergeInfo(b, a); - // } -} - - -}/* CVC4::theory::arrays namespace */ -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ diff --git a/src/theory/arrays/static_fact_manager.h b/src/theory/arrays/static_fact_manager.h deleted file mode 100644 index 2df4b0fda..000000000 --- a/src/theory/arrays/static_fact_manager.h +++ /dev/null @@ -1,116 +0,0 @@ -/********************* */ -/*! \file static_fact_manager.h - ** \verbatim - ** Top contributors (to current version): - ** Clark Barrett, Mathias Preiner, Morgan Deters - ** 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 Path-compressing, backtrackable union-find using an undo - ** stack. Refactored from the UF union-find. - ** - ** Path-compressing, backtrackable union-find using an undo stack - ** rather than storing items in a CDMap<>. - **/ - -#include "cvc4_private.h" - -#ifndef CVC4__THEORY__ARRAYS__STATIC_FACT_MANAGER_H -#define CVC4__THEORY__ARRAYS__STATIC_FACT_MANAGER_H - -#include -#include -#include - -#include "expr/node.h" - -namespace CVC4 { -namespace theory { -namespace arrays { - - class StaticFactManager { - /** Our underlying map type. */ - typedef std::unordered_map MapType; - - /** - * Our map of Nodes to their canonical representatives. - * If a Node is not present in the map, it is its own - * representative. - */ - MapType d_map; - std::vector d_diseq; - -public: - StaticFactManager() {} - - /** - * Return a Node's union-find representative, doing path compression. - */ - inline TNode find(TNode n); - - /** - * Return a Node's union-find representative, NOT doing path compression. - * This is useful for Assert() statements, debug checking, and similar - * things that you do NOT want to mutate the structure. - */ - inline TNode debugFind(TNode n) const; - - /** - * Set the canonical representative of n to newParent. They should BOTH - * be their own canonical representatives on entry to this funciton. - */ - inline void setCanon(TNode n, TNode newParent); - - bool areEq(TNode a, TNode b); - bool areDiseq(TNode a, TNode b); - void addDiseq(TNode eq); - void addEq(TNode eq); - -};/* class StaticFactManager<> */ - -inline TNode StaticFactManager::debugFind(TNode n) const { - MapType::const_iterator i = d_map.find(n); - if(i == d_map.end()) { - return n; - } else { - return debugFind((*i).second); - } -} - -inline TNode StaticFactManager::find(TNode n) { - Trace("arraysuf") << "arraysUF find of " << n << std::endl; - MapType::iterator i = d_map.find(n); - if(i == d_map.end()) { - Trace("arraysuf") << "arraysUF it is rep" << std::endl; - return n; - } else { - Trace("arraysuf") << "arraysUF not rep: par is " << (*i).second << std::endl; - std::pair pr = *i; - // our iterator is invalidated by the recursive call to find(), - // since it mutates the map - TNode p = find(pr.second); - if(p == pr.second) { - return p; - } - pr.second = p; - d_map.insert(pr); - return p; - } -} - -inline void StaticFactManager::setCanon(TNode n, TNode newParent) { - Assert(d_map.find(n) == d_map.end()); - Assert(d_map.find(newParent) == d_map.end()); - if(n != newParent) { - d_map[n] = newParent; - } -} - -}/* CVC4::theory::arrays namespace */ -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ - -#endif /*CVC4__THEORY__ARRAYS__STATIC_FACT_MANAGER_H */ diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp index 603dc9639..408f4c682 100644 --- a/src/theory/arrays/theory_arrays.cpp +++ b/src/theory/arrays/theory_arrays.cpp @@ -43,7 +43,6 @@ namespace arrays { // Use static configuration of options for now const bool d_ccStore = false; -const bool d_useArrTable = false; //const bool d_eagerLemmas = false; const bool d_preprocess = true; const bool d_solveWrite = true; @@ -85,7 +84,6 @@ TheoryArrays::TheoryArrays(context::Context* c, d_isPreRegistered(c), d_mayEqualEqualityEngine(c, name + "theory::arrays::mayEqual", true), d_notify(*this), - d_conflict(c, false), d_backtracker(c), d_infoMap(c, &d_backtracker, name), d_mergeQueue(c), @@ -175,10 +173,6 @@ void TheoryArrays::finishInit() { d_equalityEngine->addFunctionKind(kind::STORE); } - if (d_useArrTable) - { - d_equalityEngine->addFunctionKind(kind::ARR_TABLE_FUN); - } } ///////////////////////////////////////////////////////////////////////////// @@ -401,7 +395,8 @@ bool TheoryArrays::propagateLit(TNode literal) << std::endl; // If already in conflict, no more propagation - if (d_conflict) { + if (d_state.isInConflict()) + { Debug("arrays") << spaces(getSatContext()->getLevel()) << "TheoryArrays::propagateLit(" << literal << "): already in conflict" << std::endl; @@ -414,7 +409,7 @@ bool TheoryArrays::propagateLit(TNode literal) } bool ok = d_out->propagate(literal); if (!ok) { - d_conflict = true; + d_state.notifyInConflict(); } return ok; }/* TheoryArrays::propagate(TNode) */ @@ -644,7 +639,8 @@ void TheoryArrays::checkWeakEquiv(bool arraysMerged) { */ void TheoryArrays::preRegisterTermInternal(TNode node) { - if (d_conflict) { + if (d_state.isInConflict()) + { return; } Debug("arrays") << spaces(getSatContext()->getLevel()) << "TheoryArrays::preRegisterTerm(" << node << ")" << std::endl; @@ -788,7 +784,6 @@ void TheoryArrays::preRegisterTermInternal(TNode node) // The may equal needs the node d_mayEqualEqualityEngine.addTerm(node); d_equalityEngine->addTerm(node); - Assert(d_equalityEngine->getSize(node) == 1); } else { d_equalityEngine->addTerm(node); @@ -802,7 +797,6 @@ void TheoryArrays::preRegisterTermInternal(TNode node) // !d_equalityEngine->consistent()); } - void TheoryArrays::preRegisterTerm(TNode node) { preRegisterTermInternal(node); @@ -863,23 +857,6 @@ void TheoryArrays::notifySharedTerm(TNode t) } } - -EqualityStatus TheoryArrays::getEqualityStatus(TNode a, TNode b) { - Assert(d_equalityEngine->hasTerm(a) && d_equalityEngine->hasTerm(b)); - if (d_equalityEngine->areEqual(a, b)) - { - // The terms are implied to be equal - return EQUALITY_TRUE; - } - else if (d_equalityEngine->areDisequal(a, b, false)) - { - // The terms are implied to be dis-equal - return EQUALITY_FALSE; - } - return EQUALITY_UNKNOWN;//FALSE_IN_MODEL; -} - - void TheoryArrays::checkPair(TNode r1, TNode r2) { Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): checking reads " << r1 << " and " << r2 << std::endl; @@ -1061,6 +1038,7 @@ bool TheoryArrays::collectModelValues(TheoryModel* m, NodeManager* nm = NodeManager::currentNM(); // Compute arrays that we need to produce representatives for std::vector arrays; + eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine); for (; !eqcs_i.isFinished(); ++eqcs_i) { Node eqc = (*eqcs_i); @@ -1113,12 +1091,14 @@ bool TheoryArrays::collectModelValues(TheoryModel* m, //} // Loop through all array equivalence classes that need a representative computed - for (size_t i=0; igetRepresentative(n); + for (size_t i = 0; i < arrays.size(); ++i) + { + TNode n = arrays[i]; + TNode nrep = d_equalityEngine->getRepresentative(n); - //if (fullModel) { - // Compute default value for this array - there is one default value for every mayEqual equivalence class + // if (fullModel) { + // Compute default value for this array - there is one default value for + // every mayEqual equivalence class TNode mayRep = d_mayEqualEqualityEngine.getRepresentative(nrep); it = d_defValues.find(mayRep); // If this mayEqual EC doesn't have a default value associated, get the next available default value for the associated array element type @@ -1220,7 +1200,7 @@ Node TheoryArrays::getSkolem(TNode ref, const string& name, const TypeNode& type Node d = skolem.eqNode(ref); Debug("arrays-model-based") << "Asserting skolem equality " << d << endl; d_equalityEngine->assertEquality(d, true, d_true); - Assert(!d_conflict); + Assert(!d_state.isInConflict()); d_skolemAssertions.push_back(d); d_skolemIndex = d_skolemIndex + 1; } @@ -1229,115 +1209,11 @@ Node TheoryArrays::getSkolem(TNode ref, const string& name, const TypeNode& type return skolem; } - -void TheoryArrays::check(Effort e) { - if (done() && !fullEffort(e)) { - return; - } - - getOutputChannel().spendResource(ResourceManager::Resource::TheoryCheckStep); - - TimerStat::CodeTimer checkTimer(d_checkTime); - - while (!done() && !d_conflict) +void TheoryArrays::postCheck(Effort level) +{ + if ((options::arraysEagerLemmas() || fullEffort(level)) + && !d_state.isInConflict() && options::arraysWeakEquivalence()) { - // Get all the assertions - Assertion assertion = get(); - TNode fact = assertion.d_assertion; - - Debug("arrays") << spaces(getSatContext()->getLevel()) << "TheoryArrays::check(): processing " << fact << std::endl; - - bool polarity = fact.getKind() != kind::NOT; - TNode atom = polarity ? fact : fact[0]; - - if (!assertion.d_isPreregistered) - { - if (atom.getKind() == kind::EQUAL) { - if (!d_equalityEngine->hasTerm(atom[0])) - { - Assert(atom[0].isConst()); - d_equalityEngine->addTerm(atom[0]); - } - if (!d_equalityEngine->hasTerm(atom[1])) - { - Assert(atom[1].isConst()); - d_equalityEngine->addTerm(atom[1]); - } - } - } - - // Do the work - switch (fact.getKind()) { - case kind::EQUAL: - d_equalityEngine->assertEquality(fact, true, fact); - break; - case kind::SELECT: - d_equalityEngine->assertPredicate(fact, true, fact); - break; - case kind::NOT: - if (fact[0].getKind() == kind::SELECT) { - d_equalityEngine->assertPredicate(fact[0], false, fact); - } - else if (!d_equalityEngine->areDisequal(fact[0][0], fact[0][1], false)) - { - // Assert the dis-equality - d_equalityEngine->assertEquality(fact[0], false, fact); - - // Apply ArrDiseq Rule if diseq is between arrays - if(fact[0][0].getType().isArray() && !d_conflict) { - if (d_conflict) { Debug("pf::array") << "Entering the skolemization branch" << std::endl; } - - NodeManager* nm = NodeManager::currentNM(); - TypeNode indexType = fact[0][0].getType()[0]; - - TNode k; - // k is the skolem for this disequality. - 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()); - - if (options::arraysPropagate() > 0 && d_equalityEngine->hasTerm(ak) - && d_equalityEngine->hasTerm(bk)) - { - // Propagate witness disequality - might produce a conflict - d_permRef.push_back(lemma); - Debug("pf::array") << "Asserting to the equality engine:" << std::endl - << "\teq = " << eq << std::endl - << "\treason = " << fact << std::endl; - - d_equalityEngine->assertEquality( - eq, false, fact, theory::eq::MERGED_THROUGH_EXT); - ++d_numProp; - } - - // 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); - } - } - break; - default: - Unreachable(); - break; - } - } - - if ((options::arraysEagerLemmas() || fullEffort(e)) && !d_conflict && options::arraysWeakEquivalence()) { // Replay all array merges to update weak equivalence data structures context::CDList::iterator it = d_arrayMerges.begin(), iend = d_arrayMerges.end(); TNode a, b, eq; @@ -1424,10 +1300,13 @@ void TheoryArrays::check(Effort e) { d_readTableContext->pop(); } - if(!options::arraysEagerLemmas() && fullEffort(e) && !d_conflict && !options::arraysWeakEquivalence()) { + if (!options::arraysEagerLemmas() && fullEffort(level) + && !d_state.isInConflict() && !options::arraysWeakEquivalence()) + { // generate the lemmas on the worklist Trace("arrays-lem")<< "Arrays::discharging lemmas. Number of queued lemmas: " << d_RowQueue.size() << "\n"; - while (d_RowQueue.size() > 0 && !d_conflict) { + while (d_RowQueue.size() > 0 && !d_state.isInConflict()) + { if (dischargeLemmas()) { break; } @@ -1437,6 +1316,84 @@ void TheoryArrays::check(Effort e) { Trace("arrays") << spaces(getSatContext()->getLevel()) << "Arrays::check(): done" << endl; } +bool TheoryArrays::preNotifyFact( + TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal) +{ + if (!isPrereg) + { + if (atom.getKind() == kind::EQUAL) + { + if (!d_equalityEngine->hasTerm(atom[0])) + { + Assert(atom[0].isConst()); + d_equalityEngine->addTerm(atom[0]); + } + if (!d_equalityEngine->hasTerm(atom[1])) + { + Assert(atom[1].isConst()); + d_equalityEngine->addTerm(atom[1]); + } + } + } + return false; +} + +void TheoryArrays::notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) +{ + // if a disequality + if (atom.getKind() == kind::EQUAL && !pol) + { + // Apply ArrDiseq Rule if diseq is between arrays + if (fact[0][0].getType().isArray() && !d_state.isInConflict()) + { + NodeManager* nm = NodeManager::currentNM(); + TypeNode indexType = fact[0][0].getType()[0]; + + TNode k; + // k is the skolem for this disequality. + 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); + + 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()); + + if (options::arraysPropagate() > 0 && d_equalityEngine->hasTerm(ak) + && d_equalityEngine->hasTerm(bk)) + { + // Propagate witness disequality - might produce a conflict + d_permRef.push_back(lemma); + Debug("pf::array") << "Asserting to the equality engine:" << std::endl + << "\teq = " << eq << std::endl + << "\treason = " << fact << std::endl; + + d_equalityEngine->assertEquality(eq, false, fact); + ++d_numProp; + } + + // 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); + } + } +} Node TheoryArrays::mkAnd(std::vector& conjunctions, bool invert, unsigned startIndex) { @@ -1641,7 +1598,8 @@ void TheoryArrays::mergeArrays(TNode a, TNode b) } // If no more to do, break - if (d_conflict || d_mergeQueue.empty()) { + if (d_state.isInConflict() || d_mergeQueue.empty()) + { break; } @@ -1865,7 +1823,8 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem) { Debug("pf::array") << "Array solver: queue row lemma called" << std::endl; - if (d_conflict || d_RowAlreadyAdded.contains(lem)) { + if (d_state.isInConflict() || d_RowAlreadyAdded.contains(lem)) + { return; } TNode a, b, i, j; @@ -1892,15 +1851,6 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem) propagate(lem); } - // If equivalent lemma already exists, don't enqueue this one - if (d_useArrTable) { - Node tableEntry = NodeManager::currentNM()->mkNode(kind::ARR_TABLE_FUN, a, b, i, j); - if (d_equalityEngine->getSize(tableEntry) != 1) - { - return; - } - } - // Prefer equality between indexes so as not to introduce new read terms if (options::arraysEagerIndexSplitting() && !bothExist && !d_equalityEngine->areDisequal(i, j, false)) @@ -2025,7 +1975,8 @@ bool TheoryArrays::dischargeLemmas() int prop = options::arraysPropagate(); if (prop > 0) { propagate(l); - if (d_conflict) { + if (d_state.isInConflict()) + { return true; } } @@ -2103,7 +2054,7 @@ void TheoryArrays::conflict(TNode a, TNode b) { d_out->conflict(d_conflictNode); } - d_conflict = true; + d_state.notifyInConflict(); } TheoryArrays::TheoryArraysDecisionStrategy::TheoryArraysDecisionStrategy( diff --git a/src/theory/arrays/theory_arrays.h b/src/theory/arrays/theory_arrays.h index 8fdbde0ab..dea3d4136 100644 --- a/src/theory/arrays/theory_arrays.h +++ b/src/theory/arrays/theory_arrays.h @@ -240,7 +240,6 @@ class TheoryArrays : public Theory { public: void notifySharedTerm(TNode t) override; - EqualityStatus getEqualityStatus(TNode a, TNode b) override; void computeCareGraph() override; bool isShared(TNode t) { @@ -252,6 +251,7 @@ class TheoryArrays : public Theory { ///////////////////////////////////////////////////////////////////////////// public: + /** Collect model values in m based on the relevant terms given by termSet */ bool collectModelValues(TheoryModel* m, const std::set& termSet) override; @@ -267,8 +267,18 @@ class TheoryArrays : public Theory { // MAIN SOLVER ///////////////////////////////////////////////////////////////////////////// - public: - void check(Effort e) override; + //--------------------------------- standard check + /** Post-check, called after the fact queue of the theory is processed. */ + void postCheck(Effort level) override; + /** Pre-notify fact, return true if processed. */ + bool preNotifyFact(TNode atom, + bool pol, + TNode fact, + bool isPrereg, + bool isInternal) override; + /** Notify fact */ + void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override; + //--------------------------------- end standard check private: TNode weakEquivGetRep(TNode node); @@ -331,9 +341,6 @@ class TheoryArrays : public Theory { /** The notify class for d_equalityEngine */ NotifyClass d_notify; - /** Are we in conflict? */ - context::CDO d_conflict; - /** Conflict when merging constants */ void conflict(TNode a, TNode b); @@ -464,7 +471,6 @@ class TheoryArrays : public Theory { * for the comparison between the indexes that appears in the lemma. */ Node getNextDecisionRequest(); - /** * Compute relevant terms. This includes select nodes for the * RIntro1 and RIntro2 rules. -- cgit v1.2.3 From 95bba975fd13261ca8854d9fb30d03fc7447eb80 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Wed, 2 Sep 2020 11:11:48 -0500 Subject: Minor updates to theory inference manager (#5004) These updates are inspired by the current inference manager for sets. --- src/theory/datatypes/theory_datatypes.cpp | 14 +++++------ src/theory/inference_manager_buffered.cpp | 5 ++-- src/theory/theory_inference_manager.cpp | 42 ++++++++++++++++++------------- src/theory/theory_inference_manager.h | 31 +++++++++++++++-------- 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp index 78b6d81c2..5253414a9 100644 --- a/src/theory/datatypes/theory_datatypes.cpp +++ b/src/theory/datatypes/theory_datatypes.cpp @@ -170,7 +170,7 @@ void TheoryDatatypes::postCheck(Effort level) return; } else if (level == EFFORT_FULL && !d_state.isInConflict() - && !d_im.hasAddedLemma() && !d_valuation.needCheck()) + && !d_im.hasSentLemma() && !d_valuation.needCheck()) { //check for cycles Assert(!d_im.hasPendingFact()); @@ -180,11 +180,11 @@ void TheoryDatatypes::postCheck(Effort level) checkCycles(); Trace("datatypes-proc") << "...finish check cycles" << std::endl; d_im.process(); - if (d_state.isInConflict() || d_im.hasAddedLemma()) + if (d_state.isInConflict() || d_im.hasSentLemma()) { return; } - } while (d_im.hasAddedFact()); + } while (d_im.hasSentFact()); //check for splits Trace("datatypes-debug") << "Check for splits " << endl; @@ -329,7 +329,7 @@ void TheoryDatatypes::postCheck(Effort level) } ++eqcs_i; } - if (d_im.hasAddedLemma()) + if (d_im.hasSentLemma()) { // clear pending facts: we added a lemma, so internal inferences are // no longer necessary @@ -342,11 +342,11 @@ void TheoryDatatypes::postCheck(Effort level) Trace("datatypes-debug") << "Flush pending facts..." << std::endl; d_im.process(); } - } while (!d_state.isInConflict() && !d_im.hasAddedLemma() - && d_im.hasAddedFact()); + } while (!d_state.isInConflict() && !d_im.hasSentLemma() + && d_im.hasSentFact()); Trace("datatypes-debug") << "Finished, conflict=" << d_state.isInConflict() - << ", lemmas=" << d_im.hasAddedLemma() << std::endl; + << ", lemmas=" << d_im.hasSentLemma() << std::endl; if (!d_state.isInConflict()) { Trace("dt-model-debug") << std::endl; diff --git a/src/theory/inference_manager_buffered.cpp b/src/theory/inference_manager_buffered.cpp index 8d7dd2abc..8a7713121 100644 --- a/src/theory/inference_manager_buffered.cpp +++ b/src/theory/inference_manager_buffered.cpp @@ -76,8 +76,7 @@ void InferenceManagerBuffered::addPendingFact( void InferenceManagerBuffered::addPendingPhaseRequirement(Node lit, bool pol) { - // must ensure rewritten - lit = Rewriter::rewrite(lit); + // it is the responsibility of the caller to ensure lit is rewritten d_pendingReqPhase[lit] = pol; } @@ -109,7 +108,7 @@ void InferenceManagerBuffered::doPendingPhaseRequirements() // process the pending require phase calls for (const std::pair& prp : d_pendingReqPhase) { - d_out.requirePhase(prp.first, prp.second); + requirePhase(prp.first, prp.second); } d_pendingReqPhase.clear(); } diff --git a/src/theory/theory_inference_manager.cpp b/src/theory/theory_inference_manager.cpp index 3abe530f1..9405a8162 100644 --- a/src/theory/theory_inference_manager.cpp +++ b/src/theory/theory_inference_manager.cpp @@ -221,41 +221,41 @@ bool TheoryInferenceManager::hasCachedLemma(TNode lem, LemmaProperty p) return d_lemmasSent.find(lem) != d_lemmasSent.end(); } -uint32_t TheoryInferenceManager::numAddedLemmas() const +uint32_t TheoryInferenceManager::numSentLemmas() const { return d_numCurrentLemmas; } -bool TheoryInferenceManager::hasAddedLemma() const +bool TheoryInferenceManager::hasSentLemma() const { return d_numCurrentLemmas != 0; } -void TheoryInferenceManager::assertInternalFact(TNode atom, bool pol, TNode exp) +bool TheoryInferenceManager::assertInternalFact(TNode atom, bool pol, TNode exp) { - processInternalFact(atom, pol, PfRule::UNKNOWN, {exp}, {}, nullptr); + return processInternalFact(atom, pol, PfRule::UNKNOWN, {exp}, {}, nullptr); } -void TheoryInferenceManager::assertInternalFact(TNode atom, +bool TheoryInferenceManager::assertInternalFact(TNode atom, bool pol, PfRule id, const std::vector& exp, const std::vector& args) { Assert(id != PfRule::UNKNOWN); - processInternalFact(atom, pol, id, exp, args, nullptr); + return processInternalFact(atom, pol, id, exp, args, nullptr); } -void TheoryInferenceManager::assertInternalFact(TNode atom, +bool TheoryInferenceManager::assertInternalFact(TNode atom, bool pol, const std::vector& exp, ProofGenerator* pg) { Assert(pg != nullptr); - processInternalFact(atom, pol, PfRule::ASSUME, exp, {}, pg); + return processInternalFact(atom, pol, PfRule::ASSUME, exp, {}, pg); } -void TheoryInferenceManager::processInternalFact(TNode atom, +bool TheoryInferenceManager::processInternalFact(TNode atom, bool pol, PfRule id, const std::vector& exp, @@ -267,8 +267,9 @@ void TheoryInferenceManager::processInternalFact(TNode atom, // call the pre-notify fact method with preReg = false, isInternal = true if (d_theory.preNotifyFact(atom, pol, expn, false, true)) { - // handled in a theory-specific way that doesn't require equality engine - return; + // Handled in a theory-specific way that doesn't require equality engine, + // notice we return true, indicating that the fact was processed. + return true; } Assert(d_ee != nullptr); Trace("infer-manager") << "TheoryInferenceManager::assertInternalFact: " @@ -276,15 +277,16 @@ void TheoryInferenceManager::processInternalFact(TNode atom, d_numCurrentFacts++; // Now, assert the fact. How to do so depends on whether proofs are enabled. // If no proof production, or no proof rule was given + bool ret = false; if (d_pfee == nullptr || id == PfRule::UNKNOWN) { if (atom.getKind() == kind::EQUAL) { - d_ee->assertEquality(atom, pol, expn); + ret = d_ee->assertEquality(atom, pol, expn); } else { - d_ee->assertPredicate(atom, pol, expn); + ret = d_ee->assertPredicate(atom, pol, expn); } // Must reference count the equality and its explanation, which is not done // by the equality engine. Notice that we do *not* need to do this for @@ -304,18 +306,19 @@ void TheoryInferenceManager::processInternalFact(TNode atom, if (pg != nullptr) { // use the proof generator interface - d_pfee->assertFact(lit, expn, pg); + ret = d_pfee->assertFact(lit, expn, pg); } else { // use the explict proof step interface - d_pfee->assertFact(lit, id, expn, args); + ret = d_pfee->assertFact(lit, id, expn, args); } } // call the notify fact method with isInternal = true d_theory.notifyFact(atom, pol, expn, true); Trace("infer-manager") << "TheoryInferenceManager::finished assertInternalFact" << std::endl; + return ret; } void TheoryInferenceManager::explain(TNode n, std::vector& assumptions) @@ -361,12 +364,12 @@ Node TheoryInferenceManager::mkExplainPartial( return NodeManager::currentNM()->mkAnd(assumps); } -uint32_t TheoryInferenceManager::numAddedFacts() const +uint32_t TheoryInferenceManager::numSentFacts() const { return d_numCurrentFacts; } -bool TheoryInferenceManager::hasAddedFact() const +bool TheoryInferenceManager::hasSentFact() const { return d_numCurrentFacts != 0; } @@ -381,5 +384,10 @@ bool TheoryInferenceManager::cacheLemma(TNode lem, LemmaProperty p) return true; } +void TheoryInferenceManager::requirePhase(TNode n, bool pol) +{ + return d_out.requirePhase(n, pol); +} + } // namespace theory } // namespace CVC4 diff --git a/src/theory/theory_inference_manager.h b/src/theory/theory_inference_manager.h index 2ddcd0985..7e5ef6dec 100644 --- a/src/theory/theory_inference_manager.h +++ b/src/theory/theory_inference_manager.h @@ -214,9 +214,9 @@ class TheoryInferenceManager */ virtual bool hasCachedLemma(TNode lem, LemmaProperty p); /** The number of lemmas we have sent since the last call to reset */ - uint32_t numAddedLemmas() const; + uint32_t numSentLemmas() const; /** Have we added a lemma since the last call to reset? */ - bool hasAddedLemma() const; + bool hasSentLemma() const; //--------------------------------------- internal facts /** * Assert internal fact. This is recommended method for asserting "internal" @@ -229,8 +229,10 @@ class TheoryInferenceManager * @param atom The atom of the fact to assert * @param pol Its polarity * @param exp Its explanation, i.e. ( exp => (~) atom ) is valid. + * @return true if the fact was processed, i.e. it was asserted to the + * equality engine or preNotifyFact returned true. */ - void assertInternalFact(TNode atom, bool pol, TNode exp); + bool assertInternalFact(TNode atom, bool pol, TNode exp); /** * Assert internal fact, with a proof step justification. Notice that if * proofs are not enabled in this inference manager, then this asserts @@ -241,8 +243,10 @@ class TheoryInferenceManager * @param id The proof rule identifier of the proof step * @param exp Its explanation, interpreted as a conjunction * @param args The arguments of the proof step + * @return true if the fact was processed, i.e. it was asserted to the + * equality engine or preNotifyFact returned true. */ - void assertInternalFact(TNode atom, + bool assertInternalFact(TNode atom, bool pol, PfRule id, const std::vector& exp, @@ -257,22 +261,29 @@ class TheoryInferenceManager * @param pg The proof generator for this step. If non-null, pg must be able * to provide a proof concluding (~) atom from free asumptions in exp in * the remainder of the current SAT context. + * @return true if the fact was processed, i.e. it was asserted to the + * equality engine or preNotifyFact returned true. */ - void assertInternalFact(TNode atom, + bool assertInternalFact(TNode atom, bool pol, const std::vector& exp, ProofGenerator* pg); /** The number of internal facts we have added since the last call to reset */ - uint32_t numAddedFacts() const; + uint32_t numSentFacts() const; /** Have we added a internal fact since the last call to reset? */ - bool hasAddedFact() const; - + bool hasSentFact() const; + //--------------------------------------- phase requirements + /** + * Set that literal n has SAT phase requirement pol, that is, it should be + * decided with polarity pol, for details see OutputChannel::requirePhase. + */ + void requirePhase(TNode n, bool pol); protected: /** * Process internal fact. This is a common helper method for the - * assertInternalFact variants above. + * assertInternalFact variants above. Returns true if the fact was processed. */ - void processInternalFact(TNode atom, + bool processInternalFact(TNode atom, bool pol, PfRule id, const std::vector& exp, -- cgit v1.2.3 From dd912a03113bbc5ad93260babba061362b660acd Mon Sep 17 00:00:00 2001 From: Abdalrhman Mohamed <32971963+abdoo8080@users.noreply.github.com> Date: Wed, 2 Sep 2020 11:50:41 -0500 Subject: Introduce an internal version of Commands. (#4988) This PR is a step towards the migration of Commands to the public API. Node versions of some Commands are introduced for internal use (as necessary). The DumpManager is refactored to make use of those commands. --- src/CMakeLists.txt | 2 + src/printer/ast/ast_printer.cpp | 3 +- src/printer/ast/ast_printer.h | 2 +- src/printer/cvc/cvc_printer.cpp | 30 ++++--- src/printer/cvc/cvc_printer.h | 2 +- src/printer/printer.cpp | 8 +- src/printer/printer.h | 6 +- src/printer/smt2/smt2_printer.cpp | 31 +++---- src/printer/smt2/smt2_printer.h | 4 +- src/printer/tptp/tptp_printer.cpp | 13 +-- src/printer/tptp/tptp_printer.h | 2 +- src/smt/dump.h | 16 ++++ src/smt/dump_manager.cpp | 16 ++-- src/smt/dump_manager.h | 14 +-- src/smt/listeners.cpp | 19 ++-- src/smt/model.cpp | 4 +- src/smt/model.h | 4 +- src/smt/node_command.cpp | 180 ++++++++++++++++++++++++++++++++++++++ src/smt/node_command.h | 157 +++++++++++++++++++++++++++++++++ src/smt/smt_engine.cpp | 13 ++- 20 files changed, 448 insertions(+), 78 deletions(-) create mode 100644 src/smt/node_command.cpp create mode 100644 src/smt/node_command.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0ad9526a5..692ae09ac 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -210,6 +210,8 @@ libcvc4_add_sources( smt/model_core_builder.h smt/model_blocker.cpp smt/model_blocker.h + smt/node_command.cpp + smt/node_command.h smt/options_manager.cpp smt/options_manager.h smt/quant_elim_solver.cpp diff --git a/src/printer/ast/ast_printer.cpp b/src/printer/ast/ast_printer.cpp index d4f28c186..f235721f1 100644 --- a/src/printer/ast/ast_printer.cpp +++ b/src/printer/ast/ast_printer.cpp @@ -26,6 +26,7 @@ #include "options/language.h" // for LANG_AST #include "printer/dagification_visitor.h" #include "smt/command.h" +#include "smt/node_command.h" #include "theory/substitutions.h" using namespace std; @@ -156,7 +157,7 @@ void AstPrinter::toStream(std::ostream& out, const Model& m) const void AstPrinter::toStream(std::ostream& out, const Model& m, - const Command* c) const + const NodeCommand* c) const { // shouldn't be called; only the non-Command* version above should be Unreachable(); diff --git a/src/printer/ast/ast_printer.h b/src/printer/ast/ast_printer.h index 17e052037..969240930 100644 --- a/src/printer/ast/ast_printer.h +++ b/src/printer/ast/ast_printer.h @@ -175,7 +175,7 @@ class AstPrinter : public CVC4::Printer void toStream(std::ostream& out, TNode n, int toDepth, bool types) const; void toStream(std::ostream& out, const Model& m, - const Command* c) const override; + const NodeCommand* c) const override; }; /* class AstPrinter */ } // namespace ast diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp index 89b516511..b94977cfe 100644 --- a/src/printer/cvc/cvc_printer.cpp +++ b/src/printer/cvc/cvc_printer.cpp @@ -33,6 +33,7 @@ #include "options/smt_options.h" #include "printer/dagification_visitor.h" #include "smt/command.h" +#include "smt/node_command.h" #include "smt/smt_engine.h" #include "theory/arrays/theory_arrays_rewriter.h" #include "theory/substitutions.h" @@ -1059,11 +1060,11 @@ void CvcPrinter::toStream(std::ostream& out, const CommandStatus* s) const namespace { -void DeclareTypeCommandToStream(std::ostream& out, - const theory::TheoryModel& model, - const DeclareTypeCommand& command) +void DeclareTypeNodeCommandToStream(std::ostream& out, + const theory::TheoryModel& model, + const DeclareTypeNodeCommand& command) { - TypeNode type_node = TypeNode::fromType(command.getType()); + TypeNode type_node = command.getType(); const std::vector* type_reps = model.getRepSet()->getTypeRepsOrNull(type_node); if (options::modelUninterpDtEnum() && type_node.isSort() @@ -1104,11 +1105,12 @@ void DeclareTypeCommandToStream(std::ostream& out, } } -void DeclareFunctionCommandToStream(std::ostream& out, - const theory::TheoryModel& model, - const DeclareFunctionCommand& command) +void DeclareFunctionNodeCommandToStream( + std::ostream& out, + const theory::TheoryModel& model, + const DeclareFunctionNodeCommand& command) { - Node n = Node::fromExpr(command.getFunction()); + Node n = command.getFunction(); if (n.getKind() == kind::SKOLEM) { // don't print out internal stuff @@ -1172,23 +1174,23 @@ void CvcPrinter::toStream(std::ostream& out, const Model& m) const void CvcPrinter::toStream(std::ostream& out, const Model& model, - const Command* command) const + const NodeCommand* command) const { const auto* theory_model = dynamic_cast(&model); AlwaysAssert(theory_model != nullptr); if (const auto* declare_type_command = - dynamic_cast(command)) + dynamic_cast(command)) { - DeclareTypeCommandToStream(out, *theory_model, *declare_type_command); + DeclareTypeNodeCommandToStream(out, *theory_model, *declare_type_command); } else if (const auto* dfc = - dynamic_cast(command)) + dynamic_cast(command)) { - DeclareFunctionCommandToStream(out, *theory_model, *dfc); + DeclareFunctionNodeCommandToStream(out, *theory_model, *dfc); } else { - out << command << std::endl; + out << *command << std::endl; } } diff --git a/src/printer/cvc/cvc_printer.h b/src/printer/cvc/cvc_printer.h index 0fd3d3a49..3c61fb74f 100644 --- a/src/printer/cvc/cvc_printer.h +++ b/src/printer/cvc/cvc_printer.h @@ -177,7 +177,7 @@ class CvcPrinter : public CVC4::Printer std::ostream& out, TNode n, int toDepth, bool types, bool bracket) const; void toStream(std::ostream& out, const Model& m, - const Command* c) const override; + const NodeCommand* c) const override; bool d_cvc3Mode; }; /* class CvcPrinter */ diff --git a/src/printer/printer.cpp b/src/printer/printer.cpp index 0e7550518..d13fc55f1 100644 --- a/src/printer/printer.cpp +++ b/src/printer/printer.cpp @@ -23,6 +23,7 @@ #include "printer/cvc/cvc_printer.h" #include "printer/smt2/smt2_printer.h" #include "printer/tptp/tptp_printer.h" +#include "smt/node_command.h" using namespace std; @@ -72,9 +73,10 @@ unique_ptr Printer::makePrinter(OutputLanguage lang) void Printer::toStream(std::ostream& out, const Model& m) const { for(size_t i = 0; i < m.getNumCommands(); ++i) { - const Command* cmd = m.getCommand(i); - const DeclareFunctionCommand* dfc = dynamic_cast(cmd); - if (dfc != NULL && !m.isModelCoreSymbol(dfc->getFunction())) + const NodeCommand* cmd = m.getCommand(i); + const DeclareFunctionNodeCommand* dfc = + dynamic_cast(cmd); + if (dfc != NULL && !m.isModelCoreSymbol(dfc->getFunction().toExpr())) { continue; } diff --git a/src/printer/printer.h b/src/printer/printer.h index 3b737ec5f..8c95e3e9b 100644 --- a/src/printer/printer.h +++ b/src/printer/printer.h @@ -30,6 +30,8 @@ namespace CVC4 { +class NodeCommand; + class Printer { public: @@ -271,13 +273,13 @@ class Printer /** write model response to command */ virtual void toStream(std::ostream& out, const Model& m, - const Command* c) const = 0; + const NodeCommand* c) const = 0; /** write model response to command using another language printer */ void toStreamUsing(OutputLanguage lang, std::ostream& out, const Model& m, - const Command* c) const + const NodeCommand* c) const { getPrinter(lang)->toStream(out, m, c); } diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp index 3d76c81dc..da0423956 100644 --- a/src/printer/smt2/smt2_printer.cpp +++ b/src/printer/smt2/smt2_printer.cpp @@ -31,11 +31,12 @@ #include "options/printer_options.h" #include "options/smt_options.h" #include "printer/dagification_visitor.h" +#include "smt/node_command.h" #include "smt/smt_engine.h" #include "smt_util/boolean_simplification.h" #include "theory/arrays/theory_arrays_rewriter.h" -#include "theory/quantifiers/quantifiers_attributes.h" #include "theory/datatypes/sygus_datatype_utils.h" +#include "theory/quantifiers/quantifiers_attributes.h" #include "theory/substitutions.h" #include "theory/theory_model.h" #include "util/smt2_quote_string.h" @@ -1331,23 +1332,23 @@ void Smt2Printer::toStream(std::ostream& out, const Model& m) const void Smt2Printer::toStream(std::ostream& out, const Model& model, - const Command* command) const + const NodeCommand* command) const { const theory::TheoryModel* theory_model = dynamic_cast(&model); AlwaysAssert(theory_model != nullptr); - if (const DeclareTypeCommand* dtc = - dynamic_cast(command)) + if (const DeclareTypeNodeCommand* dtc = + dynamic_cast(command)) { // print out the DeclareTypeCommand - Type t = (*dtc).getType(); - if (!t.isSort()) + TypeNode tn = dtc->getType(); + if (!tn.isSort()) { out << (*dtc) << endl; } else { - std::vector elements = theory_model->getDomainElements(t); + std::vector elements = theory_model->getDomainElements(tn.toType()); if (options::modelUninterpDtEnum()) { if (isVariant_2_6(d_variant)) @@ -1367,7 +1368,7 @@ void Smt2Printer::toStream(std::ostream& out, else { // print the cardinality - out << "; cardinality of " << t << " is " << elements.size() << endl; + out << "; cardinality of " << tn << " is " << elements.size() << endl; out << (*dtc) << endl; // print the representatives for (const Expr& type_ref : elements) @@ -1375,7 +1376,7 @@ void Smt2Printer::toStream(std::ostream& out, Node trn = Node::fromExpr(type_ref); if (trn.isVar()) { - out << "(declare-fun " << quoteSymbol(trn) << " () " << t << ")" + out << "(declare-fun " << quoteSymbol(trn) << " () " << tn << ")" << endl; } else @@ -1386,11 +1387,11 @@ void Smt2Printer::toStream(std::ostream& out, } } } - else if (const DeclareFunctionCommand* dfc = - dynamic_cast(command)) + else if (const DeclareFunctionNodeCommand* dfc = + dynamic_cast(command)) { // print out the DeclareFunctionCommand - Node n = Node::fromExpr((*dfc).getFunction()); + Node n = dfc->getFunction(); if ((*dfc).getPrintInModelSetByUser()) { if (!(*dfc).getPrintInModel()) @@ -1432,10 +1433,10 @@ void Smt2Printer::toStream(std::ostream& out, out << ")" << endl; } } - else if (const DatatypeDeclarationCommand* datatype_declaration_command = - dynamic_cast(command)) + else if (const DeclareDatatypeNodeCommand* declare_datatype_command = + dynamic_cast(command)) { - out << datatype_declaration_command; + out << *declare_datatype_command; } else { diff --git a/src/printer/smt2/smt2_printer.h b/src/printer/smt2/smt2_printer.h index 6b57823a4..0cf06dd6b 100644 --- a/src/printer/smt2/smt2_printer.h +++ b/src/printer/smt2/smt2_printer.h @@ -19,8 +19,6 @@ #ifndef CVC4__PRINTER__SMT2_PRINTER_H #define CVC4__PRINTER__SMT2_PRINTER_H -#include - #include "printer/printer.h" namespace CVC4 { @@ -234,7 +232,7 @@ class Smt2Printer : public CVC4::Printer std::ostream& out, TNode n, int toDepth, bool types, TypeNode nt) const; void toStream(std::ostream& out, const Model& m, - const Command* c) const override; + const NodeCommand* c) const override; void toStream(std::ostream& out, const SExpr& sexpr) const; void toStream(std::ostream& out, const DType& dt) const; diff --git a/src/printer/tptp/tptp_printer.cpp b/src/printer/tptp/tptp_printer.cpp index c4623f76a..d25666d70 100644 --- a/src/printer/tptp/tptp_printer.cpp +++ b/src/printer/tptp/tptp_printer.cpp @@ -20,12 +20,13 @@ #include #include -#include "expr/expr.h" // for ExprSetDepth etc.. -#include "expr/node_manager.h" // for VarNameAttr -#include "options/language.h" // for LANG_AST -#include "options/smt_options.h" // for unsat cores -#include "smt/smt_engine.h" +#include "expr/expr.h" // for ExprSetDepth etc.. +#include "expr/node_manager.h" // for VarNameAttr +#include "options/language.h" // for LANG_AST +#include "options/smt_options.h" // for unsat cores #include "smt/command.h" +#include "smt/node_command.h" +#include "smt/smt_engine.h" using namespace std; @@ -59,7 +60,7 @@ void TptpPrinter::toStream(std::ostream& out, const Model& m) const void TptpPrinter::toStream(std::ostream& out, const Model& m, - const Command* c) const + const NodeCommand* c) const { // shouldn't be called; only the non-Command* version above should be Unreachable(); diff --git a/src/printer/tptp/tptp_printer.h b/src/printer/tptp/tptp_printer.h index 6682b495e..9377a8895 100644 --- a/src/printer/tptp/tptp_printer.h +++ b/src/printer/tptp/tptp_printer.h @@ -47,7 +47,7 @@ class TptpPrinter : public CVC4::Printer private: void toStream(std::ostream& out, const Model& m, - const Command* c) const override; + const NodeCommand* c) const override; }; /* class TptpPrinter */ diff --git a/src/smt/dump.h b/src/smt/dump.h index 050935422..4c0efeb6e 100644 --- a/src/smt/dump.h +++ b/src/smt/dump.h @@ -21,6 +21,7 @@ #include "base/output.h" #include "smt/command.h" +#include "smt/node_command.h" namespace CVC4 { @@ -40,6 +41,20 @@ class CVC4_PUBLIC CVC4dumpstream return *this; } + /** A convenience function for dumping internal commands. + * + * Since Commands are now part of the public API, internal code should use + * NodeCommands and this function (instead of the one above) to dump them. + */ + CVC4dumpstream& operator<<(const NodeCommand& nc) + { + if (d_os != nullptr) + { + (*d_os) << nc << std::endl; + } + return *this; + } + private: std::ostream* d_os; }; /* class CVC4dumpstream */ @@ -56,6 +71,7 @@ class CVC4_PUBLIC CVC4dumpstream CVC4dumpstream() {} CVC4dumpstream(std::ostream& os) {} CVC4dumpstream& operator<<(const Command& c) { return *this; } + CVC4dumpstream& operator<<(const NodeCommand& nc) { return *this; } }; /* class CVC4dumpstream */ #endif /* CVC4_DUMPING && !CVC4_MUZZLE */ diff --git a/src/smt/dump_manager.cpp b/src/smt/dump_manager.cpp index d5fd65c4c..033be405f 100644 --- a/src/smt/dump_manager.cpp +++ b/src/smt/dump_manager.cpp @@ -51,7 +51,7 @@ void DumpManager::finishInit() void DumpManager::resetAssertions() { d_modelGlobalCommands.clear(); } -void DumpManager::addToModelCommandAndDump(const Command& c, +void DumpManager::addToModelCommandAndDump(const NodeCommand& c, uint32_t flags, bool userVisible, const char* dumpTag) @@ -70,14 +70,14 @@ void DumpManager::addToModelCommandAndDump(const Command& c, { if (flags & ExprManager::VAR_FLAG_GLOBAL) { - d_modelGlobalCommands.push_back(std::unique_ptr(c.clone())); + d_modelGlobalCommands.push_back(std::unique_ptr(c.clone())); } else { - Command* cc = c.clone(); + NodeCommand* cc = c.clone(); d_modelCommands.push_back(cc); // also remember for memory management purposes - d_modelCommandsAlloc.push_back(std::unique_ptr(cc)); + d_modelCommandsAlloc.push_back(std::unique_ptr(cc)); } } if (Dump.isOn(dumpTag)) @@ -88,7 +88,7 @@ void DumpManager::addToModelCommandAndDump(const Command& c, } else { - d_dumpCommands.push_back(std::unique_ptr(c.clone())); + d_dumpCommands.push_back(std::unique_ptr(c.clone())); } } } @@ -96,7 +96,7 @@ void DumpManager::addToModelCommandAndDump(const Command& c, void DumpManager::setPrintFuncInModel(Node f, bool p) { Trace("setp-model") << "Set printInModel " << f << " to " << p << std::endl; - for (std::unique_ptr& c : d_modelGlobalCommands) + for (std::unique_ptr& c : d_modelGlobalCommands) { DeclareFunctionCommand* dfc = dynamic_cast(c.get()); @@ -109,7 +109,7 @@ void DumpManager::setPrintFuncInModel(Node f, bool p) } } } - for (Command* c : d_modelCommands) + for (NodeCommand* c : d_modelCommands) { DeclareFunctionCommand* dfc = dynamic_cast(c); if (dfc != NULL) @@ -128,7 +128,7 @@ size_t DumpManager::getNumModelCommands() const return d_modelCommands.size() + d_modelGlobalCommands.size(); } -const Command* DumpManager::getModelCommand(size_t i) const +const NodeCommand* DumpManager::getModelCommand(size_t i) const { Assert(i < getNumModelCommands()); // index the global commands first, then the locals diff --git a/src/smt/dump_manager.h b/src/smt/dump_manager.h index 6f2ee37a1..2ce0570e4 100644 --- a/src/smt/dump_manager.h +++ b/src/smt/dump_manager.h @@ -22,7 +22,7 @@ #include "context/cdlist.h" #include "expr/node.h" -#include "smt/command.h" +#include "smt/node_command.h" namespace CVC4 { namespace smt { @@ -36,7 +36,7 @@ namespace smt { */ class DumpManager { - typedef context::CDList CommandList; + typedef context::CDList CommandList; public: DumpManager(context::UserContext* u); @@ -54,7 +54,7 @@ class DumpManager * Add to Model command. This is used for recording a command * that should be reported during a get-model call. */ - void addToModelCommandAndDump(const Command& c, + void addToModelCommandAndDump(const NodeCommand& c, uint32_t flags = 0, bool userVisible = true, const char* dumpTag = "declarations"); @@ -66,7 +66,7 @@ class DumpManager /** get number of commands to report in a model */ size_t getNumModelCommands() const; /** get model command at index i */ - const Command* getModelCommand(size_t i) const; + const NodeCommand* getModelCommand(size_t i) const; private: /** Fully inited */ @@ -77,7 +77,7 @@ class DumpManager * regardless of push/pop). Only maintained if produce-models option * is on. */ - std::vector> d_modelGlobalCommands; + std::vector> d_modelGlobalCommands; /** * A list of commands that should be in the Model locally (i.e., @@ -89,7 +89,7 @@ class DumpManager * A list of model commands allocated to d_modelCommands at any time. This * is maintained for memory management purposes. */ - std::vector> d_modelCommandsAlloc; + std::vector> d_modelCommandsAlloc; /** * A vector of declaration commands waiting to be dumped out. @@ -97,7 +97,7 @@ class DumpManager * This ensures the declarations come after the set-logic and * any necessary set-option commands are dumped. */ - std::vector> d_dumpCommands; + std::vector> d_dumpCommands; }; } // namespace smt diff --git a/src/smt/listeners.cpp b/src/smt/listeners.cpp index 539d6ba2f..52ddcf156 100644 --- a/src/smt/listeners.cpp +++ b/src/smt/listeners.cpp @@ -18,7 +18,7 @@ #include "expr/expr.h" #include "expr/node_manager_attributes.h" #include "options/smt_options.h" -#include "smt/command.h" +#include "smt/node_command.h" #include "smt/dump.h" #include "smt/dump_manager.h" #include "smt/smt_engine.h" @@ -40,7 +40,7 @@ SmtNodeManagerListener::SmtNodeManagerListener(DumpManager& dm) : d_dm(dm) {} void SmtNodeManagerListener::nmNotifyNewSort(TypeNode tn, uint32_t flags) { - DeclareTypeCommand c(tn.getAttribute(expr::VarNameAttr()), 0, tn.toType()); + DeclareTypeNodeCommand c(tn.getAttribute(expr::VarNameAttr()), 0, tn); if ((flags & ExprManager::SORT_FLAG_PLACEHOLDER) == 0) { d_dm.addToModelCommandAndDump(c, flags); @@ -50,9 +50,9 @@ void SmtNodeManagerListener::nmNotifyNewSort(TypeNode tn, uint32_t flags) void SmtNodeManagerListener::nmNotifyNewSortConstructor(TypeNode tn, uint32_t flags) { - DeclareTypeCommand c(tn.getAttribute(expr::VarNameAttr()), - tn.getAttribute(expr::SortArityAttr()), - tn.toType()); + DeclareTypeNodeCommand c(tn.getAttribute(expr::VarNameAttr()), + tn.getAttribute(expr::SortArityAttr()), + tn); if ((flags & ExprManager::SORT_FLAG_PLACEHOLDER) == 0) { d_dm.addToModelCommandAndDump(c); @@ -68,17 +68,16 @@ void SmtNodeManagerListener::nmNotifyNewDatatypes( for (const TypeNode& dt : dtts) { Assert(dt.isDatatype()); - types.push_back(dt.toType()); } - DatatypeDeclarationCommand c(types); + DeclareDatatypeNodeCommand c(dtts); d_dm.addToModelCommandAndDump(c); } } void SmtNodeManagerListener::nmNotifyNewVar(TNode n, uint32_t flags) { - DeclareFunctionCommand c( - n.getAttribute(expr::VarNameAttr()), n.toExpr(), n.getType().toType()); + DeclareFunctionNodeCommand c( + n.getAttribute(expr::VarNameAttr()), n, n.getType()); if ((flags & ExprManager::VAR_FLAG_DEFINED) == 0) { d_dm.addToModelCommandAndDump(c, flags); @@ -90,7 +89,7 @@ void SmtNodeManagerListener::nmNotifyNewSkolem(TNode n, uint32_t flags) { std::string id = n.getAttribute(expr::VarNameAttr()); - DeclareFunctionCommand c(id, n.toExpr(), n.getType().toType()); + DeclareFunctionNodeCommand c(id, n, n.getType()); if (Dump.isOn("skolems") && comment != "") { Dump("skolems") << CommentCommand(id + " is " + comment); diff --git a/src/smt/model.cpp b/src/smt/model.cpp index 7924698ff..a23b885ff 100644 --- a/src/smt/model.cpp +++ b/src/smt/model.cpp @@ -19,8 +19,8 @@ #include "expr/expr_iomanip.h" #include "options/base_options.h" #include "printer/printer.h" -#include "smt/command.h" #include "smt/dump_manager.h" +#include "smt/node_command.h" #include "smt/smt_engine.h" #include "smt/smt_engine_scope.h" @@ -42,7 +42,7 @@ size_t Model::getNumCommands() const return d_smt.getDumpManager()->getNumModelCommands(); } -const Command* Model::getCommand(size_t i) const +const NodeCommand* Model::getCommand(size_t i) const { return d_smt.getDumpManager()->getModelCommand(i); } diff --git a/src/smt/model.h b/src/smt/model.h index 8f4409b07..4c28704c3 100644 --- a/src/smt/model.h +++ b/src/smt/model.h @@ -25,7 +25,7 @@ namespace CVC4 { -class Command; +class NodeCommand; class SmtEngine; class Model; @@ -48,7 +48,7 @@ class Model { /** get number of commands to report */ size_t getNumCommands() const; /** get command */ - const Command* getCommand(size_t i) const; + const NodeCommand* getCommand(size_t i) const; /** get the smt engine that this model is hooked up to */ SmtEngine* getSmtEngine() { return &d_smt; } /** get the smt engine (as a pointer-to-const) that this model is hooked up to */ diff --git a/src/smt/node_command.cpp b/src/smt/node_command.cpp new file mode 100644 index 000000000..265b35b3e --- /dev/null +++ b/src/smt/node_command.cpp @@ -0,0 +1,180 @@ +/********************* */ +/*! \file node_command.cpp + ** \verbatim + ** Top contributors (to current version): + ** Abdalrhman Mohamed + ** 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 Implementation of NodeCommand functions. + ** + ** Implementation of NodeCommand functions. + **/ + +#include "smt/node_command.h" + +#include "printer/printer.h" + +namespace CVC4 { + +/* -------------------------------------------------------------------------- */ +/* class NodeCommand */ +/* -------------------------------------------------------------------------- */ + +NodeCommand::~NodeCommand() {} + +std::string NodeCommand::toString() const +{ + std::stringstream ss; + toStream(ss); + return ss.str(); +} + +std::ostream& operator<<(std::ostream& out, const NodeCommand& nc) +{ + nc.toStream(out, + Node::setdepth::getDepth(out), + Node::printtypes::getPrintTypes(out), + Node::dag::getDag(out), + Node::setlanguage::getLanguage(out)); + return out; +} + +/* -------------------------------------------------------------------------- */ +/* class DeclareFunctionNodeCommand */ +/* -------------------------------------------------------------------------- */ + +DeclareFunctionNodeCommand::DeclareFunctionNodeCommand(const std::string& id, + Node expr, + TypeNode type) + : d_id(id), + d_fun(expr), + d_type(type), + d_printInModel(true), + d_printInModelSetByUser(false) +{ +} + +void DeclareFunctionNodeCommand::toStream(std::ostream& out, + int toDepth, + bool types, + size_t dag, + OutputLanguage language) const +{ + Printer::getPrinter(language)->toStreamCmdDeclareFunction(out, d_id, d_type); +} + +NodeCommand* DeclareFunctionNodeCommand::clone() const +{ + return new DeclareFunctionNodeCommand(d_id, d_fun, d_type); +} + +const Node& DeclareFunctionNodeCommand::getFunction() const { return d_fun; } + +bool DeclareFunctionNodeCommand::getPrintInModel() const +{ + return d_printInModel; +} + +bool DeclareFunctionNodeCommand::getPrintInModelSetByUser() const +{ + return d_printInModelSetByUser; +} + +void DeclareFunctionNodeCommand::setPrintInModel(bool p) +{ + d_printInModel = p; + d_printInModelSetByUser = true; +} + +/* -------------------------------------------------------------------------- */ +/* class DeclareTypeNodeCommand */ +/* -------------------------------------------------------------------------- */ + +DeclareTypeNodeCommand::DeclareTypeNodeCommand(const std::string& id, + size_t arity, + TypeNode type) + : d_id(id), d_arity(arity), d_type(type) +{ +} + +void DeclareTypeNodeCommand::toStream(std::ostream& out, + int toDepth, + bool types, + size_t dag, + OutputLanguage language) const +{ + Printer::getPrinter(language)->toStreamCmdDeclareType( + out, d_id, d_arity, d_type); +} + +NodeCommand* DeclareTypeNodeCommand::clone() const +{ + return new DeclareTypeNodeCommand(d_id, d_arity, d_type); +} + +const std::string DeclareTypeNodeCommand::getSymbol() const { return d_id; } + +const TypeNode& DeclareTypeNodeCommand::getType() const { return d_type; } + +/* -------------------------------------------------------------------------- */ +/* class DeclareDatatypeNodeCommand */ +/* -------------------------------------------------------------------------- */ + +DeclareDatatypeNodeCommand::DeclareDatatypeNodeCommand( + const std::vector& datatypes) + : d_datatypes(datatypes) +{ +} + +void DeclareDatatypeNodeCommand::toStream(std::ostream& out, + int toDepth, + bool types, + size_t dag, + OutputLanguage language) const +{ + Printer::getPrinter(language)->toStreamCmdDatatypeDeclaration(out, + d_datatypes); +} + +NodeCommand* DeclareDatatypeNodeCommand::clone() const +{ + return new DeclareDatatypeNodeCommand(d_datatypes); +} + +/* -------------------------------------------------------------------------- */ +/* class DefineFunctionNodeCommand */ +/* -------------------------------------------------------------------------- */ + +DefineFunctionNodeCommand::DefineFunctionNodeCommand( + const std::string& id, + Node fun, + const std::vector& formals, + Node formula) + : d_id(id), d_fun(fun), d_formals(formals), d_formula(formula) +{ +} + +void DefineFunctionNodeCommand::toStream(std::ostream& out, + int toDepth, + bool types, + size_t dag, + OutputLanguage language) const +{ + Printer::getPrinter(language)->toStreamCmdDefineFunction( + out, + d_fun.toString(), + d_formals, + d_fun.getType().getRangeType(), + d_formula); +} + +NodeCommand* DefineFunctionNodeCommand::clone() const +{ + return new DefineFunctionNodeCommand(d_id, d_fun, d_formals, d_formula); +} + +} // namespace CVC4 diff --git a/src/smt/node_command.h b/src/smt/node_command.h new file mode 100644 index 000000000..2ca166bb6 --- /dev/null +++ b/src/smt/node_command.h @@ -0,0 +1,157 @@ +/********************* */ +/*! \file node_command.h + ** \verbatim + ** Top contributors (to current version): + ** Abdalrhman Mohamed + ** 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 Datastructures used for printing commands internally. + ** + ** Datastructures used for printing commands internally. + **/ + +#include "cvc4_private.h" + +#ifndef CVC4__SMT__NODE_COMMAND_H +#define CVC4__SMT__NODE_COMMAND_H + +#include + +#include "expr/node.h" +#include "expr/type_node.h" +#include "options/language.h" + +namespace CVC4 { + +/** + * A node version of Command. DO NOT use this version unless there is a need + * to buffer commands for later use (e.g., printing models). + */ +class NodeCommand +{ + public: + /** Destructor */ + virtual ~NodeCommand(); + + /** Print this NodeCommand to output stream */ + virtual void toStream( + std::ostream& out, + int toDepth = -1, + bool types = false, + size_t dag = 1, + OutputLanguage language = language::output::LANG_AUTO) const = 0; + + /** Get a string representation of this NodeCommand */ + std::string toString() const; + + /** Clone this NodeCommand (make a shallow copy). */ + virtual NodeCommand* clone() const = 0; +}; + +std::ostream& operator<<(std::ostream& out, const NodeCommand& nc); + +/** + * Declare n-ary function symbol. + * SMT-LIB: ( declare-fun ( ) ) + */ +class DeclareFunctionNodeCommand : public NodeCommand +{ + public: + DeclareFunctionNodeCommand(const std::string& id, Node fun, TypeNode type); + void toStream( + std::ostream& out, + int toDepth = -1, + bool types = false, + size_t dag = 1, + OutputLanguage language = language::output::LANG_AUTO) const override; + NodeCommand* clone() const override; + const Node& getFunction() const; + bool getPrintInModel() const; + bool getPrintInModelSetByUser() const; + void setPrintInModel(bool p); + + private: + std::string d_id; + Node d_fun; + TypeNode d_type; + bool d_printInModel; + bool d_printInModelSetByUser; +}; + +/** + * Create datatype sort. + * SMT-LIB: ( declare-datatypes ( {n+1} ) ( {n+1} ) ) + */ +class DeclareDatatypeNodeCommand : public NodeCommand +{ + public: + DeclareDatatypeNodeCommand(const std::vector& datatypes); + void toStream( + std::ostream& out, + int toDepth = -1, + bool types = false, + size_t dag = 1, + OutputLanguage language = language::output::LANG_AUTO) const override; + NodeCommand* clone() const override; + + private: + std::vector d_datatypes; +}; + +/** + * Declare uninterpreted sort. + * SMT-LIB: ( declare-sort ) + */ +class DeclareTypeNodeCommand : public NodeCommand +{ + public: + DeclareTypeNodeCommand(const std::string& id, size_t arity, TypeNode type); + void toStream( + std::ostream& out, + int toDepth = -1, + bool types = false, + size_t dag = 1, + OutputLanguage language = language::output::LANG_AUTO) const override; + NodeCommand* clone() const override; + const std::string getSymbol() const; + const TypeNode& getType() const; + + private: + std::string d_id; + size_t d_arity; + TypeNode d_type; +}; + +/** + * Define n-ary function. + * SMT-LIB: ( define-fun ( ) ) + */ +class DefineFunctionNodeCommand : public NodeCommand +{ + public: + DefineFunctionNodeCommand(const std::string& id, + Node fun, + const std::vector& formals, + Node formula); + void toStream( + std::ostream& out, + int toDepth = -1, + bool types = false, + size_t dag = 1, + OutputLanguage language = language::output::LANG_AUTO) const override; + NodeCommand* clone() const override; + + private: + std::string d_id; + Node d_fun; + std::vector d_formals; + Node d_formula; +}; + +} // namespace CVC4 + +#endif /* CVC4__SMT__NODE_COMMAND_H */ diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp index 531dbff0d..81d4f594d 100644 --- a/src/smt/smt_engine.cpp +++ b/src/smt/smt_engine.cpp @@ -688,9 +688,18 @@ void SmtEngine::defineFunction(Expr func, ss << language::SetLanguage( language::SetLanguage::getLanguage(Dump.getStream())) << func; - DefineFunctionCommand c(ss.str(), func, formals, formula, global); + std::vector nFormals; + nFormals.reserve(formals.size()); + + for (const Expr& formal : formals) + { + nFormals.push_back(formal.getNode()); + } + + DefineFunctionNodeCommand nc( + ss.str(), func.getNode(), nFormals, formula.getNode()); d_dumpm->addToModelCommandAndDump( - c, ExprManager::VAR_FLAG_DEFINED, true, "declarations"); + nc, ExprManager::VAR_FLAG_DEFINED, true, "declarations"); // type check body debugCheckFunctionBody(formula, formals, func); -- cgit v1.2.3 From 254c0391d9186221bc3b8c63687cc30a06b14f1b Mon Sep 17 00:00:00 2001 From: "Andrew V. Jones" Date: Wed, 2 Sep 2020 18:17:32 +0100 Subject: Migrating from using the 'glpk-cut-log' repo to using an official GPLK release + a set of patches (#4775) This PR attempts to migrate from @timothy-king's repo for glpk-cut-log to using a set of patches against the official release that 'glpk-cut-log' was based off of (4.52). This is in preparation of trying to rework these patches to be against the latest GPLK release (4.65). If we can do this, then it makes it easier for CVC4's dependancy on GPLK to be able to follow upstream (rather than being stuck on a release that is 6.5 years old!). I have added GPLK as an option for CI, but I do not know if we actually want this. My concern with adding this to CI is that we're then not testing non-GPL builds, which doesn't seem ideal. However, before starting to rework the patches to be against 4.65, I want to make sure that things are actually working/stable against 4.52; so having at least one CI target that does use GPLK would be great. Signed-off-by: Andrew V. Jones andrew.jones@vector.com --- contrib/get-glpk-cut-log | 13 +- contrib/glpk-cut-log.patch | 1528 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1539 insertions(+), 2 deletions(-) create mode 100644 contrib/glpk-cut-log.patch diff --git a/contrib/get-glpk-cut-log b/contrib/get-glpk-cut-log index 16acf97ae..951e10620 100755 --- a/contrib/get-glpk-cut-log +++ b/contrib/get-glpk-cut-log @@ -2,15 +2,24 @@ # source "$(dirname "$0")/get-script-header.sh" +# get the full path to the contrib dir; needs to be the full path so we can +# refer the patch from within the 'glpk-cut-log' build directory +contrib_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd -P)" + +# Get the full path the patch we wish to apply +patch_file=${contrib_dir}/glpk-cut-log.patch + GLPK_DIR="$DEPS_DIR/glpk-cut-log" -commit=b420454e732f4b3d229c552ef7cd46fec75fe65c +version="4.52" check_dep_dir "$GLPK_DIR" setup_dep \ - "https://github.com/timothy-king/glpk-cut-log/archive/$commit.tar.gz" \ + "https://ftp.gnu.org/gnu/glpk/glpk-${version}.tar.gz" \ "$GLPK_DIR" cd "$GLPK_DIR" +patch -p1 < ${patch_file} + libtoolize aclocal autoheader diff --git a/contrib/glpk-cut-log.patch b/contrib/glpk-cut-log.patch new file mode 100644 index 000000000..9ef01886c --- /dev/null +++ b/contrib/glpk-cut-log.patch @@ -0,0 +1,1528 @@ +@@ This patch is taken from https://github.com/timothy-king/glpk-cut-log and +@@ has the following license: +@@ +@@ GLPK is free software: you can redistribute it and/or modify it under the +@@ terms of the GNU General Public License as published by the Free Software +@@ Foundation, either version 3 of the License, or (at your option) any later +@@ version. +@@ +From cf84e3855d8c5676557daaca434b42b2fc17dc29 Mon Sep 17 00:00:00 2001 +From: Tim King +Date: Sat, 14 Dec 2013 16:03:35 -0500 +Subject: [PATCH] Adding a function for returning the iteration count. + +Adding GLP_ICUTADDED callback: +- Adds a new callback location that is called after every cut is added to the pool. +- During this callback users can request a copy of this cut and query what kind of cut it is. +- GMI cuts also support returning what row in the tableau it came from. Users can use this to replay how the cut was generated. + +Logging MIR Cuts +- Changed the IOSAUX to be defined as a linear sum of input rows. + This is visible from the interface +- Logging the multipliers used to create the aggregate row in MIR. +- Logging the delta selected by final successful cmir_sep call. +- Logging the cset selected by final successful cmir_sep call. +- The delta and cset are not yet user visible. + +The extra mir logging information is now user visible. + +Adding GLP_ICUTSELECT callback: +- ios_process_cuts marks the cuts as selected after turning the cut into a row. +- This callback happens after ios_process_cuts marks and before the pool is + cleared by ios_clear_pool. + +Cleaning up the git directory to not track autogenerated files. + +Branch logging +- Adds to the integer interface a callback function for when branches are made. + This is called after branch_on. +- Added a public function glp_ios_branch_log. + This returns the structural variable for the branch as well as the value + branched on, and the ids of the nodes for the down and up branches. + If both branches are infeasible, the ids are -1 for both dn and up. + If one branch is infeasible (and no branch is done), this returns -1 for + the infeasible branch and the current node id for the up branch. +- Each node now has a unique ordinal associated with it. +- Added a public function to convert the id of an active node to the unique + node ordinal. +- Added a callback for when a node is closed due to being linearly infeasible. + +Improved the mir cut logging facilities to now include: +- the rid id used for virtual lower/upper bound selection, +- and the subst map, +- Changed the size of the cset array to be the same as the new arrays (m+n) +- Fixed a bug in returning the cset selected. + +Fixing a bug selecting the correct branch. + +Added a callback for tracking row deletion. + +Adding notes to node freeze and revive functions. + +Commenting out a few debugging printfs for gomory cuts. + +Changing an overly aggressive assert in MIR generate when an assignment is outside of the bounds to skipping the application of the mir rule. + +Removing some printfs. + +Weakening assert to a failure. + +Adding a stability failure limit to simplex. + +Updating the installation instructions. + +--- +diff --git a/configure.ac b/configure.ac +index 0141a8a..ffb9ae4 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1,7 +1,7 @@ + dnl Process this file with autoconf to produce a configure script + + AC_INIT([GLPK], [4.52], [bug-glpk@gnu.org]) +- ++AM_INIT_AUTOMAKE([subdir-objects]) + AC_CONFIG_SRCDIR([src/glpk.h]) + + AC_CONFIG_MACRO_DIR([m4]) +diff --git a/src/Makefile.am b/src/Makefile.am +index b39efa6..2a025bc 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -20,7 +20,10 @@ libglpk_la_LDFLAGS = \ + -version-info 36:0:1 \ + -export-symbols-regex '^glp_*' + ++ ++# all of the cut log sources are listed first + libglpk_la_SOURCES = \ ++cutlog01.c \ + glpapi01.c \ + glpapi02.c \ + glpapi03.c \ +diff --git a/src/cutlog01.c b/src/cutlog01.c +new file mode 100644 +index 0000000..9a85bb7 +--- /dev/null ++++ b/src/cutlog01.c +@@ -0,0 +1,452 @@ ++/* cutlog01.c (api extension routines) */ ++ ++ ++#include "glpapi.h" ++#include "glpios.h" ++ ++int glp_get_it_cnt(glp_prob *P){ ++ if(P == NULL){ ++ return 0; ++ }else{ ++ return P->it_cnt; ++ } ++} ++ ++int glp_ios_get_cut(glp_tree *T, int i, int* ind, double* val, int* klass, int* type, double* rhs){ ++ xassert(T != NULL); ++ ++ IOSCUT* cut; ++ int len; ++ IOSAIJ* aij; ++ glp_prob* prob; ++ ++ if (T->reason != GLP_ICUTADDED){ ++ xerror("glp_ios_get_cut: not called during cut added.\n"); ++ } ++ cut = ios_find_row(T->local, i); ++ if ( cut == NULL ) { ++ xerror("glp_ios_get_cut: called with an invalid index."); ++ } ++ len = 0; ++ for(len = 0, aij = cut->ptr; aij != NULL; aij = aij->next) ++ { ++ len++; ++ if(ind != NULL){ ind[len] = aij->j; } ++ if(val != NULL){ val[len] = aij->val; } ++ } ++ if(klass != NULL){ *klass = cut->klass; } ++ if(type != NULL){ *type = cut->type; } ++ if(rhs != NULL){ *rhs = cut->rhs; } ++ return len; ++} ++ ++ ++IOSAUX *ios_create_aux(int n, const int rows[], const double coeffs[]){ ++ IOSAUX *aux; ++ int i; ++ aux = xmalloc(sizeof(IOSAUX)); ++ aux->nrows = n; ++ aux->rows = xcalloc(1+n, sizeof(int)); ++ aux->mult = xcalloc(1+n, sizeof(double)); ++ aux->selected = -1; ++ aux->mir_cset = NULL; ++ ++ for ( i = 1; i <= n; i++) ++ { aux->rows[i] = rows[i]; ++ aux->mult[i] = coeffs[i]; ++ } ++ ++ return aux; ++} ++ ++void ios_delete_aux(IOSAUX *aux){ ++ xassert(aux != NULL); ++ xfree(aux->rows); ++ xfree(aux->mult); ++ if( aux->mir_cset != NULL ){ ++ xfree(aux->mir_cset); ++ xfree(aux->mir_subst); ++ xfree(aux->mir_vlb_rows); ++ xfree(aux->mir_vub_rows); ++ } ++ xfree(aux); ++ return; ++} ++ ++static void cut_set_aux(IOSCUT *cut, int n, ++ const int rows[], const double coeffs[]){ ++ int i; ++ xassert( cut != NULL ); ++ if( cut->aux != NULL ) { ++ ios_delete_aux(cut-> aux); ++ } ++ ++ cut->aux = ios_create_aux(n, rows, coeffs); ++ xassert( cut->aux->nrows == n ); ++} ++ ++static void cut_set_aux_mir(IOSAUX *aux, double delta, int m, int n, ++ const char cset[], const char subst[], ++ const int vlbrs[], const int vubrs[]){ ++ int i; ++ xassert( aux != NULL ); ++ if ( aux->mir_cset != NULL ) ++ { xfree(aux->mir_cset); ++ xfree(aux->mir_subst); ++ xfree(aux->mir_vlb_rows); ++ xfree(aux->mir_vub_rows); ++ } ++ ++ aux->mir_cset = xcalloc(1+n+m, sizeof(char)); ++ aux->mir_subst = xcalloc(1+n+m, sizeof(char)); ++ aux->mir_vlb_rows = xcalloc(1+n+m, sizeof(int)); ++ aux->mir_vub_rows = xcalloc(1+n+m, sizeof(int)); ++ ++ for ( i = 1; i <= n+m; i++) ++ { aux->mir_cset[i] = cset[i]; ++ aux->mir_subst[i] = subst[i]; ++ aux->mir_vlb_rows[i] = vlbrs[i]; ++ aux->mir_vub_rows[i] = vubrs[i]; ++ } ++ ++ aux->mir_delta = delta; ++} ++ ++void ios_cut_set_aux_mir(glp_tree *T, int ord, double delta, ++ const char cset[], const char subst[], ++ const int vlbrs[], const int vubrs[]){ ++ int m, n; ++ IOSCUT *cut; ++ glp_prob *mip; ++ mip = T->mip; ++ m = mip->m; ++ n = mip->n; ++ cut = ios_find_row(T->local, ord); ++ xassert(cut != NULL); ++ cut_set_aux_mir(cut->aux, delta, m, n, cset, subst, vlbrs, vubrs); ++} ++ ++void ios_cut_set_single_aux(glp_tree *T, int ord, int j){ ++ IOSCUT *cut; ++ cut = ios_find_row(T->local, ord); ++ xassert(cut != NULL); ++ ++ /* set up arrays */ ++ int ind[1+1]; ++ double coeffs[1+1]; ++ ind[1] = j; ++ coeffs[1] = +1.0; ++ ++ /* call general procedure */ ++ cut_set_aux(cut, 1, ind, coeffs); ++} ++ ++void ios_cut_set_aux(glp_tree *T, int ord, int n, ++ const int rows[], const double coeffs[]){ ++ IOSCUT *cut; ++ cut = ios_find_row(T->local, ord); ++ xassert(cut != NULL); ++ cut_set_aux(cut, n, rows, coeffs); ++} ++ ++int glp_ios_cut_get_aux_nrows(glp_tree *tree, int ord){ ++ IOSCUT *cut; ++ IOSAUX *aux; ++ if (tree->reason != GLP_ICUTADDED){ ++ xerror("glp_ios_cut_get_aux_nrows: not called during cut added.\n"); ++ } ++ cut = ios_find_row(tree->local, ord); ++ if ( cut == NULL ){ ++ xerror("glp_ios_cut_get_aux_nrows: not called on a valid cut.\n"); ++ } ++ aux = cut->aux; ++ return (aux == NULL) ? 0 : aux->nrows; ++} ++ ++void glp_ios_cut_get_aux_rows(glp_tree *tree, int ord, ++ int rows[], double coeffs[]){ ++ IOSCUT *cut; ++ IOSAUX *aux; ++ int j, nrows; ++ if (tree->reason != GLP_ICUTADDED){ ++ xerror("glp_ios_cut_get_aux_rows: not called during cut added.\n"); ++ } ++ cut = ios_find_row(tree->local, ord); ++ if ( cut == NULL ){ ++ xerror("glp_ios_cut_get_aux_rows: not called on a valid cut.\n"); ++ } ++ aux = cut->aux; ++ if( aux != NULL ){ ++ nrows = aux->nrows; ++ for ( j = 1; j <= nrows; j++ ) ++ { if ( rows != NULL ) { rows[j] = aux->rows[j]; } ++ if ( coeffs != NULL ) { coeffs[j] = aux->mult[j]; } ++ } ++ } ++ return; ++} ++ ++ ++void glp_ios_cut_get_mir_subst(glp_tree *tree, int ord, char subst[]); ++/* gets mir cut substition information. */ ++void glp_ios_cut_get_mir_virtual_rows(glp_tree *tree, int ord, ++ int vlb[], int vub[]); ++/* gets mir cut virtual bounds rows. */ ++ ++void glp_ios_cut_get_mir_cset(glp_tree *tree, int ord, char *cset){ ++ glp_prob *mip; ++ IOSCUT *cut; ++ IOSAUX *aux; ++ int j, n, m; ++ if ( tree->reason != GLP_ICUTADDED ){ ++ xerror("glp_ios_cut_get_aux_mir: not called during cut added.\n"); ++ } ++ cut = ios_find_row(tree->local, ord); ++ if ( cut == NULL ){ ++ xerror("glp_ios_cut_get_aux_mir: not called on a cut.\n"); ++ } ++ if ( cut->klass != GLP_RF_MIR ){ ++ xerror("glp_ios_cut_get_aux_mir: not called on a mir cut.\n"); ++ } ++ aux = cut->aux; ++ mip = tree->mip; ++ m = mip->m; ++ n = mip->n; ++ ++ if( cset != NULL ){ ++ for ( j=1; j <= n+m; j++ ){ ++ cset[j] = (aux->mir_cset == NULL) ? 0 : aux->mir_cset[j]; ++ } ++ } ++} ++void glp_ios_cut_get_mir_subst(glp_tree *tree, int ord, char *subst){ ++ glp_prob *mip; ++ IOSCUT *cut; ++ IOSAUX *aux; ++ int j, n, m; ++ if ( tree->reason != GLP_ICUTADDED ){ ++ xerror("glp_ios_cut_get_aux_mir: not called during cut added.\n"); ++ } ++ cut = ios_find_row(tree->local, ord); ++ if ( cut == NULL ){ ++ xerror("glp_ios_cut_get_aux_mir: not called on a cut.\n"); ++ } ++ if ( cut->klass != GLP_RF_MIR ){ ++ xerror("glp_ios_cut_get_aux_mir: not called on a mir cut.\n"); ++ } ++ aux = cut->aux; ++ mip = tree->mip; ++ m = mip->m; ++ n = mip->n; ++ ++ if( subst != NULL ){ ++ for ( j=1; j <= n+m; j++ ){ ++ subst[j] = (aux->mir_subst == NULL) ? 0 : aux->mir_subst[j]; ++ } ++ } ++} ++void glp_ios_cut_get_mir_virtual_rows(glp_tree *tree, int ord, int vlb_rows[], int vub_rows[]){ ++ glp_prob *mip; ++ IOSCUT *cut; ++ IOSAUX *aux; ++ int j, n, m; ++ if ( tree->reason != GLP_ICUTADDED ){ ++ xerror("glp_ios_cut_get_aux_mir: not called during cut added.\n"); ++ } ++ cut = ios_find_row(tree->local, ord); ++ if ( cut == NULL ){ ++ xerror("glp_ios_cut_get_aux_mir: not called on a cut.\n"); ++ } ++ if ( cut->klass != GLP_RF_MIR ){ ++ xerror("glp_ios_cut_get_aux_mir: not called on a mir cut.\n"); ++ } ++ aux = cut->aux; ++ mip = tree->mip; ++ m = mip->m; ++ n = mip->n; ++ ++ for ( j=1; j <= n+m; j++ ){ ++ vlb_rows[j] = (aux->mir_vlb_rows == NULL) ? 0 : aux->mir_vlb_rows[j]; ++ vub_rows[j] = (aux->mir_vub_rows == NULL) ? 0 : aux->mir_vub_rows[j]; ++ } ++} ++double glp_ios_cut_get_mir_delta(glp_tree *tree, int ord){ ++ glp_prob *mip; ++ IOSCUT *cut; ++ IOSAUX *aux; ++ int j, n, m; ++ if ( tree->reason != GLP_ICUTADDED ){ ++ xerror("glp_ios_cut_get_aux_mir: not called during cut added.\n"); ++ } ++ cut = ios_find_row(tree->local, ord); ++ if ( cut == NULL ){ ++ xerror("glp_ios_cut_get_aux_mir: not called on a cut.\n"); ++ } ++ if ( cut->klass != GLP_RF_MIR ){ ++ xerror("glp_ios_cut_get_aux_mir: not called on a mir cut.\n"); ++ } ++ aux = cut->aux; ++ return aux->mir_delta; ++} ++ ++ ++void ios_cut_set_selected(IOSCUT *cut, int sel){ ++#ifdef CUT_DEBUG ++ static int i = 0; ++ ++i; ++ printf("ios_cut_set_selected: %d %d %p\n", i, sel, cut); ++#endif ++ ++ IOSAUX *aux; ++ aux = cut->aux; ++ if ( aux != NULL ){ ++ aux->selected = sel; ++ } ++} ++ ++int glp_ios_selected_cuts(glp_tree *tree, int ords[], int sel[]){ ++ int len, j, N, s; ++ IOSPOOL* pool; ++ IOSCUT* cut; ++ IOSAUX* aux; ++ if ( tree == NULL ){ ++ xerror("glp_ios_selected_cuts: not called with a valid tree.\n"); ++ } ++ if ( tree->reason != GLP_ICUTSELECT ){ ++ xerror("glp_ios_selected_cuts: not called during cut selected.\n"); ++ } ++ ++ pool = tree->local; ++ if ( pool == NULL ){ ++ xerror("glp_ios_selected_cuts: called on a malformed tree.\n"); ++ } ++ ++ for (len = 0, j = 1, cut = pool->head; cut != NULL; cut = cut->next, j++) ++ { aux = cut->aux; ++#ifdef CUT_DEBUG ++ printf("glp_ios_selected_cuts: %d %p\n", j, cut); ++#endif ++ if ( aux != NULL ) ++ { s = aux->selected; ++ if ( s >= 0 ) ++ { len++; ++ if (ords != NULL) { ords[len] = j; } ++ if (sel != NULL) { sel[len] = s; } ++ } ++ } ++ } ++ return len; ++} ++ ++int glp_ios_branch_log(glp_tree *tree, double *br_val, int* parent, int* dn, int* up){ ++ IOSNPD *node; ++ int br_result, br_var; ++ int p, d, u; ++ double v; ++ glp_prob *mip; ++ if ( tree == NULL ){ ++ xerror("glp_ios_branch_log: not called with a valid tree \n"); ++ } ++ if ( tree->reason != GLP_LI_BRANCH ){ ++ xerror("glp_ios_branch_log: not called during GLP_LI_BRANCH \n"); ++ } ++ mip = tree->mip; ++ if ( mip == NULL ){ ++ xerror("glp_ios_branch_log: not called with a valid tree\n"); ++ } ++ br_result = tree->br_result; ++ br_var = tree->br_var; ++ switch(br_result){ ++ case 0: ++ p = tree->br_node; ++ node = tree->slot[p].node; ++ break; ++ case 1: ++ case 2: ++ node = tree->curr; ++ p = node->p; ++ break; ++ default: ++ xerror("glp_ios_branch_log: br_result is not properly set \n"); ++ } ++ if( node == NULL ){ ++ xerror("glp_ios_branch_log: not called with a valid tree \n"); ++ } ++ switch(br_result){ ++ case 0: ++ v = node->br_val; ++ d = tree->dn_child; ++ u = tree->up_child; ++ break; ++ case 1: ++ v = mip->col[br_var]->prim; ++ if(tree->br_to_up){ ++ d = -1; ++ u = p; ++ }else{ ++ d = p; ++ u = -1; ++ } ++ break; ++ case 2: ++ v = mip->col[br_var]->prim; ++ d = -1; ++ u = -1; ++ break; ++ default: ++ xerror("glp_ios_branch_log: not called with a valid tree \n"); ++ } ++ ++ if(br_val != NULL){ *br_val = v; } ++ if(parent != NULL){ *parent = p; } ++ if(dn != NULL){ *dn = d; } ++ if(up != NULL){ *up = u; } ++ ++ return br_var; ++} ++ ++int glp_ios_node_ord(glp_tree *tree, int p){ ++ IOSNPD *node; ++ if ( tree == NULL ){ ++ xerror("glp_ios_node_ord: not called with a valid tree.\n"); ++ } ++ if (!(1 <= p && p <= tree->nslots)){ ++ xerror("glp_ios_node_ord: not called with a valid p.\n"); ++ } ++ node = tree->slot[p].node; ++ return node->ord; ++} ++ ++void ios_cb_rows_deleted(glp_tree *T, int n, const int* rows){ ++ if (T->parm->cb_func != NULL) ++ { ++ xassert(T->reason == 0); ++ xassert(T->deleting_rows == NULL); ++ xassert(T->num_deleting_rows == 0); ++ T->num_deleting_rows = n; ++ T->deleting_rows = rows; ++ ++ T->reason = GLP_LI_DELROW; ++ T->parm->cb_func(T, T->parm->cb_info); ++ T->reason = 0; ++ T->num_deleting_rows = 0; ++ T->deleting_rows = NULL; ++ } ++} ++ ++int glp_ios_rows_deleted(glp_tree *tree, int* rows){ ++ if ( tree == NULL ){ ++ xerror("glp_ios_rows_deleted: not called with a valid tree.\n"); ++ } ++ if ( tree->reason != GLP_LI_DELROW ){ ++ xerror("glp_ios_rows_deleted: not called with a valid reason.\n"); ++ } ++ ++ int j; ++ if(rows != NULL){ ++ for(j=1; j <= tree->num_deleting_rows; j++){ ++ rows[j] = tree->deleting_rows[j]; ++ } ++ } ++ return tree->num_deleting_rows; ++} +diff --git a/src/glpapi06.c b/src/glpapi06.c +index 743d6be..05d0498 100644 +--- a/src/glpapi06.c ++++ b/src/glpapi06.c +@@ -488,6 +488,7 @@ void glp_init_smcp(glp_smcp *parm) + parm->out_frq = 500; + parm->out_dly = 0; + parm->presolve = GLP_OFF; ++ parm->stability_lmt = 200; + return; + } + +diff --git a/src/glpapi13.c b/src/glpapi13.c +index 926dda4..55adf44 100644 +--- a/src/glpapi13.c ++++ b/src/glpapi13.c +@@ -453,8 +453,14 @@ void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr) + + int glp_ios_pool_size(glp_tree *tree) + { /* determine current size of the cut pool */ +- if (tree->reason != GLP_ICUTGEN) +- xerror("glp_ios_pool_size: operation not allowed\n"); ++ switch(tree->reason) ++ { case GLP_ICUTGEN: ++ case GLP_ICUTADDED: ++ case GLP_ICUTSELECT: ++ break; ++ default: ++ xerror("glp_ios_pool_size: operation not allowed\n"); ++ } + xassert(tree->local != NULL); + return tree->local->size; + } +diff --git a/src/glpios.h b/src/glpios.h +index 9e2d6b2..3b31901 100644 +--- a/src/glpios.h ++++ b/src/glpios.h +@@ -36,6 +36,9 @@ typedef struct IOSAIJ IOSAIJ; + typedef struct IOSPOOL IOSPOOL; + typedef struct IOSCUT IOSCUT; + ++ ++typedef struct IOSAUX IOSAUX; ++ + struct glp_tree + { /* branch-and-bound tree */ + int magic; +@@ -217,6 +220,19 @@ struct glp_tree + GLP_NO_BRNCH - use general selection technique */ + int child; + /* subproblem reference number corresponding to br_sel */ ++ ++ /* start of cut log extras */ ++ int br_result; ++ int br_to_up; ++ int br_node; ++ /* subproblem reference number for the just branched node.*/ ++ int dn_child; ++ /* subproblem reference number for the just created down node */ ++ int up_child; ++ /* subproblem reference number for the just created up node */ ++ ++ const int* deleting_rows; ++ int num_deleting_rows; + }; + + struct IOSLOT +@@ -229,6 +245,8 @@ struct IOSLOT + + struct IOSNPD + { /* node subproblem descriptor */ ++ int ord; ++ /* this is a unique ordinal for each subproblem */ + int p; + /* subproblem reference number (it is the index to corresponding + slot, i.e. slot[p] points to this descriptor) */ +@@ -393,12 +411,51 @@ struct IOSCUT + GLP_FX: sum a[j] * x[j] = b */ + double rhs; + /* cut right-hand side */ ++ ++ IOSAUX *aux; ++ /* cut auxillary source information */ ++ + IOSCUT *prev; + /* pointer to previous cut */ + IOSCUT *next; + /* pointer to next cut */ + }; + ++struct IOSAUX ++{ ++ /* aux (auxillary source information for each cut) ++ * Each cut operates on a sum of rows ++ * Each cut operates on a row that can be described using ++ * a current row or a previous cut. ++ * To generalize, we assume each row is a sum of two rows: ++ * row[r]* r_mult + pool[c] * c_mult ++ */ ++ int nrows; ++ int *rows; ++ double *mult; ++ ++ int selected; ++ /* when < 0 this has not yet been turned into a row ++ when >=0 this is the id of the row added. */ ++ ++ double mir_delta; ++ /* the delta selected by a mir cut */ ++ ++ char *mir_cset; ++ /* complimented set */ ++ /* if this is NULL, it is implicitly all 0s */ ++ ++ char *mir_subst; ++ /* the substition vectors */ ++ ++ int *mir_vlb_rows; ++ /* the substition vectors */ ++ ++ int *mir_vub_rows; ++ /* the substition vectors */ ++}; ++ ++ + #define ios_create_tree _glp_ios_create_tree + glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm); + /* create branch-and-bound tree */ +@@ -615,6 +672,31 @@ int ios_choose_node(glp_tree *T); + int ios_choose_var(glp_tree *T, int *next); + /* select variable to branch on */ + ++/* functions added to retrieve information */ ++IOSAUX *ios_create_aux(int n, const int rows[], const double coeffs[]); ++/* creates an aux with n rows */ ++ ++void ios_delete_aux(IOSAUX *aux); ++/* deletes an aux */ ++ ++void ios_cut_set_single_aux(glp_tree *T, int ord, int j); ++/* sets the aux of row ord to be a single row j */ ++ ++ ++void ios_cut_set_aux(glp_tree *T, int ord, int n, ++ const int rows[], const double coeffs[]); ++/* sets an arbitrary aux sum */ ++ ++void ios_cut_set_aux_mir(glp_tree *T, int ord, double delta, ++ const char cset[], const char subst[], ++ const int vlbrs[], const int vubrs[]); ++/* sets the extra mir information */ ++ ++void ios_cut_set_selected(IOSCUT *cut, int i); ++/* the cut has been added as row i */ ++ ++void ios_cb_rows_deleted(glp_tree *T, int n, const int* rows); ++ + #endif + + /* eof */ +diff --git a/src/glpios01.c b/src/glpios01.c +index 70798fd..d9e5703 100644 +--- a/src/glpios01.c ++++ b/src/glpios01.c +@@ -159,6 +159,16 @@ glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm) + tree->stop = 0; + /* create the root subproblem, which initially is identical to + the original MIP */ ++ ++ tree->br_result = 0; ++ tree->br_to_up = 0; ++ tree->br_node = 0; ++ tree->dn_child = 0; ++ tree->up_child = 0; ++ ++ tree->deleting_rows = NULL; ++ tree->num_deleting_rows = 0; ++ + new_node(tree, NULL); + return tree; + } +@@ -278,6 +288,7 @@ void ios_revive_node(glp_tree *tree, int p) + double *val; + ind = xcalloc(1+n, sizeof(int)); + val = xcalloc(1+n, sizeof(double)); ++ /* maintains the row order during revival */ + for (r = node->r_ptr; r != NULL; r = r->next) + { i = glp_add_rows(mip, 1); + glp_set_row_name(mip, i, r->name); +@@ -457,6 +468,13 @@ void ios_freeze_node(glp_tree *tree) + double *val; + ind = xcalloc(1+n, sizeof(int)); + val = xcalloc(1+n, sizeof(double)); ++ /* Added rows are stored in the same order! ++ * This is done by 2 reversals. ++ * - Going from i = m down pred_m. ++ * - Storing the list by a stack "push" ++ * node->r_ptr = r; ++ * r->next = node->r_ptr; ++ */ + for (i = m; i > pred_m; i--) + { GLPROW *row = mip->row[i]; + IOSROW *r; +@@ -501,6 +519,8 @@ void ios_freeze_node(glp_tree *tree) + xassert(nrs > 0); + num = xcalloc(1+nrs, sizeof(int)); + for (i = 1; i <= nrs; i++) num[i] = root_m + i; ++ /* To not call ios_cb_rows_deleted here. ++ These rows have been saved earlier. */ + glp_del_rows(mip, nrs, num); + xfree(num); + } +@@ -636,6 +656,9 @@ static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent) + tree->a_cnt++; + tree->n_cnt++; + tree->t_cnt++; ++ ++ node->ord = tree->t_cnt; ++ + /* increase the number of child subproblems */ + if (parent == NULL) + xassert(p == 1); +@@ -818,6 +841,8 @@ void ios_delete_tree(glp_tree *tree) + xassert(nrs > 0); + num = xcalloc(1+nrs, sizeof(int)); + for (i = 1; i <= nrs; i++) num[i] = tree->orig_m + i; ++ /* Do not call ios_cb_rows_deleted here. ++ This does not help log information. */ + glp_del_rows(mip, nrs, num); + xfree(num); + } +@@ -1417,6 +1442,7 @@ int ios_add_row(glp_tree *tree, IOSPOOL *pool, + cut->rhs = rhs; + cut->prev = pool->tail; + cut->next = NULL; ++ cut->aux = NULL; + if (cut->prev == NULL) + pool->head = cut; + else +@@ -1517,6 +1543,11 @@ void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i) + cut->ptr = aij->next; + dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ)); + } ++ ++ if (cut->aux != NULL){ ++ ios_delete_aux(cut->aux); ++ } ++ + dmp_free_atom(tree->pool, cut, sizeof(IOSCUT)); + pool->size--; + return; +@@ -1535,6 +1566,10 @@ void ios_clear_pool(glp_tree *tree, IOSPOOL *pool) + cut->ptr = aij->next; + dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ)); + } ++ ++ if (cut->aux != NULL){ ++ ios_delete_aux(cut->aux); ++ } + dmp_free_atom(tree->pool, cut, sizeof(IOSCUT)); + } + pool->size = 0; +diff --git a/src/glpios03.c b/src/glpios03.c +index 80d701b..03e9208 100644 +--- a/src/glpios03.c ++++ b/src/glpios03.c +@@ -358,12 +358,12 @@ static void fix_by_red_cost(glp_tree *T) + * 2 - both branches are hopeless and have been pruned; new subproblem + * selection is needed to continue the search. */ + +-static int branch_on(glp_tree *T, int j, int next) ++static int branch_on(glp_tree *T, int j, int next, int clone[], int* to_up) + { glp_prob *mip = T->mip; + IOSNPD *node; + int m = mip->m; + int n = mip->n; +- int type, dn_type, up_type, dn_bad, up_bad, p, ret, clone[1+2]; ++ int type, dn_type, up_type, dn_bad, up_bad, p, ret; + double lb, ub, beta, new_ub, new_lb, dn_lp, up_lp, dn_bnd, up_bnd; + /* determine bounds and value of x[j] in optimal solution to LP + relaxation of the current subproblem */ +@@ -431,6 +431,7 @@ static int branch_on(glp_tree *T, int j, int next) + else + xassert(mip != mip); + ret = 1; ++ *to_up = 0; /* up is bad. Do not go to up. */ + goto done; + } + else if (dn_bad) +@@ -449,6 +450,7 @@ static int branch_on(glp_tree *T, int j, int next) + else + xassert(mip != mip); + ret = 1; ++ *to_up = 1; /* down is bad. Go to up. */ + goto done; + } + /* both down- and up-branches seem to be hopeful */ +@@ -702,7 +704,8 @@ static void remove_cuts(glp_tree *T) + } + } + if (cnt > 0) +- { glp_del_rows(T->mip, cnt, num); ++ { ios_cb_rows_deleted(T, cnt, num); ++ glp_del_rows(T->mip, cnt, num); + #if 0 + xprintf("%d inactive cut(s) removed\n", cnt); + #endif +@@ -784,6 +787,7 @@ static void display_cut_info(glp_tree *T) + + int ios_driver(glp_tree *T) + { int p, curr_p, p_stat, d_stat, ret; ++ int branch_clones[1 + 2]; + #if 1 /* carry out to glp_tree */ + int pred_p = 0; + /* if the current subproblem has been just created due to +@@ -1010,6 +1014,12 @@ more: /* minor loop starts here */ + if (T->parm->msg_lev >= GLP_MSG_DBG) + xprintf("LP relaxation has no feasible solution\n"); + /* prune the branch */ ++ if (T->parm->cb_func != NULL) ++ { xassert(T->reason == 0); ++ T->reason = GLP_LI_CLOSE; ++ T->parm->cb_func(T, T->parm->cb_info); ++ T->reason = 0; ++ } + goto fath; + } + else +@@ -1219,6 +1229,14 @@ more: /* minor loop starts here */ + ios_process_cuts(T); + T->reason = 0; + } ++ /* if the local cut pool is not empty and the callback func is there, ++ this gives the callback the chance to see what was selected. */ ++ if (T->parm->cb_func != NULL && T->local->size > 0) ++ { xassert(T->reason == 0); ++ T->reason = GLP_ICUTSELECT; ++ T->parm->cb_func(T, T->parm->cb_info); ++ T->reason = 0; ++ } + /* clear the local cut pool */ + ios_clear_pool(T, T->local); + /* perform re-optimization, if necessary */ +@@ -1255,7 +1273,34 @@ more: /* minor loop starts here */ + T->br_var = ios_choose_var(T, &T->br_sel); + /* perform actual branching */ + curr_p = T->curr->p; +- ret = branch_on(T, T->br_var, T->br_sel); ++ xassert(T->br_to_up == 0); ++ ret = branch_on(T, T->br_var, T->br_sel, branch_clones, &T->br_to_up); ++ if (T->parm->cb_func != NULL) ++ { xassert(T->reason == 0); ++ xassert(T->br_node == 0); ++ xassert(T->dn_child == 0); ++ xassert(T->up_child == 0); ++ // record a branch here ++ T->reason = GLP_LI_BRANCH; ++ // at this point T->br_var is the branching variable ++ T->br_node = curr_p; ++ T->br_result = ret; ++ if(ret == 0){ ++ T->dn_child = branch_clones[1]; ++ T->up_child = branch_clones[2]; ++ } ++ T->parm->cb_func(T, T->parm->cb_info); ++ T->reason = 0; ++ T->br_node = 0; ++ T->dn_child = 0; ++ T->up_child = 0; ++ if (T->stop) ++ { ret = GLP_ESTOP; ++ goto done; ++ } ++ } ++ T->br_to_up = 0; ++ + T->br_var = T->br_sel = 0; + if (ret == 0) + { /* both branches have been created */ +diff --git a/src/glpios05.c b/src/glpios05.c +index b9322b9..caf69d7 100644 +--- a/src/glpios05.c ++++ b/src/glpios05.c +@@ -65,6 +65,9 @@ static void gen_cut(glp_tree *tree, struct worka *worka, int j) + double *phi = worka->phi; + int i, k, len, kind, stat; + double lb, ub, alfa, beta, ksi, phi1, rhs; ++ int input_j; ++ input_j = j; ++ + /* compute row of the simplex tableau, which (row) corresponds + to specified basic variable xB[i] = x[m+j]; see (23) */ + len = glp_eval_tab_row(mip, m+j, ind, val); +@@ -73,6 +76,7 @@ static void gen_cut(glp_tree *tree, struct worka *worka, int j) + if it would be computed with formula (27); it is assumed that + beta[i] is fractional enough */ + beta = mip->col[j]->prim; ++ + /* compute cut coefficients phi and right-hand side rho, which + correspond to formula (30); dense format is used, because rows + of the simplex tableau is usually dense */ +@@ -104,6 +108,7 @@ static void gen_cut(glp_tree *tree, struct worka *worka, int j) + xassert(stat != GLP_BS); + /* determine row coefficient ksi[i,j] at xN[j]; see (23) */ + ksi = val[j]; ++ /* printf("%d %4.15f ", k, ksi); */ + /* if ksi[i,j] is too large in the magnitude, do not generate + the cut */ + if (fabs(ksi) > 1e+05) goto fini; +@@ -135,6 +140,7 @@ static void gen_cut(glp_tree *tree, struct worka *worka, int j) + /* y[j] is integer */ + if (fabs(alfa - floor(alfa + 0.5)) < 1e-10) + { /* alfa[i,j] is close to nearest integer; skip it */ ++ /* printf("(skip)"); */ + goto skip; + } + else if (f(alfa) <= f(beta)) +@@ -170,6 +176,13 @@ static void gen_cut(glp_tree *tree, struct worka *worka, int j) + } + skip: ; + } ++ /* printf("\n"); */ ++ /* for (i = 1; i <= m+n; i++) */ ++ /* { */ ++ /* printf("%i %f, ", i, phi[i]); */ ++ /* } */ ++ /* printf("\n"); */ ++ + /* now the cut has the form sum_k phi[k] * x[k] >= rho, where cut + coefficients are stored in the array phi in dense format; + x[1,...,m] are auxiliary variables, x[m+1,...,m+n] are struc- +@@ -218,8 +231,20 @@ skip: ; + ios_add_cut_row(tree, pool, GLP_RF_GMI, len, ind, val, GLP_LO, + rhs); + #else +- glp_ios_add_row(tree, NULL, GLP_RF_GMI, 0, len, ind, val, GLP_LO, +- rhs); ++ int ord; ++ ord = glp_ios_add_row(tree, NULL, GLP_RF_GMI, 0, len, ind, val, ++ GLP_LO, rhs); ++ ios_cut_set_single_aux(tree, ord, input_j); ++ ++ /* printf("ord: % d beta %f\n", ord, beta); */ ++ ++ /** callback for a cut being added to the cut pool */ ++ if (tree->parm->cb_func != NULL) ++ { xassert(tree->reason == GLP_ICUTGEN); ++ tree->reason = GLP_ICUTADDED; ++ tree->parm->cb_func(tree, tree->parm->cb_info); ++ tree->reason = GLP_ICUTGEN; ++ } + #endif + fini: return; + } +diff --git a/src/glpios06.c b/src/glpios06.c +index 2bd0453..4bd3cf5 100644 +--- a/src/glpios06.c ++++ b/src/glpios06.c +@@ -100,6 +100,29 @@ struct MIR + /* sparse vector of cutting plane coefficients, alpha[k] */ + double cut_rhs; + /* right-hand size of the cutting plane, beta */ ++ ++ /*-------------------------------------------------------------*/ ++ /* Extras I've added to reproduce a cut externally */ ++ double cut_delta; ++ /* the delta used for generating the cut */ ++ char *cut_cset; /* char cut_vec[1+m+n]; */ ++ /* cut_cset[k], 1 <= k <= m+n, is set to true if structural ++ variable x[k] was complemented in the cut: ++ 0 - x[k] has been not been complemented ++ non 0 - x[k] has been complemented */ ++ int *vlb_rows; /* int vlb_rows[1+m+n]; */ ++ /* vlb_rows[k], 1 <= k <= m+n, ++ * vlb_rows[k] <= 0 if virtual lower bound has not been set ++ * vlb_rows[k] = r if virtual lower bound was set using the row r ++ */ ++ int *vub_rows; /* int vub_rows[1+m+n]; */ ++ /* vub_rows[k], 1 <= k <= m+n, ++ * vub_rows[k] <= 0 if virtual upper bound has not been set ++ * vub_rows[k] = r if virtual upper bound was set using the row r ++ */ ++ ++ double *agg_coeffs; ++ /* coefficients used to multiply agg_coeffs */ + }; + + /*********************************************************************** +@@ -146,6 +169,7 @@ static void set_row_attrib(glp_tree *tree, struct MIR *mir) + xassert(row != row); + } + mir->vlb[k] = mir->vub[k] = 0; ++ mir->vlb_rows[k] = mir->vub_rows[k] = 0; + } + return; + } +@@ -181,6 +205,7 @@ static void set_col_attrib(glp_tree *tree, struct MIR *mir) + xassert(col != col); + } + mir->vlb[k] = mir->vub[k] = 0; ++ mir->vlb_rows[k] = mir->vub_rows[k] = 0; + } + return; + } +@@ -230,6 +255,7 @@ static void set_var_bounds(glp_tree *tree, struct MIR *mir) + { /* set variable lower bound for x1 */ + mir->lb[k1] = - a2 / a1; + mir->vlb[k1] = k2; ++ mir->vlb_rows[k1] = i; + /* the row should not be used */ + mir->skip[i] = 1; + } +@@ -240,6 +266,7 @@ static void set_var_bounds(glp_tree *tree, struct MIR *mir) + { /* set variable upper bound for x1 */ + mir->ub[k1] = - a2 / a1; + mir->vub[k1] = k2; ++ mir->vub_rows[k1] = i; + /* the row should not be used */ + mir->skip[i] = 1; + } +@@ -313,6 +340,13 @@ void *ios_mir_init(glp_tree *tree) + mir->subst = xcalloc(1+m+n, sizeof(char)); + mir->mod_vec = ios_create_vec(m+n); + mir->cut_vec = ios_create_vec(m+n); ++ ++ /* added */ ++ mir->cut_cset = xcalloc(1+m+n, sizeof(char)); ++ mir->vlb_rows = xcalloc(1+m+n, sizeof(int)); ++ mir->vub_rows = xcalloc(1+m+n, sizeof(int)); ++ mir->agg_coeffs = xcalloc(1+MAXAGGR, sizeof(double)); ++ + /* set global row attributes */ + set_row_attrib(tree, mir); + /* set global column attributes */ +@@ -405,6 +439,9 @@ static void initial_agg_row(glp_tree *tree, struct MIR *mir, int i) + mir->skip[i] = 2; + mir->agg_cnt = 1; + mir->agg_row[1] = i; ++ ++ mir->agg_coeffs[1] = +1.0; ++ + /* use x[i] - sum a[i,j] * x[m+j] = 0, where x[i] is auxiliary + variable of row i, x[m+j] are structural variables */ + ios_clear_vec(mir->agg_vec); +@@ -784,19 +821,19 @@ static int cmir_cmp(const void *p1, const void *p2) + + static double cmir_sep(const int n, const double a[], const double b, + const double u[], const double x[], const double s, +- double alpha[], double *beta, double *gamma) ++ double alpha[], double *beta, double *gamma, ++ double* delta, char cset[]) + { int fail, j, k, nv, v; +- double delta, eps, d_try[1+3], r, r_best; +- char *cset; ++ double eps, d_try[1+3], r, r_best; + struct vset *vset; + /* allocate working arrays */ +- cset = xcalloc(1+n, sizeof(char)); ++ //cset = xcalloc(1+n, sizeof(char)); + vset = xcalloc(1+n, sizeof(struct vset)); + /* choose initial C */ + for (j = 1; j <= n; j++) + cset[j] = (char)(x[j] >= 0.5 * u[j]); + /* choose initial delta */ +- r_best = delta = 0.0; ++ r_best = (*delta) = 0.0; + for (j = 1; j <= n; j++) + { xassert(a[j] != 0.0); + /* if x[j] is close to its bounds, skip it */ +@@ -809,16 +846,16 @@ static double cmir_sep(const int n, const double a[], const double b, + /* compute violation */ + r = - (*beta) - (*gamma) * s; + for (k = 1; k <= n; k++) r += alpha[k] * x[k]; +- if (r_best < r) r_best = r, delta = fabs(a[j]); ++ if (r_best < r) r_best = r, (*delta) = fabs(a[j]); + } + if (r_best < 0.001) r_best = 0.0; + if (r_best == 0.0) goto done; +- xassert(delta > 0.0); ++ xassert((*delta) > 0.0); + /* try to increase violation by dividing delta by 2, 4, and 8, + respectively */ +- d_try[1] = delta / 2.0; +- d_try[2] = delta / 4.0; +- d_try[3] = delta / 8.0; ++ d_try[1] = (*delta) / 2.0; ++ d_try[2] = (*delta) / 4.0; ++ d_try[3] = (*delta) / 8.0; + for (j = 1; j <= 3; j++) + { /* construct c-MIR inequality */ + fail = cmir_ineq(n, a, b, u, cset, d_try[j], alpha, beta, +@@ -827,7 +864,7 @@ static double cmir_sep(const int n, const double a[], const double b, + /* compute violation */ + r = - (*beta) - (*gamma) * s; + for (k = 1; k <= n; k++) r += alpha[k] * x[k]; +- if (r_best < r) r_best = r, delta = d_try[j]; ++ if (r_best < r) r_best = r, (*delta) = d_try[j]; + } + /* build subset of variables lying strictly between their bounds + and order it by nondecreasing values of |x[j] - u[j]/2| */ +@@ -849,7 +886,7 @@ static double cmir_sep(const int n, const double a[], const double b, + /* replace x[j] by its complement or vice versa */ + cset[j] = (char)!cset[j]; + /* construct c-MIR inequality */ +- fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma); ++ fail = cmir_ineq(n, a, b, u, cset, (*delta), alpha, beta, gamma); + /* restore the variable */ + cset[j] = (char)!cset[j]; + /* do not replace the variable in case of failure */ +@@ -860,10 +897,11 @@ static double cmir_sep(const int n, const double a[], const double b, + if (r_best < r) r_best = r, cset[j] = (char)!cset[j]; + } + /* construct the best c-MIR inequality chosen */ +- fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma); ++ fail = cmir_ineq(n, a, b, u, cset, (*delta), alpha, beta, gamma); + xassert(!fail); ++ + done: /* free working arrays */ +- xfree(cset); ++ + xfree(vset); + /* return to the calling routine */ + return r_best; +@@ -874,7 +912,8 @@ static double generate(struct MIR *mir) + int m = mir->m; + int n = mir->n; + int j, k, kk, nint; +- double s, *u, *x, *alpha, r_best = 0.0, b, beta, gamma; ++ double s, *u, *x, *alpha, r_best = 0.0, b, beta, gamma, delta; ++ char *cset; + ios_copy_vec(mir->cut_vec, mir->mod_vec); + mir->cut_rhs = mir->mod_rhs; + /* remove small terms, which can appear due to substitution of +@@ -923,6 +962,7 @@ static double generate(struct MIR *mir) + u = xcalloc(1+nint, sizeof(double)); + x = xcalloc(1+nint, sizeof(double)); + alpha = xcalloc(1+nint, sizeof(double)); ++ cset = xcalloc(1+nint, sizeof(char)); + /* determine u and x */ + for (j = 1; j <= nint; j++) + { k = mir->cut_vec->ind[j]; +@@ -936,6 +976,7 @@ static double generate(struct MIR *mir) + x[j] = mir->ub[k] - mir->x[k]; + else + xassert(k != k); ++ if(!(x[j] >= -0.001)) { goto skip; } + xassert(x[j] >= -0.001); + if (x[j] < 0.0) x[j] = 0.0; + } +@@ -965,6 +1006,7 @@ static double generate(struct MIR *mir) + } + else + xassert(k != k); ++ if(!(x >= -0.001)) { goto skip; } + xassert(x >= -0.001); + if (x < 0.0) x = 0.0; + s -= mir->cut_vec->val[j] * x; +@@ -973,7 +1015,7 @@ static double generate(struct MIR *mir) + /* apply heuristic to obtain most violated c-MIR inequality */ + b = mir->cut_rhs; + r_best = cmir_sep(nint, mir->cut_vec->val, b, u, x, s, alpha, +- &beta, &gamma); ++ &beta, &gamma, &delta, cset); + if (r_best == 0.0) goto skip; + xassert(r_best > 0.0); + /* convert to raw cut */ +@@ -988,10 +1030,22 @@ static double generate(struct MIR *mir) + #if _MIR_DEBUG + ios_check_vec(mir->cut_vec); + #endif ++ /* added */ ++ mir->cut_delta = delta; ++ // this is not a great place for resetting the array, ++ // but it should be sufficient ++ for (j = 1; j <= n+m; j++) ++ mir->cut_cset[j] = 0; ++ for (j = 1; j <= nint; j++) ++ { k = mir->cut_vec->ind[j]; ++ xassert(m <= k && k <= m+n); ++ mir->cut_cset[k] = cset[j]; ++ } + skip: /* free working arrays */ + xfree(u); + xfree(x); + xfree(alpha); ++ xfree(cset); + done: return r_best; + } + +@@ -1199,8 +1253,25 @@ static void add_cut(glp_tree *tree, struct MIR *mir) + ios_add_cut_row(tree, pool, GLP_RF_MIR, len, ind, val, GLP_UP, + mir->cut_rhs); + #else +- glp_ios_add_row(tree, NULL, GLP_RF_MIR, 0, len, ind, val, GLP_UP, ++ int ord; ++ ord = glp_ios_add_row(tree, NULL, GLP_RF_MIR, 0, len, ind, val, GLP_UP, + mir->cut_rhs); ++ ios_cut_set_aux(tree, ord, mir->agg_cnt, mir->agg_row, mir->agg_coeffs); ++ ios_cut_set_aux_mir(tree, ord, mir->cut_delta, ++ mir->cut_cset, mir->subst, ++ mir->vlb_rows, mir->vub_rows); ++ ++ /** callback for a cut being added to the cut pool */ ++ /* printf("mir tree parm %p %d\n", tree->parm->cb_func, ord); */ ++ /* printf(" agg_rhs %f\n", mir->agg_rhs); */ ++ /* printf(" mod_rhs %f\n", mir->mod_rhs); */ ++ /* printf(" cut_rhs %f\n", mir->cut_rhs); */ ++ if (tree->parm->cb_func != NULL) ++ { xassert(tree->reason == GLP_ICUTGEN); ++ tree->reason = GLP_ICUTADDED; ++ tree->parm->cb_func(tree, tree->parm->cb_info); ++ tree->reason = GLP_ICUTGEN; ++ } + #endif + xfree(ind); + xfree(val); +@@ -1216,6 +1287,7 @@ static int aggregate_row(glp_tree *tree, struct MIR *mir) + IOSVEC *v; + int ii, j, jj, k, kk, kappa = 0, ret = 0; + double d1, d2, d, d_max = 0.0; ++ double guass_coeff; + /* choose appropriate structural variable in the aggregated row + to be substituted */ + for (j = 1; j <= mir->agg_vec->nnz; j++) +@@ -1300,8 +1372,9 @@ static int aggregate_row(glp_tree *tree, struct MIR *mir) + xassert(j != 0); + jj = v->pos[kappa]; + xassert(jj != 0); +- ios_linear_comb(mir->agg_vec, +- - mir->agg_vec->val[j] / v->val[jj], v); ++ guass_coeff = - mir->agg_vec->val[j] / v->val[jj]; ++ mir->agg_coeffs[mir->agg_cnt] = guass_coeff; ++ ios_linear_comb(mir->agg_vec, guass_coeff, v); + ios_delete_vec(v); + ios_set_vj(mir->agg_vec, kappa, 0.0); + #if _MIR_DEBUG +@@ -1440,6 +1513,13 @@ void ios_mir_term(void *gen) + xfree(mir->subst); + ios_delete_vec(mir->mod_vec); + ios_delete_vec(mir->cut_vec); ++ ++ /* added */ ++ xfree(mir->cut_cset); ++ xfree(mir->vlb_rows); ++ xfree(mir->vub_rows); ++ xfree(mir->agg_coeffs); ++ + xfree(mir); + return; + } +diff --git a/src/glpios07.c b/src/glpios07.c +index 0892550..9f742e6 100644 +--- a/src/glpios07.c ++++ b/src/glpios07.c +@@ -543,6 +543,14 @@ void ios_cov_gen(glp_tree *tree) + /* add the cut to the cut pool */ + glp_ios_add_row(tree, NULL, GLP_RF_COV, 0, len, ind, val, + GLP_UP, val[0]); ++ ++ /** callback for a cut being added to the cut pool */ ++ if (tree->parm->cb_func != NULL) ++ { xassert(tree->reason == GLP_ICUTGEN); ++ tree->reason = GLP_ICUTADDED; ++ tree->parm->cb_func(tree, tree->parm->cb_info); ++ tree->reason = GLP_ICUTGEN; ++ } + } + /* free working arrays */ + xfree(ind); +diff --git a/src/glpios08.c b/src/glpios08.c +index 2d2fcd5..3aad808 100644 +--- a/src/glpios08.c ++++ b/src/glpios08.c +@@ -129,6 +129,15 @@ void ios_clq_gen(glp_tree *T, void *G_) + /* add cut inequality to local cut pool */ + glp_ios_add_row(T, NULL, GLP_RF_CLQ, 0, len, ind, val, GLP_UP, + rhs); ++ ++ /** callback for a cut being added to the cut pool */ ++ if (T->parm->cb_func != NULL) ++ { xassert(T->reason == GLP_ICUTGEN); ++ T->reason = GLP_ICUTADDED; ++ T->parm->cb_func(T, T->parm->cb_info); ++ T->reason = GLP_ICUTGEN; ++ } ++ + skip: /* free working arrays */ + tfree(ind); + tfree(val); +diff --git a/src/glpios11.c b/src/glpios11.c +index c40e9a5..82d5698 100644 +--- a/src/glpios11.c ++++ b/src/glpios11.c +@@ -193,6 +193,9 @@ void ios_process_cuts(glp_tree *T) + glp_set_mat_row(T->mip, i, len, ind, val); + xassert(cut->type == GLP_LO || cut->type == GLP_UP); + glp_set_row_bnds(T->mip, i, cut->type, cut->rhs, cut->rhs); ++ ++ /* setting this as selected */ ++ ios_cut_set_selected(cut, i); + } + /* free working arrays */ + xfree(info); +diff --git a/src/glpk.h b/src/glpk.h +index 75c292c..e117782 100644 +--- a/src/glpk.h ++++ b/src/glpk.h +@@ -130,6 +130,7 @@ typedef struct + int out_frq; /* spx.out_frq */ + int out_dly; /* spx.out_dly (milliseconds) */ + int presolve; /* enable/disable using LP presolver */ ++ int stability_lmt; /* maximum number of check stability failures before stopping */ + double foo_bar[36]; /* (reserved) */ + } glp_smcp; + +@@ -229,6 +230,11 @@ typedef struct + #define GLP_IBRANCH 0x05 /* request for branching */ + #define GLP_ISELECT 0x06 /* request for subproblem selection */ + #define GLP_IPREPRO 0x07 /* request for preprocessing */ ++#define GLP_ICUTADDED 0x08 /* cut was added to the pool */ ++#define GLP_ICUTSELECT 0x09 /* cuts were selected as rows */ ++#define GLP_LI_BRANCH 0x10 /* a branch was made */ ++#define GLP_LI_CLOSE 0x11 /* an active node was closed */ ++#define GLP_LI_DELROW 0x12 /* an active node was closed */ + + /* branch selection indicator: */ + #define GLP_NO_BRNCH 0 /* select no branch */ +@@ -1057,6 +1063,54 @@ int glp_top_sort(glp_graph *G, int v_num); + int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set); + /* find maximum weight clique with exact algorithm */ + ++/*******************************************/ ++/*** CUT LOG ***/ ++/*******************************************/ ++ ++int glp_get_it_cnt(glp_prob *P); ++/* get the iteration count of the current problem */ ++ ++ ++int glp_ios_get_cut(glp_tree *T, int i, int ind[], double val[], int* klass, int* type, double* rhs); ++/* determine reason for calling the callback routine */ ++ ++int glp_ios_cut_get_aux_nrows(glp_tree *tree, int ord); ++/* gets the number of rows used to generate a cut. */ ++ ++ ++void glp_ios_cut_get_aux_rows(glp_tree *tree, int ord, ++ int rows[], double coeffs[]); ++/* gets a cut as an input sequence of rows times coefficients. */ ++ ++ ++void glp_ios_cut_get_mir_cset(glp_tree *tree, int ord, char cset[]); ++/* gets mir cut complement set. */ ++double glp_ios_cut_get_mir_delta(glp_tree *tree, int ord); ++/* gets mir cut delta. */ ++void glp_ios_cut_get_mir_subst(glp_tree *tree, int ord, char subst[]); ++/* gets mir cut substition information. */ ++void glp_ios_cut_get_mir_virtual_rows(glp_tree *tree, int ord, ++ int vlb_rows[], int vub_rows[]); ++/* gets mir cut virtual bounds rows. */ ++ ++int glp_ios_selected_cuts(glp_tree *tree, int ords[], int sel[]); ++/* gets the list of selected cuts. ++ Can only be called when GLP_ICUTSELECT */ ++ ++ ++int glp_ios_branch_log(glp_tree *tree, double *val, int* parent, int* dn, int* up); ++/* can only be called when GLP_LI_BRANCH. ++ * If id is non-null, returns the id of the structural variable branched upon. ++ * If val is non-null, it is set to the value branched upon. ++ * If parent is non-null, it is set to node id of the node branched upon. ++ * If dn is non-null, it is set to node id of the newly created down node. ++ * If up is non-null, it is set to node id of the newly created up node. ++ */ ++ ++int glp_ios_node_ord(glp_tree *tree, int node_p); ++ ++int glp_ios_rows_deleted(glp_tree *tree, int* rows); ++ + #ifdef __cplusplus + } + #endif +diff --git a/src/glpspx01.c b/src/glpspx01.c +index 5c17114..caaab27 100644 +--- a/src/glpspx01.c ++++ b/src/glpspx01.c +@@ -238,6 +238,9 @@ struct csa + double *work2; /* double work2[1+m]; */ + double *work3; /* double work3[1+m]; */ + double *work4; /* double work4[1+m]; */ ++ ++ /** Things Tim has added. */ ++ int stability_failures; + }; + + static const double kappa = 0.10; +@@ -400,6 +403,8 @@ static void init_csa(struct csa *csa, glp_prob *lp) + csa->refct = 0; + memset(&refsp[1], 0, (m+n) * sizeof(char)); + for (j = 1; j <= n; j++) gamma[j] = 1.0; ++ ++ csa->stability_failures = 0; + return; + } + +@@ -2647,6 +2652,11 @@ loop: /* main loop starts here */ + if (check_stab(csa, parm->tol_bnd)) + { /* there are excessive bound violations due to round-off + errors */ ++ csa->stability_failures++; ++ if (csa->stability_failures >= parm->stability_lmt){ ++ ret = GLP_EINSTAB; ++ goto done; ++ } + if (parm->msg_lev >= GLP_MSG_ERR) + xprintf("Warning: numerical instability (primal simplex," + " phase %s)\n", csa->phase == 1 ? "I" : "II"); +diff --git a/src/glpspx02.c b/src/glpspx02.c +index 19152a6..de3d677 100644 +--- a/src/glpspx02.c ++++ b/src/glpspx02.c +@@ -288,6 +288,9 @@ struct csa + double *work2; /* double work2[1+m]; */ + double *work3; /* double work3[1+m]; */ + double *work4; /* double work4[1+m]; */ ++ ++ /* count the number of stability failures */ ++ int stability_failures; + }; + + static const double kappa = 0.10; +@@ -501,6 +504,8 @@ static void init_csa(struct csa *csa, glp_prob *lp) + csa->refct = 0; + memset(&refsp[1], 0, (m+n) * sizeof(char)); + for (i = 1; i <= m; i++) gamma[i] = 1.0; ++ ++ csa->stability_failures = 0; + return; + } + +@@ -2741,7 +2746,13 @@ loop: /* main loop starts here */ + /* make sure that the current basic solution remains dual + feasible */ + if (check_stab(csa, parm->tol_dj) != 0) +- { if (parm->msg_lev >= GLP_MSG_ERR) ++ { ++ csa->stability_failures++; ++ if (csa->stability_failures >= parm->stability_lmt){ ++ ret = GLP_EINSTAB; ++ goto done; ++ } ++ if (parm->msg_lev >= GLP_MSG_ERR) + xprintf("Warning: numerical instability (dual simplex, p" + "hase %s)\n", csa->phase == 1 ? "I" : "II"); + #if 1 +@@ -3023,6 +3034,10 @@ loop: /* main loop starts here */ + /* accuracy check based on the pivot element */ + { double piv1 = csa->tcol_vec[csa->p]; /* more accurate */ + double piv2 = csa->trow_vec[csa->q]; /* less accurate */ ++ if(piv1 == 0.0){ ++ ret = GLP_EFAIL; ++ goto done; ++ } + xassert(piv1 != 0.0); + if (fabs(piv1 - piv2) > 1e-8 * (1.0 + fabs(piv1)) || + !(piv1 > 0.0 && piv2 > 0.0 || piv1 < 0.0 && piv2 < 0.0)) +-- +2.26.2 -- cgit v1.2.3 From 0ee1b1371e7cf50c14883316fdd6374114799a99 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Wed, 2 Sep 2020 13:01:10 -0500 Subject: (proof-new) Make term conversion proof generator optionally term-context sensitive (#4972) This will be used by TermFormulaRemoval. --- src/expr/CMakeLists.txt | 4 + src/expr/term_conversion_proof_generator.cpp | 351 +++++++++++++++++++++------ src/expr/term_conversion_proof_generator.h | 70 +++++- 3 files changed, 338 insertions(+), 87 deletions(-) diff --git a/src/expr/CMakeLists.txt b/src/expr/CMakeLists.txt index 8bc732314..aed7a866c 100644 --- a/src/expr/CMakeLists.txt +++ b/src/expr/CMakeLists.txt @@ -63,6 +63,10 @@ libcvc4_add_sources( term_canonize.h term_context.cpp term_context.h + term_context_node.cpp + term_context_node.h + term_context_stack.cpp + term_context_stack.h term_conversion_proof_generator.cpp term_conversion_proof_generator.h type.cpp diff --git a/src/expr/term_conversion_proof_generator.cpp b/src/expr/term_conversion_proof_generator.cpp index 1c4baeed7..8cd7561b4 100644 --- a/src/expr/term_conversion_proof_generator.cpp +++ b/src/expr/term_conversion_proof_generator.cpp @@ -14,6 +14,8 @@ #include "expr/term_conversion_proof_generator.h" +#include "expr/term_context_stack.h" + using namespace CVC4::kind; namespace CVC4 { @@ -45,31 +47,38 @@ TConvProofGenerator::TConvProofGenerator(ProofNodeManager* pnm, context::Context* c, TConvPolicy pol, TConvCachePolicy cpol, - std::string name) + std::string name, + TermContext* tccb) : d_proof(pnm, nullptr, c, name + "::LazyCDProof"), d_rewriteMap(c ? c : &d_context), d_policy(pol), d_cpolicy(cpol), - d_name(name) + d_name(name), + d_tcontext(tccb) { } TConvProofGenerator::~TConvProofGenerator() {} -void TConvProofGenerator::addRewriteStep(Node t, Node s, ProofGenerator* pg) +void TConvProofGenerator::addRewriteStep( + Node t, Node s, ProofGenerator* pg, bool isClosed, uint32_t tctx) { - Node eq = registerRewriteStep(t, s); + Node eq = registerRewriteStep(t, s, tctx); if (!eq.isNull()) { - d_proof.addLazyStep(eq, pg); + d_proof.addLazyStep(eq, pg, isClosed); } } -void TConvProofGenerator::addRewriteStep(Node t, Node s, ProofStep ps) +void TConvProofGenerator::addRewriteStep(Node t, + Node s, + ProofStep ps, + uint32_t tctx) { - Node eq = registerRewriteStep(t, s); + Node eq = registerRewriteStep(t, s, tctx); if (!eq.isNull()) { + AlwaysAssert(ps.d_rule != PfRule::ASSUME); d_proof.addStep(eq, ps); } } @@ -78,33 +87,55 @@ void TConvProofGenerator::addRewriteStep(Node t, Node s, PfRule id, const std::vector& children, - const std::vector& args) + const std::vector& args, + uint32_t tctx) { - Node eq = registerRewriteStep(t, s); + Node eq = registerRewriteStep(t, s, tctx); if (!eq.isNull()) { + AlwaysAssert(id != PfRule::ASSUME); d_proof.addStep(eq, id, children, args); } } -bool TConvProofGenerator::hasRewriteStep(Node t) const +bool TConvProofGenerator::hasRewriteStep(Node t, uint32_t tctx) const { - return !getRewriteStep(t).isNull(); + return !getRewriteStep(t, tctx).isNull(); } -Node TConvProofGenerator::registerRewriteStep(Node t, Node s) +Node TConvProofGenerator::getRewriteStep(Node t, uint32_t tctx) const +{ + Node thash = t; + if (d_tcontext != nullptr) + { + thash = TCtxNode::computeNodeHash(t, tctx); + } + return getRewriteStepInternal(thash); +} + +Node TConvProofGenerator::registerRewriteStep(Node t, Node s, uint32_t tctx) { if (t == s) { return Node::null(); } + Node thash = t; + if (d_tcontext != nullptr) + { + thash = TCtxNode::computeNodeHash(t, tctx); + } + else + { + // don't use term context ids if not using term context + Assert(tctx == 0); + } // should not rewrite term to two different things - if (!getRewriteStep(t).isNull()) + if (!getRewriteStepInternal(thash).isNull()) { - Assert(getRewriteStep(t) == s); + Assert(getRewriteStepInternal(thash) == s); return Node::null(); } - d_rewriteMap[t] = s; + d_rewriteMap[thash] = s; if (d_cpolicy == TConvCachePolicy::DYNAMIC) { // clear the cache @@ -115,66 +146,140 @@ Node TConvProofGenerator::registerRewriteStep(Node t, Node s) std::shared_ptr TConvProofGenerator::getProofFor(Node f) { - Trace("tconv-pf-gen") << "TConvProofGenerator::getProofFor: " << f - << std::endl; + Trace("tconv-pf-gen") << "TConvProofGenerator::getProofFor: " << identify() + << ": " << f << std::endl; if (f.getKind() != EQUAL) { - Trace("tconv-pf-gen") << "... fail, non-equality" << std::endl; - Assert(false); + std::stringstream serr; + serr << "TConvProofGenerator::getProofFor: " << identify() + << ": fail, non-equality " << f; + Unhandled() << serr.str(); + Trace("tconv-pf-gen") << serr.str() << std::endl; return nullptr; } // we use the existing proofs LazyCDProof lpf( d_proof.getManager(), &d_proof, nullptr, d_name + "::LazyCDProof"); - Node conc = getProofForRewriting(f[0], lpf); - if (conc != f) + if (f[0] == f[1]) { - Trace("tconv-pf-gen") << "...failed, mismatch: returned proof concludes " - << conc << ", expected " << f << std::endl; - Assert(false); - return nullptr; + // assertion failure in debug + Assert(false) << "TConvProofGenerator::getProofFor: " << identify() + << ": don't ask for trivial proofs"; + lpf.addStep(f, PfRule::REFL, {}, {f[0]}); + } + else + { + Node conc = getProofForRewriting(f[0], lpf, d_tcontext); + if (conc != f) + { + Assert(conc.getKind() == EQUAL && conc[0] == f[0]); + std::stringstream serr; + serr << "TConvProofGenerator::getProofFor: " << toStringDebug() + << ": failed, mismatch (see -t tconv-pf-gen-debug for details)" + << std::endl; + serr << " source: " << f[0] << std::endl; + serr << "expected after rewriting: " << f[1] << std::endl; + serr << " actual after rewriting: " << conc[1] << std::endl; + + if (Trace.isOn("tconv-pf-gen-debug")) + { + Trace("tconv-pf-gen-debug") << "Printing rewrite steps..." << std::endl; + serr << "Rewrite steps: " << std::endl; + for (NodeNodeMap::const_iterator it = d_rewriteMap.begin(); + it != d_rewriteMap.end(); + ++it) + { + serr << (*it).first << " -> " << (*it).second << std::endl; + } + } + Unhandled() << serr.str(); + return nullptr; + } } Trace("tconv-pf-gen") << "... success" << std::endl; return lpf.getProofFor(f); } -Node TConvProofGenerator::getProofForRewriting(Node t, LazyCDProof& pf) +Node TConvProofGenerator::getProofForRewriting(Node t, + LazyCDProof& pf, + TermContext* tctx) { NodeManager* nm = NodeManager::currentNM(); - // Invariant: if visited[t] = s or rewritten[t] = s and t,s are distinct, - // then pf is able to generate a proof of t=s. + // Invariant: if visited[hash(t)] = s or rewritten[hash(t)] = s and t,s are + // distinct, then pf is able to generate a proof of t=s. We must + // Node in the domains of the maps below due to hashing creating new (SEXPR) + // nodes. + // the final rewritten form of terms - std::unordered_map visited; + std::unordered_map visited; // the rewritten form of terms we have processed so far - std::unordered_map rewritten; - std::unordered_map::iterator it; - std::unordered_map::iterator itr; + std::unordered_map rewritten; + std::unordered_map::iterator it; + std::unordered_map::iterator itr; std::map >::iterator itc; + Trace("tconv-pf-gen-rewrite") + << "TConvProofGenerator::getProofForRewriting: " << toStringDebug() + << std::endl; + Trace("tconv-pf-gen-rewrite") << "Input: " << t << std::endl; + // if provided, we use term context for cache + std::shared_ptr visitctx; + // otherwise, visit is used if we don't have a term context std::vector visit; - TNode cur; - visit.push_back(t); + Node tinitialHash; + if (tctx != nullptr) + { + visitctx = std::make_shared(tctx); + visitctx->pushInitial(t); + tinitialHash = TCtxNode::computeNodeHash(t, tctx->initialValue()); + } + else + { + visit.push_back(t); + tinitialHash = t; + } + Node cur; + uint32_t curCVal = 0; + Node curHash; do { - cur = visit.back(); - visit.pop_back(); + // pop the top element + if (tctx != nullptr) + { + std::pair curPair = visitctx->getCurrent(); + cur = curPair.first; + curCVal = curPair.second; + curHash = TCtxNode::computeNodeHash(cur, curCVal); + visitctx->pop(); + } + else + { + cur = visit.back(); + curHash = cur; + visit.pop_back(); + } + Trace("tconv-pf-gen-rewrite") << "* visit : " << curHash << std::endl; // has the proof for cur been cached? - itc = d_cache.find(cur); + itc = d_cache.find(curHash); if (itc != d_cache.end()) { Node res = itc->second->getResult(); Assert(res.getKind() == EQUAL); - visited[cur] = res[1]; + Assert(!res[1].isNull()); + visited[curHash] = res[1]; pf.addProof(itc->second); continue; } - it = visited.find(cur); + it = visited.find(curHash); if (it == visited.end()) { - visited[cur] = Node::null(); + Trace("tconv-pf-gen-rewrite") << "- previsit" << std::endl; + visited[curHash] = Node::null(); // did we rewrite the current node (possibly at pre-rewrite)? - Node rcur = getRewriteStep(cur); + Node rcur = getRewriteStepInternal(curHash); if (!rcur.isNull()) { + Trace("tconv-pf-gen-rewrite") + << "*** " << curHash << " prerewrites to " << rcur << std::endl; // d_proof has a proof of cur = rcur. Hence there is nothing // to do here, as pf will reference d_proof to get its proof. if (d_policy == TConvPolicy::FIXPOINT) @@ -182,18 +287,34 @@ Node TConvProofGenerator::getProofForRewriting(Node t, LazyCDProof& pf) // It may be the case that rcur also rewrites, thus we cannot assign // the final rewritten form for cur yet. Instead we revisit cur after // finishing visiting rcur. - rewritten[cur] = rcur; - visit.push_back(cur); - visit.push_back(rcur); + rewritten[curHash] = rcur; + if (tctx != nullptr) + { + visitctx->push(cur, curCVal); + visitctx->push(rcur, curCVal); + } + else + { + visit.push_back(cur); + visit.push_back(rcur); + } } else { Assert(d_policy == TConvPolicy::ONCE); + Trace("tconv-pf-gen-rewrite") << "-> (once, prewrite) " << curHash + << " = " << rcur << std::endl; // not rewriting again, rcur is final - visited[cur] = rcur; - doCache(cur, rcur, pf); + Assert(!rcur.isNull()); + visited[curHash] = rcur; + doCache(curHash, cur, rcur, pf); } } + else if (tctx != nullptr) + { + visitctx->push(cur, curCVal); + visitctx->pushChildren(cur, curCVal); + } else { visit.push_back(cur); @@ -202,7 +323,7 @@ Node TConvProofGenerator::getProofForRewriting(Node t, LazyCDProof& pf) } else if (it->second.isNull()) { - itr = rewritten.find(cur); + itr = rewritten.find(curHash); if (itr != rewritten.end()) { // only can generate partially rewritten nodes when rewrite again is @@ -211,9 +332,17 @@ Node TConvProofGenerator::getProofForRewriting(Node t, LazyCDProof& pf) // if it was rewritten, check the status of the rewritten node, // which should be finished now Node rcur = itr->second; + Trace("tconv-pf-gen-rewrite") + << "- postvisit, previously rewritten to " << rcur << std::endl; + Node rcurHash = rcur; + if (tctx != nullptr) + { + rcurHash = TCtxNode::computeNodeHash(rcur, curCVal); + } Assert(cur != rcur); // the final rewritten form of cur is the final form of rcur - Node rcurFinal = visited[rcur]; + Node rcurFinal = visited[rcurHash]; + Assert(!rcurFinal.isNull()); if (rcurFinal != rcur) { // must connect via TRANS @@ -223,30 +352,54 @@ Node TConvProofGenerator::getProofForRewriting(Node t, LazyCDProof& pf) Node result = cur.eqNode(rcurFinal); pf.addStep(result, PfRule::TRANS, pfChildren, {}); } - visited[cur] = rcurFinal; - doCache(cur, rcurFinal, pf); + Trace("tconv-pf-gen-rewrite") + << "-> (rewritten postrewrite) " << curHash << " = " << rcurFinal + << std::endl; + visited[curHash] = rcurFinal; + doCache(curHash, cur, rcurFinal, pf); } else { + Trace("tconv-pf-gen-rewrite") << "- postvisit" << std::endl; Node ret = cur; + Node retHash = curHash; bool childChanged = false; std::vector children; if (cur.getMetaKind() == metakind::PARAMETERIZED) { children.push_back(cur.getOperator()); } - for (const Node& cn : cur) + // get the results of the children + if (tctx != nullptr) + { + for (size_t i = 0, nchild = cur.getNumChildren(); i < nchild; i++) + { + Node cn = cur[i]; + uint32_t cnval = tctx->computeValue(cur, curCVal, i); + Node cnHash = TCtxNode::computeNodeHash(cn, cnval); + it = visited.find(cnHash); + Assert(it != visited.end()); + Assert(!it->second.isNull()); + childChanged = childChanged || cn != it->second; + children.push_back(it->second); + } + } + else { - it = visited.find(cn); - Assert(it != visited.end()); - Assert(!it->second.isNull()); - childChanged = childChanged || cn != it->second; - children.push_back(it->second); + // can use simple loop if not term-context-sensitive + for (const Node& cn : cur) + { + it = visited.find(cn); + Assert(it != visited.end()); + Assert(!it->second.isNull()); + childChanged = childChanged || cn != it->second; + children.push_back(it->second); + } } if (childChanged) { ret = nm->mkNode(cur.getKind(), children); - rewritten[cur] = ret; + rewritten[curHash] = ret; // congruence to show (cur = ret) std::vector pfChildren; for (size_t i = 0, size = cur.getNumChildren(); i < size; i++) @@ -260,62 +413,96 @@ Node TConvProofGenerator::getProofForRewriting(Node t, LazyCDProof& pf) } std::vector pfArgs; Kind k = cur.getKind(); + pfArgs.push_back(ProofRuleChecker::mkKindNode(k)); if (kind::metaKindOf(k) == kind::metakind::PARAMETERIZED) { pfArgs.push_back(cur.getOperator()); } - else - { - pfArgs.push_back(nm->operatorOf(k)); - } Node result = cur.eqNode(ret); pf.addStep(result, PfRule::CONG, pfChildren, pfArgs); + // must update the hash + retHash = ret; + if (tctx != nullptr) + { + retHash = TCtxNode::computeNodeHash(ret, curCVal); + } + } + else if (tctx != nullptr) + { + // now we need the hash + retHash = TCtxNode::computeNodeHash(cur, curCVal); } // did we rewrite ret (at post-rewrite)? Node rret; // only if not ONCE policy, which only does pre-rewrite if (d_policy != TConvPolicy::ONCE) { - rret = getRewriteStep(ret); + rret = getRewriteStepInternal(retHash); } if (!rret.isNull()) { - if (cur != ret) - { - visit.push_back(cur); - } + Trace("tconv-pf-gen-rewrite") + << "*** " << retHash << " postrewrites to " << rret << std::endl; // d_proof should have a proof of ret = rret, hence nothing to do // here, for the same reasons as above. It also may be the case that // rret rewrites, hence we must revisit ret. - rewritten[ret] = rret; - visit.push_back(ret); - visit.push_back(rret); + rewritten[retHash] = rret; + if (tctx != nullptr) + { + if (cur != ret) + { + visitctx->push(cur, curCVal); + } + visitctx->push(ret, curCVal); + visitctx->push(rret, curCVal); + } + else + { + if (cur != ret) + { + visit.push_back(cur); + } + visit.push_back(ret); + visit.push_back(rret); + } } else { + Trace("tconv-pf-gen-rewrite") + << "-> (postrewrite) " << curHash << " = " << ret << std::endl; // it is final - visited[cur] = ret; - doCache(cur, ret, pf); + Assert(!ret.isNull()); + visited[curHash] = ret; + doCache(curHash, cur, ret, pf); } } } - } while (!visit.empty()); - Assert(visited.find(t) != visited.end()); - Assert(!visited.find(t)->second.isNull()); + else + { + Trace("tconv-pf-gen-rewrite") << "- already visited" << std::endl; + } + } while (!(tctx != nullptr ? visitctx->empty() : visit.empty())); + Assert(visited.find(tinitialHash) != visited.end()); + Assert(!visited.find(tinitialHash)->second.isNull()); + Trace("tconv-pf-gen-rewrite") + << "...finished, return " << visited[tinitialHash] << std::endl; // return the conclusion of the overall proof - return t.eqNode(visited[t]); + return t.eqNode(visited[tinitialHash]); } -void TConvProofGenerator::doCache(Node cur, Node r, LazyCDProof& pf) +void TConvProofGenerator::doCache(Node curHash, + Node cur, + Node r, + LazyCDProof& pf) { if (d_cpolicy != TConvCachePolicy::NEVER) { Node eq = cur.eqNode(r); - d_cache[cur] = pf.getProofFor(eq); + d_cache[curHash] = pf.getProofFor(eq); } } -Node TConvProofGenerator::getRewriteStep(Node t) const +Node TConvProofGenerator::getRewriteStepInternal(Node t) const { NodeNodeMap::const_iterator it = d_rewriteMap.find(t); if (it == d_rewriteMap.end()) @@ -326,4 +513,12 @@ Node TConvProofGenerator::getRewriteStep(Node t) const } std::string TConvProofGenerator::identify() const { return d_name; } +std::string TConvProofGenerator::toStringDebug() const +{ + std::stringstream ss; + ss << identify() << " (policy=" << d_policy << ", cache policy=" << d_cpolicy + << (d_tcontext != nullptr ? ", term-context-sensitive" : "") << ")"; + return ss.str(); +} + } // namespace CVC4 diff --git a/src/expr/term_conversion_proof_generator.h b/src/expr/term_conversion_proof_generator.h index e634b8a83..faee2b9e3 100644 --- a/src/expr/term_conversion_proof_generator.h +++ b/src/expr/term_conversion_proof_generator.h @@ -21,6 +21,7 @@ #include "expr/lazy_proof.h" #include "expr/proof_generator.h" #include "expr/proof_node_manager.h" +#include "expr/term_context.h" namespace CVC4 { @@ -84,6 +85,35 @@ std::ostream& operator<<(std::ostream& out, TConvCachePolicy tcpol); * addRewriteStep. In particular, notice that in the above example, we realize * that f(a) --> c at pre-rewrite instead of post-rewriting a --> b and then * ending with f(a)=f(b). + * + * This class may additionally be used for term-context-sensitive rewrite + * systems. An example is the term formula removal pass which rewrites + * terms dependending on whether they occur in a "term position", for details + * see RtfTermContext in expr/term_context.h. To use this class in a way + * that takes into account term contexts, the user of the term conversion + * proof generator should: + * (1) Provide a term context callback to the constructor of this class (tccb), + * (2) Register rewrite steps that indicate the term context identifier of + * the rewrite, which is a uint32_t. + * + * For example, RtfTermContext uses hash value 2 to indicate we are in a "term + * position". Say the user of this class calls: + * addRewriteStep( (and A B), BOOLEAN_TERM_VARIABLE_1, pg, true, 2) + * This indicates that (and A B) should rewrite to BOOLEAN_TERM_VARIABLE_1 if + * (and A B) occurs in a term position, where pg is a proof generator that can + * provide a closed proof of: + * (= (and A B) BOOLEAN_TERM_VARIABLE_1) + * Subsequently, this class may respond to a call to getProofFor on: + * (= + * (or (and A B) (P (and A B))) + * (or (and A B) (P BOOLEAN_TERM_VARIABLE_1))) + * where P is a predicate Bool -> Bool. The proof returned by this class + * involves congruence and pg's proof of the equivalence above. In particular, + * assuming its proof of the equivalence is P1, this proof is: + * (CONG{=} (CONG{or} (REFL (and A B)) (CONG{P} P1))) + * Notice the callback provided to this class ensures that the rewrite is + * replayed in the expected way, e.g. the occurrence of (and A B) that is not + * in term position is not rewritten. */ class TConvProofGenerator : public ProofGenerator { @@ -99,32 +129,48 @@ class TConvProofGenerator : public ProofGenerator * details, see d_policy. * @param cpol The caching policy for this generator. * @param name The name of this generator (for debugging). + * @param tccb The term context callback that this class depends on. If this + * is non-null, then this class stores a term-context-sensitive rewrite + * system. The rewrite steps should be given term context identifiers. */ TConvProofGenerator(ProofNodeManager* pnm, context::Context* c = nullptr, TConvPolicy pol = TConvPolicy::FIXPOINT, TConvCachePolicy cpol = TConvCachePolicy::NEVER, - std::string name = "TConvProofGenerator"); + std::string name = "TConvProofGenerator", + TermContext* tccb = nullptr); ~TConvProofGenerator(); /** * Add rewrite step t --> s based on proof generator. + * + * @param isClosed whether to expect that pg can provide a closed proof for + * this fact. + * @param tctx The term context identifier for the rewrite step. This + * value should correspond to one generated by the term context callback + * class provided in the argument tccb provided to the constructor of this + * class. */ - void addRewriteStep(Node t, Node s, ProofGenerator* pg); + void addRewriteStep(Node t, + Node s, + ProofGenerator* pg, + bool isClosed = true, + uint32_t tctx = 0); /** Same as above, for a single step */ - void addRewriteStep(Node t, Node s, ProofStep ps); + void addRewriteStep(Node t, Node s, ProofStep ps, uint32_t tctx = 0); /** Same as above, with explicit arguments */ void addRewriteStep(Node t, Node s, PfRule id, const std::vector& children, - const std::vector& args); + const std::vector& args, + uint32_t tctx = 0); /** Has rewrite step for term t */ - bool hasRewriteStep(Node t) const; + bool hasRewriteStep(Node t, uint32_t tctx = 0) const; /** * Get rewrite step for term t, returns the s provided in a call to * addRewriteStep if one exists, or null otherwise. */ - Node getRewriteStep(Node t) const; + Node getRewriteStep(Node t, uint32_t tctx = 0) const; /** * Get the proof for formula f. It should be the case that f is of the form * t = t', where t' is the result of rewriting t based on the rewrite steps @@ -161,19 +207,25 @@ class TConvProofGenerator : public ProofGenerator std::string d_name; /** The cache for terms */ std::map > d_cache; + /** An (optional) term context object */ + TermContext* d_tcontext; + /** Get rewrite step for (hash value of) term. */ + Node getRewriteStepInternal(Node thash) const; /** * Adds a proof of t = t' to the proof pf where t' is the result of rewriting * t based on the rewrite steps registered to this class. This method then * returns the proved equality t = t'. */ - Node getProofForRewriting(Node t, LazyCDProof& pf); + Node getProofForRewriting(Node t, LazyCDProof& pf, TermContext* tc = nullptr); /** * Register rewrite step, returns the equality t=s if t is distinct from s * and a rewrite step has not already been registered for t. */ - Node registerRewriteStep(Node t, Node s); + Node registerRewriteStep(Node t, Node s, uint32_t tctx); /** cache that r is the rewritten form of cur, pf can provide a proof */ - void doCache(Node cur, Node r, LazyCDProof& pf); + void doCache(Node curHash, Node cur, Node r, LazyCDProof& pf); + /** get debug information on this generator */ + std::string toStringDebug() const; }; } // namespace CVC4 -- cgit v1.2.3 From a692d44ed5ba0107113df54d2654417bc9f9c345 Mon Sep 17 00:00:00 2001 From: Andres Noetzli Date: Wed, 2 Sep 2020 11:30:57 -0700 Subject: Use SMT-COMP configuration for competition build (#4995) This commit changes our `competition` build to include the libraries that we have used for SMT-COMP by default. This makes it easier for users to reproduce our SMT-COMP configuration for performance measurements. We are using GPL libraries for this build type, so the commit adds color to highlight the fact that this build type produces a GPL build. --- CMakeLists.txt | 2 +- NEWS | 2 ++ cmake/ConfigCompetition.cmake | 10 ++++++++++ cmake/Helpers.cmake | 6 ++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 02933762b..06e9c44f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -768,7 +768,7 @@ message("") if(GPL_LIBS) message( - "CVC4 license : GPLv3 (due to optional libraries; see below)" + "CVC4 license : ${Yellow}GPLv3 (due to optional libraries; see below)${ResetColor}" "\n" "\n" "Please note that CVC4 will be built against the following GPLed libraries:" diff --git a/NEWS b/NEWS index f74fe2631..d3e519c9b 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,8 @@ Changes: BSD-licensed Editline. Compiling with `--best` now enables Editline, instead of Readline. Without selecting optional GPL components, Editline-enabled CVC4 builds will be BSD licensed. +* The `competition` build type includes the dependencies used for SMT-COMP by + default. Note that this makes this build type produce GPL-licensed binaries. Changes since 1.7 ================= diff --git a/cmake/ConfigCompetition.cmake b/cmake/ConfigCompetition.cmake index e18d2b2f1..d7188f60a 100644 --- a/cmake/ConfigCompetition.cmake +++ b/cmake/ConfigCompetition.cmake @@ -22,3 +22,13 @@ cvc4_set_option(ENABLE_MUZZLE ON) # enable_shared=no cvc4_set_option(ENABLE_SHARED OFF) cvc4_set_option(ENABLE_UNIT_TESTING OFF) + +# By default, we include all dependencies in our competition build that are +# required to achieve the best performance +set(ENABLE_GPL ON) +cvc4_set_option(USE_CADICAL ON) +cvc4_set_option(USE_CLN ON) +cvc4_set_option(USE_CRYPTOMINISAT ON) +cvc4_set_option(USE_EDITLINE OFF) +cvc4_set_option(USE_GLPK ON) +cvc4_set_option(USE_SYMFPU ON) diff --git a/cmake/Helpers.cmake b/cmake/Helpers.cmake index 692e32900..79c8f7bf2 100644 --- a/cmake/Helpers.cmake +++ b/cmake/Helpers.cmake @@ -1,6 +1,12 @@ include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) +if(NOT WIN32) + string(ASCII 27 Esc) + set(Yellow "${Esc}[33m") + set(ResetColor "${Esc}[m") +endif() + # Add a C flag to the global list of C flags. macro(add_c_flag flag) if(CMAKE_C_FLAGS) -- cgit v1.2.3 From c17f9b25cac7c0d2941ef136466cb750cf4c3e7b Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Wed, 2 Sep 2020 14:01:39 -0500 Subject: (proof-new) Add proof support in TheoryUF (#5002) This makes TheoryUF use a standard theory inference manager, which thus makes it proof producing when proof-new is enabled. This additionally cleans HoExtension so that it does not keep a backwards reference to TheoryUF and instead takes its inference manager. This additionally adds two rules for higher-order that are required to make its equality engine proofs correct. Co-authored-by: Haniel Barbosa --- src/expr/proof_rule.cpp | 2 ++ src/expr/proof_rule.h | 14 ++++++++++++++ src/theory/uf/ho_extension.cpp | 19 +++++++++---------- src/theory/uf/ho_extension.h | 7 ++++--- src/theory/uf/proof_checker.cpp | 30 ++++++++++++++++++++++++++++++ src/theory/uf/theory_uf.cpp | 26 ++++++++++++-------------- src/theory/uf/theory_uf.h | 3 +++ src/theory/uf/theory_uf_rewriter.h | 1 + 8 files changed, 75 insertions(+), 27 deletions(-) diff --git a/src/expr/proof_rule.cpp b/src/expr/proof_rule.cpp index 0a45c6790..bd58fc787 100644 --- a/src/expr/proof_rule.cpp +++ b/src/expr/proof_rule.cpp @@ -94,6 +94,8 @@ const char* toString(PfRule id) case PfRule::TRUE_ELIM: return "TRUE_ELIM"; case PfRule::FALSE_INTRO: return "FALSE_INTRO"; case PfRule::FALSE_ELIM: return "FALSE_ELIM"; + case PfRule::HO_APP_ENCODE: return "HO_APP_ENCODE"; + case PfRule::HO_CONG: return "HO_CONG"; //================================================= Quantifiers rules case PfRule::WITNESS_INTRO: return "WITNESS_INTRO"; case PfRule::EXISTS_INTRO: return "EXISTS_INTRO"; diff --git a/src/expr/proof_rule.h b/src/expr/proof_rule.h index 59c406d28..b6b9f1ea8 100644 --- a/src/expr/proof_rule.h +++ b/src/expr/proof_rule.h @@ -520,6 +520,20 @@ enum class PfRule : uint32_t // ---------------------------------------- // Conclusion: (not F) FALSE_ELIM, + // ======== HO trust + // Children: none + // Arguments: (t) + // --------------------- + // Conclusion: (= t TheoryUfRewriter::getHoApplyForApplyUf(t)) + // For example, this rule concludes (f x y) = (HO_APPLY (HO_APPLY f x) y) + HO_APP_ENCODE, + // ======== Congruence + // Children: (P1:(= f g), P2:(= t1 s1), ..., Pn+1:(= tn sn)) + // Arguments: () + // --------------------------------------------- + // Conclusion: (= (f t1 ... tn) (g s1 ... sn)) + // Notice that this rule is only used when the application kinds are APPLY_UF. + HO_CONG, //================================================= Quantifiers rules // ======== Witness intro diff --git a/src/theory/uf/ho_extension.cpp b/src/theory/uf/ho_extension.cpp index 11b872e72..2a57cde5e 100644 --- a/src/theory/uf/ho_extension.cpp +++ b/src/theory/uf/ho_extension.cpp @@ -18,7 +18,6 @@ #include "expr/node_algorithm.h" #include "options/uf_options.h" #include "theory/theory_model.h" -#include "theory/uf/theory_uf.h" #include "theory/uf/theory_uf_rewriter.h" using namespace std; @@ -28,9 +27,9 @@ namespace CVC4 { namespace theory { namespace uf { -HoExtension::HoExtension(TheoryUF& p, TheoryState& state) - : d_parent(p), - d_state(state), +HoExtension::HoExtension(TheoryState& state, TheoryInferenceManager& im) + : d_state(state), + d_im(im), d_extensionality(state.getUserContext()), d_uf_std_skolem(state.getUserContext()) { @@ -108,7 +107,7 @@ unsigned HoExtension::applyExtensionality(TNode deq) Node lem = NodeManager::currentNM()->mkNode(OR, deq[0], conc); Trace("uf-ho-lemma") << "uf-ho-lemma : extensionality : " << lem << std::endl; - d_parent.getOutputChannel().lemma(lem); + d_im.lemma(lem); return 1; } return 0; @@ -168,7 +167,7 @@ Node HoExtension::getApplyUfForHoApply(Node node) Trace("uf-ho-lemma") << "uf-ho-lemma : Skolem definition for apply-conversion : " << lem << std::endl; - d_parent.getOutputChannel().lemma(lem); + d_im.lemma(lem); d_uf_std_skolem[f] = new_f; } else @@ -257,7 +256,7 @@ unsigned HoExtension::checkExtensionality(TheoryModel* m) Node lem = nm->mkNode(OR, deq.negate(), eq); Trace("uf-ho") << "HoExtension: cmi extensionality lemma " << lem << std::endl; - d_parent.getOutputChannel().lemma(lem); + d_im.lemma(lem); return 1; } } @@ -282,10 +281,10 @@ unsigned HoExtension::applyAppCompletion(TNode n) Node ret = TheoryUfRewriter::getHoApplyForApplyUf(n); if (!ee->hasTerm(ret) || !ee->areEqual(ret, n)) { - Node eq = ret.eqNode(n); + Node eq = n.eqNode(ret); Trace("uf-ho-lemma") << "uf-ho-lemma : infer, by apply-expand : " << eq << std::endl; - ee->assertEquality(eq, true, d_true); + d_im.assertInternalFact(eq, true, PfRule::HO_APP_ENCODE, {}, {n}); return 1; } Trace("uf-ho-debug") << " ...already have " << ret << " == " << n << "." @@ -442,7 +441,7 @@ bool HoExtension::collectModelInfoHoTerm(Node n, TheoryModel* m) Node eq = n.eqNode(hn); Trace("uf-ho") << "HoExtension: cmi app completion lemma " << eq << std::endl; - d_parent.getOutputChannel().lemma(eq); + d_im.lemma(eq); return false; } } diff --git a/src/theory/uf/ho_extension.h b/src/theory/uf/ho_extension.h index 25cb3623b..ceb8e9c12 100644 --- a/src/theory/uf/ho_extension.h +++ b/src/theory/uf/ho_extension.h @@ -21,6 +21,7 @@ #include "context/cdhashset.h" #include "context/cdo.h" #include "expr/node.h" +#include "theory/theory_inference_manager.h" #include "theory/theory_model.h" #include "theory/theory_state.h" @@ -51,7 +52,7 @@ class HoExtension typedef context::CDHashMap NodeNodeMap; public: - HoExtension(TheoryUF& p, TheoryState& state); + HoExtension(TheoryState& state, TheoryInferenceManager& im); /** expand definition * @@ -181,10 +182,10 @@ class HoExtension private: /** common constants */ Node d_true; - /** the parent of this extension */ - TheoryUF& d_parent; /** Reference to the state object */ TheoryState& d_state; + /** Reference to the inference manager */ + TheoryInferenceManager& d_im; /** extensionality has been applied to these disequalities */ NodeSet d_extensionality; diff --git a/src/theory/uf/proof_checker.cpp b/src/theory/uf/proof_checker.cpp index b010b6d17..ea95c1f24 100644 --- a/src/theory/uf/proof_checker.cpp +++ b/src/theory/uf/proof_checker.cpp @@ -14,6 +14,8 @@ #include "theory/uf/proof_checker.h" +#include "theory/uf/theory_uf_rewriter.h" + using namespace CVC4::kind; namespace CVC4 { @@ -31,6 +33,8 @@ void UfProofRuleChecker::registerTo(ProofChecker* pc) pc->registerChecker(PfRule::TRUE_ELIM, this); pc->registerChecker(PfRule::FALSE_INTRO, this); pc->registerChecker(PfRule::FALSE_ELIM, this); + pc->registerChecker(PfRule::HO_CONG, this); + pc->registerChecker(PfRule::HO_APP_ENCODE, this); } Node UfProofRuleChecker::checkInternal(PfRule id, @@ -171,6 +175,32 @@ Node UfProofRuleChecker::checkInternal(PfRule id, } return children[0][0].notNode(); } + if (id == PfRule::HO_CONG) + { + Assert(children.size() > 0); + std::vector lchildren; + std::vector rchildren; + for (size_t i = 0, nchild = children.size(); i < nchild; ++i) + { + Node eqp = children[i]; + if (eqp.getKind() != EQUAL) + { + return Node::null(); + } + lchildren.push_back(eqp[0]); + rchildren.push_back(eqp[1]); + } + NodeManager* nm = NodeManager::currentNM(); + Node l = nm->mkNode(kind::APPLY_UF, lchildren); + Node r = nm->mkNode(kind::APPLY_UF, rchildren); + return l.eqNode(r); + } + else if (id == PfRule::HO_APP_ENCODE) + { + Assert(args.size() == 1); + Node ret = TheoryUfRewriter::getHoApplyForApplyUf(args[0]); + return args[0].eqNode(ret); + } // no rule return Node::null(); } diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp index 3d90637e2..a58834891 100644 --- a/src/theory/uf/theory_uf.cpp +++ b/src/theory/uf/theory_uf.cpp @@ -53,7 +53,8 @@ TheoryUF::TheoryUF(context::Context* c, d_ho(nullptr), d_functionsTerms(c), d_symb(u, instanceName), - d_state(c, u, valuation) + d_state(c, u, valuation), + d_im(*this, d_state, pnm) { d_true = NodeManager::currentNM()->mkConst( true ); @@ -62,8 +63,9 @@ TheoryUF::TheoryUF(context::Context* c, { d_ufProofChecker.registerTo(pc); } - // indicate we are using the default theory state object + // indicate we are using the default theory state and inference managers d_theoryState = &d_state; + d_inferManager = &d_im; } TheoryUF::~TheoryUF() { @@ -96,7 +98,7 @@ void TheoryUF::finishInit() { if (options::ufHo()) { d_equalityEngine->addFunctionKind(kind::HO_APPLY); - d_ho.reset(new HoExtension(*this, d_state)); + d_ho.reset(new HoExtension(d_state, d_im)); } } @@ -304,12 +306,7 @@ void TheoryUF::explain(TNode literal, Node& exp) exp = mkAnd(assumptions); } -TrustNode TheoryUF::explain(TNode literal) -{ - Node explanation; - explain(literal, explanation); - return TrustNode::mkTrustPropExp(literal, explanation, nullptr); -} +TrustNode TheoryUF::explain(TNode literal) { return d_im.explainLit(literal); } bool TheoryUF::collectModelValues(TheoryModel* m, const std::set& termSet) { @@ -338,7 +335,8 @@ void TheoryUF::presolve() { i != newClauses.end(); ++i) { Debug("uf") << "uf: generating a lemma: " << *i << std::endl; - d_out->lemma(*i); + // no proof generator provided + d_im.lemma(*i); } } if( d_thss ){ @@ -652,10 +650,10 @@ void TheoryUF::computeCareGraph() { void TheoryUF::conflict(TNode a, TNode b) { - Node conf; - explain(a.eqNode(b), conf); - d_out->conflict(conf); - d_state.notifyInConflict(); + // call the inference manager, which will construct the conflict (possibly + // with proofs from the underlying proof equality engine), and notify the + // state object. + d_im.conflictEqConstantMerge(a, b); } void TheoryUF::eqNotifyNewClass(TNode t) { diff --git a/src/theory/uf/theory_uf.h b/src/theory/uf/theory_uf.h index 41f2ba9d5..4a8369483 100644 --- a/src/theory/uf/theory_uf.h +++ b/src/theory/uf/theory_uf.h @@ -26,6 +26,7 @@ #include "theory/theory.h" #include "theory/uf/equality_engine.h" #include "theory/uf/proof_checker.h" +#include "theory/uf/proof_equality_engine.h" #include "theory/uf/symmetry_breaker.h" #include "theory/uf/theory_uf_rewriter.h" @@ -205,6 +206,8 @@ private: UfProofRuleChecker d_ufProofChecker; /** A (default) theory state object */ TheoryState d_state; + /** A (default) inference manager */ + TheoryInferenceManager d_im; };/* class TheoryUF */ }/* CVC4::theory::uf namespace */ diff --git a/src/theory/uf/theory_uf_rewriter.h b/src/theory/uf/theory_uf_rewriter.h index e651edb51..5d301cf9e 100644 --- a/src/theory/uf/theory_uf_rewriter.h +++ b/src/theory/uf/theory_uf_rewriter.h @@ -22,6 +22,7 @@ #include "expr/node_algorithm.h" #include "options/uf_options.h" +#include "theory/rewriter.h" #include "theory/substitutions.h" #include "theory/theory_rewriter.h" -- cgit v1.2.3 From f9a4549c3dab3cd91f0d9973b24b7891048ed1d9 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Wed, 2 Sep 2020 14:32:24 -0500 Subject: (proof-new) Updates to builtin proof checker (#4962) This includes support for some trusted rules (whose use is to come). It also modifies THEORY_REWRITE so that it is a "trusted" rule, that is, it is not re-checked. The reason for this is that TheoryRewriter is not deterministic. An example of non-determinism in TheoryRewriter are rules that introduce bound variables (e.g. quantifiers rewriter) since these bound variables are fresh each time it is invoked. Non-deterministic theory rewriters cannot be rechecked, which was leading to failures on proof-new at proof check time. The other way to fix this would be to cache TheoryRewriter responses, but then the checker would only be verifying that the caching was being done properly. This is not worthwhile. --- src/expr/proof_rule.cpp | 4 ++- src/expr/proof_rule.h | 39 ++++++++++++++++----- src/theory/builtin/proof_checker.cpp | 68 +++++++++++++++++++++++++++--------- src/theory/builtin/proof_checker.h | 40 +++++++++++---------- src/theory/rewriter.cpp | 20 +++++++---- src/theory/rewriter.h | 9 +++-- 6 files changed, 124 insertions(+), 56 deletions(-) diff --git a/src/expr/proof_rule.cpp b/src/expr/proof_rule.cpp index bd58fc787..1d46b183f 100644 --- a/src/expr/proof_rule.cpp +++ b/src/expr/proof_rule.cpp @@ -27,13 +27,15 @@ const char* toString(PfRule id) case PfRule::SCOPE: return "SCOPE"; case PfRule::SUBS: return "SUBS"; case PfRule::REWRITE: return "REWRITE"; + case PfRule::EVALUATE: return "EVALUATE"; case PfRule::MACRO_SR_EQ_INTRO: return "MACRO_SR_EQ_INTRO"; case PfRule::MACRO_SR_PRED_INTRO: return "MACRO_SR_PRED_INTRO"; case PfRule::MACRO_SR_PRED_ELIM: return "MACRO_SR_PRED_ELIM"; case PfRule::MACRO_SR_PRED_TRANSFORM: return "MACRO_SR_PRED_TRANSFORM"; - case PfRule::THEORY_REWRITE: return "THEORY_REWRITE"; case PfRule::REMOVE_TERM_FORMULA_AXIOM: return "REMOVE_TERM_FORMULA_AXIOM"; //================================================= Trusted rules + case PfRule::THEORY_LEMMA: return "THEORY_LEMMA"; + case PfRule::THEORY_REWRITE: return "THEORY_REWRITE"; case PfRule::PREPROCESS: return "PREPROCESS"; case PfRule::PREPROCESS_LEMMA: return "PREPROCESS_LEMMA"; case PfRule::THEORY_PREPROCESS: return "THEORY_PREPROCESS"; diff --git a/src/expr/proof_rule.h b/src/expr/proof_rule.h index b6b9f1ea8..825503d5d 100644 --- a/src/expr/proof_rule.h +++ b/src/expr/proof_rule.h @@ -91,6 +91,14 @@ enum class PfRule : uint32_t // where idr is a MethodId identifier, which determines the kind of rewriter // to apply, e.g. Rewriter::rewrite. REWRITE, + // ======== Evaluate + // Children: none + // Arguments: (t) + // ---------------------------------------- + // Conclusion: (= t Evaluator::evaluate(t)) + // Note this is equivalent to: + // (REWRITE t MethodId::RW_EVALUATE) + EVALUATE, // ======== Substitution + Rewriting equality introduction // // In this rule, we provide a term t and conclude that it is equal to its @@ -163,15 +171,6 @@ enum class PfRule : uint32_t // Notice that we apply rewriting on the witness form of F and G, similar to // MACRO_SR_PRED_INTRO. MACRO_SR_PRED_TRANSFORM, - // ======== Theory Rewrite - // Children: none - // Arguments: (t, preRewrite?) - // ---------------------------------------- - // Conclusion: (= t t') - // where - // t' is the result of applying either a pre-rewrite or a post-rewrite step - // to t (depending on the second argument). - THEORY_REWRITE, //================================================= Processing rules // ======== Remove Term Formulas Axiom @@ -182,6 +181,28 @@ enum class PfRule : uint32_t REMOVE_TERM_FORMULA_AXIOM, //================================================= Trusted rules + // ======== Theory lemma + // Children: none + // Arguments: (F, tid) + // --------------------------------------------------------------- + // Conclusion: F + // where F is a (T-valid) theory lemma generated by theory with TheoryId tid. + // This is a "coarse-grained" rule that is used as a placeholder if a theory + // did not provide a proof for a lemma or conflict. + THEORY_LEMMA, + // ======== Theory Rewrite + // Children: none + // Arguments: (F, tid, preRewrite?) + // ---------------------------------------- + // Conclusion: F + // where F is an equality of the form (= t t') where t' is obtained by + // applying the theory rewriter with identifier tid in either its prewrite + // (when preRewrite is true) or postrewrite method. Notice that the checker + // for this rule does not replay the rewrite to ensure correctness, since + // theory rewriter methods are not static. For example, the quantifiers + // rewriter involves constructing new bound variables that are not guaranteed + // to be consistent on each call. + THEORY_REWRITE, // The rules in this section have the signature of a "trusted rule": // // Children: none diff --git a/src/theory/builtin/proof_checker.cpp b/src/theory/builtin/proof_checker.cpp index 7521d116e..cf27b516e 100644 --- a/src/theory/builtin/proof_checker.cpp +++ b/src/theory/builtin/proof_checker.cpp @@ -16,6 +16,7 @@ #include "expr/skolem_manager.h" #include "smt/term_formula_removal.h" +#include "theory/evaluator.h" #include "theory/rewriter.h" #include "theory/theory.h" @@ -29,6 +30,9 @@ const char* toString(MethodId id) switch (id) { case MethodId::RW_REWRITE: return "RW_REWRITE"; + case MethodId::RW_EXT_REWRITE: return "RW_EXT_REWRITE"; + case MethodId::RW_REWRITE_EQ_EXT: return "RW_REWRITE_EQ_EXT"; + case MethodId::RW_EVALUATE: return "RW_EVALUATE"; case MethodId::RW_IDENTITY: return "RW_IDENTITY"; case MethodId::SB_DEFAULT: return "SB_DEFAULT"; case MethodId::SB_LITERAL: return "SB_LITERAL"; @@ -56,6 +60,7 @@ void BuiltinProofRuleChecker::registerTo(ProofChecker* pc) pc->registerChecker(PfRule::SCOPE, this); pc->registerChecker(PfRule::SUBS, this); pc->registerChecker(PfRule::REWRITE, this); + pc->registerChecker(PfRule::EVALUATE, this); pc->registerChecker(PfRule::MACRO_SR_EQ_INTRO, this); pc->registerChecker(PfRule::MACRO_SR_PRED_INTRO, this); pc->registerChecker(PfRule::MACRO_SR_PRED_ELIM, this); @@ -63,6 +68,7 @@ void BuiltinProofRuleChecker::registerTo(ProofChecker* pc) pc->registerChecker(PfRule::THEORY_REWRITE, this); pc->registerChecker(PfRule::REMOVE_TERM_FORMULA_AXIOM, this); // trusted rules + pc->registerTrustedChecker(PfRule::THEORY_LEMMA, this, 1); pc->registerTrustedChecker(PfRule::PREPROCESS, this, 2); pc->registerTrustedChecker(PfRule::PREPROCESS_LEMMA, this, 2); pc->registerTrustedChecker(PfRule::THEORY_PREPROCESS, this, 2); @@ -70,16 +76,6 @@ void BuiltinProofRuleChecker::registerTo(ProofChecker* pc) pc->registerTrustedChecker(PfRule::WITNESS_AXIOM, this, 2); } -Node BuiltinProofRuleChecker::applyTheoryRewrite(Node n, bool preRewrite) -{ - TheoryId tid = Theory::theoryOf(n); - Rewriter* rewriter = Rewriter::getInstance(); - Node nkr = preRewrite ? rewriter->preRewrite(tid, n).d_node - : rewriter->postRewrite(tid, n).d_node; - return nkr; -} - - Node BuiltinProofRuleChecker::applySubstitutionRewrite( Node n, const std::vector& exp, MethodId ids, MethodId idr) { @@ -95,7 +91,20 @@ Node BuiltinProofRuleChecker::applyRewrite(Node n, MethodId idr) { return Rewriter::rewrite(n); } - else if (idr == MethodId::RW_IDENTITY) + if (idr == MethodId::RW_EXT_REWRITE) + { + return d_ext_rewriter.extendedRewrite(n); + } + if (idr == MethodId::RW_REWRITE_EQ_EXT) + { + return Rewriter::rewriteEqualityExt(n); + } + if (idr == MethodId::RW_EVALUATE) + { + Evaluator eval; + return eval.eval(n, {}, {}, false); + } + if (idr == MethodId::RW_IDENTITY) { // does nothing return n; @@ -228,7 +237,7 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id, { exp.push_back(children[i]); } - Node res = applySubstitution(args[0], exp); + Node res = applySubstitution(args[0], exp, ids); return args[0].eqNode(res); } else if (id == PfRule::REWRITE) @@ -243,6 +252,13 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id, Node res = applyRewrite(args[0], idr); return args[0].eqNode(res); } + else if (id == PfRule::EVALUATE) + { + Assert(children.empty()); + Assert(args.size() == 1); + Node res = applyRewrite(args[0], MethodId::RW_EVALUATE); + return args[0].eqNode(res); + } else if (id == PfRule::MACRO_SR_EQ_INTRO) { Assert(1 <= args.size() && args.size() <= 3); @@ -334,13 +350,14 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id, Assert(args.size() == 1); return RemoveTermFormulas::getAxiomFor(args[0]); } - else if (id == PfRule::PREPROCESS || id == PfRule::PREPROCESS_LEMMA - || id == PfRule::THEORY_PREPROCESS - || id == PfRule::THEORY_PREPROCESS_LEMMA - || id == PfRule::WITNESS_AXIOM) + else if (id == PfRule::PREPROCESS || id == PfRule::THEORY_PREPROCESS + || id == PfRule::WITNESS_AXIOM || id == PfRule::THEORY_LEMMA + || id == PfRule::PREPROCESS_LEMMA || id == PfRule::THEORY_REWRITE) { + // "trusted" rules Assert(children.empty()); - Assert(args.size() == 1); + Assert(!args.empty()); + Assert(args[0].getType().isBoolean()); return args[0]; } // no rule @@ -390,6 +407,23 @@ void BuiltinProofRuleChecker::addMethodIds(std::vector& args, } } +bool BuiltinProofRuleChecker::getTheoryId(TNode n, TheoryId& tid) +{ + uint32_t i; + if (!getUInt32(n, i)) + { + return false; + } + tid = static_cast(i); + return true; +} + +Node BuiltinProofRuleChecker::mkTheoryIdNode(TheoryId tid) +{ + return NodeManager::currentNM()->mkConst( + Rational(static_cast(tid))); +} + } // namespace builtin } // namespace theory } // namespace CVC4 diff --git a/src/theory/builtin/proof_checker.h b/src/theory/builtin/proof_checker.h index 7e46587b7..3251b4e9e 100644 --- a/src/theory/builtin/proof_checker.h +++ b/src/theory/builtin/proof_checker.h @@ -20,11 +20,12 @@ #include "expr/node.h" #include "expr/proof_checker.h" #include "expr/proof_node.h" +#include "theory/quantifiers/extended_rewrite.h" namespace CVC4 { namespace theory { -/** +/** * Identifiers for rewriters and substitutions, which we abstractly * classify as "methods". Methods have a unique identifier in the internal * proof calculus implemented by the checker below. @@ -41,6 +42,12 @@ enum class MethodId : uint32_t //---------------------------- Rewriters // Rewriter::rewrite(n) RW_REWRITE, + // d_ext_rew.extendedRewrite(n); + RW_EXT_REWRITE, + // Rewriter::rewriteExtEquality(n) + RW_REWRITE_EQ_EXT, + // Evaluator::evaluate(n) + RW_EVALUATE, // identity RW_IDENTITY, //---------------------------- Substitutions @@ -75,21 +82,10 @@ class BuiltinProofRuleChecker : public ProofRuleChecker * specifying a call to Rewriter::rewrite. * @return The rewritten form of n. */ - static Node applyRewrite(Node n, MethodId idr = MethodId::RW_REWRITE); - /** - * Apply small-step rewrite on n in skolem form (either pre- or - * post-rewrite). This encapsulates the exact behavior of a THEORY_REWRITE - * step in a proof. - * - * @param n The node to rewrite - * @param preRewrite If true, performs a pre-rewrite or a post-rewrite - * otherwise - * @return The rewritten form of n - */ - static Node applyTheoryRewrite(Node n, bool preRewrite); + Node applyRewrite(Node n, MethodId idr = MethodId::RW_REWRITE); /** * Get substitution. Updates vars/subs to the substitution specified by - * exp (e.g. as an equality) for the substitution method ids. + * exp for the substitution method ids. */ static bool getSubstitution(Node exp, TNode& var, @@ -123,10 +119,10 @@ class BuiltinProofRuleChecker : public ProofRuleChecker * @param idr The method identifier of the rewriter. * @return The substituted, rewritten form of n. */ - static Node applySubstitutionRewrite(Node n, - const std::vector& exp, - MethodId ids = MethodId::SB_DEFAULT, - MethodId idr = MethodId::RW_REWRITE); + Node applySubstitutionRewrite(Node n, + const std::vector& exp, + MethodId ids = MethodId::SB_DEFAULT, + MethodId idr = MethodId::RW_REWRITE); /** get a method identifier from a node, return false if we fail */ static bool getMethodId(TNode n, MethodId& i); /** @@ -144,6 +140,11 @@ class BuiltinProofRuleChecker : public ProofRuleChecker */ static void addMethodIds(std::vector& args, MethodId ids, MethodId idr); + /** get a TheoryId from a node, return false if we fail */ + static bool getTheoryId(TNode n, TheoryId& tid); + /** Make a TheoryId into a node */ + static Node mkTheoryIdNode(TheoryId tid); + /** Register all rules owned by this rule checker into pc. */ void registerTo(ProofChecker* pc) override; protected: @@ -151,6 +152,9 @@ class BuiltinProofRuleChecker : public ProofRuleChecker Node checkInternal(PfRule id, const std::vector& children, const std::vector& args) override; + + /** extended rewriter object */ + quantifiers::ExtendedRewriter d_ext_rewriter; }; } // namespace builtin diff --git a/src/theory/rewriter.cpp b/src/theory/rewriter.cpp index f2e13d1e0..9238525dc 100644 --- a/src/theory/rewriter.cpp +++ b/src/theory/rewriter.cpp @@ -21,6 +21,7 @@ #include "smt/smt_engine.h" #include "smt/smt_engine_scope.h" #include "smt/smt_statistics_registry.h" +#include "theory/builtin/proof_checker.h" #include "theory/rewriter_tables.h" #include "theory/theory.h" #include "util/resource_manager.h" @@ -115,13 +116,18 @@ TrustNode Rewriter::rewriteWithProof(TNode node, return TrustNode::mkTrustRewrite(node, ret, d_tpg.get()); } -void Rewriter::setProofChecker(ProofChecker* pc) +void Rewriter::setProofNodeManager(ProofNodeManager* pnm) { // if not already initialized with proof support if (d_tpg == nullptr) { - d_pnm.reset(new ProofNodeManager(pc)); - d_tpg.reset(new TConvProofGenerator(d_pnm.get())); + // the rewriter is staticly determinstic, thus use static cache policy + // for the term conversion proof generator + d_tpg.reset(new TConvProofGenerator(pnm, + nullptr, + TConvPolicy::FIXPOINT, + TConvCachePolicy::STATIC, + "Rewriter::TConvProofGenerator")); } } @@ -391,7 +397,7 @@ RewriteResponse Rewriter::preRewrite(theory::TheoryId theoryId, d_theoryRewriters[theoryId]->preRewriteWithProof(n); // process the trust rewrite response: store the proof step into // tcpg if necessary and then convert to rewrite response. - return processTrustRewriteResponse(tresponse, true, tcpg); + return processTrustRewriteResponse(theoryId, tresponse, true, tcpg); } return d_theoryRewriters[theoryId]->preRewrite(n); } @@ -412,7 +418,7 @@ RewriteResponse Rewriter::postRewrite(theory::TheoryId theoryId, // same as above, for post-rewrite TrustRewriteResponse tresponse = d_theoryRewriters[theoryId]->postRewriteWithProof(n); - return processTrustRewriteResponse(tresponse, false, tcpg); + return processTrustRewriteResponse(theoryId, tresponse, false, tcpg); } return d_theoryRewriters[theoryId]->postRewrite(n); } @@ -420,6 +426,7 @@ RewriteResponse Rewriter::postRewrite(theory::TheoryId theoryId, } RewriteResponse Rewriter::processTrustRewriteResponse( + theory::TheoryId theoryId, const TrustRewriteResponse& tresponse, bool isPre, TConvProofGenerator* tcpg) @@ -433,13 +440,14 @@ RewriteResponse Rewriter::processTrustRewriteResponse( ProofGenerator* pg = trn.getGenerator(); if (pg == nullptr) { + Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(theoryId); // add small step trusted rewrite NodeManager* nm = NodeManager::currentNM(); tcpg->addRewriteStep(proven[0], proven[1], PfRule::THEORY_REWRITE, {}, - {proven[0], nm->mkConst(isPre)}); + {proven, tidn, nm->mkConst(isPre)}); } else { diff --git a/src/theory/rewriter.h b/src/theory/rewriter.h index c57844f23..113749a75 100644 --- a/src/theory/rewriter.h +++ b/src/theory/rewriter.h @@ -80,7 +80,7 @@ class Rewriter { /** * Rewrite with proof production, which is managed by the term conversion * proof generator managed by this class (d_tpg). This method requires a call - * to setProofChecker prior to this call. + * to setProofNodeManager prior to this call. * * @param node The node to rewrite. * @param elimTheoryRewrite Whether we also want fine-grained proofs for @@ -94,8 +94,8 @@ class Rewriter { bool elimTheoryRewrite = false, bool isExtEq = false); - /** Set proof checker */ - void setProofChecker(ProofChecker* pc); + /** Set proof node manager */ + void setProofNodeManager(ProofNodeManager* pnm); /** * Garbage collects the rewrite caches. @@ -189,6 +189,7 @@ class Rewriter { TConvProofGenerator* tcpg = nullptr); /** processes a trust rewrite response */ RewriteResponse processTrustRewriteResponse( + theory::TheoryId theoryId, const TrustRewriteResponse& tresponse, bool isPre, TConvProofGenerator* tcpg); @@ -226,8 +227,6 @@ class Rewriter { RewriteEnvironment d_re; - /** The proof node manager */ - std::unique_ptr d_pnm; /** The proof generator */ std::unique_ptr d_tpg; #ifdef CVC4_ASSERTIONS -- cgit v1.2.3 From f845c04a147021937f1b0a942ee2080df950cda3 Mon Sep 17 00:00:00 2001 From: Gereon Kremer Date: Wed, 2 Sep 2020 22:15:30 +0200 Subject: Remove #line directives from generated files. (#5005) This PR removes any usage of the #line directive. We no longer consider it particularly useful, and it obstructs reproducible builds (see #4980). Fixes #4980. --- src/expr/expr_manager_template.cpp | 6 ------ src/expr/expr_manager_template.h | 6 ------ src/expr/expr_template.cpp | 6 ------ src/expr/expr_template.h | 8 -------- src/expr/kind_template.cpp | 3 --- src/expr/kind_template.h | 3 --- src/expr/metakind_template.h | 2 -- src/expr/mkexpr | 15 --------------- src/expr/mkkind | 26 +++++++++++--------------- src/expr/mkmetakind | 8 -------- src/expr/type_checker_template.cpp | 8 -------- src/expr/type_properties_template.h | 10 ---------- src/theory/mkrewriter | 4 ---- src/theory/mktheorytraits | 9 --------- src/theory/theory_traits_template.h | 2 -- src/theory/type_enumerator_template.cpp | 2 -- 16 files changed, 11 insertions(+), 107 deletions(-) diff --git a/src/expr/expr_manager_template.cpp b/src/expr/expr_manager_template.cpp index 0d22a3c41..bac9e3b43 100644 --- a/src/expr/expr_manager_template.cpp +++ b/src/expr/expr_manager_template.cpp @@ -26,12 +26,6 @@ ${includes} -// This is a hack, but an important one: if there's an error, the -// compiler directs the user to the template file instead of the -// generated one. We don't want the user to modify the generated one, -// since it'll get overwritten on a later build. -#line 34 "${template}" - #ifdef CVC4_STATISTICS_ON #define INC_STAT(kind) \ { \ diff --git a/src/expr/expr_manager_template.h b/src/expr/expr_manager_template.h index a6fce56a2..145f64bd3 100644 --- a/src/expr/expr_manager_template.h +++ b/src/expr/expr_manager_template.h @@ -28,12 +28,6 @@ ${includes} -// This is a hack, but an important one: if there's an error, the -// compiler directs the user to the template file instead of the -// generated one. We don't want the user to modify the generated one, -// since it'll get overwritten on a later build. -#line 36 "${template}" - namespace CVC4 { namespace api { diff --git a/src/expr/expr_template.cpp b/src/expr/expr_template.cpp index 226736e8f..a92081fe8 100644 --- a/src/expr/expr_template.cpp +++ b/src/expr/expr_template.cpp @@ -29,12 +29,6 @@ ${includes} -// This is a hack, but an important one: if there's an error, the -// compiler directs the user to the template file instead of the -// generated one. We don't want the user to modify the generated one, -// since it'll get overwritten on a later build. -#line 37 "${template}" - using namespace CVC4::kind; using namespace std; diff --git a/src/expr/expr_template.h b/src/expr/expr_template.h index 34374d354..0acce2cb0 100644 --- a/src/expr/expr_template.h +++ b/src/expr/expr_template.h @@ -39,12 +39,6 @@ ${includes} #include "options/language.h" #include "util/hash.h" -// This is a hack, but an important one: if there's an error, the -// compiler directs the user to the template file instead of the -// generated one. We don't want the user to modify the generated one, -// since it'll get overwritten on a later build. -#line 47 "${template}" - namespace CVC4 { // The internal expression representation @@ -621,8 +615,6 @@ private: ${getConst_instantiations} -#line 625 "${template}" - inline size_t ExprHashFunction::operator()(CVC4::Expr e) const { return (size_t) e.getId(); } diff --git a/src/expr/kind_template.cpp b/src/expr/kind_template.cpp index 0d7f5f4e4..b2e165558 100644 --- a/src/expr/kind_template.cpp +++ b/src/expr/kind_template.cpp @@ -69,7 +69,6 @@ std::string kindToString(::CVC4::Kind k) { std::ostream& operator<<(std::ostream& out, TypeConstant typeConstant) { switch(typeConstant) { ${type_constant_descriptions} -#line 73 "${template}" default: out << "UNKNOWN_TYPE_CONSTANT"; break; @@ -85,7 +84,6 @@ TheoryId kindToTheoryId(::CVC4::Kind k) { case kind::NULL_EXPR: break; ${kind_to_theory_id} -#line 89 "${template}" case kind::LAST_KIND: break; } @@ -97,7 +95,6 @@ TheoryId typeConstantToTheoryId(::CVC4::TypeConstant typeConstant) switch (typeConstant) { ${type_constant_to_theory_id} -#line 101 "${template}" case LAST_TYPE: break; } throw IllegalArgumentException( diff --git a/src/expr/kind_template.h b/src/expr/kind_template.h index d34179252..8ae7018b3 100644 --- a/src/expr/kind_template.h +++ b/src/expr/kind_template.h @@ -63,8 +63,6 @@ const char* toString(CVC4::Kind k); */ std::ostream& operator<<(std::ostream&, CVC4::Kind) CVC4_PUBLIC; -#line 67 "${template}" - /** Returns true if the given kind is associative. This is used by ExprManager to * decide whether it's safe to modify big expressions by changing the grouping of * the arguments. */ @@ -86,7 +84,6 @@ struct KindHashFunction { enum CVC4_PUBLIC TypeConstant { ${type_constant_list} -#line 90 "${template}" LAST_TYPE }; /* enum TypeConstant */ diff --git a/src/expr/metakind_template.h b/src/expr/metakind_template.h index 5fa10c90a..e1668836b 100644 --- a/src/expr/metakind_template.h +++ b/src/expr/metakind_template.h @@ -201,8 +201,6 @@ Kind operatorToKind(::CVC4::expr::NodeValue* nv); }/* CVC4::kind namespace */ -#line 205 "${template}" - }/* CVC4 namespace */ #endif /* CVC4__NODE_MANAGER_NEEDS_CONSTANT_MAP */ diff --git a/src/expr/mkexpr b/src/expr/mkexpr index c5f12f487..58531cba4 100755 --- a/src/expr/mkexpr +++ b/src/expr/mkexpr @@ -150,9 +150,7 @@ function typerule { lineno=${BASH_LINENO[0]} check_theory_seen typerules="${typerules} -#line $lineno \"$kf\" case kind::$1: -#line $lineno \"$kf\" typeNode = $2::computeType(nodeManager, n, check); break; " @@ -163,9 +161,7 @@ function construle { lineno=${BASH_LINENO[0]} check_theory_seen construles="${construles} -#line $lineno \"$kf\" case kind::$1: -#line $lineno \"$kf\" return $2::computeIsConst(nodeManager, n); " } @@ -218,26 +214,19 @@ function constant { fi mkConst_instantiations="${mkConst_instantiations} -#line $lineno \"$kf\" template <> Expr ExprManager::mkConst($2 const& val); " mkConst_implementations="${mkConst_implementations} -#line $lineno \"$kf\" template <> Expr ExprManager::mkConst($2 const& val) { -#line $lineno \"$kf\" return Expr(this, new Node(d_nodeManager->mkConst< $2 >(val))); } " getConst_instantiations="${getConst_instantiations} -#line $lineno \"$kf\" template <> $2 const & Expr::getConst< $2 >() const; " getConst_implementations="${getConst_implementations} -#line $lineno \"$kf\" template <> $2 const & Expr::getConst() const { -#line $lineno \"$kf\" PrettyCheckArgument(getKind() == ::CVC4::kind::$1, *this, \"Improper kind for getConst<$2>()\"); -#line $lineno \"$kf\" return d_node->getConst< $2 >(); } " @@ -288,10 +277,6 @@ check_builtin_theory_seen ## output -# generate warnings about incorrect #line annotations in templates -nl -ba -s' ' "$template" | grep '^ *[0-9][0-9]* # *line' | - awk '{OFS="";if($1+1!=$3) print "'"$template"':",$1,": warning: incorrect annotation \"#line ",$3,"\" (it should be \"#line ",($1+1),"\")"}' >&2 - text=$(cat "$template") for var in \ includes \ diff --git a/src/expr/mkkind b/src/expr/mkkind index fbf37eff4..55276549a 100755 --- a/src/expr/mkkind +++ b/src/expr/mkkind @@ -257,23 +257,23 @@ function register_sort { " type_constant_to_theory_id="${type_constant_to_theory_id} case $id: return $theory_id; " - type_constant_cardinalities="${type_constant_cardinalities}#line $lineno \"$kf\" + type_constant_cardinalities="${type_constant_cardinalities} case $id: return Cardinality($cardinality); " - type_constant_wellfoundednesses="${type_constant_wellfoundednesses}#line $lineno \"$kf\" + type_constant_wellfoundednesses="${type_constant_wellfoundednesses} case $id: return $wellfoundedness; " if [ -n "$groundterm" ]; then - type_constant_groundterms="${type_constant_groundterms}#line $lineno \"$kf\" + type_constant_groundterms="${type_constant_groundterms} case $id: return $groundterm; " if [ -n "$header" ]; then - type_properties_includes="${type_properties_includes}#line $lineno \"$kf\" + type_properties_includes="${type_properties_includes} #include \"$header\" " fi else - type_constant_groundterms="${type_constant_groundterms}#line $lineno \"$kf\" + type_constant_groundterms="${type_constant_groundterms} case $id: Unhandled() << tc; " fi @@ -284,11 +284,11 @@ function register_cardinality { cardinality_computer=$(sed 's,%TYPE%,typeNode,g' <<<"$2") header=$3 - type_cardinalities="${type_cardinalities}#line $lineno \"$kf\" + type_cardinalities="${type_cardinalities} case $id: return $cardinality_computer; " if [ -n "$header" ]; then - type_properties_includes="${type_properties_includes}#line $lineno \"$kf\" + type_properties_includes="${type_properties_includes} #include \"$header\" " fi @@ -314,20 +314,20 @@ function register_wellfoundedness { fi fi - type_wellfoundednesses="${type_wellfoundednesses}#line $lineno \"$kf\" + type_wellfoundednesses="${type_wellfoundednesses} case $id: return $wellfoundedness_computer; " if [ -n "$groundterm_computer" ]; then - type_groundterms="${type_groundterms}#line $lineno \"$kf\" + type_groundterms="${type_groundterms} case $id: return $groundterm_computer; " else - type_groundterms="${type_groundterms}#line $lineno \"$kf\" + type_groundterms="${type_groundterms} case $id: Unhandled() << typeNode; " fi if [ -n "$header" ]; then - type_properties_includes="${type_properties_includes}#line $lineno \"$kf\" + type_properties_includes="${type_properties_includes} #include \"$header\" " fi @@ -390,10 +390,6 @@ check_builtin_theory_seen ## output -# generate warnings about incorrect #line annotations in templates -nl -ba -s' ' "$template" | grep '^ *[0-9][0-9]* # *line' | - awk '{OFS="";if($1+1!=$3) print "'"$template"':",$1,": warning: incorrect annotation \"#line ",$3,"\" (it should be \"#line ",($1+1),"\")"}' >&2 - text=$(cat "$template") for var in \ kind_decls \ diff --git a/src/expr/mkmetakind b/src/expr/mkmetakind index e2a733ec8..9d2f0a475 100755 --- a/src/expr/mkmetakind +++ b/src/expr/mkmetakind @@ -270,19 +270,16 @@ $2 const& NodeValue::getConst< $2 >() const { " metakind_constHashes="${metakind_constHashes} case kind::$1: -#line $lineno \"$kf\" return $3()(nv->getConst< $2 >()); " metakind_constPrinters="${metakind_constPrinters} case kind::$1: -#line $lineno \"$kf\" out << nv->getConst< $2 >(); break; " cname=`echo "$2" | awk 'BEGIN {FS="::"} {print$NF}'` metakind_constDeleters="${metakind_constDeleters} case kind::$1: -#line $lineno \"$kf\" std::allocator< $2 >().destroy(reinterpret_cast< $2* >(nv->d_children)); break; " @@ -301,7 +298,6 @@ function registerOperatorToKind { operatorKind=$1 applyKind=$2 metakind_operatorKinds="${metakind_operatorKinds} -#line $lineno \"$kf\" case kind::$applyKind: return kind::$operatorKind;"; } @@ -396,10 +392,6 @@ check_builtin_theory_seen ## output -# generate warnings about incorrect #line annotations in templates -nl -ba -s' ' "$template" | grep '^ *[0-9][0-9]* # *line' | - awk '{OFS="";if($1+1!=$3) print "'"$template"':",$1,": warning: incorrect annotation \"#line ",$3,"\" (it should be \"#line ",($1+1),"\")"}' >&2 - text=$(cat "$template") for var in \ metakind_includes \ diff --git a/src/expr/type_checker_template.cpp b/src/expr/type_checker_template.cpp index 3dedd856a..8e4dd9236 100644 --- a/src/expr/type_checker_template.cpp +++ b/src/expr/type_checker_template.cpp @@ -14,8 +14,6 @@ ** TypeChecker implementation. **/ -#line 18 "${template}" - #include "expr/node_manager.h" #include "expr/node_manager_attributes.h" #include "expr/type_checker.h" @@ -23,8 +21,6 @@ ${typechecker_includes} -#line 27 "${template}" - namespace CVC4 { namespace expr { @@ -44,8 +40,6 @@ TypeNode TypeChecker::computeType(NodeManager* nodeManager, TNode n, bool check) ${typerules} -#line 48 "${template}" - default: Debug("getType") << "FAILURE" << std::endl; Unhandled() << n.getKind(); @@ -68,8 +62,6 @@ bool TypeChecker::computeIsConst(NodeManager* nodeManager, TNode n) switch(n.getKind()) { ${construles} -#line 72 "${template}" - default:; } diff --git a/src/expr/type_properties_template.h b/src/expr/type_properties_template.h index a8adadf6e..9bccd5892 100644 --- a/src/expr/type_properties_template.h +++ b/src/expr/type_properties_template.h @@ -19,8 +19,6 @@ #ifndef CVC4__TYPE_PROPERTIES_H #define CVC4__TYPE_PROPERTIES_H -#line 23 "${template}" - #include #include "base/check.h" @@ -31,8 +29,6 @@ ${type_properties_includes} -#line 35 "${template}" - namespace CVC4 { namespace kind { @@ -47,7 +43,6 @@ inline Cardinality getCardinality(TypeConstant tc) switch (tc) { ${type_constant_cardinalities} -#line 51 "${template}" default: InternalError() << "No cardinality known for type constant " << tc; } } /* getCardinality(TypeConstant) */ @@ -64,7 +59,6 @@ inline Cardinality getCardinality(TypeNode typeNode) { case TYPE_CONSTANT: return getCardinality(typeNode.getConst()); ${type_cardinalities} -#line 68 "${template}" default: InternalError() << "A theory kinds file did not provide a cardinality " << "or cardinality computer for type:\n" @@ -75,7 +69,6 @@ ${type_cardinalities} inline bool isWellFounded(TypeConstant tc) { switch(tc) { ${type_constant_wellfoundednesses} -#line 79 "${template}" default: InternalError() << "No well-foundedness status known for type constant: " << tc; @@ -88,7 +81,6 @@ inline bool isWellFounded(TypeNode typeNode) { case TYPE_CONSTANT: return isWellFounded(typeNode.getConst()); ${type_wellfoundednesses} -#line 92 "${template}" default: InternalError() << "A theory kinds file did not provide a well-foundedness " << "or well-foundedness computer for type:\n" @@ -101,7 +93,6 @@ inline Node mkGroundTerm(TypeConstant tc) switch (tc) { ${type_constant_groundterms} -#line 105 "${template}" default: InternalError() << "No ground term known for type constant: " << tc; } @@ -115,7 +106,6 @@ inline Node mkGroundTerm(TypeNode typeNode) case TYPE_CONSTANT: return mkGroundTerm(typeNode.getConst()); ${type_groundterms} -#line 119 "${template}" default: InternalError() << "A theory kinds file did not provide a ground term " << "or ground term computer for type:\n" diff --git a/src/theory/mkrewriter b/src/theory/mkrewriter index 3c27f1b53..871927760 100755 --- a/src/theory/mkrewriter +++ b/src/theory/mkrewriter @@ -243,10 +243,6 @@ check_builtin_theory_seen ## output -# generate warnings about incorrect #line annotations in templates -nl -ba -s' ' "$template" | grep '^ *[0-9][0-9]* # *line' | - awk '{OFS="";if($1+1!=$3) print "'"$template"':",$1,": warning: incorrect annotation \"#line ",$3,"\" (it should be \"#line ",($1+1),"\")"}' >&2 - text=$(cat "$template") for var in \ rewriter_includes \ diff --git a/src/theory/mktheorytraits b/src/theory/mktheorytraits index a87203015..1b1350abe 100755 --- a/src/theory/mktheorytraits +++ b/src/theory/mktheorytraits @@ -214,20 +214,15 @@ function enumerator { lineno=${BASH_LINENO[0]} check_theory_seen type_enumerator_includes="${type_enumerator_includes} -#line $lineno \"$kf\" #include \"$3\"" if expr "$type_constants" : '.* '"$1"' ' &>/dev/null; then mk_type_enumerator_type_constant_cases="${mk_type_enumerator_type_constant_cases} -#line $lineno \"$kf\" case $1: -#line $lineno \"$kf\" return new $2(type, tep); " elif expr "$type_kinds" : '.* '"$1"' ' &>/dev/null; then mk_type_enumerator_cases="${mk_type_enumerator_cases} -#line $lineno \"$kf\" case kind::$1: -#line $lineno \"$kf\" return new $2(type, tep); " else @@ -395,10 +390,6 @@ check_builtin_theory_seen eval "theory_constructors=\"$theory_constructors\"" -# generate warnings about incorrect #line annotations in templates -nl -ba -s' ' "$template" | grep '^ *[0-9][0-9]* # *line' | - awk '{OFS="";if($1+1!=$3) print "'"$template"':",$1,": warning: incorrect annotation \"#line ",$3,"\" (it should be \"#line ",($1+1),"\")"}' >&2 - text=$(cat "$template") for var in \ theory_traits \ diff --git a/src/theory/theory_traits_template.h b/src/theory/theory_traits_template.h index 775f42a46..d591affba 100644 --- a/src/theory/theory_traits_template.h +++ b/src/theory/theory_traits_template.h @@ -34,8 +34,6 @@ struct TheoryTraits; ${theory_traits} -#line 38 "${template}" - struct TheoryConstructor { static void addTheory(TheoryEngine* engine, TheoryId id) { switch(id) { diff --git a/src/theory/type_enumerator_template.cpp b/src/theory/type_enumerator_template.cpp index e9fdc6a86..47405f74e 100644 --- a/src/theory/type_enumerator_template.cpp +++ b/src/theory/type_enumerator_template.cpp @@ -22,7 +22,6 @@ ${type_enumerator_includes} -#line 26 "${template}" using namespace std; @@ -42,7 +41,6 @@ TypeEnumeratorInterface* TypeEnumerator::mkTypeEnumerator( } Unreachable(); ${mk_type_enumerator_cases} -#line 46 "${template}" default: Unhandled() << "No type enumerator for type `" << type << "'"; } Unreachable(); -- cgit v1.2.3 From 0f9fb31069d51e003a39b0e93f506324dec2bdac Mon Sep 17 00:00:00 2001 From: Andres Noetzli Date: Wed, 2 Sep 2020 14:02:26 -0700 Subject: [Python API] Add missing methods to Datatype/Term (#4998) Fixes #4942. The Python API was missing some methods related to datatypes. Most importantly, it was missing mkDatatypeSorts, which meant that datatypes with unresolved placeholders could not be resolved. This commit adds missing methods and ports the corresponding tests of datatype_api_black.h to Python. The commit also adds support for __getitem__ in Term. --- src/api/cvc4cpp.cpp | 9 +- src/api/cvc4cpp.h | 9 +- src/api/python/cvc4.pxd | 10 ++ src/api/python/cvc4.pxi | 47 ++++++++ test/unit/api/python/test_datatype_api.py | 171 ++++++++++++++++++++++++++++++ test/unit/api/python/test_term.py | 11 ++ 6 files changed, 249 insertions(+), 8 deletions(-) create mode 100644 test/unit/api/python/test_datatype_api.py diff --git a/src/api/cvc4cpp.cpp b/src/api/cvc4cpp.cpp index 6c39bfb91..5b3384439 100644 --- a/src/api/cvc4cpp.cpp +++ b/src/api/cvc4cpp.cpp @@ -3148,8 +3148,8 @@ Term Solver::mkTermHelper(Kind kind, const std::vector& children) const } std::vector Solver::mkDatatypeSortsInternal( - std::vector& dtypedecls, - std::set& unresolvedSorts) const + const std::vector& dtypedecls, + const std::set& unresolvedSorts) const { NodeManagerScope scope(getNodeManager()); CVC4_API_SOLVER_TRY_CATCH_BEGIN; @@ -3367,8 +3367,9 @@ std::vector Solver::mkDatatypeSorts( CVC4_API_SOLVER_TRY_CATCH_END; } -std::vector Solver::mkDatatypeSorts(std::vector& dtypedecls, - std::set& unresolvedSorts) const +std::vector Solver::mkDatatypeSorts( + const std::vector& dtypedecls, + const std::set& unresolvedSorts) const { CVC4_API_SOLVER_TRY_CATCH_BEGIN; return mkDatatypeSortsInternal(dtypedecls, unresolvedSorts); diff --git a/src/api/cvc4cpp.h b/src/api/cvc4cpp.h index d92660920..acf34abf9 100644 --- a/src/api/cvc4cpp.h +++ b/src/api/cvc4cpp.h @@ -2254,8 +2254,9 @@ class CVC4_PUBLIC Solver * @param unresolvedSorts the list of unresolved sorts * @return the datatype sorts */ - std::vector mkDatatypeSorts(std::vector& dtypedecls, - std::set& unresolvedSorts) const; + std::vector mkDatatypeSorts( + const std::vector& dtypedecls, + const std::set& unresolvedSorts) const; /** * Create function sort. @@ -3353,8 +3354,8 @@ class CVC4_PUBLIC Solver * @return the datatype sorts */ std::vector mkDatatypeSortsInternal( - std::vector& dtypedecls, - std::set& unresolvedSorts) const; + const std::vector& dtypedecls, + const std::set& unresolvedSorts) const; /** * Synthesize n-ary function following specified syntactic constraints. diff --git a/src/api/python/cvc4.pxd b/src/api/python/cvc4.pxd index 841fbb44d..76dcc5317 100644 --- a/src/api/python/cvc4.pxd +++ b/src/api/python/cvc4.pxd @@ -1,6 +1,7 @@ # import dereference and increment operators from cython.operator cimport dereference as deref, preincrement as inc from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t +from libcpp.set cimport set from libcpp.string cimport string from libcpp.vector cimport vector from libcpp.pair cimport pair @@ -27,6 +28,12 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api": Term getConstructorTerm(const string& name) except + size_t getNumConstructors() except + bint isParametric() except + + bint isCodatatype() except + + bint isTuple() except + + bint isRecord() except + + bint isFinite() except + + bint isWellFounded() except + + bint hasNestedRecursion() except + string toString() except + cppclass const_iterator: const_iterator() except + @@ -127,6 +134,8 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api": Sort mkBitVectorSort(uint32_t size) except + Sort mkFloatingPointSort(uint32_t exp, uint32_t sig) except + Sort mkDatatypeSort(DatatypeDecl dtypedecl) except + + vector[Sort] mkDatatypeSorts(const vector[DatatypeDecl]& dtypedecls, + const set[Sort]& unresolvedSorts) except + Sort mkFunctionSort(Sort domain, Sort codomain) except + Sort mkFunctionSort(const vector[Sort]& sorts, Sort codomain) except + Sort mkParamSort(const string& symbol) except + @@ -313,6 +322,7 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api": Term() bint operator==(const Term&) except + bint operator!=(const Term&) except + + Term operator[](size_t idx) except + Kind getKind() except + Sort getSort() except + Term substitute(const vector[Term] es, const vector[Term] & reps) except + diff --git a/src/api/python/cvc4.pxi b/src/api/python/cvc4.pxi index 3caead057..8c4bfe5e5 100644 --- a/src/api/python/cvc4.pxi +++ b/src/api/python/cvc4.pxi @@ -3,6 +3,7 @@ import sys from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t from libcpp.pair cimport pair +from libcpp.set cimport set from libcpp.string cimport string from libcpp.vector cimport vector @@ -110,6 +111,24 @@ cdef class Datatype: def isParametric(self): return self.cd.isParametric() + def isCodatatype(self): + return self.cd.isCodatatype() + + def isTuple(self): + return self.cd.isTuple() + + def isRecord(self): + return self.cd.isRecord() + + def isFinite(self): + return self.cd.isFinite() + + def isWellFounded(self): + return self.cd.isWellFounded() + + def hasNestedRecursion(self): + return self.cd.hasNestedRecursion() + def __str__(self): return self.cd.toString().decode() @@ -449,6 +468,26 @@ cdef class Solver: sort.csort = self.csolver.mkDatatypeSort(dtypedecl.cdd) return sort + def mkDatatypeSorts(self, list dtypedecls, unresolvedSorts): + sorts = [] + + cdef vector[c_DatatypeDecl] decls + for decl in dtypedecls: + decls.push_back(( decl).cdd) + + cdef set[c_Sort] usorts + for usort in unresolvedSorts: + usorts.insert(( usort).csort) + + csorts = self.csolver.mkDatatypeSorts( + decls, usorts) + for csort in csorts: + sort = Sort(self) + sort.csort = csort + sorts.append(sort) + + return sorts + def mkFunctionSort(self, sorts, Sort codomain): cdef Sort sort = Sort(self) @@ -1354,6 +1393,14 @@ cdef class Term: def __ne__(self, Term other): return self.cterm != other.cterm + def __getitem__(self, int index): + cdef Term term = Term(self.solver) + if index >= 0: + term.cterm = self.cterm[index] + else: + raise ValueError("Expecting a non-negative integer or string") + return term + def __str__(self): return self.cterm.toString().decode() diff --git a/test/unit/api/python/test_datatype_api.py b/test/unit/api/python/test_datatype_api.py new file mode 100644 index 000000000..a5499ffd6 --- /dev/null +++ b/test/unit/api/python/test_datatype_api.py @@ -0,0 +1,171 @@ +import pytest + +import pycvc4 +from pycvc4 import kinds + + +def test_datatype_simply_rec(): + solver = pycvc4.Solver() + + # Create mutual datatypes corresponding to this definition block: + # + # DATATYPE + # wlist = leaf(data: list), + # list = cons(car: wlist, cdr: list) | nil, + # ns = elem(ndata: set(wlist)) | elemArray(ndata2: array(list, list)) + # END; + + # Make unresolved types as placeholders + unres_wlist = solver.mkUninterpretedSort('wlist') + unres_list = solver.mkUninterpretedSort('list') + unres_ns = solver.mkUninterpretedSort('ns') + unres_types = set([unres_wlist, unres_list, unres_ns]) + + wlist = solver.mkDatatypeDecl('wlist') + leaf = solver.mkDatatypeConstructorDecl('leaf') + leaf.addSelector('data', unres_list) + wlist.addConstructor(leaf) + + dlist = solver.mkDatatypeDecl('list') + cons = solver.mkDatatypeConstructorDecl('cons') + cons.addSelector('car', unres_wlist) + cons.addSelector('cdr', unres_list) + dlist.addConstructor(cons) + nil = solver.mkDatatypeConstructorDecl("nil") + dlist.addConstructor(nil) + + ns = solver.mkDatatypeDecl('ns') + elem = solver.mkDatatypeConstructorDecl('elem') + elem.addSelector('ndata', solver.mkSetSort(unres_wlist)) + ns.addConstructor(elem) + elem_array = solver.mkDatatypeConstructorDecl('elemArray') + elem_array.addSelector('ndata', solver.mkArraySort(unres_list, unres_list)) + ns.addConstructor(elem_array) + + # this is well-founded and has no nested recursion + dtdecls = [wlist, dlist, ns] + dtsorts = solver.mkDatatypeSorts(dtdecls, unres_types) + assert len(dtsorts) == 3 + assert dtsorts[0].getDatatype().isWellFounded() + assert dtsorts[1].getDatatype().isWellFounded() + assert dtsorts[2].getDatatype().isWellFounded() + assert not dtsorts[0].getDatatype().hasNestedRecursion() + assert not dtsorts[1].getDatatype().hasNestedRecursion() + assert not dtsorts[2].getDatatype().hasNestedRecursion() + + # Create mutual datatypes corresponding to this definition block: + # DATATYPE + # ns2 = elem2(ndata: array(int,ns2)) | nil2 + # END; + unres_ns2 = solver.mkUninterpretedSort('ns2') + unres_types = set([unres_ns2]) + + ns2 = solver.mkDatatypeDecl('ns2') + elem2 = solver.mkDatatypeConstructorDecl('elem2') + elem2.addSelector('ndata', + solver.mkArraySort(solver.getIntegerSort(), unres_ns2)) + ns2.addConstructor(elem2) + nil2 = solver.mkDatatypeConstructorDecl('nil2') + ns2.addConstructor(nil2) + + # this is not well-founded due to non-simple recursion + dtdecls = [ns2] + dtsorts = solver.mkDatatypeSorts(dtdecls, unres_types) + assert len(dtsorts) == 1 + assert dtsorts[0].getDatatype()[0][0].getRangeSort().isArray() + elem_sort = dtsorts[0].getDatatype()[0][0].getRangeSort().getArrayElementSort() + assert elem_sort == dtsorts[0] + assert dtsorts[0].getDatatype().isWellFounded() + assert dtsorts[0].getDatatype().hasNestedRecursion() + + # Create mutual datatypes corresponding to this definition block: + # DATATYPE + # list3 = cons3(car: ns3, cdr: list3) | nil3, + # ns3 = elem3(ndata: set(list3)) + # END + unres_ns3 = solver.mkUninterpretedSort('ns3') + unres_list3 = solver.mkUninterpretedSort('list3') + unres_types = set([unres_ns3, unres_list3]) + + list3 = solver.mkDatatypeDecl('list3') + cons3 = solver.mkDatatypeConstructorDecl('cons3') + cons3.addSelector('car', unres_ns3) + cons3.addSelector('cdr', unres_list3) + list3.addConstructor(cons3) + nil3 = solver.mkDatatypeConstructorDecl('nil3') + list3.addConstructor(nil3) + + ns3 = solver.mkDatatypeDecl('ns3') + elem3 = solver.mkDatatypeConstructorDecl('elem3') + elem3.addSelector('ndata', solver.mkSetSort(unres_list3)) + ns3.addConstructor(elem3) + + # both are well-founded and have nested recursion + dtdecls = [list3, ns3] + dtsorts = solver.mkDatatypeSorts(dtdecls, unres_types) + assert len(dtsorts) == 2 + assert dtsorts[0].getDatatype().isWellFounded() + assert dtsorts[1].getDatatype().isWellFounded() + assert dtsorts[0].getDatatype().hasNestedRecursion() + assert dtsorts[1].getDatatype().hasNestedRecursion() + + # Create mutual datatypes corresponding to this definition block: + # DATATYPE + # list4 = cons(car: set(ns4), cdr: list4) | nil, + # ns4 = elem(ndata: list4) + # END + unres_ns4 = solver.mkUninterpretedSort('ns4') + unres_list4 = solver.mkUninterpretedSort('list4') + unres_types = set([unres_ns4, unres_list4]) + + list4 = solver.mkDatatypeDecl('list4') + cons4 = solver.mkDatatypeConstructorDecl('cons4') + cons4.addSelector('car', solver.mkSetSort(unres_ns4)) + cons4.addSelector('cdr', unres_list4) + list4.addConstructor(cons4) + nil4 = solver.mkDatatypeConstructorDecl('nil4') + list4.addConstructor(nil4) + + ns4 = solver.mkDatatypeDecl('ns4') + elem4 = solver.mkDatatypeConstructorDecl('elem3') + elem4.addSelector('ndata', unres_list4) + ns4.addConstructor(elem4) + + # both are well-founded and have nested recursion + dtdecls = [list4, ns4] + dtsorts = solver.mkDatatypeSorts(dtdecls, unres_types) + assert len(dtsorts) == 2 + assert dtsorts[0].getDatatype().isWellFounded() + assert dtsorts[1].getDatatype().isWellFounded() + assert dtsorts[0].getDatatype().hasNestedRecursion() + assert dtsorts[1].getDatatype().hasNestedRecursion() + + # Create mutual datatypes corresponding to this definition block: + # DATATYPE + # list5[X] = cons(car: X, cdr: list5[list5[X]]) | nil + # END + unres_list5 = solver.mkSortConstructorSort('list5', 1) + unres_types = set([unres_list5]) + + x = solver.mkParamSort('X') + v = [x] + list5 = solver.mkDatatypeDecl('list5', v) + + args = [x] + ur_list_x = unres_list5.instantiate(args) + args = [ur_list_x] + ur_list_list_x = unres_list5.instantiate(args) + + cons5 = solver.mkDatatypeConstructorDecl('cons5') + cons5.addSelector('car', x) + cons5.addSelector('cdr', ur_list_list_x) + list5.addConstructor(cons5) + nil5 = solver.mkDatatypeConstructorDecl('nil5') + list5.addConstructor(nil5) + + # well-founded and has nested recursion + dtdecls = [list5] + dtsorts = solver.mkDatatypeSorts(dtdecls, unres_types) + assert len(dtsorts) == 1 + assert dtsorts[0].getDatatype().isWellFounded() + assert dtsorts[0].getDatatype().hasNestedRecursion() diff --git a/test/unit/api/python/test_term.py b/test/unit/api/python/test_term.py index b135e4510..ca8d4c741 100644 --- a/test/unit/api/python/test_term.py +++ b/test/unit/api/python/test_term.py @@ -4,6 +4,17 @@ import pycvc4 from pycvc4 import kinds +def test_getitem(): + solver = pycvc4.Solver() + intsort = solver.getIntegerSort() + x = solver.mkConst(intsort, 'x') + y = solver.mkConst(intsort, 'y') + xpy = solver.mkTerm(kinds.Plus, x, y) + + assert xpy[0] == x + assert xpy[1] == y + + def test_get_kind(): solver = pycvc4.Solver() intsort = solver.getIntegerSort() -- cgit v1.2.3