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