1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds |
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 entailment check class. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/entailment_check.h" |
17 |
|
|
18 |
|
#include "theory/quantifiers/quantifiers_state.h" |
19 |
|
#include "theory/quantifiers/term_database.h" |
20 |
|
|
21 |
|
using namespace cvc5::kind; |
22 |
|
using namespace cvc5::context; |
23 |
|
|
24 |
|
namespace cvc5 { |
25 |
|
namespace theory { |
26 |
|
namespace quantifiers { |
27 |
|
|
28 |
15273 |
EntailmentCheck::EntailmentCheck(Env& env, QuantifiersState& qs, TermDb& tdb) |
29 |
15273 |
: EnvObj(env), d_qstate(qs), d_tdb(tdb) |
30 |
|
{ |
31 |
15273 |
d_true = NodeManager::currentNM()->mkConst(true); |
32 |
15273 |
d_false = NodeManager::currentNM()->mkConst(false); |
33 |
15273 |
} |
34 |
|
|
35 |
30536 |
EntailmentCheck::~EntailmentCheck() {} |
36 |
|
|
37 |
1517519 |
Node EntailmentCheck::evaluateTerm2(TNode n, |
38 |
|
std::map<TNode, Node>& visited, |
39 |
|
std::map<TNode, TNode>& subs, |
40 |
|
bool subsRep, |
41 |
|
bool useEntailmentTests, |
42 |
|
bool reqHasTerm) |
43 |
|
{ |
44 |
1517519 |
std::map<TNode, Node>::iterator itv = visited.find(n); |
45 |
1517519 |
if (itv != visited.end()) |
46 |
|
{ |
47 |
307645 |
return itv->second; |
48 |
|
} |
49 |
1209874 |
Trace("term-db-eval") << "evaluate term : " << n << std::endl; |
50 |
2419748 |
Node ret = n; |
51 |
1209874 |
Kind k = n.getKind(); |
52 |
1209874 |
if (k == FORALL) |
53 |
|
{ |
54 |
|
// do nothing |
55 |
|
} |
56 |
1209749 |
else if (k == BOUND_VARIABLE) |
57 |
|
{ |
58 |
303649 |
std::map<TNode, TNode>::iterator it = subs.find(n); |
59 |
303649 |
if (it != subs.end()) |
60 |
|
{ |
61 |
301288 |
if (!subsRep) |
62 |
|
{ |
63 |
301288 |
ret = d_qstate.getRepresentative(it->second); |
64 |
|
} |
65 |
|
else |
66 |
|
{ |
67 |
|
ret = it->second; |
68 |
|
} |
69 |
|
} |
70 |
|
} |
71 |
906100 |
else if (d_qstate.hasTerm(n)) |
72 |
|
{ |
73 |
112915 |
Trace("term-db-eval") << "...exists in ee, return rep" << std::endl; |
74 |
112915 |
ret = d_qstate.getRepresentative(n); |
75 |
112915 |
reqHasTerm = false; |
76 |
|
} |
77 |
793185 |
else if (n.hasOperator()) |
78 |
|
{ |
79 |
1585190 |
std::vector<TNode> args; |
80 |
792595 |
bool ret_set = false; |
81 |
1955905 |
for (unsigned i = 0, nchild = n.getNumChildren(); i < nchild; i++) |
82 |
|
{ |
83 |
2763616 |
TNode c = evaluateTerm2( |
84 |
2545118 |
n[i], visited, subs, subsRep, useEntailmentTests, reqHasTerm); |
85 |
1381808 |
if (c.isNull()) |
86 |
|
{ |
87 |
177292 |
ret = Node::null(); |
88 |
177292 |
ret_set = true; |
89 |
177292 |
break; |
90 |
|
} |
91 |
1204516 |
else if (c == d_true || c == d_false) |
92 |
|
{ |
93 |
|
// short-circuiting |
94 |
223423 |
if ((k == AND && c == d_false) || (k == OR && c == d_true)) |
95 |
|
{ |
96 |
35954 |
ret = c; |
97 |
35954 |
ret_set = true; |
98 |
35954 |
reqHasTerm = false; |
99 |
35954 |
break; |
100 |
|
} |
101 |
187469 |
else if (k == ITE && i == 0) |
102 |
|
{ |
103 |
5252 |
ret = evaluateTerm2(n[c == d_true ? 1 : 2], |
104 |
|
visited, |
105 |
|
subs, |
106 |
|
subsRep, |
107 |
|
useEntailmentTests, |
108 |
|
reqHasTerm); |
109 |
5252 |
ret_set = true; |
110 |
5252 |
reqHasTerm = false; |
111 |
5252 |
break; |
112 |
|
} |
113 |
|
} |
114 |
1163310 |
Trace("term-db-eval") << " child " << i << " : " << c << std::endl; |
115 |
1163310 |
args.push_back(c); |
116 |
|
} |
117 |
792595 |
if (!ret_set) |
118 |
|
{ |
119 |
|
// get the (indexed) operator of n, if it exists |
120 |
1148194 |
TNode f = d_tdb.getMatchOperator(n); |
121 |
|
// if it is an indexed term, return the congruent term |
122 |
574097 |
if (!f.isNull()) |
123 |
|
{ |
124 |
|
// if f is congruent to a term indexed by this class |
125 |
737068 |
TNode nn = d_tdb.getCongruentTerm(f, args); |
126 |
737068 |
Trace("term-db-eval") << " got congruent term " << nn |
127 |
368534 |
<< " from DB for " << n << std::endl; |
128 |
368534 |
if (!nn.isNull()) |
129 |
|
{ |
130 |
295261 |
ret = d_qstate.getRepresentative(nn); |
131 |
295261 |
Trace("term-db-eval") << "return rep" << std::endl; |
132 |
295261 |
ret_set = true; |
133 |
295261 |
reqHasTerm = false; |
134 |
295261 |
Assert(!ret.isNull()); |
135 |
|
} |
136 |
|
} |
137 |
574097 |
if (!ret_set) |
138 |
|
{ |
139 |
278836 |
Trace("term-db-eval") << "return rewrite" << std::endl; |
140 |
|
// a theory symbol or a new UF term |
141 |
278836 |
if (n.getMetaKind() == metakind::PARAMETERIZED) |
142 |
|
{ |
143 |
73140 |
args.insert(args.begin(), n.getOperator()); |
144 |
|
} |
145 |
278836 |
ret = NodeManager::currentNM()->mkNode(n.getKind(), args); |
146 |
278836 |
ret = rewrite(ret); |
147 |
278836 |
if (ret.getKind() == EQUAL) |
148 |
|
{ |
149 |
32201 |
if (d_qstate.areDisequal(ret[0], ret[1])) |
150 |
|
{ |
151 |
15925 |
ret = d_false; |
152 |
|
} |
153 |
|
} |
154 |
278836 |
if (useEntailmentTests) |
155 |
|
{ |
156 |
822 |
if (ret.getKind() == EQUAL || ret.getKind() == GEQ) |
157 |
|
{ |
158 |
22 |
Valuation& val = d_qstate.getValuation(); |
159 |
62 |
for (unsigned j = 0; j < 2; j++) |
160 |
|
{ |
161 |
|
std::pair<bool, Node> et = val.entailmentCheck( |
162 |
|
options::TheoryOfMode::THEORY_OF_TYPE_BASED, |
163 |
84 |
j == 0 ? ret : ret.negate()); |
164 |
44 |
if (et.first) |
165 |
|
{ |
166 |
4 |
ret = j == 0 ? d_true : d_false; |
167 |
4 |
break; |
168 |
|
} |
169 |
|
} |
170 |
|
} |
171 |
|
} |
172 |
|
} |
173 |
|
} |
174 |
|
} |
175 |
|
// must have the term |
176 |
1209874 |
if (reqHasTerm && !ret.isNull()) |
177 |
|
{ |
178 |
578384 |
Kind rk = ret.getKind(); |
179 |
578384 |
if (rk != OR && rk != AND && rk != EQUAL && rk != ITE && rk != NOT |
180 |
559324 |
&& rk != FORALL) |
181 |
|
{ |
182 |
559091 |
if (!d_qstate.hasTerm(ret)) |
183 |
|
{ |
184 |
71197 |
ret = Node::null(); |
185 |
|
} |
186 |
|
} |
187 |
|
} |
188 |
2419748 |
Trace("term-db-eval") << "evaluated term : " << n << ", got : " << ret |
189 |
1209874 |
<< ", reqHasTerm = " << reqHasTerm << std::endl; |
190 |
1209874 |
visited[n] = ret; |
191 |
1209874 |
return ret; |
192 |
|
} |
193 |
|
|
194 |
9793465 |
TNode EntailmentCheck::getEntailedTerm2(TNode n, |
195 |
|
std::map<TNode, TNode>& subs, |
196 |
|
bool subsRep) |
197 |
|
{ |
198 |
9793465 |
Trace("term-db-entail") << "get entailed term : " << n << std::endl; |
199 |
9793465 |
if (d_qstate.hasTerm(n)) |
200 |
|
{ |
201 |
3162031 |
Trace("term-db-entail") << "...exists in ee, return rep " << std::endl; |
202 |
3162031 |
return n; |
203 |
|
} |
204 |
6631434 |
else if (n.getKind() == BOUND_VARIABLE) |
205 |
|
{ |
206 |
3868767 |
std::map<TNode, TNode>::iterator it = subs.find(n); |
207 |
3868767 |
if (it != subs.end()) |
208 |
|
{ |
209 |
5886850 |
Trace("term-db-entail") |
210 |
2943425 |
<< "...substitution is : " << it->second << std::endl; |
211 |
2943425 |
if (subsRep) |
212 |
|
{ |
213 |
348105 |
Assert(d_qstate.hasTerm(it->second)); |
214 |
348105 |
Assert(d_qstate.getRepresentative(it->second) == it->second); |
215 |
3291530 |
return it->second; |
216 |
|
} |
217 |
2595320 |
return getEntailedTerm2(it->second, subs, subsRep); |
218 |
|
} |
219 |
|
} |
220 |
2762667 |
else if (n.getKind() == ITE) |
221 |
|
{ |
222 |
41500 |
for (uint32_t i = 0; i < 2; i++) |
223 |
|
{ |
224 |
36142 |
if (isEntailed2(n[0], subs, subsRep, i == 0)) |
225 |
|
{ |
226 |
14635 |
return getEntailedTerm2(n[i == 0 ? 1 : 2], subs, subsRep); |
227 |
|
} |
228 |
|
} |
229 |
|
} |
230 |
|
else |
231 |
|
{ |
232 |
2742674 |
if (n.hasOperator()) |
233 |
|
{ |
234 |
2748173 |
TNode f = d_tdb.getMatchOperator(n); |
235 |
2735155 |
if (!f.isNull()) |
236 |
|
{ |
237 |
5444274 |
std::vector<TNode> args; |
238 |
6204221 |
for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; i++) |
239 |
|
{ |
240 |
8527844 |
TNode c = getEntailedTerm2(n[i], subs, subsRep); |
241 |
5045760 |
if (c.isNull()) |
242 |
|
{ |
243 |
1563676 |
return TNode::null(); |
244 |
|
} |
245 |
3482084 |
c = d_qstate.getRepresentative(c); |
246 |
3482084 |
Trace("term-db-entail") << " child " << i << " : " << c << std::endl; |
247 |
3482084 |
args.push_back(c); |
248 |
|
} |
249 |
2316922 |
TNode nn = d_tdb.getCongruentTerm(f, args); |
250 |
2316922 |
Trace("term-db-entail") |
251 |
1158461 |
<< " got congruent term " << nn << " for " << n << std::endl; |
252 |
1158461 |
return nn; |
253 |
|
} |
254 |
|
} |
255 |
|
} |
256 |
951237 |
return TNode::null(); |
257 |
|
} |
258 |
|
|
259 |
128841 |
Node EntailmentCheck::evaluateTerm(TNode n, |
260 |
|
std::map<TNode, TNode>& subs, |
261 |
|
bool subsRep, |
262 |
|
bool useEntailmentTests, |
263 |
|
bool reqHasTerm) |
264 |
|
{ |
265 |
257682 |
std::map<TNode, Node> visited; |
266 |
|
return evaluateTerm2( |
267 |
257682 |
n, visited, subs, subsRep, useEntailmentTests, reqHasTerm); |
268 |
|
} |
269 |
|
|
270 |
1618 |
Node EntailmentCheck::evaluateTerm(TNode n, |
271 |
|
bool useEntailmentTests, |
272 |
|
bool reqHasTerm) |
273 |
|
{ |
274 |
3236 |
std::map<TNode, Node> visited; |
275 |
3236 |
std::map<TNode, TNode> subs; |
276 |
3236 |
return evaluateTerm2(n, visited, subs, false, useEntailmentTests, reqHasTerm); |
277 |
|
} |
278 |
|
|
279 |
860201 |
TNode EntailmentCheck::getEntailedTerm(TNode n, |
280 |
|
std::map<TNode, TNode>& subs, |
281 |
|
bool subsRep) |
282 |
|
{ |
283 |
860201 |
return getEntailedTerm2(n, subs, subsRep); |
284 |
|
} |
285 |
|
|
286 |
86651 |
TNode EntailmentCheck::getEntailedTerm(TNode n) |
287 |
|
{ |
288 |
173302 |
std::map<TNode, TNode> subs; |
289 |
173302 |
return getEntailedTerm2(n, subs, false); |
290 |
|
} |
291 |
|
|
292 |
1859179 |
bool EntailmentCheck::isEntailed2(TNode n, |
293 |
|
std::map<TNode, TNode>& subs, |
294 |
|
bool subsRep, |
295 |
|
bool pol) |
296 |
|
{ |
297 |
3718358 |
Trace("term-db-entail") << "Check entailed : " << n << ", pol = " << pol |
298 |
1859179 |
<< std::endl; |
299 |
1859179 |
Assert(n.getType().isBoolean()); |
300 |
1859179 |
if (n.getKind() == EQUAL && !n[0].getType().isBoolean()) |
301 |
|
{ |
302 |
461465 |
TNode n1 = getEntailedTerm2(n[0], subs, subsRep); |
303 |
385854 |
if (!n1.isNull()) |
304 |
|
{ |
305 |
383967 |
TNode n2 = getEntailedTerm2(n[1], subs, subsRep); |
306 |
347105 |
if (!n2.isNull()) |
307 |
|
{ |
308 |
310243 |
if (n1 == n2) |
309 |
|
{ |
310 |
29417 |
return pol; |
311 |
|
} |
312 |
|
else |
313 |
|
{ |
314 |
280826 |
Assert(d_qstate.hasTerm(n1)); |
315 |
280826 |
Assert(d_qstate.hasTerm(n2)); |
316 |
280826 |
if (pol) |
317 |
|
{ |
318 |
142940 |
return d_qstate.areEqual(n1, n2); |
319 |
|
} |
320 |
|
else |
321 |
|
{ |
322 |
137886 |
return d_qstate.areDisequal(n1, n2); |
323 |
|
} |
324 |
|
} |
325 |
|
} |
326 |
|
} |
327 |
|
} |
328 |
1473325 |
else if (n.getKind() == NOT) |
329 |
|
{ |
330 |
492818 |
return isEntailed2(n[0], subs, subsRep, !pol); |
331 |
|
} |
332 |
980507 |
else if (n.getKind() == OR || n.getKind() == AND) |
333 |
|
{ |
334 |
239366 |
bool simPol = (pol && n.getKind() == OR) || (!pol && n.getKind() == AND); |
335 |
829402 |
for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; i++) |
336 |
|
{ |
337 |
745093 |
if (isEntailed2(n[i], subs, subsRep, pol)) |
338 |
|
{ |
339 |
187632 |
if (simPol) |
340 |
|
{ |
341 |
71569 |
return true; |
342 |
|
} |
343 |
|
} |
344 |
|
else |
345 |
|
{ |
346 |
557461 |
if (!simPol) |
347 |
|
{ |
348 |
83488 |
return false; |
349 |
|
} |
350 |
|
} |
351 |
|
} |
352 |
84309 |
return !simPol; |
353 |
|
// Boolean equality here |
354 |
|
} |
355 |
741141 |
else if (n.getKind() == EQUAL || n.getKind() == ITE) |
356 |
|
{ |
357 |
247957 |
for (size_t i = 0; i < 2; i++) |
358 |
|
{ |
359 |
186054 |
if (isEntailed2(n[0], subs, subsRep, i == 0)) |
360 |
|
{ |
361 |
41423 |
size_t ch = (n.getKind() == EQUAL || i == 0) ? 1 : 2; |
362 |
41423 |
bool reqPol = (n.getKind() == ITE || i == 0) ? pol : !pol; |
363 |
41423 |
return isEntailed2(n[ch], subs, subsRep, reqPol); |
364 |
|
} |
365 |
|
} |
366 |
|
} |
367 |
637815 |
else if (n.getKind() == APPLY_UF) |
368 |
|
{ |
369 |
670253 |
TNode n1 = getEntailedTerm2(n, subs, subsRep); |
370 |
457939 |
if (!n1.isNull()) |
371 |
|
{ |
372 |
245625 |
Assert(d_qstate.hasTerm(n1)); |
373 |
245625 |
if (n1 == d_true) |
374 |
|
{ |
375 |
|
return pol; |
376 |
|
} |
377 |
245625 |
else if (n1 == d_false) |
378 |
|
{ |
379 |
|
return !pol; |
380 |
|
} |
381 |
|
else |
382 |
|
{ |
383 |
245625 |
return d_qstate.getRepresentative(n1) == (pol ? d_true : d_false); |
384 |
|
} |
385 |
|
} |
386 |
|
} |
387 |
179876 |
else if (n.getKind() == FORALL && !pol) |
388 |
|
{ |
389 |
6282 |
return isEntailed2(n[1], subs, subsRep, pol); |
390 |
|
} |
391 |
523422 |
return false; |
392 |
|
} |
393 |
|
|
394 |
2232 |
bool EntailmentCheck::isEntailed(TNode n, bool pol) |
395 |
|
{ |
396 |
4464 |
std::map<TNode, TNode> subs; |
397 |
4464 |
return isEntailed2(n, subs, false, pol); |
398 |
|
} |
399 |
|
|
400 |
349135 |
bool EntailmentCheck::isEntailed(TNode n, |
401 |
|
std::map<TNode, TNode>& subs, |
402 |
|
bool subsRep, |
403 |
|
bool pol) |
404 |
|
{ |
405 |
349135 |
return isEntailed2(n, subs, subsRep, pol); |
406 |
|
} |
407 |
|
|
408 |
|
} // namespace quantifiers |
409 |
|
} // namespace theory |
410 |
31137 |
} // namespace cvc5 |