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