From 7145d0772794013fd6eb2f145a43a30be64aa557 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Thu, 6 Dec 2018 10:38:05 -0600 Subject: Take into account minimality and types for cached PBE solutions (#2738) --- src/theory/quantifiers/sygus/sygus_unif_io.cpp | 50 ++++++++++++++++++++++---- src/theory/quantifiers/sygus/sygus_unif_io.h | 9 +++-- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/theory/quantifiers/sygus/sygus_unif_io.cpp b/src/theory/quantifiers/sygus/sygus_unif_io.cpp index a6e6b54c6..0b378875c 100644 --- a/src/theory/quantifiers/sygus/sygus_unif_io.cpp +++ b/src/theory/quantifiers/sygus/sygus_unif_io.cpp @@ -1013,6 +1013,7 @@ Node SygusUnifIo::constructSol( bool retValMod = x.isReturnValueModified(); Node ret_dt; + Node cached_ret_dt; if (nrole == role_equal) { if (!retValMod) @@ -1094,14 +1095,14 @@ Node SygusUnifIo::constructSol( { bool firstTime = true; std::unordered_set intersection; - std::map>::iterator + std::map>::iterator pit; for (size_t i = 0, nvals = x.d_vals.size(); i < nvals; i++) { if (x.d_vals[i].getConst()) { - pit = d_psolutions.find(i); - if (pit == d_psolutions.end()) + pit = d_psolutions[i].find(etn); + if (pit == d_psolutions[i].end()) { // no cached solution intersection.clear(); @@ -1135,12 +1136,31 @@ Node SygusUnifIo::constructSol( } if (!intersection.empty()) { - ret_dt = *intersection.begin(); + if (d_enableMinimality) + { + // if we are enabling minimality, the minimal cached solution may + // still not be the best solution, thus we remember it and keep it if + // we don't construct a better one below + std::vector intervec; + intervec.insert( + intervec.begin(), intersection.begin(), intersection.end()); + cached_ret_dt = getMinimalTerm(intervec); + } + else + { + ret_dt = *intersection.begin(); + } if (Trace.isOn("sygus-sui-dt")) { indent("sygus-sui-dt", ind); Trace("sygus-sui-dt") << "ConstructPBE: found in cache: "; - TermDbSygus::toStreamSygus("sygus-sui-dt", ret_dt); + Node csol = ret_dt; + if (d_enableMinimality) + { + csol = cached_ret_dt; + Trace("sygus-sui-dt") << "(minimal) "; + } + TermDbSygus::toStreamSygus("sygus-sui-dt", csol); Trace("sygus-sui-dt") << std::endl; } } @@ -1455,6 +1475,24 @@ Node SygusUnifIo::constructSol( sindex++; } + // if there was a cached solution, process it now + if (!cached_ret_dt.isNull() && cached_ret_dt != ret_dt) + { + if (ret_dt.isNull()) + { + // take the cached one if it is the only one + ret_dt = cached_ret_dt; + } + else if (d_enableMinimality) + { + Assert(ret_dt.getType() == cached_ret_dt.getType()); + // take the cached one if it is smaller + std::vector retDts; + retDts.push_back(cached_ret_dt); + retDts.push_back(ret_dt); + ret_dt = getMinimalTerm(retDts); + } + } Assert(ret_dt.isNull() || ret_dt.getType() == e.getType()); if (Trace.isOn("sygus-sui-dt")) { @@ -1479,7 +1517,7 @@ Node SygusUnifIo::constructSol( TermDbSygus::toStreamSygus("sygus-sui-cache", ret_dt); Trace("sygus-sui-cache") << std::endl; } - d_psolutions[i].insert(ret_dt); + d_psolutions[i][etn].insert(ret_dt); } } } diff --git a/src/theory/quantifiers/sygus/sygus_unif_io.h b/src/theory/quantifiers/sygus/sygus_unif_io.h index f189353b0..7f48645bf 100644 --- a/src/theory/quantifiers/sygus/sygus_unif_io.h +++ b/src/theory/quantifiers/sygus/sygus_unif_io.h @@ -304,9 +304,14 @@ class SygusUnifIo : public SygusUnif unsigned d_sol_term_size; /** partial solutions * - * Maps indices for I/O points to a list of solutions for that point. + * Maps indices for I/O points to a list of solutions for that point, for each + * type. We may have more than one type for solutions, e.g. for grammar: + * A -> ite( A, B, C ) | ... + * where terms of type B and C can both act as solutions. */ - std::map> d_psolutions; + std::map>> + d_psolutions; /** * This flag is set to true if the solution construction was * non-deterministic with respect to failure/success. -- cgit v1.2.3 From 63fb4e8c33db706589fe41476c4d3358fb47164e Mon Sep 17 00:00:00 2001 From: Andres Noetzli Date: Thu, 6 Dec 2018 15:23:00 -0800 Subject: Fix use-after-free due to destruction order (#2739) A test for PR #2737 was failing even though the PR only added dead code. This PR fixes the issue by fixing two use-after-free bugs: - `ResolutionBitVectorProof` has a `Context` and a `std::unique_ptr` member. The `BVSatProof` depends on the `Context` and tries to access it (indirectly) in its constructor but because the context was declared after the proof, the context was destroyed before the proof, leading to a use-after-free in a method called from the proof's destructor. This commit reorders the two members. - `TLazyBitblaster` was destroyed before the `LFSCCnfProof` in `BitVectorProof` because `SmtEngine`'s destructor first destroyed the theory engine and then the proof manager. This lead to a use-after-free because `LFSCCnfProof` was using the `d_nullContext` of `TLazyBitblaster`, which got indirectly accessed in `LFSCCnfProof`'s destructor. This commit moves the destruction of `ProofManager` above the destruction of the theory engine. The issues were likely introduced by #2599. They went undetected because our nightlies' ASAN check does not use proofs due to known memory leaks in the proof module of CVC4. I have tested this PR up to regression level 2 with ASAN with leak detection disabled. --- src/proof/resolution_bitvector_proof.h | 3 ++- src/smt/smt_engine.cpp | 21 ++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/proof/resolution_bitvector_proof.h b/src/proof/resolution_bitvector_proof.h index a54d72d3f..ccb288f6e 100644 --- a/src/proof/resolution_bitvector_proof.h +++ b/src/proof/resolution_bitvector_proof.h @@ -98,6 +98,8 @@ class ResolutionBitVectorProof : public BitVectorProof void initCnfProof(prop::CnfStream* cnfStream, context::Context* cnf) override; protected: + 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; @@ -105,7 +107,6 @@ class ResolutionBitVectorProof : public BitVectorProof bool d_isAssumptionConflict; theory::TheoryId getTheoryId() override; - context::Context d_fakeContext; }; class LFSCBitVectorProof : public ResolutionBitVectorProof diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp index a0939f4db..6814ad531 100644 --- a/src/smt/smt_engine.cpp +++ b/src/smt/smt_engine.cpp @@ -1071,6 +1071,18 @@ SmtEngine::~SmtEngine() //destroy all passes before destroying things that they refer to d_private->cleanupPreprocessingPasses(); + // d_proofManager is always created when proofs are enabled at configure + // time. Because of this, this code should not be wrapped in PROOF() which + // additionally checks flags such as options::proof(). + // + // Note: the proof manager must be destroyed before the theory engine. + // Because the destruction of the proofs depends on contexts owned be the + // theory solvers. +#ifdef CVC4_PROOF + delete d_proofManager; + d_proofManager = NULL; +#endif + delete d_theoryEngine; d_theoryEngine = NULL; delete d_propEngine; @@ -1078,15 +1090,6 @@ SmtEngine::~SmtEngine() delete d_decisionEngine; d_decisionEngine = NULL; - -// d_proofManager is always created when proofs are enabled at configure time. -// Becuase of this, this code should not be wrapped in PROOF() which -// additionally checks flags such as options::proof(). -#ifdef CVC4_PROOF - delete d_proofManager; - d_proofManager = NULL; -#endif - delete d_stats; d_stats = NULL; delete d_statisticsRegistry; -- cgit v1.2.3 From 14fc21fc1101587810e64b0ed78ce03622e2939d Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Thu, 6 Dec 2018 18:56:56 -0800 Subject: Enable BV proofs when using an eager bitblaster (#2733) * Enable BV proofs when using and eager bitblaster Specifically: * Removed assertions that blocked them. * Made sure that only bitvectors were stored in the BV const let-map * Prevented true/false from being bit-blasted by the eager bitblaster Also: * uncommented "no-check-proofs" from relevant tests * Option handler logic for BV proofs BV eager proofs only work when minisat is the sat solver being used by the BV theory. Added logic to the --proof hanlder to verify this or throw an option exception. * Bugfix for proof options handler I forgot that proofEnabledBuild runs even if the --proof option is negated. In my handler I now check that proofs are enabled. * Clang-format --- src/options/options_handler.cpp | 9 ++++++++- src/proof/bitvector_proof.cpp | 6 +++--- src/proof/proof_manager.cpp | 3 +-- src/theory/bv/bitblast/eager_bitblaster.cpp | 4 ++-- test/regress/regress0/bv/ackermann1.smt2 | 2 +- test/regress/regress0/bv/ackermann2.smt2 | 2 +- test/regress/regress1/bv/bug787.smt2 | 2 +- 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/options/options_handler.cpp b/src/options/options_handler.cpp index bd5b00728..a808ecd3c 100644 --- a/src/options/options_handler.cpp +++ b/src/options/options_handler.cpp @@ -1632,7 +1632,14 @@ void OptionsHandler::setProduceAssertions(std::string option, bool value) void OptionsHandler::proofEnabledBuild(std::string option, bool value) { -#ifndef CVC4_PROOF +#ifdef CVC4_PROOF + if (value && options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER + && options::bvSatSolver() != theory::bv::SAT_SOLVER_MINISAT) + { + throw OptionException( + "Eager BV proofs only supported when minisat is used"); + } +#else if(value) { std::stringstream ss; ss << "option `" << option << "' requires a proofs-enabled build of CVC4; this binary was not built with proof support"; diff --git a/src/proof/bitvector_proof.cpp b/src/proof/bitvector_proof.cpp index c9e98d170..9eb39e2e2 100644 --- a/src/proof/bitvector_proof.cpp +++ b/src/proof/bitvector_proof.cpp @@ -81,7 +81,9 @@ void BitVectorProof::registerTerm(Expr term) { Debug("pf::bv") << "BitVectorProof::registerTerm( " << term << " )" << std::endl; - if (options::lfscLetification() && term.isConst()) { + if (options::lfscLetification() && term.isConst() + && term.getType().isBitVector()) + { if (d_constantLetMap.find(term) == d_constantLetMap.end()) { std::ostringstream name; name << "letBvc" << d_constantLetMap.size(); @@ -624,8 +626,6 @@ void BitVectorProof::printBitblasting(std::ostream& os, std::ostream& paren) std::vector::const_iterator it = d_bbTerms.begin(); std::vector::const_iterator end = d_bbTerms.end(); - Assert(options::bitblastMode() != theory::bv::BITBLAST_MODE_EAGER); - for (; it != end; ++it) { if (d_usedBB.find(*it) == d_usedBB.end()) { Debug("pf::bv") << "\t" << *it << "\t(UNUSED)" << std::endl; diff --git a/src/proof/proof_manager.cpp b/src/proof/proof_manager.cpp index 5b26432dd..9878972bf 100644 --- a/src/proof/proof_manager.cpp +++ b/src/proof/proof_manager.cpp @@ -559,8 +559,6 @@ void LFSCProof::toStream(std::ostream& out, const ProofLetMap& map) const void LFSCProof::toStream(std::ostream& out) const { - Assert(options::bitblastMode() != theory::bv::BITBLAST_MODE_EAGER); - Assert(!d_satProof->proofConstructed()); d_satProof->constructProof(); @@ -730,6 +728,7 @@ void LFSCProof::toStream(std::ostream& out) const d_theoryProof->printTheoryLemmas(used_lemmas, out, paren, globalLetMap); Debug("pf::pm") << "Proof manager: printing theory lemmas DONE!" << std::endl; + out << ";; Printing final unsat proof \n"; if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER && ProofManager::getBitVectorProof()) { proof::LFSCProofPrinter::printResolutionEmptyClause( ProofManager::getBitVectorProof()->getSatProof(), out, paren); diff --git a/src/theory/bv/bitblast/eager_bitblaster.cpp b/src/theory/bv/bitblast/eager_bitblaster.cpp index 33d5a1c80..019918c2f 100644 --- a/src/theory/bv/bitblast/eager_bitblaster.cpp +++ b/src/theory/bv/bitblast/eager_bitblaster.cpp @@ -99,8 +99,8 @@ void EagerBitblaster::bbFormula(TNode node) void EagerBitblaster::bbAtom(TNode node) { node = node.getKind() == kind::NOT ? node[0] : node; - if (node.getKind() == kind::BITVECTOR_BITOF) return; - if (hasBBAtom(node)) + if (node.getKind() == kind::BITVECTOR_BITOF + || node.getKind() == kind::CONST_BOOLEAN || hasBBAtom(node)) { return; } diff --git a/test/regress/regress0/bv/ackermann1.smt2 b/test/regress/regress0/bv/ackermann1.smt2 index 9b96b38c4..218fd746b 100644 --- a/test/regress/regress0/bv/ackermann1.smt2 +++ b/test/regress/regress0/bv/ackermann1.smt2 @@ -1,4 +1,4 @@ -; COMMAND-LINE: --bitblast=eager --no-check-models --no-check-proofs --no-check-unsat-cores +; COMMAND-LINE: --bitblast=eager --no-check-models --no-check-unsat-cores ; EXPECT: sat (set-logic QF_UFBV) (set-info :smt-lib-version 2.0) diff --git a/test/regress/regress0/bv/ackermann2.smt2 b/test/regress/regress0/bv/ackermann2.smt2 index eeca505fe..b1aaa7d64 100644 --- a/test/regress/regress0/bv/ackermann2.smt2 +++ b/test/regress/regress0/bv/ackermann2.smt2 @@ -1,4 +1,4 @@ -; COMMAND-LINE: --bitblast=eager --no-check-models --no-check-proofs --no-check-unsat-cores +; COMMAND-LINE: --bitblast=eager --no-check-models --no-check-unsat-cores ; EXPECT: unsat (set-logic QF_UFBV) (set-info :smt-lib-version 2.0) diff --git a/test/regress/regress1/bv/bug787.smt2 b/test/regress/regress1/bv/bug787.smt2 index 8e0ba0016..d732b9ff0 100644 --- a/test/regress/regress1/bv/bug787.smt2 +++ b/test/regress/regress1/bv/bug787.smt2 @@ -1,4 +1,4 @@ -; COMMAND-LINE: --bitblast=eager --no-check-proofs +; COMMAND-LINE: --bitblast=eager ; EXPECT: unsat (set-logic QF_BV) (set-info :status unsat) -- cgit v1.2.3 From 136a30c2b8cb06d607c5544a3911f120216b3663 Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Thu, 6 Dec 2018 20:00:03 -0800 Subject: Arith Constraint Proof Loggin (#2732) * Arith Constraint Proof Logging Also a tiny documentation update. * Debug.isOn check around iterated output * reference iteratees --- src/theory/arith/constraint.cpp | 29 ++++++++++++++++++++++++++++- src/theory/arith/constraint.h | 6 +++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/theory/arith/constraint.cpp b/src/theory/arith/constraint.cpp index ff71f6432..352ba0f36 100644 --- a/src/theory/arith/constraint.cpp +++ b/src/theory/arith/constraint.cpp @@ -602,7 +602,7 @@ void ConstraintRule::print(std::ostream& out) const { bool Constraint::wellFormedFarkasProof() const { Assert(hasProof()); - + const ConstraintRule& cr = getConstraintRule(); if(cr.d_constraint != this){ return false; } if(cr.d_proofType != FarkasAP){ return false; } @@ -1071,6 +1071,7 @@ ConstraintP ConstraintDatabase::lookup(TNode literal) const{ } void Constraint::setAssumption(bool nowInConflict){ + Debug("constraints::pf") << "setAssumption(" << this << ")" << std::endl; Assert(!hasProof()); Assert(negationHasProof() == nowInConflict); Assert(hasLiteral()); @@ -1113,6 +1114,7 @@ void Constraint::propagate(){ * 1*(x <= a) + (-1)*(x > b) => (0 <= a-b) */ void Constraint::impliedByUnate(ConstraintCP imp, bool nowInConflict){ + Debug("constraints::pf") << "impliedByUnate(" << this << ", " << *imp << ")" << std::endl; Assert(!hasProof()); Assert(imp->hasProof()); Assert(negationHasProof() == nowInConflict); @@ -1152,6 +1154,8 @@ void Constraint::impliedByUnate(ConstraintCP imp, bool nowInConflict){ } void Constraint::impliedByTrichotomy(ConstraintCP a, ConstraintCP b, bool nowInConflict){ + Debug("constraints::pf") << "impliedByTrichotomy(" << this << ", " << *a << ", "; + Debug("constraints::pf") << *b << ")" << std::endl; Assert(!hasProof()); Assert(negationHasProof() == nowInConflict); Assert(a->hasProof()); @@ -1180,6 +1184,7 @@ bool Constraint::allHaveProof(const ConstraintCPVec& b){ } void Constraint::impliedByIntHole(ConstraintCP a, bool nowInConflict){ + Debug("constraints::pf") << "impliedByIntHole(" << this << ", " << *a << ")" << std::endl; Assert(!hasProof()); Assert(negationHasProof() == nowInConflict); Assert(a->hasProof()); @@ -1196,6 +1201,15 @@ void Constraint::impliedByIntHole(ConstraintCP a, bool nowInConflict){ } void Constraint::impliedByIntHole(const ConstraintCPVec& b, bool nowInConflict){ + Debug("constraints::pf") << "impliedByIntHole(" << this; + if (Debug.isOn("constraints::pf")) { + for (const ConstraintCP& p : b) + { + Debug("constraints::pf") << ", " << p; + } + } + Debug("constraints::pf") << ")" << std::endl; + Assert(!hasProof()); Assert(negationHasProof() == nowInConflict); Assert(allHaveProof(b)); @@ -1224,6 +1238,15 @@ void Constraint::impliedByIntHole(const ConstraintCPVec& b, bool nowInConflict){ * coeff.back() corresponds to the current constraint. */ void Constraint::impliedByFarkas(const ConstraintCPVec& a, RationalVectorCP coeffs, bool nowInConflict){ + Debug("constraints::pf") << "impliedByFarkas(" << this; + if (Debug.isOn("constraints::pf")) { + for (const ConstraintCP& p : a) + { + Debug("constraints::pf") << ", " << p; + } + } + Debug("constraints::pf") << ", "; + Debug("constraints::pf") << ")" << std::endl; Assert(!hasProof()); Assert(negationHasProof() == nowInConflict); Assert(allHaveProof(a)); @@ -1263,6 +1286,8 @@ void Constraint::impliedByFarkas(const ConstraintCPVec& a, RationalVectorCP coef void Constraint::setInternalAssumption(bool nowInConflict){ + Debug("constraints::pf") << "setInternalAssumption(" << this; + Debug("constraints::pf") << ")" << std::endl; Assert(!hasProof()); Assert(negationHasProof() == nowInConflict); Assert(!assertedToTheTheory()); @@ -1277,6 +1302,8 @@ void Constraint::setInternalAssumption(bool nowInConflict){ void Constraint::setEqualityEngineProof(){ + Debug("constraints::pf") << "setEqualityEngineProof(" << this; + Debug("constraints::pf") << ")" << std::endl; Assert(truthIsUnknown()); Assert(hasLiteral()); d_database->pushConstraintRule(ConstraintRule(this, EqualityEngineAP)); diff --git a/src/theory/arith/constraint.h b/src/theory/arith/constraint.h index 5eef9663e..d411f2d34 100644 --- a/src/theory/arith/constraint.h +++ b/src/theory/arith/constraint.h @@ -928,7 +928,11 @@ private: /** Return true if every element in b has a proof. */ static bool allHaveProof(const ConstraintCPVec& b); - /** Precondition: hasFarkasProof() */ + /** Precondition: hasFarkasProof() + * Computes the combination implied by the farkas coefficients. Sees if it is + * a contradiction. + */ + bool wellFormedFarkasProof() const; }; /* class ConstraintValue */ -- cgit v1.2.3 From 7270b2a800c45fa87ef4cdcad8fc353ccb8cd471 Mon Sep 17 00:00:00 2001 From: Andres Noetzli Date: Fri, 7 Dec 2018 07:48:38 -0800 Subject: Strings: Make EXTF_d inference more conservative (#2740) --- src/theory/strings/theory_strings.cpp | 6 +++--- test/regress/CMakeLists.txt | 1 + test/regress/regress2/strings/extf_d_perf.smt2 | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 test/regress/regress2/strings/extf_d_perf.smt2 diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp index 9da6fd277..5179ddab3 100644 --- a/src/theory/strings/theory_strings.cpp +++ b/src/theory/strings/theory_strings.cpp @@ -1662,9 +1662,9 @@ void TheoryStrings::checkExtfEval( int effort ) { << ", const = " << einfo.d_const << std::endl; for (const Node& nrcc : nrc) { - sendInference(einfo.d_exp, - einfo.d_const == d_false ? nrcc.negate() : nrcc, - effort == 0 ? "EXTF_d" : "EXTF_d-N"); + sendInternalInference(einfo.d_exp, + einfo.d_const == d_false ? nrcc.negate() : nrcc, + effort == 0 ? "EXTF_d" : "EXTF_d-N"); } }else{ to_reduce = nrc; diff --git a/test/regress/CMakeLists.txt b/test/regress/CMakeLists.txt index e0e57acf9..f22796929 100644 --- a/test/regress/CMakeLists.txt +++ b/test/regress/CMakeLists.txt @@ -1729,6 +1729,7 @@ set(regress_2_tests regress2/strings/cmu-disagree-0707-dd.smt2 regress2/strings/cmu-prereg-fmf.smt2 regress2/strings/cmu-repl-len-nterm.smt2 + regress2/strings/extf_d_perf.smt2 regress2/strings/issue918.smt2 regress2/strings/non_termination_regular_expression6.smt2 regress2/strings/norn-dis-0707-3.smt2 diff --git a/test/regress/regress2/strings/extf_d_perf.smt2 b/test/regress/regress2/strings/extf_d_perf.smt2 new file mode 100644 index 000000000..7ad094dcb --- /dev/null +++ b/test/regress/regress2/strings/extf_d_perf.smt2 @@ -0,0 +1,19 @@ +; COMMAND-LINE: --strings-exp --strings-fmf +; EXPECT: sat +(set-logic ALL) +(declare-fun _substvar_140_ () String) +(declare-fun _substvar_195_ () Int) +(declare-fun _substvar_201_ () Int) +(assert (let ((_let_0 (str.substr _substvar_140_ 10 (+ 0 (str.len _substvar_140_))))) (let ((_let_3 (str.substr _let_0 0 (str.indexof _let_0 "/" 0)))) (let ((_let_4 (str.substr _let_3 0 7))) (let ((_let_5 (str.substr _let_3 8 (+ _substvar_201_ (str.len _let_3))))) + (and + (str.contains _substvar_140_ "://") + (str.contains _let_3 "@") + (str.contains _let_5 ",") + (not (= (str.len (str.substr _let_0 (+ 1 (str.indexof _let_0 "/" 0)) _substvar_195_)) 0)) + (not (= (str.len _let_4) 0)) + (not (str.contains _let_0 ".sock")) + (not (str.contains _let_4 "@")) + (not (= (str.len _let_5) 0)) + (= "mongodb://" (str.substr _substvar_140_ 0 10)))))))) +(check-sat) + -- cgit v1.2.3 From e1dc39321cd4ab29b436025badfb05714f5649b3 Mon Sep 17 00:00:00 2001 From: makaimann Date: Mon, 10 Dec 2018 08:37:11 -0800 Subject: BoolToBV modes (off, ite, all) (#2530) --- src/options/CMakeLists.txt | 2 + src/options/bool_to_bv_mode.cpp | 42 ++++ src/options/bool_to_bv_mode.h | 57 +++++ src/options/bv_options.toml | 17 +- src/options/options_handler.cpp | 44 ++++ src/options/options_handler.h | 4 + src/preprocessing/passes/bool_to_bv.cpp | 326 ++++++++++++++++----------- src/preprocessing/passes/bool_to_bv.h | 37 +-- src/smt/smt_engine.cpp | 38 +++- src/theory/bv/theory_bv.cpp | 2 +- test/regress/CMakeLists.txt | 3 +- test/regress/regress0/bv/bool-to-bv-all.smt2 | 19 ++ test/regress/regress0/bv/bool-to-bv-ite.smt2 | 13 ++ test/regress/regress0/bv/bool-to-bv.smt2 | 19 -- 14 files changed, 447 insertions(+), 176 deletions(-) create mode 100644 src/options/bool_to_bv_mode.cpp create mode 100644 src/options/bool_to_bv_mode.h create mode 100644 test/regress/regress0/bv/bool-to-bv-all.smt2 create mode 100644 test/regress/regress0/bv/bool-to-bv-ite.smt2 delete mode 100644 test/regress/regress0/bv/bool-to-bv.smt2 diff --git a/src/options/CMakeLists.txt b/src/options/CMakeLists.txt index c711567ab..b86db8d00 100644 --- a/src/options/CMakeLists.txt +++ b/src/options/CMakeLists.txt @@ -9,6 +9,8 @@ libcvc4_add_sources( arith_unate_lemma_mode.cpp arith_unate_lemma_mode.h base_handlers.h + bool_to_bv_mode.cpp + bool_to_bv_mode.h bv_bitblast_mode.cpp bv_bitblast_mode.h datatypes_modes.h diff --git a/src/options/bool_to_bv_mode.cpp b/src/options/bool_to_bv_mode.cpp new file mode 100644 index 000000000..670e15419 --- /dev/null +++ b/src/options/bool_to_bv_mode.cpp @@ -0,0 +1,42 @@ +/********************* */ +/*! \file bool_to_bv_mode.cpp +** \verbatim +** Top contributors (to current version): +** Makai Mann +** This file is part of the CVC4 project. +** Copyright (c) 2009-2018 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 Modes for bool-to-bv preprocessing pass +** +** Modes for bool-to-bv preprocessing pass which tries to lower booleans +** to bit-vectors of width 1 at various levels of aggressiveness. +**/ + +#include "options/bool_to_bv_mode.h" + +#include + + +namespace CVC4 +{ + std::ostream& operator<<(std::ostream& out, preprocessing::passes::BoolToBVMode mode) { + switch(mode) { + case preprocessing::passes::BOOL_TO_BV_OFF: + out << "BOOL_TO_BV_OFF"; + break; + case preprocessing::passes::BOOL_TO_BV_ITE: + out << "BOOL_TO_BV_ITE"; + break; + case preprocessing::passes::BOOL_TO_BV_ALL: + out << "BOOL_TO_BV_ALL"; + break; + default: + out << "BoolToBVMode:UNKNOWN![" << unsigned(mode) << "]"; + } + + return out; + } +} // namespace CVC4 diff --git a/src/options/bool_to_bv_mode.h b/src/options/bool_to_bv_mode.h new file mode 100644 index 000000000..f2911c339 --- /dev/null +++ b/src/options/bool_to_bv_mode.h @@ -0,0 +1,57 @@ +/********************* */ +/*! \file bool_to_bv_mode.h +** \verbatim +** Top contributors (to current version): +** Makai Mann +** This file is part of the CVC4 project. +** Copyright (c) 2009-2018 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 Modes for bool-to-bv preprocessing pass +** +** Modes for bool-to-bv preprocessing pass which tries to lower booleans +** to bit-vectors of width 1 at various levels of aggressiveness. +**/ + +#include "cvc4_private.h" + +#ifndef __CVC4__PREPROCESSING__PASSES__BOOL_TO_BV_MODE_H +#define __CVC4__PREPROCESSING__PASSES__BOOL_TO_BV_MODE_H + +#include + +namespace CVC4 { +namespace preprocessing { +namespace passes { + +/** Enumeration of bool-to-bv modes */ +enum BoolToBVMode +{ + /** + * No bool-to-bv pass + */ + BOOL_TO_BV_OFF, + + /** + * Only lower bools in condition of ITEs + * Tries to give more info to bit-vector solver + * by using bit-vector-ITEs when possible + */ + BOOL_TO_BV_ITE, + + /** + * Lower every bool beneath the top layer to be a + * bit-vector + */ + BOOL_TO_BV_ALL +}; +} +} + +std::ostream& operator<<(std::ostream& out, preprocessing::passes::BoolToBVMode mode); + +} + +#endif /* __CVC4__PREPROCESSING__PASSES__BOOL_TO_BV_MODE_H */ diff --git a/src/options/bv_options.toml b/src/options/bv_options.toml index 15a9047c7..00290da7d 100644 --- a/src/options/bv_options.toml +++ b/src/options/bv_options.toml @@ -105,11 +105,22 @@ header = "options/bv_options.h" [[option]] name = "boolToBitvector" + smt_name = "bool-to-bv" category = "regular" - long = "bool-to-bv" + long = "bool-to-bv=MODE" + type = "CVC4::preprocessing::passes::BoolToBVMode" + default = "CVC4::preprocessing::passes::BOOL_TO_BV_OFF" + handler = "stringToBoolToBVMode" + includes = ["options/bool_to_bv_mode.h"] + help = "convert booleans to bit-vectors of size 1 at various levels of aggressiveness, see --bool-to-bv=help" + +[[option]] + name = "bitwiseEq" + category = "regular" + long = "bitwise-eq" type = "bool" - default = "false" - help = "convert booleans to bit-vectors of size 1 when possible" + default = "true" + help = "lift equivalence with one-bit bit-vectors to be boolean operations" [[option]] name = "bitvectorDivByZeroConst" diff --git a/src/options/options_handler.cpp b/src/options/options_handler.cpp index a808ecd3c..420396452 100644 --- a/src/options/options_handler.cpp +++ b/src/options/options_handler.cpp @@ -1301,6 +1301,50 @@ theory::bv::BvSlicerMode OptionsHandler::stringToBvSlicerMode( } } +const std::string OptionsHandler::s_boolToBVModeHelp = + "\ +BoolToBV pass modes supported by the --bool-to-bv option:\n\ +\n\ +off (default)\n\ ++ Don't push any booleans to width one bit-vectors\n\ +\n\ +ite\n\ ++ Try to turn ITEs into BITVECTOR_ITE when possible. It can fail per-formula \n\ + if not all sub-formulas can be turned to bit-vectors\n\ +\n\ +all\n\ ++ Force all booleans to be bit-vectors of width one except at the top level.\n\ + Most aggressive mode\n\ +"; + +preprocessing::passes::BoolToBVMode OptionsHandler::stringToBoolToBVMode( + std::string option, std::string optarg) +{ + if (optarg == "off") + { + return preprocessing::passes::BOOL_TO_BV_OFF; + } + else if (optarg == "ite") + { + return preprocessing::passes::BOOL_TO_BV_ITE; + } + else if (optarg == "all") + { + return preprocessing::passes::BOOL_TO_BV_ALL; + } + else if (optarg == "help") + { + puts(s_boolToBVModeHelp.c_str()); + exit(1); + } + else + { + throw OptionException(std::string("unknown option for --bool-to-bv: `") + + optarg + + "'. Try --bool-to-bv=help"); + } +} + void OptionsHandler::setBitblastAig(std::string option, bool arg) { if(arg) { diff --git a/src/options/options_handler.h b/src/options/options_handler.h index 53e317895..f96632696 100644 --- a/src/options/options_handler.h +++ b/src/options/options_handler.h @@ -27,6 +27,7 @@ #include "options/arith_propagation_mode.h" #include "options/arith_unate_lemma_mode.h" #include "options/base_handlers.h" +#include "options/bool_to_bv_mode.h" #include "options/bv_bitblast_mode.h" #include "options/datatypes_modes.h" #include "options/decision_mode.h" @@ -137,6 +138,8 @@ public: std::string optarg); theory::bv::BvSlicerMode stringToBvSlicerMode(std::string option, std::string optarg); + preprocessing::passes::BoolToBVMode stringToBoolToBVMode(std::string option, + std::string optarg); void setBitblastAig(std::string option, bool arg); theory::bv::SatSolverMode stringToSatSolver(std::string option, @@ -229,6 +232,7 @@ public: static const std::string s_bvSatSolverHelp; static const std::string s_booleanTermConversionModeHelp; static const std::string s_bvSlicerModeHelp; + static const std::string s_boolToBVModeHelp; static const std::string s_cegqiFairModeHelp; static const std::string s_decisionModeHelp; static const std::string s_instFormatHelp ; diff --git a/src/preprocessing/passes/bool_to_bv.cpp b/src/preprocessing/passes/bool_to_bv.cpp index c8a59bdc4..252ab941c 100644 --- a/src/preprocessing/passes/bool_to_bv.cpp +++ b/src/preprocessing/passes/bool_to_bv.cpp @@ -9,17 +9,17 @@ ** All rights reserved. See the file COPYING in the top-level source ** directory for licensing information.\endverbatim ** - ** \brief The BoolToBv preprocessing pass + ** \brief The BoolToBV preprocessing pass ** **/ #include "preprocessing/passes/bool_to_bv.h" #include -#include -#include +#include "base/map_util.h" #include "expr/node.h" +#include "options/bv_options.h" #include "smt/smt_statistics_registry.h" #include "theory/rewriter.h" #include "theory/theory.h" @@ -30,183 +30,253 @@ namespace passes { using namespace CVC4::theory; BoolToBV::BoolToBV(PreprocessingPassContext* preprocContext) - : PreprocessingPass(preprocContext, "bool-to-bv"), - d_lowerCache(), - d_one(bv::utils::mkOne(1)), - d_zero(bv::utils::mkZero(1)), - d_statistics(){}; + : PreprocessingPass(preprocContext, "bool-to-bv"), d_statistics(){}; PreprocessingPassResult BoolToBV::applyInternal( AssertionPipeline* assertionsToPreprocess) { NodeManager::currentResourceManager()->spendResource( options::preprocessStep()); - std::vector new_assertions; - lowerBoolToBv(assertionsToPreprocess->ref(), new_assertions); - for (unsigned i = 0; i < assertionsToPreprocess->size(); ++i) + + unsigned size = assertionsToPreprocess->size(); + for (unsigned i = 0; i < size; ++i) { - assertionsToPreprocess->replace(i, Rewriter::rewrite(new_assertions[i])); + assertionsToPreprocess->replace( + i, Rewriter::rewrite(lowerAssertion((*assertionsToPreprocess)[i]))); } - return PreprocessingPassResult::NO_CONFLICT; -} -void BoolToBV::addToLowerCache(TNode term, Node new_term) -{ - Assert(new_term != Node()); - Assert(!hasLowerCache(term)); - d_lowerCache[term] = new_term; + return PreprocessingPassResult::NO_CONFLICT; } -Node BoolToBV::getLowerCache(TNode term) const +Node BoolToBV::fromCache(TNode n) const { - Assert(hasLowerCache(term)); - return d_lowerCache.find(term)->second; + if (d_lowerCache.find(n) != d_lowerCache.end()) + { + return d_lowerCache.find(n)->second; + } + return n; } -bool BoolToBV::hasLowerCache(TNode term) const +bool BoolToBV::needToRebuild(TNode n) const { - return d_lowerCache.find(term) != d_lowerCache.end(); + // check if any children were rebuilt + for (const Node& nn : n) + { + if (ContainsKey(d_lowerCache, nn)) + { + return true; + } + } + return false; } -Node BoolToBV::lowerNode(TNode current, bool topLevel) +Node BoolToBV::lowerAssertion(const TNode& a) { - Node result; + bool optionITE = options::boolToBitvector() == BOOL_TO_BV_ITE; NodeManager* nm = NodeManager::currentNM(); - if (hasLowerCache(current)) - { - result = getLowerCache(current); - } - else + std::vector visit; + visit.push_back(a); + std::unordered_set visited; + // for ite mode, keeps track of whether you're in an ite condition + // for all mode, unused + std::unordered_set ite_cond; + + while (!visit.empty()) { - if (current.getNumChildren() == 0) + TNode n = visit.back(); + visit.pop_back(); + + int numChildren = n.getNumChildren(); + Kind k = n.getKind(); + Debug("bool-to-bv") << "BoolToBV::lowerAssertion Post-traversal with " << n + << " and visited = " << ContainsKey(visited, n) + << std::endl; + + // Mark as visited + /* Optimization: if it's a leaf, don't need to wait to do the work */ + if (!ContainsKey(visited, n) && (numChildren > 0)) { - if (current.getKind() == kind::CONST_BOOLEAN) + visited.insert(n); + visit.push_back(n); + + // insert children in reverse order so that they're processed in order + // important for rewriting which sorts by node id + for (int i = numChildren - 1; i >= 0; --i) { - result = (current == bv::utils::mkTrue()) ? d_one : d_zero; + visit.push_back(n[i]); } - else + + if (optionITE) { - result = current; + // check for ite-conditions + if (k == kind::ITE) + { + ite_cond.insert(n[0]); + } + else if (ContainsKey(ite_cond, n)) + { + // being part of an ite condition is inherited from the parent + ite_cond.insert(n.begin(), n.end()); + } } } + /* Optimization for ite mode */ + else if (optionITE && !ContainsKey(ite_cond, n) && !needToRebuild(n)) + { + Debug("bool-to-bv") + << "BoolToBV::lowerAssertion Skipping because don't need to rebuild: " + << n << std::endl; + // in ite mode, if you've already visited the node but it's not + // in an ite condition and doesn't need to be rebuilt, then + // don't need to do anything + continue; + } else { - Kind kind = current.getKind(); - Kind new_kind = kind; - switch (kind) - { - case kind::EQUAL: - if (current[0].getType().isBitVector() - || current[0].getType().isBoolean()) - { - new_kind = kind::BITVECTOR_COMP; - } - break; - case kind::AND: new_kind = kind::BITVECTOR_AND; break; - case kind::OR: new_kind = kind::BITVECTOR_OR; break; - case kind::NOT: new_kind = kind::BITVECTOR_NOT; break; - case kind::XOR: new_kind = kind::BITVECTOR_XOR; break; - case kind::IMPLIES: new_kind = kind::BITVECTOR_OR; break; - case kind::ITE: - if (current.getType().isBitVector() || current.getType().isBoolean()) - { - new_kind = kind::BITVECTOR_ITE; - } - break; - case kind::BITVECTOR_ULT: new_kind = kind::BITVECTOR_ULTBV; break; - case kind::BITVECTOR_SLT: new_kind = kind::BITVECTOR_SLTBV; break; - case kind::BITVECTOR_ULE: - case kind::BITVECTOR_UGT: - case kind::BITVECTOR_UGE: - case kind::BITVECTOR_SLE: - case kind::BITVECTOR_SGT: - case kind::BITVECTOR_SGE: - // Should have been removed by rewriting. - Unreachable(); - default: break; - } - NodeBuilder<> builder(new_kind); - if (kind != new_kind) - { - ++(d_statistics.d_numTermsLowered); - } - if (current.getMetaKind() == kind::metakind::PARAMETERIZED) - { - builder << current.getOperator(); - } - Node converted; - if (new_kind == kind::ITE) + lowerNode(n); + } + } + + if (fromCache(a).getType().isBitVector()) + { + return nm->mkNode(kind::EQUAL, fromCache(a), bv::utils::mkOne(1)); + } + else + { + Assert(a == fromCache(a)); + return a; + } +} + +void BoolToBV::lowerNode(const TNode& n) +{ + NodeManager* nm = NodeManager::currentNM(); + Kind k = n.getKind(); + + bool all_bv = true; + // check if it was able to convert all children to bitvectors + for (const Node& nn : n) + { + all_bv = all_bv && fromCache(nn).getType().isBitVector(); + if (!all_bv) + { + break; + } + } + + if (!all_bv || (n.getNumChildren() == 0)) + { + if ((options::boolToBitvector() == BOOL_TO_BV_ALL) + && n.getType().isBoolean()) + { + if (k == kind::CONST_BOOLEAN) { - // Special-case ITE because need condition to be Boolean. - converted = lowerNode(current[0], true); - builder << converted; - converted = lowerNode(current[1]); - builder << converted; - converted = lowerNode(current[2]); - builder << converted; - } - else if (kind == kind::IMPLIES) { - // Special-case IMPLIES because needs to be rewritten. - converted = lowerNode(current[0]); - builder << nm->mkNode(kind::BITVECTOR_NOT, converted); - converted = lowerNode(current[1]); - builder << converted; + d_lowerCache[n] = (n == bv::utils::mkTrue()) ? bv::utils::mkOne(1) + : bv::utils::mkZero(1); } else { - for (unsigned i = 0; i < current.getNumChildren(); ++i) - { - converted = lowerNode(current[i]); - builder << converted; - } + d_lowerCache[n] = + nm->mkNode(kind::ITE, n, bv::utils::mkOne(1), bv::utils::mkZero(1)); } - result = builder; + + Debug("bool-to-bv") << "BoolToBV::lowerNode " << n << " =>\n" + << fromCache(n) << std::endl; + ++(d_statistics.d_numTermsForcedLowered); + return; } - if (result.getType().isBoolean()) + else { - ++(d_statistics.d_numTermsForcedLowered); - result = nm->mkNode(kind::ITE, result, d_one, d_zero); + // invariant + // either one of the children is not a bit-vector or bool + // i.e. something that can't be 'forced' to a bitvector + // or it's in 'ite' mode which will give up on bools that + // can't be converted easily + + Debug("bool-to-bv") << "BoolToBV::lowerNode skipping: " << n << std::endl; + return; } - addToLowerCache(current, result); } - if (topLevel) + + Kind new_kind = k; + switch (k) { - result = nm->mkNode(kind::EQUAL, result, d_one); + case kind::EQUAL: new_kind = kind::BITVECTOR_COMP; break; + case kind::AND: new_kind = kind::BITVECTOR_AND; break; + case kind::OR: new_kind = kind::BITVECTOR_OR; break; + case kind::NOT: new_kind = kind::BITVECTOR_NOT; break; + case kind::XOR: new_kind = kind::BITVECTOR_XOR; break; + case kind::IMPLIES: new_kind = kind::BITVECTOR_OR; break; + case kind::ITE: new_kind = kind::BITVECTOR_ITE; break; + case kind::BITVECTOR_ULT: new_kind = kind::BITVECTOR_ULTBV; break; + case kind::BITVECTOR_SLT: new_kind = kind::BITVECTOR_SLTBV; break; + case kind::BITVECTOR_ULE: + case kind::BITVECTOR_UGT: + case kind::BITVECTOR_UGE: + case kind::BITVECTOR_SLE: + case kind::BITVECTOR_SGT: + case kind::BITVECTOR_SGE: + // Should have been removed by rewriting. + Unreachable(); + default: break; } - Assert(result != Node()); - Debug("bool-to-bv") << "BoolToBV::lowerNode " << current << " => \n" - << result << "\n"; - return result; -} -void BoolToBV::lowerBoolToBv(const std::vector& assertions, - std::vector& new_assertions) -{ - for (unsigned i = 0; i < assertions.size(); ++i) + NodeBuilder<> builder(new_kind); + if ((options::boolToBitvector() == BOOL_TO_BV_ALL) && (new_kind != k)) + { + ++(d_statistics.d_numTermsLowered); + } + + if (n.getMetaKind() == kind::metakind::PARAMETERIZED) + { + builder << n.getOperator(); + } + + // special case IMPLIES because needs to be rewritten + if (k == kind::IMPLIES) + { + builder << nm->mkNode(kind::BITVECTOR_NOT, fromCache(n[0])); + builder << fromCache(n[1]); + } + else { - Node new_assertion = lowerNode(assertions[i], true); - new_assertions.push_back(new_assertion); - Trace("bool-to-bv") << " " << assertions[i] << " => " << new_assertions[i] - << "\n"; + for (const Node& nn : n) + { + builder << fromCache(nn); + } } + + Debug("bool-to-bv") << "BoolToBV::lowerNode " << n << " =>\n" + << builder << std::endl; + + d_lowerCache[n] = builder.constructNode(); } BoolToBV::Statistics::Statistics() - : d_numTermsLowered("preprocessing::passes::BoolToBV::NumTermsLowered", 0), - d_numAtomsLowered("preprocessing::passes::BoolToBV::NumAtomsLowered", 0), + : d_numIteToBvite("preprocessing::passes::BoolToBV::NumIteToBvite", 0), + d_numTermsLowered("preprocessing::passes:BoolToBV::NumTermsLowered", 0), d_numTermsForcedLowered( "preprocessing::passes::BoolToBV::NumTermsForcedLowered", 0) { - smtStatisticsRegistry()->registerStat(&d_numTermsLowered); - smtStatisticsRegistry()->registerStat(&d_numAtomsLowered); - smtStatisticsRegistry()->registerStat(&d_numTermsForcedLowered); + smtStatisticsRegistry()->registerStat(&d_numIteToBvite); + if (options::boolToBitvector() == BOOL_TO_BV_ALL) + { + // these statistics wouldn't be correct in the ITE mode, + // because it might discard rebuilt nodes if it fails to + // convert a bool to width-one bit-vector (never forces) + smtStatisticsRegistry()->registerStat(&d_numTermsLowered); + smtStatisticsRegistry()->registerStat(&d_numTermsForcedLowered); + } } BoolToBV::Statistics::~Statistics() { - smtStatisticsRegistry()->unregisterStat(&d_numTermsLowered); - smtStatisticsRegistry()->unregisterStat(&d_numAtomsLowered); - smtStatisticsRegistry()->unregisterStat(&d_numTermsForcedLowered); + smtStatisticsRegistry()->unregisterStat(&d_numIteToBvite); + if (options::boolToBitvector() == BOOL_TO_BV_ALL) + { + smtStatisticsRegistry()->unregisterStat(&d_numTermsLowered); + smtStatisticsRegistry()->unregisterStat(&d_numTermsForcedLowered); + } } diff --git a/src/preprocessing/passes/bool_to_bv.h b/src/preprocessing/passes/bool_to_bv.h index 49c9dc944..da99d3c84 100644 --- a/src/preprocessing/passes/bool_to_bv.h +++ b/src/preprocessing/passes/bool_to_bv.h @@ -2,14 +2,14 @@ /*! \file bool_to_bv.h ** \verbatim ** Top contributors (to current version): - ** Yoni Zohar + ** Makai Mann, Yoni Zohar ** This file is part of the CVC4 project. ** Copyright (c) 2009-2018 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 BoolToBv preprocessing pass + ** \brief The BoolToBV preprocessing pass ** **/ @@ -18,9 +18,9 @@ #ifndef __CVC4__PREPROCESSING__PASSES__BOOL_TO_BV_H #define __CVC4__PREPROCESSING__PASSES__BOOL_TO_BV_H -#include "preprocessing/passes/bv_to_bool.h" #include "preprocessing/preprocessing_pass.h" #include "preprocessing/preprocessing_pass_context.h" +#include "theory/bv/theory_bv_utils.h" #include "util/statistics_registry.h" namespace CVC4 { @@ -39,24 +39,33 @@ class BoolToBV : public PreprocessingPass private: struct Statistics { + IntStat d_numIteToBvite; IntStat d_numTermsLowered; - IntStat d_numAtomsLowered; IntStat d_numTermsForcedLowered; Statistics(); ~Statistics(); }; - void lowerBoolToBv(const std::vector& assertions, - std::vector& new_assertions); - void addToLowerCache(TNode term, Node new_term); - Node getLowerCache(TNode term) const; - bool hasLowerCache(TNode term) const; - Node lowerNode(TNode current, bool topLevel = false); - NodeNodeMap d_lowerCache; - Node d_one; - Node d_zero; + /* Takes an assertion and tries to create more bit-vector structure */ + Node lowerAssertion(const TNode& a); + + /* Tries to lower one node to a width-one bit-vector */ + void lowerNode(const TNode& n); + + /* Returns cached node if it exists, otherwise returns the node */ + Node fromCache(TNode n) const; + + /** Checks if any of the nodes children were rebuilt, + * in which case n needs to be rebuilt as well + */ + bool needToRebuild(TNode n) const; + Statistics d_statistics; -}; // class + + /* Keeps track of lowered nodes */ + std::unordered_map d_lowerCache; +}; // class BoolToBV + } // namespace passes } // namespace preprocessing } // namespace CVC4 diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp index 6814ad531..7abfd8273 100644 --- a/src/smt/smt_engine.cpp +++ b/src/smt/smt_engine.cpp @@ -1379,17 +1379,17 @@ void SmtEngine::setDefaults() { options::bitvectorToBool.set(false); } - if (options::boolToBitvector()) + if (options::boolToBitvector() != preprocessing::passes::BOOL_TO_BV_OFF) { if (options::boolToBitvector.wasSetByUser()) { throw OptionException( - "bool-to-bv not supported with unsat cores/proofs"); + "bool-to-bv != off not supported with unsat cores/proofs"); } - Notice() << "SmtEngine: turning off bool-to-bitvector to support unsat " + Notice() << "SmtEngine: turning off bool-to-bv to support unsat " "cores/proofs" << endl; - options::boolToBitvector.set(false); + setOption("boolToBitvector", SExpr("off")); } if (options::bvIntroducePow2()) @@ -1449,13 +1449,18 @@ void SmtEngine::setDefaults() { if (options::cbqiBv() && d_logic.isQuantified()) { - if(options::boolToBitvector.wasSetByUser()) { - throw OptionException( - "bool-to-bv not supported with CBQI BV for quantified logics"); + if (options::boolToBitvector() != preprocessing::passes::BOOL_TO_BV_OFF) + { + if (options::boolToBitvector.wasSetByUser()) + { + throw OptionException( + "bool-to-bv != off not supported with CBQI BV for quantified " + "logics"); + } + Notice() << "SmtEngine: turning off bool-to-bitvector to support CBQI BV" + << endl; + setOption("boolToBitvector", SExpr("off")); } - Notice() << "SmtEngine: turning off bool-to-bitvector to support CBQI BV" - << endl; - options::boolToBitvector.set(false); } // cases where we need produce models @@ -1617,6 +1622,19 @@ void SmtEngine::setDefaults() { } } + if (options::boolToBitvector() == preprocessing::passes::BOOL_TO_BV_ALL + && !d_logic.isTheoryEnabled(THEORY_BV)) + { + if (options::boolToBitvector.wasSetByUser()) + { + throw OptionException( + "bool-to-bv=all not supported for non-bitvector logics."); + } + Notice() << "SmtEngine: turning off bool-to-bv for non-bv logic: " + << d_logic.getLogicString() << std::endl; + setOption("boolToBitvector", SExpr("off")); + } + if (! options::bvEagerExplanations.wasSetByUser() && d_logic.isTheoryEnabled(THEORY_ARRAYS) && d_logic.isTheoryEnabled(THEORY_BV)) { diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp index e60d60456..949a3d738 100644 --- a/src/theory/bv/theory_bv.cpp +++ b/src/theory/bv/theory_bv.cpp @@ -740,7 +740,7 @@ Node TheoryBV::ppRewrite(TNode t) { Debug("bv-pp-rewrite") << "TheoryBV::ppRewrite " << t << "\n"; Node res = t; - if (RewriteRule::applies(t)) { + if (options::bitwiseEq() && RewriteRule::applies(t)) { Node result = RewriteRule::run(t); res = Rewriter::rewrite(result); } else if (d_isCoreTheory && t.getKind() == kind::EQUAL) { diff --git a/test/regress/CMakeLists.txt b/test/regress/CMakeLists.txt index f22796929..9e942aae1 100644 --- a/test/regress/CMakeLists.txt +++ b/test/regress/CMakeLists.txt @@ -159,7 +159,8 @@ set(regress_0_tests regress0/bv/ackermann2.smt2 regress0/bv/ackermann3.smt2 regress0/bv/ackermann4.smt2 - regress0/bv/bool-to-bv.smt2 + regress0/bv/bool-to-bv-all.smt2 + regress0/bv/bool-to-bv-ite.smt2 regress0/bv/bug260a.smt regress0/bv/bug260b.smt regress0/bv/bug440.smt diff --git a/test/regress/regress0/bv/bool-to-bv-all.smt2 b/test/regress/regress0/bv/bool-to-bv-all.smt2 new file mode 100644 index 000000000..5947699d9 --- /dev/null +++ b/test/regress/regress0/bv/bool-to-bv-all.smt2 @@ -0,0 +1,19 @@ +; COMMAND-LINE: --bool-to-bv=all +; EXPECT: sat +(set-logic QF_BV) +(declare-fun x2 () (_ BitVec 3)) +(declare-fun x1 () (_ BitVec 3)) +(declare-fun x0 () (_ BitVec 3)) +(declare-fun b1 () Bool) +(declare-fun b2 () Bool) +(declare-fun b3 () Bool) +(assert (not (bvult (bvudiv (bvudiv (bvudiv x0 x0) x1) x2) x1))) +(assert (not (bvslt (bvudiv (bvudiv (bvudiv x0 x0) x1) x2) x1))) +(assert (= #b000 x2)) +(assert (=> b1 b2)) +(assert (and b1 b2)) +(assert (or b1 b2)) +(assert (xor b1 b3)) +(assert (not (xor b2 b2))) +(assert (ite b2 b2 b1)) +(check-sat) diff --git a/test/regress/regress0/bv/bool-to-bv-ite.smt2 b/test/regress/regress0/bv/bool-to-bv-ite.smt2 new file mode 100644 index 000000000..e1be3ea10 --- /dev/null +++ b/test/regress/regress0/bv/bool-to-bv-ite.smt2 @@ -0,0 +1,13 @@ +; COMMAND-LINE: --bool-to-bv=ite +; EXPECT: sat +(set-logic QF_BV) +(declare-fun x2 () (_ BitVec 3)) +(declare-fun x1 () (_ BitVec 3)) +(declare-fun x0 () (_ BitVec 3)) +(declare-fun b1 () Bool) +(declare-fun b2 () Bool) +(assert (not (bvult (bvudiv (bvudiv (bvudiv x0 x0) x1) x2) x1))) +(assert (= #b000 x2)) +(assert (=> b1 b2)) +(assert (= x2 (ite (bvugt x0 x1) (bvadd x0 (_ bv1 3)) (bvadd x1 (_ bv1 3))))) +(check-sat) diff --git a/test/regress/regress0/bv/bool-to-bv.smt2 b/test/regress/regress0/bv/bool-to-bv.smt2 deleted file mode 100644 index 8706c51a8..000000000 --- a/test/regress/regress0/bv/bool-to-bv.smt2 +++ /dev/null @@ -1,19 +0,0 @@ -; COMMAND-LINE: --bool-to-bv -; EXPECT: sat -(set-logic QF_BV) -(declare-fun x2 () (_ BitVec 3)) -(declare-fun x1 () (_ BitVec 3)) -(declare-fun x0 () (_ BitVec 3)) -(declare-fun b1 () Bool) -(declare-fun b2 () Bool) -(declare-fun b3 () Bool) -(assert (not (bvult (bvudiv (bvudiv (bvudiv x0 x0) x1) x2) x1))) -(assert (not (bvslt (bvudiv (bvudiv (bvudiv x0 x0) x1) x2) x1))) -(assert (= #b000 x2)) -(assert (=> b1 b2)) -(assert (and b1 b2)) -(assert (or b1 b2)) -(assert (xor b1 b3)) -(assert (not (xor b2 b2))) -(assert (ite b2 b2 b1)) -(check-sat) -- cgit v1.2.3 From 1c114dc487d94d72ebf3453611c42b28777d6482 Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Tue, 11 Dec 2018 11:46:38 -0800 Subject: LRAT signature (#2731) * LRAT signature Added an LRAT signature. It is almost entirely side-conditions, but it works. There is also a collection of tests for it. You can run them by invoking ``` lfscc smt.plf sat.plf lrat.plf lrat_test.plf ``` * Update proofs/signatures/lrat.plf per Yoni's suggestion. Co-Authored-By: alex-ozdemir * Responding to Yoni's comments. * Removed unused varaibles Some tests declared `var`s which were unused. Now they don't. --- proofs/signatures/lrat.plf | 566 +++++++++++++++++++++++++++++ proofs/signatures/lrat_test.plf | 786 ++++++++++++++++++++++++++++++++++++++++ proofs/signatures/sat.plf | 6 +- proofs/signatures/smt.plf | 16 + proofs/signatures/th_bv.plf | 14 - 5 files changed, 1371 insertions(+), 17 deletions(-) create mode 100644 proofs/signatures/lrat.plf create mode 100644 proofs/signatures/lrat_test.plf diff --git a/proofs/signatures/lrat.plf b/proofs/signatures/lrat.plf new file mode 100644 index 000000000..f5af891bc --- /dev/null +++ b/proofs/signatures/lrat.plf @@ -0,0 +1,566 @@ +; LRAT Proof signature +; LRAT format detailed in "Efficient Certified RAT Verification" +; Author: aozdemir +; Depends On: sat.plf, smt.plf + + +; A general note about the design of the side conditions: +; Some side-conditions make use of a _global assignment_ encoded in +; 0 (true) / 1 (false) marks on variables. + +; A list of clauses, CNF if interpretted as a formula, +; but also sometimes just a list +(declare cnf type) +(declare cnfn cnf) +(declare cnfc (! h clause (! t cnf cnf))) + +; Unit (https://en.wikipedia.org/wiki/Unit_type) +; For functions that don't return anything +(declare Unit type) ; The type with only one value (like `void` in C) +(declare unit Unit) ; That value + +; Boolean operator (not short-circuiting) +(program bool_or ((l bool) (r bool)) bool (match l (ff r) (tt tt))) +(program bool_and ((l bool) (r bool)) bool (match l (tt r) (ff ff))) +(program bool_not ((b bool)) bool (match b (tt ff) (ff tt))) + +; =================== ; +; Working CNF formula ; +; =================== ; + +; Represents a CNF formula as a map from clause indices to clauses +; Should be sorted ascending, always! +; Here, and for all collections, the suffix "n" denotes the empty collection and +; the suffix "c" denotes the constructor for the collection in the style of lisp's +; "cons cells" +(declare CMap type) +(declare CMapn CMap) +(declare CMapc (! i mpz (! c clause (! r CMap CMap)))) + +; ================= ; +; LRAT Proof Format ; +; ================= ; + +; CI lists are lists of clause indices. +; They represent clauses to delete. +; They must be sorted. +(declare CIList type) +(declare CIListn CIList) +(declare CIListc (! z mpz (! zs CIList CIList))) + +; Traces are a list of clause indices into the working CNF formula +; They represent the clauses that will be unit in a unit propegation to bottom +; Thus their elements are *not* in value order. +(declare Trace type) +(declare Tracen Trace) +(declare Tracec (! z mpz (! zs Trace Trace))) + +; RAT Hint list +; Each hint is +; * An index indicating a clause in the working CNF formula to resolve with +; * A trace indicating how UP should be done after that resolution +(declare RATHints type) +(declare RATHintsn RATHints) +(declare RATHintsc + (! target mpz + (! trace Trace + (! rest RATHints + RATHints)))) + +; LRAT proof +(declare LRATProof type) +(declare LRATProofn LRATProof) +; Deletion (includes a list of clause indices to delete) +(declare LRATProofd (! cis CIList (! rest LRATProof LRATProof))) +; Addition: a clause index, a clause, RUP trace for that clause, and hints for +; what resolutions should happen then, and how those resolutions imply bottom +; via UP. +; If the list of hints is empty, then bottom is already implied. +(declare LRATProofa + (! ci mpz + (! c clause + (! t Trace + (! h RATHints + (! rest LRATProof + LRATProof)))))) + +; ========================================== ; +; Functional programs for manipulating types ; +; ========================================== ; + +; Flip the polarity of the literal +(program lit_flip ((l lit)) lit + (match l + ((pos v) (neg v)) + ((neg v) (pos v)))) + +; Are two literal equal? +(program lit_eq ((l1 lit) (l2 lit)) bool + (match l1 + ((pos v1) (match l2 + ((pos v2) (ifequal v1 v2 tt ff)) + ((neg v2) ff))) + ((neg v1) (match l2 + ((pos v2) ff) + ((neg v2) (ifequal v1 v2 tt ff)))))) + +; Remove **all** occurences of a literal from clause +(program clause_remove_all ((l lit) (c clause)) clause + (match c + (cln cln) + ((clc l' c') + (let rest_res (clause_remove_all l c') + (match (lit_eq l l') + (tt rest_res) + (ff (clc l' rest_res))))))) + +; Return the clause's first literal +; fails on an empty clause +(program clause_head ((c clause)) lit + (match c + (cln (fail lit)) + ((clc l c') l))) + +; Does a clause contain some literal? +(program clause_contains_lit ((c clause) (l lit)) bool + (match c + ((clc l' c') (match (lit_eq l l') + (tt tt) + (ff (clause_contains_lit c' l)))) + (cln ff))) + +; Append two traces +(program Trace_concat ((t1 Trace) (t2 Trace)) Trace + (match t1 + (Tracen t2) + ((Tracec h1 r1) (Tracec h1 (Trace_concat r1 t2))))) + +; Return whether a list of RAT hits is empty +(program RATHints_is_empty ((h RATHints)) bool + (match h + (RATHintsn tt) + ((RATHintsc a b c) ff))) + +; Insert into a CMap, preserving order +(program CMap_insert ((i mpz) (c clause) (cs CMap)) CMap + (match cs + (CMapn (CMapc i c CMapn)) + ((CMapc i' c' r) + (mp_ifneg (mpz_sub i i') + (CMapc i c cs) + (CMapc i' c' (CMap_insert i c r)))))) + +; Get from a CMap +(program CMap_get ((i mpz) (cs CMap)) clause + (match cs + (CMapn (fail clause)) + ((CMapc i' c r) + (mp_ifzero (mpz_sub i i') + c + (CMap_get i r))))) + +; Remove from CMap. Only removes one element. +(program CMap_remove ((i mpz) (cs CMap)) CMap + (match cs + (CMapn CMapn) + ((CMapc i' c r) + (mp_ifzero (mpz_sub i i') + r + (CMapc i' c (CMap_remove i r)))))) + +; Remove many indices from a CMap. Asuumes the input list is sorted. +(program CMap_remove_many ((is CIList) (cs CMap)) CMap + (match + is + (CIListn cs) + ((CIListc i is') + (match + cs + (CMapn (fail CMap)) ; All deletion indices must be valid! + ((CMapc ci c cs') + (mp_ifzero (mpz_sub i ci) + (CMap_remove_many is' cs') + (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, +; return the indices of all clauses containing x. +(program collect_resolution_targets_w_lit ((cs CMap) (l lit)) CIList + (match cs + (CMapn CIListn) + ((CMapc i c cs') + (let rest_solution (collect_resolution_targets_w_lit cs' l) + (match (clause_contains_lit c l) + (tt (CIListc i rest_solution)) + (ff rest_solution)))))) + +; Given a clause and a maps of clauses, return all indices in the map +; corresponding to clauses which could resolve with this one on its first +; literal +(program collect_resolution_targets ((cs CMap) (c clause)) CIList + (collect_resolution_targets_w_lit cs (lit_flip (clause_head c)))) + +; Is this clause a tautology? +; Internally uses mark 5 to flag variables that occur (+) +; and mark 6 to flag variables that occur (-) +(program is_t ((c clause)) bool + (match + c + (cln ff) + ((clc l c') (match + l + ((pos v) + (ifmarked5 + v + (is_t c') + (ifmarked6 + v + tt + (do + (markvar5 v) + (let r (is_t c') (do (markvar5 v) r)))))) + ((neg v) + (ifmarked6 + v + (is_t c') + (ifmarked5 + v + tt + (do + (markvar6 v) + (let r (is_t c') (do (markvar6 v) r)))))))))) + +; ===================================================================== ; +; Programs for manipulating and querying the global variable assignment ; +; ===================================================================== ; + +; This assignment marks values of type `var`. +; It marks a variable with 1 if that variable is true +; It marks a variable with 2 if that variable is false +; A variable should not be marked with both! +; A variable may be marked with neither, indicating that variable is presently +; unassigned, which we call "floating". + +; Mark the variable within to satisfy this literal. +; fails if the literal is already UNSAT +(program lit_mk_sat ((l lit)) Unit + (match l + ((pos v) (ifmarked2 v + (fail Unit) + (ifmarked1 v unit (do (markvar1 v) unit)))) + ((neg v) (ifmarked1 v + (fail Unit) + (ifmarked2 v unit (do (markvar2 v) unit)))))) + +; Mark the variable within to falsify this literal. +; fails is the literal is already SAT +(program lit_mk_unsat ((l lit)) Unit + (match l + ((neg v) (ifmarked2 v + (fail Unit) + (ifmarked1 v unit (do (markvar1 v) unit)))) + ((pos v) (ifmarked1 v + (fail Unit) + (ifmarked2 v unit (do (markvar2 v) unit)))))) + +; Unmarks the variable within a satified literal to render it neither satified 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 +; fails if the literal is not already falsified +(program lit_un_mk_unsat ((l lit)) Unit + (match l + ((pos v) (ifmarked2 v (do (markvar2 v) unit) (fail Unit))) + ((neg v) (ifmarked1 v (do (markvar1 v) unit) (fail Unit))))) + +; Is a literal presently satisfied? +(program lit_is_sat ((l lit)) bool + (match l + ((pos v) (ifmarked1 v tt ff)) + ((neg v) (ifmarked2 v tt ff)))) + +; Is a literal presently falsified? +(program lit_is_unsat ((l lit)) bool + (match l + ((pos v) (ifmarked2 v tt ff)) + ((neg v) (ifmarked1 v tt ff)))) + +; Is a literal presently neither satisfied nor falsified? +(program lit_is_floating ((l lit)) bool + (bool_not (bool_or (lit_is_sat l) (lit_is_unsat l)))) + +; Does this clause contain a floating literal? +(program clause_has_floating ((c clause)) bool + (match c + (cln ff) + ((clc l c') (match (lit_is_floating l) + (tt tt) + (ff (clause_has_floating c')))))) + +; Is this clause falsified? i.e. are all its clauses falsified? +(program clause_is_unsat ((c clause)) bool + (match c + (cln tt) + ((clc l c') (match (lit_is_unsat l) + (tt (clause_is_unsat c')) + (ff ff))))) + +; Is this clause presently satisfied? +(program clause_is_sat ((c clause)) bool + (match c + (cln ff) + ((clc l c') (match (lit_is_sat l) + (tt tt) + (ff (clause_is_sat c')))))) + +; Falsify **all** contained literals. +; Fails on a tautological clause +(program clause_mk_all_unsat ((c clause)) Unit + (match c + (cln unit) + ((clc l c') (do + (lit_mk_unsat l) + (clause_mk_all_unsat c'))))) + +; Unfalsifies **all** contained literals +; Fails on a clause with duplicate literals +(program clause_un_mk_all_unsat ((c clause)) Unit + (match c + (cln unit) + ((clc l c') (do + (lit_un_mk_unsat l) + (clause_un_mk_all_unsat c'))))) + +; Get the first floating literal out of this clause. +; fails if there are no floating literals +(program clause_first_floating ((c clause)) lit + (match c + (cln (fail lit)) + ((clc l c') (match (lit_is_floating l) + (tt l) + (ff (clause_first_floating c')))))) + +; ===================================== ; +; High-Level Programs for LRAT Checking ; +; ===================================== ; + +; 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. +(declare MRUnit (! l lit MarkResult)) +; The clause was unsat! +(declare MRUnsat MarkResult) +; The clauss was already satisfied. +(declare MRSat MarkResult) +; The clause had multiple floating literals. +(declare MRNotUnit MarkResult) + +; Determine wether 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. +; +; Fails if `c` is a TAUT +(program clause_check_unit_and_maybe_mark ((c clause)) MarkResult + (match (clause_is_sat c) + (tt MRSat) + (ff (match (clause_is_unsat c) + (tt MRUnsat) + (ff (match (is_t c) + (tt (fail MarkResult)) + (ff ; Dedent + (match (clause_has_floating c) + (tt (let first (clause_first_floating c) + (do (lit_mk_sat first) + (match (clause_has_floating c) + (tt (do (lit_un_mk_sat first) MRNotUnit)) + (ff (MRUnit first)))))) + ; Unreachable. If clause is not floating it must have been SAT or UNSAT. + (ff (fail MarkResult)) + )))))))) + +; The return type for the process of Trace-guided unit propegation +(declare UPResult type) +; The trace guided unit propegation correctly, but that unit propegation did not end in an empty clause +(declare UPR_Ok UPResult) +; The trace guided unit propegation correctly to an empty clause +(declare UPR_Bottom UPResult) +; The trace was malformed, +;; i.e. at some point indicates that a non-unit, non-empty clause should be examined +(declare UPR_Broken UPResult) + +; Execute the unit propegation indicated by the trace. Report whether that +; unit propegation succeeds and produces bottom, fails, or succeeds but does +; not produce bottom. +; +; If the trace tries to propegate through a TAUT clause, fails. +(program do_up ((cs CMap) (t Trace)) UPResult + (match + t + (Tracen UPR_Ok) + ((Tracec i r) (match (clause_check_unit_and_maybe_mark (CMap_get i cs)) + ((MRUnit l) + (let res (do_up cs r) + (do (lit_un_mk_sat l) res))) + (MRUnsat UPR_Bottom) + (MRSat UPR_Broken) + (MRNotUnit UPR_Broken))))) + + +; Determine whether a list of indices agrees with the list of indices latent in +; a list of hints. Both lists should be sorted. +(program resolution_targets_match ( + (computed CIList) + (given RATHints)) bool + (match given + (RATHintsn + (match computed + (CIListn tt) + ((CIListc a b) ff))) + ((RATHintsc hint_idx t given') + (match computed + ((CIListc comp_idx computed') + (mp_ifzero (mpz_sub hint_idx comp_idx) + (resolution_targets_match computed' given') + (ff))) + (CIListn ff))))) + + +; Determines whether `t` is a witness that `c` is an Assymetric Tautology in `cs`. +; +; Does unit propegation in the formula `cs`, beginning by falsifying +; all literals in `c`, and then looking at the clauses indicated by `t`. +; Assumes no marks, and cleans up marks afterwards. +; +; Fails if `c` has duplicates +(program is_at_trace ((cs CMap) (c clause) (t Trace)) UPResult + (match (is_t c) + (ff + (do + (clause_mk_all_unsat c) + (let result (do_up cs t) + (do (clause_un_mk_all_unsat c) result)))) + (tt + UPR_Bottom))) + + + +; List of (clause, trace) pairs +(declare CTPairs type) +(declare CTPn CTPairs) +(declare CTPc (! c clause (! t Trace (! rest CTPairs CTPairs)))) + +; For each RAT hint, construct the pseudo-resolvant for that hint, and the net +; trace for that hint. Return a list of these. +; +; Pseudo resolvant: if l v C is the clause, and D is another clause containing +; ~l, then l v C v (D \ ~l) is the pseudo-resolvant, which is the actual +; resolant, plut l, which would be implied by UP. +; +; The net trace is the global trace (`t`), plut the trace for that specific +; resolvant. +(program construct_ct_pairs ( + (cs CMap) + (c clause) + (t Trace) + (hints RATHints) + ) CTPairs + (match hints + (RATHintsn CTPn) + ((RATHintsc i ht hints') + (CTPc + (clause_append c + (clause_remove_all (lit_flip (clause_head c)) + (CMap_get i cs))) + (Trace_concat t ht) + (construct_ct_pairs cs c t hints'))))) + +; Goes through a list of clause, trace pairs and verifies that each clause is +; an AT via that trace. +; Fails if any putative AT is a TAUT or contains duplicates +(program are_all_at ( + (cs CMap) + (l CTPairs) + ) UPResult + (match l + (CTPn UPR_Bottom) + ((CTPc c t l') + (match (is_at_trace cs c t) + (UPR_Ok UPR_Ok) + (UPR_Broken UPR_Broken) + (UPR_Bottom (are_all_at cs l')))))) + +; Is this trace, and list of hints, proof that `c` is an Resolution Assymeytic +; Tautology? +; Fails is the hints are empty (i.e. `c` should be AT, and c is TAUT or contains duplicates) +; Also fails if any of the pseudo-resolvants are TAUT or contain duplicates. +(program is_rat_trace ((cs CMap) (c clause) (t Trace) (hints RATHints)) UPResult + (match + (RATHints_is_empty hints) + (tt ; Empty RAT hints -- the clause must be AT + (is_at_trace cs c t)) + (ff ; Ew -- we must verify this is a RAT + (match (resolution_targets_match + (collect_resolution_targets cs c) + hints) + (ff ; Res targets are bad + UPR_Broken) + (tt + (are_all_at cs (construct_ct_pairs cs c t hints))))))) + +; Is this proof an LRAT proof of bottom? +; Fails if any added AT is a TAUT or contains duplicates OR if any added RAT +; produces pseudo-resolvants which are TAUT or contain duplicates +(program is_lrat_proof_of_bottom ((f CMap) (proof LRATProof)) bool + (match proof + ((LRATProofd indices rest) + (is_lrat_proof_of_bottom + (CMap_remove_many indices f) + rest)) + ((LRATProofa idx c trace hints rest) + (match (is_rat_trace f c trace hints) + (UPR_Bottom + (match + c + (cln tt) + ((clc a b) + (is_lrat_proof_of_bottom (CMap_insert idx c f) rest)))) + (UPR_Ok ff) + (UPR_Broken ff))) + (LRATProofn ff)) + ) + +; Proof of a CMap from clause proofs. +; The idx is unelidable b/c it is unspecified. +(declare CMap_holds (! c CMap type)) +(declare CMapn_proof (CMap_holds CMapn)) +(declare CMapc_proof + (! idx mpz ; Not elidable! + (! c clause + (! rest CMap + (! proof_c (holds c) + ( ! proof_rest (CMap_holds rest) + (CMap_holds (CMapc idx c rest)))))))) + +(define bottom (holds cln)) +(declare lrat_proof_of_bottom + (! cm CMap + (! proof_cm (CMap_holds cm) + (! proof LRATProof + (! sc (^ (is_lrat_proof_of_bottom cm proof) tt) + bottom))))) + + +; TODO(aozdemir) Reducing the amount of checking that resides in side-conditions. +; Steps +; 1. Unroll the traversal of is_lrat_proof_of_bottom into a serialized +; sequence of axiom applications. +; The axioms would likely correspond to DELETE, IS T, IS AT, IS RAT. +; They would manipulate a CMap by way of side-conditions. +; 2. Unroll AT checks by manifesting the assignment in data rather than marks, +; and having axioms like IS_UNSAT, IS_UNIT_ON_LITERAL. +; 3. Unroll RAT checks in a similar fashion, although more painfully. diff --git a/proofs/signatures/lrat_test.plf b/proofs/signatures/lrat_test.plf new file mode 100644 index 000000000..3ba785507 --- /dev/null +++ b/proofs/signatures/lrat_test.plf @@ -0,0 +1,786 @@ +(declare test_clause_append + (! c1 clause + (! c2 clause + (! cr clause + (! sc (^ (clause_append c1 c2) cr) type))))) + +; Test passes if the (test_clause_append ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (test_clause_append + (clc (pos v1) (clc (neg v2) cln)) + (clc (pos v3) (clc (neg v2) cln)) + (clc (pos v1) (clc (neg v2) (clc (pos v3) (clc (neg v2) cln)))) + ) + ))) +) + +; Test passes if the (test_clause_append ...) application is well-typed. +(check + (% v2 var + (% v3 var + (test_clause_append + cln + (clc (pos v3) (clc (neg v2) cln)) + (clc (pos v3) (clc (neg v2) cln)) + ) + )) +) + +; Test passes if the (test_clause_append ...) application is well-typed. +(check + (% v2 var + (% v3 var + (test_clause_append + (clc (pos v3) (clc (neg v2) cln)) + cln + (clc (pos v3) (clc (neg v2) cln)) + ) + )) +) + +(declare test_CMap_remove_many + (! is CIList + (! cs CMap + (! csr CMap + (! sc (^ (CMap_remove_many is cs) csr) type))))) + +; Test passes if the (test_CMap_remove_many ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v4) (clc (neg v2) cln)) + (@ c2 (clc (neg v3) (clc (neg v1) cln)) + (@ c3 (clc (neg v2) (clc (pos v3) cln)) + (@ c4 (clc (neg v3) (clc (neg v4) cln)) + (@ cs_in (CMapc 0 c1 (CMapc 3 c2 (CMapc 4 c3 (CMapc 5 c3 (CMapc 6 c4 CMapn))))) + (@ cs_out (CMapc 3 c2 (CMapc 5 c3 CMapn)) + (@ is_in (CIListc 0 (CIListc 4 (CIListc 6 CIListn))) + (test_CMap_remove_many + is_in + cs_in + cs_out + ) + ))) + )))) + )))) +) + +; Test passes if the (test_CMap_remove_many ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v4) (clc (neg v2) cln)) + (@ c2 (clc (neg v3) (clc (neg v1) cln)) + (@ c3 (clc (neg v2) (clc (pos v3) cln)) + (@ c4 (clc (neg v3) (clc (neg v4) cln)) + (@ cs_in (CMapc 0 c1 (CMapc 3 c2 (CMapc 4 c3 (CMapc 5 c3 (CMapc 6 c4 CMapn))))) + (@ cs_out (CMapc 0 c1 (CMapc 3 c2 (CMapc 5 c3 (CMapc 6 c4 CMapn)))) + (@ is_in (CIListc 4 CIListn) + (test_CMap_remove_many + is_in + cs_in + cs_out + ) + ))) + )))) + )))) +) + +(declare test_clause_remove_all + (! l lit + (! c clause + (! c' clause + (! sc (^ (clause_remove_all l c) c') type))))) + +; Test passes if the (test_clause_remove_all ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v4) (clc (neg v2) (clc (neg v2) (clc (pos v2) (clc (pos v1) cln))))) + (@ c2 (clc (pos v4) (clc (pos v2) (clc (pos v1) cln))) + (test_clause_remove_all + (neg v2) + c1 + c2 + ) + )) + )))) +) + +(declare test_collect_resolution_targets + (! cs CMap + (! c clause + (! is CIList + (! sc (^ (collect_resolution_targets cs c) is) type))))) + +; Test passes if the (test_collect_resolution_targets ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v3) (clc (neg v2) cln)) + (@ c2 (clc (neg v3) (clc (neg v1) cln)) + (@ c3 (clc (neg v2) (clc (pos v3) cln)) + (@ c4 (clc (neg v3) (clc (pos v3) cln)) + (@ ct (clc (neg v3) (clc (neg v4) cln)) + (@ cs_in (CMapc 0 c1 (CMapc 3 c2 (CMapc 4 c3 (CMapc 5 c3 (CMapc 6 c4 CMapn))))) + (@ is_out (CIListc 0 (CIListc 4 (CIListc 5 (CIListc 6 CIListn)))) + (test_collect_resolution_targets + cs_in + ct + is_out + ) + ))) + )))) + )))) +) + +(declare test_resolution_targets_match + (! c CIList + (! g RATHints + (! ans bool + (! sc (^ (resolution_targets_match c g) ans) type))))) + +; Test passes if the (test_resolution_targets_match ...) application is well-typed. +(check + (@ idxs_in (CIListc 0 (CIListc 4 (CIListc 5 (CIListc 6 CIListn)))) + (@ hints_in + (RATHintsc 0 Tracen + (RATHintsc 4 Tracen + (RATHintsc 5 Tracen + (RATHintsc 6 Tracen + RATHintsn)))) + (test_resolution_targets_match + idxs_in + hints_in + tt + ) + )) +) + +; Test passes if the (test_resolution_targets_match ...) application is well-typed. +(check + (@ idxs_in (CIListc 0 (CIListc 2 (CIListc 5 (CIListc 6 CIListn)))) + (@ hints_in + (RATHintsc 0 Tracen + (RATHintsc 4 Tracen + (RATHintsc 5 Tracen + (RATHintsc 6 Tracen + RATHintsn)))) + (test_resolution_targets_match + idxs_in + hints_in + ff + ) + )) +) + +(declare test_is_at_trace + (! cs CMap + (! c clause + (! t Trace + (! r UPResult + (! sc (^ (is_at_trace cs c t) r) type)))))) + +; Test passes if the (test_is_at_trace ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v3) (clc (neg v2) cln)) + (@ c2 (clc (neg v3) (clc (neg v1) cln)) + (@ c3 (clc (neg v2) (clc (pos v1) cln)) + (@ c4 (clc (neg v3) (clc (pos v2) cln)) + (@ cs (CMapc 0 c1 (CMapc 3 c2 (CMapc 5 c3 (CMapc 6 c4 CMapn)))) + (@ c (clc (neg v3) cln) + (@ t (Tracec 3 (Tracec 5 (Tracec 6 Tracen))) + (test_is_at_trace + cs + c + t + UPR_Bottom + ) + ))) + )))) + )))) +) + +; Test passes if the (test_is_at_trace ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v3) (clc (neg v2) cln)) + (@ c2 (clc (neg v3) (clc (neg v1) cln)) + (@ c3 (clc (neg v2) (clc (pos v1) cln)) + (@ c4 (clc (neg v3) (clc (pos v2) cln)) + (@ cs (CMapc 0 c1 (CMapc 3 c2 (CMapc 5 c3 (CMapc 6 c4 CMapn)))) + (@ c (clc (neg v3) cln) + (@ t (Tracec 3 (Tracec 5 Tracen)) + (test_is_at_trace + cs + c + t + UPR_Ok + ) + ))) + )))) + )))) +) + +; Test passes if the (test_is_at_trace ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v3) (clc (neg v2) cln)) + (@ c2 (clc (neg v3) (clc (neg v1) cln)) + (@ c3 (clc (neg v2) (clc (pos v1) cln)) + (@ c4 (clc (neg v3) (clc (pos v2) cln)) + (@ cs (CMapc 1 c1 (CMapc 2 c2 (CMapc 3 c3 (CMapc 4 c4 CMapn)))) + (@ c (clc (neg v3) cln) + (@ t (Tracec 2 (Tracec 1 Tracen)) + (test_is_at_trace + cs + c + t + UPR_Broken + ) + ))) + )))) + )))) +) + +(declare test_is_rat_trace (! cs CMap + (! c clause + (! t Trace + (! h RATHints + (! r UPResult + (! sc (^ (is_rat_trace cs c t h) r) type))))))) + +; Test passes if the (test_is_rat_trace ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))) + (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))) + (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))) + (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))) + (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))) + (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))) + (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))) + (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))) + (@ cs (CMapc 1 c1 + (CMapc 2 c2 + (CMapc 3 c3 + (CMapc 4 c4 + (CMapc 5 c5 + (CMapc 6 c6 + (CMapc 7 c7 + (CMapc 8 c8 CMapn)))))))) + (@ c (clc (pos v1) cln) + (@ t Tracen + (@ h (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen)) + (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen)) + (RATHintsc 7 (Tracec 6 (Tracec 1 Tracen)) + RATHintsn))) + (test_is_rat_trace + cs + c + t + h + UPR_Bottom + ) + )))) + )))))))) + )))) +) + +; Test passes if the (test_is_rat_trace ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))) + (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))) + (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))) + (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))) + (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))) + (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))) + (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))) + (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))) + (@ cs (CMapc 1 c1 + (CMapc 2 c2 + (CMapc 3 c3 + (CMapc 4 c4 + (CMapc 5 c5 + (CMapc 6 c6 + (CMapc 7 c7 + (CMapc 8 c8 CMapn)))))))) + (@ c (clc (pos v1) cln) + (@ t Tracen + (@ h (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen)) + (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen)) + RATHintsn)) + (test_is_rat_trace + cs + c + t + h + UPR_Broken + ) + )))) + )))))))) + )))) +) + +; Test passes if the (test_is_rat_trace ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))) + (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))) + (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))) + (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))) + (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))) + (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))) + (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))) + (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))) + (@ cs (CMapc 1 c1 + (CMapc 2 c2 + (CMapc 3 c3 + (CMapc 4 c4 + (CMapc 5 c5 + (CMapc 6 c6 + (CMapc 7 c7 + (CMapc 8 c8 CMapn)))))))) + (@ c (clc (pos v1) cln) + (@ t Tracen + (@ h (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen)) + (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen)) + (RATHintsc 7 (Tracec 3 (Tracec 1 Tracen)) + RATHintsn))) + (test_is_rat_trace + cs + c + t + h + UPR_Broken + ) + )))) + )))))))) + )))) +) + +; Test passes if the (test_is_rat_trace ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))) + (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))) + (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))) + (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))) + (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))) + (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))) + (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))) + (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))) + (@ cs (CMapc 1 c1 + (CMapc 2 c2 + (CMapc 3 c3 + (CMapc 4 c4 + (CMapc 5 c5 + (CMapc 6 c6 + (CMapc 7 c7 + (CMapc 8 c8 CMapn)))))))) + (@ c (clc (pos v1) cln) + (@ t Tracen + (@ h (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen)) + (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen)) + (RATHintsc 7 (Tracec 3 Tracen) + RATHintsn))) + (test_is_rat_trace + cs + c + t + h + UPR_Broken + ) + )))) + )))))))) + )))) +) + +; Test passes if the (test_is_rat_trace ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))) + (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))) + (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))) + (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))) + (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))) + (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))) + (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))) + (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))) + (@ c9 (clc (pos v1) cln) + (@ cs (CMapc 1 c1 + (CMapc 2 c2 + (CMapc 3 c3 + (CMapc 4 c4 + (CMapc 5 c5 + (CMapc 6 c6 + (CMapc 7 c7 + (CMapc 8 c8 + (CMapc 9 c9 + CMapn))))))))) + (@ c (clc (pos v2) cln) + (@ t (Tracec 9 (Tracec 7 (Tracec 5 (Tracec 3 Tracen)))) + (@ h RATHintsn + (test_is_rat_trace + cs + c + t + h + UPR_Bottom + ) + )))) + ))))))))) + )))) +) + +; Test passes if the (test_is_rat_trace ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))) + (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))) + (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))) + (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))) + (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))) + (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))) + (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))) + (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))) + (@ c9 (clc (pos v1) cln) + (@ c10 (clc (pos v2) cln) + (@ cs (CMapc 1 c1 + (CMapc 2 c2 + (CMapc 3 c3 + (CMapc 4 c4 + (CMapc 5 c5 + (CMapc 6 c6 + (CMapc 7 c7 + (CMapc 8 c8 + (CMapc 9 c9 + (CMapc 10 c10 + CMapn)))))))))) + (@ c cln + (@ t (Tracec 9 (Tracec 10 (Tracec 2 (Tracec 4 (Tracec 5 Tracen))))) + (@ h RATHintsn + (test_is_rat_trace + cs + c + t + h + UPR_Bottom + ) + )))) + )))))))))) + )))) +) + +(declare test_is_lrat_proof_of_bottom + (! f CMap + (! p LRATProof + (! r bool + (! sc (^ (is_lrat_proof_of_bottom f p) r) type))))) + +; Test passes if the (test_is_lrat_proof_of_bottom ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))) + (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))) + (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))) + (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))) + (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))) + (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))) + (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))) + (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))) + (@ cs (CMapc 1 c1 + (CMapc 2 c2 + (CMapc 3 c3 + (CMapc 4 c4 + (CMapc 5 c5 + (CMapc 6 c6 + (CMapc 7 c7 + (CMapc 8 c8 + CMapn)))))))) + (@ p + (LRATProofa 9 + (clc (pos v1) cln) + Tracen + (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen)) + (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen)) + (RATHintsc 7 (Tracec 6 (Tracec 1 Tracen)) + RATHintsn))) + (LRATProofd (CIListc 1 (CIListc 6 (CIListc 8 CIListn))) + (LRATProofa 10 + (clc (pos v2) cln) + (Tracec 9 (Tracec 7 (Tracec 5 (Tracec 3 Tracen)))) + RATHintsn + (LRATProofd (CIListc 3 (CIListc 7 CIListn)) + (LRATProofa 11 + cln + (Tracec 9 (Tracec 10 (Tracec 2 (Tracec 4 (Tracec 5 Tracen))))) + RATHintsn + LRATProofn))))) + (test_is_lrat_proof_of_bottom + cs + p + tt + ) + )) + )))))))) + )))) +) + +; Test passes if the (test_is_lrat_proof_of_bottom ...) application is well-typed. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))) + (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))) + (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))) + (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))) + (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))) + (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))) + (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))) + (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))) + (@ cs (CMapc 1 c1 + (CMapc 2 c2 + (CMapc 3 c3 + (CMapc 4 c4 + (CMapc 5 c5 + (CMapc 6 c6 + (CMapc 7 c7 + (CMapc 8 c8 + CMapn)))))))) + (@ p + (LRATProofa 9 + (clc (pos v1) cln) + Tracen + (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen)) + (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen)) + (RATHintsc 7 (Tracec 6 (Tracec 1 Tracen)) + RATHintsn))) + (LRATProofd (CIListc 1 (CIListc 6 (CIListc 8 CIListn))) + (LRATProofa 10 + (clc (pos v2) cln) + (Tracec 9 (Tracec 7 (Tracec 5 (Tracec 3 Tracen)))) + RATHintsn + (LRATProofd (CIListc 3 (CIListc 7 CIListn)) + (LRATProofa 11 + cln + (Tracec 9 (Tracec 10 (Tracec 2 (Tracec 4 Tracen)))) + RATHintsn + LRATProofn))))) + (test_is_lrat_proof_of_bottom + cs + p + ff + ) + )) + )))))))) + )))) +) + +; Proof from Figure 2 of "Efficient Certified RAT Verification" +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (% pf_c1 (holds (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))) + (% pf_c2 (holds (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))) + (% pf_c3 (holds (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))) + (% pf_c4 (holds (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))) + (% pf_c5 (holds (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))) + (% pf_c6 (holds (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))) + (% pf_c7 (holds (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))) + (% pf_c8 (holds (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))) + (@ pf_cmap + (CMapc_proof 1 _ _ pf_c1 + (CMapc_proof 2 _ _ pf_c2 + (CMapc_proof 3 _ _ pf_c3 + (CMapc_proof 4 _ _ pf_c4 + (CMapc_proof 5 _ _ pf_c5 + (CMapc_proof 6 _ _ pf_c6 + (CMapc_proof 7 _ _ pf_c7 + (CMapc_proof 8 _ _ pf_c8 + CMapn_proof)))))))) + (@ lrat_proof_witness + (LRATProofa 9 + (clc (pos v1) cln) + Tracen + (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen)) + (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen)) + (RATHintsc 7 (Tracec 6 (Tracec 1 Tracen)) + RATHintsn))) + (LRATProofd (CIListc 1 (CIListc 6 (CIListc 8 CIListn))) + (LRATProofa 10 + (clc (pos v2) cln) + (Tracec 9 (Tracec 7 (Tracec 5 (Tracec 3 Tracen)))) + RATHintsn + (LRATProofd (CIListc 3 (CIListc 7 CIListn)) + (LRATProofa 11 + cln + (Tracec 9 (Tracec 10 (Tracec 2 (Tracec 4 (Tracec 5 Tracen))))) + RATHintsn + LRATProofn))))) + (: + (holds cln) + (lrat_proof_of_bottom _ pf_cmap lrat_proof_witness)) + )) + )))))))) + )))) +) + +; Clauses 1 and 9 are identical. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (% pf_c1 (holds (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))) + (% pf_c2 (holds (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))) + (% pf_c3 (holds (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))) + (% pf_c4 (holds (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))) + (% pf_c5 (holds (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))) + (% pf_c6 (holds (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))) + (% pf_c7 (holds (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))) + (% pf_c8 (holds (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))) + (% pf_c9 (holds (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))) + (@ pf_cmap + (CMapc_proof 1 _ _ pf_c1 + (CMapc_proof 2 _ _ pf_c2 + (CMapc_proof 3 _ _ pf_c3 + (CMapc_proof 4 _ _ pf_c4 + (CMapc_proof 5 _ _ pf_c5 + (CMapc_proof 6 _ _ pf_c6 + (CMapc_proof 7 _ _ pf_c7 + (CMapc_proof 8 _ _ pf_c8 + (CMapc_proof 9 _ _ pf_c9 + CMapn_proof))))))))) + (@ lrat_proof_witness + (LRATProofa 10 + (clc (pos v1) cln) + Tracen + (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen)) + (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen)) + (RATHintsc 7 (Tracec 6 (Tracec 9 Tracen)) + RATHintsn))) + (LRATProofd (CIListc 1 (CIListc 6 (CIListc 8 (CIListc 9 CIListn)))) + (LRATProofa 11 + (clc (pos v2) cln) + (Tracec 10 (Tracec 7 (Tracec 5 (Tracec 3 Tracen)))) + RATHintsn + (LRATProofd (CIListc 3 (CIListc 7 CIListn)) + (LRATProofa 12 + cln + (Tracec 10 (Tracec 11 (Tracec 2 (Tracec 4 (Tracec 5 Tracen))))) + RATHintsn + LRATProofn))))) + (: + (holds cln) + (lrat_proof_of_bottom _ pf_cmap lrat_proof_witness)) + )) + ))))))))) + )))) +) + +; Proof from Figure 1 of "Efficient Certified RAT Verification" +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (% pf_c1 (holds (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))) + (% pf_c2 (holds (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))) + (% pf_c3 (holds (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))) + (% pf_c4 (holds (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))) + (% pf_c5 (holds (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))) + (% pf_c6 (holds (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))) + (% pf_c7 (holds (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))) + (% pf_c8 (holds (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))) + (@ pf_cmap + (CMapc_proof 1 _ _ pf_c1 + (CMapc_proof 2 _ _ pf_c2 + (CMapc_proof 3 _ _ pf_c3 + (CMapc_proof 4 _ _ pf_c4 + (CMapc_proof 5 _ _ pf_c5 + (CMapc_proof 6 _ _ pf_c6 + (CMapc_proof 7 _ _ pf_c7 + (CMapc_proof 8 _ _ pf_c8 + CMapn_proof)))))))) + (@ lrat_proof_witness + (LRATProofa 9 + (clc (pos v1) (clc (pos v2) cln)) + (Tracec 1 (Tracec 6 (Tracec 3 Tracen))) + RATHintsn + (LRATProofd (CIListc 1 CIListn) + (LRATProofa 10 + (clc (pos v1) (clc (pos v3) cln)) + (Tracec 9 (Tracec 8 (Tracec 6 Tracen))) + RATHintsn + (LRATProofd (CIListc 6 CIListn) + (LRATProofa 11 + (clc (pos v1) cln) + (Tracec 10 (Tracec 9 (Tracec 4 (Tracec 8 Tracen)))) + RATHintsn + (LRATProofd (CIListc 8 (CIListc 9 (CIListc 10 CIListn))) + (LRATProofa 12 + (clc (pos v2) cln) + (Tracec 11 (Tracec 7 (Tracec 5 (Tracec 3 Tracen)))) + RATHintsn + (LRATProofd (CIListc 3 (CIListc 7 CIListn)) + (LRATProofa 13 + cln + (Tracec 11 (Tracec 12 (Tracec 2 (Tracec 4 (Tracec 5 Tracen))))) + RATHintsn + LRATProofn + ))))))))) + (: + (holds cln) + (lrat_proof_of_bottom _ pf_cmap lrat_proof_witness)) + )) + )))))))) + )))) +) diff --git a/proofs/signatures/sat.plf b/proofs/signatures/sat.plf index b95caa8fd..8f40aa8bf 100644 --- a/proofs/signatures/sat.plf +++ b/proofs/signatures/sat.plf @@ -19,8 +19,8 @@ ; code to check resolutions -(program append ((c1 clause) (c2 clause)) clause - (match c1 (cln c2) ((clc l c1') (clc l (append c1' c2))))) +(program clause_append ((c1 clause) (c2 clause)) clause + (match c1 (cln c2) ((clc l c1') (clc l (clause_append c1' c2))))) ; we use marks as follows: ; -- mark 1 to record if we are supposed to remove a positive occurrence of the variable. @@ -49,7 +49,7 @@ (match m (tt (do (ifmarked4 v v (markvar4 v)) c')) (ff (do (ifmarked4 v (markvar4 v) v) (markvar2 v) (clc l c'))))))))) - ((concat_cl c1 c2) (append (simplify_clause c1) (simplify_clause c2))) + ((concat_cl c1 c2) (clause_append (simplify_clause c1) (simplify_clause c2))) ((clr l c1) (match l ; set mark 1 to indicate we should remove v, and fail if diff --git a/proofs/signatures/smt.plf b/proofs/signatures/smt.plf index 06dc16153..57dc5bd1e 100644 --- a/proofs/signatures/smt.plf +++ b/proofs/signatures/smt.plf @@ -439,6 +439,22 @@ (holds C)) (holds (clc (neg v) C)))))))))) +;; Numeric primitives + +(program mpz_sub ((x mpz) (y mpz)) mpz + (mp_add x (mp_mul (~1) y))) + +(program mp_ispos ((x mpz)) formula + (mp_ifneg x false true)) + +(program mpz_eq ((x mpz) (y mpz)) formula + (mp_ifzero (mpz_sub x y) true false)) + +(program mpz_lt ((x mpz) (y mpz)) formula + (mp_ifneg (mpz_sub x y) true false)) + +(program mpz_lte ((x mpz) (y mpz)) formula + (mp_ifneg (mpz_sub x y) true (mpz_eq x y))) ;; Example: ;; diff --git a/proofs/signatures/th_bv.plf b/proofs/signatures/th_bv.plf index 6012e052a..934951a86 100644 --- a/proofs/signatures/th_bv.plf +++ b/proofs/signatures/th_bv.plf @@ -3,20 +3,6 @@ (declare trust-bad (th_holds false)) ; helper stuff -(program mpz_sub ((x mpz) (y mpz)) mpz - (mp_add x (mp_mul (~1) y))) - -(program mp_ispos ((x mpz)) formula - (mp_ifneg x false true)) - -(program mpz_eq ((x mpz) (y mpz)) formula - (mp_ifzero (mpz_sub x y) true false)) - -(program mpz_lt ((x mpz) (y mpz)) formula - (mp_ifneg (mpz_sub x y) true false)) - -(program mpz_lte ((x mpz) (y mpz)) formula - (mp_ifneg (mpz_sub x y) true (mpz_eq x y))) (program mpz_ ((x mpz) (y mpz)) formula (mp_ifzero (mpz_sub x y) true false)) -- cgit v1.2.3 From 147fd723e6c13eb3dd44a43073be03a64ea3fe66 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Tue, 11 Dec 2018 16:38:00 -0600 Subject: Remove alternate versions of mbqi (#2742) --- src/CMakeLists.txt | 2 - src/options/options_handler.cpp | 18 +- src/options/quantifiers_modes.cpp | 6 - src/options/quantifiers_modes.h | 4 - src/smt/smt_engine.cpp | 17 - src/theory/quantifiers/first_order_model.cpp | 590 ------------- src/theory/quantifiers/first_order_model.h | 121 +-- src/theory/quantifiers/fmf/ambqi_builder.cpp | 971 --------------------- src/theory/quantifiers/fmf/ambqi_builder.h | 105 --- src/theory/quantifiers/fmf/model_builder.cpp | 684 --------------- src/theory/quantifiers/fmf/model_builder.h | 157 ---- src/theory/quantifiers/fmf/model_engine.cpp | 1 - src/theory/quantifiers_engine.cpp | 13 +- src/theory/uf/theory_uf_model.cpp | 84 -- src/theory/uf/theory_uf_model.h | 39 - .../regress0/fmf/Arrow_Order-smtlib.778341.smt | 2 +- test/regress/regress0/fmf/QEpres-uf.855035.smt | 2 +- test/regress/regress1/fmf/nlp042+1.smt2 | 2 +- 18 files changed, 14 insertions(+), 2804 deletions(-) delete mode 100644 src/theory/quantifiers/fmf/ambqi_builder.cpp delete mode 100644 src/theory/quantifiers/fmf/ambqi_builder.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9e93bd953..91c06ddd9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -475,8 +475,6 @@ libcvc4_add_sources( theory/quantifiers/extended_rewrite.h theory/quantifiers/first_order_model.cpp theory/quantifiers/first_order_model.h - theory/quantifiers/fmf/ambqi_builder.cpp - theory/quantifiers/fmf/ambqi_builder.h theory/quantifiers/fmf/bounded_integers.cpp theory/quantifiers/fmf/bounded_integers.h theory/quantifiers/fmf/full_model_check.cpp diff --git a/src/options/options_handler.cpp b/src/options/options_handler.cpp index 420396452..36144e70e 100644 --- a/src/options/options_handler.cpp +++ b/src/options/options_handler.cpp @@ -267,7 +267,8 @@ agg \n\ \n\ "; -const std::string OptionsHandler::s_mbqiModeHelp = "\ +const std::string OptionsHandler::s_mbqiModeHelp = + "\ Model-based quantifier instantiation modes currently supported by the --mbqi option:\n\ \n\ default \n\ @@ -277,12 +278,8 @@ default \n\ none \n\ + Disable model-based quantifier instantiation.\n\ \n\ -gen-ev \n\ -+ Use model-based quantifier instantiation algorithm from CADE 24 finite\n\ - model finding paper based on generalizing evaluations.\n\ -\n\ -abs \n\ -+ Use abstract MBQI algorithm (uses disjoint sets). \n\ +trust \n\ ++ Do not instantiate quantified formulas (incomplete technique).\n\ \n\ "; @@ -660,14 +657,11 @@ void OptionsHandler::checkLiteralMatchMode( theory::quantifiers::MbqiMode OptionsHandler::stringToMbqiMode( std::string option, std::string optarg) { - if(optarg == "gen-ev") { - return theory::quantifiers::MBQI_GEN_EVAL; - } else if(optarg == "none") { + if (optarg == "none") + { return theory::quantifiers::MBQI_NONE; } else if(optarg == "default" || optarg == "fmc") { return theory::quantifiers::MBQI_FMC; - } else if(optarg == "abs") { - return theory::quantifiers::MBQI_ABS; } else if(optarg == "trust") { return theory::quantifiers::MBQI_TRUST; } else if(optarg == "help") { diff --git a/src/options/quantifiers_modes.cpp b/src/options/quantifiers_modes.cpp index 1814a363d..b08f71c2e 100644 --- a/src/options/quantifiers_modes.cpp +++ b/src/options/quantifiers_modes.cpp @@ -64,18 +64,12 @@ std::ostream& operator<<(std::ostream& out, theory::quantifiers::LiteralMatchMod std::ostream& operator<<(std::ostream& out, theory::quantifiers::MbqiMode mode) { switch(mode) { - case theory::quantifiers::MBQI_GEN_EVAL: - out << "MBQI_GEN_EVAL"; - break; case theory::quantifiers::MBQI_NONE: out << "MBQI_NONE"; break; case theory::quantifiers::MBQI_FMC: out << "MBQI_FMC"; break; - case theory::quantifiers::MBQI_ABS: - out << "MBQI_ABS"; - break; case theory::quantifiers::MBQI_TRUST: out << "MBQI_TRUST"; break; diff --git a/src/options/quantifiers_modes.h b/src/options/quantifiers_modes.h index 41378d2cd..eea043865 100644 --- a/src/options/quantifiers_modes.h +++ b/src/options/quantifiers_modes.h @@ -53,14 +53,10 @@ enum LiteralMatchMode { }; enum MbqiMode { - /** mbqi from CADE 24 paper */ - MBQI_GEN_EVAL, /** no mbqi */ MBQI_NONE, /** default, mbqi from Section 5.4.2 of AJR thesis */ MBQI_FMC, - /** abstract mbqi algorithm */ - MBQI_ABS, /** mbqi trust (produce no instantiations) */ MBQI_TRUST, }; diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp index 7abfd8273..ae20fa156 100644 --- a/src/smt/smt_engine.cpp +++ b/src/smt/smt_engine.cpp @@ -1809,12 +1809,6 @@ void SmtEngine::setDefaults() { options::mbqiMode.set( quantifiers::MBQI_NONE ); } } - if( options::mbqiMode()==quantifiers::MBQI_ABS ){ - if( !d_logic.isPure(THEORY_UF) ){ - //MBQI_ABS is only supported in pure quantified UF - options::mbqiMode.set( quantifiers::MBQI_FMC ); - } - } if( options::fmfFunWellDefinedRelevant() ){ if( !options::fmfFunWellDefined.wasSetByUser() ){ options::fmfFunWellDefined.set( true ); @@ -1852,17 +1846,6 @@ void SmtEngine::setDefaults() { options::instWhenMode.set( quantifiers::INST_WHEN_LAST_CALL ); } } - if( options::mbqiMode()==quantifiers::MBQI_ABS ){ - if( !options::preSkolemQuant.wasSetByUser() ){ - options::preSkolemQuant.set( true ); - } - if( !options::preSkolemQuantNested.wasSetByUser() ){ - options::preSkolemQuantNested.set( true ); - } - if( !options::fmfOneInstPerRound.wasSetByUser() ){ - options::fmfOneInstPerRound.set( true ); - } - } } //apply counterexample guided instantiation options diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp index 0eec40de2..5eb65ed21 100644 --- a/src/theory/quantifiers/first_order_model.cpp +++ b/src/theory/quantifiers/first_order_model.cpp @@ -15,7 +15,6 @@ #include "theory/quantifiers/first_order_model.h" #include "options/base_options.h" #include "options/quantifiers_options.h" -#include "theory/quantifiers/fmf/ambqi_builder.h" #include "theory/quantifiers/fmf/bounded_integers.h" #include "theory/quantifiers/fmf/full_model_check.h" #include "theory/quantifiers/fmf/model_engine.h" @@ -414,473 +413,6 @@ unsigned FirstOrderModel::getModelBasisArg(Node n) return n.getAttribute(ModelBasisArgAttribute()); } -Node FirstOrderModelIG::UfModelTreeGenerator::getIntersection(TheoryModel* m, - Node n1, - Node n2, - bool& isGround) -{ - isGround = true; - std::vector children; - children.push_back(n1.getOperator()); - for (unsigned i = 0, size = n1.getNumChildren(); i < size; i++) - { - if (n1[i] == n2[i]) - { - if (n1[i].getAttribute(ModelBasisAttribute())) - { - isGround = false; - } - children.push_back(n1[i]); - } - else if (n1[i].getAttribute(ModelBasisAttribute())) - { - children.push_back(n2[i]); - } - else if (n2[i].getAttribute(ModelBasisAttribute())) - { - children.push_back(n1[i]); - } - else if (m->areEqual(n1[i], n2[i])) - { - children.push_back(n1[i]); - } - else - { - return Node::null(); - } - } - return NodeManager::currentNM()->mkNode(APPLY_UF, children); -} - -void FirstOrderModelIG::UfModelTreeGenerator::setValue( - TheoryModel* m, Node n, Node v, bool ground, bool isReq) -{ - Assert(!n.isNull()); - Assert(!v.isNull()); - d_set_values[isReq ? 1 : 0][ground ? 1 : 0][n] = v; - if (!ground) - { - for (unsigned i = 0, defSize = d_defaults.size(); i < defSize; i++) - { - // for correctness, to allow variable order-independent function - // interpretations, we must ensure that the intersection of all default - // terms is also defined. - // for example, if we have that f( e, a ) = ..., and f( b, e ) = ..., - // then we must define f( b, a ). - bool isGround; - Node ni = getIntersection(m, n, d_defaults[i], isGround); - if (!ni.isNull()) - { - // if the intersection exists, and is not already defined - if (d_set_values[0][isGround ? 1 : 0].find(ni) - == d_set_values[0][isGround ? 1 : 0].end() - && d_set_values[1][isGround ? 1 : 0].find(ni) - == d_set_values[1][isGround ? 1 : 0].end()) - { - // use the current value - setValue(m, ni, v, isGround, false); - } - } - } - d_defaults.push_back(n); - } - if (isReq - && d_set_values[0][ground ? 1 : 0].find(n) - != d_set_values[0][ground ? 1 : 0].end()) - { - d_set_values[0][ground ? 1 : 0].erase(n); - } -} - -void FirstOrderModelIG::UfModelTreeGenerator::makeModel(TheoryModel* m, - uf::UfModelTree& tree) -{ - for (int j = 0; j < 2; j++) - { - for (int k = 0; k < 2; k++) - { - for (std::map::iterator it = d_set_values[j][k].begin(); - it != d_set_values[j][k].end(); - ++it) - { - tree.setValue(m, it->first, it->second, k == 1); - } - } - } - if (!d_default_value.isNull()) - { - tree.setDefaultValue(m, d_default_value); - } - tree.simplify(); -} - -void FirstOrderModelIG::UfModelTreeGenerator::clear() -{ - d_default_value = Node::null(); - for (int j = 0; j < 2; j++) - { - for (int k = 0; k < 2; k++) - { - d_set_values[j][k].clear(); - } - } - d_defaults.clear(); -} - -FirstOrderModelIG::FirstOrderModelIG(QuantifiersEngine * qe, context::Context* c, std::string name) : -FirstOrderModel(qe, c,name) { - -} - -void FirstOrderModelIG::processInitialize( bool ispre ){ - if( ispre ){ - //rebuild models - d_uf_model_tree.clear(); - d_uf_model_gen.clear(); - } -} - -void FirstOrderModelIG::processInitializeModelForTerm( Node n ){ - if( n.getKind()==APPLY_UF ){ - Node op = n.getOperator(); - if( d_uf_model_tree.find( op )==d_uf_model_tree.end() ){ - TypeNode tn = op.getType(); - tn = tn[ (int)tn.getNumChildren()-1 ]; - //only generate models for predicates and functions with uninterpreted range types - //if( tn==NodeManager::currentNM()->booleanType() || tn.isSort() ){ - d_uf_model_tree[ op ] = uf::UfModelTree( op ); - d_uf_model_gen[ op ].clear(); - //} - } - } - /* - if( n.getType().isArray() ){ - while( n.getKind()==STORE ){ - n = n[0]; - } - Node nn = getRepresentative( n ); - if( d_array_model.find( nn )==d_array_model.end() ){ - d_array_model[nn] = arrays::ArrayModel( nn, this ); - } - } - */ -} - -//for evaluation of quantifier bodies - -void FirstOrderModelIG::resetEvaluate(){ - d_eval_uf_use_default.clear(); - d_eval_uf_model.clear(); - d_eval_term_index_order.clear(); -} - -//if evaluate( n ) = eVal, -// let n' = ri * n be the formula n instantiated with the current values in r_iter -// if eVal = 1, then n' is true, if eVal = -1, then n' is false, -// if eVal = 0, then n' cannot be proven to be equal to phaseReq -// if eVal is not 0, then -// each n{ri->d_index[0]/x_0...ri->d_index[depIndex]/x_depIndex, */x_(depIndex+1) ... */x_n } is equivalent in the current model -int FirstOrderModelIG::evaluate( Node n, int& depIndex, RepSetIterator* ri ){ - Debug("fmf-eval-debug2") << "Evaluate " << n << std::endl; - //Notice() << "Eval " << n << std::endl; - if( n.getKind()==NOT ){ - int val = evaluate( n[0], depIndex, ri ); - return val==1 ? -1 : ( val==-1 ? 1 : 0 ); - }else if( n.getKind()==OR || n.getKind()==AND ){ - int baseVal = n.getKind()==AND ? 1 : -1; - int eVal = baseVal; - int posDepIndex = ri->getNumTerms(); - int negDepIndex = -1; - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - //evaluate subterm - int childDepIndex; - Node nn = n[i]; - int eValT = evaluate( nn, childDepIndex, ri ); - if( eValT==baseVal ){ - if( eVal==baseVal ){ - if( childDepIndex>negDepIndex ){ - negDepIndex = childDepIndex; - } - } - }else if( eValT==-baseVal ){ - eVal = -baseVal; - if( childDepIndexdepIndex2 ? depIndex1 : depIndex2; - return eVal==eVal2 ? 1 : -1; - } - } - return 0; - }else if( n.getKind()==ITE ){ - int depIndex1, depIndex2; - int eVal = evaluate( n[0], depIndex1, ri ); - if( eVal==0 ){ - //evaluate children to see if they are the same value - int eval1 = evaluate( n[1], depIndex1, ri ); - if( eval1!=0 ){ - int eval2 = evaluate( n[1], depIndex2, ri ); - if( eval1==eval2 ){ - depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2; - return eval1; - } - } - }else{ - int eValT = evaluate( n[eVal==1 ? 1 : 2], depIndex2, ri ); - depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2; - return eValT; - } - return 0; - }else if( n.getKind()==FORALL ){ - return 0; - }else{ - //Debug("fmf-eval-debug") << "Evaluate literal " << n << std::endl; - int retVal = 0; - depIndex = ri->getNumTerms()-1; - Node val = evaluateTerm( n, depIndex, ri ); - if( !val.isNull() ){ - if( areEqual( val, d_true ) ){ - retVal = 1; - }else if( areEqual( val, d_false ) ){ - retVal = -1; - }else{ - if( val.getKind()==EQUAL ){ - if( areEqual( val[0], val[1] ) ){ - retVal = 1; - }else if( areDisequal( val[0], val[1] ) ){ - retVal = -1; - } - } - } - } - if( retVal!=0 ){ - Debug("fmf-eval-debug") << "Evaluate literal: return " << retVal << ", depIndex = " << depIndex << std::endl; - }else{ - Trace("fmf-eval-amb") << "Neither true nor false : " << n << std::endl; - Trace("fmf-eval-amb") << " value : " << val << std::endl; - } - return retVal; - } -} - -Node FirstOrderModelIG::evaluateTerm( Node n, int& depIndex, RepSetIterator* ri ){ - //Message() << "Eval term " << n << std::endl; - Node val; - depIndex = ri->getNumTerms()-1; - //check the type of n - if( n.getKind()==INST_CONSTANT ){ - int v = n.getAttribute(InstVarNumAttribute()); - depIndex = ri->getIndexOrder( v ); - val = ri->getCurrentTerm( v ); - }else if( n.getKind()==ITE ){ - int depIndex1, depIndex2; - int eval = evaluate( n[0], depIndex1, ri ); - if( eval==0 ){ - //evaluate children to see if they are the same - Node val1 = evaluateTerm( n[ 1 ], depIndex1, ri ); - Node val2 = evaluateTerm( n[ 2 ], depIndex2, ri ); - if( val1==val2 ){ - val = val1; - depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2; - }else{ - return Node::null(); - } - }else{ - val = evaluateTerm( n[ eval==1 ? 1 : 2 ], depIndex2, ri ); - depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2; - } - }else{ - std::vector< int > children_depIndex; - //default term evaluate : evaluate all children, recreate the value - val = evaluateTermDefault( n, depIndex, children_depIndex, ri ); - Trace("fmf-eval-debug") << "Evaluate term, value from " << n << " is " << val << std::endl; - if( !val.isNull() ){ - bool setVal = false; - //custom ways of evaluating terms - if( n.getKind()==APPLY_UF ){ - Node op = n.getOperator(); - //Debug("fmf-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl; - //if it is a defined UF, then consult the interpretation - if( d_uf_model_tree.find( op )!=d_uf_model_tree.end() ){ - int argDepIndex = 0; - //make the term model specifically for n - makeEvalUfModel( n ); - //now, consult the model - if( d_eval_uf_use_default[n] ){ - Trace("fmf-eval-debug") << "get default" << std::endl; - val = d_uf_model_tree[ op ].getValue( this, val, argDepIndex ); - }else{ - Trace("fmf-eval-debug") << "get uf model" << std::endl; - val = d_eval_uf_model[ n ].getValue( this, val, argDepIndex ); - } - //Debug("fmf-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl; - //d_eval_uf_model[ n ].debugPrint("fmf-eval-debug", d_qe ); - Assert( !val.isNull() ); - //recalculate the depIndex - depIndex = -1; - for( int i=0; idepIndex ){ - depIndex = children_depIndex[index]; - } - } - setVal = true; - }else{ - Trace("fmf-eval-debug") << "No model." << std::endl; - } - } - //if not set already, rewrite and consult model for interpretation - if( !setVal ){ - val = Rewriter::rewrite( val ); - if( !val.isConst() ){ - return Node::null(); - } - } - Trace("fmf-eval-debug") << "Evaluate term " << n << " = "; - Trace("fmf-eval-debug") << getRepresentative(val); - Trace("fmf-eval-debug") << " (term " << val << "), depIndex = " << depIndex << std::endl; - } - } - return val; -} - -Node FirstOrderModelIG::evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex, RepSetIterator* ri ){ - depIndex = -1; - if( n.getNumChildren()==0 ){ - return n; - }else{ - bool isInterp = n.getKind()!=APPLY_UF; - //first we must evaluate the arguments - std::vector< Node > children; - if( n.getMetaKind()==kind::metakind::PARAMETERIZED ){ - children.push_back( n.getOperator() ); - } - //for each argument, calculate its value, and the variables its value depends upon - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - childDepIndex.push_back( -1 ); - Node nn = evaluateTerm( n[i], childDepIndex[i], ri ); - if( nn.isNull() ){ - depIndex = ri->getNumTerms()-1; - return nn; - }else{ - if( childDepIndex[i]>depIndex ){ - depIndex = childDepIndex[i]; - } - if( isInterp ){ - if( !nn.isConst() ) { - nn = getRepresentative( nn ); - } - } - children.push_back( nn ); - } - } - //recreate the value - Node val = NodeManager::currentNM()->mkNode( n.getKind(), children ); - return val; - } -} - -void FirstOrderModelIG::makeEvalUfModel( Node n ){ - if( d_eval_uf_model.find( n )==d_eval_uf_model.end() ){ - makeEvalUfIndexOrder( n ); - if( !d_eval_uf_use_default[n] ){ - Node op = n.getOperator(); - d_eval_uf_model[n] = uf::UfModelTree( op, d_eval_term_index_order[n] ); - d_uf_model_gen[op].makeModel( this, d_eval_uf_model[n] ); - //Debug("fmf-index-order") << "Make model for " << n << " : " << std::endl; - //d_eval_uf_model[n].debugPrint( std::cout, d_qe->getModel(), 2 ); - } - } -} - -struct sortGetMaxVariableNum { - std::map< Node, int > d_max_var_num; - int computeMaxVariableNum( Node n ){ - if( n.getKind()==INST_CONSTANT ){ - return n.getAttribute(InstVarNumAttribute()); - }else if( TermUtil::hasInstConstAttr(n) ){ - int maxVal = -1; - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - int val = getMaxVariableNum( n[i] ); - if( val>maxVal ){ - maxVal = val; - } - } - return maxVal; - }else{ - return -1; - } - } - int getMaxVariableNum( Node n ){ - std::map< Node, int >::iterator it = d_max_var_num.find( n ); - if( it==d_max_var_num.end() ){ - int num = computeMaxVariableNum( n ); - d_max_var_num[n] = num; - return num; - }else{ - return it->second; - } - } - bool operator() (Node i,Node j) { return (getMaxVariableNum(i) > argIndex; - std::vector< Node > args; - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( argIndex.find( n[i] )==argIndex.end() ){ - args.push_back( n[i] ); - } - argIndex[n[i]].push_back( i ); - } - sortGetMaxVariableNum sgmvn; - std::sort( args.begin(), args.end(), sgmvn ); - for( int i=0; i<(int)args.size(); i++ ){ - for( int j=0; j<(int)argIndex[ args[i] ].size(); j++ ){ - d_eval_term_index_order[n].push_back( argIndex[ args[i] ][j] ); - } - } - bool useDefault = true; - for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){ - if( i!=d_eval_term_index_order[n][i] ){ - useDefault = false; - break; - } - } - d_eval_uf_use_default[n] = useDefault; - Debug("fmf-index-order") << "Will consider the following index ordering for " << n << " : "; - for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){ - Debug("fmf-index-order") << d_eval_term_index_order[n][i] << " "; - } - Debug("fmf-index-order") << std::endl; - } -} - FirstOrderModelFmc::FirstOrderModelFmc(QuantifiersEngine * qe, context::Context* c, std::string name) : FirstOrderModel(qe, c, name){ @@ -989,128 +521,6 @@ Node FirstOrderModelFmc::getFunctionValue(Node op, const char* argPrefix ) { return NodeManager::currentNM()->mkNode(kind::LAMBDA, boundVarList, curr); } -FirstOrderModelAbs::FirstOrderModelAbs(QuantifiersEngine * qe, context::Context* c, std::string name) : -FirstOrderModel(qe, c, name) { - -} - -FirstOrderModelAbs::~FirstOrderModelAbs() -{ - for(std::map::iterator i = d_models.begin(); i != d_models.end(); ++i) { - delete (*i).second; - } -} - -void FirstOrderModelAbs::processInitialize( bool ispre ) { - if( !ispre ){ - Trace("ambqi-debug") << "Process initialize" << std::endl; - for( std::map::iterator it = d_models.begin(); it != d_models.end(); ++it ) { - Node op = it->first; - TypeNode tno = op.getType(); - Trace("ambqi-debug") << " Init " << op << " " << tno << std::endl; - for( unsigned i=0; i::iterator it = d_rep_id.find( r ); - if( it!=d_rep_id.end() ){ - return it->second; - }else{ - return 0; - } -} - -TNode FirstOrderModelAbs::getUsedRepresentative( TNode n ) { - if( hasTerm( n ) ){ - if( n.getType().isBoolean() ){ - return areEqual(n, d_true) ? d_true : d_false; - }else{ - return getRepresentative( n ); - } - }else{ - Trace("qint-debug") << "Get rep " << n << " " << n.getType() << std::endl; - Assert( d_rep_set.hasType( n.getType() ) && !d_rep_set.d_type_reps[n.getType()].empty() ); - return d_rep_set.d_type_reps[n.getType()][0]; - } -} - -Node FirstOrderModelAbs::getFunctionValue(Node op, const char* argPrefix ) { - if( d_models_valid[op] ){ - Trace("ambqi-debug") << "Get function value for " << op << std::endl; - TypeNode type = op.getType(); - std::vector< Node > vars; - for( size_t i=0; imkBoundVar( ss.str(), type[i] ); - vars.push_back( b ); - } - Node boundVarList = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, vars); - Node curr = d_models[op]->getFunctionValue( this, op, vars ); - Node fv = NodeManager::currentNM()->mkNode(kind::LAMBDA, boundVarList, curr); - Trace("ambqi-debug") << "Return " << fv << std::endl; - return fv; - }else{ - - } - return Node::null(); -} - -void FirstOrderModelAbs::processInitializeModelForTerm( Node n ) { - if( n.getKind()==APPLY_UF || n.getKind()==VARIABLE || n.getKind()==SKOLEM ){ - Node op = n.getKind()==APPLY_UF ? n.getOperator() : n; - if( d_models.find(op)==d_models.end()) { - Trace("abmqi-debug") << "init model for " << op << std::endl; - d_models[op] = new AbsDef; - d_models_valid[op] = false; - } - } -} - -void FirstOrderModelAbs::collectEqVars( TNode q, TNode n, std::map< int, bool >& eq_vars ) { - for( unsigned i=0; i=0 && v<(int)q[0].getNumChildren() ); - eq_vars[v] = true; - } - collectEqVars( q, n[i], eq_vars ); - } -} - -void FirstOrderModelAbs::processInitializeQuantifier( Node q ) { - if( d_var_order.find( q )==d_var_order.end() ){ - std::map< int, bool > eq_vars; - for( unsigned i=0; i::iterator it = eq_vars.begin(); it != eq_vars.end(); ++it ){ - if( it->second==(r==1) ){ - d_var_index[q][it->first] = d_var_order[q].size(); - d_var_order[q].push_back( it->first ); - } - } - } - } -} - -Node FirstOrderModelAbs::getVariable( Node q, unsigned i ) { - return q[0][d_var_order[q][i]]; -} - } /* CVC4::theory::quantifiers namespace */ } /* CVC4::theory namespace */ } /* CVC4 namespace */ diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h index 7da5b2088..b96b42dc2 100644 --- a/src/theory/quantifiers/first_order_model.h +++ b/src/theory/quantifiers/first_order_model.h @@ -42,15 +42,10 @@ namespace quantifiers { class TermDb; -class FirstOrderModelIG; - namespace fmcheck { class FirstOrderModelFmc; }/* CVC4::theory::quantifiers::fmcheck namespace */ -class FirstOrderModelQInt; -class FirstOrderModelAbs; - struct IsStarAttributeId {}; typedef expr::Attribute IsStarAttribute; @@ -94,10 +89,7 @@ class FirstOrderModel : public TheoryModel public: FirstOrderModel(QuantifiersEngine* qe, context::Context* c, std::string name); - virtual FirstOrderModelIG* asFirstOrderModelIG() { return nullptr; } virtual fmcheck::FirstOrderModelFmc* asFirstOrderModelFmc() { return nullptr; } - virtual FirstOrderModelQInt* asFirstOrderModelQInt() { return nullptr; } - virtual FirstOrderModelAbs* asFirstOrderModelAbs() { return nullptr; } /** assert quantifier */ void assertQuantifier( Node n ); /** get number of asserted quantifiers */ @@ -172,11 +164,11 @@ class FirstOrderModel : public TheoryModel /** get variable id */ std::map > d_quant_var_id; /** process initialize model for term */ - virtual void processInitializeModelForTerm(Node n) = 0; + virtual void processInitializeModelForTerm(Node n) {} /** process initialize quantifier */ virtual void processInitializeQuantifier(Node q) {} /** process initialize */ - virtual void processInitialize(bool ispre) = 0; + virtual void processInitialize(bool ispre) {} private: // list of inactive quantified formulas @@ -193,85 +185,6 @@ class FirstOrderModel : public TheoryModel void computeModelBasisArgAttribute(Node n); };/* class FirstOrderModel */ -class FirstOrderModelIG : public FirstOrderModel -{ - public: // for Theory UF: - /** class for generating models for uninterpreted functions - * - * This implements the model construction from page 6 of Reynolds et al, - * "Quantifier Instantiation Techniques for Finite Model Finding in SMT", - * CADE 2013. - */ - class UfModelTreeGenerator - { - public: - UfModelTreeGenerator() {} - ~UfModelTreeGenerator() {} - /** set default value */ - void setDefaultValue(Node v) { d_default_value = v; } - /** set value */ - void setValue( - TheoryModel* m, Node n, Node v, bool ground = true, bool isReq = true); - /** make model */ - void makeModel(TheoryModel* m, uf::UfModelTree& tree); - /** reset */ - void clear(); - - public: - /** the overall default value */ - Node d_default_value; - /** - * Stores (required, ground) values in key, value pairs of the form - * ( P( a, b ), c ), which indicates P( a, b ) has value c in the model. - * The "non-ground" values indicate that the key has a "model-basis" - * variable, for example, ( P( _, b ), c ) indicates that P( x, b ) has the - * value b for any value of x. - */ - std::map d_set_values[2][2]; - /** stores the set of non-ground keys in the above maps */ - std::vector d_defaults; - /** - * Returns the term corresponding to the intersection of n1 and n2, if it - * exists, for example, for P( _, a ) and P( b, _ ), this method returns - * P( b, a ), where _ is the "model basis" variable. We take into account - * equality between arguments, so if a=b, then the intersection of P( a, a ) - * and P( b, _ ) is P( a, a ). - */ - Node getIntersection(TheoryModel* m, Node n1, Node n2, bool& isGround); - }; - /** models for each UF operator */ - std::map d_uf_model_tree; - /** model generators for each UF operator */ - std::map d_uf_model_gen; - - private: - //map from terms to the models used to calculate their value - std::map< Node, bool > d_eval_uf_use_default; - std::map< Node, uf::UfModelTree > d_eval_uf_model; - void makeEvalUfModel( Node n ); - //index ordering to use for each term - std::map< Node, std::vector< int > > d_eval_term_index_order; - void makeEvalUfIndexOrder( Node n ); -//the following functions are for evaluating quantifier bodies -public: - FirstOrderModelIG(QuantifiersEngine * qe, context::Context* c, std::string name); - - FirstOrderModelIG* asFirstOrderModelIG() override { return this; } - // initialize the model - void processInitialize(bool ispre) override; - //for initialize model - void processInitializeModelForTerm(Node n) override; - /** reset evaluation */ - void resetEvaluate(); - /** evaluate functions */ - int evaluate( Node n, int& depIndex, RepSetIterator* ri ); - Node evaluateTerm( Node n, int& depIndex, RepSetIterator* ri ); -private: - //default evaluate term function - Node evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex, RepSetIterator* ri ); -};/* class FirstOrderModelIG */ - - namespace fmcheck { class Def; @@ -301,36 +214,6 @@ class FirstOrderModelFmc : public FirstOrderModel }/* CVC4::theory::quantifiers::fmcheck namespace */ -class AbsDef; - -class FirstOrderModelAbs : public FirstOrderModel -{ - public: - std::map< Node, AbsDef * > d_models; - std::map< Node, bool > d_models_valid; - std::map< TNode, unsigned > d_rep_id; - std::map< TypeNode, unsigned > d_domain; - std::map< Node, std::vector< int > > d_var_order; - std::map< Node, std::map< int, int > > d_var_index; - - private: - /** get current model value */ - void processInitializeModelForTerm(Node n) override; - void processInitializeQuantifier(Node q) override; - void collectEqVars( TNode q, TNode n, std::map< int, bool >& eq_vars ); - TNode getUsedRepresentative( TNode n ); - - public: - FirstOrderModelAbs(QuantifiersEngine * qe, context::Context* c, std::string name); - ~FirstOrderModelAbs() override; - FirstOrderModelAbs* asFirstOrderModelAbs() override { return this; } - void processInitialize(bool ispre) override; - unsigned getRepresentativeId( TNode n ); - bool isValidType( TypeNode tn ) { return d_domain.find( tn )!=d_domain.end(); } - Node getFunctionValue(Node op, const char* argPrefix ); - Node getVariable( Node q, unsigned i ); -}; - }/* CVC4::theory::quantifiers namespace */ }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/theory/quantifiers/fmf/ambqi_builder.cpp b/src/theory/quantifiers/fmf/ambqi_builder.cpp deleted file mode 100644 index f2b131f21..000000000 --- a/src/theory/quantifiers/fmf/ambqi_builder.cpp +++ /dev/null @@ -1,971 +0,0 @@ -/********************* */ -/*! \file ambqi_builder.cpp - ** \verbatim - ** Top contributors (to current version): - ** Andrew Reynolds, Tim King - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2018 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 abstract MBQI builder - **/ - -#include "theory/quantifiers/fmf/ambqi_builder.h" - -#include "base/cvc4_check.h" -#include "options/quantifiers_options.h" -#include "theory/quantifiers/instantiate.h" -#include "theory/quantifiers/term_database.h" -#include "theory/quantifiers/term_util.h" - -using namespace std; -using namespace CVC4::kind; -using namespace CVC4::context; - -namespace CVC4 { -namespace theory { -namespace quantifiers { - - -void AbsDef::construct_func( FirstOrderModelAbs * m, std::vector< TNode >& fapps, unsigned depth ) { - d_def.clear(); - Assert( !fapps.empty() ); - if( depth==fapps[0].getNumChildren() ){ - //if( fapps.size()>1 ){ - // for( unsigned i=0; i " << m->getRepresentativeId( fapps[i] ) << std::endl; - // } - //} - //get representative in model for this term - d_value = m->getRepresentativeId( fapps[0] ); - Assert( d_value!=val_none ); - }else{ - TypeNode tn = fapps[0][depth].getType(); - std::map< unsigned, std::vector< TNode > > fapp_child; - - //partition based on evaluations of fapps[1][depth]....fapps[n][depth] - for( unsigned i=0; igetRepresentativeId( fapps[i][depth] ); - Assert( r < 32 ); - fapp_child[r].push_back( fapps[i] ); - } - - //do completion - std::map< unsigned, unsigned > fapp_child_index; - unsigned def = m->d_domain[ tn ]; - unsigned minSize = fapp_child.begin()->second.size(); - unsigned minSizeIndex = fapp_child.begin()->first; - for( std::map< unsigned, std::vector< TNode > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){ - fapp_child_index[it->first] = ( 1 << it->first ); - def = def & ~( 1 << it->first ); - if( it->second.size()second.size(); - minSizeIndex = it->first; - } - } - fapp_child_index[minSizeIndex] |= def; - d_default = fapp_child_index[minSizeIndex]; - - //construct children - for( std::map< unsigned, std::vector< TNode > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){ - Trace("abs-model-debug") << "Construct " << it->first << " : " << fapp_child_index[it->first] << " : "; - const RepSet* rs = m->getRepSet(); - debugPrintUInt("abs-model-debug", - rs->getNumRepresentatives(tn), - fapp_child_index[it->first]); - Trace("abs-model-debug") << " : " << it->second.size() << " terms." << std::endl; - d_def[fapp_child_index[it->first]].construct_func( m, it->second, depth+1 ); - } - } -} - -void AbsDef::simplify( FirstOrderModelAbs * m, TNode q, TNode n, unsigned depth ) { - if( d_value==val_none && !d_def.empty() ){ - //process the default - std::map< unsigned, AbsDef >::iterator defd = d_def.find( d_default ); - Assert( defd!=d_def.end() ); - unsigned newDef = d_default; - std::vector< unsigned > to_erase; - defd->second.simplify( m, q, n, depth+1 ); - int defVal = defd->second.d_value; - bool isConstant = ( defVal!=val_none ); - //process each child - for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){ - if( it->first!=d_default ){ - it->second.simplify( m, q, n, depth+1 ); - if( it->second.d_value==defVal && it->second.d_value!=val_none ){ - newDef = newDef | it->first; - to_erase.push_back( it->first ); - }else{ - isConstant = false; - } - } - } - if( !to_erase.empty() ){ - //erase old default - int defVal = defd->second.d_value; - d_def.erase( d_default ); - //set new default - d_default = newDef; - d_def[d_default].construct_def_entry( m, q, n, defVal, depth+1 ); - //erase redundant entries - for( unsigned i=0; igetRepSet(); - unsigned dSize = rs->getNumRepresentatives(tn); - Assert( dSize<32 ); - for( std::map< unsigned, AbsDef >::const_iterator it = d_def.begin(); it != d_def.end(); ++it ){ - for( unsigned i=0; ifirst ); - if( it->first==d_default ){ - Trace(c) << "*"; - } - if( it->second.d_value!=val_none ){ - Trace(c) << " -> V[" << it->second.d_value << "]"; - } - Trace(c) << std::endl; - it->second.debugPrint( c, m, f, depth+1 ); - } - } - } -} - -bool AbsDef::addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, TNode q, std::vector< Node >& terms, int& inst, unsigned depth ) { - if( inst==0 || !options::fmfOneInstPerRound() ){ - if( d_value==1 ){ - //instantiations are all true : ignore this - return true; - }else{ - if( depth==q[0].getNumChildren() ){ - if (qe->getInstantiate()->addInstantiation(q, terms, true)) - { - Trace("ambqi-inst-debug") << "-> Added instantiation." << std::endl; - inst++; - return true; - }else{ - Trace("ambqi-inst-debug") << "-> Failed to add instantiation." << std::endl; - //we are incomplete - return false; - } - }else{ - bool osuccess = true; - TypeNode tn = m->getVariable( q, depth ).getType(); - for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){ - //get witness term - unsigned index = 0; - bool success; - do { - success = false; - index = getId( it->first, index ); - if( index<32 ){ - const RepSet* rs = m->getRepSet(); - Assert(index < rs->getNumRepresentatives(tn)); - terms[m->d_var_order[q][depth]] = - rs->getRepresentative(tn, index); - if( !it->second.addInstantiations( m, qe, q, terms, inst, depth+1 ) && inst==0 ){ - //if we are incomplete, and have not yet added an instantiation, keep trying - index++; - Trace("ambqi-inst-debug") << "At depth " << depth << ", failed branch, no instantiations and incomplete, increment index : " << index << std::endl; - }else{ - success = true; - } - } - }while( !qe->inConflict() && !success && index<32 ); - //mark if we are incomplete - osuccess = osuccess && success; - } - return osuccess; - } - } - }else{ - return true; - } -} - -void AbsDef::construct_entry( std::vector< unsigned >& entry, std::vector< bool >& entry_def, int v, unsigned depth ) { - if( depth==entry.size() ){ - d_value = v; - }else{ - d_def[entry[depth]].construct_entry( entry, entry_def, v, depth+1 ); - if( entry_def[depth] ){ - d_default = entry[depth]; - } - } -} - -void AbsDef::get_defs( unsigned u, std::vector< AbsDef * >& defs ) { - for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){ - if( ( u & it->first )!=0 ){ - Assert( (u & it->first)==u ); - defs.push_back( &it->second ); - } - } -} - -void AbsDef::construct_normalize( FirstOrderModelAbs * m, TNode q, std::vector< AbsDef * >& defs, unsigned depth ) { - if( depth==q[0].getNumChildren() ){ - Assert( defs.size()==1 ); - d_value = defs[0]->d_value; - }else{ - TypeNode tn = m->getVariable( q, depth ).getType(); - unsigned def = m->d_domain[tn]; - for( unsigned i=0; i::iterator itd = defs[i]->d_def.begin(); itd != defs[i]->d_def.end(); ++itd ){ - if( isSimple( itd->first ) && ( def & itd->first )!=0 ){ - def &= ~( itd->first ); - //process this value - std::vector< AbsDef * > cdefs; - for( unsigned j=0; jget_defs( itd->first, cdefs ); - } - d_def[itd->first].construct_normalize( m, q, cdefs, depth+1 ); - if( def==0 ){ - d_default = itd->first; - break; - } - } - } - if( def==0 ){ - break; - } - } - if( def!=0 ){ - d_default = def; - //process the default - std::vector< AbsDef * > cdefs; - for( unsigned j=0; jget_defs( d_default, cdefs ); - } - d_def[d_default].construct_normalize( m, q, cdefs, depth+1 ); - } - } -} - -void AbsDef::construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth ) { - d_value = v; - if( depthgetVariable( q, depth ).getType(); - unsigned dom = m->d_domain[tn] ; - d_def[dom].construct_def_entry( m, q, n, v, depth+1 ); - d_default = dom; - } -} - -void AbsDef::apply_ucompose( FirstOrderModelAbs * m, TNode q, - std::vector< unsigned >& entry, std::vector< bool >& entry_def, - std::vector< int >& terms, std::map< unsigned, int >& vchildren, - AbsDef * a, unsigned depth ) { - if( depth==terms.size() ){ - if( Trace.isOn("ambqi-check-debug2") ){ - Trace("ambqi-check-debug2") << "Add entry ( "; - const RepSet* rs = m->getRepSet(); - for( unsigned i=0; igetNumRepresentatives(m->getVariable(q, i).getType()); - debugPrintUInt( "ambqi-check-debug2", dSize, entry[i] ); - Trace("ambqi-check-debug2") << " "; - } - Trace("ambqi-check-debug2") << ")" << std::endl; - } - a->construct_entry( entry, entry_def, d_value ); - }else{ - unsigned id; - if( terms[depth]==val_none ){ - //a variable - std::map< unsigned, int >::iterator itv = vchildren.find( depth ); - Assert( itv!=vchildren.end() ); - unsigned prev_v = entry[itv->second]; - bool prev_vd = entry_def[itv->second]; - for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){ - entry[itv->second] = it->first & prev_v; - entry_def[itv->second] = ( it->first==d_default ) && prev_vd; - if( entry[itv->second]!=0 ){ - it->second.apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 ); - } - } - entry[itv->second] = prev_v; - entry_def[itv->second] = prev_vd; - }else{ - id = (unsigned)terms[depth]; - Assert( id<32 ); - unsigned fid = 1 << id; - std::map< unsigned, AbsDef >::iterator it = d_def.find( fid ); - if( it!=d_def.end() ){ - it->second.apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 ); - }else{ - d_def[d_default].apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 ); - } - } - } -} - -void AbsDef::construct_var_eq( FirstOrderModelAbs * m, TNode q, unsigned v1, unsigned v2, int curr, int currv, unsigned depth ) { - if( depth==q[0].getNumChildren() ){ - Assert( currv!=val_none ); - d_value = currv; - }else{ - TypeNode tn = m->getVariable( q, depth ).getType(); - unsigned dom = m->d_domain[tn]; - int vindex = depth==v1 ? 0 : ( depth==v2 ? 1 : val_none ); - if( vindex==val_none ){ - d_def[dom].construct_var_eq( m, q, v1, v2, curr, currv, depth+1 ); - d_default = dom; - }else{ - Assert( currv==val_none ); - if( curr==val_none ){ - unsigned numReps = m->getRepSet()->getNumRepresentatives(tn); - Assert( numReps < 32 ); - for( unsigned i=0; igetVariable( q, depth ).getType(); - if( v==depth ){ - const unsigned numReps = m->getRepSet()->getNumRepresentatives(tn); - CVC4_CHECK(numReps > 0 && numReps < 32); - for( unsigned i=0; id_domain[tn]; - d_def[dom].construct_var( m, q, v, currv, depth+1 ); - d_default = dom; - } - } -} - -void AbsDef::construct_compose( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f, - std::map< unsigned, AbsDef * >& children, - std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren, - std::vector< unsigned >& entry, std::vector< bool >& entry_def ) { - const RepSet* rs = m->getRepSet(); - if( n.getKind()==OR || n.getKind()==AND ){ - // short circuiting - for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){ - if( ( it->second->d_value==0 && n.getKind()==AND ) || - ( it->second->d_value==1 && n.getKind()==OR ) ){ - //std::cout << "Short circuit " << it->second->d_value << " " << entry.size() << "/" << q[0].getNumChildren() << std::endl; - unsigned count = q[0].getNumChildren() - entry.size(); - for( unsigned i=0; id_domain[m->getVariable( q, entry.size() ).getType()] ); - entry_def.push_back( true ); - } - construct_entry( entry, entry_def, it->second->d_value ); - for( unsigned i=0; i values; - values.resize( n.getNumChildren(), val_none ); - for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){ - values[it->first] = it->second->d_value; - } - for( std::map< unsigned, int >::iterator it = bchildren.begin(); it != bchildren.end(); ++it ){ - values[it->first] = it->second; - } - //look up value(s) - f->apply_ucompose( m, q, entry, entry_def, values, vchildren, this ); - }else{ - bool incomplete = false; - //we are composing with an interpreted function - std::vector< TNode > values; - values.resize( n.getNumChildren(), TNode::null() ); - for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){ - Trace("ambqi-check-debug2") << "composite : " << it->first << " : " << it->second->d_value; - if( it->second->d_value>=0 ){ - if (it->second->d_value - >= (int)rs->getNumRepresentatives(n[it->first].getType())) - { - std::cout << it->second->d_value << " " << n[it->first] << " " - << n[it->first].getType() << " " - << rs->getNumRepresentatives(n[it->first].getType()) - << std::endl; - } - Assert(it->second->d_value - < (int)rs->getNumRepresentatives(n[it->first].getType())); - values[it->first] = rs->getRepresentative(n[it->first].getType(), - it->second->d_value); - }else{ - incomplete = true; - } - Trace("ambqi-check-debug2") << " ->> " << values[it->first] << std::endl; - } - for( std::map< unsigned, int >::iterator it = bchildren.begin(); it != bchildren.end(); ++it ){ - Trace("ambqi-check-debug2") << " basic : " << it->first << " : " << it->second; - if( it->second>=0 ){ - Assert(it->second - < (int)rs->getNumRepresentatives(n[it->first].getType())); - values[it->first] = - rs->getRepresentative(n[it->first].getType(), it->second); - }else{ - incomplete = true; - } - Trace("ambqi-check-debug2") << " ->> " << values[it->first] << std::endl; - } - Assert( vchildren.empty() ); - if( incomplete ){ - Trace("ambqi-check-debug2") << "Construct incomplete entry." << std::endl; - - //if a child is unknown, we must return unknown - construct_entry( entry, entry_def, val_unk ); - }else{ - if( Trace.isOn("ambqi-check-debug2") ){ - for( unsigned i=0; imkNode( n.getKind(), values ); - vv = Rewriter::rewrite( vv ); - int v = m->getRepresentativeId( vv ); - construct_entry( entry, entry_def, v ); - } - } - }else{ - //take product of arguments - TypeNode tn = m->getVariable( q, entry.size() ).getType(); - Assert( m->isValidType( tn ) ); - unsigned def = m->d_domain[tn]; - if( Trace.isOn("ambqi-check-debug2") ){ - for( unsigned i=0; i::iterator it = children.begin(); it != children.end(); ++it ){ - Assert( it->second!=NULL ); - //process each child - for( std::map< unsigned, AbsDef >::iterator itd = it->second->d_def.begin(); itd != it->second->d_def.end(); ++itd ){ - if( itd->first!=it->second->d_default && ( def & itd->first )!=0 ){ - def &= ~( itd->first ); - //process this value - std::map< unsigned, AbsDef * > cchildren; - for( std::map< unsigned, AbsDef * >::iterator it2 = children.begin(); it2 != children.end(); ++it2 ){ - Assert( it2->second!=NULL ); - std::map< unsigned, AbsDef >::iterator itdf = it2->second->d_def.find( itd->first ); - if( itdf!=it2->second->d_def.end() ){ - cchildren[it2->first] = &itdf->second; - }else{ - Assert( it2->second->getDefault()!=NULL ); - cchildren[it2->first] = it2->second->getDefault(); - } - } - if( Trace.isOn("ambqi-check-debug2") ){ - for( unsigned i=0; igetNumRepresentatives(tn), - itd->first); - Trace("ambqi-check-debug2") << " " << children.size() << " " << cchildren.size() << std::endl; - } - entry.push_back( itd->first ); - entry_def.push_back( def==0 ); - construct_compose( m, q, n, f, cchildren, bchildren, vchildren, entry, entry_def ); - entry_def.pop_back(); - entry.pop_back(); - if( def==0 ){ - break; - } - } - } - if( def==0 ){ - break; - } - } - if( def!=0 ){ - if( Trace.isOn("ambqi-check-debug2") ){ - for( unsigned i=0; i cdchildren; - for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){ - Assert( it->second->getDefault()!=NULL ); - cdchildren[it->first] = it->second->getDefault(); - } - if( Trace.isOn("ambqi-check-debug2") ){ - for( unsigned i=0; igetNumRepresentatives(tn), def); - Trace("ambqi-check-debug2") << " " << children.size() << " " << cdchildren.size() << std::endl; - } - entry.push_back( def ); - entry_def.push_back( true ); - construct_compose( m, q, n, f, cdchildren, bchildren, vchildren, entry, entry_def ); - entry_def.pop_back(); - entry.pop_back(); - } - } -} - -bool AbsDef::construct( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f, - std::map< unsigned, AbsDef * >& children, - std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren, - int varChCount ) { - if( Trace.isOn("ambqi-check-debug3") ){ - for( unsigned i=0; i::iterator it = bchildren.begin(); it !=bchildren.end(); ++it ){ - if( ( it->second==0 && n.getKind()==AND ) || - ( it->second==1 && n.getKind()==OR ) ){ - construct_def_entry( m, q, q[0], it->second ); - return true; - } - } - } - Trace("ambqi-check-debug2") << "Construct compose..." << std::endl; - std::vector< unsigned > entry; - std::vector< bool > entry_def; - if( f && varChCount>0 ){ - AbsDef unorm; - unorm.construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def ); - //normalize - std::vector< AbsDef* > defs; - defs.push_back( &unorm ); - construct_normalize( m, q, defs ); - }else{ - construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def ); - } - Assert( is_normalized() ); - return true; - }else if( varChCount==1 && ( n.getKind()==EQUAL && !n[0].getType().isBoolean() ) ){ - Trace("ambqi-check-debug2") << "Expand variable child..." << std::endl; - //expand the variable based on its finite domain - AbsDef a; - a.construct_var( m, q, vchildren.begin()->second, val_none ); - children[vchildren.begin()->first] = &a; - vchildren.clear(); - std::vector< unsigned > entry; - std::vector< bool > entry_def; - Trace("ambqi-check-debug2") << "Construct compose with variable..." << std::endl; - construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def ); - return true; - }else if( varChCount==2 && ( n.getKind()==EQUAL && !n[0].getType().isBoolean() ) ){ - Trace("ambqi-check-debug2") << "Construct variable equality..." << std::endl; - //efficient expansion of the equality - construct_var_eq( m, q, vchildren[0], vchildren[1], val_none, val_none ); - return true; - }else{ - return false; - } -} - -void AbsDef::negate() { - for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){ - it->second.negate(); - } - if( d_value==0 ){ - d_value = 1; - }else if( d_value==1 ){ - d_value = 0; - } -} - -Node AbsDef::getFunctionValue( FirstOrderModelAbs * m, TNode op, std::vector< Node >& vars, unsigned depth ) { - const RepSet* rs = m->getRepSet(); - if( depth==vars.size() ){ - TypeNode tn = op.getType(); - if( tn.getNumChildren()>0 ){ - tn = tn[tn.getNumChildren() - 1]; - } - if( d_value>=0 ){ - Assert(d_value < (int)rs->getNumRepresentatives(tn)); - if( tn.isBoolean() ){ - return NodeManager::currentNM()->mkConst( d_value==1 ); - }else{ - return rs->getRepresentative(tn, d_value); - } - }else{ - return Node::null(); - } - }else{ - TypeNode tn = vars[depth].getType(); - Node curr; - curr = d_def[d_default].getFunctionValue( m, op, vars, depth+1 ); - for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){ - if( it->first!=d_default ){ - unsigned id = getId( it->first ); - Assert(id < rs->getNumRepresentatives(tn)); - TNode n = rs->getRepresentative(tn, id); - Node fv = it->second.getFunctionValue( m, op, vars, depth+1 ); - if( !curr.isNull() && !fv.isNull() ){ - curr = NodeManager::currentNM()->mkNode( ITE, vars[depth].eqNode( n ), fv, curr ); - }else{ - curr = Node::null(); - } - } - } - return curr; - } -} - -bool AbsDef::isSimple( unsigned n ) { - return (n & (n - 1))==0; -} - -unsigned AbsDef::getId( unsigned n, unsigned start, unsigned end ) { - Assert( n!=0 ); - while( (n & ( 1 << start )) == 0 ){ - start++; - if( start==end ){ - return start; - } - } - return start; -} - -Node AbsDef::evaluate( FirstOrderModelAbs * m, TypeNode retTyp, std::vector< Node >& args ) { - std::vector< unsigned > iargs; - for( unsigned i=0; igetRepresentativeId( args[i] ); - iargs.push_back( v ); - } - return evaluate( m, retTyp, iargs, 0 ); -} - -Node AbsDef::evaluate( FirstOrderModelAbs * m, TypeNode retTyp, std::vector< unsigned >& iargs, unsigned depth ) { - if( d_value!=val_none ){ - if( d_value==val_unk ){ - return Node::null(); - }else{ - const RepSet* rs = m->getRepSet(); - Assert(d_value >= 0 && d_value < (int)rs->getNumRepresentatives(retTyp)); - return rs->getRepresentative(retTyp, d_value); - } - }else{ - std::map< unsigned, AbsDef >::iterator it = d_def.find( iargs[depth] ); - if( it==d_def.end() ){ - return d_def[d_default].evaluate( m, retTyp, iargs, depth+1 ); - }else{ - return it->second.evaluate( m, retTyp, iargs, depth+1 ); - } - } -} - -bool AbsDef::is_normalized() { - for( std::map< unsigned, AbsDef >::iterator it1 = d_def.begin(); it1 != d_def.end(); ++it1 ){ - if( !it1->second.is_normalized() ){ - return false; - } - for( std::map< unsigned, AbsDef >::iterator it2 = d_def.begin(); it2 != d_def.end(); ++it2 ){ - if( it1->first!=it2->first && (( it1->first & it2->first )!=0) ){ - return false; - } - } - } - return true; -} - -AbsMbqiBuilder::AbsMbqiBuilder( context::Context* c, QuantifiersEngine* qe ) : -QModelBuilder( c, qe ){ - d_true = NodeManager::currentNM()->mkConst( true ); - d_false = NodeManager::currentNM()->mkConst( false ); -} - - -//------------------------model construction---------------------------- - -bool AbsMbqiBuilder::processBuildModel(TheoryModel* m) { - if (!m->areFunctionValuesEnabled()) - { - // nothing to do if no functions - return true; - } - Trace("ambqi-debug") << "process build model " << std::endl; - FirstOrderModel* f = (FirstOrderModel*)m; - FirstOrderModelAbs* fm = f->asFirstOrderModelAbs(); - RepSet* rs = m->getRepSetPtr(); - fm->initialize(); - //process representatives - fm->d_rep_id.clear(); - fm->d_domain.clear(); - - //initialize boolean sort - TypeNode b = d_true.getType(); - rs->d_type_reps[b].clear(); - rs->d_type_reps[b].push_back(d_false); - rs->d_type_reps[b].push_back(d_true); - fm->d_rep_id[d_false] = 0; - fm->d_rep_id[d_true] = 1; - - //initialize unintpreted sorts - Trace("ambqi-model") << std::endl << "Making representatives..." << std::endl; - for (std::map >::iterator it = - rs->d_type_reps.begin(); - it != rs->d_type_reps.end(); - ++it) - { - if( it->first.isSort() ){ - Assert( !it->second.empty() ); - //set the domain - fm->d_domain[it->first] = 0; - Trace("ambqi-model") << "Representatives for " << it->first << " : " << std::endl; - for( unsigned i=0; isecond.size(); i++ ){ - if( i<32 ){ - fm->d_domain[it->first] |= ( 1 << i ); - } - Trace("ambqi-model") << i << " : " << it->second[i] << std::endl; - fm->d_rep_id[it->second[i]] = i; - } - if( it->second.size()>=32 ){ - fm->d_domain.erase( it->first ); - } - } - } - - Trace("ambqi-model") << std::endl << "Making function definitions..." << std::endl; - //construct the models for functions - for( std::map::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) { - Node f = it->first; - Trace("ambqi-model-debug") << "Building Model for " << f << std::endl; - //reset the model - it->second->clear(); - //get all (non-redundant) f-applications - std::vector< TNode > fapps; - Trace("ambqi-model-debug") << "Initial terms: " << std::endl; - std::map< Node, std::vector< Node > >::iterator itut = fm->d_uf_terms.find( f ); - if( itut!=fm->d_uf_terms.end() ){ - for( size_t i=0; isecond.size(); i++ ){ - Node n = itut->second[i]; - // only consider unique up to congruence (in model equality engine)? - Trace("ambqi-model-debug") << " " << n << " -> " << fm->getRepresentativeId( n ) << std::endl; - fapps.push_back( n ); - } - } - if( fapps.empty() ){ - //choose arbitrary value - Node mbt = fm->getModelBasisOpTerm(f); - Trace("ambqi-model-debug") << "Initial terms empty, add " << mbt << std::endl; - fapps.push_back( mbt ); - } - bool fValid = true; - for( unsigned i=0; id_domain.find( fapps[0][i].getType() )==fm->d_domain.end() ){ - Trace("ambqi-model") << "Interpretation of " << f << " is not valid."; - Trace("ambqi-model") << " (domain for " << fapps[0][i].getType() << " is too large)." << std::endl; - fValid = false; - break; - } - } - fm->d_models_valid[f] = fValid; - if( fValid ){ - //construct the ambqi model - it->second->construct_func( fm, fapps ); - Trace("ambqi-model-debug") << "Interpretation of " << f << " : " << std::endl; - it->second->debugPrint("ambqi-model-debug", fm, fapps[0] ); - Trace("ambqi-model-debug") << "Simplifying " << f << "..." << std::endl; - it->second->simplify( fm, TNode::null(), fapps[0] ); - Trace("ambqi-model") << "(Simplified) interpretation of " << f << " : " << std::endl; - it->second->debugPrint("ambqi-model", fm, fapps[0] ); - -/* - if( Debug.isOn("ambqi-model-debug") ){ - for( size_t i=0; id_uf_terms[f].size(); i++ ){ - Node e = it->second->evaluate_n( fm, fm->d_uf_terms[f][i] ); - Debug("ambqi-model-debug") << fm->d_uf_terms[f][i] << " evaluates to " << e << std::endl; - Assert( fm->areEqual( e, fm->d_uf_terms[f][i] ) ); - } - } -*/ - } - } - Trace("ambqi-model") << "Construct model representation..." << std::endl; - //make function values - for( std::map::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) { - if( it->first.getType().getNumChildren()>1 ){ - Trace("ambqi-model") << "Construct for " << it->first << "..." << std::endl; - Node f_def = fm->getFunctionValue( it->first, "$x" ); - m->assignFunctionDefinition( it->first, f_def ); - } - } - Assert( d_addedLemmas==0 ); - return TheoryEngineModelBuilder::processBuildModel( m ); -} - - -//--------------------model checking--------------------------------------- - -//do exhaustive instantiation -int AbsMbqiBuilder::doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ) { - Trace("ambqi-check") << "Exhaustive instantiation " << q << " " << effort << std::endl; - if (effort==0) { - FirstOrderModelAbs * fma = fm->asFirstOrderModelAbs(); - bool quantValid = true; - for( unsigned i=0; iisValidType( q[0][i].getType() ) ){ - quantValid = false; - Trace("ambqi-inst") << "Interpretation of " << q << " is not valid because of type " << q[0][i].getType() << std::endl; - break; - } - } - if( quantValid ){ - Trace("ambqi-check") << "Compute interpretation..." << std::endl; - AbsDef ad; - doCheck( fma, q, ad, q[1] ); - //now process entries - Trace("ambqi-inst-debug") << "...Current : " << d_addedLemmas << std::endl; - Trace("ambqi-inst") << "Interpretation of " << q << " is : " << std::endl; - ad.debugPrint( "ambqi-inst", fma, q[0] ); - Trace("ambqi-inst") << std::endl; - Trace("ambqi-check") << "Add instantiations..." << std::endl; - int lem = 0; - quantValid = ad.addInstantiations( fma, d_qe, q, lem ); - Trace("ambqi-inst") << "...Added " << lem << " lemmas." << std::endl; - if( lem>0 ){ - //if we were incomplete but added at least one lemma, we are ok - quantValid = true; - } - d_addedLemmas += lem; - Trace("ambqi-inst-debug") << "...Total : " << d_addedLemmas << std::endl; - } - return quantValid ? 1 : 0; - }else{ - return 1; - } -} - -bool AbsMbqiBuilder::doCheck( FirstOrderModelAbs * m, TNode q, AbsDef & ad, TNode n ) { - Assert( n.getKind()!=FORALL ); - if( n.getKind()==NOT && n[0].getKind()!=FORALL ){ - doCheck( m, q, ad, n[0] ); - ad.negate(); - return true; - }else{ - std::map< unsigned, AbsDef > children; - std::map< unsigned, int > bchildren; - std::map< unsigned, int > vchildren; - int varChCount = 0; - for( unsigned i=0; id_var_index[q][ m->getVariableId( q, n[i] ) ]; - //vchildren[i] = m->getVariableId( q, n[i] ); - }else if( m->hasTerm( n[i] ) ){ - bchildren[i] = m->getRepresentativeId( n[i] ); - }else{ - if( !doCheck( m, q, children[i], n[i] ) ){ - bchildren[i] = AbsDef::val_unk; - children.erase( i ); - } - } - } - //convert to pointers - std::map< unsigned, AbsDef * > pchildren; - for( std::map< unsigned, AbsDef >::iterator it = children.begin(); it != children.end(); ++it ){ - pchildren[it->first] = &it->second; - } - //construct the interpretation - Trace("ambqi-check-debug") << "Compute Interpretation of " << n << " " << n.getKind() << std::endl; - if( n.getKind() == APPLY_UF || n.getKind() == VARIABLE || n.getKind() == SKOLEM ){ - Node op; - if( n.getKind() == APPLY_UF ){ - op = n.getOperator(); - }else{ - op = n; - } - //uninterpreted compose - if( m->d_models_valid[op] ){ - ad.construct( m, q, n, m->d_models[op], pchildren, bchildren, vchildren, varChCount ); - }else{ - Trace("ambqi-check-debug") << "** Cannot produce interpretation for " << n << " (no function model)" << std::endl; - return false; - } - }else if( !ad.construct( m, q, n, NULL, pchildren, bchildren, vchildren, varChCount ) ){ - Trace("ambqi-check-debug") << "** Cannot produce interpretation for " << n << " (variables are children of interpreted symbol)" << std::endl; - return false; - } - Trace("ambqi-check-try") << "Interpretation for " << n << " is : " << std::endl; - ad.debugPrint("ambqi-check-try", m, q[0] ); - ad.simplify( m, q, q[0] ); - Trace("ambqi-check-debug") << "(Simplified) Interpretation for " << n << " is : " << std::endl; - ad.debugPrint("ambqi-check-debug", m, q[0] ); - Trace("ambqi-check-debug") << std::endl; - return true; - } -} - -}/* namespace CVC4::theory::quantifiers */ -}/* namespace CVC4::theory */ -}/* namespace CVC4 */ diff --git a/src/theory/quantifiers/fmf/ambqi_builder.h b/src/theory/quantifiers/fmf/ambqi_builder.h deleted file mode 100644 index b052e0985..000000000 --- a/src/theory/quantifiers/fmf/ambqi_builder.h +++ /dev/null @@ -1,105 +0,0 @@ -/********************* */ -/*! \file ambqi_builder.h - ** \verbatim - ** Top contributors (to current version): - ** Andrew Reynolds, Tim King - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2018 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 Abstract MBQI model builder class - **/ - -#include "cvc4_private.h" - -#ifndef ABSTRACT_MBQI_BUILDER -#define ABSTRACT_MBQI_BUILDER - -#include "theory/quantifiers/fmf/model_builder.h" -#include "theory/quantifiers/first_order_model.h" - -namespace CVC4 { -namespace theory { -namespace quantifiers { - -class FirstOrderModelAbs; - -//representiation of function and term interpretations -class AbsDef -{ -private: - bool addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, TNode q, std::vector< Node >& terms, int& inst, unsigned depth ); - void construct_compose( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f, - std::map< unsigned, AbsDef * >& children, - std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren, - std::vector< unsigned >& entry, std::vector< bool >& entry_def ); - void construct_entry( std::vector< unsigned >& entry, std::vector< bool >& entry_def, int v, unsigned depth = 0 ); - void construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth = 0 ); - void apply_ucompose( FirstOrderModelAbs * m, TNode q, - std::vector< unsigned >& entry, std::vector< bool >& entry_def, std::vector< int >& terms, - std::map< unsigned, int >& vchildren, AbsDef * a, unsigned depth = 0 ); - void construct_var_eq( FirstOrderModelAbs * m, TNode q, unsigned v1, unsigned v2, int curr, int currv, unsigned depth = 0 ); - void construct_var( FirstOrderModelAbs * m, TNode q, unsigned v, int currv, unsigned depth = 0 ); - void get_defs( unsigned u, std::vector< AbsDef * >& defs ); - void construct_normalize( FirstOrderModelAbs * m, TNode q, std::vector< AbsDef * >& defs, unsigned depth = 0 ); -public: - enum { - val_none = -1, - val_unk = -2, - }; - AbsDef() : d_default( 0 ), d_value( -1 ){} - std::map< unsigned, AbsDef > d_def; - unsigned d_default; - int d_value; - - void clear() { d_def.clear(); d_default = 0; d_value = -1; } - AbsDef * getDefault() { return &d_def[d_default]; } - void construct_func( FirstOrderModelAbs * m, std::vector< TNode >& fapps, unsigned depth = 0 ); - void debugPrintUInt( const char * c, unsigned dSize, unsigned u ) const; - void debugPrint( const char * c, FirstOrderModelAbs * m, TNode f, unsigned depth = 0 ) const; - void simplify( FirstOrderModelAbs * m, TNode q, TNode n, unsigned depth = 0 ); - int addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, Node q, int& inst ){ - std::vector< Node > terms; - terms.resize( q[0].getNumChildren() ); - return addInstantiations( m, qe, q, terms, inst, 0 ); - } - bool construct( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f, - std::map< unsigned, AbsDef * >& children, - std::map< unsigned, int >& bchildren, - std::map< unsigned, int >& vchildren, - int varChCount ); - void negate(); - Node getFunctionValue( FirstOrderModelAbs * m, TNode op, std::vector< Node >& vars, unsigned depth = 0 ); - static bool isSimple( unsigned n ); - static unsigned getId( unsigned n, unsigned start=0, unsigned end=32 ); - Node evaluate( FirstOrderModelAbs * m, TypeNode retType, std::vector< Node >& args ); - Node evaluate( FirstOrderModelAbs * m, TypeNode retType, std::vector< unsigned >& iargs, unsigned depth = 0 ); - //for debugging - bool is_normalized(); -}; - -class AbsMbqiBuilder : public QModelBuilder -{ - friend class AbsDef; -private: - Node d_true; - Node d_false; - bool doCheck( FirstOrderModelAbs * m, TNode q, AbsDef & ad, TNode n ); -public: - AbsMbqiBuilder( context::Context* c, QuantifiersEngine* qe ); - - //process build model - bool processBuildModel(TheoryModel* m) override; - //do exhaustive instantiation - int doExhaustiveInstantiation(FirstOrderModel* fm, - Node q, - int effort) override; -}; - -} -} -} - -#endif diff --git a/src/theory/quantifiers/fmf/model_builder.cpp b/src/theory/quantifiers/fmf/model_builder.cpp index c03fc7a32..8ef30fc4d 100644 --- a/src/theory/quantifiers/fmf/model_builder.cpp +++ b/src/theory/quantifiers/fmf/model_builder.cpp @@ -143,687 +143,3 @@ void QModelBuilder::debugModel( TheoryModel* m ){ } } } - -bool TermArgBasisTrie::addTerm(FirstOrderModel* fm, Node n, unsigned argIndex) -{ - if (argIndex < n.getNumChildren()) - { - Node r; - if( n[ argIndex ].getAttribute(ModelBasisAttribute()) ){ - r = n[ argIndex ]; - }else{ - r = fm->getRepresentative( n[ argIndex ] ); - } - std::map< Node, TermArgBasisTrie >::iterator it = d_data.find( r ); - if( it==d_data.end() ){ - d_data[r].addTerm(fm, n, argIndex + 1); - return true; - }else{ - return it->second.addTerm(fm, n, argIndex + 1); - } - }else{ - return false; - } -} - -void QModelBuilderIG::UfModelPreferenceData::setValuePreference(Node q, - Node r, - bool isPro) -{ - if (std::find(d_values.begin(), d_values.end(), r) == d_values.end()) - { - d_values.push_back(r); - } - int index = isPro ? 0 : 1; - if (std::find( - d_value_pro_con[index][r].begin(), d_value_pro_con[index][r].end(), q) - == d_value_pro_con[index][r].end()) - { - d_value_pro_con[index][r].push_back(q); - } -} - -Node QModelBuilderIG::UfModelPreferenceData::getBestDefaultValue( - Node defaultTerm, TheoryModel* m) -{ - Node defaultVal; - double maxScore = -1; - for (size_t i = 0, size = d_values.size(); i < size; i++) - { - Node v = d_values[i]; - double score = (1.0 + static_cast(d_value_pro_con[0][v].size())) - / (1.0 + static_cast(d_value_pro_con[1][v].size())); - Debug("fmf-model-cons-debug") << " - score( "; - Debug("fmf-model-cons-debug") << m->getRepresentative(v); - Debug("fmf-model-cons-debug") << " ) = " << score << std::endl; - if (score > maxScore) - { - defaultVal = v; - maxScore = score; - } - } - if (maxScore < 1.0) - { - // consider finding another value, if possible - Debug("fmf-model-cons-debug") - << "Poor choice for default value, score = " << maxScore << std::endl; - TypeNode tn = defaultTerm.getType(); - Node newDefaultVal = m->getRepSet()->getDomainValue(tn, d_values); - if (!newDefaultVal.isNull()) - { - defaultVal = newDefaultVal; - Debug("fmf-model-cons-debug") << "-> Change default value to "; - Debug("fmf-model-cons-debug") << m->getRepresentative(defaultVal); - Debug("fmf-model-cons-debug") << std::endl; - } - else - { - Debug("fmf-model-cons-debug") - << "-> Could not find arbitrary element of type " - << tn[tn.getNumChildren() - 1] << std::endl; - Debug("fmf-model-cons-debug") << " Excluding: " << d_values; - Debug("fmf-model-cons-debug") << std::endl; - } - } - // get the default term (this term must be defined non-ground in model) - Debug("fmf-model-cons-debug") << " Choose "; - Debug("fmf-model-cons-debug") << m->getRepresentative(defaultVal); - Debug("fmf-model-cons-debug") - << " as default value (" << defaultTerm << ")" << std::endl; - Debug("fmf-model-cons-debug") - << " # quantifiers pro = " << d_value_pro_con[0][defaultVal].size() - << std::endl; - Debug("fmf-model-cons-debug") - << " # quantifiers con = " << d_value_pro_con[1][defaultVal].size() - << std::endl; - return defaultVal; -} - -QModelBuilderIG::QModelBuilderIG(context::Context* c, QuantifiersEngine* qe) - : QModelBuilder(c, qe), - d_didInstGen(false), - d_numQuantSat(0), - d_numQuantInstGen(0), - d_numQuantNoInstGen(0), - d_numQuantNoSelForm(0), - d_instGenMatches(0) {} - -/* -Node QModelBuilderIG::getCurrentUfModelValue( FirstOrderModel* fm, Node n, std::vector< Node > & args, bool partial ) { - return n; -} -*/ - -bool QModelBuilderIG::processBuildModel( TheoryModel* m ) { - if (!m->areFunctionValuesEnabled()) - { - // nothing to do if no functions - return true; - } - FirstOrderModel* f = (FirstOrderModel*)m; - FirstOrderModelIG* fm = f->asFirstOrderModelIG(); - Trace("model-engine-debug") << "Process build model " << optUseModel() << std::endl; - d_didInstGen = false; - //reset the internal information - reset( fm ); - //only construct first order model if optUseModel() is true - if( optUseModel() ){ - Trace("model-engine-debug") << "Initializing " << fm->getNumAssertedQuantifiers() << " quantifiers..." << std::endl; - //check if any quantifiers are un-initialized - for( unsigned i=0; igetNumAssertedQuantifiers(); i++ ){ - Node q = fm->getAssertedQuantifier( i ); - if( d_qe->getModel()->isQuantifierActive( q ) ){ - int lems = initializeQuantifier(q, q, f); - d_statistics.d_init_inst_gen_lemmas += lems; - d_addedLemmas += lems; - if( d_qe->inConflict() ){ - break; - } - } - } - if( d_addedLemmas>0 ){ - Trace("model-engine") << "Initialize, Added Lemmas = " << d_addedLemmas << std::endl; - return false; - }else{ - Assert( !d_qe->inConflict() ); - //initialize model - fm->initialize(); - //analyze the functions - Trace("model-engine-debug") << "Analyzing model..." << std::endl; - analyzeModel( fm ); - //analyze the quantifiers - Trace("model-engine-debug") << "Analyzing quantifiers..." << std::endl; - d_uf_prefs.clear(); - for( unsigned i=0; igetNumAssertedQuantifiers(); i++ ){ - Node q = fm->getAssertedQuantifier( i ); - analyzeQuantifier( fm, q ); - } - - //if applicable, find exceptions to model via inst-gen - if( options::fmfInstGen() ){ - d_didInstGen = true; - d_instGenMatches = 0; - d_numQuantSat = 0; - d_numQuantInstGen = 0; - d_numQuantNoInstGen = 0; - d_numQuantNoSelForm = 0; - //now, see if we know that any exceptions via InstGen exist - Trace("model-engine-debug") << "Perform InstGen techniques for quantifiers..." << std::endl; - for( unsigned i=0; igetNumAssertedQuantifiers(); i++ ){ - Node f = fm->getAssertedQuantifier( i ); - if( d_qe->getModel()->isQuantifierActive( f ) ){ - int lems = doInstGen( fm, f ); - d_statistics.d_inst_gen_lemmas += lems; - d_addedLemmas += lems; - //temporary - if( lems>0 ){ - d_numQuantInstGen++; - }else if( hasInstGen( f ) ){ - d_numQuantNoInstGen++; - }else{ - d_numQuantNoSelForm++; - } - if( d_qe->inConflict() || ( options::fmfInstGenOneQuantPerRound() && lems>0 ) ){ - break; - } - }else{ - d_numQuantSat++; - } - } - Trace("model-engine-debug") << "Quantifiers sat/ig/n-ig/null " << d_numQuantSat << " / " << d_numQuantInstGen << " / "; - Trace("model-engine-debug") << d_numQuantNoInstGen << " / " << d_numQuantNoSelForm << std::endl; - Trace("model-engine-debug") << "Inst-gen # matches examined = " << d_instGenMatches << std::endl; - if( Trace.isOn("model-engine") ){ - if( d_addedLemmas>0 ){ - Trace("model-engine") << "InstGen, added lemmas = " << d_addedLemmas << std::endl; - }else{ - Trace("model-engine") << "No InstGen lemmas..." << std::endl; - } - } - } - //construct the model if necessary - if( d_addedLemmas==0 ){ - //if no immediate exceptions, build the model - // this model will be an approximation that will need to be tested via exhaustive instantiation - Trace("model-engine-debug") << "Building model..." << std::endl; - //build model for UF - for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){ - Trace("model-engine-debug-uf") << "Building model for " << it->first << "..." << std::endl; - constructModelUf( fm, it->first ); - } - Trace("model-engine-debug") << "Done building models." << std::endl; - }else{ - return false; - } - } - } - //update models - for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){ - it->second.update( fm ); - Trace("model-func") << "QModelBuilder: Make function value from tree " << it->first << std::endl; - //construct function values - Node f_def = it->second.getFunctionValue( "$x" ); - fm->assignFunctionDefinition( it->first, f_def ); - } - Assert( d_addedLemmas==0 ); - return TheoryEngineModelBuilder::processBuildModel( m ); -} - -int QModelBuilderIG::initializeQuantifier(Node f, Node fp, FirstOrderModel* fm) -{ - if( d_quant_basis_match_added.find( f )==d_quant_basis_match_added.end() ){ - //create the basis match if necessary - if( d_quant_basis_match.find( f )==d_quant_basis_match.end() ){ - Trace("inst-fmf-init") << "Initialize " << f << std::endl; - //add the model basis instantiation - // This will help produce the necessary information for model completion. - // We do this by extending distinguish ground assertions (those - // containing terms with "model basis" attribute) to hold for all cases. - - ////first, check if any variables are required to be equal - //for( std::map< Node, bool >::iterator it = d_quantEngine->d_phase_reqs[f].begin(); - // it != d_quantEngine->d_phase_reqs[f].end(); ++it ){ - // Node n = it->first; - // if( n.getKind()==EQUAL && n[0].getKind()==INST_CONSTANT && n[1].getKind()==INST_CONSTANT ){ - // Notice() << "Unhandled phase req: " << n << std::endl; - // } - //} - d_quant_basis_match[f] = InstMatch( f ); - for (unsigned j = 0; j < f[0].getNumChildren(); j++) - { - Node t = fm->getModelBasisTerm(f[0][j].getType()); - //calculate the basis match for f - d_quant_basis_match[f].setValue( j, t ); - } - ++(d_statistics.d_num_quants_init); - } - //try to add it - Trace("inst-fmf-init") << "Init: try to add match " << d_quant_basis_match[f] << std::endl; - //add model basis instantiation - if (d_qe->getInstantiate()->addInstantiation(fp, d_quant_basis_match[f])) - { - d_quant_basis_match_added[f] = true; - return 1; - }else{ - //shouldn't happen usually, but will occur if x != y is a required literal for f. - //Notice() << "No model basis for " << f << std::endl; - d_quant_basis_match_added[f] = false; - } - } - return 0; -} - -void QModelBuilderIG::analyzeModel( FirstOrderModel* fm ){ - FirstOrderModelIG* fmig = fm->asFirstOrderModelIG(); - d_uf_model_constructed.clear(); - //determine if any functions are constant - for( std::map< Node, uf::UfModelTree >::iterator it = fmig->d_uf_model_tree.begin(); it != fmig->d_uf_model_tree.end(); ++it ){ - Node op = it->first; - std::map< Node, std::vector< Node > >::iterator itut = fmig->d_uf_terms.find( op ); - if( itut!=fmig->d_uf_terms.end() ){ - for( size_t i=0; isecond.size(); i++ ){ - Node n = fmig->d_uf_terms[op][i]; - //for calculating if op is constant - Node v = fmig->getRepresentative( n ); - if( i==0 ){ - d_uf_prefs[op].d_const_val = v; - }else if( v!=d_uf_prefs[op].d_const_val ){ - d_uf_prefs[op].d_const_val = Node::null(); - break; - } - } - } - if( !d_uf_prefs[op].d_const_val.isNull() ){ - fmig->d_uf_model_gen[op].setDefaultValue( d_uf_prefs[op].d_const_val ); - fmig->d_uf_model_gen[op].makeModel( fmig, it->second ); - Debug("fmf-model-cons") << "Function " << op << " is the constant function "; - Debug("fmf-model-cons") << d_uf_prefs[op].d_const_val; - Debug("fmf-model-cons") << std::endl; - d_uf_model_constructed[op] = true; - }else{ - d_uf_model_constructed[op] = false; - } - } -} - -bool QModelBuilderIG::hasConstantDefinition( Node n ){ - Node lit = n.getKind()==NOT ? n[0] : n; - if( lit.getKind()==APPLY_UF ){ - Node op = lit.getOperator(); - if( !d_uf_prefs[op].d_const_val.isNull() ){ - return true; - } - } - return false; -} - -QModelBuilderIG::Statistics::Statistics() - : d_num_quants_init("QModelBuilderIG::Number_Quantifiers", 0), - d_num_partial_quants_init("QModelBuilderIG::Number_Partial_Quantifiers", - 0), - d_init_inst_gen_lemmas("QModelBuilderIG::Initialize_Inst_Gen_Lemmas", 0), - d_inst_gen_lemmas("QModelBuilderIG::Inst_Gen_Lemmas", 0) -{ - smtStatisticsRegistry()->registerStat(&d_num_quants_init); - smtStatisticsRegistry()->registerStat(&d_num_partial_quants_init); - smtStatisticsRegistry()->registerStat(&d_init_inst_gen_lemmas); - smtStatisticsRegistry()->registerStat(&d_inst_gen_lemmas); -} - -QModelBuilderIG::Statistics::~Statistics(){ - smtStatisticsRegistry()->unregisterStat(&d_num_quants_init); - smtStatisticsRegistry()->unregisterStat(&d_num_partial_quants_init); - smtStatisticsRegistry()->unregisterStat(&d_init_inst_gen_lemmas); - smtStatisticsRegistry()->unregisterStat(&d_inst_gen_lemmas); -} - -//do exhaustive instantiation -int QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) { - if( optUseModel() ){ - QRepBoundExt qrbe(d_qe); - RepSetIterator riter(d_qe->getModel()->getRepSet(), &qrbe); - if( riter.setQuantifier( f ) ){ - FirstOrderModelIG * fmig = (FirstOrderModelIG*)d_qe->getModel(); - Debug("inst-fmf-ei") << "Reset evaluate..." << std::endl; - fmig->resetEvaluate(); - Debug("inst-fmf-ei") << "Begin instantiation..." << std::endl; - EqualityQuery* qy = d_qe->getEqualityQuery(); - Instantiate* inst = d_qe->getInstantiate(); - TermUtil* util = d_qe->getTermUtil(); - while( !riter.isFinished() && ( d_addedLemmas==0 || !options::fmfOneInstPerRound() ) ){ - d_triedLemmas++; - if( Debug.isOn("inst-fmf-ei-debug") ){ - for( int i=0; i<(int)riter.d_index.size(); i++ ){ - Debug("inst-fmf-ei-debug") << i << " : " << riter.d_index[i] << " : " << riter.getCurrentTerm( i ) << std::endl; - } - } - int eval = 0; - int depIndex; - //see if instantiation is already true in current model - if( Debug.isOn("fmf-model-eval") ){ - Debug("fmf-model-eval") << "Evaluating "; - riter.debugPrintSmall("fmf-model-eval"); - Debug("fmf-model-eval") << "Done calculating terms." << std::endl; - } - //if evaluate(...)==1, then the instantiation is already true in the model - // depIndex is the index of the least significant variable that this evaluation relies upon - depIndex = riter.getNumTerms()-1; - Debug("fmf-model-eval") << "We will evaluate " - << util->getInstConstantBody(f) << std::endl; - eval = fmig->evaluate(util->getInstConstantBody(f), depIndex, &riter); - if( eval==1 ){ - Debug("fmf-model-eval") << " Returned success with depIndex = " << depIndex << std::endl; - }else{ - Debug("fmf-model-eval") << " Returned " << (eval==-1 ? "failure" : "unknown") << ", depIndex = " << depIndex << std::endl; - } - if( eval==1 ){ - //instantiation is already true -> skip - riter.incrementAtIndex(depIndex); - }else{ - //instantiation was not shown to be true, construct the match - InstMatch m( f ); - for (unsigned i = 0; i < riter.getNumTerms(); i++) - { - m.set(qy, i, riter.getCurrentTerm(i)); - } - Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl; - //add as instantiation - if (inst->addInstantiation(f, m, true)) - { - d_addedLemmas++; - if( d_qe->inConflict() ){ - break; - } - //if the instantiation is show to be false, and we wish to skip multiple instantiations at once - if( eval==-1 ){ - riter.incrementAtIndex(depIndex); - }else{ - riter.increment(); - } - }else{ - Debug("fmf-model-eval") << "* Failed Add instantiation " << m << std::endl; - riter.increment(); - } - } - } - //print debugging information - Trace("inst-fmf-ei") << "For " << f << ", finished: " << std::endl; - Trace("inst-fmf-ei") << " Inst Tried: " << d_triedLemmas << std::endl; - Trace("inst-fmf-ei") << " Inst Added: " << d_addedLemmas << std::endl; - if( d_addedLemmas>1000 ){ - Trace("model-engine-warn") << "WARNING: many instantiations produced for " << f << ": " << std::endl; - Trace("model-engine-warn") << " Inst Tried: " << d_triedLemmas << std::endl; - Trace("model-engine-warn") << " Inst Added: " << d_addedLemmas << std::endl; - Trace("model-engine-warn") << std::endl; - } - } - //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round - return riter.isIncomplete() ? -1 : 1; - }else{ - return 0; - } -} - - - -void QModelBuilderDefault::reset( FirstOrderModel* fm ){ - d_quant_selection_lit.clear(); - d_quant_selection_lit_candidates.clear(); - d_quant_selection_lit_terms.clear(); - d_term_selection_lit.clear(); - d_op_selection_terms.clear(); -} - - -int QModelBuilderDefault::getSelectionScore( std::vector< Node >& uf_terms ) { - /* - size_t maxChildren = 0; - for( size_t i=0; imaxChildren ){ - maxChildren = uf_terms[i].getNumChildren(); - } - } - //TODO: look at how many entries they have? - return (int)maxChildren; - */ - return 0; -} - -void QModelBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f ){ - if( d_qe->getModel()->isQuantifierActive( f ) ){ - FirstOrderModelIG* fmig = fm->asFirstOrderModelIG(); - Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl; - //the pro/con preferences for this quantifier - std::vector< Node > pro_con[2]; - //the terms in the selection literal we choose - std::vector< Node > selectionLitTerms; - Trace("inst-gen-debug-quant") << "Inst-gen analyze " << f << std::endl; - //for each asserted quantifier f, - // - determine selection literals - // - check which function/predicates have good and bad definitions for satisfying f - if( d_phase_reqs.find( f )==d_phase_reqs.end() ){ - d_phase_reqs[f].initialize( d_qe->getTermUtil()->getInstConstantBody( f ), true ); - } - int selectLitScore = -1; - for( std::map< Node, bool >::iterator it = d_phase_reqs[f].d_phase_reqs.begin(); it != d_phase_reqs[f].d_phase_reqs.end(); ++it ){ - //the literal n is phase-required for quantifier f - Node n = it->first; - Node gn = fm->getModelBasis(f, n); - Debug("fmf-model-req") << " Req: " << n << " -> " << it->second << std::endl; - bool value; - //if the corresponding ground abstraction literal has a SAT value - if( d_qe->getValuation().hasSatValue( gn, value ) ){ - //collect the non-ground uf terms that this literal contains - // and compute if all of the symbols in this literal have - // constant definitions. - bool isConst = true; - std::vector< Node > uf_terms; - if( TermUtil::hasInstConstAttr(n) ){ - isConst = false; - if( gn.getKind()==APPLY_UF ){ - uf_terms.push_back( gn ); - isConst = hasConstantDefinition( gn ); - }else if( gn.getKind()==EQUAL ){ - isConst = true; - for( int j=0; j<2; j++ ){ - if( TermUtil::hasInstConstAttr(n[j]) ){ - if( n[j].getKind()==APPLY_UF && - fmig->d_uf_model_tree.find( gn[j].getOperator() )!=fmig->d_uf_model_tree.end() ){ - uf_terms.push_back( gn[j] ); - isConst = isConst && hasConstantDefinition( gn[j] ); - }else{ - isConst = false; - } - } - } - } - } - //check if the value in the SAT solver matches the preference according to the quantifier - int pref = 0; - if( value!=it->second ){ - //we have a possible selection literal - bool selectLit = d_quant_selection_lit[f].isNull(); - bool selectLitConstraints = true; - //it is a constantly defined selection literal : the quantifier is sat - if( isConst ){ - selectLit = selectLit || d_qe->getModel()->isQuantifierActive( f ); - d_qe->getModel()->setQuantifierActive( f, false ); - //check if choosing this literal would add any additional constraints to default definitions - selectLitConstraints = false; - selectLit = true; - } - //also check if it is naturally a better literal - if( !selectLit ){ - int score = getSelectionScore( uf_terms ); - //Trace("inst-gen-debug") << "Check " << score << " < " << selectLitScore << std::endl; - selectLit = scoregetModel()->isQuantifierActive( f ) ){ - Debug("fmf-model-prefs") << " It is " << ( pref==1 ? "pro" : "con" ); - Debug("fmf-model-prefs") << " the definition of " << n << std::endl; - for( int j=0; j<(int)uf_terms.size(); j++ ){ - pro_con[ pref==1 ? 0 : 1 ].push_back( uf_terms[j] ); - } - } - } - } - //process information about selection literal for f - if( !d_quant_selection_lit[f].isNull() ){ - d_quant_selection_lit_terms[f].insert( d_quant_selection_lit_terms[f].begin(), selectionLitTerms.begin(), selectionLitTerms.end() ); - for( int i=0; i<(int)selectionLitTerms.size(); i++ ){ - d_term_selection_lit[ selectionLitTerms[i] ] = d_quant_selection_lit[f]; - d_op_selection_terms[ selectionLitTerms[i].getOperator() ].push_back( selectionLitTerms[i] ); - } - }else{ - Trace("inst-gen-warn") << "WARNING: " << f << " has no selection literals" << std::endl; - } - //process information about requirements and preferences of quantifier f - if( !d_qe->getModel()->isQuantifierActive( f ) ){ - Debug("fmf-model-prefs") << " * Constant SAT due to definition of ops: "; - for( int i=0; i<(int)selectionLitTerms.size(); i++ ){ - Debug("fmf-model-prefs") << selectionLitTerms[i] << " "; - } - Debug("fmf-model-prefs") << std::endl; - }else{ - //note quantifier's value preferences to models - for( int k=0; k<2; k++ ){ - for( int j=0; j<(int)pro_con[k].size(); j++ ){ - Node op = pro_con[k][j].getOperator(); - Node r = fmig->getRepresentative( pro_con[k][j] ); - d_uf_prefs[op].setValuePreference(f, r, k == 0); - } - } - } - } -} - -int QModelBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){ - int addedLemmas = 0; - //we wish to add all known exceptions to our selection literal for f. this will help to refine our current model. - //This step is advantageous over exhaustive instantiation, since we are adding instantiations that involve model basis terms, - // effectively acting as partial instantiations instead of pointwise instantiations. - if( !d_quant_selection_lit[f].isNull() ){ - Trace("inst-gen") << "Do Inst-Gen for " << f << std::endl; - for( size_t i=0; i tr_terms; - if( lit.getKind()==APPLY_UF ){ - //only match predicates that are contrary to this one, use literal matching - Node eq = NodeManager::currentNM()->mkNode( - EQUAL, lit, NodeManager::currentNM()->mkConst(!phase)); - tr_terms.push_back( eq ); - }else if( lit.getKind()==EQUAL ){ - //collect trigger terms - for( int j=0; j<2; j++ ){ - if( TermUtil::hasInstConstAttr(lit[j]) ){ - if( lit[j].getKind()==APPLY_UF ){ - tr_terms.push_back( lit[j] ); - }else{ - tr_terms.clear(); - break; - } - } - } - if( tr_terms.size()==1 && !phase ){ - //equality between a function and a ground term, use literal matching - tr_terms.clear(); - tr_terms.push_back( lit ); - } - } - //if applicable, try to add exceptions here - if( !tr_terms.empty() ){ - //make a trigger for these terms, add instantiations - inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms, true, inst::Trigger::TR_MAKE_NEW ); - //Notice() << "Trigger = " << (*tr) << std::endl; - tr->resetInstantiationRound(); - tr->reset( Node::null() ); - //d_qe->d_optInstMakeRepresentative = false; - //d_qe->d_optMatchIgnoreModelBasis = true; - addedLemmas += tr->addInstantiations(); - } - } - } - return addedLemmas; -} - -void QModelBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op ){ - FirstOrderModelIG* fmig = fm->asFirstOrderModelIG(); - if( !d_uf_model_constructed[op] ){ - //construct the model for the uninterpretted function/predicate - bool setDefaultVal = true; - Node defaultTerm = fmig->getModelBasisOpTerm(op); - Trace("fmf-model-cons") << "Construct model for " << op << "..." << std::endl; - //set the values in the model - std::map< Node, std::vector< Node > >::iterator itut = fmig->d_uf_terms.find( op ); - if( itut!=fmig->d_uf_terms.end() ){ - for( size_t i=0; isecond.size(); i++ ){ - Node n = itut->second[i]; - // only consider unique up to congruence (in model equality engine)? - Node v = fmig->getRepresentative( n ); - Trace("fmf-model-cons") << "Set term " << n << " : " - << fmig->getRepSet()->getIndexFor(v) << " " << v - << std::endl; - //if this assertion did not help the model, just consider it ground - //set n = v in the model tree - //set it as ground value - fmig->d_uf_model_gen[op].setValue( fm, n, v ); - // also set as default value if necessary - if (n.hasAttribute(ModelBasisArgAttribute()) - && n.getAttribute(ModelBasisArgAttribute()) != 0) - { - Trace("fmf-model-cons") << " Set as default." << std::endl; - fmig->d_uf_model_gen[op].setValue(fm, n, v, false); - if( n==defaultTerm ){ - //incidentally already set, we will not need to find a default value - setDefaultVal = false; - } - } - } - } - //set the overall default value if not set already (is this necessary??) - if( setDefaultVal ){ - Trace("fmf-model-cons") << " Choose default value..." << std::endl; - //chose defaultVal based on heuristic, currently the best ratio of "pro" responses - Node defaultVal = d_uf_prefs[op].getBestDefaultValue( defaultTerm, fm ); - if( defaultVal.isNull() ){ - if (!fmig->getRepSet()->hasType(defaultTerm.getType())) - { - Node mbt = fmig->getModelBasisTerm(defaultTerm.getType()); - fmig->getRepSetPtr()->d_type_reps[defaultTerm.getType()].push_back( - mbt); - } - defaultVal = - fmig->getRepSet()->getRepresentative(defaultTerm.getType(), 0); - } - Assert( !defaultVal.isNull() ); - Trace("fmf-model-cons") - << "Set default term : " << fmig->getRepSet()->getIndexFor(defaultVal) - << std::endl; - fmig->d_uf_model_gen[op].setValue( fm, defaultTerm, defaultVal, false ); - } - Debug("fmf-model-cons") << " Making model..."; - fmig->d_uf_model_gen[op].makeModel( fm, fmig->d_uf_model_tree[op] ); - d_uf_model_constructed[op] = true; - Debug("fmf-model-cons") << " Finished constructing model for " << op << "." << std::endl; - } -} diff --git a/src/theory/quantifiers/fmf/model_builder.h b/src/theory/quantifiers/fmf/model_builder.h index b34f1e580..b73716169 100644 --- a/src/theory/quantifiers/fmf/model_builder.h +++ b/src/theory/quantifiers/fmf/model_builder.h @@ -56,163 +56,6 @@ public: unsigned getNumTriedLemmas() { return d_triedLemmas; } }; -class TermArgBasisTrie { -public: - /** the data */ - std::map< Node, TermArgBasisTrie > d_data; - /** add term to the trie */ - bool addTerm(FirstOrderModel* fm, Node n, unsigned argIndex = 0); -};/* class TermArgBasisTrie */ - -/** model builder class - * This class is capable of building candidate models based on the current quantified formulas - * that are asserted. Use: - * (1) call QModelBuilder::buildModel( m, false );, where m is a FirstOrderModel - * (2) if candidate model is determined to be a real model, - then call QModelBuilder::buildModel( m, true ); - */ -class QModelBuilderIG : public QModelBuilder -{ - typedef context::CDHashMap BoolMap; - - protected: - /** - * This class stores temporary information useful to model engine for - * constructing models for uninterpreted functions. - */ - class UfModelPreferenceData - { - public: - UfModelPreferenceData() {} - virtual ~UfModelPreferenceData() {} - /** any constant value of the type */ - Node d_const_val; - /** list of possible default values */ - std::vector d_values; - /** - * Map from values to the set of quantified formulas that are (pro, con) - * that value. A quantified formula may be "pro" a particular default - * value of an uninterpreted function if that value is likely to satisfy - * many points in its domain. For example, forall x. P( f( x ) ) may be - * "pro" the default value true for P. - */ - std::map > d_value_pro_con[2]; - /** set that quantified formula q is pro/con the default value of r */ - void setValuePreference(Node q, Node r, bool isPro); - /** get best default value */ - Node getBestDefaultValue(Node defaultTerm, TheoryModel* m); - }; - /** map from operators to model preference data */ - std::map d_uf_prefs; - //built model uf - std::map< Node, bool > d_uf_model_constructed; - //whether inst gen was done - bool d_didInstGen; - /** process build model */ - bool processBuildModel(TheoryModel* m) override; - - protected: - //reset - virtual void reset( FirstOrderModel* fm ) = 0; - //initialize quantifiers, return number of lemmas produced - virtual int initializeQuantifier(Node f, Node fp, FirstOrderModel* fm); - //analyze model - virtual void analyzeModel( FirstOrderModel* fm ); - //analyze quantifiers - virtual void analyzeQuantifier( FirstOrderModel* fm, Node f ) = 0; - //do InstGen techniques for quantifier, return number of lemmas produced - virtual int doInstGen( FirstOrderModel* fm, Node f ) = 0; - //theory-specific build models - virtual void constructModelUf( FirstOrderModel* fm, Node op ) = 0; - - protected: - //map from quantifiers to if are SAT - //std::map< Node, bool > d_quant_sat; - //which quantifiers have been initialized - std::map< Node, bool > d_quant_basis_match_added; - //map from quantifiers to model basis match - std::map< Node, InstMatch > d_quant_basis_match; - - protected: // helper functions - /** term has constant definition */ - bool hasConstantDefinition( Node n ); - - public: - QModelBuilderIG( context::Context* c, QuantifiersEngine* qe ); - - public: - /** statistics class */ - class Statistics { - public: - IntStat d_num_quants_init; - IntStat d_num_partial_quants_init; - IntStat d_init_inst_gen_lemmas; - IntStat d_inst_gen_lemmas; - Statistics(); - ~Statistics(); - }; - Statistics d_statistics; - // is term selected - virtual bool isTermSelected( Node n ) { return false; } - /** quantifier has inst-gen definition */ - virtual bool hasInstGen( Node f ) = 0; - /** did inst gen this round? */ - bool didInstGen() { return d_didInstGen; } - // is quantifier active? - bool isQuantifierActive( Node f ); - //do exhaustive instantiation - int doExhaustiveInstantiation(FirstOrderModel* fm, - Node f, - int effort) override; - - //temporary stats - int d_numQuantSat; - int d_numQuantInstGen; - int d_numQuantNoInstGen; - int d_numQuantNoSelForm; - //temporary stat - int d_instGenMatches; -};/* class QModelBuilder */ - - -class QModelBuilderDefault : public QModelBuilderIG -{ - private: /// information for (old) InstGen - // map from quantifiers to their selection literals - std::map< Node, Node > d_quant_selection_lit; - std::map< Node, std::vector< Node > > d_quant_selection_lit_candidates; - //map from quantifiers to their selection literal terms - std::map< Node, std::vector< Node > > d_quant_selection_lit_terms; - //map from terms to the selection literals they exist in - std::map< Node, Node > d_term_selection_lit; - //map from operators to terms that appear in selection literals - std::map< Node, std::vector< Node > > d_op_selection_terms; - //get selection score - int getSelectionScore( std::vector< Node >& uf_terms ); - - protected: - //reset - void reset(FirstOrderModel* fm) override; - //analyze quantifier - void analyzeQuantifier(FirstOrderModel* fm, Node f) override; - //do InstGen techniques for quantifier, return number of lemmas produced - int doInstGen(FirstOrderModel* fm, Node f) override; - //theory-specific build models - void constructModelUf(FirstOrderModel* fm, Node op) override; - - protected: - std::map< Node, QuantPhaseReq > d_phase_reqs; - - public: - QModelBuilderDefault( context::Context* c, QuantifiersEngine* qe ) : QModelBuilderIG( c, qe ){} - - //has inst gen - bool hasInstGen(Node f) override - { - return !d_quant_selection_lit[f].isNull(); - } -}; - }/* CVC4::theory::quantifiers namespace */ }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/theory/quantifiers/fmf/model_engine.cpp b/src/theory/quantifiers/fmf/model_engine.cpp index 81ecf9e77..d2579b4ee 100644 --- a/src/theory/quantifiers/fmf/model_engine.cpp +++ b/src/theory/quantifiers/fmf/model_engine.cpp @@ -15,7 +15,6 @@ #include "theory/quantifiers/fmf/model_engine.h" #include "options/quantifiers_options.h" -#include "theory/quantifiers/fmf/ambqi_builder.h" #include "theory/quantifiers/first_order_model.h" #include "theory/quantifiers/fmf/full_model_check.h" #include "theory/quantifiers/instantiate.h" diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp index 320f50afb..433621d31 100644 --- a/src/theory/quantifiers_engine.cpp +++ b/src/theory/quantifiers_engine.cpp @@ -30,7 +30,6 @@ #include "theory/quantifiers/equality_infer.h" #include "theory/quantifiers/equality_query.h" #include "theory/quantifiers/first_order_model.h" -#include "theory/quantifiers/fmf/ambqi_builder.h" #include "theory/quantifiers/fmf/bounded_integers.h" #include "theory/quantifiers/fmf/full_model_check.h" #include "theory/quantifiers/fmf/model_engine.h" @@ -249,20 +248,14 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c, d_model.reset(new quantifiers::fmcheck::FirstOrderModelFmc( this, c, "FirstOrderModelFmc")); d_builder.reset(new quantifiers::fmcheck::FullModelChecker(c, this)); - }else if( options::mbqiMode()==quantifiers::MBQI_ABS ){ - Trace("quant-engine-debug") << "...make abs mbqi builder." << std::endl; - d_model.reset( - new quantifiers::FirstOrderModelAbs(this, c, "FirstOrderModelAbs")); - d_builder.reset(new quantifiers::AbsMbqiBuilder(c, this)); }else{ Trace("quant-engine-debug") << "...make default model builder." << std::endl; d_model.reset( - new quantifiers::FirstOrderModelIG(this, c, "FirstOrderModelIG")); - d_builder.reset(new quantifiers::QModelBuilderDefault(c, this)); + new quantifiers::FirstOrderModel(this, c, "FirstOrderModel")); + d_builder.reset(new quantifiers::QModelBuilder(c, this)); } }else{ - d_model.reset( - new quantifiers::FirstOrderModelIG(this, c, "FirstOrderModelIG")); + d_model.reset(new quantifiers::FirstOrderModel(this, c, "FirstOrderModel")); } } diff --git a/src/theory/uf/theory_uf_model.cpp b/src/theory/uf/theory_uf_model.cpp index a3e058569..42847dfd4 100644 --- a/src/theory/uf/theory_uf_model.cpp +++ b/src/theory/uf/theory_uf_model.cpp @@ -37,17 +37,6 @@ void UfModelTreeNode::clear(){ d_value = Node::null(); } -bool UfModelTreeNode::hasConcreteArgumentDefinition(){ - if( d_data.size()>1 ){ - return true; - }else if( d_data.empty() ){ - return false; - }else{ - Node r; - return d_data.find( r )==d_data.end(); - } -} - //set value function void UfModelTreeNode::setValue( TheoryModel* m, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex ){ if( d_data.empty() ){ @@ -67,75 +56,6 @@ void UfModelTreeNode::setValue( TheoryModel* m, Node n, Node v, std::vector< int } } -//get value function -Node UfModelTreeNode::getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int& depIndex, int argIndex ){ - if( !d_value.isNull() && isTotal( n.getOperator(), argIndex ) ){ - //Notice() << "Constant, return " << d_value << ", depIndex = " << argIndex << std::endl; - depIndex = argIndex; - return d_value; - }else{ - Node val; - int childDepIndex[2] = { argIndex, argIndex }; - for( int i=0; i<2; i++ ){ - //first check the argument, then check default - Node r; - if( i==0 ){ - r = m->getRepresentative( n[ indexOrder[argIndex] ] ); - } - std::map< Node, UfModelTreeNode >::iterator it = d_data.find( r ); - if( it!=d_data.end() ){ - val = it->second.getValue( m, n, indexOrder, childDepIndex[i], argIndex+1 ); - if( !val.isNull() ){ - break; - } - }else{ - //argument is not a defined argument: thus, it depends on this argument - childDepIndex[i] = argIndex+1; - } - } - //update depIndex - depIndex = childDepIndex[0]>childDepIndex[1] ? childDepIndex[0] : childDepIndex[1]; - //Notice() << "Return " << val << ", depIndex = " << depIndex; - //Notice() << " ( " << childDepIndex[0] << ", " << childDepIndex[1] << " )" << std::endl; - return val; - } -} - -Node UfModelTreeNode::getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, std::vector< int >& depIndex, int argIndex ){ - if( argIndex==(int)indexOrder.size() ){ - return d_value; - }else{ - Node val; - bool depArg = false; - //will try concrete value first, then default - for( int i=0; i<2; i++ ){ - Node r; - if( i==0 ){ - r = m->getRepresentative( n[ indexOrder[argIndex] ] ); - } - std::map< Node, UfModelTreeNode >::iterator it = d_data.find( r ); - if( it!=d_data.end() ){ - val = it->second.getValue( m, n, indexOrder, depIndex, argIndex+1 ); - //we have found a value - if( !val.isNull() ){ - if( i==0 ){ - depArg = true; - } - break; - } - } - } - //it depends on this argument if we found it via concrete argument value, - // or if found by default/disequal from some concrete argument value(s). - if( depArg || hasConcreteArgumentDefinition() ){ - if( std::find( depIndex.begin(), depIndex.end(), indexOrder[argIndex] )==depIndex.end() ){ - depIndex.push_back( indexOrder[argIndex] ); - } - } - return val; - } -} - Node UfModelTreeNode::getFunctionValue(std::vector& args, int index, Node argDefaultValue, bool simplify) { if(!d_data.empty()) { Node defaultValue = argDefaultValue; @@ -264,10 +184,6 @@ bool UfModelTreeNode::isTotal( Node op, int argIndex ){ } } -Node UfModelTreeNode::getConstantValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int argIndex ){ - return d_value; -} - void indent( std::ostream& out, int ind ){ for( int i=0; i d_data; /** the value of this tree node (if all paths lead to same value) */ Node d_value; - /** has concrete argument defintion */ - bool hasConcreteArgumentDefinition(); public: //is this model tree empty? bool isEmpty() { return d_data.empty() && d_value.isNull(); } @@ -40,11 +38,6 @@ public: void clear(); /** setValue function */ void setValue( TheoryModel* m, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex ); - /** getValue function */ - Node getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int& depIndex, int argIndex ); - Node getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, std::vector< int >& depIndex, int argIndex ); - /** getConstant Value function */ - Node getConstantValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int argIndex ); /** getFunctionValue */ Node getFunctionValue( std::vector< Node >& args, int index, Node argDefaultValue, bool simplify = true ); /** update function */ @@ -92,36 +85,6 @@ public: void setDefaultValue( TheoryModel* m, Node v ){ d_tree.setValue( m, Node::null(), v, d_index_order, false, 0 ); } - /** getValue function - * - * returns val, the value of ground term n - * Say n is f( t_0...t_n ) - * depIndex is the index for which every term of the form f( t_0 ... t_depIndex, *,... * ) is equal to val - * for example, if g( x_0, x_1, x_2 ) := lambda x_0 x_1 x_2. if( x_1==a ) b else c, - * then g( a, a, a ) would return b with depIndex = 1 - * - */ - Node getValue( TheoryModel* m, Node n, int& depIndex ){ - return d_tree.getValue( m, n, d_index_order, depIndex, 0 ); - } - /** -> implementation incomplete */ - Node getValue( TheoryModel* m, Node n, std::vector< int >& depIndex ){ - return d_tree.getValue( m, n, d_index_order, depIndex, 0 ); - } - /** getConstantValue function - * - * given term n, where n may contain "all value" arguments, aka model basis arguments - * if n is null, then every argument of n is considered "all value" - * if n is constant for the entire domain specified by n, then this function returns the value of its domain - * otherwise, it returns null - * for example, say the term e represents "all values" - * if f( x_0, x_1 ) := if( x_0 = a ) b else if( x_1 = a ) a else b, - * then f( a, e ) would return b, while f( e, a ) would return null - * -> implementation incomplete - */ - Node getConstantValue( TheoryModel* m, Node n ) { - return d_tree.getConstantValue( m, n, d_index_order, 0 ); - } /** getFunctionValue * Returns a representation of this function. */ @@ -136,8 +99,6 @@ public: void simplify() { d_tree.simplify( d_op, Node::null(), 0 ); } /** is this tree total? */ bool isTotal() { return d_tree.isTotal( d_op, 0 ); } - /** is this function constant? */ - bool isConstant( TheoryModel* m ) { return !getConstantValue( m, Node::null() ).isNull(); } /** is this tree empty? */ bool isEmpty() { return d_tree.isEmpty(); } public: diff --git a/test/regress/regress0/fmf/Arrow_Order-smtlib.778341.smt b/test/regress/regress0/fmf/Arrow_Order-smtlib.778341.smt index e8c7949dc..bb2630b93 100644 --- a/test/regress/regress0/fmf/Arrow_Order-smtlib.778341.smt +++ b/test/regress/regress0/fmf/Arrow_Order-smtlib.778341.smt @@ -1,4 +1,4 @@ -; COMMAND-LINE: --finite-model-find --mbqi=gen-ev +; COMMAND-LINE: --finite-model-find ; EXPECT: unsat (benchmark Isabelle :status sat diff --git a/test/regress/regress0/fmf/QEpres-uf.855035.smt b/test/regress/regress0/fmf/QEpres-uf.855035.smt index 4fe592638..97a585090 100644 --- a/test/regress/regress0/fmf/QEpres-uf.855035.smt +++ b/test/regress/regress0/fmf/QEpres-uf.855035.smt @@ -1,4 +1,4 @@ -; COMMAND-LINE: --finite-model-find --mbqi=gen-ev +; COMMAND-LINE: --finite-model-find ; EXPECT: sat (benchmark Isabelle :status sat diff --git a/test/regress/regress1/fmf/nlp042+1.smt2 b/test/regress/regress1/fmf/nlp042+1.smt2 index 567a3c0b7..6159f0b41 100644 --- a/test/regress/regress1/fmf/nlp042+1.smt2 +++ b/test/regress/regress1/fmf/nlp042+1.smt2 @@ -1,4 +1,4 @@ -; COMMAND-LINE: --finite-model-find --mbqi=abs --no-check-models +; COMMAND-LINE: --finite-model-find --no-check-models ; EXPECT: sat (set-logic UF) (set-info :status sat) -- cgit v1.2.3 From 3687e098f4b6a969d265641e413ab05117bf53a7 Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Tue, 11 Dec 2018 17:19:07 -0800 Subject: [LRAT] signature robust against duplicate literals (#2743) * [LRAT] signature robust against duplicate literals The LRAT signature previously had complex, surprising, and occasionally incorrect behavior when given clauses with duplicate literals. Now it does not. Now clauses have true set semantics, and clauses with duplicate literals are treated identically to those without. * Test with logically = but structurally != clauses. --- proofs/signatures/lrat.plf | 39 ++++++++-- proofs/signatures/lrat_test.plf | 155 +++++++++++++++++++++++++++++++++------- 2 files changed, 163 insertions(+), 31 deletions(-) diff --git a/proofs/signatures/lrat.plf b/proofs/signatures/lrat.plf index f5af891bc..96cdd83b3 100644 --- a/proofs/signatures/lrat.plf +++ b/proofs/signatures/lrat.plf @@ -129,6 +129,28 @@ (ff (clause_contains_lit c' l)))) (cln ff))) +; Returns a copy of `c` with any duplicate literals removed. +; Never fails. +; Uses marks 3 & 4. Expects them to be clear before hand, and leaves them clear +; afterwards. +(program clause_dedup ((c clause)) clause + (match c + (cln cln) + ((clc l rest) + (match l + ((pos v) (ifmarked3 + v + (clause_dedup rest) + (do (markvar3 v) + (let result (clc (pos v) (clause_dedup rest)) + (do (markvar3 v) result))))) + ((neg v) (ifmarked4 + v + (clause_dedup rest) + (do (markvar4 v) + (let result (clc (neg v) (clause_dedup rest)) + (do (markvar4 v) result))))))))) + ; Append two traces (program Trace_concat ((t1 Trace) (t2 Trace)) Trace (match t1 @@ -473,9 +495,9 @@ (RATHintsn CTPn) ((RATHintsc i ht hints') (CTPc - (clause_append c + (clause_dedup (clause_append c (clause_remove_all (lit_flip (clause_head c)) - (CMap_get i cs))) + (CMap_get i cs)))) (Trace_concat t ht) (construct_ct_pairs cs c t hints'))))) @@ -534,17 +556,22 @@ (LRATProofn ff)) ) + ; Proof of a CMap from clause proofs. ; The idx is unelidable b/c it is unspecified. +; Robust against clauses with duplicat literals, but not against tautological +; clauses. (declare CMap_holds (! c CMap type)) (declare CMapn_proof (CMap_holds CMapn)) (declare CMapc_proof (! idx mpz ; Not elidable! (! c clause - (! rest CMap - (! proof_c (holds c) - ( ! proof_rest (CMap_holds rest) - (CMap_holds (CMapc idx c rest)))))))) + (! deduped_c clause + (! rest CMap + (! proof_c (holds c) + (! proof_rest (CMap_holds rest) + (! sc (^ (clause_dedup c) deduped_c) + (CMap_holds (CMapc idx deduped_c rest)))))))))) (define bottom (holds cln)) (declare lrat_proof_of_bottom diff --git a/proofs/signatures/lrat_test.plf b/proofs/signatures/lrat_test.plf index 3ba785507..0663a08f7 100644 --- a/proofs/signatures/lrat_test.plf +++ b/proofs/signatures/lrat_test.plf @@ -637,14 +637,66 @@ (% pf_c7 (holds (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))) (% pf_c8 (holds (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))) (@ pf_cmap - (CMapc_proof 1 _ _ pf_c1 - (CMapc_proof 2 _ _ pf_c2 - (CMapc_proof 3 _ _ pf_c3 - (CMapc_proof 4 _ _ pf_c4 - (CMapc_proof 5 _ _ pf_c5 - (CMapc_proof 6 _ _ pf_c6 - (CMapc_proof 7 _ _ pf_c7 - (CMapc_proof 8 _ _ pf_c8 + (CMapc_proof 1 _ _ _ pf_c1 + (CMapc_proof 2 _ _ _ pf_c2 + (CMapc_proof 3 _ _ _ pf_c3 + (CMapc_proof 4 _ _ _ pf_c4 + (CMapc_proof 5 _ _ _ pf_c5 + (CMapc_proof 6 _ _ _ pf_c6 + (CMapc_proof 7 _ _ _ pf_c7 + (CMapc_proof 8 _ _ _ pf_c8 + CMapn_proof)))))))) + (@ lrat_proof_witness + (LRATProofa 9 + (clc (pos v1) cln) + Tracen + (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen)) + (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen)) + (RATHintsc 7 (Tracec 6 (Tracec 1 Tracen)) + RATHintsn))) + (LRATProofd (CIListc 1 (CIListc 6 (CIListc 8 CIListn))) + (LRATProofa 10 + (clc (pos v2) cln) + (Tracec 9 (Tracec 7 (Tracec 5 (Tracec 3 Tracen)))) + RATHintsn + (LRATProofd (CIListc 3 (CIListc 7 CIListn)) + (LRATProofa 11 + cln + (Tracec 9 (Tracec 10 (Tracec 2 (Tracec 4 (Tracec 5 Tracen))))) + RATHintsn + LRATProofn))))) + (: + (holds cln) + (lrat_proof_of_bottom _ pf_cmap lrat_proof_witness)) + )) + )))))))) + )))) +) + +; Proof from Figure 2 of "Efficient Certified RAT Verification" +; With duplicates +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (% pf_c1 (holds (clc (pos v1) (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))))) + (% pf_c2 (holds (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))) + (% pf_c3 (holds (clc (pos v2) (clc (pos v3) (clc (pos v3) (clc (pos v3) (clc (neg v4) cln)))))) + (% pf_c4 (holds (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))) + (% pf_c5 (holds (clc (neg v1) (clc (neg v3) (clc (neg v4) (clc (neg v4) cln))))) + (% pf_c6 (holds (clc (pos v1) (clc (pos v3) (clc (pos v3) (clc (pos v4) cln))))) + (% pf_c7 (holds (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))) + (% pf_c8 (holds (clc (pos v1) (clc (neg v2) (clc (neg v2) (clc (neg v4) cln))))) + (@ pf_cmap + (CMapc_proof 1 _ _ _ pf_c1 + (CMapc_proof 2 _ _ _ pf_c2 + (CMapc_proof 3 _ _ _ pf_c3 + (CMapc_proof 4 _ _ _ pf_c4 + (CMapc_proof 5 _ _ _ pf_c5 + (CMapc_proof 6 _ _ _ pf_c6 + (CMapc_proof 7 _ _ _ pf_c7 + (CMapc_proof 8 _ _ _ pf_c8 CMapn_proof)))))))) (@ lrat_proof_witness (LRATProofa 9 @@ -689,15 +741,68 @@ (% pf_c8 (holds (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))) (% pf_c9 (holds (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))) (@ pf_cmap - (CMapc_proof 1 _ _ pf_c1 - (CMapc_proof 2 _ _ pf_c2 - (CMapc_proof 3 _ _ pf_c3 - (CMapc_proof 4 _ _ pf_c4 - (CMapc_proof 5 _ _ pf_c5 - (CMapc_proof 6 _ _ pf_c6 - (CMapc_proof 7 _ _ pf_c7 - (CMapc_proof 8 _ _ pf_c8 - (CMapc_proof 9 _ _ pf_c9 + (CMapc_proof 1 _ _ _ pf_c1 + (CMapc_proof 2 _ _ _ pf_c2 + (CMapc_proof 3 _ _ _ pf_c3 + (CMapc_proof 4 _ _ _ pf_c4 + (CMapc_proof 5 _ _ _ pf_c5 + (CMapc_proof 6 _ _ _ pf_c6 + (CMapc_proof 7 _ _ _ pf_c7 + (CMapc_proof 8 _ _ _ pf_c8 + (CMapc_proof 9 _ _ _ pf_c9 + CMapn_proof))))))))) + (@ lrat_proof_witness + (LRATProofa 10 + (clc (pos v1) cln) + Tracen + (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen)) + (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen)) + (RATHintsc 7 (Tracec 6 (Tracec 9 Tracen)) + RATHintsn))) + (LRATProofd (CIListc 1 (CIListc 6 (CIListc 8 (CIListc 9 CIListn)))) + (LRATProofa 11 + (clc (pos v2) cln) + (Tracec 10 (Tracec 7 (Tracec 5 (Tracec 3 Tracen)))) + RATHintsn + (LRATProofd (CIListc 3 (CIListc 7 CIListn)) + (LRATProofa 12 + cln + (Tracec 10 (Tracec 11 (Tracec 2 (Tracec 4 (Tracec 5 Tracen))))) + RATHintsn + LRATProofn))))) + (: + (holds cln) + (lrat_proof_of_bottom _ pf_cmap lrat_proof_witness)) + )) + ))))))))) + )))) +) + +; Clauses 1 and 9 are logically identical, but the literals have been reordered. +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (% pf_c1 (holds (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))) + (% pf_c2 (holds (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))) + (% pf_c3 (holds (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))) + (% pf_c4 (holds (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))) + (% pf_c5 (holds (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))) + (% pf_c6 (holds (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))) + (% pf_c7 (holds (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))) + (% pf_c8 (holds (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))) + (% pf_c9 (holds (clc (neg v3) (clc (pos v2) (clc (pos v1) cln)))) + (@ pf_cmap + (CMapc_proof 1 _ _ _ pf_c1 + (CMapc_proof 2 _ _ _ pf_c2 + (CMapc_proof 3 _ _ _ pf_c3 + (CMapc_proof 4 _ _ _ pf_c4 + (CMapc_proof 5 _ _ _ pf_c5 + (CMapc_proof 6 _ _ _ pf_c6 + (CMapc_proof 7 _ _ _ pf_c7 + (CMapc_proof 8 _ _ _ pf_c8 + (CMapc_proof 9 _ _ _ pf_c9 CMapn_proof))))))))) (@ lrat_proof_witness (LRATProofa 10 @@ -741,14 +846,14 @@ (% pf_c7 (holds (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))) (% pf_c8 (holds (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))) (@ pf_cmap - (CMapc_proof 1 _ _ pf_c1 - (CMapc_proof 2 _ _ pf_c2 - (CMapc_proof 3 _ _ pf_c3 - (CMapc_proof 4 _ _ pf_c4 - (CMapc_proof 5 _ _ pf_c5 - (CMapc_proof 6 _ _ pf_c6 - (CMapc_proof 7 _ _ pf_c7 - (CMapc_proof 8 _ _ pf_c8 + (CMapc_proof 1 _ _ _ pf_c1 + (CMapc_proof 2 _ _ _ pf_c2 + (CMapc_proof 3 _ _ _ pf_c3 + (CMapc_proof 4 _ _ _ pf_c4 + (CMapc_proof 5 _ _ _ pf_c5 + (CMapc_proof 6 _ _ _ pf_c6 + (CMapc_proof 7 _ _ _ pf_c7 + (CMapc_proof 8 _ _ _ pf_c8 CMapn_proof)))))))) (@ lrat_proof_witness (LRATProofa 9 -- cgit v1.2.3 From fb6bab97d8a9103a0d9c94ea9ba54cb04ed2a2a8 Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Tue, 11 Dec 2018 17:35:26 -0800 Subject: [LRA proof] More complete LRA example proofs. (#2722) * [LRA proof] Refine "poly" and "term Real" distinction Short Version: Refined the LRA signature and used the refined version to write two new test proofs which are close to interface compatible with the LRA proofs that CVC4 will produce. Love Version: LRA proofs have the following interface: * Given predicates between real terms * Prove bottom However, even though the type of the interface does not express this, the predicates are **linear bounds**, not arbitrary real bounds. Thus LRA proofs have the following structure: 1. Prove that the input predicates are equivalent to a set of linear bounds. 2. Use the linear bounds to prove bottom using farkas coefficients. Notice that the distinction between linear bounds (associated in the signature with the string "poly") and real predicates (which relate "term Real"s to one another) matters quite a bit. We have certain inds of axioms for one, and other axioms for the other. The signature used to muddy this distinction using a constructor called "term_poly" which converted between them. I decided it was better to buy into the distinction fully. Now all of the axioms for step (2) use the linear bounds and axioms for step (1) use both kinds of bounds, which makes sense because step (1) is basically a conversion. Also had to add an axiom or two, because some were missing. * Update proofs/signatures/th_lra.plf Co-Authored-By: alex-ozdemir * Improved test readability, removed unused axioms The LRA proof tests did not have appropriate documentation, and did not specify **what** they proved. Now they each have a header comment stating their premises and conclusion, and that conclusion is enforced by a type annotation in the test. The LRA signature included some unused axioms concerning `poly_term`. Now they've been removed. Credits to Yoni for noticing both problems. --- proofs/signatures/th_lra.plf | 195 +++++++++++++++++++------------------- proofs/signatures/th_lra_test.plf | 155 ++++++++++++++++++++++++++++-- 2 files changed, 240 insertions(+), 110 deletions(-) diff --git a/proofs/signatures/th_lra.plf b/proofs/signatures/th_lra.plf index 67b17c9af..76e5127c2 100644 --- a/proofs/signatures/th_lra.plf +++ b/proofs/signatures/th_lra.plf @@ -1,4 +1,22 @@ -; Depends on th_real.plf, th_smt.plf +; Depends on th_real.plf, smt.plf, sat.plf + +; LRA proofs have the following interface: +; * Given predicates between real terms +; * Prove bottom +; +; However, even though the type of the interface does not express this, +; the predicates are **linear bounds**, not arbitrary real bounds. Thus +; LRA proofs have the following structure: +; +; 1. Prove that the input predicates are equivalent to a set of linear +; bounds. +; 2. Use the linear bounds to prove bottom using farkas coefficients. +; +; Notice that the distinction between linear bounds (associated in the signature +; with the string "poly") and real predicates (which relate "term Real"s to one +; another) matters quite a bit. We have certain kinds of axioms for one, and +; other axioms for the other. + (program mpq_ifpos ((x mpq)) bool (mp_ifneg x ff (mp_ifzero x ff tt))) @@ -100,61 +118,65 @@ ;; conversion to use polynomials in term formulas -(declare poly_term (! p poly (term Real))) + +(declare >=0_poly (! x poly formula)) +(declare =0_poly (! x poly formula)) +(declare >0_poly (! x poly formula)) +(declare distinct0_poly (! x poly formula)) ;; create new equality out of inequality (declare lra_>=_>=_to_= (! p1 poly (! p2 poly - (! f1 (th_holds (>=0_Real (poly_term p1))) - (! f2 (th_holds (>=0_Real (poly_term p2))) + (! f1 (th_holds (>=0_poly p1)) + (! f2 (th_holds (>=0_poly p2)) (! i2 (^ (mp_ifzero (is_poly_const (poly_add p1 p2)) tt ff) tt) - (th_holds (=0_Real (poly_term p2))))))))) + (th_holds (=0_poly p2)))))))) ;; axioms (declare lra_axiom_= - (th_holds (=0_Real (poly_term (polyc 0/1 lmonn))))) + (th_holds (=0_poly (polyc 0/1 lmonn)))) (declare lra_axiom_> (! c mpq (! i (^ (mpq_ifpos c) tt) - (th_holds (>0_Real (poly_term (polyc c lmonn))))))) + (th_holds (>0_poly (polyc c lmonn)))))) (declare lra_axiom_>= (! c mpq (! i (^ (mp_ifneg c tt ff) ff) - (th_holds (>=0_Real (poly_term (polyc c lmonn))))))) + (th_holds (>=0_poly (polyc c lmonn)))))) (declare lra_axiom_distinct (! c mpq (! i (^ (mp_ifzero c tt ff) ff) - (th_holds (distinct0_Real (poly_term (polyc c lmonn))))))) + (th_holds (distinct0_poly (polyc c lmonn)))))) ;; contradiction rules (declare lra_contra_= (! p poly - (! f (th_holds (=0_Real (poly_term p))) + (! f (th_holds (=0_poly p)) (! i (^ (mp_ifzero (is_poly_const p) tt ff) ff) (holds cln))))) (declare lra_contra_> (! p poly - (! f (th_holds (>0_Real (poly_term p))) + (! f (th_holds (>0_poly p)) (! i2 (^ (mpq_ifpos (is_poly_const p)) ff) (holds cln))))) (declare lra_contra_>= (! p poly - (! f (th_holds (>=0_Real (poly_term p))) + (! f (th_holds (>=0_poly p)) (! i2 (^ (mp_ifneg (is_poly_const p) tt ff) tt) (holds cln))))) (declare lra_contra_distinct (! p poly - (! f (th_holds (distinct0_Real (poly_term p))) + (! f (th_holds (distinct0_poly p)) (! i2 (^ (mp_ifzero (is_poly_const p) tt ff) tt) (holds cln))))) @@ -164,33 +186,33 @@ (! p poly (! p' poly (! c mpq - (! f (th_holds (=0_Real (poly_term p))) + (! f (th_holds (=0_poly p)) (! i (^ (poly_mul_c p c) p') - (th_holds (=0_Real (poly_term p'))))))))) + (th_holds (=0_poly p')))))))) (declare lra_mul_c_> (! p poly (! p' poly (! c mpq - (! f (th_holds (>0_Real (poly_term p))) + (! f (th_holds (>0_poly p)) (! i (^ (mp_ifneg c (fail poly) (mp_ifzero c (fail poly) (poly_mul_c p c))) p') - (th_holds (>0_Real (poly_term p')))))))));) + (th_holds (>0_poly p')))))))); (declare lra_mul_c_>= (! p poly (! p' poly (! c mpq - (! f (th_holds (>=0_Real (poly_term p))) + (! f (th_holds (>=0_poly p)) (! i (^ (mp_ifneg c (fail poly) (poly_mul_c p c)) p') - (th_holds (>=0_Real (poly_term p')))))))));) + (th_holds (>=0_poly p')))))))) (declare lra_mul_c_distinct (! p poly (! p' poly (! c mpq - (! f (th_holds (distinct0_Real (poly_term p))) + (! f (th_holds (distinct0_poly p)) (! i (^ (mp_ifzero c (fail poly) (poly_mul_c p c)) p') - (th_holds (distinct0_Real (poly_term p')))))))));) + (th_holds (distinct0_poly p')))))))) ;; adding equations @@ -198,64 +220,73 @@ (! p1 poly (! p2 poly (! p3 poly - (! f1 (th_holds (=0_Real (poly_term p1))) - (! f2 (th_holds (=0_Real (poly_term p2))) + (! f1 (th_holds (=0_poly p1)) + (! f2 (th_holds (=0_poly p2)) (! i (^ (poly_add p1 p2) p3) - (th_holds (=0_Real (poly_term p3)))))))))) + (th_holds (=0_poly p3))))))))) (declare lra_add_>_> (! p1 poly (! p2 poly (! p3 poly - (! f1 (th_holds (>0_Real (poly_term p1))) - (! f2 (th_holds (>0_Real (poly_term p2))) + (! f1 (th_holds (>0_poly p1)) + (! f2 (th_holds (>0_poly p2)) (! i (^ (poly_add p1 p2) p3) - (th_holds (>0_Real (poly_term p3)))))))))) + (th_holds (>0_poly p3))))))))) (declare lra_add_>=_>= (! p1 poly (! p2 poly (! p3 poly - (! f1 (th_holds (>=0_Real (poly_term p1))) - (! f2 (th_holds (>=0_Real (poly_term p2))) + (! f1 (th_holds (>=0_poly p1)) + (! f2 (th_holds (>=0_poly p2)) (! i (^ (poly_add p1 p2) p3) - (th_holds (>=0_Real (poly_term p3)))))))))) + (th_holds (>=0_poly p3))))))))) (declare lra_add_=_> (! p1 poly (! p2 poly (! p3 poly - (! f1 (th_holds (=0_Real (poly_term p1))) - (! f2 (th_holds (>0_Real (poly_term p2))) + (! f1 (th_holds (=0_poly p1)) + (! f2 (th_holds (>0_poly p2)) (! i (^ (poly_add p1 p2) p3) - (th_holds (>0_Real (poly_term p3)))))))))) + (th_holds (>0_poly p3))))))))) (declare lra_add_=_>= (! p1 poly (! p2 poly (! p3 poly - (! f1 (th_holds (=0_Real (poly_term p1))) - (! f2 (th_holds (>=0_Real (poly_term p2))) + (! f1 (th_holds (=0_poly p1)) + (! f2 (th_holds (>=0_poly p2)) (! i (^ (poly_add p1 p2) p3) - (th_holds (>=0_Real (poly_term p3)))))))))) + (th_holds (>=0_poly p3))))))))) (declare lra_add_>_>= (! p1 poly (! p2 poly (! p3 poly - (! f1 (th_holds (>0_Real (poly_term p1))) - (! f2 (th_holds (>=0_Real (poly_term p2))) + (! f1 (th_holds (>0_poly p1)) + (! f2 (th_holds (>=0_poly p2)) + (! i (^ (poly_add p1 p2) p3) + (th_holds (>0_poly p3))))))))) + +(declare lra_add_>=_> + (! p1 poly + (! p2 poly + (! p3 poly + (! f1 (th_holds (>=0_poly p1)) + (! f2 (th_holds (>0_poly p2)) (! i (^ (poly_add p1 p2) p3) - (th_holds (>0_Real (poly_term p3)))))))))) + (th_holds (>0_poly p3))))))))) (declare lra_add_=_distinct (! p1 poly (! p2 poly (! p3 poly - (! f1 (th_holds (=0_Real (poly_term p1))) - (! f2 (th_holds (distinct0_Real (poly_term p2))) + (! f1 (th_holds (=0_poly p1)) + (! f2 (th_holds (distinct0_poly p2)) (! i (^ (poly_add p1 p2) p3) - (th_holds (distinct0_Real (poly_term p3)))))))))) + (th_holds (distinct0_poly p3))))))))) ;; substracting equations @@ -263,37 +294,37 @@ (! p1 poly (! p2 poly (! p3 poly - (! f1 (th_holds (=0_Real (poly_term p1))) - (! f2 (th_holds (=0_Real (poly_term p2))) + (! f1 (th_holds (=0_poly p1)) + (! f2 (th_holds (=0_poly p2)) (! i (^ (poly_sub p1 p2) p3) - (th_holds (=0_Real (poly_term p3))))))))))) + (th_holds (=0_poly p3))))))))) (declare lra_sub_>_= (! p1 poly (! p2 poly (! p3 poly - (! f1 (th_holds (>0_Real (poly_term p1))) - (! f2 (th_holds (=0_Real (poly_term p2))) + (! f1 (th_holds (>0_poly p1)) + (! f2 (th_holds (=0_poly p2)) (! i (^ (poly_sub p1 p2) p3) - (th_holds (>0_Real (poly_term p3)))))))))) + (th_holds (>0_poly p3))))))))) (declare lra_sub_>=_= (! p1 poly (! p2 poly (! p3 poly - (! f1 (th_holds (>=0_Real (poly_term p1))) - (! f2 (th_holds (=0_Real (poly_term p2))) + (! f1 (th_holds (>=0_poly p1)) + (! f2 (th_holds (=0_poly p2)) (! i (^ (poly_sub p1 p2) p3) - (th_holds (>=0_Real (poly_term p3)))))))))) + (th_holds (>=0_poly p3))))))))) (declare lra_sub_distinct_= (! p1 poly (! p2 poly (! p3 poly - (! f1 (th_holds (distinct0_Real (poly_term p1))) - (! f2 (th_holds (=0_Real (poly_term p2))) + (! f1 (th_holds (distinct0_poly p1)) + (! f2 (th_holds (=0_poly p2)) (! i (^ (poly_sub p1 p2) p3) - (th_holds (distinct0_Real (poly_term p3))))))))))) + (th_holds (distinct0_poly p3))))))))) ;; converting between terms and polynomials @@ -357,6 +388,14 @@ (! a (^ (poly_mul_c py x) pz) (poly_norm (*_Real y (a_real x)) pz)))))))) +(declare poly_flip_not_>= + (! p poly + (! p_negged poly + (! pf_formula (th_holds (not (>=0_poly p))) + (! sc (^ (poly_neg p) p_negged) + (th_holds (>0_poly p_negged))))))) + + ;; for polynomializing other terms, in particular ite's (declare term_atom (! v var_real (! t (term Real) type))) @@ -395,54 +434,10 @@ (! u (th_holds (not ft)) (th_holds (not fp))))))) -; form equivalence between term formula and polynomial formula - -(declare poly_norm_= - (! x (term Real) - (! y (term Real) - (! p poly - (! h (th_holds (= Real x y)) - (! n (poly_norm (-_Real x y) p) - (! u (! pn (th_holds (=0_Real (poly_term p))) - (holds cln)) - (holds cln)))))))) - -(declare poly_norm_> +(declare poly_formula_norm_>= (! x (term Real) (! y (term Real) (! p poly - (! h (th_holds (>_Real x y)) - (! n (poly_norm (-_Real x y) p) - (! u (! pn (th_holds (>0_Real (poly_term p))) - (holds cln)) - (holds cln)))))))) - -(declare poly_norm_< - (! x (term Real) - (! y (term Real) - (! p poly - (! h (th_holds (<_Real x y)) (! n (poly_norm (-_Real y x) p) - (! u (! pn (th_holds (>0_Real (poly_term p))) - (holds cln)) - (holds cln)))))))) - -(declare poly_norm_>= - (! x (term Real) - (! y (term Real) - (! p poly - (! h (th_holds (>=_Real x y)) - (! n (poly_norm (-_Real x y) p) - (! u (! pn (th_holds (>=0_Real (poly_term p))) - (holds cln)) - (holds cln)))))))) + (poly_formula_norm (>=_Real y x) (>=0_poly p))))))) -(declare poly_norm_<= - (! x (term Real) - (! y (term Real) - (! p poly - (! h (th_holds (<=_Real x y)) - (! n (poly_norm (-_Real y x) p) - (! u (! pn (th_holds (>=0_Real (poly_term p))) - (holds cln)) - (holds cln)))))))) diff --git a/proofs/signatures/th_lra_test.plf b/proofs/signatures/th_lra_test.plf index 687ff988b..fb3ca828c 100644 --- a/proofs/signatures/th_lra_test.plf +++ b/proofs/signatures/th_lra_test.plf @@ -1,4 +1,10 @@ ; Depends On: th_lra.plf +;; Proof (from predicates on linear polynomials) that the following imply bottom +; +; -x - 1/2 y + 2 >= 0 +; x + y - 8 >= 0 +; x - y + 0 >= 0 +; (check ; Variables (% x var_real @@ -11,22 +17,151 @@ (@ p1 (polyc 2/1 m1) (@ p2 (polyc (~ 8/1) m2) (@ p3 (polyc 0/1 m3) - (% pf_nonneg_1 (th_holds (>=0_Real (poly_term p1))) - (% pf_nonneg_2 (th_holds (>=0_Real (poly_term p2))) - (% pf_nonneg_3 (th_holds (>=0_Real (poly_term p3))) - (lra_contra_>= - _ - (lra_add_>=_>= _ _ _ - (lra_mul_c_>= _ _ 4/1 pf_nonneg_1) + (% pf_nonneg_1 (th_holds (>=0_poly p1)) + (% pf_nonneg_2 (th_holds (>=0_poly p2)) + (% pf_nonneg_3 (th_holds (>=0_poly p3)) + (: + (holds cln) + (lra_contra_>= + _ (lra_add_>=_>= _ _ _ - (lra_mul_c_>= _ _ 3/1 pf_nonneg_2) + (lra_mul_c_>= _ _ 4/1 pf_nonneg_1) (lra_add_>=_>= _ _ _ - (lra_mul_c_>= _ _ 1/1 pf_nonneg_3) - (lra_axiom_>= 0/1))))) + (lra_mul_c_>= _ _ 3/1 pf_nonneg_2) + (lra_add_>=_>= _ _ _ + (lra_mul_c_>= _ _ 1/1 pf_nonneg_3) + (lra_axiom_>= 0/1)))))) ))))) )))) )) ) +;; Proof (from predicates on real terms) that the following imply bottom +; +; -x - 1/2 y >= 2 +; x + y >= 8 +; x - y >= 0 +; +(check + ; Declarations + ; Variables + (% x var_real + (% y var_real + ; real predicates + (@ f1 (>=_Real (+_Real (*_Real (a_real (~ 1/1)) (a_var_real x)) (*_Real (a_real (~ 1/2)) (a_var_real y))) (a_real (~ 2/1))) + (@ f2 (>=_Real (+_Real (*_Real (a_real 1/1) (a_var_real x)) (*_Real (a_real 1/1) (a_var_real y))) (a_real 8/1)) + (@ f3 (>=_Real (+_Real (*_Real (a_real 1/1) (a_var_real x)) (*_Real (a_real (~ 1/1)) (a_var_real y))) (a_real 0/1)) + ; proof of real predicates + (% pf_f1 (th_holds f1) + (% pf_f2 (th_holds f2) + (% pf_f3 (th_holds f3) + + + ; Normalization + ; real term -> linear polynomial normalization witnesses + (@ n1 (poly_formula_norm_>= _ _ _ + (pn_- _ _ _ _ _ + (pn_+ _ _ _ _ _ + (pn_mul_c_L _ _ _ (~ 1/1) (pn_var x)) + (pn_mul_c_L _ _ _ (~ 1/2) (pn_var y))) + (pn_const (~ 2/1)))) + (@ n2 (poly_formula_norm_>= _ _ _ + (pn_- _ _ _ _ _ + (pn_+ _ _ _ _ _ + (pn_mul_c_L _ _ _ 1/1 (pn_var x)) + (pn_mul_c_L _ _ _ 1/1 (pn_var y))) + (pn_const 8/1))) + (@ n3 (poly_formula_norm_>= _ _ _ + (pn_- _ _ _ _ _ + (pn_+ _ _ _ _ _ + (pn_mul_c_L _ _ _ 1/1 (pn_var x)) + (pn_mul_c_L _ _ _ (~ 1/1) (pn_var y))) + (pn_const 0/1))) + ; proof of linear polynomial predicates + (@ pf_n1 (poly_form _ _ n1 pf_f1) + (@ pf_n2 (poly_form _ _ n2 pf_f2) + (@ pf_n3 (poly_form _ _ n3 pf_f3) + + ; derivation of a contradiction using farkas coefficients + (: + (holds cln) + (lra_contra_>= _ + (lra_add_>=_>= _ _ _ + (lra_mul_c_>= _ _ 4/1 pf_n1) + (lra_add_>=_>= _ _ _ + (lra_mul_c_>= _ _ 3/1 pf_n2) + (lra_add_>=_>= _ _ _ + (lra_mul_c_>= _ _ 1/1 pf_n3) + (lra_axiom_>= 0/1)))))) + ))) + ))) + ))) + ))) + )) +) + +;; Term proof, 2 (>=), one (not >=) +;; Proof (from predicates on real terms) that the following imply bottom +; +; -x + y >= 2 +; x + y >= 2 +; not[ y >= -2] => [y < -2] => [-y > 2] +; +(check + ; Declarations + ; Variables + (% x var_real + (% y var_real + ; real predicates + (@ f1 (>=_Real + (+_Real (*_Real (a_real (~ 1/1)) (a_var_real x)) (a_var_real y)) + (a_real 2/1)) + (@ f2 (>=_Real + (+_Real (a_var_real x) (a_var_real y)) + (a_real 2/1)) + (@ f3 (not (>=_Real (a_var_real y) (a_real (~ 2/1)))) + ; Normalization + ; proof of real predicates + (% pf_f1 (th_holds f1) + (% pf_f2 (th_holds f2) + (% pf_f3 (th_holds f3) + ; real term -> linear polynomial normalization witnesses + (@ n1 (poly_formula_norm_>= _ _ _ + (pn_- _ _ _ _ _ + (pn_+ _ _ _ _ _ + (pn_mul_c_L _ _ _ (~ 1/1) (pn_var x)) + (pn_var y)) + (pn_const 2/1))) + (@ n2 (poly_formula_norm_>= _ _ _ + (pn_- _ _ _ _ _ + (pn_+ _ _ _ _ _ + (pn_var x) + (pn_var y)) + (pn_const 2/1))) + (@ n3 (poly_formula_norm_>= _ _ _ + (pn_- _ _ _ _ _ + (pn_var y) + (pn_const (~ 2/1)))) + ; proof of linear polynomial predicates + (@ pf_n1 (poly_form _ _ n1 pf_f1) + (@ pf_n2 (poly_form _ _ n2 pf_f2) + (@ pf_n3 (poly_flip_not_>= _ _ (poly_form_not _ _ n3 pf_f3)) + ; derivation of a contradiction using farkas coefficients + (: + (holds cln) + (lra_contra_> _ + (lra_add_>=_> _ _ _ + (lra_mul_c_>= _ _ 1/1 pf_n1) + (lra_add_>=_> _ _ _ + (lra_mul_c_>= _ _ 1/1 pf_n2) + (lra_add_>_>= _ _ _ + (lra_mul_c_> _ _ 2/1 pf_n3) + (lra_axiom_>= 0/1)))))) + ))) + ))) + ))) + ))) + )) +) -- cgit v1.2.3 From 12f88ad664c24ee522643073dcddf144854ca1ef Mon Sep 17 00:00:00 2001 From: Andres Noetzli Date: Wed, 12 Dec 2018 23:19:30 +0000 Subject: API: Add simple empty/sigma regexp unit tests (#2746) --- test/unit/api/solver_black.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/unit/api/solver_black.h b/test/unit/api/solver_black.h index 538899a0f..7527a5c55 100644 --- a/test/unit/api/solver_black.h +++ b/test/unit/api/solver_black.h @@ -36,6 +36,8 @@ class SolverBlack : public CxxTest::TestSuite void testDefineFun(); void testDefineFunRec(); void testDefineFunsRec(); + void testMkRegexpEmpty(); + void testMkRegexpSigma(); private: Solver d_solver; @@ -228,3 +230,19 @@ void SolverBlack::testDefineFunsRec() d_solver.defineFunsRec({f1, f2}, {{b1, b11}, {b4}}, {v1, v4}), CVC4ApiException&); } + +void SolverBlack::testMkRegexpEmpty() +{ + Sort strSort = d_solver.getStringSort(); + Term s = d_solver.mkVar("s", strSort); + TS_ASSERT_THROWS_NOTHING( + d_solver.mkTerm(STRING_IN_REGEXP, s, d_solver.mkRegexpEmpty())); +} + +void SolverBlack::testMkRegexpSigma() +{ + Sort strSort = d_solver.getStringSort(); + Term s = d_solver.mkVar("s", strSort); + TS_ASSERT_THROWS_NOTHING( + d_solver.mkTerm(STRING_IN_REGEXP, s, d_solver.mkRegexpSigma())); +} -- cgit v1.2.3 From c2be681200406d8a96a1c2e1b9fbbb228334eed8 Mon Sep 17 00:00:00 2001 From: Aina Niemetz Date: Wed, 12 Dec 2018 16:37:59 -0800 Subject: Fix compiler warnings. (#2748) --- src/theory/bv/theory_bv_rewrite_rules_simplification.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/theory/bv/theory_bv_rewrite_rules_simplification.h b/src/theory/bv/theory_bv_rewrite_rules_simplification.h index 7efdc2c81..c58d69f6f 100644 --- a/src/theory/bv/theory_bv_rewrite_rules_simplification.h +++ b/src/theory/bv/theory_bv_rewrite_rules_simplification.h @@ -535,7 +535,7 @@ inline Node RewriteRule::apply(TNode node) { Debug("bv-rewrite") << "RewriteRule(" << node << ")" << std::endl; - uint32_t m, my, mz, n; + uint32_t m, my, mz; size_t nc; Kind kind = node.getKind(); TNode concat; @@ -589,7 +589,9 @@ inline Node RewriteRule::apply(TNode node) z = nc > 1 ? zb.constructNode() : zb[0]; } m = utils::getSize(x); - n = utils::getSize(c); +#ifdef CVC4_ASSERTIONS + uint32_t n = utils::getSize(c); +#endif my = y.isNull() ? 0 : utils::getSize(y); mz = z.isNull() ? 0 : utils::getSize(z); Assert(mz == m - my - n); -- cgit v1.2.3 From f038f308e044bd1e842996e891e3cb119825113a Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Thu, 13 Dec 2018 12:03:16 -0600 Subject: Remove spurious map (#2750) --- src/theory/quantifiers/sygus/sygus_unif_io.cpp | 150 +++++++++++-------------- 1 file changed, 68 insertions(+), 82 deletions(-) diff --git a/src/theory/quantifiers/sygus/sygus_unif_io.cpp b/src/theory/quantifiers/sygus/sygus_unif_io.cpp index 0b378875c..c9db62735 100644 --- a/src/theory/quantifiers/sygus/sygus_unif_io.cpp +++ b/src/theory/quantifiers/sygus/sygus_unif_io.cpp @@ -1323,7 +1323,6 @@ Node SygusUnifIo::constructSol( Trace("sygus-sui-dt") << "...try STRATEGY " << strat << "..." << std::endl; - std::map look_ahead_solved_children; std::vector dt_children_cons; bool success = true; @@ -1338,108 +1337,95 @@ Node SygusUnifIo::constructSol( Trace("sygus-sui-dt") << "construct PBE child #" << sc << "..." << std::endl; Node rec_c; - std::map::iterator itla = - look_ahead_solved_children.find(sc); - if (itla != look_ahead_solved_children.end()) + + std::pair& cenum = etis->d_cenum[sc]; + + // update the context + std::vector prev; + if (strat == strat_ITE && sc > 0) { - rec_c = itla->second; - indent("sygus-sui-dt-debug", ind + 1); - Trace("sygus-sui-dt-debug") - << "ConstructPBE: look ahead solved : " - << d_tds->sygusToBuiltin(rec_c) << std::endl; + EnumCache& ecache_cond = d_ecache[split_cond_enum]; + Assert(set_split_cond_res_index); + Assert(split_cond_res_index < ecache_cond.d_enum_vals_res.size()); + prev = x.d_vals; + x.updateContext(this, + ecache_cond.d_enum_vals_res[split_cond_res_index], + sc == 1); + // return value of above call may be false in corner cases where we + // must choose a non-separating condition to traverse to another + // strategy node } - else - { - std::pair& cenum = etis->d_cenum[sc]; - // update the context - std::vector prev; - if (strat == strat_ITE && sc > 0) - { - EnumCache& ecache_cond = d_ecache[split_cond_enum]; - Assert(set_split_cond_res_index); - Assert(split_cond_res_index < ecache_cond.d_enum_vals_res.size()); - prev = x.d_vals; - x.updateContext(this, - ecache_cond.d_enum_vals_res[split_cond_res_index], - sc == 1); - // return value of above call may be false in corner cases where we - // must choose a non-separating condition to traverse to another - // strategy node - } - - // recurse - if (strat == strat_ITE && sc == 0) - { - Node ce = cenum.first; + // recurse + if (strat == strat_ITE && sc == 0) + { + Node ce = cenum.first; - EnumCache& ecache_child = d_ecache[ce]; + EnumCache& ecache_child = d_ecache[ce]; - // get the conditionals in the current context : they must be - // distinguishable - std::map > possible_cond; - std::map solved_cond; // stores branch - ecache_child.d_term_trie.getLeaves(x.d_vals, true, possible_cond); + // get the conditionals in the current context : they must be + // distinguishable + std::map > possible_cond; + std::map solved_cond; // stores branch + ecache_child.d_term_trie.getLeaves(x.d_vals, true, possible_cond); - std::map>::iterator itpc = - possible_cond.find(0); - if (itpc != possible_cond.end()) + std::map>::iterator itpc = + possible_cond.find(0); + if (itpc != possible_cond.end()) + { + if (Trace.isOn("sygus-sui-dt-debug")) { - if (Trace.isOn("sygus-sui-dt-debug")) + indent("sygus-sui-dt-debug", ind + 1); + Trace("sygus-sui-dt-debug") + << "PBE : We have " << itpc->second.size() + << " distinguishable conditionals:" << std::endl; + for (Node& cond : itpc->second) { - indent("sygus-sui-dt-debug", ind + 1); + indent("sygus-sui-dt-debug", ind + 2); Trace("sygus-sui-dt-debug") - << "PBE : We have " << itpc->second.size() - << " distinguishable conditionals:" << std::endl; - for (Node& cond : itpc->second) - { - indent("sygus-sui-dt-debug", ind + 2); - Trace("sygus-sui-dt-debug") - << d_tds->sygusToBuiltin(cond) << std::endl; - } - } - if (rec_c.isNull()) - { - rec_c = constructBestConditional(ce, itpc->second); - Assert(!rec_c.isNull()); - indent("sygus-sui-dt", ind); - Trace("sygus-sui-dt") - << "PBE: ITE strategy : choose best conditional " - << d_tds->sygusToBuiltin(rec_c) << std::endl; + << d_tds->sygusToBuiltin(cond) << std::endl; } } - else + if (rec_c.isNull()) { - // TODO (#1250) : degenerate case where children have different - // types? + rec_c = constructBestConditional(ce, itpc->second); + Assert(!rec_c.isNull()); indent("sygus-sui-dt", ind); - Trace("sygus-sui-dt") << "return PBE: failed ITE strategy, " - "cannot find a distinguishable condition" - << std::endl; - } - if (!rec_c.isNull()) - { - Assert(ecache_child.d_enum_val_to_index.find(rec_c) - != ecache_child.d_enum_val_to_index.end()); - split_cond_res_index = ecache_child.d_enum_val_to_index[rec_c]; - set_split_cond_res_index = true; - split_cond_enum = ce; - Assert(split_cond_res_index - < ecache_child.d_enum_vals_res.size()); + Trace("sygus-sui-dt") + << "PBE: ITE strategy : choose best conditional " + << d_tds->sygusToBuiltin(rec_c) << std::endl; } } else { - did_recurse = true; - rec_c = constructSol(f, cenum.first, cenum.second, ind + 2, lemmas); + // TODO (#1250) : degenerate case where children have different + // types? + indent("sygus-sui-dt", ind); + Trace("sygus-sui-dt") << "return PBE: failed ITE strategy, " + "cannot find a distinguishable condition" + << std::endl; } - - // undo update the context - if (strat == strat_ITE && sc > 0) + if (!rec_c.isNull()) { - x.d_vals = prev; + Assert(ecache_child.d_enum_val_to_index.find(rec_c) + != ecache_child.d_enum_val_to_index.end()); + split_cond_res_index = ecache_child.d_enum_val_to_index[rec_c]; + set_split_cond_res_index = true; + split_cond_enum = ce; + Assert(split_cond_res_index + < ecache_child.d_enum_vals_res.size()); } } + else + { + did_recurse = true; + rec_c = constructSol(f, cenum.first, cenum.second, ind + 2, lemmas); + } + // undo update the context + if (strat == strat_ITE && sc > 0) + { + x.d_vals = prev; + } if (!rec_c.isNull()) { dt_children_cons.push_back(rec_c); -- cgit v1.2.3 From bc59b160f3890f68c497dde13ff54c194f476eb4 Mon Sep 17 00:00:00 2001 From: Aina Niemetz Date: Thu, 13 Dec 2018 13:17:22 -0800 Subject: New C++ API: Add tests for sort functions of solver object. (#2752) --- src/api/cvc4cpp.cpp | 1 + test/unit/api/solver_black.h | 99 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/src/api/cvc4cpp.cpp b/src/api/cvc4cpp.cpp index b4d3b013d..cadad4eff 100644 --- a/src/api/cvc4cpp.cpp +++ b/src/api/cvc4cpp.cpp @@ -1750,6 +1750,7 @@ Sort Solver::mkUninterpretedSort(const std::string& symbol) const Sort Solver::mkSortConstructorSort(const std::string& symbol, size_t arity) const { + CVC4_API_ARG_CHECK_EXPECTED(arity > 0, arity) << "an arity > 0"; return d_exprMgr->mkSortConstructor(symbol, arity); } diff --git a/test/unit/api/solver_black.h b/test/unit/api/solver_black.h index 7527a5c55..b0249b8a0 100644 --- a/test/unit/api/solver_black.h +++ b/test/unit/api/solver_black.h @@ -26,16 +26,31 @@ class SolverBlack : public CxxTest::TestSuite void setUp() override; void tearDown() override; + void testGetBooleanSort(); + void testGetIntegerSort(); + void testGetRealSort(); + void testGetRegExpSort(); + void testGetStringSort(); + void testGetRoundingmodeSort(); + + void testMkArraySort(); void testMkBitVectorSort(); void testMkFloatingPointSort(); void testMkDatatypeSort(); void testMkFunctionSort(); + void testMkParamSort(); void testMkPredicateSort(); + void testMkRecordSort(); + void testMkSetSort(); + void testMkSortConstructorSort(); + void testMkUninterpretedSort(); void testMkTupleSort(); + void testDeclareFun(); void testDefineFun(); void testDefineFunRec(); void testDefineFunsRec(); + void testMkRegexpEmpty(); void testMkRegexpSigma(); @@ -47,6 +62,53 @@ void SolverBlack::setUp() {} void SolverBlack::tearDown() {} +void SolverBlack::testGetBooleanSort() +{ + TS_ASSERT_THROWS_NOTHING(d_solver.getBooleanSort()); +} + +void SolverBlack::testGetIntegerSort() +{ + TS_ASSERT_THROWS_NOTHING(d_solver.getIntegerSort()); +} + +void SolverBlack::testGetRealSort() +{ + TS_ASSERT_THROWS_NOTHING(d_solver.getRealSort()); +} + +void SolverBlack::testGetRegExpSort() +{ + TS_ASSERT_THROWS_NOTHING(d_solver.getRegExpSort()); +} + +void SolverBlack::testGetStringSort() +{ + TS_ASSERT_THROWS_NOTHING(d_solver.getStringSort()); +} + +void SolverBlack::testGetRoundingmodeSort() +{ + TS_ASSERT_THROWS_NOTHING(d_solver.getRoundingmodeSort()); +} + +void SolverBlack::testMkArraySort() +{ + Sort boolSort = d_solver.getBooleanSort(); + 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)); +} + void SolverBlack::testMkBitVectorSort() { TS_ASSERT_THROWS_NOTHING(d_solver.mkBitVectorSort(32)); @@ -99,6 +161,12 @@ void SolverBlack::testMkFunctionSort() CVC4ApiException&); } +void SolverBlack::testMkParamSort() +{ + TS_ASSERT_THROWS_NOTHING(d_solver.mkParamSort("T")); + TS_ASSERT_THROWS_NOTHING(d_solver.mkParamSort("")); +} + void SolverBlack::testMkPredicateSort() { TS_ASSERT_THROWS_NOTHING( @@ -111,6 +179,37 @@ void SolverBlack::testMkPredicateSort() CVC4ApiException&); } +void SolverBlack::testMkRecordSort() +{ + std::vector> fields = { + std::make_pair("b", d_solver.getBooleanSort()), + std::make_pair("bv", d_solver.mkBitVectorSort(8)), + std::make_pair("i", d_solver.getIntegerSort())}; + std::vector> empty; + TS_ASSERT_THROWS_NOTHING(d_solver.mkRecordSort(fields)); + TS_ASSERT_THROWS_NOTHING(d_solver.mkRecordSort(empty)); +} + +void SolverBlack::testMkSetSort() +{ + TS_ASSERT_THROWS_NOTHING(d_solver.mkSetSort(d_solver.getBooleanSort())); + TS_ASSERT_THROWS_NOTHING(d_solver.mkSetSort(d_solver.getIntegerSort())); + TS_ASSERT_THROWS_NOTHING(d_solver.mkSetSort(d_solver.mkBitVectorSort(4))); +} + +void SolverBlack::testMkUninterpretedSort() +{ + TS_ASSERT_THROWS_NOTHING(d_solver.mkUninterpretedSort("u")); + TS_ASSERT_THROWS_NOTHING(d_solver.mkUninterpretedSort("")); +} + +void SolverBlack::testMkSortConstructorSort() +{ + TS_ASSERT_THROWS_NOTHING(d_solver.mkSortConstructorSort("s", 2)); + TS_ASSERT_THROWS_NOTHING(d_solver.mkSortConstructorSort("", 2)); + TS_ASSERT_THROWS(d_solver.mkSortConstructorSort("", 0), CVC4ApiException&); +} + void SolverBlack::testMkTupleSort() { TS_ASSERT_THROWS_NOTHING(d_solver.mkTupleSort({d_solver.getIntegerSort()})); -- cgit v1.2.3 From 000feaeb02292d7a2873198664022801b12e5151 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Thu, 13 Dec 2018 18:39:26 -0600 Subject: Make single invocation and invariant pre/post condition templates independent (#2749) --cegqi-si=none previously disabled pre/post-condition templates for invariant synthesis. This PR eliminates this dependency. There are no major code changes in this PR, unfortunately a large block of code changed indentation so I refactored it to be more up to date with the coding guidelines. --- .../quantifiers/sygus/ce_guided_single_inv.cpp | 318 ++++++++++++--------- 1 file changed, 177 insertions(+), 141 deletions(-) diff --git a/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp b/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp index d4735b3d8..aa20c1f76 100644 --- a/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp +++ b/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp @@ -138,159 +138,195 @@ void CegSingleInv::initialize(Node q) } } // compute single invocation partition - if( options::cegqiSingleInvMode()!=CEGQI_SI_MODE_NONE ){ - Node qq; - if( q[1].getKind()==NOT && q[1][0].getKind()==FORALL ){ - qq = q[1][0][1]; - }else{ - qq = TermUtil::simpleNegate( q[1] ); - } - //process the single invocation-ness of the property - if( !d_sip->init( progs, qq ) ){ - Trace("cegqi-si") << "...not single invocation (type mismatch)" << std::endl; - }else{ - Trace("cegqi-si") << "- Partitioned to single invocation parts : " << std::endl; - d_sip->debugPrint( "cegqi-si" ); + Node qq; + if (q[1].getKind() == NOT && q[1][0].getKind() == FORALL) + { + qq = q[1][0][1]; + } + else + { + qq = TermUtil::simpleNegate(q[1]); + } + // process the single invocation-ness of the property + if (!d_sip->init(progs, qq)) + { + Trace("cegqi-si") << "...not single invocation (type mismatch)" + << std::endl; + return; + } + Trace("cegqi-si") << "- Partitioned to single invocation parts : " + << std::endl; + d_sip->debugPrint("cegqi-si"); + + // map from program to bound variables + std::vector funcs; + d_sip->getFunctions(funcs); + for (unsigned j = 0, size = funcs.size(); j < size; j++) + { + Assert(std::find(progs.begin(), progs.end(), funcs[j]) != progs.end()); + d_prog_to_sol_index[funcs[j]] = j; + } - //map from program to bound variables - std::vector funcs; - d_sip->getFunctions(funcs); - for (unsigned j = 0, size = funcs.size(); j < size; j++) + // check if it is single invocation + if (d_sip->isPurelySingleInvocation()) + { + // We are fully single invocation, set single invocation if we haven't + // disabled single invocation techniques. + if (options::cegqiSingleInvMode() != CEGQI_SI_MODE_NONE) + { + d_single_invocation = true; + return; + } + } + // We are processing without single invocation techniques, now check if + // we should fix an invariant template (post-condition strengthening or + // pre-condition weakening). + SygusInvTemplMode tmode = options::sygusInvTemplMode(); + if (tmode != SYGUS_INV_TEMPL_MODE_NONE) + { + // currently only works for single predicate synthesis + if (q[0].getNumChildren() > 1 || !q[0][0].getType().isPredicate()) + { + tmode = SYGUS_INV_TEMPL_MODE_NONE; + } + else if (!options::sygusInvTemplWhenSyntax()) + { + // only use invariant templates if no syntactic restrictions + if (CegGrammarConstructor::hasSyntaxRestrictions(q)) { - Assert(std::find(progs.begin(), progs.end(), funcs[j]) != progs.end()); - d_prog_to_sol_index[funcs[j]] = j; + tmode = SYGUS_INV_TEMPL_MODE_NONE; } + } + } + + if (tmode == SYGUS_INV_TEMPL_MODE_NONE) + { + // not processing invariant templates + return; + } + // if we are doing invariant templates, then construct the template + Trace("cegqi-si") << "- Do transition inference..." << std::endl; + d_ti[q].process(qq); + Trace("cegqi-inv") << std::endl; + if (d_ti[q].d_func.isNull()) + { + // the invariant could not be inferred + return; + } + NodeManager* nm = NodeManager::currentNM(); + // map the program back via non-single invocation map + Node prog = d_ti[q].d_func; + std::vector prog_templ_vars; + prog_templ_vars.insert( + prog_templ_vars.end(), d_ti[q].d_vars.begin(), d_ti[q].d_vars.end()); + d_trans_pre[prog] = d_ti[q].getComponent(1); + d_trans_post[prog] = d_ti[q].getComponent(-1); + Trace("cegqi-inv") << " precondition : " << d_trans_pre[prog] << std::endl; + Trace("cegqi-inv") << " postcondition : " << d_trans_post[prog] << std::endl; + std::vector sivars; + d_sip->getSingleInvocationVariables(sivars); + Node invariant = d_sip->getFunctionInvocationFor(prog); + Assert(!invariant.isNull()); + invariant = invariant.substitute(sivars.begin(), + sivars.end(), + prog_templ_vars.begin(), + prog_templ_vars.end()); + Trace("cegqi-inv") << " invariant : " << invariant << std::endl; - //check if it is single invocation - if (!d_sip->isPurelySingleInvocation()) + // store simplified version of quantified formula + d_simp_quant = d_sip->getFullSpecification(); + std::vector new_bv; + for( const Node& v : sivars ) + { + new_bv.push_back(nm->mkBoundVar(v.getType())); + } + d_simp_quant = d_simp_quant.substitute( + sivars.begin(), sivars.end(), new_bv.begin(), new_bv.end()); + Assert(q[1].getKind() == NOT && q[1][0].getKind() == FORALL); + for (const Node& v : q[1][0][0]) + { + new_bv.push_back(v); + } + d_simp_quant = + nm->mkNode(FORALL, nm->mkNode(BOUND_VAR_LIST, new_bv), d_simp_quant) + .negate(); + d_simp_quant = Rewriter::rewrite(d_simp_quant); + d_simp_quant = nm->mkNode(FORALL, q[0], d_simp_quant, q[2]); + Trace("cegqi-si") << "Rewritten quantifier : " << d_simp_quant << std::endl; + + // construct template argument + d_templ_arg[prog] = nm->mkSkolem("I", invariant.getType()); + + // construct template + Node templ; + if (options::sygusInvAutoUnfold()) + { + if (d_ti[q].isComplete()) + { + Trace("cegqi-inv-auto-unfold") + << "Automatic deterministic unfolding... " << std::endl; + // auto-unfold + DetTrace dt; + int init_dt = d_ti[q].initializeTrace(dt); + if (init_dt == 0) { - SygusInvTemplMode tmode = options::sygusInvTemplMode(); - if (tmode != SYGUS_INV_TEMPL_MODE_NONE) + Trace("cegqi-inv-auto-unfold") << " Init : "; + dt.print("cegqi-inv-auto-unfold"); + Trace("cegqi-inv-auto-unfold") << std::endl; + unsigned counter = 0; + unsigned status = 0; + while (counter < 100 && status == 0) { - // currently only works for single predicate synthesis - if (q[0].getNumChildren() > 1 || !q[0][0].getType().isPredicate()) - { - tmode = SYGUS_INV_TEMPL_MODE_NONE; - } - else if (!options::sygusInvTemplWhenSyntax()) - { - // only use invariant templates if no syntactic restrictions - if (CegGrammarConstructor::hasSyntaxRestrictions(q)) - { - tmode = SYGUS_INV_TEMPL_MODE_NONE; - } - } + status = d_ti[q].incrementTrace(dt); + counter++; + Trace("cegqi-inv-auto-unfold") << " #" << counter << " : "; + dt.print("cegqi-inv-auto-unfold"); + Trace("cegqi-inv-auto-unfold") + << "...status = " << status << std::endl; } - - if (tmode != SYGUS_INV_TEMPL_MODE_NONE) + if (status == 1) { - //if we are doing invariant templates, then construct the template - Trace("cegqi-si") << "- Do transition inference..." << std::endl; - d_ti[q].process( qq ); - Trace("cegqi-inv") << std::endl; - if( !d_ti[q].d_func.isNull() ){ - // map the program back via non-single invocation map - Node prog = d_ti[q].d_func; - std::vector< Node > prog_templ_vars; - prog_templ_vars.insert( prog_templ_vars.end(), d_ti[q].d_vars.begin(), d_ti[q].d_vars.end() ); - d_trans_pre[prog] = d_ti[q].getComponent( 1 ); - d_trans_post[prog] = d_ti[q].getComponent( -1 ); - Trace("cegqi-inv") << " precondition : " << d_trans_pre[prog] << std::endl; - Trace("cegqi-inv") << " postcondition : " << d_trans_post[prog] << std::endl; - std::vector sivars; - d_sip->getSingleInvocationVariables(sivars); - Node invariant = d_sip->getFunctionInvocationFor(prog); - Assert(!invariant.isNull()); - invariant = invariant.substitute(sivars.begin(), - sivars.end(), - prog_templ_vars.begin(), - prog_templ_vars.end()); - Trace("cegqi-inv") << " invariant : " << invariant << std::endl; - - // store simplified version of quantified formula - d_simp_quant = d_sip->getFullSpecification(); - std::vector< Node > new_bv; - for (unsigned j = 0, size = sivars.size(); j < size; j++) - { - new_bv.push_back( - NodeManager::currentNM()->mkBoundVar(sivars[j].getType())); - } - d_simp_quant = d_simp_quant.substitute( - sivars.begin(), sivars.end(), new_bv.begin(), new_bv.end()); - Assert( q[1].getKind()==NOT && q[1][0].getKind()==FORALL ); - for( unsigned j=0; jmkNode( kind::FORALL, NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, new_bv ), d_simp_quant ).negate(); - d_simp_quant = Rewriter::rewrite( d_simp_quant ); - d_simp_quant = NodeManager::currentNM()->mkNode( kind::FORALL, q[0], d_simp_quant, q[2] ); - Trace("cegqi-si") << "Rewritten quantifier : " << d_simp_quant << std::endl; - - //construct template argument - d_templ_arg[prog] = NodeManager::currentNM()->mkSkolem( "I", invariant.getType() ); - - //construct template - Node templ; - if( options::sygusInvAutoUnfold() ){ - if( d_ti[q].isComplete() ){ - Trace("cegqi-inv-auto-unfold") << "Automatic deterministic unfolding... " << std::endl; - // auto-unfold - DetTrace dt; - int init_dt = d_ti[q].initializeTrace( dt ); - if( init_dt==0 ){ - Trace("cegqi-inv-auto-unfold") << " Init : "; - dt.print("cegqi-inv-auto-unfold"); - Trace("cegqi-inv-auto-unfold") << std::endl; - unsigned counter = 0; - unsigned status = 0; - while( counter<100 && status==0 ){ - status = d_ti[q].incrementTrace( dt ); - counter++; - Trace("cegqi-inv-auto-unfold") << " #" << counter << " : "; - dt.print("cegqi-inv-auto-unfold"); - Trace("cegqi-inv-auto-unfold") << "...status = " << status << std::endl; - } - if( status==1 ){ - // we have a trivial invariant - templ = d_ti[q].constructFormulaTrace( dt ); - Trace("cegqi-inv") << "By finite deterministic terminating trace, a solution invariant is : " << std::endl; - Trace("cegqi-inv") << " " << templ << std::endl; - // FIXME : this should be unnecessary - templ = NodeManager::currentNM()->mkNode( AND, templ, d_templ_arg[prog] ); - } - }else{ - Trace("cegqi-inv-auto-unfold") << "...failed initialize." << std::endl; - } - } - } - Trace("cegqi-inv") << "Make the template... " << tmode << " " - << templ << std::endl; - if( templ.isNull() ){ - if (tmode == SYGUS_INV_TEMPL_MODE_PRE) - { - //d_templ[prog] = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ), d_trans_post[prog] ); - templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], d_templ_arg[prog] ); - }else{ - Assert(tmode == SYGUS_INV_TEMPL_MODE_POST); - //d_templ[prog] = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ) ); - templ = NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], d_templ_arg[prog] ); - } - } - Trace("cegqi-inv") << " template (pre-substitution) : " << templ << std::endl; - Assert( !templ.isNull() ); - // subsitute the template arguments - Assert(prog_templ_vars.size() == prog_vars[prog].size()); - templ = templ.substitute( prog_templ_vars.begin(), prog_templ_vars.end(), prog_vars[prog].begin(), prog_vars[prog].end() ); - Trace("cegqi-inv") << " template : " << templ << std::endl; - d_templ[prog] = templ; - } + // we have a trivial invariant + templ = d_ti[q].constructFormulaTrace(dt); + Trace("cegqi-inv") << "By finite deterministic terminating trace, a " + "solution invariant is : " + << std::endl; + Trace("cegqi-inv") << " " << templ << std::endl; + // this should be unnecessary + templ = nm->mkNode(AND, templ, d_templ_arg[prog]); } - }else{ - //we are fully single invocation - d_single_invocation = true; } + else + { + Trace("cegqi-inv-auto-unfold") << "...failed initialize." << std::endl; + } + } + } + Trace("cegqi-inv") << "Make the template... " << tmode << " " << templ + << std::endl; + if (templ.isNull()) + { + if (tmode == SYGUS_INV_TEMPL_MODE_PRE) + { + templ = nm->mkNode(OR, d_trans_pre[prog], d_templ_arg[prog]); + } + else + { + Assert(tmode == SYGUS_INV_TEMPL_MODE_POST); + templ = nm->mkNode(AND, d_trans_post[prog], d_templ_arg[prog]); } } + Trace("cegqi-inv") << " template (pre-substitution) : " << templ + << std::endl; + Assert(!templ.isNull()); + // subsitute the template arguments + Assert(prog_templ_vars.size() == prog_vars[prog].size()); + templ = templ.substitute(prog_templ_vars.begin(), + prog_templ_vars.end(), + prog_vars[prog].begin(), + prog_vars[prog].end()); + Trace("cegqi-inv") << " template : " << templ << std::endl; + d_templ[prog] = templ; } void CegSingleInv::finishInit(bool syntaxRestricted) -- cgit v1.2.3 From 075e3d97974c89dcbd4cf6c7a1c3b37cbb27403d Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Thu, 13 Dec 2018 20:17:50 -0600 Subject: Fix extended rewriter for binary associative operators. (#2751) This was causing assertion failures when using Sets + Sygus. --- src/theory/quantifiers/extended_rewrite.cpp | 3 ++- src/theory/quantifiers/term_util.cpp | 20 ++++++++++++++++++-- src/theory/quantifiers/term_util.h | 16 ++++++++++++---- src/theory/sets/theory_sets_rewriter.cpp | 3 ++- test/regress/CMakeLists.txt | 1 + test/regress/regress0/sets/sets-extr.smt2 | 15 +++++++++++++++ 6 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 test/regress/regress0/sets/sets-extr.smt2 diff --git a/src/theory/quantifiers/extended_rewrite.cpp b/src/theory/quantifiers/extended_rewrite.cpp index b583a55da..ae053930c 100644 --- a/src/theory/quantifiers/extended_rewrite.cpp +++ b/src/theory/quantifiers/extended_rewrite.cpp @@ -119,7 +119,8 @@ Node ExtendedRewriter::extendedRewrite(Node n) Kind k = n.getKind(); bool childChanged = false; bool isNonAdditive = TermUtil::isNonAdditive(k); - bool isAssoc = TermUtil::isAssoc(k); + // We flatten associative operators below, which requires k to be n-ary. + bool isAssoc = TermUtil::isAssoc(k, true); for (unsigned i = 0; i < n.getNumChildren(); i++) { Node nc = extendedRewrite(n[i]); diff --git a/src/theory/quantifiers/term_util.cpp b/src/theory/quantifiers/term_util.cpp index f8e8ed5ad..4c9cf2c8d 100644 --- a/src/theory/quantifiers/term_util.cpp +++ b/src/theory/quantifiers/term_util.cpp @@ -654,7 +654,15 @@ bool TermUtil::isNegate(Kind k) return k == NOT || k == BITVECTOR_NOT || k == BITVECTOR_NEG || k == UMINUS; } -bool TermUtil::isAssoc( Kind k ) { +bool TermUtil::isAssoc(Kind k, bool reqNAry) +{ + if (reqNAry) + { + if (k == UNION || k == INTERSECTION) + { + return false; + } + } return k == PLUS || k == MULT || k == NONLINEAR_MULT || k == AND || k == OR || k == XOR || k == BITVECTOR_PLUS || k == BITVECTOR_MULT || k == BITVECTOR_AND || k == BITVECTOR_OR || k == BITVECTOR_XOR @@ -663,7 +671,15 @@ bool TermUtil::isAssoc( Kind k ) { || k == SEP_STAR; } -bool TermUtil::isComm( Kind k ) { +bool TermUtil::isComm(Kind k, bool reqNAry) +{ + if (reqNAry) + { + if (k == UNION || k == INTERSECTION) + { + return false; + } + } return k == EQUAL || k == PLUS || k == MULT || k == NONLINEAR_MULT || k == AND || k == OR || k == XOR || k == BITVECTOR_PLUS || k == BITVECTOR_MULT || k == BITVECTOR_AND || k == BITVECTOR_OR || k == BITVECTOR_XOR diff --git a/src/theory/quantifiers/term_util.h b/src/theory/quantifiers/term_util.h index dd3e76ee2..820821991 100644 --- a/src/theory/quantifiers/term_util.h +++ b/src/theory/quantifiers/term_util.h @@ -270,10 +270,18 @@ public: * double negation if applicable, e.g. mkNegate( ~, ~x ) ---> x. */ static Node mkNegate(Kind notk, Node n); - /** is assoc */ - static bool isAssoc( Kind k ); - /** is k commutative? */ - static bool isComm( Kind k ); + /** is k associative? + * + * If flag reqNAry is true, then we additionally require that k is an + * n-ary operator. + */ + static bool isAssoc(Kind k, bool reqNAry = false); + /** is k commutative? + * + * If flag reqNAry is true, then we additionally require that k is an + * n-ary operator. + */ + static bool isComm(Kind k, bool reqNAry = false); /** is k non-additive? * Returns true if diff --git a/src/theory/sets/theory_sets_rewriter.cpp b/src/theory/sets/theory_sets_rewriter.cpp index a3f1f9893..2a2015319 100644 --- a/src/theory/sets/theory_sets_rewriter.cpp +++ b/src/theory/sets/theory_sets_rewriter.cpp @@ -47,7 +47,7 @@ bool checkConstantMembership(TNode elementTerm, TNode setTerm) RewriteResponse TheorySetsRewriter::postRewrite(TNode node) { NodeManager* nm = NodeManager::currentNM(); Kind kind = node.getKind(); - + Trace("sets-postrewrite") << "Process: " << node << std::endl; if(node.isConst()) { // Dare you touch the const and mangle it to something else. @@ -204,6 +204,7 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) { if( rew!=node ){ Trace("sets-rewrite") << "Sets::rewrite " << node << " -> " << rew << std::endl; } + Trace("sets-rewrite") << "...no rewrite." << std::endl; return RewriteResponse(REWRITE_DONE, rew); } break; diff --git a/test/regress/CMakeLists.txt b/test/regress/CMakeLists.txt index 9e942aae1..95e4b8875 100644 --- a/test/regress/CMakeLists.txt +++ b/test/regress/CMakeLists.txt @@ -776,6 +776,7 @@ set(regress_0_tests regress0/sets/pre-proc-univ.smt2 regress0/sets/rec_copy_loop_check_heap_access_43_4.smt2 regress0/sets/sets-equal.smt2 + regress0/sets/sets-extr.smt2 regress0/sets/sets-inter.smt2 regress0/sets/sets-of-sets-subtypes.smt2 regress0/sets/sets-poly-int-real.smt2 diff --git a/test/regress/regress0/sets/sets-extr.smt2 b/test/regress/regress0/sets/sets-extr.smt2 new file mode 100644 index 000000000..c497ff189 --- /dev/null +++ b/test/regress/regress0/sets/sets-extr.smt2 @@ -0,0 +1,15 @@ +; COMMAND-LINE: --ext-rew-prep --ext-rew-prep-agg +; EXPECT: sat +(set-logic ALL) +(declare-sort Atom 0) + +(declare-fun a () Atom) +(declare-fun b () Atom) +(declare-fun c () Atom) +(declare-fun S () (Set Atom)) + + +(assert (= S (union (singleton a) (union (singleton c) (singleton b))))) + +(check-sat) + -- cgit v1.2.3 From a383b73fbb01acb8bc1726c6a1b61c8d1b214aae Mon Sep 17 00:00:00 2001 From: Aina Niemetz Date: Fri, 14 Dec 2018 10:25:15 -0800 Subject: New C++ API: Add tests for opterm object. (#2756) --- src/api/cvc4cpp.cpp | 16 +++++++++++-- test/unit/api/CMakeLists.txt | 1 + test/unit/api/opterm_black.h | 57 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 test/unit/api/opterm_black.h diff --git a/src/api/cvc4cpp.cpp b/src/api/cvc4cpp.cpp index cadad4eff..68b0301ec 100644 --- a/src/api/cvc4cpp.cpp +++ b/src/api/cvc4cpp.cpp @@ -635,6 +635,10 @@ class CVC4ApiExceptionStream CVC4_PREDICT_FALSE(cond) \ ? (void)0 : OstreamVoider() & CVC4ApiExceptionStream().ostream() +#define CVC4_API_CHECK_NOT_NULL \ + CVC4_API_CHECK(!isNull()) << "Invalid call to '" << __PRETTY_FUNCTION__ \ + << "', expected non-null object"; + #define CVC4_API_KIND_CHECK(kind) \ CVC4_API_CHECK(isDefinedKind(kind)) \ << "Invalid kind '" << kindToString(kind) << "'"; @@ -1166,9 +1170,17 @@ bool OpTerm::operator==(const OpTerm& t) const { return *d_expr == *t.d_expr; } bool OpTerm::operator!=(const OpTerm& t) const { return *d_expr != *t.d_expr; } -Kind OpTerm::getKind() const { return intToExtKind(d_expr->getKind()); } +Kind OpTerm::getKind() const +{ + CVC4_API_CHECK_NOT_NULL; + return intToExtKind(d_expr->getKind()); +} -Sort OpTerm::getSort() const { return Sort(d_expr->getType()); } +Sort OpTerm::getSort() const +{ + CVC4_API_CHECK_NOT_NULL; + return Sort(d_expr->getType()); +} bool OpTerm::isNull() const { return d_expr->isNull(); } diff --git a/test/unit/api/CMakeLists.txt b/test/unit/api/CMakeLists.txt index eeab46f99..8a6be70b9 100644 --- a/test/unit/api/CMakeLists.txt +++ b/test/unit/api/CMakeLists.txt @@ -4,3 +4,4 @@ cvc4_add_unit_test_black(solver_black api) cvc4_add_unit_test_black(sort_black api) cvc4_add_unit_test_black(term_black api) +cvc4_add_unit_test_black(opterm_black api) diff --git a/test/unit/api/opterm_black.h b/test/unit/api/opterm_black.h new file mode 100644 index 000000000..637301dd3 --- /dev/null +++ b/test/unit/api/opterm_black.h @@ -0,0 +1,57 @@ +/********************* */ +/*! \file opterm_black.h + ** \verbatim + ** Top contributors (to current version): + ** Aina Niemetz + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2018 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 Term class + **/ + +#include + +#include "api/cvc4cpp.h" + +using namespace CVC4::api; + +class OpTermBlack : public CxxTest::TestSuite +{ + public: + void setUp() override {} + void tearDown() override {} + + void testGetKind(); + void testGetSort(); + void testIsNull(); + + private: + Solver d_solver; +}; + +void OpTermBlack::testGetKind() +{ + OpTerm x; + TS_ASSERT_THROWS(x.getSort(), CVC4ApiException&); + x = d_solver.mkOpTerm(BITVECTOR_EXTRACT_OP, 31, 1); + TS_ASSERT_THROWS_NOTHING(x.getKind()); +} + +void OpTermBlack::testGetSort() +{ + OpTerm x; + TS_ASSERT_THROWS(x.getSort(), CVC4ApiException&); + x = d_solver.mkOpTerm(BITVECTOR_EXTRACT_OP, 31, 1); + TS_ASSERT_THROWS_NOTHING(x.getSort()); +} + +void OpTermBlack::testIsNull() +{ + OpTerm x; + TS_ASSERT(x.isNull()); + x = d_solver.mkOpTerm(BITVECTOR_EXTRACT_OP, 31, 1); + TS_ASSERT(!x.isNull()); +} -- cgit v1.2.3 From 0a5e63b5c4c851275cf8928cf9224857b61aa650 Mon Sep 17 00:00:00 2001 From: Aina Niemetz Date: Fri, 14 Dec 2018 15:12:27 -0800 Subject: Fixed typos. --- src/options/options_template.cpp | 2 +- src/theory/arith/cut_log.h | 2 +- src/util/sexpr.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/options/options_template.cpp b/src/options/options_template.cpp index 85a9747fe..9650aba7a 100644 --- a/src/options/options_template.cpp +++ b/src/options/options_template.cpp @@ -112,7 +112,7 @@ struct OptionHandler { if(!success){ throw OptionException(option + ": failed to parse "+ optionarg + - " as an integer of the appropraite type."); + " as an integer of the appropriate type."); } // Depending in the platform unsigned numbers with '-' signs may parse. diff --git a/src/theory/arith/cut_log.h b/src/theory/arith/cut_log.h index 6650e6680..5fd585588 100644 --- a/src/theory/arith/cut_log.h +++ b/src/theory/arith/cut_log.h @@ -216,7 +216,7 @@ public: int getUpId() const; /** - * Looks up a row id to the appropraite arith variable. + * Looks up a row id to the appropriate arith variable. * Be careful these are deleted in context during replay! * failure returns ARITHVAR_SENTINEL */ ArithVar lookupRowId(int rowId) const; diff --git a/src/util/sexpr.h b/src/util/sexpr.h index 427eba5f8..bad6cdb2b 100644 --- a/src/util/sexpr.h +++ b/src/util/sexpr.h @@ -13,7 +13,7 @@ ** ** Simple representation of S-expressions. ** These are used when a simple, and obvious interface for basic - ** expressions is appropraite. + ** expressions is appropriate. ** ** These are quite ineffecient. ** These are totally disconnected from any ExprManager. -- cgit v1.2.3 From 4983fb0e4339d1c03c8eb5567aca566a378114ea Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Fri, 14 Dec 2018 17:44:39 -0800 Subject: [LRA Proof] Storage for LRA proofs (#2747) * [LRA Proof] Storage for LRA proofs During LRA solving the `ConstraintDatabase` contains the reasoning behind different constraints. Combinations of constraints are periodically used to justify lemmas (conflict clauses, propegations, ... ?). `ConstraintDatabase` is SAT context-dependent. ArithProofRecorder will be used to store concise representations of the proof for each lemma raised by the (LR)A theory. The (LR)A theory will write to it, and the ArithProof class will read from it to produce LFSC proofs. Right now, it's pretty simplistic -- it allows for only Farkas proofs. In future PRs I'll: 1. add logic that stores proofs therein 2. add logic that retrieves and prints proofs 3. enable LRA proof production, checking, and testing * Document ArithProofRecorder use-sites * Update src/proof/arith_proof_recorder.cpp Co-Authored-By: alex-ozdemir * Yoni's review * clang-format * Response to Mathias' review. --- src/CMakeLists.txt | 2 + src/proof/arith_proof.cpp | 6 ++- src/proof/arith_proof.h | 6 +++ src/proof/arith_proof_recorder.cpp | 81 ++++++++++++++++++++++++++++ src/proof/arith_proof_recorder.h | 107 +++++++++++++++++++++++++++++++++++++ src/theory/arith/theory_arith.cpp | 1 + src/theory/arith/theory_arith.h | 11 ++++ 7 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 src/proof/arith_proof_recorder.cpp create mode 100644 src/proof/arith_proof_recorder.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 91c06ddd9..7ecee2dee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -124,6 +124,8 @@ libcvc4_add_sources( 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 diff --git a/src/proof/arith_proof.cpp b/src/proof/arith_proof.cpp index 3b57be1f2..1d51f99e1 100644 --- a/src/proof/arith_proof.cpp +++ b/src/proof/arith_proof.cpp @@ -640,8 +640,10 @@ Node ProofArith::toStreamRecLFSC(std::ostream& out, } ArithProof::ArithProof(theory::arith::TheoryArith* arith, TheoryProofEngine* pe) - : TheoryProof(arith, pe), d_realMode(false) -{} + : TheoryProof(arith, pe), d_recorder(), d_realMode(false) +{ + arith->setProofRecorder(&d_recorder); +} theory::TheoryId ArithProof::getTheoryId() { return theory::THEORY_ARITH; } void ArithProof::registerTerm(Expr term) { diff --git a/src/proof/arith_proof.h b/src/proof/arith_proof.h index 27012184a..a58294998 100644 --- a/src/proof/arith_proof.h +++ b/src/proof/arith_proof.h @@ -23,6 +23,7 @@ #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" @@ -62,6 +63,11 @@ protected: // TypeSet d_sorts; // all the uninterpreted sorts in this theory ExprSet d_declarations; // all the variable/function declarations + /** + * @brief Where farkas proofs of lemmas are stored. + */ + proof::ArithProofRecorder d_recorder; + bool d_realMode; theory::TheoryId getTheoryId() override; diff --git a/src/proof/arith_proof_recorder.cpp b/src/proof/arith_proof_recorder.cpp new file mode 100644 index 000000000..d654ea073 --- /dev/null +++ b/src/proof/arith_proof_recorder.cpp @@ -0,0 +1,81 @@ +/********************* */ +/*! \file arith_proof_recorder.cpp + ** \verbatim + ** Top contributors (to current version): + ** Alex Ozdemir + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2018 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) +{ + Assert(conflict.getKind() == kind::AND); + Assert(conflict.getNumChildren() == farkasCoefficients->size()); + for (size_t i = 0; i < conflict.getNumChildren(); ++i) + { + const Node& child = conflict[i]; + Assert(child.getType().isBoolean() && child[0].getType().isReal()); + } + Debug("pf::arith") << "Saved Farkas Coefficients:" << std::endl; + if (Debug.isOn("pf::arith")) + { + for (size_t i = 0; i < conflict.getNumChildren(); ++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 new file mode 100644 index 000000000..2d0501332 --- /dev/null +++ b/src/proof/arith_proof_recorder.h @@ -0,0 +1,107 @@ +/********************* */ +/*! \file arith_proof_recorder.h + ** \verbatim + ** Top contributors (to current version): + ** Alex Ozdemir + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2018 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/theory/arith/theory_arith.cpp b/src/theory/arith/theory_arith.cpp index d7113b17d..9902121d0 100644 --- a/src/theory/arith/theory_arith.cpp +++ b/src/theory/arith/theory_arith.cpp @@ -36,6 +36,7 @@ TheoryArith::TheoryArith(context::Context* c, context::UserContext* u, : Theory(THEORY_ARITH, c, u, out, valuation, logicInfo) , d_internal(new TheoryArithPrivate(*this, c, u, out, valuation, logicInfo)) , d_ppRewriteTimer("theory::arith::ppRewriteTimer") + , d_proofRecorder(nullptr) { smtStatisticsRegistry()->registerStat(&d_ppRewriteTimer); if (options::nlExt()) { diff --git a/src/theory/arith/theory_arith.h b/src/theory/arith/theory_arith.h index 195cb1883..e4b1c5b26 100644 --- a/src/theory/arith/theory_arith.h +++ b/src/theory/arith/theory_arith.h @@ -19,6 +19,7 @@ #include "theory/theory.h" #include "expr/node.h" +#include "proof/arith_proof_recorder.h" #include "theory/arith/theory_arith_private_forward.h" @@ -40,6 +41,11 @@ private: TimerStat d_ppRewriteTimer; + /** + * @brief Where to store Farkas proofs of lemmas + */ + proof::ArithProofRecorder * d_proofRecorder; + public: TheoryArith(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo); @@ -90,6 +96,11 @@ public: const EntailmentCheckParameters* params, EntailmentCheckSideEffects* out) override; + void setProofRecorder(proof::ArithProofRecorder * proofRecorder) + { + d_proofRecorder = proofRecorder; + } + };/* class TheoryArith */ }/* CVC4::theory::arith namespace */ -- cgit v1.2.3 From e644cb6dc8b5b8c64663bd4e57d14e1d86588695 Mon Sep 17 00:00:00 2001 From: Andres Noetzli Date: Fri, 14 Dec 2018 23:37:56 -0800 Subject: Revert "Move ss-combine rewrite to extended rewriter (#2703)" This reverts commit eb7226ebeabf7cc70ec023107d74ffc5c1bad5e7. After merging #2740, our experiments show that the ss-combine rewrite is now beneficial for solving performance. --- src/theory/quantifiers/extended_rewrite.cpp | 4 ---- src/theory/strings/theory_strings_rewriter.cpp | 21 ++++++--------------- src/theory/strings/theory_strings_rewriter.h | 9 --------- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/src/theory/quantifiers/extended_rewrite.cpp b/src/theory/quantifiers/extended_rewrite.cpp index ae053930c..46dcb7151 100644 --- a/src/theory/quantifiers/extended_rewrite.cpp +++ b/src/theory/quantifiers/extended_rewrite.cpp @@ -1677,10 +1677,6 @@ Node ExtendedRewriter::extendedRewriteStrings(Node ret) { new_ret = strings::TheoryStringsRewriter::rewriteEqualityExt(ret); } - else if (ret.getKind() == STRING_SUBSTR) - { - new_ret = strings::TheoryStringsRewriter::rewriteSubstrExt(ret); - } return new_ret; } diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp index 0de42f686..57a99532e 100644 --- a/src/theory/strings/theory_strings_rewriter.cpp +++ b/src/theory/strings/theory_strings_rewriter.cpp @@ -1806,18 +1806,8 @@ Node TheoryStringsRewriter::rewriteSubstr(Node node) } } } - Trace("strings-rewrite-nf") << "No rewrites for : " << node << std::endl; - return node; -} - -Node TheoryStringsRewriter::rewriteSubstrExt(Node node) -{ - Assert(node.getKind() == STRING_SUBSTR); - - NodeManager* nm = NodeManager::currentNM(); - // combine substr - if (node[0].getKind() == STRING_SUBSTR) + if (node[0].getKind() == kind::STRING_SUBSTR) { Node start_inner = node[0][1]; Node start_outer = node[1]; @@ -1830,7 +1820,7 @@ Node TheoryStringsRewriter::rewriteSubstrExt(Node node) // the length of a string from the inner substr subtracts the start point // of the outer substr Node len_from_inner = - Rewriter::rewrite(nm->mkNode(MINUS, node[0][2], start_outer)); + Rewriter::rewrite(nm->mkNode(kind::MINUS, node[0][2], start_outer)); Node len_from_outer = node[2]; Node new_len; // take quantity that is for sure smaller than the other @@ -1848,13 +1838,14 @@ Node TheoryStringsRewriter::rewriteSubstrExt(Node node) } if (!new_len.isNull()) { - Node new_start = nm->mkNode(PLUS, start_inner, start_outer); - Node ret = nm->mkNode(STRING_SUBSTR, node[0][0], new_start, new_len); + Node new_start = nm->mkNode(kind::PLUS, start_inner, start_outer); + Node ret = + nm->mkNode(kind::STRING_SUBSTR, node[0][0], new_start, new_len); return returnRewrite(node, ret, "ss-combine"); } } } - + Trace("strings-rewrite-nf") << "No rewrites for : " << node << std::endl; return node; } diff --git a/src/theory/strings/theory_strings_rewriter.h b/src/theory/strings/theory_strings_rewriter.h index 7731cd078..69d6ff68e 100644 --- a/src/theory/strings/theory_strings_rewriter.h +++ b/src/theory/strings/theory_strings_rewriter.h @@ -159,21 +159,12 @@ class TheoryStringsRewriter { * Returns the rewritten form of node. */ static Node rewriteConcat(Node node); - /** rewrite substr * This is the entry point for post-rewriting terms node of the form * str.substr( s, i1, i2 ) * Returns the rewritten form of node. */ static Node rewriteSubstr(Node node); - - /** rewrite substr extended - * This is the entry point for extended post-rewriting terms node of the form - * str.substr( s, i1, i2 ) - * Returns the rewritten form of node. - */ - static Node rewriteSubstrExt(Node node); - /** rewrite contains * This is the entry point for post-rewriting terms node of the form * str.contains( t, s ) -- cgit v1.2.3 From 76dc42ce7e4a156b4381994b5562a41e5d6b9985 Mon Sep 17 00:00:00 2001 From: Andres Noetzli Date: Sat, 15 Dec 2018 01:26:22 -0800 Subject: simplify --- src/theory/strings/theory_strings.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp index 5179ddab3..71a0ef63a 100644 --- a/src/theory/strings/theory_strings.cpp +++ b/src/theory/strings/theory_strings.cpp @@ -3195,7 +3195,6 @@ void TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal Node firstChar = stra.size() == 1 ? const_str : NodeManager::currentNM()->mkConst( isRev ? stra.suffix( 1 ) : stra.prefix( 1 ) ); Node sk = d_sk_cache.mkSkolemCached( other_str, - firstChar, isRev ? SkolemCache::SK_ID_VC_SPT_REV : SkolemCache::SK_ID_VC_SPT, "c_spt"); @@ -3570,11 +3569,10 @@ void TheoryStrings::processDeq( Node ni, Node nj ) { } }else{ Node sk = d_sk_cache.mkSkolemCached( - nconst_k, firstChar, SkolemCache::SK_ID_DC_SPT, "dc_spt"); + nconst_k, SkolemCache::SK_ID_DC_SPT, "dc_spt"); registerLength(sk, LENGTH_ONE); Node skr = d_sk_cache.mkSkolemCached(nconst_k, - firstChar, SkolemCache::SK_ID_DC_SPT_REM, "dc_spt_rem"); Node eq1 = nconst_k.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk, skr ) ); -- cgit v1.2.3 From 9f4d6f8d0c5df6dce27461f5cf07126ded7068e6 Mon Sep 17 00:00:00 2001 From: Andres Noetzli Date: Sat, 15 Dec 2018 01:55:50 -0800 Subject: Strings: More aggressive skolem normalization This PR makes the skolem normalization in the string solver quite a bit more aggressive by reducing more skolems to prefix and suffix skolems. Experiments show that this PR significantly improves performance on CMU benchmarks. --- src/theory/strings/skolem_cache.cpp | 91 +++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 8 deletions(-) diff --git a/src/theory/strings/skolem_cache.cpp b/src/theory/strings/skolem_cache.cpp index b6604d6e0..38d5ed3bf 100644 --- a/src/theory/strings/skolem_cache.cpp +++ b/src/theory/strings/skolem_cache.cpp @@ -18,6 +18,8 @@ #include "theory/strings/theory_strings_rewriter.h" #include "util/rational.h" +using namespace CVC4::kind; + namespace CVC4 { namespace theory { namespace strings { @@ -90,23 +92,96 @@ SkolemCache::normalizeStringSkolem(SkolemId id, Node a, Node b) Trace("skolem-cache") << "normalizeStringSkolem start: (" << id << ", " << a << ", " << b << ")" << std::endl; - // SK_PURIFY(str.substr x 0 (str.indexof x y 0)) ---> SK_FIRST_CTN_PRE(x, y) + NodeManager* nm = NodeManager::currentNM(); + + if (id == SK_FIRST_CTN_POST) + { + // SK_FIRST_CTN_POST(x, y) ---> + // SK_SUFFIX_REM(x, (+ (str.len SK_FIRST_CTN_PRE(x, y)) (str.len y))) + id = SK_SUFFIX_REM; + Node pre = mkSkolemCached(a, b, SK_FIRST_CTN_PRE, "pre"); + b = Rewriter::rewrite(nm->mkNode( + PLUS, nm->mkNode(STRING_LENGTH, pre), nm->mkNode(STRING_LENGTH, b))); + } + + if (id == SK_ID_C_SPT) + { + // SK_ID_C_SPT(x, y) ---> SK_SUFFIX_REM(x, (str.len y)) + id = SK_SUFFIX_REM; + b = Rewriter::rewrite(nm->mkNode(STRING_LENGTH, b)); + } + else if (id == SK_ID_VC_SPT) + { + // SK_ID_VC_SPT(x, y) ---> SK_SUFFIX_REM(x, 1) + id = SK_SUFFIX_REM; + b = nm->mkConst(Rational(1)); + } + else if (id == SK_ID_VC_SPT_REV) + { + // SK_ID_VC_SPT_REV(x, y) ---> SK_PREFIX(x, (- (str.len x) 1)) + id = SK_PREFIX; + b = Rewriter::rewrite(nm->mkNode( + MINUS, nm->mkNode(STRING_LENGTH, a), nm->mkConst(Rational(1)))); + } + else if (id == SK_ID_DC_SPT) + { + // SK_ID_DC_SPT(x, y) ---> SK_PREFIX(x, 1) + id = SK_PREFIX; + b = nm->mkConst(Rational(1)); + } + else if (id == SK_ID_DC_SPT_REM) + { + // SK_ID_DC_SPT_REM(x, y) ---> SK_SUFFIX_REM(x, 1) + id = SK_SUFFIX_REM; + b = nm->mkConst(Rational(1)); + } + else if (id == SK_ID_DEQ_X) + { + // SK_ID_DEQ_X(x, y) ---> SK_PREFIX(y, (str.len x)) + id = SK_PREFIX; + Node aOld = a; + a = b; + b = Rewriter::rewrite(nm->mkNode(STRING_LENGTH, aOld)); + } + else if (id == SK_ID_DEQ_Y) + { + // SK_ID_DEQ_Y(x, y) ---> SK_PREFIX(x, (str.len y)) + id = SK_PREFIX; + b = Rewriter::rewrite(nm->mkNode(STRING_LENGTH, b)); + } + if (id == SK_PURIFY && a.getKind() == kind::STRING_SUBSTR) { Node s = a[0]; Node n = a[1]; Node m = a[2]; - if (m.getKind() == kind::STRING_STRIDOF && m[0] == s) + + if (n == d_zero) + { + // SK_PURIFY((str.substr x 0 m)) ---> SK_PREFIX(x, m) + id = SK_PREFIX; + a = s; + b = m; + } + else if (TheoryStringsRewriter::checkEntailArith( + nm->mkNode(PLUS, n, m), nm->mkNode(STRING_LENGTH, s))) { - if (n == d_zero && m[2] == d_zero) - { - id = SK_FIRST_CTN_PRE; - a = m[0]; - b = m[1]; - } + // SK_PURIFY((str.substr x n m)) ---> SK_SUFFIX_REM(x, n) + // if n + m >= (str.len x) + id = SK_SUFFIX_REM; + a = s; + b = n; } } + if (id == SK_PREFIX && b.getKind() == kind::STRING_STRIDOF && a == b[0] + && b[2] == d_zero) + { + // SK_PREFIX(x, (str.indexof x y 0)) ---> SK_FIRST_CTN_PRE(x, y) + id = SK_FIRST_CTN_PRE; + b = b[1]; + } + if (id == SK_FIRST_CTN_PRE) { // SK_FIRST_CTN_PRE((str.substr x 0 n), y) ---> SK_FIRST_CTN_PRE(x, y) -- cgit v1.2.3 From f5b05e8cc794fa5cad43f5827b84cca4c702dde2 Mon Sep 17 00:00:00 2001 From: Andres Noetzli Date: Sat, 15 Dec 2018 16:40:03 +0000 Subject: Revert "Move ss-combine rewrite to extended rewriter (#2703)" (#2759) --- src/theory/quantifiers/extended_rewrite.cpp | 4 ---- src/theory/strings/theory_strings_rewriter.cpp | 21 ++++++--------------- src/theory/strings/theory_strings_rewriter.h | 9 --------- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/src/theory/quantifiers/extended_rewrite.cpp b/src/theory/quantifiers/extended_rewrite.cpp index ae053930c..46dcb7151 100644 --- a/src/theory/quantifiers/extended_rewrite.cpp +++ b/src/theory/quantifiers/extended_rewrite.cpp @@ -1677,10 +1677,6 @@ Node ExtendedRewriter::extendedRewriteStrings(Node ret) { new_ret = strings::TheoryStringsRewriter::rewriteEqualityExt(ret); } - else if (ret.getKind() == STRING_SUBSTR) - { - new_ret = strings::TheoryStringsRewriter::rewriteSubstrExt(ret); - } return new_ret; } diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp index 0de42f686..57a99532e 100644 --- a/src/theory/strings/theory_strings_rewriter.cpp +++ b/src/theory/strings/theory_strings_rewriter.cpp @@ -1806,18 +1806,8 @@ Node TheoryStringsRewriter::rewriteSubstr(Node node) } } } - Trace("strings-rewrite-nf") << "No rewrites for : " << node << std::endl; - return node; -} - -Node TheoryStringsRewriter::rewriteSubstrExt(Node node) -{ - Assert(node.getKind() == STRING_SUBSTR); - - NodeManager* nm = NodeManager::currentNM(); - // combine substr - if (node[0].getKind() == STRING_SUBSTR) + if (node[0].getKind() == kind::STRING_SUBSTR) { Node start_inner = node[0][1]; Node start_outer = node[1]; @@ -1830,7 +1820,7 @@ Node TheoryStringsRewriter::rewriteSubstrExt(Node node) // the length of a string from the inner substr subtracts the start point // of the outer substr Node len_from_inner = - Rewriter::rewrite(nm->mkNode(MINUS, node[0][2], start_outer)); + Rewriter::rewrite(nm->mkNode(kind::MINUS, node[0][2], start_outer)); Node len_from_outer = node[2]; Node new_len; // take quantity that is for sure smaller than the other @@ -1848,13 +1838,14 @@ Node TheoryStringsRewriter::rewriteSubstrExt(Node node) } if (!new_len.isNull()) { - Node new_start = nm->mkNode(PLUS, start_inner, start_outer); - Node ret = nm->mkNode(STRING_SUBSTR, node[0][0], new_start, new_len); + Node new_start = nm->mkNode(kind::PLUS, start_inner, start_outer); + Node ret = + nm->mkNode(kind::STRING_SUBSTR, node[0][0], new_start, new_len); return returnRewrite(node, ret, "ss-combine"); } } } - + Trace("strings-rewrite-nf") << "No rewrites for : " << node << std::endl; return node; } diff --git a/src/theory/strings/theory_strings_rewriter.h b/src/theory/strings/theory_strings_rewriter.h index 7731cd078..69d6ff68e 100644 --- a/src/theory/strings/theory_strings_rewriter.h +++ b/src/theory/strings/theory_strings_rewriter.h @@ -159,21 +159,12 @@ class TheoryStringsRewriter { * Returns the rewritten form of node. */ static Node rewriteConcat(Node node); - /** rewrite substr * This is the entry point for post-rewriting terms node of the form * str.substr( s, i1, i2 ) * Returns the rewritten form of node. */ static Node rewriteSubstr(Node node); - - /** rewrite substr extended - * This is the entry point for extended post-rewriting terms node of the form - * str.substr( s, i1, i2 ) - * Returns the rewritten form of node. - */ - static Node rewriteSubstrExt(Node node); - /** rewrite contains * This is the entry point for post-rewriting terms node of the form * str.contains( t, s ) -- cgit v1.2.3 From bc40c176eb1205452e824ec9d89dc9a7c76cbd67 Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Sun, 16 Dec 2018 17:49:34 -0800 Subject: DRAT Signature (#2757) * DRAT signature Added the DRAT signature to CVC4. We'll need this in order to compare three BV proof pipelines: 1. DRAT -> Resolution -> Check 2. DRAT -> LRAT -> Check 3. DRAT -> Check (this one!) Tested the signature using the attached test file. i.e. running ``` lfscc sat.plf smt.plf lrat.plf drat.plf drat_test.plf ``` * Added type annotations for tests * Respond to Yoni's review * Apply Yoni's suggestions from code review Documentation polish Co-Authored-By: alex-ozdemir * Whoops, missed a spot or two --- proofs/signatures/drat.plf | 224 ++++++++++++++++++++++++++++++++++++++++ proofs/signatures/drat_test.plf | 191 ++++++++++++++++++++++++++++++++++ proofs/signatures/lrat.plf | 13 +-- 3 files changed, 422 insertions(+), 6 deletions(-) create mode 100644 proofs/signatures/drat.plf create mode 100644 proofs/signatures/drat_test.plf diff --git a/proofs/signatures/drat.plf b/proofs/signatures/drat.plf new file mode 100644 index 000000000..d52586bc9 --- /dev/null +++ b/proofs/signatures/drat.plf @@ -0,0 +1,224 @@ +; Depends on lrat.plf +; +; Implementation of DRAT checking. +; +; Unfortunately, there are **two** different notions of DRAT floating around in +; the world: +; * Specified DRAT : This is a reasonable proof format +; * Operational DRAT : This is a variant of specified DRAT warped by the +; details of common SAT solver architectures. +; +; Both are detailed in this paper, along with their differences: +; http://fmv.jku.at/papers/RebolaPardoBiere-POS18.pdf +; +; This signature checks **Specified DRAT**. + +(declare cnf_holds (! c cnf type)) +(declare cnfn_proof (cnf_holds cnfn)) +(declare cnfc_proof + (! c clause + (! deduped_c clause + (! rest cnf + (! proof_c (holds c) + (! proof_rest (cnf_holds rest) + (! sc (^ (clause_dedup c) deduped_c) + (cnf_holds (cnfc c rest))))))))) + +; A DRAT proof itself: a list of addition or deletion instructions. +(declare DRATProof type) +(declare DRATProofn DRATProof) +(declare DRATProofa (! c clause (! p DRATProof DRATProof))) +(declare DRATProofd (! c clause (! p DRATProof DRATProof))) + +; ==================== ; +; Functional Programs ; +; ==================== ; + +; Are two clauses equal (in the set sense) +; +; Since clauses are sets, it is insufficient to do list equality +; We could sort them, but that would require defining an order on our variables, +; and incurring the cost of sorting. +; Instead, we do the following: +; 1. Sweep the first clause, marking variables with flags 1 (pos) and 2 (neg) +; 2. Sweep the second clause, erasing marks. +; 3. Unsweep the first clause, returning FALSE on marks. +; Also unmarking +; TODO(aozdemir) This implementation could be further optimized b/c once c1 is +; drained, we need not continue to pattern match on it. +(program clause_eq ((c1 clause) (c2 clause)) bool + (match + c1 + (cln (match + c2 + (cln tt) + ((clc c2h c2t) (match + c2h + ((pos v) (ifmarked1 + v + (do (markvar1 v) (clause_eq c1 c2t)) + ff)) + ((neg v) (ifmarked2 + v + (do (markvar2 v) (clause_eq c1 c2t)) + ff)))))) + ((clc c1h c1t) (match + c1h + ((pos v) (do + (markvar1 v) + (let res (clause_eq c1t c2) + (ifmarked1 + v + (do (markvar1 v) ff) + res)))) + ((neg v) (do + (markvar2 v) + (let res (clause_eq c1t c2) + (ifmarked2 + v + (do (markvar2 v) ff) + res)))))))) + +; Does this formula contain bottom as one of its clauses? +(program cnf_has_bottom ((cs cnf)) bool + (match cs + (cnfn ff) + ((cnfc c rest) (match c + (cln tt) + ((clc l c') (cnf_has_bottom rest)))))) + +; Return a new cnf with one copy of this clause removed. +(program cnf_remove_clause ((c clause) (cs cnf)) cnf + (match cs + (cnfn (fail cnf)) + ((cnfc c' cs') + (match (clause_eq c c') + (tt cs') + (ff (cnfc c' (cnf_remove_clause c cs'))))))) + +; return (c1 union (c2 \ ~l)) +; Significant for how a RAT is defined. +(program clause_pseudo_resolvent ((c1 clause) (c2 clause)) clause + (clause_dedup (clause_append c1 + (clause_remove_all + (lit_flip (clause_head c1)) c2)))) + +; Given a formula, `cs` and a clause `c`, return all pseudo resolvents, i.e. all +; (c union (c' \ ~head(c))) +; for c' in cs, where c' contains ~head(c) +(program collect_pseudo_resolvents ((cs cnf) (c clause)) cnf + (match cs + (cnfn cnfn) + ((cnfc c' cs') + (let rest_of_resolvents (collect_pseudo_resolvents cs' c) + (match (clause_contains_lit c' (lit_flip (clause_head c))) + (tt (cnfc (clause_pseudo_resolvent + c + c') + rest_of_resolvents)) + (ff rest_of_resolvents)))))) + +; =============================================================== ; +; Unit Propegation implementation (manipulates global assignment) ; +; =============================================================== ; +; See the lrat file for a description of the global assignment. + +; The result of search for a unit clause in +(declare UnitSearchResult type) +; There was a unit, and +; this is the (previously floating) literal that is now satisfied. +; this is a version of the input cnf with satisfied clauses removed. +(declare USRUnit (! l lit (! f cnf UnitSearchResult))) +; There was an unsat clause +(declare USRBottom UnitSearchResult) +; There was no unit. +(declare USRNoUnit UnitSearchResult) + +; If a UnitSearchResult is a Unit, containing a cnf, adds this clause to that +; cnf. Otherwise, returns the UnitSearchResult unmodified. +(program USR_add_clause ((c clause) (usr UnitSearchResult)) UnitSearchResult + (match usr + ((USRUnit l f) (USRUnit l (cnfc c f))) + (USRBottom USRBottom) + (USRNoUnit USRNoUnit))) + +; Searches through the clauses, looking for a unit clause. +; Reads the global assignment. Possibly assigns one variable. +; Returns +; USRBottom if there is an unsat clause +; (USRUnit l f) if there is a unit, with lit l, and +; f is the cnf with some SAT clauses removed. +; USRNoUnit if there is no unit +(program unit_search ((f cnf)) UnitSearchResult + (match f + (cnfn USRNoUnit) + ((cnfc c f') + (match (clause_check_unit_and_maybe_mark c) + (MRSat (unit_search f')) + ((MRUnit l) (USRUnit l f')) + (MRUnsat USRBottom) + (MRNotUnit (USR_add_clause c (unit_search f'))))))) + + +; Given the current global assignment, does the formula `f` imply bottom via +; unit propegation? Leaves the global assignment in the same state that it was +; initially. +(program unit_propegates_to_bottom ((f cnf)) bool + (match (unit_search f) + (USRBottom tt) + ((USRUnit l f') (let result (unit_propegates_to_bottom f') + (do (lit_un_mk_sat l) + result))) + (USRNoUnit ff))) + +; ================================== ; +; High-Level DRAT checking functions ; +; ================================== ; + +; Is this clause an AT? +(program is_at ((cs cnf) (c clause)) bool + (match (is_t c) + (tt tt) + (ff (do (clause_mk_all_unsat c) + (let r (unit_propegates_to_bottom cs) + (do (clause_un_mk_all_unsat c) + r)))))) + +; Are all of these clauses ATs? +(program are_all_at ((cs cnf) (clauses cnf)) bool + (match clauses + (cnfn tt) + ((cnfc c clauses') + (match (is_at cs c) + (tt (are_all_at cs clauses')) + (ff ff))))) + +; Is the clause `c` a RAT for the formula `cs`? +(program is_rat ((cs cnf) (c clause)) bool + (match (is_t c) + (tt tt) + (ff (match (is_at cs c) + (tt tt) + (ff (are_all_at + cs + (collect_pseudo_resolvents cs c))))))) + +; Is this proof a valid DRAT proof of bottom? +(program is_drat_proof_of_bottom ((f cnf) (proof DRATProof)) bool + (match proof + (DRATProofn (cnf_has_bottom f)) + ((DRATProofa c p) (match + (is_rat f c) + (tt (is_drat_proof_of_bottom (cnfc c f) p)) + (ff ff))) + ((DRATProofd c p) + (is_drat_proof_of_bottom (cnf_remove_clause c f) p)))) + + +(declare drat_proof_of_bottom + (! f cnf + (! proof_of_formula (cnf_holds f) + (! proof DRATProof + (! sc (^ (is_drat_proof_of_bottom f proof) tt) + bottom))))) + diff --git a/proofs/signatures/drat_test.plf b/proofs/signatures/drat_test.plf new file mode 100644 index 000000000..f2f2c7286 --- /dev/null +++ b/proofs/signatures/drat_test.plf @@ -0,0 +1,191 @@ +;depends on drat.plf +(declare check_rat + (! f cnf + (! c clause + (! b bool + (! sc (^ (is_rat f c) b) + bottom))))) + +(declare trust_cnf (! f cnf (cnf_holds f))) + +; RAT Test 1 +; Formula: (-p, -a) ^ (-p, b) ^( b, c) ^ (-c, a) +; Candidate RAT: (p, a) +; Answer: true +(check + (% va var + (% vb var + (% vc var + (% vp var + (check_rat + (cnfc (clc (neg vp) (clc (neg va) cln)) + (cnfc (clc (neg vp) (clc (pos vb) cln)) + (cnfc (clc (pos vb) (clc (pos vc) cln)) + (cnfc (clc (neg vc) (clc (pos va) cln)) cnfn)))) + (clc (pos vp) (clc (pos va) cln)) + tt)))))) + +; RAT Test 2 +; Formula: +; p cnf 4 8 +; 1 2 -3 0 +; -1 -2 3 0 +; 2 3 -4 0 +; -2 -3 4 0 +; -1 -3 -4 0 +; 1 3 4 0 +; -1 2 4 0 +; 1 -2 -4 0 +; Candidate RAT: -1 +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (check_rat + (cnfc (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))) + (cnfc (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))) + (cnfc (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))) + (cnfc (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))) + (cnfc (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))) + (cnfc (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))) + (cnfc (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))) + (cnfc (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))) + cnfn)))))))) + (clc (neg v1) cln) + tt)))))) + +; RAT Test 3 +; Formula: +; p cnf 4 9 +; 1 2 -3 0 +; -1 -2 3 0 +; 2 3 -4 0 +; -2 -3 4 0 +; -1 -3 -4 0 +; 1 3 4 0 +; -1 2 4 0 +; 1 -2 -4 0 +; -1 0 +; Candidate RAT: 2 +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (check_rat + (cnfc (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))) + (cnfc (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))) + (cnfc (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))) + (cnfc (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))) + (cnfc (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))) + (cnfc (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))) + (cnfc (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))) + (cnfc (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))) + (cnfc (clc (neg v1) cln) + cnfn))))))))) + (clc (pos v2) cln) + tt)))))) + +; RAT Test 4 +; Formula: +; p cnf 4 2 +; 2 -3 0 +; 1 -4 0 +; Candidate RAT: 3 +; Answer: false +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (check_rat + (cnfc (clc (pos v2) (clc (neg v3) cln)) + (cnfc (clc (pos v1) (clc (neg v4) cln)) cnfn)) + (clc (pos v3) cln) + ff)))))) + + +; DRAT Test 1 (from Example 1 @ https://www.cs.utexas.edu/~marijn/drat-trim/) +; without deletions +; Formula: +; p cnf 4 8 +; 1 2 -3 0 +; -1 -2 3 0 +; 2 3 -4 0 +; -2 -3 4 0 +; -1 -3 -4 0 +; 1 3 4 0 +; -1 2 4 0 +; 1 -2 -4 +; Proof: +; -1 0 +; 2 0 +; 0 +(check + (% v1 var + (% v2 var + (% v3 var + (% v4 var + (: + (holds cln) + (drat_proof_of_bottom _ + (trust_cnf (cnfc (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))) + (cnfc (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))) + (cnfc (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))) + (cnfc (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))) + (cnfc (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))) + (cnfc (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))) + (cnfc (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))) + (cnfc (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))) + cnfn))))))))) + (DRATProofa (clc (neg v1) cln) + (DRATProofa (clc (pos v2) cln) + (DRATProofa cln + DRATProofn)))))))))) + + +; DRAT Test 2 (from Example 1 @ https://www.cs.utexas.edu/~marijn/drat-trim/) +; with deletions +; Formula: +; p cnf 4 8 +; 1 2 -3 0 +; -1 -2 3 0 +; 2 3 -4 0 +; -2 -3 4 0 +; -1 -3 -4 0 +; 1 3 4 0 +; -1 2 4 0 +; 1 -2 -4 +; Proof: +; -1 0 +; d -1 -2 3 0 +; d -1 -3 -4 0 +; d -1 2 4 0 +; 2 0 +; d 1 2 -3 0 +; d 2 3 -4 0 +; 0 +(check + (% v1 var (% v2 var (% v3 var (% v4 var + (: (holds cln) + (drat_proof_of_bottom _ + (trust_cnf + (cnfc (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))) + (cnfc (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))) + (cnfc (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))) + (cnfc (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))) + (cnfc (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))) + (cnfc (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))) + (cnfc (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))) + (cnfc (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))) + cnfn))))))))) + (DRATProofa (clc (neg v1) cln) + (DRATProofd (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))) + (DRATProofd (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))) + (DRATProofd (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))) + (DRATProofa (clc (pos v2) cln) + (DRATProofd (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))) + (DRATProofd (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))) + (DRATProofa cln + DRATProofn))))))))))))))) diff --git a/proofs/signatures/lrat.plf b/proofs/signatures/lrat.plf index 96cdd83b3..5224cf3ce 100644 --- a/proofs/signatures/lrat.plf +++ b/proofs/signatures/lrat.plf @@ -1,5 +1,6 @@ ; LRAT Proof signature ; LRAT format detailed in "Efficient Certified RAT Verification" +; Link: https://www.cs.utexas.edu/~marijn/publications/lrat.pdf ; Author: aozdemir ; Depends On: sat.plf, smt.plf @@ -504,7 +505,7 @@ ; Goes through a list of clause, trace pairs and verifies that each clause is ; an AT via that trace. ; Fails if any putative AT is a TAUT or contains duplicates -(program are_all_at ( +(program are_all_at_trace ( (cs CMap) (l CTPairs) ) UPResult @@ -514,12 +515,12 @@ (match (is_at_trace cs c t) (UPR_Ok UPR_Ok) (UPR_Broken UPR_Broken) - (UPR_Bottom (are_all_at cs l')))))) + (UPR_Bottom (are_all_at_trace cs l')))))) ; Is this trace, and list of hints, proof that `c` is an Resolution Assymeytic ; Tautology? -; Fails is the hints are empty (i.e. `c` should be AT, and c is TAUT or contains duplicates) -; Also fails if any of the pseudo-resolvants are TAUT or contain duplicates. +; Fails is the hints are empty (which means `c` should be AT) and `c` contains +; duplicates) (program is_rat_trace ((cs CMap) (c clause) (t Trace) (hints RATHints)) UPResult (match (RATHints_is_empty hints) @@ -529,10 +530,10 @@ (match (resolution_targets_match (collect_resolution_targets cs c) hints) - (ff ; Res targets are bad + (ff ; Resolution targets disagree with hints. UPR_Broken) (tt - (are_all_at cs (construct_ct_pairs cs c t hints))))))) + (are_all_at_trace cs (construct_ct_pairs cs c t hints))))))) ; Is this proof an LRAT proof of bottom? ; Fails if any added AT is a TAUT or contains duplicates OR if any added RAT -- cgit v1.2.3 From 332357104e9ab1937049f0ea8e53042d8534f966 Mon Sep 17 00:00:00 2001 From: Aina Niemetz Date: Mon, 17 Dec 2018 14:11:37 -0800 Subject: New C++ API: Add tests for term object. (#2755) --- NEWS | 11 + src/api/cvc4cpp.cpp | 93 +++++++- src/api/cvc4cpp.h | 4 +- src/expr/expr_template.cpp | 3 +- src/expr/expr_template.h | 2 +- src/proof/bitvector_proof.cpp | 2 +- test/unit/api/term_black.h | 522 +++++++++++++++++++++++++++++++++++++++++- 7 files changed, 615 insertions(+), 22 deletions(-) diff --git a/NEWS b/NEWS index 038b02026..0cc8cab44 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,16 @@ This file contains a summary of important user-visible changes. +Changes since 1.6 +================= + +New Features: + +Improvements: + +Changes: +* API change: Expr::iffExpr() is renamed to Expr::eqExpr() to reflect its + actual behavior. + Changes since 1.5 ================= diff --git a/src/api/cvc4cpp.cpp b/src/api/cvc4cpp.cpp index 68b0301ec..cd604a25c 100644 --- a/src/api/cvc4cpp.cpp +++ b/src/api/cvc4cpp.cpp @@ -1007,27 +1007,102 @@ bool Term::operator==(const Term& t) const { return *d_expr == *t.d_expr; } bool Term::operator!=(const Term& t) const { return *d_expr != *t.d_expr; } -Kind Term::getKind() const { return intToExtKind(d_expr->getKind()); } +Kind Term::getKind() const +{ + CVC4_API_CHECK_NOT_NULL; + return intToExtKind(d_expr->getKind()); +} -Sort Term::getSort() const { return Sort(d_expr->getType()); } +Sort Term::getSort() const +{ + CVC4_API_CHECK_NOT_NULL; + return Sort(d_expr->getType()); +} bool Term::isNull() const { return d_expr->isNull(); } -Term Term::notTerm() const { return d_expr->notExpr(); } +Term Term::notTerm() const +{ + try + { + return d_expr->notExpr(); + } + catch (TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } +} -Term Term::andTerm(const Term& t) const { return d_expr->andExpr(*t.d_expr); } +Term Term::andTerm(const Term& t) const +{ + try + { + return d_expr->andExpr(*t.d_expr); + } + catch (TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } +} -Term Term::orTerm(const Term& t) const { return d_expr->orExpr(*t.d_expr); } +Term Term::orTerm(const Term& t) const +{ + try + { + return d_expr->orExpr(*t.d_expr); + } + catch (TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } +} -Term Term::xorTerm(const Term& t) const { return d_expr->xorExpr(*t.d_expr); } +Term Term::xorTerm(const Term& t) const +{ + try + { + return d_expr->xorExpr(*t.d_expr); + } + catch (TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } +} -Term Term::iffTerm(const Term& t) const { return d_expr->iffExpr(*t.d_expr); } +Term Term::eqTerm(const Term& t) const +{ + try + { + return d_expr->eqExpr(*t.d_expr); + } + catch (TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } +} -Term Term::impTerm(const Term& t) const { return d_expr->impExpr(*t.d_expr); } +Term Term::impTerm(const Term& t) const +{ + try + { + return d_expr->impExpr(*t.d_expr); + } + catch (TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } +} Term Term::iteTerm(const Term& then_t, const Term& else_t) const { - return d_expr->iteExpr(*then_t.d_expr, *else_t.d_expr); + try + { + return d_expr->iteExpr(*then_t.d_expr, *else_t.d_expr); + } + catch (TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } std::string Term::toString() const { return d_expr->toString(); } diff --git a/src/api/cvc4cpp.h b/src/api/cvc4cpp.h index aebeffb0d..d06955a05 100644 --- a/src/api/cvc4cpp.h +++ b/src/api/cvc4cpp.h @@ -607,11 +607,11 @@ class CVC4_PUBLIC Term Term xorTerm(const Term& t) const; /** - * Boolean if-and-only-if. + * Equality. * @param t a Boolean term * @return the Boolean equivalence of this term and the given term */ - Term iffTerm(const Term& t) const; + Term eqTerm(const Term& t) const; /** * Boolean implication. diff --git a/src/expr/expr_template.cpp b/src/expr/expr_template.cpp index 61568e411..96bdb2d04 100644 --- a/src/expr/expr_template.cpp +++ b/src/expr/expr_template.cpp @@ -595,7 +595,8 @@ Expr Expr::xorExpr(const Expr& e) const { return d_exprManager->mkExpr(XOR, *this, e); } -Expr Expr::iffExpr(const Expr& e) const { +Expr Expr::eqExpr(const Expr& e) const +{ Assert(d_exprManager != NULL, "Don't have an expression manager for this expression!"); PrettyCheckArgument(d_exprManager == e.d_exprManager, e, diff --git a/src/expr/expr_template.h b/src/expr/expr_template.h index 324915b1d..da9d22389 100644 --- a/src/expr/expr_template.h +++ b/src/expr/expr_template.h @@ -391,7 +391,7 @@ public: * Returns the Boolean equivalence of this expression and * the given expression. */ - Expr iffExpr(const Expr& e) const; + Expr eqExpr(const Expr& e) const; /** * Returns the implication of this expression and diff --git a/src/proof/bitvector_proof.cpp b/src/proof/bitvector_proof.cpp index 9eb39e2e2..ba3533cc3 100644 --- a/src/proof/bitvector_proof.cpp +++ b/src/proof/bitvector_proof.cpp @@ -68,7 +68,7 @@ void BitVectorProof::registerAtomBB(Expr atom, Expr atom_bb) { Debug("pf::bv") << "BitVectorProof::registerAtomBB( " << atom << ", " << atom_bb << " )" << std::endl; - Expr def = atom.iffExpr(atom_bb); + Expr def = atom.eqExpr(atom_bb); d_bbAtoms.insert(std::make_pair(atom, def)); registerTerm(atom); diff --git a/test/unit/api/term_black.h b/test/unit/api/term_black.h index c2ca1cb08..ae1dfe7ba 100644 --- a/test/unit/api/term_black.h +++ b/test/unit/api/term_black.h @@ -2,7 +2,7 @@ /*! \file term_black.h ** \verbatim ** Top contributors (to current version): - ** Andres Noetzli + ** Aina Niemetz, Andres Noetzli ** This file is part of the CVC4 project. ** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS ** in the top-level source directory) and their institutional affiliations. @@ -24,14 +24,520 @@ class TermBlack : public CxxTest::TestSuite void setUp() override {} void tearDown() override {} - void testTermAssignment() - { - Term t1 = d_solver.mkReal(1); - Term t2 = t1; - t2 = d_solver.mkReal(2); - TS_ASSERT_EQUALS(t1, d_solver.mkReal(1)); - } + void testEq(); + void testGetKind(); + void testGetSort(); + void testIsNull(); + void testNotTerm(); + void testAndTerm(); + void testOrTerm(); + void testXorTerm(); + void testEqTerm(); + void testImpTerm(); + void testIteTerm(); + + void testTermAssignment(); private: Solver d_solver; }; + +void TermBlack::testEq() +{ + Sort uSort = d_solver.mkUninterpretedSort("u"); + Term x = d_solver.mkVar("x", uSort); + Term y = d_solver.mkVar("y", uSort); + Term z; + + TS_ASSERT(x == x); + TS_ASSERT(!(x != x)); + TS_ASSERT(!(x == y)); + TS_ASSERT(x != y); + TS_ASSERT(!(x == z)); + TS_ASSERT(x != z); +} + +void TermBlack::testGetKind() +{ + Sort uSort = d_solver.mkUninterpretedSort("u"); + Sort intSort = d_solver.getIntegerSort(); + Sort boolSort = d_solver.getBooleanSort(); + Sort funSort1 = d_solver.mkFunctionSort(uSort, intSort); + Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort); + + Term n; + TS_ASSERT_THROWS(n.getKind(), CVC4ApiException&); + Term x = d_solver.mkVar("x", uSort); + TS_ASSERT_THROWS_NOTHING(x.getKind()); + Term y = d_solver.mkVar("y", uSort); + TS_ASSERT_THROWS_NOTHING(y.getKind()); + + Term f = d_solver.mkVar("f", funSort1); + TS_ASSERT_THROWS_NOTHING(f.getKind()); + Term p = d_solver.mkVar("p", funSort2); + TS_ASSERT_THROWS_NOTHING(p.getKind()); + + Term zero = d_solver.mkInteger(0); + TS_ASSERT_THROWS_NOTHING(zero.getKind()); + + Term f_x = d_solver.mkTerm(APPLY_UF, f, x); + TS_ASSERT_THROWS_NOTHING(f_x.getKind()); + Term f_y = d_solver.mkTerm(APPLY_UF, f, y); + TS_ASSERT_THROWS_NOTHING(f_y.getKind()); + Term sum = d_solver.mkTerm(PLUS, f_x, f_y); + TS_ASSERT_THROWS_NOTHING(sum.getKind()); + Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero); + TS_ASSERT_THROWS_NOTHING(p_0.getKind()); + Term p_f_y = d_solver.mkTerm(APPLY_UF, p, f_y); + TS_ASSERT_THROWS_NOTHING(p_f_y.getKind()); +} + +void TermBlack::testGetSort() +{ + Sort bvSort = d_solver.mkBitVectorSort(8); + Sort intSort = d_solver.getIntegerSort(); + Sort boolSort = d_solver.getBooleanSort(); + Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort); + Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort); + + Term n; + TS_ASSERT_THROWS(n.getSort(), CVC4ApiException&); + Term x = d_solver.mkVar("x", bvSort); + TS_ASSERT_THROWS_NOTHING(x.getSort()); + TS_ASSERT(x.getSort() == bvSort); + Term y = d_solver.mkVar("y", bvSort); + TS_ASSERT_THROWS_NOTHING(y.getSort()); + TS_ASSERT(y.getSort() == bvSort); + + Term f = d_solver.mkVar("f", funSort1); + TS_ASSERT_THROWS_NOTHING(f.getSort()); + TS_ASSERT(f.getSort() == funSort1); + Term p = d_solver.mkVar("p", funSort2); + TS_ASSERT_THROWS_NOTHING(p.getSort()); + TS_ASSERT(p.getSort() == funSort2); + + Term zero = d_solver.mkInteger(0); + TS_ASSERT_THROWS_NOTHING(zero.getSort()); + TS_ASSERT(zero.getSort() == intSort); + + Term f_x = d_solver.mkTerm(APPLY_UF, f, x); + TS_ASSERT_THROWS_NOTHING(f_x.getSort()); + TS_ASSERT(f_x.getSort() == intSort); + Term f_y = d_solver.mkTerm(APPLY_UF, f, y); + TS_ASSERT_THROWS_NOTHING(f_y.getSort()); + TS_ASSERT(f_y.getSort() == intSort); + Term sum = d_solver.mkTerm(PLUS, f_x, f_y); + TS_ASSERT_THROWS_NOTHING(sum.getSort()); + TS_ASSERT(sum.getSort() == intSort); + Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero); + TS_ASSERT_THROWS_NOTHING(p_0.getSort()); + TS_ASSERT(p_0.getSort() == boolSort); + Term p_f_y = d_solver.mkTerm(APPLY_UF, p, f_y); + TS_ASSERT_THROWS_NOTHING(p_f_y.getSort()); + TS_ASSERT(p_f_y.getSort() == boolSort); +} + +void TermBlack::testIsNull() +{ + Term x; + TS_ASSERT(x.isNull()); + x = d_solver.mkVar("x", d_solver.mkBitVectorSort(4)); + TS_ASSERT(!x.isNull()); +} + +void TermBlack::testNotTerm() +{ + Sort bvSort = d_solver.mkBitVectorSort(8); + Sort intSort = d_solver.getIntegerSort(); + Sort boolSort = d_solver.getBooleanSort(); + Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort); + Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort); + + Term b = d_solver.mkTrue(); + TS_ASSERT_THROWS_NOTHING(b.notTerm()); + Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8)); + TS_ASSERT_THROWS(x.notTerm(), CVC4ApiException&); + Term f = d_solver.mkVar("f", funSort1); + TS_ASSERT_THROWS(f.notTerm(), CVC4ApiException&); + Term p = d_solver.mkVar("p", funSort2); + TS_ASSERT_THROWS(p.notTerm(), CVC4ApiException&); + Term zero = d_solver.mkInteger(0); + TS_ASSERT_THROWS(zero.notTerm(), CVC4ApiException&); + Term f_x = d_solver.mkTerm(APPLY_UF, f, x); + TS_ASSERT_THROWS(f_x.notTerm(), CVC4ApiException&); + Term sum = d_solver.mkTerm(PLUS, f_x, f_x); + TS_ASSERT_THROWS(sum.notTerm(), CVC4ApiException&); + Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero); + TS_ASSERT_THROWS_NOTHING(p_0.notTerm()); + Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x); + TS_ASSERT_THROWS_NOTHING(p_f_x.notTerm()); +} + +void TermBlack::testAndTerm() +{ + Sort bvSort = d_solver.mkBitVectorSort(8); + Sort intSort = d_solver.getIntegerSort(); + Sort boolSort = d_solver.getBooleanSort(); + Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort); + Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort); + + Term b = d_solver.mkTrue(); + TS_ASSERT_THROWS_NOTHING(b.andTerm(b)); + Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8)); + TS_ASSERT_THROWS(x.andTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(x.andTerm(x), CVC4ApiException&); + Term f = d_solver.mkVar("f", funSort1); + TS_ASSERT_THROWS(f.andTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(f.andTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(f.andTerm(f), CVC4ApiException&); + Term p = d_solver.mkVar("p", funSort2); + TS_ASSERT_THROWS(p.andTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(p.andTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p.andTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p.andTerm(p), CVC4ApiException&); + Term zero = d_solver.mkInteger(0); + TS_ASSERT_THROWS(zero.andTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(zero.andTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(zero.andTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(zero.andTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(zero.andTerm(zero), CVC4ApiException&); + Term f_x = d_solver.mkTerm(APPLY_UF, f, x); + TS_ASSERT_THROWS(f_x.andTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.andTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.andTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.andTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.andTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.andTerm(f_x), CVC4ApiException&); + Term sum = d_solver.mkTerm(PLUS, f_x, f_x); + TS_ASSERT_THROWS(sum.andTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(sum.andTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(sum.andTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(sum.andTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(sum.andTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(sum.andTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(sum.andTerm(sum), CVC4ApiException&); + Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero); + TS_ASSERT_THROWS_NOTHING(p_0.andTerm(b)); + TS_ASSERT_THROWS(p_0.andTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.andTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.andTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.andTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.andTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.andTerm(sum), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(p_0.andTerm(p_0)); + Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x); + TS_ASSERT_THROWS_NOTHING(p_f_x.andTerm(b)); + TS_ASSERT_THROWS(p_f_x.andTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.andTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.andTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.andTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.andTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.andTerm(sum), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(p_f_x.andTerm(p_0)); + TS_ASSERT_THROWS_NOTHING(p_f_x.andTerm(p_f_x)); +} + +void TermBlack::testOrTerm() +{ + Sort bvSort = d_solver.mkBitVectorSort(8); + Sort intSort = d_solver.getIntegerSort(); + Sort boolSort = d_solver.getBooleanSort(); + Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort); + Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort); + + Term b = d_solver.mkTrue(); + TS_ASSERT_THROWS_NOTHING(b.orTerm(b)); + Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8)); + TS_ASSERT_THROWS(x.orTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(x.orTerm(x), CVC4ApiException&); + Term f = d_solver.mkVar("f", funSort1); + TS_ASSERT_THROWS(f.orTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(f.orTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(f.orTerm(f), CVC4ApiException&); + Term p = d_solver.mkVar("p", funSort2); + TS_ASSERT_THROWS(p.orTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(p.orTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p.orTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p.orTerm(p), CVC4ApiException&); + Term zero = d_solver.mkInteger(0); + TS_ASSERT_THROWS(zero.orTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(zero.orTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(zero.orTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(zero.orTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(zero.orTerm(zero), CVC4ApiException&); + Term f_x = d_solver.mkTerm(APPLY_UF, f, x); + TS_ASSERT_THROWS(f_x.orTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.orTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.orTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.orTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.orTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.orTerm(f_x), CVC4ApiException&); + Term sum = d_solver.mkTerm(PLUS, f_x, f_x); + TS_ASSERT_THROWS(sum.orTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(sum.orTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(sum.orTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(sum.orTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(sum.orTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(sum.orTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(sum.orTerm(sum), CVC4ApiException&); + Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero); + TS_ASSERT_THROWS_NOTHING(p_0.orTerm(b)); + TS_ASSERT_THROWS(p_0.orTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.orTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.orTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.orTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.orTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.orTerm(sum), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(p_0.orTerm(p_0)); + Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x); + TS_ASSERT_THROWS_NOTHING(p_f_x.orTerm(b)); + TS_ASSERT_THROWS(p_f_x.orTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.orTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.orTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.orTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.orTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.orTerm(sum), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(p_f_x.orTerm(p_0)); + TS_ASSERT_THROWS_NOTHING(p_f_x.orTerm(p_f_x)); +} + +void TermBlack::testXorTerm() +{ + Sort bvSort = d_solver.mkBitVectorSort(8); + Sort intSort = d_solver.getIntegerSort(); + Sort boolSort = d_solver.getBooleanSort(); + Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort); + Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort); + + Term b = d_solver.mkTrue(); + TS_ASSERT_THROWS_NOTHING(b.xorTerm(b)); + Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8)); + TS_ASSERT_THROWS(x.xorTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(x.xorTerm(x), CVC4ApiException&); + Term f = d_solver.mkVar("f", funSort1); + TS_ASSERT_THROWS(f.xorTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(f.xorTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(f.xorTerm(f), CVC4ApiException&); + Term p = d_solver.mkVar("p", funSort2); + TS_ASSERT_THROWS(p.xorTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(p.xorTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p.xorTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p.xorTerm(p), CVC4ApiException&); + Term zero = d_solver.mkInteger(0); + TS_ASSERT_THROWS(zero.xorTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(zero.xorTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(zero.xorTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(zero.xorTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(zero.xorTerm(zero), CVC4ApiException&); + Term f_x = d_solver.mkTerm(APPLY_UF, f, x); + TS_ASSERT_THROWS(f_x.xorTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.xorTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.xorTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.xorTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.xorTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.xorTerm(f_x), CVC4ApiException&); + Term sum = d_solver.mkTerm(PLUS, f_x, f_x); + TS_ASSERT_THROWS(sum.xorTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(sum.xorTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(sum.xorTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(sum.xorTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(sum.xorTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(sum.xorTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(sum.xorTerm(sum), CVC4ApiException&); + Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero); + TS_ASSERT_THROWS_NOTHING(p_0.xorTerm(b)); + TS_ASSERT_THROWS(p_0.xorTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.xorTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.xorTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.xorTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.xorTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.xorTerm(sum), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(p_0.xorTerm(p_0)); + Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x); + TS_ASSERT_THROWS_NOTHING(p_f_x.xorTerm(b)); + TS_ASSERT_THROWS(p_f_x.xorTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.xorTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.xorTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.xorTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.xorTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.xorTerm(sum), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(p_f_x.xorTerm(p_0)); + TS_ASSERT_THROWS_NOTHING(p_f_x.xorTerm(p_f_x)); +} + +void TermBlack::testEqTerm() +{ + Sort bvSort = d_solver.mkBitVectorSort(8); + Sort intSort = d_solver.getIntegerSort(); + Sort boolSort = d_solver.getBooleanSort(); + Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort); + Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort); + + Term b = d_solver.mkTrue(); + TS_ASSERT_THROWS_NOTHING(b.eqTerm(b)); + Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8)); + TS_ASSERT_THROWS(x.eqTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(x.eqTerm(x)); + Term f = d_solver.mkVar("f", funSort1); + TS_ASSERT_THROWS(f.eqTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(f.eqTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(f.eqTerm(f)); + Term p = d_solver.mkVar("p", funSort2); + TS_ASSERT_THROWS(p.eqTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(p.eqTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p.eqTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(p.eqTerm(p)); + Term zero = d_solver.mkInteger(0); + TS_ASSERT_THROWS(zero.eqTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(zero.eqTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(zero.eqTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(zero.eqTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(zero.eqTerm(zero)); + Term f_x = d_solver.mkTerm(APPLY_UF, f, x); + TS_ASSERT_THROWS(f_x.eqTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.eqTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.eqTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.eqTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(f_x.eqTerm(zero)); + TS_ASSERT_THROWS_NOTHING(f_x.eqTerm(f_x)); + Term sum = d_solver.mkTerm(PLUS, f_x, f_x); + TS_ASSERT_THROWS(sum.eqTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(sum.eqTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(sum.eqTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(sum.eqTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(sum.eqTerm(zero)); + TS_ASSERT_THROWS_NOTHING(sum.eqTerm(f_x)); + TS_ASSERT_THROWS_NOTHING(sum.eqTerm(sum)); + Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero); + TS_ASSERT_THROWS_NOTHING(p_0.eqTerm(b)); + TS_ASSERT_THROWS(p_0.eqTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.eqTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.eqTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.eqTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.eqTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.eqTerm(sum), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(p_0.eqTerm(p_0)); + Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x); + TS_ASSERT_THROWS_NOTHING(p_f_x.eqTerm(b)); + TS_ASSERT_THROWS(p_f_x.eqTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.eqTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.eqTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.eqTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.eqTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.eqTerm(sum), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(p_f_x.eqTerm(p_0)); + TS_ASSERT_THROWS_NOTHING(p_f_x.eqTerm(p_f_x)); +} + +void TermBlack::testImpTerm() +{ + Sort bvSort = d_solver.mkBitVectorSort(8); + Sort intSort = d_solver.getIntegerSort(); + Sort boolSort = d_solver.getBooleanSort(); + Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort); + Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort); + + Term b = d_solver.mkTrue(); + TS_ASSERT_THROWS_NOTHING(b.impTerm(b)); + Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8)); + TS_ASSERT_THROWS(x.impTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(x.impTerm(x), CVC4ApiException&); + Term f = d_solver.mkVar("f", funSort1); + TS_ASSERT_THROWS(f.impTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(f.impTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(f.impTerm(f), CVC4ApiException&); + Term p = d_solver.mkVar("p", funSort2); + TS_ASSERT_THROWS(p.impTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(p.impTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p.impTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p.impTerm(p), CVC4ApiException&); + Term zero = d_solver.mkInteger(0); + TS_ASSERT_THROWS(zero.impTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(zero.impTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(zero.impTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(zero.impTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(zero.impTerm(zero), CVC4ApiException&); + Term f_x = d_solver.mkTerm(APPLY_UF, f, x); + TS_ASSERT_THROWS(f_x.impTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.impTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.impTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.impTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.impTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.impTerm(f_x), CVC4ApiException&); + Term sum = d_solver.mkTerm(PLUS, f_x, f_x); + TS_ASSERT_THROWS(sum.impTerm(b), CVC4ApiException&); + TS_ASSERT_THROWS(sum.impTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(sum.impTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(sum.impTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(sum.impTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(sum.impTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(sum.impTerm(sum), CVC4ApiException&); + Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero); + TS_ASSERT_THROWS_NOTHING(p_0.impTerm(b)); + TS_ASSERT_THROWS(p_0.impTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.impTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.impTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.impTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.impTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(p_0.impTerm(sum), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(p_0.impTerm(p_0)); + Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x); + TS_ASSERT_THROWS_NOTHING(p_f_x.impTerm(b)); + TS_ASSERT_THROWS(p_f_x.impTerm(x), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.impTerm(f), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.impTerm(p), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.impTerm(zero), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.impTerm(f_x), CVC4ApiException&); + TS_ASSERT_THROWS(p_f_x.impTerm(sum), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(p_f_x.impTerm(p_0)); + TS_ASSERT_THROWS_NOTHING(p_f_x.impTerm(p_f_x)); +} + +void TermBlack::testIteTerm() +{ + Sort bvSort = d_solver.mkBitVectorSort(8); + Sort intSort = d_solver.getIntegerSort(); + Sort boolSort = d_solver.getBooleanSort(); + Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort); + Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort); + + Term b = d_solver.mkTrue(); + TS_ASSERT_THROWS_NOTHING(b.iteTerm(b, b)); + Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8)); + TS_ASSERT_THROWS_NOTHING(b.iteTerm(x, x)); + TS_ASSERT_THROWS_NOTHING(b.iteTerm(b, b)); + TS_ASSERT_THROWS(b.iteTerm(x, b), CVC4ApiException&); + TS_ASSERT_THROWS(x.iteTerm(x, x), CVC4ApiException&); + TS_ASSERT_THROWS(x.iteTerm(x, b), CVC4ApiException&); + Term f = d_solver.mkVar("f", funSort1); + TS_ASSERT_THROWS(f.iteTerm(b, b), CVC4ApiException&); + TS_ASSERT_THROWS(x.iteTerm(b, x), CVC4ApiException&); + Term p = d_solver.mkVar("p", funSort2); + TS_ASSERT_THROWS(p.iteTerm(b, b), CVC4ApiException&); + TS_ASSERT_THROWS(p.iteTerm(x, b), CVC4ApiException&); + Term zero = d_solver.mkInteger(0); + TS_ASSERT_THROWS(zero.iteTerm(x, x), CVC4ApiException&); + TS_ASSERT_THROWS(zero.iteTerm(x, b), CVC4ApiException&); + Term f_x = d_solver.mkTerm(APPLY_UF, f, x); + TS_ASSERT_THROWS(f_x.iteTerm(b, b), CVC4ApiException&); + TS_ASSERT_THROWS(f_x.iteTerm(b, x), CVC4ApiException&); + Term sum = d_solver.mkTerm(PLUS, f_x, f_x); + TS_ASSERT_THROWS(sum.iteTerm(x, x), CVC4ApiException&); + TS_ASSERT_THROWS(sum.iteTerm(b, x), CVC4ApiException&); + Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero); + TS_ASSERT_THROWS_NOTHING(p_0.iteTerm(b, b)); + TS_ASSERT_THROWS_NOTHING(p_0.iteTerm(x, x)); + TS_ASSERT_THROWS(p_0.iteTerm(x, b), CVC4ApiException&); + Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x); + TS_ASSERT_THROWS_NOTHING(p_f_x.iteTerm(b, b)); + TS_ASSERT_THROWS_NOTHING(p_f_x.iteTerm(x, x)); + TS_ASSERT_THROWS(p_f_x.iteTerm(x, b), CVC4ApiException&); +} + +void TermBlack::testTermAssignment() +{ + Term t1 = d_solver.mkReal(1); + Term t2 = t1; + t2 = d_solver.mkReal(2); + TS_ASSERT_EQUALS(t1, d_solver.mkReal(1)); +} -- cgit v1.2.3 From 6660ab05c399d309208251263faeff3be2964f7b Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Mon, 17 Dec 2018 15:01:23 -0800 Subject: Configured for linking against drat2er (#2754) drat2er is a C/C++ project which includes support for * Checking DRAT proofs * Converting DRAT proofs to LRAT proofs * Converting DRAT proofs to ER proofs It does the first 2 by using drat-trim under the hood. I've modified our CMake configuration to allow drat2er to be linked into CVC4, and I added a contrib script. --- CMakeLists.txt | 12 ++++++++++++ cmake/FindDrat2Er.cmake | 31 +++++++++++++++++++++++++++++++ configure.sh | 14 ++++++++++++++ contrib/get-drat2er | 25 +++++++++++++++++++++++++ src/CMakeLists.txt | 4 ++++ src/base/configuration_private.h | 6 ++++++ 6 files changed, 92 insertions(+) create mode 100644 cmake/FindDrat2Er.cmake create mode 100755 contrib/get-drat2er diff --git a/CMakeLists.txt b/CMakeLists.txt index 099fc00fa..3265830cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,6 +93,7 @@ cvc4_option(USE_READLINE "Use readline for better interactive support") # > for options where we don't need to detect if set by user (default: OFF) option(USE_CADICAL "Use CaDiCaL SAT solver") option(USE_CRYPTOMINISAT "Use CryptoMiniSat SAT solver") +option(USE_DRAT2ER "Include drat2er for making eager BV proofs") option(USE_LFSC "Use LFSC proof checker") option(USE_SYMFPU "Use SymFPU for floating point support") option(USE_PYTHON2 "Prefer using Python 2 (for Python bindings)") @@ -108,6 +109,7 @@ set(ANTLR_DIR "" CACHE STRING "Set ANTLR3 install directory") set(CADICAL_DIR "" CACHE STRING "Set CaDiCaL install directory") set(CRYPTOMINISAT_DIR "" CACHE STRING "Set CryptoMiniSat install directory") set(CXXTEST_DIR "" CACHE STRING "Set CxxTest install directory") +set(DRAT2ER_DIR "" CACHE STRING "Set drat2er install directory") set(GLPK_DIR "" CACHE STRING "Set GLPK install directory") set(GMP_DIR "" CACHE STRING "Set GMP install directory") set(LFSC_DIR "" CACHE STRING "Set LFSC install directory") @@ -410,6 +412,12 @@ if(USE_CRYPTOMINISAT) add_definitions(-DCVC4_USE_CRYPTOMINISAT) endif() +if(USE_DRAT2ER) + set(Drat2Er_HOME ${DRAT2ER_DIR}) + find_package(Drat2Er REQUIRED) + add_definitions(-DCVC4_USE_DRAT2ER) +endif() + if(USE_GLPK) set(GPL_LIBS "${GPL_LIBS} glpk") set(GLPK_HOME ${GLPK_DIR}) @@ -523,6 +531,7 @@ message("") print_config("ABC :" USE_ABC) print_config("CaDiCaL :" USE_CADICAL) print_config("CryptoMiniSat :" USE_CRYPTOMINISAT) +print_config("drat2er :" USE_DRAT2ER) print_config("GLPK :" USE_GLPK) print_config("LFSC :" USE_LFSC) @@ -546,6 +555,9 @@ endif() if(CRYPTOMINISAT_DIR) message("CRYPTOMINISAT dir : ${CRYPTOMINISAT_DIR}") endif() +if(DRAT2ER_DIR) + message("DRAT2ER dir : ${DRAT2ER_DIR}") +endif() if(GLPK_DIR) message("GLPK dir : ${GLPK_DIR}") endif() diff --git a/cmake/FindDrat2Er.cmake b/cmake/FindDrat2Er.cmake new file mode 100644 index 000000000..e0bc8d446 --- /dev/null +++ b/cmake/FindDrat2Er.cmake @@ -0,0 +1,31 @@ +# Find drat2er +# Drat2Er_FOUND - system has Drat2Er lib +# Drat2Er_INCLUDE_DIR - the Drat2Er include directory +# Drat2Er_LIBRARIES - Libraries needed to use Drat2Er + + +# Check default location of Drat2Er built with contrib/get-drat2er. +# If the user provides a directory we will not search the default paths and +# fail if Drat2Er was not found in the specified directory. +if(NOT Drat2Er_HOME) + set(Drat2Er_HOME ${PROJECT_SOURCE_DIR}/drat2er/build/install) +endif() + +find_path(Drat2Er_INCLUDE_DIR + NAMES drat2er.h + PATHS ${Drat2Er_HOME}/include + NO_DEFAULT_PATH) +find_library(Drat2Er_LIBRARIES + NAMES libdrat2er.a + PATHS ${Drat2Er_HOME}/lib + NO_DEFAULT_PATH) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Drat2Er + DEFAULT_MSG + Drat2Er_INCLUDE_DIR Drat2Er_LIBRARIES) + +mark_as_advanced(Drat2Er_INCLUDE_DIR Drat2Er_LIBRARIES) +if(Drat2Er_LIBRARIES) + message(STATUS "Found Drat2Er libs: ${Drat2Er_LIBRARIES}") +endif() diff --git a/configure.sh b/configure.sh index 7fa842f70..e53d8caa7 100755 --- a/configure.sh +++ b/configure.sh @@ -55,6 +55,7 @@ The following flags enable optional packages (disable with --no-