1 /********************* */
2 /*! \file proof_checker.cpp
4 ** Top contributors (to current version):
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
8 ** in the top-level source directory) and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
12 ** \brief Implementation of equality proof checker
15 #include "theory/builtin/proof_checker.h"
17 #include "expr/proof_skolem_cache.h"
18 #include "theory/rewriter.h"
19 #include "theory/theory.h"
21 using namespace CVC4::kind
;
26 const char* toString(MethodId id
)
30 case MethodId::RW_REWRITE
: return "RW_REWRITE";
31 case MethodId::RW_IDENTITY
: return "RW_IDENTITY";
32 case MethodId::SB_DEFAULT
: return "SB_DEFAULT";
33 case MethodId::SB_LITERAL
: return "SB_LITERAL";
34 case MethodId::SB_FORMULA
: return "SB_FORMULA";
35 default: return "MethodId::Unknown";
39 std::ostream
& operator<<(std::ostream
& out
, MethodId id
)
45 Node
mkMethodId(MethodId id
)
47 return NodeManager::currentNM()->mkConst(Rational(static_cast<uint32_t>(id
)));
52 void BuiltinProofRuleChecker::registerTo(ProofChecker
* pc
)
54 pc
->registerChecker(PfRule::ASSUME
, this);
55 pc
->registerChecker(PfRule::SCOPE
, this);
56 pc
->registerChecker(PfRule::SUBS
, this);
57 pc
->registerChecker(PfRule::REWRITE
, this);
58 pc
->registerChecker(PfRule::MACRO_SR_EQ_INTRO
, this);
59 pc
->registerChecker(PfRule::MACRO_SR_PRED_INTRO
, this);
60 pc
->registerChecker(PfRule::MACRO_SR_PRED_ELIM
, this);
61 pc
->registerChecker(PfRule::MACRO_SR_PRED_TRANSFORM
, this);
64 Node
BuiltinProofRuleChecker::applyRewrite(Node n
, MethodId idr
)
66 Node nk
= ProofSkolemCache::getSkolemForm(n
);
67 Node nkr
= applyRewriteExternal(nk
, idr
);
68 return ProofSkolemCache::getWitnessForm(nkr
);
71 Node
BuiltinProofRuleChecker::applySubstitution(Node n
, Node exp
, MethodId ids
)
73 if (exp
.isNull() || exp
.getKind() != EQUAL
)
77 Node nk
= ProofSkolemCache::getSkolemForm(n
);
78 Node nks
= applySubstitutionExternal(nk
, exp
, ids
);
79 return ProofSkolemCache::getWitnessForm(nks
);
82 Node
BuiltinProofRuleChecker::applySubstitution(Node n
,
83 const std::vector
<Node
>& exp
,
86 Node nk
= ProofSkolemCache::getSkolemForm(n
);
87 Node nks
= applySubstitutionExternal(nk
, exp
, ids
);
88 return ProofSkolemCache::getWitnessForm(nks
);
91 Node
BuiltinProofRuleChecker::applySubstitutionRewrite(
92 Node n
, const std::vector
<Node
>& exp
, MethodId ids
, MethodId idr
)
94 Node nk
= ProofSkolemCache::getSkolemForm(n
);
95 Node nks
= applySubstitutionExternal(nk
, exp
, ids
);
96 Node nksr
= applyRewriteExternal(nks
, idr
);
97 return ProofSkolemCache::getWitnessForm(nksr
);
100 Node
BuiltinProofRuleChecker::applyRewriteExternal(Node n
, MethodId idr
)
102 Trace("builtin-pfcheck-debug")
103 << "applyRewriteExternal (" << idr
<< "): " << n
<< std::endl
;
104 if (idr
== MethodId::RW_REWRITE
)
106 return Rewriter::rewrite(n
);
108 else if (idr
== MethodId::RW_IDENTITY
)
115 << "BuiltinProofRuleChecker::applyRewriteExternal: no rewriter for "
120 Node
BuiltinProofRuleChecker::applySubstitutionExternal(Node n
,
124 Assert(!exp
.isNull());
125 Node expk
= ProofSkolemCache::getSkolemForm(exp
);
127 if (ids
== MethodId::SB_DEFAULT
)
129 if (expk
.getKind() != EQUAL
)
136 else if (ids
== MethodId::SB_LITERAL
)
138 bool polarity
= expk
.getKind() != NOT
;
139 var
= polarity
? expk
: expk
[0];
140 subs
= NodeManager::currentNM()->mkConst(polarity
);
142 else if (ids
== MethodId::SB_FORMULA
)
145 subs
= NodeManager::currentNM()->mkConst(true);
149 Assert(false) << "BuiltinProofRuleChecker::applySubstitutionExternal: no "
153 return n
.substitute(var
, subs
);
156 Node
BuiltinProofRuleChecker::applySubstitutionExternal(
157 Node n
, const std::vector
<Node
>& exp
, MethodId ids
)
160 // apply substitution one at a time, in reverse order
161 for (size_t i
= 0, nexp
= exp
.size(); i
< nexp
; i
++)
163 if (exp
[nexp
- 1 - i
].isNull())
167 curr
= applySubstitutionExternal(curr
, exp
[nexp
- 1 - i
], ids
);
176 bool BuiltinProofRuleChecker::getMethodId(TNode n
, MethodId
& i
)
179 if (!getUInt32(n
, index
))
183 i
= static_cast<MethodId
>(index
);
187 Node
BuiltinProofRuleChecker::checkInternal(PfRule id
,
188 const std::vector
<Node
>& children
,
189 const std::vector
<Node
>& args
)
191 // compute what was proven
192 if (id
== PfRule::ASSUME
)
194 Assert(children
.empty());
195 Assert(args
.size() == 1);
196 Assert(args
[0].getType().isBoolean());
199 else if (id
== PfRule::SCOPE
)
201 Assert(children
.size() == 1);
207 Node ant
= mkAnd(args
);
208 // if the conclusion is false, its the negated antencedant only
209 if (children
[0].isConst() && !children
[0].getConst
<bool>())
211 return ant
.notNode();
213 return NodeManager::currentNM()->mkNode(IMPLIES
, ant
, children
[0]);
215 else if (id
== PfRule::SUBS
)
217 Assert(children
.size() > 0);
218 Assert(1 <= args
.size() && args
.size() <= 2);
219 MethodId ids
= MethodId::SB_DEFAULT
;
220 if (args
.size() == 2 && !getMethodId(args
[1], ids
))
224 std::vector
<Node
> exp
;
225 for (size_t i
= 0, nchild
= children
.size(); i
< nchild
; i
++)
227 exp
.push_back(children
[i
]);
229 Node res
= applySubstitution(args
[0], exp
);
230 return args
[0].eqNode(res
);
232 else if (id
== PfRule::REWRITE
)
234 Assert(children
.empty());
235 Assert(1 <= args
.size() && args
.size() <= 2);
236 MethodId ids
= MethodId::RW_REWRITE
;
237 if (args
.size() == 2 && !getMethodId(args
[1], ids
))
241 Node res
= applyRewrite(args
[0]);
242 return args
[0].eqNode(res
);
244 else if (id
== PfRule::MACRO_SR_EQ_INTRO
)
246 Assert(1 <= args
.size() && args
.size() <= 3);
248 if (!getMethodIds(args
, ids
, idr
, 1))
252 Node res
= applySubstitutionRewrite(args
[0], children
, idr
);
253 return args
[0].eqNode(res
);
255 else if (id
== PfRule::MACRO_SR_PRED_INTRO
)
257 Trace("builtin-pfcheck") << "Check " << id
<< " " << children
.size() << " "
258 << args
.size() << std::endl
;
259 Assert(1 <= args
.size() && args
.size() <= 3);
261 if (!getMethodIds(args
, ids
, idr
, 1))
265 Node res
= applySubstitutionRewrite(args
[0], children
, ids
, idr
);
270 // **** NOTE: can rewrite the witness form here. This enables certain lemmas
271 // to be provable, e.g. (= k t) where k is a purification Skolem for t.
272 res
= Rewriter::rewrite(res
);
273 if (!res
.isConst() || !res
.getConst
<bool>())
275 Trace("builtin-pfcheck")
276 << "Failed to rewrite to true, res=" << res
<< std::endl
;
281 else if (id
== PfRule::MACRO_SR_PRED_ELIM
)
283 Trace("builtin-pfcheck") << "Check " << id
<< " " << children
.size() << " "
284 << args
.size() << std::endl
;
285 Assert(children
.size() >= 1);
286 Assert(args
.size() <= 2);
287 std::vector
<Node
> exp
;
288 exp
.insert(exp
.end(), children
.begin() + 1, children
.end());
290 if (!getMethodIds(args
, ids
, idr
, 0))
294 Node res1
= applySubstitutionRewrite(children
[0], exp
, ids
, idr
);
295 Trace("builtin-pfcheck") << "Returned " << res1
<< std::endl
;
298 else if (id
== PfRule::MACRO_SR_PRED_TRANSFORM
)
300 Trace("builtin-pfcheck") << "Check " << id
<< " " << children
.size() << " "
301 << args
.size() << std::endl
;
302 Assert(children
.size() >= 1);
303 Assert(1 <= args
.size() && args
.size() <= 3);
304 Assert(args
[0].getType().isBoolean());
306 if (!getMethodIds(args
, ids
, idr
, 1))
310 std::vector
<Node
> exp
;
311 exp
.insert(exp
.end(), children
.begin() + 1, children
.end());
312 Node res1
= applySubstitutionRewrite(children
[0], exp
, ids
, idr
);
313 Node res2
= applySubstitutionRewrite(args
[0], exp
, ids
, idr
);
314 // can rewrite the witness forms
315 res1
= Rewriter::rewrite(res1
);
316 res2
= Rewriter::rewrite(res2
);
317 if (res1
.isNull() || res1
!= res2
)
319 Trace("builtin-pfcheck") << "Failed to match results" << std::endl
;
320 Trace("builtin-pfcheck-debug") << res1
<< " vs " << res2
<< std::endl
;
329 bool BuiltinProofRuleChecker::getMethodIds(const std::vector
<Node
>& args
,
334 ids
= MethodId::SB_DEFAULT
;
335 idr
= MethodId::RW_REWRITE
;
336 if (args
.size() > index
)
338 if (!getMethodId(args
[index
], ids
))
340 Trace("builtin-pfcheck")
341 << "Failed to get id from " << args
[index
] << std::endl
;
345 if (args
.size() > index
+ 1)
347 if (!getMethodId(args
[index
+ 1], idr
))
349 Trace("builtin-pfcheck")
350 << "Failed to get id from " << args
[index
+ 1] << std::endl
;
357 } // namespace builtin
358 } // namespace theory