1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Mudathir Mohamed, Kshitij Bansal |
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 |
|
* Sets theory implementation. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/sets/theory_sets_private.h" |
17 |
|
|
18 |
|
#include <algorithm> |
19 |
|
#include <climits> |
20 |
|
|
21 |
|
#include "expr/emptyset.h" |
22 |
|
#include "expr/node_algorithm.h" |
23 |
|
#include "expr/skolem_manager.h" |
24 |
|
#include "options/sets_options.h" |
25 |
|
#include "smt/smt_statistics_registry.h" |
26 |
|
#include "theory/sets/normal_form.h" |
27 |
|
#include "theory/sets/theory_sets.h" |
28 |
|
#include "theory/theory_model.h" |
29 |
|
#include "util/rational.h" |
30 |
|
#include "util/result.h" |
31 |
|
|
32 |
|
using namespace std; |
33 |
|
using namespace cvc5::kind; |
34 |
|
|
35 |
|
namespace cvc5 { |
36 |
|
namespace theory { |
37 |
|
namespace sets { |
38 |
|
|
39 |
9917 |
TheorySetsPrivate::TheorySetsPrivate(Env& env, |
40 |
|
TheorySets& external, |
41 |
|
SolverState& state, |
42 |
|
InferenceManager& im, |
43 |
|
SkolemCache& skc, |
44 |
9917 |
ProofNodeManager* pnm) |
45 |
|
: EnvObj(env), |
46 |
|
d_deq(context()), |
47 |
9917 |
d_termProcessed(userContext()), |
48 |
|
d_fullCheckIncomplete(false), |
49 |
|
d_fullCheckIncompleteId(IncompleteId::UNKNOWN), |
50 |
|
d_external(external), |
51 |
|
d_state(state), |
52 |
|
d_im(im), |
53 |
|
d_skCache(skc), |
54 |
|
d_treg(d_env, state, im, skc, pnm), |
55 |
9917 |
d_rels(new TheorySetsRels(d_env, state, im, skc, d_treg)), |
56 |
9917 |
d_cardSolver(new CardinalityExtension(d_env, state, im, d_treg)), |
57 |
|
d_rels_enabled(false), |
58 |
39668 |
d_card_enabled(false) |
59 |
|
{ |
60 |
9917 |
d_true = NodeManager::currentNM()->mkConst(true); |
61 |
9917 |
d_false = NodeManager::currentNM()->mkConst(false); |
62 |
9917 |
d_zero = NodeManager::currentNM()->mkConst(Rational(0)); |
63 |
9917 |
} |
64 |
|
|
65 |
29742 |
TheorySetsPrivate::~TheorySetsPrivate() |
66 |
|
{ |
67 |
14797 |
for (std::pair<const Node, EqcInfo*>& current_pair : d_eqc_info) |
68 |
|
{ |
69 |
4883 |
delete current_pair.second; |
70 |
|
} |
71 |
19828 |
} |
72 |
|
|
73 |
9917 |
void TheorySetsPrivate::finishInit() |
74 |
|
{ |
75 |
9917 |
d_equalityEngine = d_external.getEqualityEngine(); |
76 |
9917 |
Assert(d_equalityEngine != nullptr); |
77 |
9917 |
} |
78 |
|
|
79 |
79641 |
void TheorySetsPrivate::eqNotifyNewClass(TNode t) |
80 |
|
{ |
81 |
79641 |
if (t.getKind() == kind::SINGLETON || t.getKind() == kind::EMPTYSET) |
82 |
|
{ |
83 |
3603 |
EqcInfo* e = getOrMakeEqcInfo(t, true); |
84 |
3603 |
e->d_singleton = t; |
85 |
|
} |
86 |
79641 |
} |
87 |
|
|
88 |
246300 |
void TheorySetsPrivate::eqNotifyMerge(TNode t1, TNode t2) |
89 |
|
{ |
90 |
246300 |
if (!d_state.isInConflict() && t1.getType().isSet()) |
91 |
|
{ |
92 |
56082 |
Trace("sets-prop-debug") |
93 |
28041 |
<< "Merge " << t1 << " and " << t2 << "..." << std::endl; |
94 |
55907 |
Node s1, s2; |
95 |
28041 |
EqcInfo* e2 = getOrMakeEqcInfo(t2); |
96 |
28041 |
if (e2) |
97 |
|
{ |
98 |
17419 |
s2 = e2->d_singleton; |
99 |
17419 |
EqcInfo* e1 = getOrMakeEqcInfo(t1); |
100 |
17419 |
Trace("sets-prop-debug") << "Merging singletons..." << std::endl; |
101 |
17419 |
if (e1) |
102 |
|
{ |
103 |
17300 |
s1 = e1->d_singleton; |
104 |
17300 |
if (!s1.isNull() && !s2.isNull()) |
105 |
|
{ |
106 |
13794 |
if (s1.getKind() == s2.getKind()) |
107 |
|
{ |
108 |
27448 |
Trace("sets-prop") << "Propagate eq inference : " << s1 |
109 |
13724 |
<< " == " << s2 << std::endl; |
110 |
|
// infer equality between elements of singleton |
111 |
27448 |
Node exp = s1.eqNode(s2); |
112 |
27448 |
Node eq = s1[0].eqNode(s2[0]); |
113 |
13724 |
d_im.assertSetsFact(eq, true, InferenceId::SETS_SINGLETON_EQ, exp); |
114 |
|
} |
115 |
|
else |
116 |
|
{ |
117 |
|
// singleton equal to emptyset, conflict |
118 |
140 |
Trace("sets-prop") |
119 |
70 |
<< "Propagate conflict : " << s1 << " == " << s2 << std::endl; |
120 |
140 |
Node eqs = s1.eqNode(s2); |
121 |
70 |
d_im.conflict(eqs, InferenceId::SETS_EQ_CONFLICT); |
122 |
70 |
return; |
123 |
|
} |
124 |
|
} |
125 |
|
} |
126 |
|
else |
127 |
|
{ |
128 |
|
// copy information |
129 |
119 |
e1 = getOrMakeEqcInfo(t1, true); |
130 |
119 |
e1->d_singleton.set(e2->d_singleton); |
131 |
|
} |
132 |
|
} |
133 |
|
// merge membership list |
134 |
27971 |
Trace("sets-prop-debug") << "Copying membership list..." << std::endl; |
135 |
|
// if s1 has a singleton or empty set and s2 does not, we may have new |
136 |
|
// inferences to process. |
137 |
55837 |
Node checkSingleton = s2.isNull() ? s1 : Node::null(); |
138 |
55837 |
std::vector<Node> facts; |
139 |
|
// merge the membership list in the state, which may produce facts or |
140 |
|
// conflicts to propagate |
141 |
27971 |
if (!d_state.merge(t1, t2, facts, checkSingleton)) |
142 |
|
{ |
143 |
|
// conflict case |
144 |
105 |
Assert(facts.size() == 1); |
145 |
210 |
Trace("sets-prop") << "Propagate eq-mem conflict : " << facts[0] |
146 |
105 |
<< std::endl; |
147 |
105 |
d_im.conflict(facts[0], InferenceId::SETS_EQ_MEM_CONFLICT); |
148 |
105 |
return; |
149 |
|
} |
150 |
27995 |
for (const Node& f : facts) |
151 |
|
{ |
152 |
129 |
Assert(f.getKind() == kind::IMPLIES); |
153 |
258 |
Trace("sets-prop") << "Propagate eq-mem eq inference : " << f[0] << " => " |
154 |
129 |
<< f[1] << std::endl; |
155 |
129 |
d_im.assertSetsFact(f[1], true, InferenceId::SETS_EQ_MEM, f[0]); |
156 |
|
} |
157 |
|
} |
158 |
|
} |
159 |
|
|
160 |
33404 |
void TheorySetsPrivate::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) |
161 |
|
{ |
162 |
33404 |
if (t1.getType().isSet()) |
163 |
|
{ |
164 |
20726 |
Node eq = t1.eqNode(t2); |
165 |
10363 |
if (d_deq.find(eq) == d_deq.end()) |
166 |
|
{ |
167 |
10363 |
d_deq[eq] = true; |
168 |
|
} |
169 |
|
} |
170 |
33404 |
} |
171 |
|
|
172 |
4883 |
TheorySetsPrivate::EqcInfo::EqcInfo(context::Context* c) : d_singleton(c) {} |
173 |
|
|
174 |
112996 |
TheorySetsPrivate::EqcInfo* TheorySetsPrivate::getOrMakeEqcInfo(TNode n, |
175 |
|
bool doMake) |
176 |
|
{ |
177 |
112996 |
std::map<Node, EqcInfo*>::iterator eqc_i = d_eqc_info.find(n); |
178 |
112996 |
if (eqc_i == d_eqc_info.end()) |
179 |
|
{ |
180 |
15624 |
EqcInfo* ei = NULL; |
181 |
15624 |
if (doMake) |
182 |
|
{ |
183 |
4883 |
ei = new EqcInfo(context()); |
184 |
4883 |
d_eqc_info[n] = ei; |
185 |
|
} |
186 |
15624 |
return ei; |
187 |
|
} |
188 |
|
else |
189 |
|
{ |
190 |
97372 |
return eqc_i->second; |
191 |
|
} |
192 |
|
} |
193 |
|
|
194 |
35403 |
bool TheorySetsPrivate::areCareDisequal(Node a, Node b) |
195 |
|
{ |
196 |
106209 |
if (d_equalityEngine->isTriggerTerm(a, THEORY_SETS) |
197 |
106209 |
&& d_equalityEngine->isTriggerTerm(b, THEORY_SETS)) |
198 |
|
{ |
199 |
|
TNode a_shared = |
200 |
34398 |
d_equalityEngine->getTriggerTermRepresentative(a, THEORY_SETS); |
201 |
|
TNode b_shared = |
202 |
34398 |
d_equalityEngine->getTriggerTermRepresentative(b, THEORY_SETS); |
203 |
|
EqualityStatus eqStatus = |
204 |
19847 |
d_external.d_valuation.getEqualityStatus(a_shared, b_shared); |
205 |
19847 |
if (eqStatus == EQUALITY_FALSE_AND_PROPAGATED || eqStatus == EQUALITY_FALSE |
206 |
19847 |
|| eqStatus == EQUALITY_FALSE_IN_MODEL) |
207 |
|
{ |
208 |
5296 |
return true; |
209 |
|
} |
210 |
|
} |
211 |
30107 |
return false; |
212 |
|
} |
213 |
|
|
214 |
20560 |
void TheorySetsPrivate::fullEffortReset() |
215 |
|
{ |
216 |
20560 |
Assert(d_equalityEngine->consistent()); |
217 |
20560 |
d_fullCheckIncomplete = false; |
218 |
20560 |
d_fullCheckIncompleteId = IncompleteId::UNKNOWN; |
219 |
20560 |
d_most_common_type.clear(); |
220 |
20560 |
d_most_common_type_term.clear(); |
221 |
20560 |
d_card_enabled = false; |
222 |
20560 |
d_rels_enabled = false; |
223 |
|
// reset the state object |
224 |
20560 |
d_state.reset(); |
225 |
|
// reset the inference manager |
226 |
20560 |
d_im.reset(); |
227 |
20560 |
d_im.clearPendingLemmas(); |
228 |
|
// reset the cardinality solver |
229 |
20560 |
d_cardSolver->reset(); |
230 |
20560 |
} |
231 |
|
|
232 |
20560 |
void TheorySetsPrivate::fullEffortCheck() |
233 |
|
{ |
234 |
20560 |
Trace("sets") << "----- Full effort check ------" << std::endl; |
235 |
|
do |
236 |
|
{ |
237 |
20560 |
Assert(!d_im.hasPendingLemma() || d_im.hasSent()); |
238 |
|
|
239 |
20560 |
Trace("sets") << "...iterate full effort check..." << std::endl; |
240 |
20560 |
fullEffortReset(); |
241 |
|
|
242 |
20560 |
Trace("sets-eqc") << "Equality Engine:" << std::endl; |
243 |
36609 |
std::map<TypeNode, unsigned> eqcTypeCount; |
244 |
20560 |
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine); |
245 |
342474 |
while (!eqcs_i.isFinished()) |
246 |
|
{ |
247 |
321914 |
Node eqc = (*eqcs_i); |
248 |
160957 |
bool isSet = false; |
249 |
321914 |
TypeNode tn = eqc.getType(); |
250 |
160957 |
d_state.registerEqc(tn, eqc); |
251 |
160957 |
eqcTypeCount[tn]++; |
252 |
|
// common type node and term |
253 |
321914 |
TypeNode tnc; |
254 |
321914 |
Node tnct; |
255 |
160957 |
if (tn.isSet()) |
256 |
|
{ |
257 |
54121 |
isSet = true; |
258 |
54121 |
tnc = tn.getSetElementType(); |
259 |
54121 |
tnct = eqc; |
260 |
|
} |
261 |
160957 |
Trace("sets-eqc") << "[" << eqc << "] : "; |
262 |
160957 |
eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, d_equalityEngine); |
263 |
1220833 |
while (!eqc_i.isFinished()) |
264 |
|
{ |
265 |
1061011 |
Node n = (*eqc_i); |
266 |
531073 |
if (n != eqc) |
267 |
|
{ |
268 |
370116 |
Trace("sets-eqc") << n << " (" << n.isConst() << ") "; |
269 |
|
} |
270 |
1061011 |
TypeNode tnn = n.getType(); |
271 |
531073 |
if (isSet) |
272 |
|
{ |
273 |
141126 |
Assert(tnn.isSet()); |
274 |
282252 |
TypeNode tnnel = tnn.getSetElementType(); |
275 |
141126 |
tnc = TypeNode::mostCommonTypeNode(tnc, tnnel); |
276 |
141126 |
Assert(!tnc.isNull()); |
277 |
|
// update the common type term |
278 |
141126 |
if (tnc == tnnel) |
279 |
|
{ |
280 |
141126 |
tnct = n; |
281 |
|
} |
282 |
|
} |
283 |
|
// register it with the state |
284 |
531073 |
d_state.registerTerm(eqc, tnn, n); |
285 |
531073 |
Kind nk = n.getKind(); |
286 |
531073 |
if (nk == kind::SINGLETON) |
287 |
|
{ |
288 |
|
// ensure the proxy has been introduced |
289 |
8848 |
d_treg.getProxy(n); |
290 |
|
} |
291 |
522225 |
else if (nk == kind::CARD) |
292 |
|
{ |
293 |
52846 |
d_card_enabled = true; |
294 |
|
// register it with the cardinality solver |
295 |
52846 |
d_cardSolver->registerTerm(n); |
296 |
52846 |
if (d_im.hasSent()) |
297 |
|
{ |
298 |
1135 |
break; |
299 |
|
} |
300 |
|
// if we do not handle the kind, set incomplete |
301 |
51711 |
Kind nk0 = n[0].getKind(); |
302 |
|
// some kinds of cardinality we cannot handle |
303 |
51711 |
if (d_rels->isRelationKind(nk0)) |
304 |
|
{ |
305 |
28 |
d_fullCheckIncomplete = true; |
306 |
28 |
d_fullCheckIncompleteId = IncompleteId::SETS_RELS_CARD; |
307 |
56 |
Trace("sets-incomplete") |
308 |
28 |
<< "Sets : incomplete because of " << n << "." << std::endl; |
309 |
|
// TODO (#1124): The issue can be divided into 4 parts |
310 |
|
// 1- Supporting the universe cardinality for finite types with |
311 |
|
// finite cardinality (done) |
312 |
|
// 2- Supporting the universe cardinality for uninterpreted sorts |
313 |
|
// with finite-model-find (pending) See the implementation of |
314 |
|
// CardinalityExtension::checkCardinalityExtended |
315 |
|
// 3- Supporting the universe cardinality for non-finite types |
316 |
|
// (done) |
317 |
|
// 4- Supporting cardinality for relations (hard) |
318 |
|
} |
319 |
|
} |
320 |
469379 |
else if (d_rels->isRelationKind(nk)) |
321 |
|
{ |
322 |
2266 |
d_rels_enabled = true; |
323 |
|
} |
324 |
529938 |
++eqc_i; |
325 |
|
} |
326 |
160957 |
if (isSet) |
327 |
|
{ |
328 |
54121 |
Assert(tnct.getType().getSetElementType() == tnc); |
329 |
54121 |
d_most_common_type[eqc] = tnc; |
330 |
54121 |
d_most_common_type_term[eqc] = tnct; |
331 |
|
} |
332 |
160957 |
Trace("sets-eqc") << std::endl; |
333 |
160957 |
++eqcs_i; |
334 |
|
} |
335 |
|
|
336 |
20560 |
Trace("sets-eqc") << "...finished equality engine." << std::endl; |
337 |
|
|
338 |
20560 |
if (Trace.isOn("sets-state")) |
339 |
|
{ |
340 |
|
Trace("sets-state") << "Equivalence class counters:" << std::endl; |
341 |
|
for (std::pair<const TypeNode, unsigned>& ec : eqcTypeCount) |
342 |
|
{ |
343 |
|
Trace("sets-state") |
344 |
|
<< " " << ec.first << " -> " << ec.second << std::endl; |
345 |
|
} |
346 |
|
} |
347 |
|
|
348 |
|
// We may have sent lemmas while registering the terms in the loop above, |
349 |
|
// e.g. the cardinality solver. |
350 |
20560 |
if (d_im.hasSent()) |
351 |
|
{ |
352 |
532 |
continue; |
353 |
|
} |
354 |
20028 |
if (Trace.isOn("sets-mem")) |
355 |
|
{ |
356 |
|
const std::vector<Node>& sec = d_state.getSetsEqClasses(); |
357 |
|
for (const Node& s : sec) |
358 |
|
{ |
359 |
|
Trace("sets-mem") << "Eqc " << s << " : "; |
360 |
|
const std::map<Node, Node>& smem = d_state.getMembers(s); |
361 |
|
if (!smem.empty()) |
362 |
|
{ |
363 |
|
Trace("sets-mem") << "Memberships : "; |
364 |
|
for (const std::pair<const Node, Node>& it2 : smem) |
365 |
|
{ |
366 |
|
Trace("sets-mem") << it2.first << " "; |
367 |
|
} |
368 |
|
} |
369 |
|
Node ss = d_state.getSingletonEqClass(s); |
370 |
|
if (!ss.isNull()) |
371 |
|
{ |
372 |
|
Trace("sets-mem") << " : Singleton : " << ss; |
373 |
|
} |
374 |
|
Trace("sets-mem") << std::endl; |
375 |
|
} |
376 |
|
} |
377 |
20028 |
d_im.doPendingLemmas(); |
378 |
20028 |
if (d_im.hasSent()) |
379 |
|
{ |
380 |
|
continue; |
381 |
|
} |
382 |
|
// check downwards closure |
383 |
20028 |
checkDownwardsClosure(); |
384 |
20028 |
d_im.doPendingLemmas(); |
385 |
20028 |
if (d_im.hasSent()) |
386 |
|
{ |
387 |
548 |
continue; |
388 |
|
} |
389 |
|
// check upwards closure |
390 |
19480 |
checkUpwardsClosure(); |
391 |
19480 |
d_im.doPendingLemmas(); |
392 |
19480 |
if (d_im.hasSent()) |
393 |
|
{ |
394 |
1154 |
continue; |
395 |
|
} |
396 |
|
// check disequalities |
397 |
18326 |
checkDisequalities(); |
398 |
18326 |
d_im.doPendingLemmas(); |
399 |
18326 |
if (d_im.hasSent()) |
400 |
|
{ |
401 |
595 |
continue; |
402 |
|
} |
403 |
|
// check reduce comprehensions |
404 |
17731 |
checkReduceComprehensions(); |
405 |
|
|
406 |
17731 |
d_im.doPendingLemmas(); |
407 |
17731 |
if (d_im.hasSent()) |
408 |
|
{ |
409 |
18 |
continue; |
410 |
|
} |
411 |
17713 |
if (d_card_enabled) |
412 |
|
{ |
413 |
|
// call the check method of the cardinality solver |
414 |
1799 |
d_cardSolver->check(); |
415 |
1798 |
if (d_im.hasSent()) |
416 |
|
{ |
417 |
1664 |
continue; |
418 |
|
} |
419 |
|
} |
420 |
16048 |
if (d_rels_enabled) |
421 |
|
{ |
422 |
|
// call the check method of the relations solver |
423 |
769 |
d_rels->check(Theory::EFFORT_FULL); |
424 |
|
} |
425 |
35996 |
} while (!d_im.hasSentLemma() && !d_state.isInConflict() |
426 |
35996 |
&& d_im.hasSentFact()); |
427 |
20559 |
Assert(!d_im.hasPendingLemma() || d_im.hasSent()); |
428 |
41118 |
Trace("sets") << "----- End full effort check, conflict=" |
429 |
41118 |
<< d_state.isInConflict() << ", lemma=" << d_im.hasSentLemma() |
430 |
20559 |
<< std::endl; |
431 |
20559 |
} |
432 |
|
|
433 |
20028 |
void TheorySetsPrivate::checkDownwardsClosure() |
434 |
|
{ |
435 |
20028 |
Trace("sets") << "TheorySetsPrivate: check downwards closure..." << std::endl; |
436 |
|
// downwards closure |
437 |
20028 |
const std::vector<Node>& sec = d_state.getSetsEqClasses(); |
438 |
69127 |
for (const Node& s : sec) |
439 |
|
{ |
440 |
49099 |
const std::vector<Node>& nvsets = d_state.getNonVariableSets(s); |
441 |
49099 |
if (!nvsets.empty()) |
442 |
|
{ |
443 |
36550 |
const std::map<Node, Node>& smem = d_state.getMembers(s); |
444 |
97214 |
for (const Node& nv : nvsets) |
445 |
|
{ |
446 |
60664 |
if (!d_state.isCongruent(nv)) |
447 |
|
{ |
448 |
110930 |
for (const std::pair<const Node, Node>& it2 : smem) |
449 |
|
{ |
450 |
110420 |
Node mem = it2.second; |
451 |
110420 |
Node eq_set = nv; |
452 |
55210 |
Assert(d_equalityEngine->areEqual(mem[1], eq_set)); |
453 |
55210 |
if (mem[1] != eq_set) |
454 |
|
{ |
455 |
107108 |
Trace("sets-debug") << "Downwards closure based on " << mem |
456 |
53554 |
<< ", eq_set = " << eq_set << std::endl; |
457 |
53554 |
if (!options::setsProxyLemmas()) |
458 |
|
{ |
459 |
|
Node nmem = NodeManager::currentNM()->mkNode( |
460 |
107108 |
kind::MEMBER, mem[0], eq_set); |
461 |
53554 |
nmem = Rewriter::rewrite(nmem); |
462 |
107108 |
std::vector<Node> exp; |
463 |
53554 |
exp.push_back(mem); |
464 |
53554 |
exp.push_back(mem[1].eqNode(eq_set)); |
465 |
53554 |
d_im.assertInference(nmem, InferenceId::SETS_DOWN_CLOSURE, exp); |
466 |
53554 |
if (d_state.isInConflict()) |
467 |
|
{ |
468 |
|
return; |
469 |
|
} |
470 |
|
} |
471 |
|
else |
472 |
|
{ |
473 |
|
// use proxy set |
474 |
|
Node k = d_treg.getProxy(eq_set); |
475 |
|
Node pmem = |
476 |
|
NodeManager::currentNM()->mkNode(kind::MEMBER, mem[0], k); |
477 |
|
Node nmem = NodeManager::currentNM()->mkNode( |
478 |
|
kind::MEMBER, mem[0], eq_set); |
479 |
|
nmem = Rewriter::rewrite(nmem); |
480 |
|
std::vector<Node> exp; |
481 |
|
if (d_state.areEqual(mem, pmem)) |
482 |
|
{ |
483 |
|
exp.push_back(pmem); |
484 |
|
} |
485 |
|
else |
486 |
|
{ |
487 |
|
nmem = NodeManager::currentNM()->mkNode( |
488 |
|
kind::OR, pmem.negate(), nmem); |
489 |
|
} |
490 |
|
d_im.assertInference(nmem, InferenceId::SETS_DOWN_CLOSURE, exp); |
491 |
|
} |
492 |
|
} |
493 |
|
} |
494 |
|
} |
495 |
|
} |
496 |
|
} |
497 |
|
} |
498 |
|
} |
499 |
|
|
500 |
19480 |
void TheorySetsPrivate::checkUpwardsClosure() |
501 |
|
{ |
502 |
|
// upwards closure |
503 |
19480 |
NodeManager* nm = NodeManager::currentNM(); |
504 |
|
const std::map<Kind, std::map<Node, std::map<Node, Node> > >& boi = |
505 |
19480 |
d_state.getBinaryOpIndex(); |
506 |
8269 |
for (const std::pair<const Kind, std::map<Node, std::map<Node, Node> > >& |
507 |
19480 |
itb : boi) |
508 |
|
{ |
509 |
8269 |
Kind k = itb.first; |
510 |
16538 |
Trace("sets") << "TheorySetsPrivate: check upwards closure " << k << "..." |
511 |
8269 |
<< std::endl; |
512 |
33942 |
for (const std::pair<const Node, std::map<Node, Node> >& it : itb.second) |
513 |
|
{ |
514 |
51346 |
Node r1 = it.first; |
515 |
|
// see if there are members in first argument r1 |
516 |
25673 |
const std::map<Node, Node>& r1mem = d_state.getMembers(r1); |
517 |
25673 |
if (!r1mem.empty() || k == kind::UNION) |
518 |
|
{ |
519 |
50999 |
for (const std::pair<const Node, Node>& it2 : it.second) |
520 |
|
{ |
521 |
60100 |
Node r2 = it2.first; |
522 |
60100 |
Node term = it2.second; |
523 |
|
// see if there are members in second argument |
524 |
30050 |
const std::map<Node, Node>& r2mem = d_state.getMembers(r2); |
525 |
30050 |
const std::map<Node, Node>& r2nmem = d_state.getNegativeMembers(r2); |
526 |
30050 |
if (!r2mem.empty() || k != kind::INTERSECTION) |
527 |
|
{ |
528 |
58562 |
Trace("sets-debug") |
529 |
58562 |
<< "Checking " << term << ", members = " << (!r1mem.empty()) |
530 |
29281 |
<< ", " << (!r2mem.empty()) << std::endl; |
531 |
|
// for all members of r1 |
532 |
29281 |
if (!r1mem.empty()) |
533 |
|
{ |
534 |
76750 |
for (const std::pair<const Node, Node>& itm1m : r1mem) |
535 |
|
{ |
536 |
99962 |
Node xr = itm1m.first; |
537 |
99962 |
Node x = itm1m.second[0]; |
538 |
99962 |
Trace("sets-debug") << "checking membership " << xr << " " |
539 |
49981 |
<< itm1m.second << std::endl; |
540 |
99962 |
std::vector<Node> exp; |
541 |
49981 |
exp.push_back(itm1m.second); |
542 |
49981 |
d_state.addEqualityToExp(term[0], itm1m.second[1], exp); |
543 |
49981 |
bool valid = false; |
544 |
49981 |
int inferType = 0; |
545 |
49981 |
if (k == kind::UNION) |
546 |
|
{ |
547 |
8516 |
valid = true; |
548 |
|
} |
549 |
41465 |
else if (k == kind::INTERSECTION) |
550 |
|
{ |
551 |
|
// conclude x is in term |
552 |
|
// if also existing in members of r2 |
553 |
13212 |
std::map<Node, Node>::const_iterator itm = r2mem.find(xr); |
554 |
13212 |
if (itm != r2mem.end()) |
555 |
|
{ |
556 |
8343 |
exp.push_back(itm->second); |
557 |
8343 |
d_state.addEqualityToExp(term[1], itm->second[1], exp); |
558 |
8343 |
d_state.addEqualityToExp(x, itm->second[0], exp); |
559 |
8343 |
valid = true; |
560 |
|
} |
561 |
|
else |
562 |
|
{ |
563 |
|
// if not, check whether it is definitely not a member, if |
564 |
|
// unknown, split |
565 |
4869 |
if (r2nmem.find(xr) == r2nmem.end()) |
566 |
|
{ |
567 |
717 |
exp.push_back(nm->mkNode(kind::MEMBER, x, term[1])); |
568 |
717 |
valid = true; |
569 |
717 |
inferType = 1; |
570 |
|
} |
571 |
|
} |
572 |
|
} |
573 |
|
else |
574 |
|
{ |
575 |
28253 |
Assert(k == kind::SETMINUS); |
576 |
28253 |
std::map<Node, Node>::const_iterator itm = r2mem.find(xr); |
577 |
28253 |
if (itm == r2mem.end()) |
578 |
|
{ |
579 |
|
// must add lemma for set minus since non-membership in this |
580 |
|
// case is not explained |
581 |
12404 |
exp.push_back( |
582 |
24808 |
nm->mkNode(kind::MEMBER, x, term[1]).negate()); |
583 |
12404 |
valid = true; |
584 |
12404 |
inferType = 1; |
585 |
|
} |
586 |
|
} |
587 |
49981 |
if (valid) |
588 |
|
{ |
589 |
59960 |
Node rr = d_equalityEngine->getRepresentative(term); |
590 |
29980 |
if (!d_state.isMember(x, rr)) |
591 |
|
{ |
592 |
4676 |
Node kk = d_treg.getProxy(term); |
593 |
4676 |
Node fact = nm->mkNode(kind::MEMBER, x, kk); |
594 |
2338 |
d_im.assertInference( |
595 |
|
fact, InferenceId::SETS_UP_CLOSURE, exp, inferType); |
596 |
2338 |
if (d_state.isInConflict()) |
597 |
|
{ |
598 |
|
return; |
599 |
|
} |
600 |
|
} |
601 |
|
} |
602 |
99962 |
Trace("sets-debug") << "done checking membership " << xr << " " |
603 |
49981 |
<< itm1m.second << std::endl; |
604 |
|
} |
605 |
|
} |
606 |
29281 |
if (k == kind::UNION) |
607 |
|
{ |
608 |
8224 |
if (!r2mem.empty()) |
609 |
|
{ |
610 |
|
// for all members of r2 |
611 |
19849 |
for (const std::pair<const Node, Node>& itm2m : r2mem) |
612 |
|
{ |
613 |
27104 |
Node x = itm2m.second[0]; |
614 |
27104 |
Node rr = d_equalityEngine->getRepresentative(term); |
615 |
13552 |
if (!d_state.isMember(x, rr)) |
616 |
|
{ |
617 |
1116 |
std::vector<Node> exp; |
618 |
558 |
exp.push_back(itm2m.second); |
619 |
558 |
d_state.addEqualityToExp(term[1], itm2m.second[1], exp); |
620 |
1116 |
Node r = d_treg.getProxy(term); |
621 |
1116 |
Node fact = nm->mkNode(kind::MEMBER, x, r); |
622 |
558 |
d_im.assertInference(fact, InferenceId::SETS_UP_CLOSURE_2, exp); |
623 |
558 |
if (d_state.isInConflict()) |
624 |
|
{ |
625 |
|
return; |
626 |
|
} |
627 |
|
} |
628 |
|
} |
629 |
|
} |
630 |
|
} |
631 |
|
} |
632 |
|
} |
633 |
|
} |
634 |
|
} |
635 |
|
} |
636 |
19480 |
if (!d_im.hasSent()) |
637 |
|
{ |
638 |
19023 |
if (options::setsExt()) |
639 |
|
{ |
640 |
|
// universal sets |
641 |
1601 |
Trace("sets-debug") << "Check universe sets..." << std::endl; |
642 |
|
// all elements must be in universal set |
643 |
1601 |
const std::vector<Node>& sec = d_state.getSetsEqClasses(); |
644 |
15423 |
for (const Node& s : sec) |
645 |
|
{ |
646 |
|
// if equivalence class contains a variable |
647 |
27644 |
Node v = d_state.getVariableSet(s); |
648 |
13822 |
if (!v.isNull()) |
649 |
|
{ |
650 |
|
// the variable in the equivalence class |
651 |
8396 |
std::map<TypeNode, Node> univ_set; |
652 |
4198 |
const std::map<Node, Node>& smems = d_state.getMembers(s); |
653 |
9098 |
for (const std::pair<const Node, Node>& it2 : smems) |
654 |
|
{ |
655 |
9800 |
Node e = it2.second[0]; |
656 |
9800 |
TypeNode tn = NodeManager::currentNM()->mkSetType(e.getType()); |
657 |
9800 |
Node u; |
658 |
4900 |
std::map<TypeNode, Node>::iterator itu = univ_set.find(tn); |
659 |
4900 |
if (itu == univ_set.end()) |
660 |
|
{ |
661 |
5232 |
Node ueqc = d_state.getUnivSetEqClass(tn); |
662 |
|
// if the universe does not yet exist, or is not in this |
663 |
|
// equivalence class |
664 |
2616 |
if (s != ueqc) |
665 |
|
{ |
666 |
1943 |
u = d_treg.getUnivSet(tn); |
667 |
|
} |
668 |
2616 |
univ_set[tn] = u; |
669 |
|
} |
670 |
|
else |
671 |
|
{ |
672 |
2284 |
u = itu->second; |
673 |
|
} |
674 |
4900 |
if (!u.isNull()) |
675 |
|
{ |
676 |
3207 |
Assert(it2.second.getKind() == kind::MEMBER); |
677 |
6414 |
std::vector<Node> exp; |
678 |
3207 |
exp.push_back(it2.second); |
679 |
3207 |
if (v != it2.second[1]) |
680 |
|
{ |
681 |
762 |
exp.push_back(v.eqNode(it2.second[1])); |
682 |
|
} |
683 |
6414 |
Node fact = nm->mkNode(kind::MEMBER, it2.second[0], u); |
684 |
3207 |
d_im.assertInference(fact, InferenceId::SETS_UP_UNIV, exp); |
685 |
3207 |
if (d_state.isInConflict()) |
686 |
|
{ |
687 |
|
return; |
688 |
|
} |
689 |
|
} |
690 |
|
} |
691 |
|
} |
692 |
|
} |
693 |
|
} |
694 |
|
} |
695 |
|
} |
696 |
|
|
697 |
18326 |
void TheorySetsPrivate::checkDisequalities() |
698 |
|
{ |
699 |
|
// disequalities |
700 |
18326 |
Trace("sets") << "TheorySetsPrivate: check disequalities..." << std::endl; |
701 |
18326 |
NodeManager* nm = NodeManager::currentNM(); |
702 |
26266 |
for (NodeBoolMap::const_iterator it = d_deq.begin(); it != d_deq.end(); ++it) |
703 |
|
{ |
704 |
8535 |
if (!(*it).second) |
705 |
|
{ |
706 |
|
// not active |
707 |
11082 |
continue; |
708 |
|
} |
709 |
5393 |
Node deq = (*it).first; |
710 |
|
// check if it is already satisfied |
711 |
5393 |
Assert(d_equalityEngine->hasTerm(deq[0]) |
712 |
|
&& d_equalityEngine->hasTerm(deq[1])); |
713 |
5393 |
Node r1 = d_equalityEngine->getRepresentative(deq[0]); |
714 |
5393 |
Node r2 = d_equalityEngine->getRepresentative(deq[1]); |
715 |
5393 |
bool is_sat = d_state.isSetDisequalityEntailed(r1, r2); |
716 |
10786 |
Trace("sets-debug") << "Check disequality " << deq |
717 |
5393 |
<< ", is_sat = " << is_sat << std::endl; |
718 |
|
// will process regardless of sat/processed/unprocessed |
719 |
5393 |
d_deq[deq] = false; |
720 |
|
|
721 |
5393 |
if (is_sat) |
722 |
|
{ |
723 |
|
// already satisfied |
724 |
4661 |
continue; |
725 |
|
} |
726 |
732 |
if (d_termProcessed.find(deq) != d_termProcessed.end()) |
727 |
|
{ |
728 |
|
// already added lemma |
729 |
137 |
continue; |
730 |
|
} |
731 |
595 |
d_termProcessed.insert(deq); |
732 |
595 |
d_termProcessed.insert(deq[1].eqNode(deq[0])); |
733 |
595 |
Trace("sets") << "Process Disequality : " << deq.negate() << std::endl; |
734 |
595 |
TypeNode elementType = deq[0].getType().getSetElementType(); |
735 |
595 |
Node x = d_skCache.mkTypedSkolemCached( |
736 |
595 |
elementType, deq[0], deq[1], SkolemCache::SK_DISEQUAL, "sde"); |
737 |
595 |
Node mem1 = nm->mkNode(MEMBER, x, deq[0]); |
738 |
595 |
Node mem2 = nm->mkNode(MEMBER, x, deq[1]); |
739 |
595 |
Node lem = nm->mkNode(OR, deq, nm->mkNode(EQUAL, mem1, mem2).negate()); |
740 |
595 |
lem = Rewriter::rewrite(lem); |
741 |
595 |
d_im.assertInference(lem, InferenceId::SETS_DEQ, d_true, 1); |
742 |
595 |
d_im.doPendingLemmas(); |
743 |
595 |
if (d_im.hasSent()) |
744 |
|
{ |
745 |
595 |
return; |
746 |
|
} |
747 |
|
} |
748 |
|
} |
749 |
|
|
750 |
17731 |
void TheorySetsPrivate::checkReduceComprehensions() |
751 |
|
{ |
752 |
17731 |
NodeManager* nm = NodeManager::currentNM(); |
753 |
17731 |
const std::vector<Node>& comps = d_state.getComprehensionSets(); |
754 |
17799 |
for (const Node& n : comps) |
755 |
|
{ |
756 |
68 |
if (d_termProcessed.find(n) != d_termProcessed.end()) |
757 |
|
{ |
758 |
|
// already reduced it |
759 |
46 |
continue; |
760 |
|
} |
761 |
22 |
d_termProcessed.insert(n); |
762 |
44 |
Node v = nm->mkBoundVar(n[2].getType()); |
763 |
44 |
Node body = nm->mkNode(AND, n[1], v.eqNode(n[2])); |
764 |
|
// must do substitution |
765 |
44 |
std::vector<Node> vars; |
766 |
44 |
std::vector<Node> subs; |
767 |
44 |
for (const Node& cv : n[0]) |
768 |
|
{ |
769 |
22 |
vars.push_back(cv); |
770 |
44 |
Node cvs = nm->mkBoundVar(cv.getType()); |
771 |
22 |
subs.push_back(cvs); |
772 |
|
} |
773 |
22 |
body = body.substitute(vars.begin(), vars.end(), subs.begin(), subs.end()); |
774 |
44 |
Node bvl = nm->mkNode(BOUND_VAR_LIST, subs); |
775 |
22 |
body = nm->mkNode(EXISTS, bvl, body); |
776 |
44 |
Node mem = nm->mkNode(MEMBER, v, n); |
777 |
|
Node lem = |
778 |
44 |
nm->mkNode(FORALL, nm->mkNode(BOUND_VAR_LIST, v), body.eqNode(mem)); |
779 |
44 |
Trace("sets-comprehension") |
780 |
22 |
<< "Comprehension reduction: " << lem << std::endl; |
781 |
22 |
d_im.lemma(lem, InferenceId::SETS_COMPREHENSION); |
782 |
|
} |
783 |
17731 |
} |
784 |
|
|
785 |
|
//--------------------------------- standard check |
786 |
|
|
787 |
106350 |
void TheorySetsPrivate::postCheck(Theory::Effort level) |
788 |
|
{ |
789 |
212700 |
Trace("sets-check") << "Sets finished assertions effort " << level |
790 |
106350 |
<< std::endl; |
791 |
|
// invoke full effort check, relations check |
792 |
106350 |
if (!d_state.isInConflict()) |
793 |
|
{ |
794 |
100213 |
if (level == Theory::EFFORT_FULL) |
795 |
|
{ |
796 |
25261 |
if (!d_external.d_valuation.needCheck()) |
797 |
|
{ |
798 |
20560 |
fullEffortCheck(); |
799 |
61677 |
if (!d_state.isInConflict() && !d_im.hasSentLemma() |
800 |
35996 |
&& d_fullCheckIncomplete) |
801 |
|
{ |
802 |
4 |
d_im.setIncomplete(d_fullCheckIncompleteId); |
803 |
|
} |
804 |
|
} |
805 |
|
} |
806 |
|
} |
807 |
106349 |
Trace("sets-check") << "Sets finish Check effort " << level << std::endl; |
808 |
106349 |
} |
809 |
|
|
810 |
229125 |
void TheorySetsPrivate::notifyFact(TNode atom, bool polarity, TNode fact) |
811 |
|
{ |
812 |
229125 |
if (d_state.isInConflict()) |
813 |
|
{ |
814 |
5977 |
return; |
815 |
|
} |
816 |
223148 |
if (atom.getKind() == kind::MEMBER && polarity) |
817 |
|
{ |
818 |
|
// check if set has a value, if so, we can propagate |
819 |
127628 |
Node r = d_equalityEngine->getRepresentative(atom[1]); |
820 |
63814 |
EqcInfo* e = getOrMakeEqcInfo(r, true); |
821 |
63814 |
if (e) |
822 |
|
{ |
823 |
127628 |
Node s = e->d_singleton; |
824 |
63814 |
if (!s.isNull()) |
825 |
|
{ |
826 |
|
Node pexp = NodeManager::currentNM()->mkNode( |
827 |
5044 |
kind::AND, atom, atom[1].eqNode(s)); |
828 |
2522 |
if (s.getKind() == kind::SINGLETON) |
829 |
|
{ |
830 |
2362 |
if (s[0] != atom[0]) |
831 |
|
{ |
832 |
414 |
Trace("sets-prop") << "Propagate mem-eq : " << pexp << std::endl; |
833 |
828 |
Node eq = s[0].eqNode(atom[0]); |
834 |
|
// triggers an internal inference |
835 |
414 |
d_im.assertSetsFact(eq, true, InferenceId::SETS_MEM_EQ, pexp); |
836 |
|
} |
837 |
|
} |
838 |
|
else |
839 |
|
{ |
840 |
320 |
Trace("sets-prop") |
841 |
160 |
<< "Propagate mem-eq conflict : " << pexp << std::endl; |
842 |
160 |
d_im.conflict(pexp, InferenceId::SETS_MEM_EQ_CONFLICT); |
843 |
|
} |
844 |
|
} |
845 |
|
} |
846 |
|
// add to membership list |
847 |
63814 |
d_state.addMember(r, atom); |
848 |
|
} |
849 |
|
} |
850 |
|
//--------------------------------- end standard check |
851 |
|
|
852 |
|
/************************ Sharing ************************/ |
853 |
|
/************************ Sharing ************************/ |
854 |
|
/************************ Sharing ************************/ |
855 |
|
|
856 |
16315 |
void TheorySetsPrivate::addCarePairs(TNodeTrie* t1, |
857 |
|
TNodeTrie* t2, |
858 |
|
unsigned arity, |
859 |
|
unsigned depth, |
860 |
|
unsigned& n_pairs) |
861 |
|
{ |
862 |
16315 |
if (depth == arity) |
863 |
|
{ |
864 |
9910 |
if (t2 != NULL) |
865 |
|
{ |
866 |
19820 |
Node f1 = t1->getData(); |
867 |
19820 |
Node f2 = t2->getData(); |
868 |
|
|
869 |
|
// Usually when (= (f x) (f y)), we don't care whether (= x y) is true or |
870 |
|
// not for the shared variables x, y in the care graph. |
871 |
|
// However, this does not apply to the membership operator since the |
872 |
|
// equality or disequality between members affects the number of elements |
873 |
|
// in a set. Therefore we need to split on (= x y) for kind MEMBER. |
874 |
|
// Example: |
875 |
|
// Suppose (= (member x S) member( y, S)) is true and there are |
876 |
|
// no other members in S. We would get S = {x} if (= x y) is true. |
877 |
|
// Otherwise we would get S = {x, y}. |
878 |
9910 |
if (f1.getKind() == MEMBER || !d_state.areEqual(f1, f2)) |
879 |
|
{ |
880 |
9910 |
Trace("sets-cg") << "Check " << f1 << " and " << f2 << std::endl; |
881 |
19820 |
vector<pair<TNode, TNode> > currentPairs; |
882 |
29065 |
for (unsigned k = 0; k < f1.getNumChildren(); ++k) |
883 |
|
{ |
884 |
38310 |
TNode x = f1[k]; |
885 |
38310 |
TNode y = f2[k]; |
886 |
19155 |
Assert(d_equalityEngine->hasTerm(x)); |
887 |
19155 |
Assert(d_equalityEngine->hasTerm(y)); |
888 |
19155 |
Assert(!d_state.areDisequal(x, y)); |
889 |
19155 |
Assert(!areCareDisequal(x, y)); |
890 |
19155 |
if (!d_equalityEngine->areEqual(x, y)) |
891 |
|
{ |
892 |
23978 |
Trace("sets-cg") |
893 |
11989 |
<< "Arg #" << k << " is " << x << " " << y << std::endl; |
894 |
35967 |
if (d_equalityEngine->isTriggerTerm(x, THEORY_SETS) |
895 |
35967 |
&& d_equalityEngine->isTriggerTerm(y, THEORY_SETS)) |
896 |
|
{ |
897 |
4468 |
TNode x_shared = d_equalityEngine->getTriggerTermRepresentative( |
898 |
8936 |
x, THEORY_SETS); |
899 |
4468 |
TNode y_shared = d_equalityEngine->getTriggerTermRepresentative( |
900 |
8936 |
y, THEORY_SETS); |
901 |
4468 |
currentPairs.push_back(make_pair(x_shared, y_shared)); |
902 |
|
} |
903 |
7521 |
else if (isCareArg(f1, k) && isCareArg(f2, k)) |
904 |
|
{ |
905 |
|
// splitting on sets (necessary for handling set of sets properly) |
906 |
6 |
if (x.getType().isSet()) |
907 |
|
{ |
908 |
6 |
Assert(y.getType().isSet()); |
909 |
6 |
if (!d_state.areDisequal(x, y)) |
910 |
|
{ |
911 |
12 |
Trace("sets-cg-lemma") |
912 |
6 |
<< "Should split on : " << x << "==" << y << std::endl; |
913 |
6 |
d_im.split(x.eqNode(y), InferenceId::SETS_CG_SPLIT); |
914 |
|
} |
915 |
|
} |
916 |
|
} |
917 |
|
} |
918 |
|
} |
919 |
14378 |
for (unsigned c = 0; c < currentPairs.size(); ++c) |
920 |
|
{ |
921 |
8936 |
Trace("sets-cg-pair") << "Pair : " << currentPairs[c].first << " " |
922 |
4468 |
<< currentPairs[c].second << std::endl; |
923 |
4468 |
d_external.addCarePair(currentPairs[c].first, currentPairs[c].second); |
924 |
4468 |
n_pairs++; |
925 |
|
} |
926 |
|
} |
927 |
|
} |
928 |
|
} |
929 |
|
else |
930 |
|
{ |
931 |
6405 |
if (t2 == NULL) |
932 |
|
{ |
933 |
5363 |
if (depth < (arity - 1)) |
934 |
|
{ |
935 |
|
// add care pairs internal to each child |
936 |
4833 |
for (std::pair<const TNode, TNodeTrie>& t : t1->d_data) |
937 |
|
{ |
938 |
3738 |
addCarePairs(&t.second, NULL, arity, depth + 1, n_pairs); |
939 |
|
} |
940 |
|
} |
941 |
|
// add care pairs based on each pair of non-disequal arguments |
942 |
17890 |
for (std::map<TNode, TNodeTrie>::iterator it = t1->d_data.begin(); |
943 |
17890 |
it != t1->d_data.end(); |
944 |
|
++it) |
945 |
|
{ |
946 |
12527 |
std::map<TNode, TNodeTrie>::iterator it2 = it; |
947 |
12527 |
++it2; |
948 |
61829 |
for (; it2 != t1->d_data.end(); ++it2) |
949 |
|
{ |
950 |
24651 |
if (!d_equalityEngine->areDisequal(it->first, it2->first, false)) |
951 |
|
{ |
952 |
13715 |
if (!areCareDisequal(it->first, it2->first)) |
953 |
|
{ |
954 |
25257 |
addCarePairs( |
955 |
16838 |
&it->second, &it2->second, arity, depth + 1, n_pairs); |
956 |
|
} |
957 |
|
} |
958 |
|
} |
959 |
|
} |
960 |
|
} |
961 |
|
else |
962 |
|
{ |
963 |
|
// add care pairs based on product of indices, non-disequal arguments |
964 |
2802 |
for (std::pair<const TNode, TNodeTrie>& tt1 : t1->d_data) |
965 |
|
{ |
966 |
5195 |
for (std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data) |
967 |
|
{ |
968 |
3435 |
if (!d_equalityEngine->areDisequal(tt1.first, tt2.first, false)) |
969 |
|
{ |
970 |
2533 |
if (!areCareDisequal(tt1.first, tt2.first)) |
971 |
|
{ |
972 |
2533 |
addCarePairs(&tt1.second, &tt2.second, arity, depth + 1, n_pairs); |
973 |
|
} |
974 |
|
} |
975 |
|
} |
976 |
|
} |
977 |
|
} |
978 |
|
} |
979 |
16315 |
} |
980 |
|
|
981 |
6390 |
void TheorySetsPrivate::computeCareGraph() |
982 |
|
{ |
983 |
6390 |
const std::map<Kind, std::vector<Node> >& ol = d_state.getOperatorList(); |
984 |
8372 |
for (const std::pair<const Kind, std::vector<Node> >& it : ol) |
985 |
|
{ |
986 |
1982 |
Kind k = it.first; |
987 |
1982 |
if (k == kind::SINGLETON || k == kind::MEMBER) |
988 |
|
{ |
989 |
1265 |
unsigned n_pairs = 0; |
990 |
2530 |
Trace("sets-cg-summary") << "Compute graph for sets, op=" << k << "..." |
991 |
1265 |
<< it.second.size() << std::endl; |
992 |
1265 |
Trace("sets-cg") << "Build index for " << k << "..." << std::endl; |
993 |
2530 |
std::map<TypeNode, TNodeTrie> index; |
994 |
1265 |
unsigned arity = 0; |
995 |
|
// populate indices |
996 |
10054 |
for (TNode f1 : it.second) |
997 |
|
{ |
998 |
8789 |
Trace("sets-cg-debug") << "...build for " << f1 << std::endl; |
999 |
8789 |
Assert(d_equalityEngine->hasTerm(f1)); |
1000 |
|
// break into index based on operator, and the type of the element |
1001 |
|
// type of the proper set, which notice must be safe wrt subtyping. |
1002 |
17578 |
TypeNode tn; |
1003 |
8789 |
if (k == kind::SINGLETON) |
1004 |
|
{ |
1005 |
|
// get the type of the singleton set (not the type of its element) |
1006 |
1469 |
tn = f1.getType().getSetElementType(); |
1007 |
|
} |
1008 |
|
else |
1009 |
|
{ |
1010 |
7320 |
Assert (k == kind::MEMBER); |
1011 |
|
// get the element type of the set (not the type of the element) |
1012 |
7320 |
tn = f1[1].getType().getSetElementType(); |
1013 |
|
} |
1014 |
17578 |
std::vector<TNode> reps; |
1015 |
8789 |
bool hasCareArg = false; |
1016 |
24898 |
for (unsigned j = 0; j < f1.getNumChildren(); j++) |
1017 |
|
{ |
1018 |
16109 |
reps.push_back(d_equalityEngine->getRepresentative(f1[j])); |
1019 |
16109 |
if (isCareArg(f1, j)) |
1020 |
|
{ |
1021 |
11377 |
hasCareArg = true; |
1022 |
|
} |
1023 |
|
} |
1024 |
8789 |
if (hasCareArg) |
1025 |
|
{ |
1026 |
8789 |
Trace("sets-cg-debug") << "......adding." << std::endl; |
1027 |
8789 |
index[tn].addTerm(f1, reps); |
1028 |
8789 |
arity = reps.size(); |
1029 |
|
} |
1030 |
|
else |
1031 |
|
{ |
1032 |
|
Trace("sets-cg-debug") << "......skip." << std::endl; |
1033 |
|
} |
1034 |
|
} |
1035 |
1265 |
if (arity > 0) |
1036 |
|
{ |
1037 |
|
// for each index |
1038 |
2890 |
for (std::pair<const TypeNode, TNodeTrie>& tt : index) |
1039 |
|
{ |
1040 |
3250 |
Trace("sets-cg") << "Process index " << tt.first << "..." |
1041 |
1625 |
<< std::endl; |
1042 |
1625 |
addCarePairs(&tt.second, nullptr, arity, 0, n_pairs); |
1043 |
|
} |
1044 |
|
} |
1045 |
1265 |
Trace("sets-cg-summary") << "...done, # pairs = " << n_pairs << std::endl; |
1046 |
|
} |
1047 |
|
} |
1048 |
6390 |
} |
1049 |
|
|
1050 |
26245 |
bool TheorySetsPrivate::isCareArg(Node n, unsigned a) |
1051 |
|
{ |
1052 |
26245 |
if (d_equalityEngine->isTriggerTerm(n[a], THEORY_SETS)) |
1053 |
|
{ |
1054 |
13978 |
return true; |
1055 |
|
} |
1056 |
24534 |
else if ((n.getKind() == kind::MEMBER || n.getKind() == kind::SINGLETON) |
1057 |
36801 |
&& a == 0 && n[0].getType().isSet()) |
1058 |
|
{ |
1059 |
20 |
return true; |
1060 |
|
} |
1061 |
|
else |
1062 |
|
{ |
1063 |
12247 |
return false; |
1064 |
|
} |
1065 |
|
} |
1066 |
|
|
1067 |
|
/******************** Model generation ********************/ |
1068 |
|
/******************** Model generation ********************/ |
1069 |
|
/******************** Model generation ********************/ |
1070 |
|
|
1071 |
|
namespace { |
1072 |
|
/** |
1073 |
|
* This function is a helper function to print sets as |
1074 |
|
* Set A = { a0, a1, a2, } |
1075 |
|
* instead of |
1076 |
|
* (union (singleton a0) (union (singleton a1) (singleton a2))) |
1077 |
|
*/ |
1078 |
3266 |
void traceSetElementsRecursively(stringstream& stream, const Node& set) |
1079 |
|
{ |
1080 |
3266 |
Assert(set.getType().isSet()); |
1081 |
3266 |
if (set.getKind() == SINGLETON) |
1082 |
|
{ |
1083 |
2145 |
stream << set[0] << ", "; |
1084 |
|
} |
1085 |
3266 |
if (set.getKind() == UNION) |
1086 |
|
{ |
1087 |
763 |
traceSetElementsRecursively(stream, set[0]); |
1088 |
763 |
traceSetElementsRecursively(stream, set[1]); |
1089 |
|
} |
1090 |
3266 |
} |
1091 |
|
|
1092 |
1740 |
std::string traceElements(const Node& set) |
1093 |
|
{ |
1094 |
3480 |
std::stringstream stream; |
1095 |
1740 |
traceSetElementsRecursively(stream, set); |
1096 |
3480 |
return stream.str(); |
1097 |
|
} |
1098 |
|
|
1099 |
|
} // namespace |
1100 |
|
|
1101 |
4730 |
bool TheorySetsPrivate::collectModelValues(TheoryModel* m, |
1102 |
|
const std::set<Node>& termSet) |
1103 |
|
{ |
1104 |
4730 |
Trace("sets-model") << "Set collect model values" << std::endl; |
1105 |
|
|
1106 |
4730 |
NodeManager* nm = NodeManager::currentNM(); |
1107 |
9460 |
std::map<Node, Node> mvals; |
1108 |
|
// If cardinality is enabled, we need to use the ordered equivalence class |
1109 |
|
// list computed by the cardinality solver, where sets equivalence classes |
1110 |
|
// are assigned model values based on their position in the cardinality |
1111 |
|
// graph. |
1112 |
4730 |
const std::vector<Node>& sec = d_card_enabled |
1113 |
9389 |
? d_cardSolver->getOrderedSetsEqClasses() |
1114 |
9389 |
: d_state.getSetsEqClasses(); |
1115 |
4730 |
Valuation& val = getValuation(); |
1116 |
6512 |
for (int i = (int)(sec.size() - 1); i >= 0; i--) |
1117 |
|
{ |
1118 |
3564 |
Node eqc = sec[i]; |
1119 |
1782 |
if (termSet.find(eqc) == termSet.end()) |
1120 |
|
{ |
1121 |
84 |
Trace("sets-model") << "* Do not assign value for " << eqc |
1122 |
42 |
<< " since is not relevant." << std::endl; |
1123 |
|
} |
1124 |
|
else |
1125 |
|
{ |
1126 |
3480 |
std::vector<Node> els; |
1127 |
1740 |
bool is_base = !d_card_enabled || d_cardSolver->isModelValueBasic(eqc); |
1128 |
1740 |
if (is_base) |
1129 |
|
{ |
1130 |
3364 |
Trace("sets-model") |
1131 |
1682 |
<< "Collect elements of base eqc " << eqc << std::endl; |
1132 |
|
// members that must be in eqc |
1133 |
1682 |
const std::map<Node, Node>& emems = d_state.getMembers(eqc); |
1134 |
1682 |
if (!emems.empty()) |
1135 |
|
{ |
1136 |
2726 |
TypeNode elementType = eqc.getType().getSetElementType(); |
1137 |
3316 |
for (const std::pair<const Node, Node>& itmm : emems) |
1138 |
|
{ |
1139 |
3906 |
Trace("sets-model") |
1140 |
1953 |
<< "m->getRepresentative(" << itmm.first |
1141 |
1953 |
<< ")= " << m->getRepresentative(itmm.first) << std::endl; |
1142 |
3906 |
Node t = nm->mkSingleton(elementType, itmm.first); |
1143 |
1953 |
els.push_back(t); |
1144 |
|
} |
1145 |
|
} |
1146 |
|
} |
1147 |
1740 |
if (d_card_enabled) |
1148 |
|
{ |
1149 |
|
// make the slack elements for the equivalence class based on set |
1150 |
|
// cardinality |
1151 |
175 |
d_cardSolver->mkModelValueElementsFor(val, eqc, els, mvals, m); |
1152 |
|
} |
1153 |
|
|
1154 |
3480 |
Node rep = NormalForm::mkBop(kind::UNION, els, eqc.getType()); |
1155 |
1740 |
rep = Rewriter::rewrite(rep); |
1156 |
3480 |
Trace("sets-model") << "* Assign representative of " << eqc << " to " |
1157 |
1740 |
<< rep << std::endl; |
1158 |
1740 |
mvals[eqc] = rep; |
1159 |
1740 |
if (!m->assertEquality(eqc, rep, true)) |
1160 |
|
{ |
1161 |
|
return false; |
1162 |
|
} |
1163 |
1740 |
m->assertSkeleton(rep); |
1164 |
|
|
1165 |
|
// we add the element terms (singletons) as representatives to tell the |
1166 |
|
// model builder to evaluate them along with their union (rep). |
1167 |
|
// This is needed to account for cases when members and rep are not enough |
1168 |
|
// for the model builder to evaluate set terms. |
1169 |
|
// e.g. |
1170 |
|
// eqc(rep) = [(union (singleton skolem) (singleton 0))] |
1171 |
|
// eqc(skolem) = [0] |
1172 |
|
// The model builder would fail to evaluate rep as (singleton 0) |
1173 |
|
// if (singleton skolem) is not registered as a representative in the |
1174 |
|
// model |
1175 |
3816 |
for (const Node& el : els) |
1176 |
|
{ |
1177 |
2076 |
m->assertSkeleton(el); |
1178 |
|
} |
1179 |
|
|
1180 |
3480 |
Trace("sets-model") << "Set " << eqc << " = { " << traceElements(rep) |
1181 |
1740 |
<< " }" << std::endl; |
1182 |
|
} |
1183 |
|
} |
1184 |
|
|
1185 |
|
// handle slack elements constraints for finite types |
1186 |
4730 |
if (d_card_enabled) |
1187 |
|
{ |
1188 |
|
const std::map<TypeNode, std::vector<TNode> >& slackElements = |
1189 |
71 |
d_cardSolver->getFiniteTypeSlackElements(); |
1190 |
81 |
for (const auto& pair : slackElements) |
1191 |
|
{ |
1192 |
|
const std::vector<Node>& members = |
1193 |
10 |
d_cardSolver->getFiniteTypeMembers(pair.first); |
1194 |
10 |
m->setAssignmentExclusionSetGroup(pair.second, members); |
1195 |
20 |
Trace("sets-model") << "ExclusionSet: Group " << pair.second |
1196 |
10 |
<< " is excluded from set" << members << std::endl; |
1197 |
|
} |
1198 |
|
} |
1199 |
4730 |
return true; |
1200 |
|
} |
1201 |
|
|
1202 |
|
/********************** Helper functions ***************************/ |
1203 |
|
/********************** Helper functions ***************************/ |
1204 |
|
/********************** Helper functions ***************************/ |
1205 |
|
|
1206 |
2807 |
Node mkAnd(const std::vector<TNode>& conjunctions) |
1207 |
|
{ |
1208 |
2807 |
Assert(conjunctions.size() > 0); |
1209 |
|
|
1210 |
5614 |
std::set<TNode> all; |
1211 |
12800 |
for (unsigned i = 0; i < conjunctions.size(); ++i) |
1212 |
|
{ |
1213 |
19986 |
TNode t = conjunctions[i]; |
1214 |
9993 |
if (t.getKind() == kind::AND) |
1215 |
|
{ |
1216 |
426 |
for (TNode::iterator child_it = t.begin(); child_it != t.end(); |
1217 |
|
++child_it) |
1218 |
|
{ |
1219 |
284 |
Assert((*child_it).getKind() != kind::AND); |
1220 |
284 |
all.insert(*child_it); |
1221 |
|
} |
1222 |
|
} |
1223 |
|
else |
1224 |
|
{ |
1225 |
9851 |
all.insert(t); |
1226 |
|
} |
1227 |
|
} |
1228 |
|
|
1229 |
2807 |
Assert(all.size() > 0); |
1230 |
2807 |
if (all.size() == 1) |
1231 |
|
{ |
1232 |
|
// All the same, or just one |
1233 |
367 |
return conjunctions[0]; |
1234 |
|
} |
1235 |
|
|
1236 |
4880 |
NodeBuilder conjunction(kind::AND); |
1237 |
2440 |
std::set<TNode>::const_iterator it = all.begin(); |
1238 |
2440 |
std::set<TNode>::const_iterator it_end = all.end(); |
1239 |
20776 |
while (it != it_end) |
1240 |
|
{ |
1241 |
9168 |
conjunction << *it; |
1242 |
9168 |
++it; |
1243 |
|
} |
1244 |
2440 |
return conjunction; |
1245 |
|
} /* mkAnd() */ |
1246 |
|
|
1247 |
4730 |
Valuation& TheorySetsPrivate::getValuation() { return d_external.d_valuation; } |
1248 |
|
|
1249 |
2807 |
Node TheorySetsPrivate::explain(TNode literal) |
1250 |
|
{ |
1251 |
2807 |
Debug("sets") << "TheorySetsPrivate::explain(" << literal << ")" << std::endl; |
1252 |
|
|
1253 |
2807 |
bool polarity = literal.getKind() != kind::NOT; |
1254 |
5614 |
TNode atom = polarity ? literal : literal[0]; |
1255 |
5614 |
std::vector<TNode> assumptions; |
1256 |
|
|
1257 |
2807 |
if (atom.getKind() == kind::EQUAL) |
1258 |
|
{ |
1259 |
1703 |
d_equalityEngine->explainEquality(atom[0], atom[1], polarity, assumptions); |
1260 |
|
} |
1261 |
1104 |
else if (atom.getKind() == kind::MEMBER) |
1262 |
|
{ |
1263 |
1104 |
d_equalityEngine->explainPredicate(atom, polarity, assumptions); |
1264 |
|
} |
1265 |
|
else |
1266 |
|
{ |
1267 |
|
Debug("sets") << "unhandled: " << literal << "; (" << atom << ", " |
1268 |
|
<< polarity << "); kind" << atom.getKind() << std::endl; |
1269 |
|
Unhandled(); |
1270 |
|
} |
1271 |
|
|
1272 |
5614 |
return mkAnd(assumptions); |
1273 |
|
} |
1274 |
|
|
1275 |
75657 |
void TheorySetsPrivate::preRegisterTerm(TNode node) |
1276 |
|
{ |
1277 |
151314 |
Debug("sets") << "TheorySetsPrivate::preRegisterTerm(" << node << ")" |
1278 |
75657 |
<< std::endl; |
1279 |
75657 |
switch (node.getKind()) |
1280 |
|
{ |
1281 |
41548 |
case kind::EQUAL: |
1282 |
|
case kind::MEMBER: |
1283 |
|
{ |
1284 |
|
// add trigger predicate for equality and membership |
1285 |
41548 |
d_equalityEngine->addTriggerPredicate(node); |
1286 |
|
} |
1287 |
41548 |
break; |
1288 |
32 |
case kind::JOIN_IMAGE: |
1289 |
|
{ |
1290 |
|
// these are logic exceptions, not type checking exceptions |
1291 |
32 |
if (node[1].getKind() != kind::CONST_RATIONAL) |
1292 |
|
{ |
1293 |
|
throw LogicException( |
1294 |
|
"JoinImage cardinality constraint must be a constant"); |
1295 |
|
} |
1296 |
64 |
cvc5::Rational r(INT_MAX); |
1297 |
32 |
if (node[1].getConst<Rational>() > r) |
1298 |
|
{ |
1299 |
|
throw LogicException( |
1300 |
|
"JoinImage Exceeded INT_MAX in cardinality constraint"); |
1301 |
|
} |
1302 |
32 |
if (node[1].getConst<Rational>().getNumerator().getSignedInt() < 0) |
1303 |
|
{ |
1304 |
|
throw LogicException( |
1305 |
|
"JoinImage cardinality constraint must be non-negative"); |
1306 |
32 |
} |
1307 |
|
} |
1308 |
32 |
break; |
1309 |
34077 |
default: d_equalityEngine->addTerm(node); break; |
1310 |
|
} |
1311 |
75657 |
} |
1312 |
|
|
1313 |
45567 |
TrustNode TheorySetsPrivate::ppRewrite(Node node, |
1314 |
|
std::vector<SkolemLemma>& lems) |
1315 |
|
{ |
1316 |
45567 |
Debug("sets-proc") << "ppRewrite : " << node << std::endl; |
1317 |
|
|
1318 |
45567 |
switch (node.getKind()) |
1319 |
|
{ |
1320 |
6 |
case kind::CHOOSE: return expandChooseOperator(node, lems); |
1321 |
17 |
case kind::IS_SINGLETON: return expandIsSingletonOperator(node); |
1322 |
45544 |
default: return TrustNode::null(); |
1323 |
|
} |
1324 |
|
} |
1325 |
|
|
1326 |
6 |
TrustNode TheorySetsPrivate::expandChooseOperator( |
1327 |
|
const Node& node, std::vector<SkolemLemma>& lems) |
1328 |
|
{ |
1329 |
6 |
Assert(node.getKind() == CHOOSE); |
1330 |
|
|
1331 |
|
// (choose A) is expanded as |
1332 |
|
// (witness ((x elementType)) |
1333 |
|
// (ite |
1334 |
|
// (= A (as emptyset setType)) |
1335 |
|
// (= x chooseUf(A)) |
1336 |
|
// (and (member x A) (= x chooseUf(A))) |
1337 |
|
|
1338 |
6 |
NodeManager* nm = NodeManager::currentNM(); |
1339 |
12 |
Node set = node[0]; |
1340 |
12 |
TypeNode setType = set.getType(); |
1341 |
12 |
Node chooseSkolem = getChooseFunction(setType); |
1342 |
12 |
Node apply = NodeManager::currentNM()->mkNode(APPLY_UF, chooseSkolem, set); |
1343 |
|
|
1344 |
12 |
Node witnessVariable = nm->mkBoundVar(setType.getSetElementType()); |
1345 |
|
|
1346 |
12 |
Node equal = witnessVariable.eqNode(apply); |
1347 |
12 |
Node emptySet = nm->mkConst(EmptySet(setType)); |
1348 |
12 |
Node isEmpty = set.eqNode(emptySet); |
1349 |
12 |
Node member = nm->mkNode(MEMBER, witnessVariable, set); |
1350 |
12 |
Node memberAndEqual = member.andNode(equal); |
1351 |
12 |
Node ite = nm->mkNode(ITE, isEmpty, equal, memberAndEqual); |
1352 |
6 |
SkolemManager* sm = nm->getSkolemManager(); |
1353 |
12 |
Node ret = sm->mkSkolem(witnessVariable, ite, "kSetChoose"); |
1354 |
6 |
lems.push_back(SkolemLemma(ret, nullptr)); |
1355 |
12 |
return TrustNode::mkTrustRewrite(node, ret, nullptr); |
1356 |
|
} |
1357 |
|
|
1358 |
17 |
TrustNode TheorySetsPrivate::expandIsSingletonOperator(const Node& node) |
1359 |
|
{ |
1360 |
17 |
Assert(node.getKind() == IS_SINGLETON); |
1361 |
|
|
1362 |
|
// we call the rewriter here to handle the pattern |
1363 |
|
// (is_singleton (singleton x)) because the rewriter is called after expansion |
1364 |
34 |
Node rewritten = Rewriter::rewrite(node); |
1365 |
17 |
if (rewritten.getKind() != IS_SINGLETON) |
1366 |
|
{ |
1367 |
|
return TrustNode::mkTrustRewrite(node, rewritten, nullptr); |
1368 |
|
} |
1369 |
|
|
1370 |
|
// (is_singleton A) is expanded as |
1371 |
|
// (exists ((x: T)) (= A (singleton x))) |
1372 |
|
// where T is the sort of elements of A |
1373 |
|
|
1374 |
17 |
NodeManager* nm = NodeManager::currentNM(); |
1375 |
34 |
Node set = rewritten[0]; |
1376 |
|
|
1377 |
17 |
std::map<Node, Node>::iterator it = d_isSingletonNodes.find(rewritten); |
1378 |
|
|
1379 |
17 |
if (it != d_isSingletonNodes.end()) |
1380 |
|
{ |
1381 |
|
return TrustNode::mkTrustRewrite(rewritten, it->second, nullptr); |
1382 |
|
} |
1383 |
|
|
1384 |
34 |
TypeNode setType = set.getType(); |
1385 |
34 |
Node boundVar = nm->mkBoundVar(setType.getSetElementType()); |
1386 |
34 |
Node singleton = nm->mkSingleton(setType.getSetElementType(), boundVar); |
1387 |
34 |
Node equal = set.eqNode(singleton); |
1388 |
34 |
std::vector<Node> variables = {boundVar}; |
1389 |
34 |
Node boundVars = nm->mkNode(BOUND_VAR_LIST, variables); |
1390 |
34 |
Node exists = nm->mkNode(kind::EXISTS, boundVars, equal); |
1391 |
17 |
d_isSingletonNodes[rewritten] = exists; |
1392 |
|
|
1393 |
17 |
return TrustNode::mkTrustRewrite(node, exists, nullptr); |
1394 |
|
} |
1395 |
|
|
1396 |
6 |
Node TheorySetsPrivate::getChooseFunction(const TypeNode& setType) |
1397 |
|
{ |
1398 |
6 |
std::map<TypeNode, Node>::iterator it = d_chooseFunctions.find(setType); |
1399 |
6 |
if (it != d_chooseFunctions.end()) |
1400 |
|
{ |
1401 |
|
return it->second; |
1402 |
|
} |
1403 |
|
|
1404 |
6 |
NodeManager* nm = NodeManager::currentNM(); |
1405 |
6 |
SkolemManager* sm = nm->getSkolemManager(); |
1406 |
12 |
TypeNode chooseUf = nm->mkFunctionType(setType, setType.getSetElementType()); |
1407 |
12 |
stringstream stream; |
1408 |
6 |
stream << "chooseUf" << setType.getId(); |
1409 |
12 |
string name = stream.str(); |
1410 |
|
Node chooseSkolem = sm->mkDummySkolem( |
1411 |
12 |
name, chooseUf, "choose function", NodeManager::SKOLEM_EXACT_NAME); |
1412 |
6 |
d_chooseFunctions[setType] = chooseSkolem; |
1413 |
6 |
return chooseSkolem; |
1414 |
|
} |
1415 |
|
|
1416 |
15241 |
void TheorySetsPrivate::presolve() { d_state.reset(); } |
1417 |
|
|
1418 |
|
} // namespace sets |
1419 |
|
} // namespace theory |
1420 |
29517 |
} // namespace cvc5 |