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 equality proof checker. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/uf/proof_checker.h" |
17 |
|
|
18 |
|
#include "theory/uf/theory_uf_rewriter.h" |
19 |
|
|
20 |
|
using namespace cvc5::kind; |
21 |
|
|
22 |
|
namespace cvc5 { |
23 |
|
namespace theory { |
24 |
|
namespace uf { |
25 |
|
|
26 |
143 |
void UfProofRuleChecker::registerTo(ProofChecker* pc) |
27 |
|
{ |
28 |
|
// add checkers |
29 |
143 |
pc->registerChecker(PfRule::REFL, this); |
30 |
143 |
pc->registerChecker(PfRule::SYMM, this); |
31 |
143 |
pc->registerChecker(PfRule::TRANS, this); |
32 |
143 |
pc->registerChecker(PfRule::CONG, this); |
33 |
143 |
pc->registerChecker(PfRule::TRUE_INTRO, this); |
34 |
143 |
pc->registerChecker(PfRule::TRUE_ELIM, this); |
35 |
143 |
pc->registerChecker(PfRule::FALSE_INTRO, this); |
36 |
143 |
pc->registerChecker(PfRule::FALSE_ELIM, this); |
37 |
143 |
pc->registerChecker(PfRule::HO_CONG, this); |
38 |
143 |
pc->registerChecker(PfRule::HO_APP_ENCODE, this); |
39 |
143 |
} |
40 |
|
|
41 |
12114 |
Node UfProofRuleChecker::checkInternal(PfRule id, |
42 |
|
const std::vector<Node>& children, |
43 |
|
const std::vector<Node>& args) |
44 |
|
{ |
45 |
|
// compute what was proven |
46 |
12114 |
if (id == PfRule::REFL) |
47 |
|
{ |
48 |
300 |
Assert(children.empty()); |
49 |
300 |
Assert(args.size() == 1); |
50 |
300 |
return args[0].eqNode(args[0]); |
51 |
|
} |
52 |
11814 |
else if (id == PfRule::SYMM) |
53 |
|
{ |
54 |
10957 |
Assert(children.size() == 1); |
55 |
10957 |
Assert(args.empty()); |
56 |
10957 |
bool polarity = children[0].getKind() != NOT; |
57 |
21914 |
Node eqp = polarity ? children[0] : children[0][0]; |
58 |
10957 |
if (eqp.getKind() != EQUAL) |
59 |
|
{ |
60 |
|
// not a (dis)equality |
61 |
|
return Node::null(); |
62 |
|
} |
63 |
21914 |
Node conc = eqp[1].eqNode(eqp[0]); |
64 |
10957 |
return polarity ? conc : conc.notNode(); |
65 |
|
} |
66 |
857 |
else if (id == PfRule::TRANS) |
67 |
|
{ |
68 |
103 |
Assert(children.size() > 0); |
69 |
103 |
Assert(args.empty()); |
70 |
206 |
Node first; |
71 |
206 |
Node curr; |
72 |
310 |
for (size_t i = 0, nchild = children.size(); i < nchild; i++) |
73 |
|
{ |
74 |
414 |
Node eqp = children[i]; |
75 |
207 |
if (eqp.getKind() != EQUAL) |
76 |
|
{ |
77 |
|
return Node::null(); |
78 |
|
} |
79 |
207 |
if (first.isNull()) |
80 |
|
{ |
81 |
103 |
first = eqp[0]; |
82 |
|
} |
83 |
104 |
else if (eqp[0] != curr) |
84 |
|
{ |
85 |
|
return Node::null(); |
86 |
|
} |
87 |
207 |
curr = eqp[1]; |
88 |
|
} |
89 |
103 |
return first.eqNode(curr); |
90 |
|
} |
91 |
754 |
else if (id == PfRule::CONG) |
92 |
|
{ |
93 |
218 |
Assert(children.size() > 0); |
94 |
218 |
Assert(args.size() >= 1 && args.size() <= 2); |
95 |
|
// We do congruence over builtin kinds using operatorToKind |
96 |
436 |
std::vector<Node> lchildren; |
97 |
436 |
std::vector<Node> rchildren; |
98 |
|
// get the kind encoded as args[0] |
99 |
|
Kind k; |
100 |
218 |
if (!getKind(args[0], k)) |
101 |
|
{ |
102 |
|
return Node::null(); |
103 |
|
} |
104 |
218 |
if (k == kind::UNDEFINED_KIND) |
105 |
|
{ |
106 |
|
return Node::null(); |
107 |
|
} |
108 |
436 |
Trace("uf-pfcheck") << "congruence for " << args[0] << " uses kind " << k |
109 |
218 |
<< ", metakind=" << kind::metaKindOf(k) << std::endl; |
110 |
218 |
if (kind::metaKindOf(k) == kind::metakind::PARAMETERIZED) |
111 |
|
{ |
112 |
|
if (args.size() <= 1) |
113 |
|
{ |
114 |
|
return Node::null(); |
115 |
|
} |
116 |
|
// parameterized kinds require the operator |
117 |
|
lchildren.push_back(args[1]); |
118 |
|
rchildren.push_back(args[1]); |
119 |
|
} |
120 |
218 |
else if (args.size() > 1) |
121 |
|
{ |
122 |
|
return Node::null(); |
123 |
|
} |
124 |
960 |
for (size_t i = 0, nchild = children.size(); i < nchild; i++) |
125 |
|
{ |
126 |
1484 |
Node eqp = children[i]; |
127 |
742 |
if (eqp.getKind() != EQUAL) |
128 |
|
{ |
129 |
|
return Node::null(); |
130 |
|
} |
131 |
742 |
lchildren.push_back(eqp[0]); |
132 |
742 |
rchildren.push_back(eqp[1]); |
133 |
|
} |
134 |
218 |
NodeManager* nm = NodeManager::currentNM(); |
135 |
436 |
Node l = nm->mkNode(k, lchildren); |
136 |
436 |
Node r = nm->mkNode(k, rchildren); |
137 |
218 |
return l.eqNode(r); |
138 |
|
} |
139 |
536 |
else if (id == PfRule::TRUE_INTRO) |
140 |
|
{ |
141 |
517 |
Assert(children.size() == 1); |
142 |
517 |
Assert(args.empty()); |
143 |
1034 |
Node trueNode = NodeManager::currentNM()->mkConst(true); |
144 |
517 |
return children[0].eqNode(trueNode); |
145 |
|
} |
146 |
19 |
else if (id == PfRule::TRUE_ELIM) |
147 |
|
{ |
148 |
17 |
Assert(children.size() == 1); |
149 |
17 |
Assert(args.empty()); |
150 |
51 |
if (children[0].getKind() != EQUAL || !children[0][1].isConst() |
151 |
51 |
|| !children[0][1].getConst<bool>()) |
152 |
|
{ |
153 |
|
return Node::null(); |
154 |
|
} |
155 |
17 |
return children[0][0]; |
156 |
|
} |
157 |
2 |
else if (id == PfRule::FALSE_INTRO) |
158 |
|
{ |
159 |
2 |
Assert(children.size() == 1); |
160 |
2 |
Assert(args.empty()); |
161 |
2 |
if (children[0].getKind() != kind::NOT) |
162 |
|
{ |
163 |
|
return Node::null(); |
164 |
|
} |
165 |
4 |
Node falseNode = NodeManager::currentNM()->mkConst(false); |
166 |
2 |
return children[0][0].eqNode(falseNode); |
167 |
|
} |
168 |
|
else if (id == PfRule::FALSE_ELIM) |
169 |
|
{ |
170 |
|
Assert(children.size() == 1); |
171 |
|
Assert(args.empty()); |
172 |
|
if (children[0].getKind() != EQUAL || !children[0][1].isConst() |
173 |
|
|| children[0][1].getConst<bool>()) |
174 |
|
{ |
175 |
|
return Node::null(); |
176 |
|
} |
177 |
|
return children[0][0].notNode(); |
178 |
|
} |
179 |
|
if (id == PfRule::HO_CONG) |
180 |
|
{ |
181 |
|
Assert(children.size() > 0); |
182 |
|
std::vector<Node> lchildren; |
183 |
|
std::vector<Node> rchildren; |
184 |
|
for (size_t i = 0, nchild = children.size(); i < nchild; ++i) |
185 |
|
{ |
186 |
|
Node eqp = children[i]; |
187 |
|
if (eqp.getKind() != EQUAL) |
188 |
|
{ |
189 |
|
return Node::null(); |
190 |
|
} |
191 |
|
lchildren.push_back(eqp[0]); |
192 |
|
rchildren.push_back(eqp[1]); |
193 |
|
} |
194 |
|
NodeManager* nm = NodeManager::currentNM(); |
195 |
|
Node l = nm->mkNode(kind::APPLY_UF, lchildren); |
196 |
|
Node r = nm->mkNode(kind::APPLY_UF, rchildren); |
197 |
|
return l.eqNode(r); |
198 |
|
} |
199 |
|
else if (id == PfRule::HO_APP_ENCODE) |
200 |
|
{ |
201 |
|
Assert(args.size() == 1); |
202 |
|
Node ret = TheoryUfRewriter::getHoApplyForApplyUf(args[0]); |
203 |
|
return args[0].eqNode(ret); |
204 |
|
} |
205 |
|
// no rule |
206 |
|
return Node::null(); |
207 |
|
} |
208 |
|
|
209 |
|
} // namespace uf |
210 |
|
} // namespace theory |
211 |
22755 |
} // namespace cvc5 |