summaryrefslogtreecommitdiff
path: root/src/expr/proof_checker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/expr/proof_checker.cpp')
-rw-r--r--src/expr/proof_checker.cpp206
1 files changed, 190 insertions, 16 deletions
diff --git a/src/expr/proof_checker.cpp b/src/expr/proof_checker.cpp
index 95e43620b..7e7a26c5b 100644
--- a/src/expr/proof_checker.cpp
+++ b/src/expr/proof_checker.cpp
@@ -14,8 +14,94 @@
#include "expr/proof_checker.h"
+#include "expr/proof_skolem_cache.h"
+#include "smt/smt_statistics_registry.h"
+
+using namespace CVC4::kind;
+
namespace CVC4 {
+Node ProofRuleChecker::check(PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args)
+{
+ // convert to witness form
+ std::vector<Node> childrenw = children;
+ std::vector<Node> argsw = args;
+ ProofSkolemCache::convertToWitnessFormVec(childrenw);
+ ProofSkolemCache::convertToWitnessFormVec(argsw);
+ Node res = checkInternal(id, childrenw, argsw);
+ // res is in terms of witness form, convert back to Skolem form
+ return ProofSkolemCache::getSkolemForm(res);
+}
+
+Node ProofRuleChecker::checkChildrenArg(PfRule id,
+ const std::vector<Node>& children,
+ Node arg)
+{
+ return check(id, children, {arg});
+}
+Node ProofRuleChecker::checkChildren(PfRule id,
+ const std::vector<Node>& children)
+{
+ return check(id, children, {});
+}
+Node ProofRuleChecker::checkChild(PfRule id, Node child)
+{
+ return check(id, {child}, {});
+}
+Node ProofRuleChecker::checkArg(PfRule id, Node arg)
+{
+ return check(id, {}, {arg});
+}
+
+Node ProofRuleChecker::mkAnd(const std::vector<Node>& a)
+{
+ if (a.empty())
+ {
+ return NodeManager::currentNM()->mkConst(true);
+ }
+ else if (a.size() == 1)
+ {
+ return a[0];
+ }
+ return NodeManager::currentNM()->mkNode(AND, a);
+}
+
+bool ProofRuleChecker::getUInt32(TNode n, uint32_t& i)
+{
+ // must be a non-negative integer constant that fits an unsigned int
+ if (n.isConst() && n.getType().isInteger()
+ && n.getConst<Rational>().sgn() >= 0
+ && n.getConst<Rational>().getNumerator().fitsUnsignedInt())
+ {
+ i = n.getConst<Rational>().getNumerator().toUnsignedInt();
+ return true;
+ }
+ return false;
+}
+
+bool ProofRuleChecker::getBool(TNode n, bool& b)
+{
+ if (n.isConst() && n.getType().isBoolean())
+ {
+ b = n.getConst<bool>();
+ return true;
+ }
+ return false;
+}
+
+ProofCheckerStatistics::ProofCheckerStatistics()
+ : d_ruleChecks("ProofCheckerStatistics::ruleChecks")
+{
+ smtStatisticsRegistry()->registerStat(&d_ruleChecks);
+}
+
+ProofCheckerStatistics::~ProofCheckerStatistics()
+{
+ smtStatisticsRegistry()->unregisterStat(&d_ruleChecks);
+}
+
Node ProofChecker::check(ProofNode* pn, Node expected)
{
return check(pn->getRule(), pn->getChildren(), pn->getArguments(), expected);
@@ -27,15 +113,17 @@ Node ProofChecker::check(
const std::vector<Node>& args,
Node expected)
{
- std::map<PfRule, ProofRuleChecker*>::iterator it = d_checker.find(id);
- if (it == d_checker.end())
+ // optimization: immediately return for ASSUME
+ if (id == PfRule::ASSUME)
{
- // no checker for the rule
- Trace("pfcheck") << "ProofChecker::check: no checker for rule " << id
- << std::endl;
- return Node::null();
+ Assert(children.empty());
+ Assert(args.size() == 1 && args[0].getType().isBoolean());
+ Assert(expected.isNull() || expected == args[0]);
+ return expected;
}
- // check it with the corresponding checker
+ // record stat
+ d_stats.d_ruleChecks << id;
+ Trace("pfcheck") << "ProofChecker::check: " << id << std::endl;
std::vector<Node> cchildren;
for (const std::shared_ptr<ProofNode>& pc : children)
{
@@ -43,26 +131,112 @@ Node ProofChecker::check(
Node cres = pc->getResult();
if (cres.isNull())
{
- Trace("pfcheck")
+ Trace("pfcheck") << "ProofChecker::check: failed child" << std::endl;
+ Unreachable()
<< "ProofChecker::check: child proof was invalid (null conclusion)"
<< std::endl;
// should not have been able to create such a proof node
- Assert(false);
return Node::null();
}
cchildren.push_back(cres);
+ if (Trace.isOn("pfcheck"))
+ {
+ std::stringstream ssc;
+ pc->printDebug(ssc);
+ Trace("pfcheck") << " child: " << ssc.str() << " : " << cres
+ << std::endl;
+ }
}
- Node res = it->second->check(id, cchildren, args);
- if (!expected.isNull() && res != expected)
+ Trace("pfcheck") << " args: " << args << std::endl;
+ Trace("pfcheck") << " expected: " << expected << std::endl;
+ std::stringstream out;
+ // we use trusted (null) checkers here, since we want the proof generation to
+ // proceed without failing here.
+ Node res = checkInternal(id, cchildren, args, expected, out, true);
+ if (res.isNull())
{
- Trace("pfcheck")
- << "ProofChecker::check: result does not match expected value."
- << std::endl;
- Trace("pfcheck") << " result: " << res << std::endl;
- Trace("pfcheck") << " expected: " << expected << std::endl;
+ Trace("pfcheck") << "ProofChecker::check: failed" << std::endl;
+ Unreachable() << "ProofChecker::check: failed, " << out.str() << std::endl;
// it did not match the given expectation, fail
return Node::null();
}
+ Trace("pfcheck") << "ProofChecker::check: success!" << std::endl;
+ return res;
+}
+
+Node ProofChecker::checkDebug(PfRule id,
+ const std::vector<Node>& cchildren,
+ const std::vector<Node>& args,
+ Node expected,
+ const char* traceTag)
+{
+ std::stringstream out;
+ // since we are debugging, we want to treat trusted (null) checkers as
+ // a failure.
+ Node res = checkInternal(id, cchildren, args, expected, out, false);
+ Trace(traceTag) << "ProofChecker::checkDebug: " << id;
+ if (res.isNull())
+ {
+ Trace(traceTag) << " failed, " << out.str() << std::endl;
+ }
+ else
+ {
+ Trace(traceTag) << " success" << std::endl;
+ }
+ return res;
+}
+
+Node ProofChecker::checkInternal(PfRule id,
+ const std::vector<Node>& cchildren,
+ const std::vector<Node>& args,
+ Node expected,
+ std::stringstream& out,
+ bool useTrustedChecker)
+{
+ std::map<PfRule, ProofRuleChecker*>::iterator it = d_checker.find(id);
+ if (it == d_checker.end())
+ {
+ // no checker for the rule
+ out << "no checker for rule " << id << std::endl;
+ return Node::null();
+ }
+ else if (it->second == nullptr)
+ {
+ if (useTrustedChecker)
+ {
+ Notice() << "ProofChecker::check: trusting PfRule " << id << std::endl;
+ // trusted checker
+ return expected;
+ }
+ else
+ {
+ out << "trusted checker for rule " << id << std::endl;
+ return Node::null();
+ }
+ }
+ // check it with the corresponding checker
+ Node res = it->second->check(id, cchildren, args);
+ if (!expected.isNull())
+ {
+ Node expectedw = expected;
+ if (res != expectedw)
+ {
+ out << "result does not match expected value." << std::endl
+ << " PfRule: " << id << std::endl;
+ for (const Node& c : cchildren)
+ {
+ out << " child: " << c << std::endl;
+ }
+ for (const Node& a : args)
+ {
+ out << " arg: " << a << std::endl;
+ }
+ out << " result: " << res << std::endl
+ << " expected: " << expected << std::endl;
+ // it did not match the given expectation, fail
+ return Node::null();
+ }
+ }
return res;
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback