1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Haniel Barbosa, Andrew Reynolds, Aina Niemetz |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 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. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* Implementation of theory proof step buffer utility. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/theory_proof_step_buffer.h" |
17 |
|
|
18 |
|
#include "expr/proof.h" |
19 |
|
|
20 |
|
using namespace cvc5::kind; |
21 |
|
|
22 |
|
namespace cvc5 { |
23 |
|
namespace theory { |
24 |
|
|
25 |
9749 |
TheoryProofStepBuffer::TheoryProofStepBuffer(ProofChecker* pc) |
26 |
9749 |
: ProofStepBuffer(pc) |
27 |
|
{ |
28 |
9749 |
} |
29 |
|
|
30 |
10761 |
bool TheoryProofStepBuffer::applyEqIntro(Node src, |
31 |
|
Node tgt, |
32 |
|
const std::vector<Node>& exp, |
33 |
|
MethodId ids, |
34 |
|
MethodId ida, |
35 |
|
MethodId idr) |
36 |
|
{ |
37 |
21522 |
std::vector<Node> args; |
38 |
10761 |
args.push_back(src); |
39 |
10761 |
builtin::BuiltinProofRuleChecker::addMethodIds(args, ids, ida, idr); |
40 |
21522 |
Node res = tryStep(PfRule::MACRO_SR_EQ_INTRO, exp, args); |
41 |
10761 |
if (res.isNull()) |
42 |
|
{ |
43 |
|
// failed to apply |
44 |
|
return false; |
45 |
|
} |
46 |
|
// should have concluded the expected equality |
47 |
21522 |
Node expected = src.eqNode(tgt); |
48 |
10761 |
if (res != expected) |
49 |
|
{ |
50 |
|
// did not provide the correct target |
51 |
|
popStep(); |
52 |
|
return false; |
53 |
|
} |
54 |
|
// successfully proved src == tgt. |
55 |
10761 |
return true; |
56 |
|
} |
57 |
|
|
58 |
2031 |
bool TheoryProofStepBuffer::applyPredTransform(Node src, |
59 |
|
Node tgt, |
60 |
|
const std::vector<Node>& exp, |
61 |
|
MethodId ids, |
62 |
|
MethodId ida, |
63 |
|
MethodId idr) |
64 |
|
{ |
65 |
|
// symmetric equalities |
66 |
2031 |
if (CDProof::isSame(src, tgt)) |
67 |
|
{ |
68 |
578 |
return true; |
69 |
|
} |
70 |
2906 |
std::vector<Node> children; |
71 |
1453 |
children.push_back(src); |
72 |
2906 |
std::vector<Node> args; |
73 |
|
// try to prove that tgt rewrites to src |
74 |
1453 |
children.insert(children.end(), exp.begin(), exp.end()); |
75 |
1453 |
args.push_back(tgt); |
76 |
1453 |
builtin::BuiltinProofRuleChecker::addMethodIds(args, ids, ida, idr); |
77 |
2906 |
Node res = tryStep(PfRule::MACRO_SR_PRED_TRANSFORM, children, args); |
78 |
1453 |
if (res.isNull()) |
79 |
|
{ |
80 |
|
// failed to apply |
81 |
108 |
return false; |
82 |
|
} |
83 |
|
// should definitely have concluded tgt |
84 |
1345 |
Assert(res == tgt); |
85 |
1345 |
return true; |
86 |
|
} |
87 |
|
|
88 |
|
bool TheoryProofStepBuffer::applyPredIntro(Node tgt, |
89 |
|
const std::vector<Node>& exp, |
90 |
|
MethodId ids, |
91 |
|
MethodId ida, |
92 |
|
MethodId idr) |
93 |
|
{ |
94 |
|
std::vector<Node> args; |
95 |
|
args.push_back(tgt); |
96 |
|
builtin::BuiltinProofRuleChecker::addMethodIds(args, ids, ida, idr); |
97 |
|
Node res = tryStep(PfRule::MACRO_SR_PRED_INTRO, exp, args); |
98 |
|
if (res.isNull()) |
99 |
|
{ |
100 |
|
return false; |
101 |
|
} |
102 |
|
Assert(res == tgt); |
103 |
|
return true; |
104 |
|
} |
105 |
|
|
106 |
89 |
Node TheoryProofStepBuffer::applyPredElim(Node src, |
107 |
|
const std::vector<Node>& exp, |
108 |
|
MethodId ids, |
109 |
|
MethodId ida, |
110 |
|
MethodId idr) |
111 |
|
{ |
112 |
178 |
std::vector<Node> children; |
113 |
89 |
children.push_back(src); |
114 |
89 |
children.insert(children.end(), exp.begin(), exp.end()); |
115 |
178 |
std::vector<Node> args; |
116 |
89 |
builtin::BuiltinProofRuleChecker::addMethodIds(args, ids, ida, idr); |
117 |
89 |
Node srcRew = tryStep(PfRule::MACRO_SR_PRED_ELIM, children, args); |
118 |
89 |
if (CDProof::isSame(src, srcRew)) |
119 |
|
{ |
120 |
21 |
popStep(); |
121 |
|
} |
122 |
178 |
return srcRew; |
123 |
|
} |
124 |
|
|
125 |
377534 |
Node TheoryProofStepBuffer::factorReorderElimDoubleNeg(Node n) |
126 |
|
{ |
127 |
377534 |
if (n.getKind() != kind::OR) |
128 |
|
{ |
129 |
|
return elimDoubleNegLit(n); |
130 |
|
} |
131 |
377534 |
NodeManager* nm = NodeManager::currentNM(); |
132 |
755068 |
std::vector<Node> children{n.begin(), n.end()}; |
133 |
755068 |
std::vector<Node> childrenEqs; |
134 |
|
// eliminate double neg for each lit. Do it first because it may expose |
135 |
|
// duplicates |
136 |
377534 |
bool hasDoubleNeg = false; |
137 |
1662452 |
for (unsigned i = 0; i < children.size(); ++i) |
138 |
|
{ |
139 |
2569836 |
if (children[i].getKind() == kind::NOT |
140 |
2569836 |
&& children[i][0].getKind() == kind::NOT) |
141 |
|
{ |
142 |
157363 |
hasDoubleNeg = true; |
143 |
157363 |
childrenEqs.push_back(children[i].eqNode(children[i][0][0])); |
144 |
629452 |
addStep(PfRule::MACRO_SR_PRED_INTRO, |
145 |
|
{}, |
146 |
157363 |
{childrenEqs.back()}, |
147 |
314726 |
childrenEqs.back()); |
148 |
|
// update child |
149 |
157363 |
children[i] = children[i][0][0]; |
150 |
|
} |
151 |
|
else |
152 |
|
{ |
153 |
1127555 |
childrenEqs.push_back(children[i].eqNode(children[i])); |
154 |
1127555 |
addStep(PfRule::REFL, {}, {children[i]}, childrenEqs.back()); |
155 |
|
} |
156 |
|
} |
157 |
377534 |
if (hasDoubleNeg) |
158 |
|
{ |
159 |
94172 |
Node oldn = n; |
160 |
47086 |
n = nm->mkNode(kind::OR, children); |
161 |
|
// Create a congruence step to justify replacement of each doubly negated |
162 |
|
// literal. This is done to avoid having to use MACRO_SR_PRED_TRANSFORM |
163 |
|
// from the old clause to the new one, which, under the standard rewriter, |
164 |
|
// may not hold. An example is |
165 |
|
// |
166 |
|
// --------------------------------------------------------------------- |
167 |
|
// (or (or (not x2) x1 x2) (not (not x2))) = (or (or (not x2) x1 x2) x2) |
168 |
|
// |
169 |
|
// which fails due to factoring not happening after flattening. |
170 |
|
// |
171 |
|
// Using congruence only the |
172 |
|
// |
173 |
|
// ------------------ MACRO_SR_PRED_INTRO |
174 |
|
// (not (not t)) = t |
175 |
|
// |
176 |
|
// steps are added, which, since double negation is eliminated in a |
177 |
|
// pre-rewrite in the Boolean rewriter, will always hold under the |
178 |
|
// standard rewriter. |
179 |
94172 |
Node congEq = oldn.eqNode(n); |
180 |
94172 |
addStep(PfRule::CONG, |
181 |
|
childrenEqs, |
182 |
|
{ProofRuleChecker::mkKindNode(kind::OR)}, |
183 |
47086 |
congEq); |
184 |
|
// add an equality resolution step to derive normalize clause |
185 |
47086 |
addStep(PfRule::EQ_RESOLVE, {oldn, congEq}, {}, n); |
186 |
|
} |
187 |
377534 |
children.clear(); |
188 |
|
// remove duplicates while keeping the order of children |
189 |
755068 |
std::unordered_set<TNode> clauseSet; |
190 |
377534 |
unsigned size = n.getNumChildren(); |
191 |
1662452 |
for (unsigned i = 0; i < size; ++i) |
192 |
|
{ |
193 |
1284918 |
if (clauseSet.count(n[i])) |
194 |
|
{ |
195 |
603 |
continue; |
196 |
|
} |
197 |
1284315 |
children.push_back(n[i]); |
198 |
1284315 |
clauseSet.insert(n[i]); |
199 |
|
} |
200 |
|
// if factoring changed |
201 |
377534 |
if (children.size() < size) |
202 |
|
{ |
203 |
474 |
Node factored = children.empty() |
204 |
|
? nm->mkConst<bool>(false) |
205 |
474 |
: children.size() == 1 ? children[0] |
206 |
1422 |
: nm->mkNode(kind::OR, children); |
207 |
|
// don't overwrite what already has a proof step to avoid cycles |
208 |
474 |
addStep(PfRule::FACTORING, {n}, {}, factored); |
209 |
474 |
n = factored; |
210 |
|
} |
211 |
|
// nothing to order |
212 |
377534 |
if (children.size() < 2) |
213 |
|
{ |
214 |
|
return n; |
215 |
|
} |
216 |
|
// order |
217 |
377534 |
std::sort(children.begin(), children.end()); |
218 |
755068 |
Node ordered = nm->mkNode(kind::OR, children); |
219 |
|
// if ordering changed |
220 |
377534 |
if (ordered != n) |
221 |
|
{ |
222 |
|
// don't overwrite what already has a proof step to avoid cycles |
223 |
302551 |
addStep(PfRule::REORDERING, {n}, {ordered}, ordered); |
224 |
|
} |
225 |
377534 |
return ordered; |
226 |
|
} |
227 |
|
|
228 |
|
Node TheoryProofStepBuffer::elimDoubleNegLit(Node n) |
229 |
|
{ |
230 |
|
// eliminate double neg |
231 |
|
if (n.getKind() == kind::NOT && n[0].getKind() == kind::NOT) |
232 |
|
{ |
233 |
|
addStep(PfRule::NOT_NOT_ELIM, {n}, {}, n[0][0]); |
234 |
|
return n[0][0]; |
235 |
|
} |
236 |
|
return n; |
237 |
|
} |
238 |
|
|
239 |
|
} // namespace theory |
240 |
28191 |
} // namespace cvc5 |