summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaniel Barbosa <hanielbbarbosa@gmail.com>2020-05-18 20:00:37 -0300
committerHaniel Barbosa <hanielbbarbosa@gmail.com>2020-05-18 20:00:37 -0300
commitd7d4a134ce89d1a0ad42468306b0cb9d216d5ac6 (patch)
tree18d6e3fc7620e35837bd41a0f47917f21e2cdadd
parent4df56a4fe3da185d3a2dabfb92a7370b07b72871 (diff)
parentafc01bf9df9a36b6c8f83ff9706cfa349da8d24a (diff)
Merge branch 'stringsPf' into fix-eqproof4
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/README1
-rw-r--r--src/expr/proof.cpp7
-rw-r--r--src/expr/proof.h7
-rw-r--r--src/expr/proof_node_manager.cpp97
-rw-r--r--src/expr/proof_node_manager.h5
-rw-r--r--src/prop/theory_proxy.cpp4
-rw-r--r--src/theory/builtin/proof_checker.cpp209
-rw-r--r--src/theory/builtin/proof_checker.h54
-rw-r--r--src/theory/builtin/proof_kinds4
-rw-r--r--src/theory/eager_proof_generator.cpp7
-rw-r--r--src/theory/engine_output_channel.cpp21
-rw-r--r--src/theory/engine_output_channel.h25
-rw-r--r--src/theory/proof_engine_output_channel.cpp100
-rw-r--r--src/theory/proof_engine_output_channel.h99
-rw-r--r--src/theory/shared_terms_database.cpp51
-rw-r--r--src/theory/shared_terms_database.h38
-rw-r--r--src/theory/strings/core_solver.cpp36
-rw-r--r--src/theory/strings/infer_proof_cons.cpp76
-rw-r--r--src/theory/strings/infer_proof_cons.h13
-rw-r--r--src/theory/strings/proof_checker.cpp4
-rw-r--r--src/theory/theory_engine.cpp356
-rw-r--r--src/theory/theory_engine.h42
-rw-r--r--src/theory/theory_engine_proof_generator.cpp84
-rw-r--r--src/theory/theory_engine_proof_generator.h58
-rw-r--r--src/theory/trust_node.cpp56
-rw-r--r--src/theory/trust_node.h44
-rw-r--r--src/theory/uf/eq_proof.h3
-rw-r--r--src/theory/uf/equality_engine.cpp12
-rw-r--r--src/theory/uf/proof_equality_engine.cpp6
30 files changed, 966 insertions, 557 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2ac73f067..f5be109ed 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -450,8 +450,6 @@ libcvc4_add_sources(
theory/logic_info.cpp
theory/logic_info.h
theory/output_channel.h
- theory/proof_engine_output_channel.cpp
- theory/proof_engine_output_channel.h
theory/quantifiers/alpha_equivalence.cpp
theory/quantifiers/alpha_equivalence.h
theory/quantifiers/anti_skolem.cpp
@@ -748,6 +746,8 @@ libcvc4_add_sources(
theory/theory.h
theory/theory_engine.cpp
theory/theory_engine.h
+ theory/theory_engine_proof_generator.cpp
+ theory/theory_engine_proof_generator.h
theory/theory_id.cpp
theory/theory_id.h
theory/theory_model.cpp
diff --git a/src/README b/src/README
index c7a940837..1de6ac991 100644
--- a/src/README
+++ b/src/README
@@ -80,7 +80,6 @@ PRs:
(6) Split EngineOutputChannel from TheoryEngine to its own file
(7) Add LazyCDProof and ProofGenerator
(8) Add TrustNode
-(9) Add ProofEngineOutputChannel
- Add EagerProofGenerator
(10) ProofEqEngine
(11) TheoryEngine proof checker initialize
diff --git a/src/expr/proof.cpp b/src/expr/proof.cpp
index 8ec55d1f5..15e996684 100644
--- a/src/expr/proof.cpp
+++ b/src/expr/proof.cpp
@@ -381,4 +381,11 @@ bool CDProof::isAssumption(ProofNode* pn)
return false;
}
+bool CDProof::isSame(TNode f, TNode g)
+{
+ return f == g
+ || (f.getKind() == EQUAL && g.getKind() == EQUAL && f[0] == g[1]
+ && f[1] == g[0]);
+}
+
} // namespace CVC4
diff --git a/src/expr/proof.h b/src/expr/proof.h
index e5b2775d9..2ff3604f8 100644
--- a/src/expr/proof.h
+++ b/src/expr/proof.h
@@ -206,6 +206,13 @@ class CDProof
/** Get the proof manager for this proof */
ProofNodeManager* getManager() const;
+ /**
+ * Is same? Returns true if f and g are the same formula, or if they are
+ * symmetric equalities. If two nodes f and g are the same, then a proof for
+ * f suffices as a proof for g according to this class.
+ */
+ static bool isSame(TNode f, TNode g);
+
protected:
typedef context::CDHashMap<Node, std::shared_ptr<ProofNode>, NodeHashFunction>
NodeProofNodeMap;
diff --git a/src/expr/proof_node_manager.cpp b/src/expr/proof_node_manager.cpp
index f15e43553..f1ec78aab 100644
--- a/src/expr/proof_node_manager.cpp
+++ b/src/expr/proof_node_manager.cpp
@@ -60,6 +60,103 @@ std::shared_ptr<ProofNode> ProofNodeManager::mkAssume(Node fact)
return mkNode(PfRule::ASSUME, children, args, fact);
}
+std::shared_ptr<ProofNode> ProofNodeManager::mkScope(
+ std::shared_ptr<ProofNode> pf,
+ std::vector<Node>& assumps,
+ bool ensureClosed)
+{
+ std::vector<std::shared_ptr<ProofNode>> pfChildren;
+ pfChildren.push_back(pf);
+ if (!ensureClosed)
+ {
+ return mkNode(PfRule::SCOPE, pfChildren, assumps);
+ }
+ Trace("pnm-scope") << "ProofNodeManager::mkScope " << assumps << std::endl;
+ // we first ensure the assumptions are flattened
+ std::unordered_set<Node, NodeHashFunction> ac;
+ for (const TNode& a : assumps)
+ {
+ if (a.getKind() == AND)
+ {
+ ac.insert(a.begin(), a.end());
+ }
+ else
+ {
+ ac.insert(a);
+ }
+ }
+ // The free assumptions of the proof
+ std::map<Node, std::vector<ProofNode*>> famap;
+ pf->getFreeAssumptionsMap(famap);
+ std::unordered_set<Node, NodeHashFunction> acu;
+ std::unordered_set<Node, NodeHashFunction>::iterator itf;
+ for (const std::pair<const Node, std::vector<ProofNode*>>& fa : famap)
+ {
+ Node a = fa.first;
+ if (ac.find(a) != ac.end())
+ {
+ // already covered by an assumption
+ acu.insert(a);
+ continue;
+ }
+ // otherwise it may be due to symmetry?
+ bool polarity = a.getKind() != NOT;
+ Node aeq = polarity ? a : a[0];
+ if (aeq.getKind() == EQUAL)
+ {
+ Node aeqSym = aeq[1].eqNode(aeq[0]);
+ aeqSym = polarity ? aeqSym : aeqSym.notNode();
+ itf = ac.find(aeqSym);
+ if (itf != ac.end())
+ {
+ Trace("pnm-scope") << "- reorient assumption " << aeqSym << " via " << a
+ << " for " << fa.second.size() << " proof nodes"
+ << std::endl;
+ std::shared_ptr<ProofNode> pfaa = mkAssume(aeqSym);
+ for (ProofNode* pfs : fa.second)
+ {
+ Assert(pfs->getResult() == a);
+ // must correct the orientation on this leaf
+ std::vector<std::shared_ptr<ProofNode>> children;
+ children.push_back(pfaa);
+ std::vector<Node> args;
+ args.push_back(a);
+ updateNode(pfs, PfRule::MACRO_SR_PRED_TRANSFORM, children, args);
+ }
+ Trace("pnm-scope") << "...finished" << std::endl;
+ acu.insert(aeqSym);
+ continue;
+ }
+ }
+ // All free assumptions should be arguments to SCOPE.
+ std::stringstream ss;
+ pf->printDebug(ss);
+ ss << std::endl << "Free assumption: " << a << std::endl;
+ for (const Node& aprint : ac)
+ {
+ ss << "- assumption: " << aprint << std::endl;
+ }
+ AlwaysAssert(false) << "Generated a proof that is not closed by the scope: "
+ << ss.str() << std::endl;
+ }
+ if (acu.size() < ac.size())
+ {
+ // All assumptions should match a free assumption; if one does not, then
+ // the explanation could have been smaller.
+ for (const Node& a : ac)
+ {
+ if (acu.find(a) == acu.end())
+ {
+ Notice() << "ProofNodeManager::mkScope: assumption " << a
+ << " does not match a free assumption in proof" << std::endl;
+ }
+ }
+ }
+ assumps.clear();
+ assumps.insert(assumps.end(), acu.begin(), acu.end());
+ return mkNode(PfRule::SCOPE, pfChildren, assumps);
+}
+
bool ProofNodeManager::updateNode(
ProofNode* pn,
PfRule id,
diff --git a/src/expr/proof_node_manager.h b/src/expr/proof_node_manager.h
index 9904a78ec..527f2562d 100644
--- a/src/expr/proof_node_manager.h
+++ b/src/expr/proof_node_manager.h
@@ -80,6 +80,11 @@ class ProofNodeManager
Node expected = Node::null());
/** Make assume */
std::shared_ptr<ProofNode> mkAssume(Node fact);
+ /** Make scope */
+ std::shared_ptr<ProofNode> mkScope(std::shared_ptr<ProofNode> pf,
+ std::vector<Node>& assumps,
+ bool ensureClosed = true);
+
/**
* This method updates pn to be a proof of the form <id>( children, args ),
* while maintaining its d_proven field. This method returns false if this
diff --git a/src/prop/theory_proxy.cpp b/src/prop/theory_proxy.cpp
index 38c99f551..2c6d22d27 100644
--- a/src/prop/theory_proxy.cpp
+++ b/src/prop/theory_proxy.cpp
@@ -79,7 +79,9 @@ void TheoryProxy::explainPropagation(SatLiteral l, SatClause& explanation) {
LemmaProofRecipe* proofRecipe = NULL;
PROOF(proofRecipe = new LemmaProofRecipe;);
- Node theoryExplanation = d_theoryEngine->getExplanationAndRecipe(lNode, proofRecipe);
+ theory::TrustNode tte =
+ d_theoryEngine->getExplanationAndRecipe(lNode, proofRecipe);
+ Node theoryExplanation = tte.getNode();
PROOF({
ProofManager::getCnfProof()->pushCurrentAssertion(theoryExplanation);
diff --git a/src/theory/builtin/proof_checker.cpp b/src/theory/builtin/proof_checker.cpp
index ddc222ffb..8c47bc060 100644
--- a/src/theory/builtin/proof_checker.cpp
+++ b/src/theory/builtin/proof_checker.cpp
@@ -22,23 +22,30 @@ using namespace CVC4::kind;
namespace CVC4 {
namespace theory {
-const char* toString(RewriterId id)
+const char* toString(MethodId id)
{
switch (id)
{
- case RewriterId::REWRITE: return "REWRITE";
- case RewriterId::REWRITE_EQ_EXT: return "REWRITE_EQ_EXT";
- case RewriterId::IDENTITY: return "IDENTITY";
- default: return "RewriterId::Unknown";
+ case MethodId::RW_REWRITE: return "RW_REWRITE";
+ case MethodId::RW_REWRITE_EQ_EXT: return "RW_REWRITE_EQ_EXT";
+ case MethodId::RW_IDENTITY: return "RW_IDENTITY";
+ case MethodId::SB_DEFAULT: return "SB_DEFAULT";
+ case MethodId::SB_PREDICATE: return "SB_PREDICATE";
+ default: return "MethodId::Unknown";
};
}
-std::ostream& operator<<(std::ostream& out, RewriterId id)
+std::ostream& operator<<(std::ostream& out, MethodId id)
{
out << toString(id);
return out;
}
+Node mkMethodId(MethodId id)
+{
+ return NodeManager::currentNM()->mkConst(Rational(static_cast<uint32_t>(id)));
+}
+
namespace builtin {
void BuiltinProofRuleChecker::registerTo(ProofChecker* pc)
@@ -55,109 +62,131 @@ void BuiltinProofRuleChecker::registerTo(ProofChecker* pc)
pc->registerChecker(PfRule::THEORY_LEMMA, nullptr);
}
-Node BuiltinProofRuleChecker::applyRewrite(Node n, RewriterId id)
+Node BuiltinProofRuleChecker::applyRewrite(Node n, MethodId idr)
{
Node nk = ProofSkolemCache::getSkolemForm(n);
- Node nkr = applyRewriteExternal(n, id);
+ Node nkr = applyRewriteExternal(n, idr);
return ProofSkolemCache::getWitnessForm(nkr);
}
-Node BuiltinProofRuleChecker::applySubstitution(Node n, Node exp)
+Node BuiltinProofRuleChecker::applySubstitution(Node n, Node exp, MethodId ids)
{
if (exp.isNull() || exp.getKind() != EQUAL)
{
return Node::null();
}
Node nk = ProofSkolemCache::getSkolemForm(n);
- Node nks = applySubstitutionExternal(nk, exp);
+ Node nks = applySubstitutionExternal(nk, exp, ids);
return ProofSkolemCache::getWitnessForm(nks);
}
Node BuiltinProofRuleChecker::applySubstitution(Node n,
- const std::vector<Node>& exp)
+ const std::vector<Node>& exp,
+ MethodId ids)
{
Node nk = ProofSkolemCache::getSkolemForm(n);
- Node nks = applySubstitutionExternal(nk, exp);
+ Node nks = applySubstitutionExternal(nk, exp, ids);
return ProofSkolemCache::getWitnessForm(nks);
}
Node BuiltinProofRuleChecker::applySubstitutionRewrite(
- Node n, const std::vector<Node>& exp, RewriterId id)
+ Node n, const std::vector<Node>& exp, MethodId ids, MethodId idr)
{
Node nk = ProofSkolemCache::getSkolemForm(n);
- Node nks = applySubstitutionExternal(nk, exp);
- Node nksr = applyRewriteExternal(nks, id);
+ Node nks = applySubstitutionExternal(nk, exp, ids);
+ Node nksr = applyRewriteExternal(nks, idr);
return ProofSkolemCache::getWitnessForm(nksr);
}
-Node BuiltinProofRuleChecker::applyRewriteExternal(Node n, RewriterId id)
+Node BuiltinProofRuleChecker::applyRewriteExternal(Node n, MethodId idr)
{
Trace("builtin-pfcheck-debug")
- << "applyRewriteExternal (" << id << "): " << n << std::endl;
+ << "applyRewriteExternal (" << idr << "): " << n << std::endl;
// index determines the kind of rewriter
- if (id == RewriterId::REWRITE)
+ if (idr == MethodId::RW_REWRITE)
{
return Rewriter::rewrite(n);
}
- else if (id == RewriterId::REWRITE_EQ_EXT)
+ else if (idr == MethodId::RW_REWRITE_EQ_EXT)
{
Node ret = Rewriter::rewriteEqualityExt(n);
// also rewrite
return Rewriter::rewrite(ret);
}
- else if (id == RewriterId::IDENTITY)
+ else if (idr == MethodId::RW_IDENTITY)
{
// does nothing
return n;
}
// unknown rewriter
Assert(false)
- << "BuiltinProofRuleChecker::applyRewriteExternal: no rewriter for " << id
- << std::endl;
+ << "BuiltinProofRuleChecker::applyRewriteExternal: no rewriter for "
+ << idr << std::endl;
return n;
}
-Node BuiltinProofRuleChecker::applySubstitutionExternal(Node n, Node exp)
+Node BuiltinProofRuleChecker::applySubstitutionExternal(Node n,
+ Node exp,
+ MethodId ids)
{
- Assert(!exp.isNull() && exp.getKind() == EQUAL);
+ Assert(!exp.isNull());
Node expk = ProofSkolemCache::getSkolemForm(exp);
- TNode var = expk[0];
- TNode subs = expk[1];
+ TNode var, subs;
+ if (ids == MethodId::SB_DEFAULT)
+ {
+ if (expk.getKind() != EQUAL)
+ {
+ return Node::null();
+ }
+ var = expk[0];
+ subs = expk[1];
+ }
+ else if (ids == MethodId::SB_PREDICATE)
+ {
+ bool polarity = expk.getKind() != NOT;
+ var = polarity ? expk : expk[0];
+ subs = NodeManager::currentNM()->mkConst(polarity);
+ }
+ else
+ {
+ Assert(false) << "BuiltinProofRuleChecker::applySubstitutionExternal: no "
+ "substitution for "
+ << ids << std::endl;
+ }
return n.substitute(var, subs);
}
Node BuiltinProofRuleChecker::applySubstitutionExternal(
- Node n, const std::vector<Node>& exp)
+ Node n, const std::vector<Node>& exp, MethodId ids)
{
Node curr = n;
// apply substitution one at a time, in reverse order
for (size_t i = 0, nexp = exp.size(); i < nexp; i++)
{
- if (exp[nexp - 1 - i].isNull() || exp[nexp - 1 - i].getKind() != EQUAL)
+ if (exp[nexp - 1 - i].isNull())
{
return Node::null();
}
- curr = applySubstitutionExternal(curr, exp[nexp - 1 - i]);
+ curr = applySubstitutionExternal(curr, exp[nexp - 1 - i], ids);
+ if (curr.isNull())
+ {
+ break;
+ }
}
return curr;
}
-bool BuiltinProofRuleChecker::getRewriterId(TNode n, RewriterId& i)
+bool BuiltinProofRuleChecker::getMethodId(TNode n, MethodId& i)
{
uint32_t index;
if (!getIndex(n, index))
{
return false;
}
- i = static_cast<RewriterId>(index);
+ i = static_cast<MethodId>(index);
return true;
}
-Node BuiltinProofRuleChecker::mkRewriterId(RewriterId i)
-{
- return NodeManager::currentNM()->mkConst(Rational(static_cast<uint32_t>(i)));
-}
-
Node BuiltinProofRuleChecker::checkInternal(PfRule id,
const std::vector<Node>& children,
const std::vector<Node>& args)
@@ -189,7 +218,12 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
else if (id == PfRule::SUBS)
{
Assert(children.size() > 0);
- Assert(args.size() == 1);
+ Assert(1 <= args.size() && args.size() <= 2);
+ MethodId ids = MethodId::SB_DEFAULT;
+ if (args.size() == 2 && !getMethodId(args[1], ids))
+ {
+ return Node::null();
+ }
std::vector<Node> exp;
for (size_t i = 0, nchild = children.size(); i < nchild; i++)
{
@@ -201,7 +235,12 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
else if (id == PfRule::REWRITE)
{
Assert(children.empty());
- Assert(args.size() == 1);
+ Assert(1 <= args.size() && args.size() <= 2);
+ MethodId ids = MethodId::RW_REWRITE;
+ if (args.size() == 2 && !getMethodId(args[1], ids))
+ {
+ return Node::null();
+ }
Node res = applyRewrite(args[0]);
return args[0].eqNode(res);
}
@@ -211,18 +250,13 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
// (TRANS
// (SUBS P1 ... Pn t)
// (REWRITE <t.substitute(xn,tn). ... .substitute(x1,t1)>))
- Assert(1 <= args.size() && args.size() <= 2);
- RewriterId idRewriter = RewriterId::REWRITE;
- if (args.size() >= 2)
+ Assert(1 <= args.size() && args.size() <= 3);
+ MethodId ids, idr;
+ if (!getMethodIds(args, ids, idr, 1))
{
- if (!getRewriterId(args[1], idRewriter))
- {
- Trace("builtin-pfcheck")
- << "Failed to get id from " << args[1] << std::endl;
- return Node::null();
- }
+ return Node::null();
}
- Node res = applySubstitutionRewrite(args[0], children, idRewriter);
+ Node res = applySubstitutionRewrite(args[0], children, idr);
return args[0].eqNode(res);
}
else if (id == PfRule::MACRO_SR_PRED_INTRO)
@@ -232,18 +266,13 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
// NOTE: technically a macro:
// (TRUE_ELIM
// (MACRO_SR_EQ_INTRO <children> <args>[0]))
- Assert(1 <= args.size() && args.size() <= 2);
- RewriterId idRewriter = RewriterId::REWRITE;
- if (args.size() >= 2)
+ Assert(1 <= args.size() && args.size() <= 3);
+ MethodId ids, idr;
+ if (!getMethodIds(args, ids, idr, 1))
{
- if (!getRewriterId(args[1], idRewriter))
- {
- Trace("builtin-pfcheck")
- << "Failed to get id from " << args[1] << std::endl;
- return Node::null();
- }
+ return Node::null();
}
- Node res = applySubstitutionRewrite(args[0], children, idRewriter);
+ Node res = applySubstitutionRewrite(args[0], children, ids, idr);
if (res.isNull())
{
return Node::null();
@@ -264,7 +293,7 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
Trace("builtin-pfcheck") << "Check " << id << " " << children.size() << " "
<< args.size() << std::endl;
Assert(children.size() >= 1);
- Assert(args.size() <= 1);
+ Assert(args.size() <= 2);
// NOTE: technically a macro:
// (TRUE_ELIM
// (TRANS
@@ -272,17 +301,12 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
// (TRUE_INTRO <children>[0])))
std::vector<Node> exp;
exp.insert(exp.end(), children.begin() + 1, children.end());
- RewriterId idRewriter = RewriterId::REWRITE;
- if (0 < args.size())
+ MethodId ids, idr;
+ if (!getMethodIds(args, ids, idr, 0))
{
- if (!getRewriterId(args[0], idRewriter))
- {
- Trace("builtin-pfcheck")
- << "Failed to get id from " << args[0] << std::endl;
- return Node::null();
- }
+ return Node::null();
}
- Node res1 = applySubstitutionRewrite(children[0], exp, idRewriter);
+ Node res1 = applySubstitutionRewrite(children[0], exp, ids, idr);
Trace("builtin-pfcheck") << "Returned " << res1 << std::endl;
return res1;
}
@@ -291,24 +315,19 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
Trace("builtin-pfcheck") << "Check " << id << " " << children.size() << " "
<< args.size() << std::endl;
Assert(children.size() >= 1);
- Assert(args.size() <= 2);
+ Assert(1 <= args.size() && args.size() <= 3);
Assert(args[0].getType().isBoolean());
- std::vector<Node> exp;
- exp.insert(exp.end(), children.begin() + 1, children.end());
- RewriterId idRewriter = RewriterId::REWRITE;
- if (1 < args.size())
+ MethodId ids, idr;
+ if (!getMethodIds(args, ids, idr, 1))
{
- if (!getRewriterId(args[1], idRewriter))
- {
- Trace("builtin-pfcheck")
- << "Failed to get id from " << args[1] << std::endl;
- return Node::null();
- }
+ return Node::null();
}
- Node res1 = applySubstitutionRewrite(children[0], exp, idRewriter);
+ std::vector<Node> exp;
+ exp.insert(exp.end(), children.begin() + 1, children.end());
+ Node res1 = applySubstitutionRewrite(children[0], exp, ids, idr);
// Trace("builtin-pfcheck")
// << "Returned " << res1 << std::endl;
- Node res2 = applySubstitutionRewrite(args[0], exp, idRewriter);
+ Node res2 = applySubstitutionRewrite(args[0], exp, ids, idr);
// Trace("builtin-pfcheck")
// << "Returned " << res2 << " from " << args[0] << std::endl;
// can rewrite the witness forms
@@ -334,6 +353,34 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
return Node::null();
}
+bool BuiltinProofRuleChecker::getMethodIds(const std::vector<Node>& args,
+ MethodId& ids,
+ MethodId& idr,
+ size_t index)
+{
+ ids = MethodId::SB_DEFAULT;
+ idr = MethodId::RW_REWRITE;
+ if (args.size() > index)
+ {
+ if (!getMethodId(args[index], ids))
+ {
+ Trace("builtin-pfcheck")
+ << "Failed to get id from " << args[index] << std::endl;
+ return false;
+ }
+ }
+ if (args.size() > index + 1)
+ {
+ if (!getMethodId(args[index + 1], idr))
+ {
+ Trace("builtin-pfcheck")
+ << "Failed to get id from " << args[index + 1] << std::endl;
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace builtin
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/builtin/proof_checker.h b/src/theory/builtin/proof_checker.h
index 7c6f29354..afd9bad5a 100644
--- a/src/theory/builtin/proof_checker.h
+++ b/src/theory/builtin/proof_checker.h
@@ -24,26 +24,36 @@
namespace CVC4 {
namespace theory {
-/** Identifiers for rewriters.
+/** Identifiers for rewriters and substitutions.
*
* A "rewriter" is abstractly a method from Node to Node, where the output
* is semantically equivalent to the input. The identifiers below list
* various methods that have this contract. This identifier is used
* in a number of the builtin rules.
+ *
+ * A substitution is a method for turning a formula into
*/
-enum class RewriterId : uint32_t
+enum class MethodId : uint32_t
{
+ //---------------------------- Rewriters
// Rewriter::rewrite(n)
- REWRITE,
+ RW_REWRITE,
// Rewriter::rewriteExtEquality(n)
- REWRITE_EQ_EXT,
+ RW_REWRITE_EQ_EXT,
// identity
- IDENTITY,
+ RW_IDENTITY,
+ //---------------------------- Substitutions
+ // (= x y) is interpreted as x -> y, using Node::substitute(...)
+ SB_DEFAULT,
+ // (= x y) is interpreted as (= x y) -> true, using Node::substitute(...)
+ SB_PREDICATE,
};
/** Converts a rewriter id to a string. */
-const char* toString(RewriterId id);
+const char* toString(MethodId id);
/** Write a rewriter id to out */
-std::ostream& operator<<(std::ostream& out, RewriterId id);
+std::ostream& operator<<(std::ostream& out, MethodId id);
+/** Make a method id node */
+Node mkMethodId(MethodId id);
namespace builtin {
@@ -62,7 +72,7 @@ class BuiltinProofRuleChecker : public ProofRuleChecker
* @param id The identifier of the rewriter.
* @return The rewritten form of n.
*/
- static Node applyRewrite(Node n, RewriterId id = RewriterId::REWRITE);
+ static Node applyRewrite(Node n, MethodId idr = MethodId::RW_REWRITE);
/**
* Apply substitution on n (in witness form). This encapsulates the exact
* behavior of a SUBS step in a proof. Substitution is on the Skolem form of
@@ -73,8 +83,12 @@ class BuiltinProofRuleChecker : public ProofRuleChecker
* substitution
* @return The substituted form of n.
*/
- static Node applySubstitution(Node n, Node exp);
- static Node applySubstitution(Node n, const std::vector<Node>& exp);
+ static Node applySubstitution(Node n,
+ Node exp,
+ MethodId ids = MethodId::SB_DEFAULT);
+ static Node applySubstitution(Node n,
+ const std::vector<Node>& exp,
+ MethodId ids = MethodId::SB_DEFAULT);
/** Apply substitution + rewriting
*
* Combines the above two steps.
@@ -87,11 +101,10 @@ class BuiltinProofRuleChecker : public ProofRuleChecker
*/
static Node applySubstitutionRewrite(Node n,
const std::vector<Node>& exp,
- RewriterId id = RewriterId::REWRITE);
+ MethodId ids = MethodId::SB_DEFAULT,
+ MethodId idr = MethodId::RW_REWRITE);
/** get a rewriter Id from a node, return false if we fail */
- static bool getRewriterId(TNode n, RewriterId& i);
- /** Make a rewriter id node */
- static Node mkRewriterId(RewriterId i);
+ static bool getMethodId(TNode n, MethodId& i);
/** Register all rules owned by this rule checker into pc. */
void registerTo(ProofChecker* pc) override;
@@ -101,17 +114,24 @@ class BuiltinProofRuleChecker : public ProofRuleChecker
Node checkInternal(PfRule id,
const std::vector<Node>& children,
const std::vector<Node>& args) override;
+ /** get method ids */
+ bool getMethodIds(const std::vector<Node>& args,
+ MethodId& ids,
+ MethodId& idr,
+ size_t index);
/**
* Apply rewrite (on Skolem form). id is the identifier of the rewriter.
*/
- static Node applyRewriteExternal(Node n, RewriterId id = RewriterId::REWRITE);
+ static Node applyRewriteExternal(Node n, MethodId idr = MethodId::RW_REWRITE);
/**
* Apply substitution for n (on Skolem form), where exp is an equality
* (or set of equalities) in Witness form. Returns the result of
* n * { exp[0] -> exp[1] } in Skolem form.
*/
- static Node applySubstitutionExternal(Node n, Node exp);
- static Node applySubstitutionExternal(Node n, const std::vector<Node>& exp);
+ static Node applySubstitutionExternal(Node n, Node exp, MethodId ids);
+ static Node applySubstitutionExternal(Node n,
+ const std::vector<Node>& exp,
+ MethodId ids);
};
} // namespace builtin
diff --git a/src/theory/builtin/proof_kinds b/src/theory/builtin/proof_kinds
index 404dfbc06..eb9643ec3 100644
--- a/src/theory/builtin/proof_kinds
+++ b/src/theory/builtin/proof_kinds
@@ -38,7 +38,7 @@ proofrule SCOPE 1 1: ::CVC4::theory::builtin::BuiltinProofRuleChecker
// ======== Substitution
// Children: (P1:(= x1 t1), ..., Pn:(= xn tn))
-// Arguments: (t)
+// Arguments: (t, id?)
// ---------------------------------------------------------------
// Conclusion: (= t t.substitute(xn,tn). ... .substitute(x1,t1))
// Notice that the orientation of the premises matters.
@@ -46,7 +46,7 @@ proofrule SUBS 1: 1 ::CVC4::theory::builtin::BuiltinProofRuleChecker
// ======== Rewrite
// Children: none
-// Arguments: (t)
+// Arguments: (t, id?)
// ----------------------------------------
// Conclusion: (= t Rewriter::rewrite(t))
proofrule REWRITE 0 1 ::CVC4::theory::builtin::BuiltinProofRuleChecker
diff --git a/src/theory/eager_proof_generator.cpp b/src/theory/eager_proof_generator.cpp
index c2080f20e..0dc87e6ba 100644
--- a/src/theory/eager_proof_generator.cpp
+++ b/src/theory/eager_proof_generator.cpp
@@ -15,7 +15,6 @@
#include "theory/eager_proof_generator.h"
#include "expr/proof_node_manager.h"
-#include "theory/proof_engine_output_channel.h"
namespace CVC4 {
namespace theory {
@@ -30,7 +29,7 @@ void EagerProofGenerator::setProofForConflict(Node conf,
std::shared_ptr<ProofNode> pf)
{
// Normalize based on key
- Node ckey = TrustNode::getConflictKeyValue(conf);
+ Node ckey = TrustNode::getConflictProven(conf);
d_proofs[ckey] = pf;
}
@@ -38,7 +37,7 @@ void EagerProofGenerator::setProofForLemma(Node lem,
std::shared_ptr<ProofNode> pf)
{
// Normalize based on key
- Node lkey = TrustNode::getLemmaKeyValue(lem);
+ Node lkey = TrustNode::getLemmaProven(lem);
d_proofs[lkey] = pf;
}
@@ -47,7 +46,7 @@ void EagerProofGenerator::setProofForPropExp(TNode lit,
std::shared_ptr<ProofNode> pf)
{
// Normalize based on key
- Node pekey = TrustNode::getPropExpKeyValue(lit, exp);
+ Node pekey = TrustNode::getPropExpProven(lit, exp);
d_proofs[pekey] = pf;
}
diff --git a/src/theory/engine_output_channel.cpp b/src/theory/engine_output_channel.cpp
index 176d08acf..9e4e56543 100644
--- a/src/theory/engine_output_channel.cpp
+++ b/src/theory/engine_output_channel.cpp
@@ -298,5 +298,26 @@ void EngineOutputChannel::handleUserAttribute(const char* attr,
d_engine->handleUserAttribute(attr, t);
}
+void EngineOutputChannel::trustedConflict(TrustNode pconf)
+{
+ Assert(pconf.getKind() == TrustNodeKind::CONFLICT);
+ d_engine->processTrustNode(pconf, d_theory);
+ TNode conf = pconf.getNode();
+ // now, call the normal interface to conflict
+ conflict(conf);
+}
+
+LemmaStatus EngineOutputChannel::trustedLemma(TrustNode plem,
+ bool removable,
+ bool preprocess,
+ bool sendAtoms)
+{
+ Assert(plem.getKind() == TrustNodeKind::LEMMA);
+ d_engine->processTrustNode(plem, d_theory);
+ TNode lem = plem.getNode();
+ // now, call the normal interface for lemma
+ return OutputChannel::lemma(lem, removable, preprocess, sendAtoms);
+}
+
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/engine_output_channel.h b/src/theory/engine_output_channel.h
index 1699795a1..2d07d3f63 100644
--- a/src/theory/engine_output_channel.h
+++ b/src/theory/engine_output_channel.h
@@ -31,6 +31,10 @@ namespace theory {
/**
* An output channel for Theory that passes messages back to a TheoryEngine
* for a given Theory.
+ *
+ * Notice that is has interfaces trustedConflict and trustedLemma which are
+ * used for ensuring that proof generators are associated with the lemmas
+ * and conflicts sent on this output channel.
*/
class EngineOutputChannel : public theory::OutputChannel
{
@@ -63,6 +67,27 @@ class EngineOutputChannel : public theory::OutputChannel
void handleUserAttribute(const char* attr, theory::Theory* t) override;
+ /**
+ * Let pconf be the pair (Node conf, ProofGenerator * pfg). This method
+ * sends conf on the output channel of this class whose proof can be generated
+ * by the generator pfg. It calls TheoryEngine::processTrustNode,
+ * which ensures that the generator pfg is associated with conf in the
+ * lazy proof owned by the theory engine of this class.
+ */
+ void trustedConflict(TrustNode pconf) override;
+ /**
+ * Let plem be the pair (Node lem, ProofGenerator * pfg).
+ * Send lem on the output channel of this class whose proof can be generated
+ * by the generator pfg. Apart from pfg, the interface for this method is
+ * the same as OutputChannel. It calls TheoryEngine::processTrustNode,
+ * which ensures that the generator pfg is associated with lem in the
+ * lazy proof owned by the theory engine of this class.
+ */
+ LemmaStatus trustedLemma(TrustNode plem,
+ bool removable = false,
+ bool preprocess = false,
+ bool sendAtoms = false) override;
+
protected:
/**
* Statistics for a particular theory.
diff --git a/src/theory/proof_engine_output_channel.cpp b/src/theory/proof_engine_output_channel.cpp
deleted file mode 100644
index 4f35a7639..000000000
--- a/src/theory/proof_engine_output_channel.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/********************* */
-/*! \file proof_engine_output_channel.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 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 Evaluator class
- **
- ** The Evaluator class.
- **/
-
-#include "theory/proof_engine_output_channel.h"
-
-#include "expr/lazy_proof.h"
-
-namespace CVC4 {
-namespace theory {
-
-ProofEngineOutputChannel::ProofEngineOutputChannel(TheoryEngine* engine,
- theory::TheoryId theory,
- LazyCDProof* lpf)
- : EngineOutputChannel(engine, theory), d_lazyPf(lpf)
-{
-}
-void ProofEngineOutputChannel::trustedConflict(TrustNode pconf)
-{
- Assert(pconf.getKind() == TrustNodeKind::CONFLICT);
- Node conf = pconf.getNode();
- if (d_lazyPf != nullptr)
- {
- Node ckey = TrustNode::getConflictKeyValue(conf);
- ProofGenerator* pfg = pconf.getGenerator();
- // may or may not have supplied a generator
- if (pfg != nullptr)
- {
- ++d_statistics.trustedConflicts;
- // if we have, add it to the lazy proof object
- d_lazyPf->addLazyStep(ckey, pfg);
- Assert(pfg->hasProofFor(ckey));
- }
- else
- {
- // if none provided, do a very coarse-grained step
- addTheoryLemmaStep(ckey);
- }
- }
- // now, call the normal interface to conflict
- conflict(conf);
-}
-
-LemmaStatus ProofEngineOutputChannel::trustedLemma(TrustNode plem,
- bool removable,
- bool preprocess,
- bool sendAtoms)
-{
- Assert(plem.getKind() == TrustNodeKind::LEMMA);
- TNode lem = plem.getNode();
- ProofGenerator* pfg = plem.getGenerator();
- if (d_lazyPf != nullptr)
- {
- Node lkey = TrustNode::getLemmaKeyValue(lem);
- // may or may not have supplied a generator
- if (pfg != nullptr)
- {
- ++d_statistics.trustedLemmas;
- // if we have, add it to the lazy proof object
- d_lazyPf->addLazyStep(lkey, pfg);
- Assert(pfg->hasProofFor(lkey));
- }
- else
- {
- // if none provided, do a very coarse-grained step
- addTheoryLemmaStep(lkey);
- }
- }
- // now, call the normal interface for lemma
- return OutputChannel::lemma(lem, removable, preprocess, sendAtoms);
-}
-
-bool ProofEngineOutputChannel::addTheoryLemmaStep(Node f)
-{
- Assert(d_lazyPf != nullptr);
- Assert(!f.isNull());
- std::vector<Node> children;
- std::vector<Node> args;
- args.push_back(f);
- unsigned tid = static_cast<unsigned>(d_theory);
- Node tidn = NodeManager::currentNM()->mkConst(Rational(tid));
- args.push_back(tidn);
- // add the step, should always succeed;
- return d_lazyPf->addStep(f, PfRule::THEORY_LEMMA, children, args);
-}
-
-} // namespace theory
-} // namespace CVC4
diff --git a/src/theory/proof_engine_output_channel.h b/src/theory/proof_engine_output_channel.h
deleted file mode 100644
index 1b1beb84d..000000000
--- a/src/theory/proof_engine_output_channel.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/********************* */
-/*! \file proof_engine_output_channel.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 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 proof output channel class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__THEORY__PROOF_ENGINE_OUTPUT_CHANNEL_H
-#define CVC4__THEORY__PROOF_ENGINE_OUTPUT_CHANNEL_H
-
-#include "context/cdhashmap.h"
-#include "expr/node.h"
-#include "theory/engine_output_channel.h"
-
-namespace CVC4 {
-
-class LazyCDProof;
-
-namespace theory {
-
-/**
- * TODO: merge with engine output channel
- *
- * A layer on top of an output channel to ensure proofs are constructed and
- * available for conflicts and lemmas that may require proofs. It is
- * intended to be owned by TheoryEngine and passed as reference to each of
- * its Theory solvers. Its use can be summarized in two parts:
- *
- * (1) Theory objects should use the output calls to methods in this class,
- * e.g. trustedConflict(...), trustedLemma(...).
- *
- * (2) This class is responsible for adding proof steps to the provide proof
- * object that correspond to steps.
- *
- * It is implemented by requiring that calls to conflict(...) provide an
- * pointer to a proof generator object, as part of the TrustNode pair.
- *
- * In more detail, when a call to
- * ProofOutputChannel::trustedConflict(TrustNode(conf, pfg))
- * is made
- */
-class ProofEngineOutputChannel : public EngineOutputChannel
-{
- typedef context::CDHashMap<Node, ProofGenerator*, NodeHashFunction>
- NodeProofGenMap;
-
- public:
- ProofEngineOutputChannel(TheoryEngine* engine,
- theory::TheoryId theory,
- LazyCDProof* lpf);
- ~ProofEngineOutputChannel() {}
- /**
- * Let pconf be the pair (Node conf, ProofGenerator * pfg). This method
- * sends conf on the output channel of this class whose proof can be generated
- * by the generator pfg. It stores the mapping
- * getConflictKeyValue(conf) |-> pfg
- * as a (lazy) step in the lazy proof object owned by this class.
- */
- void trustedConflict(TrustNode pconf) override;
- /**
- * Let plem be the pair (Node lem, ProofGenerator * pfg).
- * Send lem on the output channel of this class whose proof can be generated
- * by the generator pfg. Apart from pfg, the interface for this method is
- * the same as OutputChannel. It stores the mapping
- * getLemmaKeyValue(lem) |-> pfg
- * as a (lazy) step in the lazy proof object owned by this class.
- */
- LemmaStatus trustedLemma(TrustNode plem,
- bool removable = false,
- bool preprocess = false,
- bool sendAtoms = false) override;
-
- private:
- /** Pointer to the lazy proof
- *
- * This object stores the mapping between formulas (conflicts or lemmas)
- * and the proof generator provided for them.
- */
- LazyCDProof* d_lazyPf;
- /**
- * Add coarse grained THEORY_LEMMA step for formula f that is the key of
- * a lemma or conflict being sent out on the output channel of this class.
- */
- bool addTheoryLemmaStep(Node f);
-};
-
-} // namespace theory
-} // namespace CVC4
-
-#endif /* CVC4__THEORY__PROOF_OUTPUT_CHANNEL_H */
diff --git a/src/theory/shared_terms_database.cpp b/src/theory/shared_terms_database.cpp
index 6d87530cb..43950383b 100644
--- a/src/theory/shared_terms_database.cpp
+++ b/src/theory/shared_terms_database.cpp
@@ -23,11 +23,11 @@ using namespace CVC4::theory;
namespace CVC4 {
-// below, proofs are enabled in d_pfee if we are provided a lazy proof
SharedTermsDatabase::SharedTermsDatabase(TheoryEngine* theoryEngine,
context::Context* context,
context::UserContext* userContext,
- ProofNodeManager* pnm, LazyCDProof* lcp)
+ ProofNodeManager* pnm,
+ bool pfEnabled)
: ContextNotifyObj(context),
d_statSharedTerms("theory::shared_terms", 0),
d_addedSharedTermsSize(context, 0),
@@ -36,11 +36,11 @@ SharedTermsDatabase::SharedTermsDatabase(TheoryEngine* theoryEngine,
d_registeredEqualities(context),
d_EENotify(*this),
d_equalityEngine(d_EENotify, context, "SharedTermsDatabase", true),
- d_pfee(context,userContext,d_equalityEngine,pnm, lcp!=nullptr),
+ d_pfee(context, userContext, d_equalityEngine, pnm, pfEnabled),
d_theoryEngine(theoryEngine),
d_inConflict(context, false),
- d_conflictPolarity(),
- d_lazyPf(lcp) {
+ d_conflictPolarity()
+{
smtStatisticsRegistry()->registerStat(&d_statSharedTerms);
}
@@ -199,12 +199,13 @@ bool SharedTermsDatabase::areDisequal(TNode a, TNode b) const {
}
}
-void SharedTermsDatabase::assertEquality(TNode equality, bool polarity, TNode reason)
+void SharedTermsDatabase::assertLiteral(TNode lit)
{
- Debug("shared-terms-database::assert") << "SharedTermsDatabase::assertEquality(" << equality << ", " << (polarity ? "true" : "false") << ", " << reason << ")" << endl;
+ Debug("shared-terms-database::assert")
+ << "SharedTermsDatabase::assertLiteral(" << lit << ")" << endl;
// Add it to the equality engine
- //d_equalityEngine.assertEquality(equality, polarity, reason);
- d_pfee.assertAssume(reason);
+ // d_equalityEngine.assertEquality(equality, polarity, reason);
+ d_pfee.assertAssume(lit);
// Check for conflict
checkForConflict();
}
@@ -218,28 +219,6 @@ bool SharedTermsDatabase::propagateEquality(TNode equality, bool polarity) {
return true;
}
-static Node mkAnd(const std::vector<TNode>& conjunctions) {
- Assert(conjunctions.size() > 0);
-
- std::set<TNode> all;
- all.insert(conjunctions.begin(), conjunctions.end());
-
- if (all.size() == 1) {
- // All the same, or just one
- return conjunctions[0];
- }
-
- NodeBuilder<> conjunction(kind::AND);
- std::set<TNode>::const_iterator it = all.begin();
- std::set<TNode>::const_iterator it_end = all.end();
- while (it != it_end) {
- conjunction << *it;
- ++ it;
- }
-
- return conjunction;
-}
-
void SharedTermsDatabase::checkForConflict() {
if (d_inConflict) {
d_inConflict = false;
@@ -249,12 +228,7 @@ void SharedTermsDatabase::checkForConflict() {
conflict = conflict.notNode();
}
TrustNode trnc = d_pfee.assertConflict(conflict);
- if (d_lazyPf!=nullptr)
- {
- // add the step to the proof
- Node ckey = TrustNode::getConflictKeyValue(trnc.getNode());
- d_lazyPf->addLazyStep(ckey, &d_pfee);
- }
+ d_theoryEngine->processTrustNode(trnc, THEORY_BUILTIN);
d_theoryEngine->conflict(trnc.getNode(), THEORY_BUILTIN);
d_conflictLHS = d_conflictRHS = Node::null();
}
@@ -270,7 +244,8 @@ bool SharedTermsDatabase::isKnown(TNode literal) const {
}
}
-theory::TrustNode SharedTermsDatabase::explain(TNode literal) {
+theory::TrustNode SharedTermsDatabase::explain(TNode literal)
+{
TrustNode trn = d_pfee.explain(literal);
return trn;
}
diff --git a/src/theory/shared_terms_database.h b/src/theory/shared_terms_database.h
index ccee94c8d..88664544b 100644
--- a/src/theory/shared_terms_database.h
+++ b/src/theory/shared_terms_database.h
@@ -21,30 +21,26 @@
#include "context/cdhashset.h"
#include "expr/node.h"
+#include "expr/proof_node_manager.h"
#include "theory/theory.h"
+#include "theory/trust_node.h"
#include "theory/uf/equality_engine.h"
#include "theory/uf/proof_equality_engine.h"
-#include "theory/trust_node.h"
-#include "expr/proof_node_manager.h"
#include "util/statistics_registry.h"
-#include "expr/lazy_proof.h"
namespace CVC4 {
class TheoryEngine;
class SharedTermsDatabase : public context::ContextNotifyObj {
-
-public:
-
+ public:
/** A container for a list of shared terms */
typedef std::vector<TNode> shared_terms_list;
/** The iterator to go through the shared terms list */
typedef shared_terms_list::const_iterator shared_terms_iterator;
-private:
-
+ private:
/** Some statistics */
IntStat d_statSharedTerms;
@@ -72,8 +68,7 @@ private:
typedef context::CDHashSet<Node, NodeHashFunction> RegisteredEqualitiesSet;
RegisteredEqualitiesSet d_registeredEqualities;
-private:
-
+ private:
/** This method removes all the un-necessary stuff from the maps */
void backtrack();
@@ -118,7 +113,7 @@ private:
/** Equality engine */
theory::eq::EqualityEngine d_equalityEngine;
-
+
/** Proof equality engine */
theory::eq::ProofEqEngine d_pfee;
@@ -162,17 +157,19 @@ private:
*/
void checkForConflict();
-public:
-
- SharedTermsDatabase(TheoryEngine* theoryEngine, context::Context* context,
- context::UserContext* userContext,
- ProofNodeManager* pnm, LazyCDProof* lcp);
+ public:
+ SharedTermsDatabase(TheoryEngine* theoryEngine,
+ context::Context* context,
+ context::UserContext* userContext,
+ ProofNodeManager* pnm,
+ bool pfEnabled);
~SharedTermsDatabase();
/**
- * Asserts the equality to the shared terms database,
+ * Asserts the literal lit to the shared terms database, where lit is
+ * an equality or disequality.
*/
- void assertEquality(TNode equality, bool polarity, TNode reason);
+ void assertLiteral(TNode lit);
/**
* Return whether the equality is alreday known to the engine
@@ -256,10 +253,7 @@ public:
*/
theory::eq::EqualityEngine* getEqualityEngine() { return &d_equalityEngine; }
-protected:
-
- /** Pointer to the lazy proof of TheoryEngine */
- LazyCDProof* d_lazyPf;
+ protected:
/**
* This method gets called on backtracks from the context manager.
*/
diff --git a/src/theory/strings/core_solver.cpp b/src/theory/strings/core_solver.cpp
index cc73da8f2..27e2520b8 100644
--- a/src/theory/strings/core_solver.cpp
+++ b/src/theory/strings/core_solver.cpp
@@ -773,17 +773,20 @@ Node CoreSolver::getConclusion(Node x,
{
// we can assume its length is greater than zero
Node emp = Word::mkEmptyWord(sk1.getType());
- conc = nm->mkNode(AND, conc, sk1.eqNode(emp).negate(),
- nm->mkNode(GT,nm->mkNode(STRING_LENGTH,sk1), nm->mkConst(Rational(0))));
+ conc = nm->mkNode(
+ AND,
+ conc,
+ sk1.eqNode(emp).negate(),
+ nm->mkNode(
+ GT, nm->mkNode(STRING_LENGTH, sk1), nm->mkConst(Rational(0))));
}
}
- else if (rule==PfRule::CONCAT_CSPLIT)
+ else if (rule == PfRule::CONCAT_CSPLIT)
{
- Assert (y.isConst());
+ Assert(y.isConst());
size_t yLen = Word::getLength(y);
- Node firstChar = yLen == 1 ? y
- : (isRev ? Word::suffix(y, 1)
- : Word::prefix(y, 1));
+ Node firstChar =
+ yLen == 1 ? y : (isRev ? Word::suffix(y, 1) : Word::prefix(y, 1));
Node sk = skc->mkSkolemCached(
x,
isRev ? SkolemCache::SK_ID_VC_SPT_REV : SkolemCache::SK_ID_VC_SPT,
@@ -792,17 +795,15 @@ Node CoreSolver::getConclusion(Node x,
conc = x.eqNode(isRev ? utils::mkNConcat(sk, firstChar)
: utils::mkNConcat(firstChar, sk));
}
- else if (rule==PfRule::CONCAT_CPROP)
+ else if (rule == PfRule::CONCAT_CPROP)
{
// expect (str.++ z c1) and c2
- Assert (x.getKind()==STRING_CONCAT && x.getNumChildren()==2);
+ Assert(x.getKind() == STRING_CONCAT && x.getNumChildren() == 2);
Node z = x[isRev ? 1 : 0];
Node c1 = x[isRev ? 0 : 1];
- Assert (c1.isConst());
+ Assert(c1.isConst());
Node c2 = y;
- Assert (c2.isConst());
-
-
+ Assert(c2.isConst());
}
return conc;
@@ -1011,14 +1012,14 @@ void CoreSolver::getNormalForms(Node eqc,
if (!StringsEntail::canConstantContainList(c, nf.d_nf, firstc, lastc))
{
Node n = nf.d_base;
+ std::vector<Node> exp;
//conflict
Trace("strings-solve") << "Normal form for " << n << " cannot be contained in constant " << c << std::endl;
//conflict, explanation is n = base ^ base = c ^ relevant porition of ( n = N[n] )
- std::vector< Node > exp;
- d_bsolver.explainConstantEqc(n,eqc,exp);
// Notice although not implemented, this can be minimized based on
// firstc/lastc, normal_forms_exp_depend.
exp.insert(exp.end(), nf.d_exp.begin(), nf.d_exp.end());
+ d_bsolver.explainConstantEqc(n, eqc, exp);
Node conc = d_false;
d_im.sendInference(exp, conc, Inference::N_NCTN);
}
@@ -1556,11 +1557,12 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
// E.g. "abc" ++ ... = nc ++ ... ---> nc = "a" ++ k
SkolemCache* skc = d_termReg.getSkolemCache();
std::vector<Node> newSkolems;
- iinfo.d_conc = getConclusion(nc,nfcv[index],PfRule::CONCAT_CSPLIT,isRev,skc,newSkolems);
+ iinfo.d_conc = getConclusion(
+ nc, nfcv[index], PfRule::CONCAT_CSPLIT, isRev, skc, newSkolems);
NormalForm::getExplanationForPrefixEq(
nfi, nfj, index, index, iinfo.d_ant);
iinfo.d_ant.push_back(expNonEmpty);
- Assert(newSkolems.size()==1);
+ Assert(newSkolems.size() == 1);
iinfo.d_new_skolem[LENGTH_SPLIT].push_back(newSkolems[0]);
iinfo.d_id = Inference::SSPLIT_CST;
iinfo.d_idRev = isRev;
diff --git a/src/theory/strings/infer_proof_cons.cpp b/src/theory/strings/infer_proof_cons.cpp
index 9af4dc565..49a697592 100644
--- a/src/theory/strings/infer_proof_cons.cpp
+++ b/src/theory/strings/infer_proof_cons.cpp
@@ -48,7 +48,7 @@ void InferProofCons::notifyFact(const InferInfo& ii)
Trace("strings-ipc-debug") << "...duplicate!" << std::endl;
return;
}
- if (fact.getKind()==EQUAL)
+ if (fact.getKind() == EQUAL)
{
Node symFact = fact[1].eqNode(fact[0]);
if (d_lazyFactMap.find(symFact) != d_lazyFactMap.end())
@@ -168,8 +168,9 @@ Node InferProofCons::convert(Inference infer,
case Inference::INFER_EMP:
{
// need the "extended equality rewrite"
- ps.d_args.push_back(builtin::BuiltinProofRuleChecker::mkRewriterId(
- RewriterId::REWRITE_EQ_EXT));
+ MethodId ids = MethodId::SB_DEFAULT;
+ MethodId idr = MethodId::RW_REWRITE_EQ_EXT;
+ addMethodIds(ps.d_args, ids, idr);
ps.d_rule = PfRule::MACRO_SR_PRED_ELIM;
}
break;
@@ -260,7 +261,7 @@ Node InferProofCons::convert(Inference infer,
ps.d_children.begin() + mainEqIndex);
Node mainEqSRew =
d_psb.tryStep(PfRule::MACRO_SR_PRED_ELIM, childrenSRew, emptyVec);
- if (isSymm(mainEqSRew, mainEq))
+ if (CDProof::isSame(mainEqSRew, mainEq))
{
Trace("strings-ipc-core") << "...undo step" << std::endl;
// not necessary
@@ -305,8 +306,11 @@ Node InferProofCons::convert(Inference infer,
// optimization in processSimpleNEq. Alternatively, this could
// possibly be done by CONCAT_EQ with !isRev.
std::vector<Node> cexp;
- if (convertPredTransform(
- mainEqCeq, conc, cexp, RewriterId::REWRITE_EQ_EXT))
+ if (convertPredTransform(mainEqCeq,
+ conc,
+ cexp,
+ MethodId::SB_DEFAULT,
+ MethodId::RW_REWRITE_EQ_EXT))
{
Trace("strings-ipc-core") << "Transformed to " << conc
<< " via pred transform" << std::endl;
@@ -901,10 +905,11 @@ bool InferProofCons::convertLengthPf(Node lenReq,
bool InferProofCons::convertPredTransform(Node src,
Node tgt,
const std::vector<Node>& exp,
- RewriterId id)
+ MethodId ids,
+ MethodId idr)
{
// symmetric equalities
- if (isSymm(src, tgt))
+ if (CDProof::isSame(src, tgt))
{
return true;
}
@@ -914,19 +919,16 @@ bool InferProofCons::convertPredTransform(Node src,
// try to prove that tgt rewrites to src
children.insert(children.end(), exp.begin(), exp.end());
args.push_back(tgt);
- if (id != RewriterId::REWRITE)
- {
- args.push_back(builtin::BuiltinProofRuleChecker::mkRewriterId(id));
- }
+ addMethodIds(args, ids, idr);
Node res = d_psb.tryStep(PfRule::MACRO_SR_PRED_TRANSFORM, children, args);
if (res.isNull())
{
// failed to apply
return false;
}
- Trace("strings-ipc-debug")
- << "InferProofCons::convertPredTransform: success " << src
- << " == " << tgt << " under " << exp << " via " << id << std::endl;
+ Trace("strings-ipc-debug") << "InferProofCons::convertPredTransform: success "
+ << src << " == " << tgt << " under " << exp
+ << " via " << ids << "/" << idr << std::endl;
// should definitely have concluded tgt
Assert(res == tgt);
return true;
@@ -934,14 +936,12 @@ bool InferProofCons::convertPredTransform(Node src,
bool InferProofCons::convertPredIntro(Node tgt,
const std::vector<Node>& exp,
- RewriterId id)
+ MethodId ids,
+ MethodId idr)
{
std::vector<Node> args;
args.push_back(tgt);
- if (id != RewriterId::REWRITE)
- {
- args.push_back(builtin::BuiltinProofRuleChecker::mkRewriterId(id));
- }
+ addMethodIds(args, ids, idr);
Node res = d_psb.tryStep(PfRule::MACRO_SR_PRED_INTRO, exp, args);
if (res.isNull())
{
@@ -953,18 +953,16 @@ bool InferProofCons::convertPredIntro(Node tgt,
Node InferProofCons::convertPredElim(Node src,
const std::vector<Node>& exp,
- RewriterId id)
+ MethodId ids,
+ MethodId idr)
{
std::vector<Node> children;
children.push_back(src);
children.insert(children.end(), exp.begin(), exp.end());
std::vector<Node> args;
- if (id != RewriterId::REWRITE)
- {
- args.push_back(builtin::BuiltinProofRuleChecker::mkRewriterId(id));
- }
+ addMethodIds(args, ids, idr);
Node srcRew = d_psb.tryStep(PfRule::MACRO_SR_PRED_ELIM, children, args);
- if (isSymm(src, srcRew))
+ if (CDProof::isSame(src, srcRew))
{
d_psb.popStep();
return src;
@@ -972,6 +970,21 @@ Node InferProofCons::convertPredElim(Node src,
return srcRew;
}
+void InferProofCons::addMethodIds(std::vector<Node>& args,
+ MethodId ids,
+ MethodId idr)
+{
+ bool ndefRewriter = (idr != MethodId::RW_REWRITE);
+ if (ids != MethodId::SB_DEFAULT || ndefRewriter)
+ {
+ args.push_back(mkMethodId(ids));
+ }
+ if (ndefRewriter)
+ {
+ args.push_back(mkMethodId(idr));
+ }
+}
+
Node InferProofCons::convertTrans(Node eqa, Node eqb)
{
if (eqa.getKind() != EQUAL || eqb.getKind() != EQUAL)
@@ -997,13 +1010,6 @@ Node InferProofCons::convertTrans(Node eqa, Node eqb)
return Node::null();
}
-bool InferProofCons::isSymm(Node src, Node tgt)
-{
- return src == tgt
- || (src.getKind() == EQUAL && tgt.getKind() == EQUAL
- && src[0] == tgt[1] && src[1] == tgt[0]);
-}
-
ProofStepBuffer* InferProofCons::getBuffer() { return &d_psb; }
std::shared_ptr<ProofNode> InferProofCons::getProofFor(Node fact)
@@ -1012,9 +1018,9 @@ std::shared_ptr<ProofNode> InferProofCons::getProofFor(Node fact)
CDProof pf(d_pnm);
// get the inference
NodeInferInfoMap::iterator it = d_lazyFactMap.find(fact);
- if (it==d_lazyFactMap.end())
+ if (it == d_lazyFactMap.end())
{
- if (fact.getKind()==EQUAL)
+ if (fact.getKind() == EQUAL)
{
// Use the symmetric fact. There is no need to explictly make a
// SYMM proof, as this is handled by CDProof::mkProof below.
diff --git a/src/theory/strings/infer_proof_cons.h b/src/theory/strings/infer_proof_cons.h
index 612e67693..18f2d0b61 100644
--- a/src/theory/strings/infer_proof_cons.h
+++ b/src/theory/strings/infer_proof_cons.h
@@ -126,22 +126,25 @@ class InferProofCons : public ProofGenerator
bool convertPredTransform(Node src,
Node tgt,
const std::vector<Node>& exp,
- RewriterId id = RewriterId::REWRITE);
+ MethodId ids = MethodId::SB_DEFAULT,
+ MethodId idr = MethodId::RW_REWRITE);
/**
*/
bool convertPredIntro(Node tgt,
const std::vector<Node>& exp,
- RewriterId id = RewriterId::REWRITE);
+ MethodId ids = MethodId::SB_DEFAULT,
+ MethodId idr = MethodId::RW_REWRITE);
/**
*/
Node convertPredElim(Node src,
const std::vector<Node>& exp,
- RewriterId id = RewriterId::REWRITE);
+ MethodId ids = MethodId::SB_DEFAULT,
+ MethodId idr = MethodId::RW_REWRITE);
+ /** Add method ids */
+ void addMethodIds(std::vector<Node>& args, MethodId ids, MethodId idr);
/**
*/
Node convertTrans(Node eqa, Node eqb);
- /** Is symm */
- static bool isSymm(Node src, Node tgt);
/** the proof node manager */
ProofNodeManager* d_pnm;
/** The lazy fact map */
diff --git a/src/theory/strings/proof_checker.cpp b/src/theory/strings/proof_checker.cpp
index a5a22dfa0..3b06ea447 100644
--- a/src/theory/strings/proof_checker.cpp
+++ b/src/theory/strings/proof_checker.cpp
@@ -307,8 +307,8 @@ Node StringProofRuleChecker::checkInternal(PfRule id,
std::vector<Node> newSkolems;
Node kt0 = ProofSkolemCache::getSkolemForm(t0);
Node ks0 = ProofSkolemCache::getSkolemForm(s0);
- Node conc = CoreSolver::getConclusion(
- kt0, ks0, id, isRev, &skc, newSkolems);
+ Node conc =
+ CoreSolver::getConclusion(kt0, ks0, id, isRev, &skc, newSkolems);
conc = ProofSkolemCache::getWitnessForm(conc);
return conc;
}
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index b2793fac9..3b6ffd6de 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -48,6 +48,7 @@
#include "theory/quantifiers_engine.h"
#include "theory/rewriter.h"
#include "theory/theory.h"
+#include "theory/theory_engine_proof_generator.h"
#include "theory/theory_model.h"
#include "theory/theory_traits.h"
#include "theory/uf/equality_engine.h"
@@ -131,7 +132,7 @@ std::string getTheoryString(theory::TheoryId id)
void TheoryEngine::finishInit()
{
// if we are using the new proofs module
- if (options::proofNew())
+ if (d_lazyProof != nullptr)
{
// ask the theories to populate the proof checking rules in the checker
for (TheoryId theoryId = theory::THEORY_FIRST;
@@ -197,8 +198,17 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_logicInfo(logicInfo),
d_pchecker(new ProofChecker),
d_pNodeManager(new ProofNodeManager(d_pchecker.get())),
- d_lazyProof(options::proofNew() ? new LazyCDProof(d_pNodeManager.get(), nullptr, d_userContext) : nullptr),
- d_sharedTerms(this, context, userContext, d_pNodeManager.get(), d_lazyProof.get()),
+ d_lazyProof(
+ options::proofNew()
+ ? new LazyCDProof(d_pNodeManager.get(), nullptr, d_userContext)
+ : nullptr),
+ d_tepg(
+ new TheoryEngineProofGenerator(d_pNodeManager.get(), d_userContext)),
+ d_sharedTerms(this,
+ context,
+ userContext,
+ d_pNodeManager.get(),
+ d_lazyProof != nullptr),
d_masterEqualityEngine(nullptr),
d_masterEENotify(*this),
d_quantEngine(nullptr),
@@ -637,12 +647,16 @@ void TheoryEngine::combineTheories() {
// We need to split on it
Debug("combineTheories") << "TheoryEngine::combineTheories(): requesting a split " << endl;
- lemma(equality.orNode(equality.notNode()),
- RULE_INVALID,
- false,
- false,
- false,
- carePair.d_theory);
+ Node split = equality.orNode(equality.notNode());
+ if (d_lazyProof != nullptr)
+ {
+ std::vector<Node> pfChildren;
+ std::vector<Node> pfArgs;
+ pfArgs.push_back(equality);
+ d_lazyProof->addStep(split, PfRule::SPLIT, pfChildren, pfArgs);
+ }
+
+ lemma(split, RULE_INVALID, false, false, false, carePair.d_theory);
// This code is supposed to force preference to follow what the theory models already have
// but it doesn't seem to make a big difference - need to explore more -Clark
@@ -1205,18 +1219,14 @@ void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theo
return;
}
- // Polarity of the assertion
- bool polarity = assertion.getKind() != kind::NOT;
-
- // Atom of the assertion
- TNode atom = polarity ? assertion : assertion[0];
-
// If sending to the shared terms database, it's also simple
if (toTheoryId == THEORY_BUILTIN) {
- Assert(atom.getKind() == kind::EQUAL)
- << "atom should be an EQUALity, not `" << atom << "'";
+ Assert(assertion.getKind() == kind::EQUAL
+ || (assertion.getKind() == kind::NOT
+ && assertion[0].getKind() == kind::EQUAL))
+ << "atom should be an EQUALity, not `" << assertion << "'";
if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
- d_sharedTerms.assertEquality(atom, polarity, assertion);
+ d_sharedTerms.assertLiteral(assertion);
}
return;
}
@@ -1257,7 +1267,9 @@ void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theo
return;
}
- Assert(atom.getKind() == kind::EQUAL);
+ Assert(assertion.getKind() == kind::EQUAL
+ || (assertion.getKind() == kind::NOT
+ && assertion[0].getKind() == kind::EQUAL));
// Normalize
Node normalizedLiteral = Rewriter::rewrite(assertion);
@@ -1543,7 +1555,9 @@ static Node mkExplanation(const std::vector<NodeTheoryPair>& explanation) {
return conjunction;
}
-Node TheoryEngine::getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRecipe) {
+theory::TrustNode TheoryEngine::getExplanationAndRecipe(
+ TNode node, LemmaProofRecipe* proofRecipe)
+{
Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << "): current propagation index = " << d_propagationMapTimestamp << endl;
bool polarity = node.getKind() != kind::NOT;
@@ -1597,8 +1611,7 @@ Node TheoryEngine::getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRe
proofRecipe->addStep(proofStep);
}
});
-
- return explanation;
+ return texplanation;
}
Debug("theory::explain") << "TheoryEngine::getExplanation: sharing IS enabled" << std::endl;
@@ -1615,8 +1628,8 @@ Node TheoryEngine::getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRe
TheoryId explainer = nodeExplainerPair.d_theory;
// Create the workplace for explanations
- std::vector<NodeTheoryPair> explanationVector;
- explanationVector.push_back(d_propagationMap[toExplain]);
+ std::vector<NodeTheoryPair> vec;
+ vec.push_back(d_propagationMap[toExplain]);
// Process the explanation
if (proofRecipe) {
Node emptyNode;
@@ -1626,16 +1639,17 @@ Node TheoryEngine::getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRe
proofRecipe->addBaseAssertion(node);
}
- getExplanation(explanationVector, proofRecipe);
- Node explanation = mkExplanation(explanationVector);
-
- Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl;
+ TrustNode texplanation = getExplanation(vec, proofRecipe);
- return explanation;
+ Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => "
+ << texplanation.getNode() << endl;
+ return texplanation;
}
-Node TheoryEngine::getExplanation(TNode node) {
+theory::TrustNode TheoryEngine::getExplanation(TNode node)
+{
LemmaProofRecipe *dontCareRecipe = NULL;
+ // the trust node was processed within getExplanationAndRecipe
return getExplanationAndRecipe(node, dontCareRecipe);
}
@@ -1745,7 +1759,7 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node,
theory::TheoryId atomsTo) {
// For resource-limiting (also does a time check).
// spendResource();
-
+
// Do we need to check atoms
if (atomsTo != theory::THEORY_LAST) {
Debug("theory::atoms") << "TheoryEngine::lemma(" << node << ", " << atomsTo << ")" << endl;
@@ -1763,16 +1777,35 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node,
<< CheckSatCommand(n.toExpr());
}
- // if proofNew is enabled, then d_lazyProof contains a proof of n.
- /*
- Node lemma = node;
- if (negated)
+ // if d_lazyProof is enabled, then d_lazyProof contains a proof of n.
+ if (d_lazyProof != nullptr)
{
- lemma = lemma.negate();
+ Node lemma = node;
+ if (negated)
+ {
+ lemma = lemma.negate();
+ }
+ if (!d_lazyProof->hasStep(lemma) && !d_lazyProof->hasGenerator(lemma))
+ {
+ Trace("te-proof") << "No proof for lemma: " << lemma << std::endl;
+ Trace("te-proof-warn")
+ << "WARNING: No proof for lemma: " << lemma << std::endl;
+ }
+ else
+ {
+ Trace("te-proof") << "Proof for lemma: " << lemma << std::endl;
+ }
}
- Assert (!options::proofNew() || d_lazyProof->hasStep(lemma));
- */
-
+
+ // FIXME
+ std::shared_ptr<LazyCDProof> lcp;
+ if (d_lazyProof != nullptr)
+ {
+ Trace("te-proof-exp") << "TheoryEngine::lemma: process " << node
+ << std::endl;
+ lcp.reset(new LazyCDProof(d_pNodeManager.get()));
+ }
+
AssertionPipeline additionalLemmas;
// Run theory preprocessing, maybe
@@ -1799,10 +1832,12 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node,
}
// assert to prop engine
- for (size_t i = 0, lsize = additionalLemmas.size(); i < lsize; ++ i) {
+ for (size_t i = 0, lsize = additionalLemmas.size(); i < lsize; ++i)
+ {
Node rewritten = Rewriter::rewrite(additionalLemmas[i]);
additionalLemmas.replace(i, rewritten);
- d_propEngine->assertLemma(additionalLemmas[i], i==0 && negated, removable, rule, node);
+ d_propEngine->assertLemma(
+ additionalLemmas[i], i == 0 && negated, removable, rule, node);
}
// WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
@@ -1825,12 +1860,47 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node,
return theory::LemmaStatus(additionalLemmas[0], d_userContext->getLevel());
}
+void TheoryEngine::processTrustNode(theory::TrustNode trn,
+ theory::TheoryId from)
+{
+ if (d_lazyProof == nullptr)
+ {
+ // proofs not enabled
+ return;
+ }
+ ProofGenerator* pfg = trn.getGenerator();
+ Node p = trn.getProven();
+ // may or may not have supplied a generator
+ if (pfg != nullptr)
+ {
+ // if we have, add it to the lazy proof object
+ d_lazyProof->addLazyStep(p, pfg);
+ // generator should have a proof for p
+ Assert(pfg->hasProofFor(p));
+ }
+ else
+ {
+ // all BUILTIN should be handled
+ Assert(from != THEORY_BUILTIN);
+ // untrusted theory lemma
+ std::vector<Node> children;
+ std::vector<Node> args;
+ args.push_back(p);
+ unsigned tid = static_cast<unsigned>(from);
+ Node tidn = NodeManager::currentNM()->mkConst(Rational(tid));
+ args.push_back(tidn);
+ // add the step, should always succeed;
+ d_lazyProof->addStep(p, PfRule::THEORY_LEMMA, children, args);
+ }
+}
+
void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
- // if proofNew is enabled, then d_lazyProof contains a proof of conflict.negate()
- //Assert (!options::proofNew() || d_lazyProof->hasStep(conflict.negate()));
-
Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << ")" << endl;
+ // if proofNew is enabled, then d_lazyProof contains a proof of
+ // conflict.negate()
+ // Assert (d_lazyProof==nullptr || d_lazyProof->hasStep(conflict.negate()) ||
+ // d_lazyProof->hasGenerator(conflict.negate()) || theoryId==THEORY_ARITH);
Trace("dtview::conflict") << ":THEORY-CONFLICT: " << conflict << std::endl;
@@ -1862,13 +1932,36 @@ void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
// In the multiple-theories case, we need to reconstruct the conflict
if (d_logicInfo.isSharingEnabled()) {
// Create the workplace for explanations
- std::vector<NodeTheoryPair> explanationVector;
- explanationVector.push_back(NodeTheoryPair(conflict, theoryId, d_propagationMapTimestamp));
+ std::vector<NodeTheoryPair> vec;
+ vec.push_back(
+ NodeTheoryPair(conflict, theoryId, d_propagationMapTimestamp));
// Process the explanation
- getExplanation(explanationVector, proofRecipe);
+ TrustNode tncExp = getExplanation(vec, proofRecipe);
PROOF(ProofManager::getCnfProof()->setProofRecipe(proofRecipe));
- Node fullConflict = mkExplanation(explanationVector);
+ Node fullConflict = tncExp.getNode();
+
+ if (d_lazyProof != nullptr)
+ {
+ if (fullConflict!=conflict)
+ {
+ // store the explicit step
+ processTrustNode(tncExp, THEORY_BUILTIN);
+ }
+ Node fullConflictNeg = fullConflict.notNode();
+ // ------------------------- explained ---------- from theory
+ // fullConflict => conflict ~conflict
+ // ----------------------------------------------- MACRO_SR_PRED_TRANSFORM
+ // ~fullConflict
+ std::vector<Node> children;
+ children.push_back(tncExp.getProven());
+ children.push_back(conflict.notNode());
+ std::vector<Node> args;
+ args.push_back(fullConflictNeg);
+ args.push_back(mkMethodId(MethodId::SB_PREDICATE));
+ d_lazyProof->addStep(fullConflictNeg, PfRule::MACRO_SR_PRED_TRANSFORM, children, args);
+ }
+
Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << "): full = " << fullConflict << endl;
Assert(properConflict(fullConflict));
lemma(fullConflict, RULE_CONFLICT, true, true, false, THEORY_LAST);
@@ -1954,9 +2047,22 @@ void TheoryEngine::staticInitializeBVOptions(
}
}
-void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector, LemmaProofRecipe* proofRecipe) {
- Assert(explanationVector.size() > 0);
+theory::TrustNode TheoryEngine::getExplanation(
+ std::vector<NodeTheoryPair>& explanationVector,
+ LemmaProofRecipe* proofRecipe)
+{
+ Assert(explanationVector.size() == 1);
+ Node conclusion = explanationVector[0].d_node;
+ std::shared_ptr<LazyCDProof> lcp;
+ bool simpleExplain = true;
+ TrustNode simpleTrn;
+ if (d_lazyProof != nullptr)
+ {
+ Trace("te-proof-exp") << "TheoryEngine::getExplanation " << conclusion
+ << std::endl;
+ lcp.reset(new LazyCDProof(d_pNodeManager.get()));
+ }
unsigned i = 0; // Index of the current literal we are processing
unsigned j = 0; // Index of the last literal we are keeping
@@ -1979,15 +2085,25 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
<< toExplain.d_theory << endl;
// If a true constant or a negation of a false constant we can ignore it
- if (toExplain.d_node.isConst() && toExplain.d_node.getConst<bool>())
- {
- ++ i;
- continue;
- }
- if (toExplain.d_node.getKind() == kind::NOT && toExplain.d_node[0].isConst()
- && !toExplain.d_node[0].getConst<bool>())
+ if ((toExplain.d_node.isConst() && toExplain.d_node.getConst<bool>())
+ || (toExplain.d_node.getKind() == kind::NOT
+ && toExplain.d_node[0].isConst()
+ && !toExplain.d_node[0].getConst<bool>()))
{
++ i;
+ if (lcp != nullptr)
+ {
+ Trace("te-proof-exp")
+ << "- explain " << toExplain.d_node << " trivially..." << std::endl;
+ // ------------------MACRO_SR_PRED_INTRO
+ // toExplain.d_node
+ std::vector<Node> children;
+ std::vector<Node> args;
+ args.push_back(toExplain.d_node);
+ lcp->addStep(
+ toExplain.d_node, PfRule::MACRO_SR_PRED_INTRO, children, args);
+ simpleExplain = false;
+ }
continue;
}
@@ -1996,6 +2112,8 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
{
Debug("theory::explain") << "\tLiteral came from THEORY_SAT_SOLVER. Kepping it." << endl;
explanationVector[j++] = explanationVector[i++];
+ // it will be a free assumption in the proof
+ Trace("te-proof-exp") << "- keep " << toExplain.d_node << std::endl;
continue;
}
@@ -2005,12 +2123,32 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
Debug("theory::explain")
<< "TheoryEngine::explain(): expanding " << toExplain.d_node
<< " got from " << toExplain.d_theory << endl;
- for (unsigned k = 0; k < toExplain.d_node.getNumChildren(); ++k)
+ size_t nchild = toExplain.d_node.getNumChildren();
+ for (size_t k = 0; k < nchild; ++k)
{
NodeTheoryPair newExplain(
toExplain.d_node[k], toExplain.d_theory, toExplain.d_timestamp);
explanationVector.push_back(newExplain);
}
+ if (lcp != nullptr)
+ {
+ Trace("te-proof-exp")
+ << "- AND expand " << toExplain.d_node << std::endl;
+ // toExplain.d_node[0] ... toExplain.d_node[n]
+ // --------------------------------------------MACRO_SR_PRED_INTRO
+ // toExplain.d_node
+ std::vector<Node> children;
+ for (size_t k = 0; k < nchild; ++k)
+ {
+ children.push_back(toExplain.d_node[k]);
+ }
+ std::vector<Node> args;
+ args.push_back(toExplain.d_node);
+ args.push_back(mkMethodId(MethodId::SB_PREDICATE));
+ lcp->addStep(
+ toExplain.d_node, PfRule::MACRO_SR_PRED_INTRO, children, args);
+ simpleExplain = false;
+ }
++ i;
continue;
}
@@ -2045,7 +2183,18 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
}
}
})
-
+ if (lcp != nullptr)
+ {
+ if (!CDProof::isSame(toExplain.d_node, (*find).second.d_node))
+ {
+ Trace("te-proof-exp")
+ << "- t-explained cached: " << toExplain.d_node << " by "
+ << (*find).second.d_node << std::endl;
+ // does this ever happen?
+ Assert(false);
+ simpleExplain = false;
+ }
+ }
continue;
}
}
@@ -2055,15 +2204,70 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
if (toExplain.d_theory == THEORY_BUILTIN)
{
texplanation = d_sharedTerms.explain(toExplain.d_node);
- Debug("theory::explain") << "\tTerm was propagated by THEORY_BUILTIN. Explanation: " << texplanation.getNode() << std::endl;
+ Debug("theory::explain")
+ << "\tTerm was propagated by THEORY_BUILTIN. Explanation: "
+ << texplanation.getNode() << std::endl;
}
else
{
- texplanation =
- theoryOf(toExplain.d_theory)->explain(toExplain.d_node);
- Debug("theory::explain") << "\tTerm was propagated by owner theory: "
- << theoryOf(toExplain.d_theory)->getId()
- << ". Explanation: " << texplanation.getNode() << std::endl;
+ texplanation = theoryOf(toExplain.d_theory)->explain(toExplain.d_node);
+ Debug("theory::explain")
+ << "\tTerm was propagated by owner theory: "
+ << theoryOf(toExplain.d_theory)->getId()
+ << ". Explanation: " << texplanation.getNode() << std::endl;
+ }
+ if (lcp != nullptr)
+ {
+ Trace("te-proof-exp")
+ << "- t-explained[" << toExplain.d_theory << "]: " << toExplain.d_node
+ << " by " << texplanation.getNode() << std::endl;
+ // if not a trivial explanation
+ if (!CDProof::isSame(texplanation.getNode(), toExplain.d_node))
+ {
+ // ----------- Via theory
+ // exp => lit exp
+ // ---------------------------------MACRO_SR_PRED_TRANSFORM
+ // lit
+ Node proven = texplanation.getProven();
+ if (texplanation.getGenerator() != nullptr)
+ {
+ lcp->addLazyStep(proven, texplanation.getGenerator());
+ }
+ else
+ {
+ Trace("te-proof-exp") << "...trust THEORY_LEMMA" << std::endl;
+ // otherwise, trusted theory lemma
+ std::vector<Node> children;
+ std::vector<Node> args;
+ args.push_back(proven);
+ unsigned tid = static_cast<unsigned>(toExplain.d_theory);
+ Node tidn = NodeManager::currentNM()->mkConst(Rational(tid));
+ args.push_back(tidn);
+ lcp->addStep(proven, PfRule::THEORY_LEMMA, children, args);
+ }
+ std::vector<Node> children;
+ children.push_back(proven);
+ children.push_back(texplanation.getNode());
+ std::vector<Node> args;
+ args.push_back(toExplain.d_node);
+ args.push_back(mkMethodId(MethodId::SB_PREDICATE));
+ lcp->addStep(
+ toExplain.d_node, PfRule::MACRO_SR_PRED_TRANSFORM, children, args);
+ if (simpleExplain)
+ {
+ if (simpleTrn.isNull())
+ {
+ // as an optimization, it may be a simple explanation, so we
+ // remember the trust node for now
+ simpleTrn = texplanation;
+ }
+ else
+ {
+ // multiple theories involved, not simple
+ simpleExplain = false;
+ }
+ }
+ }
}
Node explanation = texplanation.getNode();
@@ -2131,6 +2335,28 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
}
}
});
+
+ Node exp = mkExplanation(explanationVector);
+
+ if (lcp != nullptr)
+ {
+ // doesn't work currently due to reordering of assumptions
+ /*
+ if (simpleExplain)
+ {
+ // single call to a theory's explain method, skip the proof generator
+ Assert (!simpleTrn.isNull());
+ Trace("te-proof-exp") << "...simple explain " << simpleTrn.getNode() <<
+ std::endl; return simpleTrn;
+ }
+ */
+ // store in the proof generator
+ TrustNode trn = d_tepg->mkTrustExplain(conclusion, exp, lcp);
+ // return the trust node
+ return trn;
+ }
+
+ return theory::TrustNode::mkTrustLemma(exp, nullptr);
}
void TheoryEngine::setUserAttribute(const std::string& attr,
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index cd3e8e122..a5b9c393f 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -37,14 +37,15 @@
#include "smt/command.h"
#include "theory/atom_requests.h"
#include "theory/decision_manager.h"
+#include "theory/engine_output_channel.h"
#include "theory/interrupted.h"
-#include "theory/proof_engine_output_channel.h"
#include "theory/rewriter.h"
#include "theory/shared_terms_database.h"
#include "theory/sort_inference.h"
#include "theory/substitutions.h"
#include "theory/term_registration_visitor.h"
#include "theory/theory.h"
+#include "theory/trust_node.h"
#include "theory/uf/equality_engine.h"
#include "theory/valuation.h"
#include "util/hash.h"
@@ -57,6 +58,7 @@ namespace CVC4 {
class ResourceManager;
class LemmaProofRecipe;
class LazyCDProof;
+class TheoryEngineProofGenerator;
/**
* A pair of a theory and a node. This is used to mark the flow of
@@ -155,8 +157,10 @@ class TheoryEngine {
* This stores instructions for how to construct proofs for all theory lemmas.
*/
std::shared_ptr<LazyCDProof> d_lazyProof;
+ /** The proof generator */
+ std::shared_ptr<TheoryEngineProofGenerator> d_tepg;
//--------------------------------- end new proofs
-
+
/**
* The database of shared terms.
*/
@@ -252,10 +256,8 @@ class TheoryEngine {
*/
context::CDHashSet<Node, NodeHashFunction> d_hasPropagated;
- /**
- * Output channels for individual theories.
- */
- theory::ProofEngineOutputChannel* d_theoryOut[theory::THEORY_LAST];
+ /** Output channels for individual theories. */
+ theory::EngineOutputChannel* d_theoryOut[theory::THEORY_LAST];
/**
* Are we in conflict.
@@ -360,6 +362,19 @@ class TheoryEngine {
bool preprocess,
theory::TheoryId atomsTo);
+ /**
+ * Process trust node. This method ensures that the proof for the proven node
+ * of trn is stored as a lazy step in the lazy proof (d_lazyProof) maintained
+ * by this class, referencing the proof generator of the trust node. The
+ * argument from specifies the theory responsible for this trust node. If
+ * no generator is provided, then a (eager) THEORY_LEMMA step is added to
+ * the lazy proof.
+ *
+ * @param trn The trust node to process
+ * @param from The id of the theory responsible for the trust node.
+ */
+ void processTrustNode(theory::TrustNode trn, theory::TheoryId from);
+
/** Enusre that the given atoms are send to the given theory */
void ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId theory);
@@ -401,8 +416,7 @@ class TheoryEngine {
inline void addTheory(theory::TheoryId theoryId)
{
Assert(d_theoryTable[theoryId] == NULL && d_theoryOut[theoryId] == NULL);
- d_theoryOut[theoryId] =
- new theory::ProofEngineOutputChannel(this, theoryId, d_lazyProof.get());
+ d_theoryOut[theoryId] = new theory::EngineOutputChannel(this, theoryId);
d_theoryTable[theoryId] = new TheoryClass(d_context,
d_userContext,
*d_theoryOut[theoryId],
@@ -514,10 +528,11 @@ class TheoryEngine {
* theory that sent the literal. The lemmaProofRecipe will contain a list
* of the explanation steps required to produce the original node.
*/
- void getExplanation(std::vector<NodeTheoryPair>& explanationVector, LemmaProofRecipe* lemmaProofRecipe);
-
-public:
+ theory::TrustNode getExplanation(
+ std::vector<NodeTheoryPair>& explanationVector,
+ LemmaProofRecipe* lemmaProofRecipe);
+ public:
/**
* Signal the start of a new round of assertion preprocessing
*/
@@ -635,13 +650,14 @@ public:
/**
* Returns an explanation of the node propagated to the SAT solver.
*/
- Node getExplanation(TNode node);
+ theory::TrustNode getExplanation(TNode node);
/**
* Returns an explanation of the node propagated to the SAT solver and the theory
* that propagated it.
*/
- Node getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRecipe);
+ theory::TrustNode getExplanationAndRecipe(TNode node,
+ LemmaProofRecipe* proofRecipe);
/**
* collect model info
diff --git a/src/theory/theory_engine_proof_generator.cpp b/src/theory/theory_engine_proof_generator.cpp
new file mode 100644
index 000000000..c11378e04
--- /dev/null
+++ b/src/theory/theory_engine_proof_generator.cpp
@@ -0,0 +1,84 @@
+/********************* */
+/*! \file theory_engine_proof_generator.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The theory engine proof generator
+ **/
+
+#include "theory/theory_engine_proof_generator.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+
+TheoryEngineProofGenerator::TheoryEngineProofGenerator(ProofNodeManager* pnm,
+ context::UserContext* u)
+ : d_pnm(pnm), d_proofs(u)
+{
+}
+
+theory::TrustNode TheoryEngineProofGenerator::mkTrustExplain(
+ TNode lit, Node exp, std::shared_ptr<LazyCDProof> lpf)
+{
+ theory::TrustNode trn = theory::TrustNode::mkTrustPropExp(lit, exp, this);
+ Node p = trn.getProven();
+ Assert(p.getKind() == IMPLIES && p.getNumChildren() == 2);
+ // should not already be proven
+ NodeLazyCDProofMap::iterator it = d_proofs.find(p);
+ if (it != d_proofs.end())
+ {
+ Assert(false);
+ }
+ else
+ {
+ // we will prove this
+ d_proofs.insert(p, lpf);
+ }
+ return trn;
+}
+
+std::shared_ptr<ProofNode> TheoryEngineProofGenerator::getProofFor(Node f)
+{
+ // should only ask this generator for proofs of implications
+ Assert(f.getKind() == IMPLIES && f.getNumChildren() == 2);
+ NodeLazyCDProofMap::iterator it = d_proofs.find(f);
+ if (it == d_proofs.end())
+ {
+ return nullptr;
+ }
+ std::shared_ptr<LazyCDProof> lcp = (*it).second;
+ // finalize it via scope
+ std::vector<Node> scopeAssumps;
+ if (f[0].getKind() == AND)
+ {
+ for (const Node& fc : f[0])
+ {
+ scopeAssumps.push_back(fc);
+ }
+ }
+ else
+ {
+ scopeAssumps.push_back(f[1]);
+ }
+ Node conclusion = f[1];
+
+ // get the proof for conclusion
+ std::shared_ptr<ProofNode> pfb = lcp->mkProof(conclusion);
+ // call the scope method of proof node manager
+ std::shared_ptr<ProofNode> pf = d_pnm->mkScope(pfb, scopeAssumps);
+ return pf;
+}
+
+std::string TheoryEngineProofGenerator::identify() const
+{
+ return "TheoryEngineProofGenerator";
+}
+
+} // namespace CVC4
diff --git a/src/theory/theory_engine_proof_generator.h b/src/theory/theory_engine_proof_generator.h
new file mode 100644
index 000000000..c81a2c09b
--- /dev/null
+++ b/src/theory/theory_engine_proof_generator.h
@@ -0,0 +1,58 @@
+/********************* */
+/*! \file theory_engine.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The theory engine proof generator
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY_ENGINE_PROOF_GENERATOR_H
+#define CVC4__THEORY_ENGINE_PROOF_GENERATOR_H
+
+#include <memory>
+
+#include "context/cdhashmap.h"
+#include "context/context.h"
+#include "expr/lazy_proof.h"
+#include "expr/proof_generator.h"
+#include "expr/proof_node_manager.h"
+#include "theory/trust_node.h"
+
+namespace CVC4 {
+
+class TheoryEngineProofGenerator : public ProofGenerator
+{
+ typedef context::
+ CDHashMap<Node, std::shared_ptr<LazyCDProof>, NodeHashFunction>
+ NodeLazyCDProofMap;
+
+ public:
+ TheoryEngineProofGenerator(ProofNodeManager* pnm, context::UserContext* u);
+ ~TheoryEngineProofGenerator() {}
+ /** Set proof */
+ theory::TrustNode mkTrustExplain(TNode lit,
+ Node exp,
+ std::shared_ptr<LazyCDProof> lpf);
+ /** Get proof for */
+ std::shared_ptr<ProofNode> getProofFor(Node f) override;
+ /** Identify this generator (for debugging, etc..) */
+ std::string identify() const override;
+
+ private:
+ /** The proof manager, used for allocating new ProofNode objects */
+ ProofNodeManager* d_pnm;
+ /** Map from formulas to lazy CD proofs */
+ NodeLazyCDProofMap d_proofs;
+};
+
+} // namespace CVC4
+
+#endif /* CVC4__THEORY_ENGINE_PROOF_GENERATOR_H */
diff --git a/src/theory/trust_node.cpp b/src/theory/trust_node.cpp
index 4c6246888..ff3e89154 100644
--- a/src/theory/trust_node.cpp
+++ b/src/theory/trust_node.cpp
@@ -15,7 +15,6 @@
#include "theory/trust_node.h"
#include "expr/proof_generator.h"
-#include "theory/proof_engine_output_channel.h"
namespace CVC4 {
namespace theory {
@@ -39,22 +38,25 @@ std::ostream& operator<<(std::ostream& out, TrustNodeKind tnk)
TrustNode TrustNode::mkTrustConflict(Node conf, ProofGenerator* g)
{
+ Node ckey = getConflictProven(conf);
// if a generator is provided, should confirm that it can prove it
- Assert(g == nullptr || g->hasProofFor(getConflictKeyValue(conf)));
- return TrustNode(TrustNodeKind::CONFLICT, conf, g);
+ Assert(g == nullptr || g->hasProofFor(ckey));
+ return TrustNode(TrustNodeKind::CONFLICT, ckey, g);
}
TrustNode TrustNode::mkTrustLemma(Node lem, ProofGenerator* g)
{
+ Node lkey = getLemmaProven(lem);
// if a generator is provided, should confirm that it can prove it
- Assert(g == nullptr || g->hasProofFor(getLemmaKeyValue(lem)));
- return TrustNode(TrustNodeKind::LEMMA, lem, g);
+ Assert(g == nullptr || g->hasProofFor(lkey));
+ return TrustNode(TrustNodeKind::LEMMA, lkey, g);
}
TrustNode TrustNode::mkTrustPropExp(TNode lit, Node exp, ProofGenerator* g)
{
- Assert(g == nullptr || g->hasProofFor(getPropExpKeyValue(lit, exp)));
- return TrustNode(TrustNodeKind::PROP_EXP, exp, g);
+ Node pekey = getPropExpProven(lit, exp);
+ Assert(g == nullptr || g->hasProofFor(pekey));
+ return TrustNode(TrustNodeKind::PROP_EXP, pekey, g);
}
TrustNode TrustNode::null()
@@ -62,50 +64,34 @@ TrustNode TrustNode::null()
return TrustNode(TrustNodeKind::INVALID, Node::null());
}
-TrustNode::TrustNode(TrustNodeKind tnk, Node n, ProofGenerator* g)
- : d_tnk(tnk), d_node(n), d_gen(g)
+TrustNode::TrustNode(TrustNodeKind tnk, Node p, ProofGenerator* g)
+ : d_tnk(tnk), d_proven(p), d_gen(g)
{
// does not make sense to provide null node with generator
- Assert(!d_node.isNull() || d_gen == nullptr);
+ Assert(!d_proven.isNull() || d_gen == nullptr);
}
TrustNodeKind TrustNode::getKind() const { return d_tnk; }
-Node TrustNode::getNode() const { return d_node; }
+Node TrustNode::getNode() const
+{
+ return d_tnk == TrustNodeKind::LEMMA ? d_proven : d_proven[0];
+}
+Node TrustNode::getProven() const { return d_proven; }
ProofGenerator* TrustNode::getGenerator() const { return d_gen; }
-bool TrustNode::isNull() const { return d_node.isNull(); }
+bool TrustNode::isNull() const { return d_proven.isNull(); }
-Node TrustNode::getConflictKeyValue(Node conf) { return conf.negate(); }
+Node TrustNode::getConflictProven(Node conf) { return conf.notNode(); }
-Node TrustNode::getLemmaKeyValue(Node lem) { return lem; }
+Node TrustNode::getLemmaProven(Node lem) { return lem; }
-Node TrustNode::getPropExpKeyValue(TNode lit, Node exp)
+Node TrustNode::getPropExpProven(TNode lit, Node exp)
{
- if (exp.isConst())
- {
- Assert(exp.getConst<bool>());
- return lit;
- }
return NodeManager::currentNM()->mkNode(kind::IMPLIES, exp, lit);
}
-Node TrustNode::getKeyValue(TrustNodeKind tnk, Node exp, Node conc)
-{
- if (conc.isConst())
- {
- Assert(!conc.getConst<bool>());
- return exp.negate();
- }
- if (exp.isConst())
- {
- Assert(exp.getConst<bool>());
- return conc;
- }
- return NodeManager::currentNM()->mkNode(kind::IMPLIES, exp, conc);
-}
-
std::ostream& operator<<(std::ostream& out, TrustNode n)
{
out << "(trust " << n.getNode() << ")";
diff --git a/src/theory/trust_node.h b/src/theory/trust_node.h
index 3ced7efe9..8d3548bd5 100644
--- a/src/theory/trust_node.h
+++ b/src/theory/trust_node.h
@@ -87,28 +87,48 @@ class TrustNode
~TrustNode() {}
/** get kind */
TrustNodeKind getKind() const;
- /** get node */
+ /** get node
+ *
+ * This is the node that is used in a common interface, either:
+ * (1) A T-unsat conjunction conf to pass to OutputChannel::conflict,
+ * (2) A valid T-formula lem to pass to OutputChannel::lemma, or
+ * (3) A conjunction of literals exp to return in Theory::explain(lit).
+ *
+ * Notice that this node does not necessarily correspond to a valid formula.
+ * The call getProven() below retrieves a valid formula corresponding to
+ * the above calls.
+ */
Node getNode() const;
+ /** get proven
+ *
+ * This is the corresponding formula that is proven by the proof generator
+ * for the above cases:
+ * (1) (not conf), for conflicts,
+ * (2) lem, for lemmas,
+ * (3) (=> exp lit), for propagations from explanations.
+ *
+ * When constructing this trust node, the proof generator should be able to
+ * provide a proof for this fact.
+ */
+ Node getProven() const;
/** get generator */
ProofGenerator* getGenerator() const;
/** is null? */
bool isNull() const;
- /** Get the node key for which conflict calls are cached */
- static Node getConflictKeyValue(Node conf);
- /** Get the node key for which lemma calls are cached */
- static Node getLemmaKeyValue(Node lem);
- /** Get the node key for which explanations for propagations are cached */
- static Node getPropExpKeyValue(TNode lit, Node exp);
- /** Get the node key for the exp => conc */
- static Node getKeyValue(TrustNodeKind tnk, Node exp, Node conc);
+ /** Get the proven formula corresponding to a conflict call */
+ static Node getConflictProven(Node conf);
+ /** Get the proven formula corresponding to a lemma call */
+ static Node getLemmaProven(Node lem);
+ /** Get the proven formula corresponding to explanations for propagation*/
+ static Node getPropExpProven(TNode lit, Node exp);
private:
- TrustNode(TrustNodeKind tnk, Node n, ProofGenerator* g = nullptr);
+ TrustNode(TrustNodeKind tnk, Node p, ProofGenerator* g = nullptr);
/** The kind */
TrustNodeKind d_tnk;
- /** The node */
- Node d_node;
+ /** The proven node */
+ Node d_proven;
/** The generator */
ProofGenerator* d_gen;
};
diff --git a/src/theory/uf/eq_proof.h b/src/theory/uf/eq_proof.h
index 42783d31f..49529aa2f 100644
--- a/src/theory/uf/eq_proof.h
+++ b/src/theory/uf/eq_proof.h
@@ -97,7 +97,8 @@ class EqProof
CDProof* p,
std::unordered_set<Node, NodeHashFunction>& assumptions) const;
- bool buildTransitivityChain(Node conclusion, std::vector<Node>& premises) const;
+ bool buildTransitivityChain(Node conclusion,
+ std::vector<Node>& premises) const;
// returns whether it did reordering
void maybeAddSymmOrTrueIntroToProof(unsigned i,
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index 504f43d72..ae7477480 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -456,7 +456,11 @@ void EqualityEngine::assertEqualityInternal(TNode t1, TNode t2, TNode reason, un
enqueue(MergeCandidate(t1Id, t2Id, pid, reason));
}
-bool EqualityEngine::assertPredicate(TNode t, bool polarity, TNode reason, unsigned pid) {
+bool EqualityEngine::assertPredicate(TNode t,
+ bool polarity,
+ TNode reason,
+ unsigned pid)
+{
Debug("equality") << d_name << "::eq::addPredicate(" << t << "," << (polarity ? "true" : "false") << ")" << std::endl;
Assert(t.getKind() != kind::EQUAL) << "Use assertEquality instead";
TNode b = polarity ? d_true : d_false;
@@ -469,7 +473,11 @@ bool EqualityEngine::assertPredicate(TNode t, bool polarity, TNode reason, unsig
return true;
}
-bool EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason, unsigned pid) {
+bool EqualityEngine::assertEquality(TNode eq,
+ bool polarity,
+ TNode reason,
+ unsigned pid)
+{
Debug("equality") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ")" << std::endl;
if (polarity) {
// If two terms are already equal, don't assert anything
diff --git a/src/theory/uf/proof_equality_engine.cpp b/src/theory/uf/proof_equality_engine.cpp
index d600a546b..13a1d581c 100644
--- a/src/theory/uf/proof_equality_engine.cpp
+++ b/src/theory/uf/proof_equality_engine.cpp
@@ -394,9 +394,6 @@ TrustNode ProofEqEngine::ensureProofForFact(Node conc,
// assumption (= y x). We modify the proof leaves to account for this
// below.
- // The free assumptions of the proof
- std::map<Node, std::vector<ProofNode*>> famap;
- pfConc->getFreeAssumptionsMap(famap);
// we first ensure the assumptions are flattened
std::unordered_set<Node, NodeHashFunction> ac;
for (const TNode& a : assumps)
@@ -410,6 +407,9 @@ TrustNode ProofEqEngine::ensureProofForFact(Node conc,
ac.insert(a);
}
}
+ // The free assumptions of the proof
+ std::map<Node, std::vector<ProofNode*>> famap;
+ pfConc->getFreeAssumptionsMap(famap);
std::unordered_set<Node, NodeHashFunction> acu;
std::unordered_set<Node, NodeHashFunction>::iterator itf;
for (const std::pair<const Node, std::vector<ProofNode*>>& fa : famap)
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback