Update copyright headers.
[cvc5.git] / src / theory / sets / theory_sets_private.cpp
1 /********************* */
2 /*! \file theory_sets_private.cpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Mudathir Mohamed, Kshitij Bansal
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2020 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.\endverbatim
11 **
12 ** \brief Sets theory implementation.
13 **
14 ** Sets theory implementation.
15 **/
16
17 #include "theory/sets/theory_sets_private.h"
18
19 #include <algorithm>
20
21 #include "expr/emptyset.h"
22 #include "expr/node_algorithm.h"
23 #include "options/sets_options.h"
24 #include "smt/smt_statistics_registry.h"
25 #include "theory/sets/normal_form.h"
26 #include "theory/sets/theory_sets.h"
27 #include "theory/theory_model.h"
28 #include "util/result.h"
29
30 using namespace std;
31 using namespace CVC4::kind;
32
33 namespace CVC4 {
34 namespace theory {
35 namespace sets {
36
37 TheorySetsPrivate::TheorySetsPrivate(TheorySets& external,
38 context::Context* c,
39 context::UserContext* u)
40 : d_members(c),
41 d_deq(c),
42 d_termProcessed(u),
43 d_keep(c),
44 d_full_check_incomplete(false),
45 d_external(external),
46 d_notify(*this),
47 d_equalityEngine(d_notify, c, "theory::sets::ee", true),
48 d_state(*this, d_equalityEngine, c, u),
49 d_im(*this, d_state, d_equalityEngine, c, u),
50 d_rels(new TheorySetsRels(d_state, d_im, d_equalityEngine, u)),
51 d_cardSolver(
52 new CardinalityExtension(d_state, d_im, d_equalityEngine, c, u)),
53 d_rels_enabled(false),
54 d_card_enabled(false)
55 {
56 d_true = NodeManager::currentNM()->mkConst(true);
57 d_false = NodeManager::currentNM()->mkConst(false);
58 d_zero = NodeManager::currentNM()->mkConst(Rational(0));
59
60 d_equalityEngine.addFunctionKind(kind::SINGLETON);
61 d_equalityEngine.addFunctionKind(kind::UNION);
62 d_equalityEngine.addFunctionKind(kind::INTERSECTION);
63 d_equalityEngine.addFunctionKind(kind::SETMINUS);
64
65 d_equalityEngine.addFunctionKind(kind::MEMBER);
66 d_equalityEngine.addFunctionKind(kind::SUBSET);
67 }
68
69 TheorySetsPrivate::~TheorySetsPrivate()
70 {
71 for (std::pair<const Node, EqcInfo*>& current_pair : d_eqc_info)
72 {
73 delete current_pair.second;
74 }
75 }
76
77 void TheorySetsPrivate::eqNotifyNewClass(TNode t)
78 {
79 if (t.getKind() == kind::SINGLETON || t.getKind() == kind::EMPTYSET)
80 {
81 EqcInfo* e = getOrMakeEqcInfo(t, true);
82 e->d_singleton = t;
83 }
84 }
85
86 void TheorySetsPrivate::eqNotifyPreMerge(TNode t1, TNode t2) {}
87
88 void TheorySetsPrivate::eqNotifyPostMerge(TNode t1, TNode t2)
89 {
90 if (!d_state.isInConflict())
91 {
92 Trace("sets-prop-debug")
93 << "Merge " << t1 << " and " << t2 << "..." << std::endl;
94 Node s1, s2;
95 EqcInfo* e2 = getOrMakeEqcInfo(t2);
96 if (e2)
97 {
98 s2 = e2->d_singleton;
99 EqcInfo* e1 = getOrMakeEqcInfo(t1);
100 Trace("sets-prop-debug") << "Merging singletons..." << std::endl;
101 if (e1)
102 {
103 s1 = e1->d_singleton;
104 if (!s1.isNull() && !s2.isNull())
105 {
106 if (s1.getKind() == s2.getKind())
107 {
108 Trace("sets-prop") << "Propagate eq inference : " << s1
109 << " == " << s2 << std::endl;
110 // infer equality between elements of singleton
111 Node exp = s1.eqNode(s2);
112 Node eq = s1[0].eqNode(s2[0]);
113 d_keep.insert(exp);
114 d_keep.insert(eq);
115 assertFact(eq, exp);
116 }
117 else
118 {
119 // singleton equal to emptyset, conflict
120 Trace("sets-prop")
121 << "Propagate conflict : " << s1 << " == " << s2 << std::endl;
122 conflict(s1, s2);
123 return;
124 }
125 }
126 }
127 else
128 {
129 // copy information
130 e1 = getOrMakeEqcInfo(t1, true);
131 e1->d_singleton.set(e2->d_singleton);
132 }
133 }
134 // merge membership list
135 Trace("sets-prop-debug") << "Copying membership list..." << std::endl;
136 NodeIntMap::iterator mem_i2 = d_members.find(t2);
137 if (mem_i2 != d_members.end())
138 {
139 NodeIntMap::iterator mem_i1 = d_members.find(t1);
140 int n_members = 0;
141 if (mem_i1 != d_members.end())
142 {
143 n_members = (*mem_i1).second;
144 }
145 for (int i = 0; i < (*mem_i2).second; i++)
146 {
147 Assert(i < (int)d_members_data[t2].size()
148 && d_members_data[t2][i].getKind() == kind::MEMBER);
149 Node m2 = d_members_data[t2][i];
150 // check if redundant
151 bool add = true;
152 for (int j = 0; j < n_members; j++)
153 {
154 Assert(j < (int)d_members_data[t1].size()
155 && d_members_data[t1][j].getKind() == kind::MEMBER);
156 if (d_state.areEqual(m2[0], d_members_data[t1][j][0]))
157 {
158 add = false;
159 break;
160 }
161 }
162 if (add)
163 {
164 if (!s1.isNull() && s2.isNull())
165 {
166 Assert(m2[1].getType().isComparableTo(s1.getType()));
167 Assert(d_state.areEqual(m2[1], s1));
168 Node exp = NodeManager::currentNM()->mkNode(
169 kind::AND, m2[1].eqNode(s1), m2);
170 if (s1.getKind() == kind::SINGLETON)
171 {
172 if (s1[0] != m2[0])
173 {
174 Node eq = s1[0].eqNode(m2[0]);
175 d_keep.insert(exp);
176 d_keep.insert(eq);
177 Trace("sets-prop") << "Propagate eq-mem eq inference : " << exp
178 << " => " << eq << std::endl;
179 assertFact(eq, exp);
180 }
181 }
182 else
183 {
184 // conflict
185 Trace("sets-prop")
186 << "Propagate eq-mem conflict : " << exp << std::endl;
187 d_state.setConflict(exp);
188 return;
189 }
190 }
191 if (n_members < (int)d_members_data[t1].size())
192 {
193 d_members_data[t1][n_members] = m2;
194 }
195 else
196 {
197 d_members_data[t1].push_back(m2);
198 }
199 n_members++;
200 }
201 }
202 d_members[t1] = n_members;
203 }
204 }
205 }
206
207 void TheorySetsPrivate::eqNotifyDisequal(TNode t1, TNode t2, TNode reason)
208 {
209 if (t1.getType().isSet())
210 {
211 Node eq = t1.eqNode(t2);
212 if (d_deq.find(eq) == d_deq.end())
213 {
214 d_deq[eq] = true;
215 }
216 }
217 }
218
219 TheorySetsPrivate::EqcInfo::EqcInfo(context::Context* c) : d_singleton(c) {}
220
221 TheorySetsPrivate::EqcInfo* TheorySetsPrivate::getOrMakeEqcInfo(TNode n,
222 bool doMake)
223 {
224 std::map<Node, EqcInfo*>::iterator eqc_i = d_eqc_info.find(n);
225 if (eqc_i == d_eqc_info.end())
226 {
227 EqcInfo* ei = NULL;
228 if (doMake)
229 {
230 ei = new EqcInfo(d_external.getSatContext());
231 d_eqc_info[n] = ei;
232 }
233 return ei;
234 }
235 else
236 {
237 return eqc_i->second;
238 }
239 }
240
241 bool TheorySetsPrivate::areCareDisequal(Node a, Node b)
242 {
243 if (d_equalityEngine.isTriggerTerm(a, THEORY_SETS)
244 && d_equalityEngine.isTriggerTerm(b, THEORY_SETS))
245 {
246 TNode a_shared =
247 d_equalityEngine.getTriggerTermRepresentative(a, THEORY_SETS);
248 TNode b_shared =
249 d_equalityEngine.getTriggerTermRepresentative(b, THEORY_SETS);
250 EqualityStatus eqStatus =
251 d_external.d_valuation.getEqualityStatus(a_shared, b_shared);
252 if (eqStatus == EQUALITY_FALSE_AND_PROPAGATED || eqStatus == EQUALITY_FALSE
253 || eqStatus == EQUALITY_FALSE_IN_MODEL)
254 {
255 return true;
256 }
257 }
258 return false;
259 }
260
261 bool TheorySetsPrivate::isMember(Node x, Node s)
262 {
263 Assert(d_equalityEngine.hasTerm(s)
264 && d_equalityEngine.getRepresentative(s) == s);
265 NodeIntMap::iterator mem_i = d_members.find(s);
266 if (mem_i != d_members.end())
267 {
268 for (int i = 0; i < (*mem_i).second; i++)
269 {
270 if (d_state.areEqual(d_members_data[s][i][0], x))
271 {
272 return true;
273 }
274 }
275 }
276 return false;
277 }
278
279 bool TheorySetsPrivate::assertFact(Node fact, Node exp)
280 {
281 Trace("sets-assert") << "TheorySets::assertFact : " << fact
282 << ", exp = " << exp << std::endl;
283 bool polarity = fact.getKind() != kind::NOT;
284 TNode atom = polarity ? fact : fact[0];
285 if (!d_state.isEntailed(atom, polarity))
286 {
287 if (atom.getKind() == kind::EQUAL)
288 {
289 d_equalityEngine.assertEquality(atom, polarity, exp);
290 }
291 else
292 {
293 d_equalityEngine.assertPredicate(atom, polarity, exp);
294 }
295 if (!d_state.isInConflict())
296 {
297 if (atom.getKind() == kind::MEMBER && polarity)
298 {
299 // check if set has a value, if so, we can propagate
300 Node r = d_equalityEngine.getRepresentative(atom[1]);
301 EqcInfo* e = getOrMakeEqcInfo(r, true);
302 if (e)
303 {
304 Node s = e->d_singleton;
305 if (!s.isNull())
306 {
307 Node pexp = NodeManager::currentNM()->mkNode(
308 kind::AND, atom, atom[1].eqNode(s));
309 d_keep.insert(pexp);
310 if (s.getKind() == kind::SINGLETON)
311 {
312 if (s[0] != atom[0])
313 {
314 Trace("sets-prop")
315 << "Propagate mem-eq : " << pexp << std::endl;
316 Node eq = s[0].eqNode(atom[0]);
317 d_keep.insert(eq);
318 assertFact(eq, pexp);
319 }
320 }
321 else
322 {
323 Trace("sets-prop")
324 << "Propagate mem-eq conflict : " << pexp << std::endl;
325 d_state.setConflict(pexp);
326 }
327 }
328 }
329 // add to membership list
330 NodeIntMap::iterator mem_i = d_members.find(r);
331 int n_members = 0;
332 if (mem_i != d_members.end())
333 {
334 n_members = (*mem_i).second;
335 }
336 d_members[r] = n_members + 1;
337 if (n_members < (int)d_members_data[r].size())
338 {
339 d_members_data[r][n_members] = atom;
340 }
341 else
342 {
343 d_members_data[r].push_back(atom);
344 }
345 }
346 }
347 return true;
348 }
349 else
350 {
351 return false;
352 }
353 }
354
355 void TheorySetsPrivate::fullEffortReset()
356 {
357 Assert(d_equalityEngine.consistent());
358 d_full_check_incomplete = false;
359 d_most_common_type.clear();
360 d_most_common_type_term.clear();
361 d_card_enabled = false;
362 d_rels_enabled = false;
363 // reset the state object
364 d_state.reset();
365 // reset the inference manager
366 d_im.reset();
367 // reset the cardinality solver
368 d_cardSolver->reset();
369 }
370
371 void TheorySetsPrivate::fullEffortCheck()
372 {
373 Trace("sets") << "----- Full effort check ------" << std::endl;
374 do
375 {
376 Assert(!d_im.hasPendingLemmas() || d_im.hasProcessed());
377
378 Trace("sets") << "...iterate full effort check..." << std::endl;
379 fullEffortReset();
380
381 Trace("sets-eqc") << "Equality Engine:" << std::endl;
382 std::map<TypeNode, unsigned> eqcTypeCount;
383 eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
384 while (!eqcs_i.isFinished())
385 {
386 Node eqc = (*eqcs_i);
387 bool isSet = false;
388 TypeNode tn = eqc.getType();
389 d_state.registerEqc(tn, eqc);
390 eqcTypeCount[tn]++;
391 // common type node and term
392 TypeNode tnc;
393 Node tnct;
394 if (tn.isSet())
395 {
396 isSet = true;
397 tnc = tn.getSetElementType();
398 tnct = eqc;
399 }
400 Trace("sets-eqc") << "[" << eqc << "] : ";
401 eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, &d_equalityEngine);
402 while (!eqc_i.isFinished())
403 {
404 Node n = (*eqc_i);
405 if (n != eqc)
406 {
407 Trace("sets-eqc") << n << " ";
408 }
409 TypeNode tnn = n.getType();
410 if (isSet)
411 {
412 Assert(tnn.isSet());
413 TypeNode tnnel = tnn.getSetElementType();
414 tnc = TypeNode::mostCommonTypeNode(tnc, tnnel);
415 Assert(!tnc.isNull());
416 // update the common type term
417 if (tnc == tnnel)
418 {
419 tnct = n;
420 }
421 }
422 // register it with the state
423 d_state.registerTerm(eqc, tnn, n);
424 if (n.getKind() == kind::CARD)
425 {
426 d_card_enabled = true;
427 // register it with the cardinality solver
428 d_cardSolver->registerTerm(n);
429 // if we do not handle the kind, set incomplete
430 Kind nk = n[0].getKind();
431 // some kinds of cardinality we cannot handle
432 if (d_rels->isRelationKind(nk))
433 {
434 d_full_check_incomplete = true;
435 Trace("sets-incomplete")
436 << "Sets : incomplete because of " << n << "." << std::endl;
437 // TODO (#1124): The issue can be divided into 4 parts
438 // 1- Supporting the universe cardinality for finite types with
439 // finite cardinality (done)
440 // 2- Supporting the universe cardinality for uninterpreted sorts
441 // with finite-model-find (pending) See the implementation of
442 // CardinalityExtension::checkCardinalityExtended
443 // 3- Supporting the universe cardinality for non-finite types
444 // (done)
445 // 4- Supporting cardinality for relations (hard)
446 }
447 }
448 else
449 {
450 if (d_rels->isRelationKind(n.getKind()))
451 {
452 d_rels_enabled = true;
453 }
454 }
455 ++eqc_i;
456 }
457 if (isSet)
458 {
459 Assert(tnct.getType().getSetElementType() == tnc);
460 d_most_common_type[eqc] = tnc;
461 d_most_common_type_term[eqc] = tnct;
462 }
463 Trace("sets-eqc") << std::endl;
464 ++eqcs_i;
465 }
466
467 Trace("sets-eqc") << "...finished equality engine." << std::endl;
468
469 if (Trace.isOn("sets-state"))
470 {
471 Trace("sets-state") << "Equivalence class counters:" << std::endl;
472 for (std::pair<const TypeNode, unsigned>& ec : eqcTypeCount)
473 {
474 Trace("sets-state")
475 << " " << ec.first << " -> " << ec.second << std::endl;
476 }
477 }
478
479 // We may have sent lemmas while registering the terms in the loop above,
480 // e.g. the cardinality solver.
481 if (d_im.hasProcessed())
482 {
483 continue;
484 }
485 if (Trace.isOn("sets-mem"))
486 {
487 const std::vector<Node>& sec = d_state.getSetsEqClasses();
488 for (const Node& s : sec)
489 {
490 Trace("sets-mem") << "Eqc " << s << " : ";
491 const std::map<Node, Node>& smem = d_state.getMembers(s);
492 if (!smem.empty())
493 {
494 Trace("sets-mem") << "Memberships : ";
495 for (const std::pair<const Node, Node>& it2 : smem)
496 {
497 Trace("sets-mem") << it2.first << " ";
498 }
499 }
500 Node ss = d_state.getSingletonEqClass(s);
501 if (!ss.isNull())
502 {
503 Trace("sets-mem") << " : Singleton : " << ss;
504 }
505 Trace("sets-mem") << std::endl;
506 }
507 }
508 // check subtypes
509 checkSubtypes();
510 d_im.flushPendingLemmas(true);
511 if (d_im.hasProcessed())
512 {
513 continue;
514 }
515 // check downwards closure
516 checkDownwardsClosure();
517 d_im.flushPendingLemmas();
518 if (d_im.hasProcessed())
519 {
520 continue;
521 }
522 // check upwards closure
523 checkUpwardsClosure();
524 d_im.flushPendingLemmas();
525 if (d_im.hasProcessed())
526 {
527 continue;
528 }
529 // check disequalities
530 checkDisequalities();
531 d_im.flushPendingLemmas();
532 if (d_im.hasProcessed())
533 {
534 continue;
535 }
536 // check reduce comprehensions
537 checkReduceComprehensions();
538 d_im.flushPendingLemmas();
539 if (d_im.hasProcessed())
540 {
541 continue;
542 }
543 if (d_card_enabled)
544 {
545 // call the check method of the cardinality solver
546 d_cardSolver->check();
547 if (d_im.hasProcessed())
548 {
549 continue;
550 }
551 }
552 if (d_rels_enabled)
553 {
554 // call the check method of the relations solver
555 d_rels->check(Theory::EFFORT_FULL);
556 }
557 } while (!d_im.hasSentLemma() && !d_state.isInConflict()
558 && d_im.hasAddedFact());
559 Assert(!d_im.hasPendingLemmas() || d_im.hasProcessed());
560 Trace("sets") << "----- End full effort check, conflict="
561 << d_state.isInConflict() << ", lemma=" << d_im.hasSentLemma()
562 << std::endl;
563 }
564
565 void TheorySetsPrivate::checkSubtypes()
566 {
567 Trace("sets") << "TheorySetsPrivate: check Subtypes..." << std::endl;
568 const std::vector<Node>& sec = d_state.getSetsEqClasses();
569 for (const Node& s : sec)
570 {
571 TypeNode mct = d_most_common_type[s];
572 Assert(!mct.isNull());
573 const std::map<Node, Node>& smems = d_state.getMembers(s);
574 if (!smems.empty())
575 {
576 for (const std::pair<const Node, Node>& it2 : smems)
577 {
578 Trace("sets") << " check subtype " << it2.first << " " << it2.second
579 << std::endl;
580 Trace("sets") << " types : " << it2.first.getType() << " " << mct
581 << std::endl;
582 if (!it2.first.getType().isSubtypeOf(mct))
583 {
584 Node mctt = d_most_common_type_term[s];
585 Assert(!mctt.isNull());
586 Trace("sets") << " most common type term is " << mctt << std::endl;
587 std::vector<Node> exp;
588 exp.push_back(it2.second);
589 Assert(d_state.areEqual(mctt, it2.second[1]));
590 exp.push_back(mctt.eqNode(it2.second[1]));
591 Node tc_k = d_state.getTypeConstraintSkolem(it2.first, mct);
592 if (!tc_k.isNull())
593 {
594 Node etc = tc_k.eqNode(it2.first);
595 d_im.assertInference(etc, exp, "subtype-clash");
596 if (d_state.isInConflict())
597 {
598 return;
599 }
600 }
601 }
602 }
603 }
604 }
605 Trace("sets") << "TheorySetsPrivate: finished." << std::endl;
606 }
607
608 void TheorySetsPrivate::checkDownwardsClosure()
609 {
610 Trace("sets") << "TheorySetsPrivate: check downwards closure..." << std::endl;
611 // downwards closure
612 const std::vector<Node>& sec = d_state.getSetsEqClasses();
613 for (const Node& s : sec)
614 {
615 const std::vector<Node>& nvsets = d_state.getNonVariableSets(s);
616 if (!nvsets.empty())
617 {
618 const std::map<Node, Node>& smem = d_state.getMembers(s);
619 for (const Node& nv : nvsets)
620 {
621 if (!d_state.isCongruent(nv))
622 {
623 for (const std::pair<const Node, Node>& it2 : smem)
624 {
625 Node mem = it2.second;
626 Node eq_set = nv;
627 Assert(d_equalityEngine.areEqual(mem[1], eq_set));
628 if (mem[1] != eq_set)
629 {
630 Trace("sets-debug") << "Downwards closure based on " << mem
631 << ", eq_set = " << eq_set << std::endl;
632 if (!options::setsProxyLemmas())
633 {
634 Node nmem = NodeManager::currentNM()->mkNode(
635 kind::MEMBER, mem[0], eq_set);
636 nmem = Rewriter::rewrite(nmem);
637 std::vector<Node> exp;
638 exp.push_back(mem);
639 exp.push_back(mem[1].eqNode(eq_set));
640 d_im.assertInference(nmem, exp, "downc");
641 if (d_state.isInConflict())
642 {
643 return;
644 }
645 }
646 else
647 {
648 // use proxy set
649 Node k = d_state.getProxy(eq_set);
650 Node pmem =
651 NodeManager::currentNM()->mkNode(kind::MEMBER, mem[0], k);
652 Node nmem = NodeManager::currentNM()->mkNode(
653 kind::MEMBER, mem[0], eq_set);
654 nmem = Rewriter::rewrite(nmem);
655 std::vector<Node> exp;
656 if (d_state.areEqual(mem, pmem))
657 {
658 exp.push_back(pmem);
659 }
660 else
661 {
662 nmem = NodeManager::currentNM()->mkNode(
663 kind::OR, pmem.negate(), nmem);
664 }
665 d_im.assertInference(nmem, exp, "downc");
666 }
667 }
668 }
669 }
670 }
671 }
672 }
673 }
674
675 void TheorySetsPrivate::checkUpwardsClosure()
676 {
677 // upwards closure
678 NodeManager* nm = NodeManager::currentNM();
679 const std::map<Kind, std::map<Node, std::map<Node, Node> > >& boi =
680 d_state.getBinaryOpIndex();
681 for (const std::pair<const Kind, std::map<Node, std::map<Node, Node> > >&
682 itb : boi)
683 {
684 Kind k = itb.first;
685 Trace("sets") << "TheorySetsPrivate: check upwards closure " << k << "..."
686 << std::endl;
687 for (const std::pair<const Node, std::map<Node, Node> >& it : itb.second)
688 {
689 Node r1 = it.first;
690 // see if there are members in first argument r1
691 const std::map<Node, Node>& r1mem = d_state.getMembers(r1);
692 if (!r1mem.empty() || k == kind::UNION)
693 {
694 for (const std::pair<const Node, Node>& it2 : it.second)
695 {
696 Node r2 = it2.first;
697 Node term = it2.second;
698 // see if there are members in second argument
699 const std::map<Node, Node>& r2mem = d_state.getMembers(r2);
700 const std::map<Node, Node>& r2nmem = d_state.getNegativeMembers(r2);
701 if (!r2mem.empty() || k != kind::INTERSECTION)
702 {
703 Trace("sets-debug")
704 << "Checking " << term << ", members = " << (!r1mem.empty())
705 << ", " << (!r2mem.empty()) << std::endl;
706 // for all members of r1
707 if (!r1mem.empty())
708 {
709 for (const std::pair<const Node, Node>& itm1m : r1mem)
710 {
711 Node xr = itm1m.first;
712 Node x = itm1m.second[0];
713 Trace("sets-debug") << "checking membership " << xr << " "
714 << itm1m.second << std::endl;
715 std::vector<Node> exp;
716 exp.push_back(itm1m.second);
717 d_state.addEqualityToExp(term[0], itm1m.second[1], exp);
718 bool valid = false;
719 int inferType = 0;
720 if (k == kind::UNION)
721 {
722 valid = true;
723 }
724 else if (k == kind::INTERSECTION)
725 {
726 // conclude x is in term
727 // if also existing in members of r2
728 std::map<Node, Node>::const_iterator itm = r2mem.find(xr);
729 if (itm != r2mem.end())
730 {
731 exp.push_back(itm->second);
732 d_state.addEqualityToExp(term[1], itm->second[1], exp);
733 d_state.addEqualityToExp(x, itm->second[0], exp);
734 valid = true;
735 }
736 else
737 {
738 // if not, check whether it is definitely not a member, if
739 // unknown, split
740 if (r2nmem.find(xr) == r2nmem.end())
741 {
742 exp.push_back(nm->mkNode(kind::MEMBER, x, term[1]));
743 valid = true;
744 inferType = 1;
745 }
746 }
747 }
748 else
749 {
750 Assert(k == kind::SETMINUS);
751 std::map<Node, Node>::const_iterator itm = r2mem.find(xr);
752 if (itm == r2mem.end())
753 {
754 // must add lemma for set minus since non-membership in this
755 // case is not explained
756 exp.push_back(
757 nm->mkNode(kind::MEMBER, x, term[1]).negate());
758 valid = true;
759 inferType = 1;
760 }
761 }
762 if (valid)
763 {
764 Node rr = d_equalityEngine.getRepresentative(term);
765 if (!isMember(x, rr))
766 {
767 Node kk = d_state.getProxy(term);
768 Node fact = nm->mkNode(kind::MEMBER, x, kk);
769 d_im.assertInference(fact, exp, "upc", inferType);
770 if (d_state.isInConflict())
771 {
772 return;
773 }
774 }
775 }
776 Trace("sets-debug") << "done checking membership " << xr << " "
777 << itm1m.second << std::endl;
778 }
779 }
780 if (k == kind::UNION)
781 {
782 if (!r2mem.empty())
783 {
784 // for all members of r2
785 for (const std::pair<const Node, Node>& itm2m : r2mem)
786 {
787 Node x = itm2m.second[0];
788 Node rr = d_equalityEngine.getRepresentative(term);
789 if (!isMember(x, rr))
790 {
791 std::vector<Node> exp;
792 exp.push_back(itm2m.second);
793 d_state.addEqualityToExp(term[1], itm2m.second[1], exp);
794 Node r = d_state.getProxy(term);
795 Node fact = nm->mkNode(kind::MEMBER, x, r);
796 d_im.assertInference(fact, exp, "upc2");
797 if (d_state.isInConflict())
798 {
799 return;
800 }
801 }
802 }
803 }
804 }
805 }
806 }
807 }
808 }
809 }
810 if (!d_im.hasProcessed())
811 {
812 if (options::setsExt())
813 {
814 // universal sets
815 Trace("sets-debug") << "Check universe sets..." << std::endl;
816 // all elements must be in universal set
817 const std::vector<Node>& sec = d_state.getSetsEqClasses();
818 for (const Node& s : sec)
819 {
820 // if equivalence class contains a variable
821 Node v = d_state.getVariableSet(s);
822 if (!v.isNull())
823 {
824 // the variable in the equivalence class
825 std::map<TypeNode, Node> univ_set;
826 const std::map<Node, Node>& smems = d_state.getMembers(s);
827 for (const std::pair<const Node, Node>& it2 : smems)
828 {
829 Node e = it2.second[0];
830 TypeNode tn = NodeManager::currentNM()->mkSetType(e.getType());
831 Node u;
832 std::map<TypeNode, Node>::iterator itu = univ_set.find(tn);
833 if (itu == univ_set.end())
834 {
835 Node ueqc = d_state.getUnivSetEqClass(tn);
836 // if the universe does not yet exist, or is not in this
837 // equivalence class
838 if (s != ueqc)
839 {
840 u = d_state.getUnivSet(tn);
841 }
842 univ_set[tn] = u;
843 }
844 else
845 {
846 u = itu->second;
847 }
848 if (!u.isNull())
849 {
850 Assert(it2.second.getKind() == kind::MEMBER);
851 std::vector<Node> exp;
852 exp.push_back(it2.second);
853 if (v != it2.second[1])
854 {
855 exp.push_back(v.eqNode(it2.second[1]));
856 }
857 Node fact = nm->mkNode(kind::MEMBER, it2.second[0], u);
858 d_im.assertInference(fact, exp, "upuniv");
859 if (d_state.isInConflict())
860 {
861 return;
862 }
863 }
864 }
865 }
866 }
867 }
868 }
869 }
870
871 void TheorySetsPrivate::checkDisequalities()
872 {
873 // disequalities
874 Trace("sets") << "TheorySetsPrivate: check disequalities..." << std::endl;
875 NodeManager* nm = NodeManager::currentNM();
876 for (NodeBoolMap::const_iterator it = d_deq.begin(); it != d_deq.end(); ++it)
877 {
878 if (!(*it).second)
879 {
880 // not active
881 continue;
882 }
883 Node deq = (*it).first;
884 // check if it is already satisfied
885 Assert(d_equalityEngine.hasTerm(deq[0])
886 && d_equalityEngine.hasTerm(deq[1]));
887 Node r1 = d_equalityEngine.getRepresentative(deq[0]);
888 Node r2 = d_equalityEngine.getRepresentative(deq[1]);
889 bool is_sat = d_state.isSetDisequalityEntailed(r1, r2);
890 Trace("sets-debug") << "Check disequality " << deq
891 << ", is_sat = " << is_sat << std::endl;
892 // will process regardless of sat/processed/unprocessed
893 d_deq[deq] = false;
894
895 if (is_sat)
896 {
897 // already satisfied
898 continue;
899 }
900 if (d_termProcessed.find(deq) != d_termProcessed.end())
901 {
902 // already added lemma
903 continue;
904 }
905 d_termProcessed.insert(deq);
906 d_termProcessed.insert(deq[1].eqNode(deq[0]));
907 Trace("sets") << "Process Disequality : " << deq.negate() << std::endl;
908 TypeNode elementType = deq[0].getType().getSetElementType();
909 Node x = d_state.getSkolemCache().mkTypedSkolemCached(
910 elementType, deq[0], deq[1], SkolemCache::SK_DISEQUAL, "sde");
911 Node mem1 = nm->mkNode(MEMBER, x, deq[0]);
912 Node mem2 = nm->mkNode(MEMBER, x, deq[1]);
913 Node lem = nm->mkNode(OR, deq, nm->mkNode(EQUAL, mem1, mem2).negate());
914 lem = Rewriter::rewrite(lem);
915 d_im.assertInference(lem, d_true, "diseq", 1);
916 d_im.flushPendingLemmas();
917 if (d_im.hasProcessed())
918 {
919 return;
920 }
921 }
922 }
923
924 void TheorySetsPrivate::checkReduceComprehensions()
925 {
926 NodeManager* nm = NodeManager::currentNM();
927 const std::vector<Node>& comps = d_state.getComprehensionSets();
928 for (const Node& n : comps)
929 {
930 if (d_termProcessed.find(n) != d_termProcessed.end())
931 {
932 // already reduced it
933 continue;
934 }
935 d_termProcessed.insert(n);
936 Node v = nm->mkBoundVar(n[2].getType());
937 Node body = nm->mkNode(AND, n[1], v.eqNode(n[2]));
938 // must do substitution
939 std::vector<Node> vars;
940 std::vector<Node> subs;
941 for (const Node& cv : n[0])
942 {
943 vars.push_back(cv);
944 Node cvs = nm->mkBoundVar(cv.getType());
945 subs.push_back(cvs);
946 }
947 body = body.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
948 Node bvl = nm->mkNode(BOUND_VAR_LIST, subs);
949 body = nm->mkNode(EXISTS, bvl, body);
950 Node mem = nm->mkNode(MEMBER, v, n);
951 Node lem =
952 nm->mkNode(FORALL, nm->mkNode(BOUND_VAR_LIST, v), body.eqNode(mem));
953 Trace("sets-comprehension")
954 << "Comprehension reduction: " << lem << std::endl;
955 d_im.flushLemma(lem);
956 }
957 }
958
959 /**************************** TheorySetsPrivate *****************************/
960 /**************************** TheorySetsPrivate *****************************/
961 /**************************** TheorySetsPrivate *****************************/
962
963 void TheorySetsPrivate::check(Theory::Effort level)
964 {
965 Trace("sets-check") << "Sets check effort " << level << std::endl;
966 if (level == Theory::EFFORT_LAST_CALL)
967 {
968 return;
969 }
970 while (!d_external.done() && !d_state.isInConflict())
971 {
972 // Get all the assertions
973 Assertion assertion = d_external.get();
974 TNode fact = assertion.d_assertion;
975 Trace("sets-assert") << "Assert from input " << fact << std::endl;
976 // assert the fact
977 assertFact(fact, fact);
978 }
979 Trace("sets-check") << "Sets finished assertions effort " << level
980 << std::endl;
981 // invoke full effort check, relations check
982 if (!d_state.isInConflict())
983 {
984 if (level == Theory::EFFORT_FULL)
985 {
986 if (!d_external.d_valuation.needCheck())
987 {
988 fullEffortCheck();
989 if (!d_state.isInConflict() && !d_im.hasSentLemma()
990 && d_full_check_incomplete)
991 {
992 d_external.d_out->setIncomplete();
993 }
994 }
995 }
996 }
997 Trace("sets-check") << "Sets finish Check effort " << level << std::endl;
998 } /* TheorySetsPrivate::check() */
999
1000 /************************ Sharing ************************/
1001 /************************ Sharing ************************/
1002 /************************ Sharing ************************/
1003
1004 void TheorySetsPrivate::addSharedTerm(TNode n)
1005 {
1006 Debug("sets") << "[sets] TheorySetsPrivate::addSharedTerm( " << n << ")"
1007 << std::endl;
1008 d_equalityEngine.addTriggerTerm(n, THEORY_SETS);
1009 }
1010
1011 void TheorySetsPrivate::addCarePairs(TNodeTrie* t1,
1012 TNodeTrie* t2,
1013 unsigned arity,
1014 unsigned depth,
1015 unsigned& n_pairs)
1016 {
1017 if (depth == arity)
1018 {
1019 if (t2 != NULL)
1020 {
1021 Node f1 = t1->getData();
1022 Node f2 = t2->getData();
1023 if (!d_state.areEqual(f1, f2))
1024 {
1025 Trace("sets-cg") << "Check " << f1 << " and " << f2 << std::endl;
1026 vector<pair<TNode, TNode> > currentPairs;
1027 for (unsigned k = 0; k < f1.getNumChildren(); ++k)
1028 {
1029 TNode x = f1[k];
1030 TNode y = f2[k];
1031 Assert(d_equalityEngine.hasTerm(x));
1032 Assert(d_equalityEngine.hasTerm(y));
1033 Assert(!d_state.areDisequal(x, y));
1034 Assert(!areCareDisequal(x, y));
1035 if (!d_equalityEngine.areEqual(x, y))
1036 {
1037 Trace("sets-cg")
1038 << "Arg #" << k << " is " << x << " " << y << std::endl;
1039 if (d_equalityEngine.isTriggerTerm(x, THEORY_SETS)
1040 && d_equalityEngine.isTriggerTerm(y, THEORY_SETS))
1041 {
1042 TNode x_shared =
1043 d_equalityEngine.getTriggerTermRepresentative(x, THEORY_SETS);
1044 TNode y_shared =
1045 d_equalityEngine.getTriggerTermRepresentative(y, THEORY_SETS);
1046 currentPairs.push_back(make_pair(x_shared, y_shared));
1047 }
1048 else if (isCareArg(f1, k) && isCareArg(f2, k))
1049 {
1050 // splitting on sets (necessary for handling set of sets properly)
1051 if (x.getType().isSet())
1052 {
1053 Assert(y.getType().isSet());
1054 if (!d_state.areDisequal(x, y))
1055 {
1056 Trace("sets-cg-lemma")
1057 << "Should split on : " << x << "==" << y << std::endl;
1058 d_im.split(x.eqNode(y));
1059 }
1060 }
1061 }
1062 }
1063 }
1064 for (unsigned c = 0; c < currentPairs.size(); ++c)
1065 {
1066 Trace("sets-cg-pair") << "Pair : " << currentPairs[c].first << " "
1067 << currentPairs[c].second << std::endl;
1068 d_external.addCarePair(currentPairs[c].first, currentPairs[c].second);
1069 n_pairs++;
1070 }
1071 }
1072 }
1073 }
1074 else
1075 {
1076 if (t2 == NULL)
1077 {
1078 if (depth < (arity - 1))
1079 {
1080 // add care pairs internal to each child
1081 for (std::pair<const TNode, TNodeTrie>& t : t1->d_data)
1082 {
1083 addCarePairs(&t.second, NULL, arity, depth + 1, n_pairs);
1084 }
1085 }
1086 // add care pairs based on each pair of non-disequal arguments
1087 for (std::map<TNode, TNodeTrie>::iterator it = t1->d_data.begin();
1088 it != t1->d_data.end();
1089 ++it)
1090 {
1091 std::map<TNode, TNodeTrie>::iterator it2 = it;
1092 ++it2;
1093 for (; it2 != t1->d_data.end(); ++it2)
1094 {
1095 if (!d_equalityEngine.areDisequal(it->first, it2->first, false))
1096 {
1097 if (!areCareDisequal(it->first, it2->first))
1098 {
1099 addCarePairs(
1100 &it->second, &it2->second, arity, depth + 1, n_pairs);
1101 }
1102 }
1103 }
1104 }
1105 }
1106 else
1107 {
1108 // add care pairs based on product of indices, non-disequal arguments
1109 for (std::pair<const TNode, TNodeTrie>& tt1 : t1->d_data)
1110 {
1111 for (std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data)
1112 {
1113 if (!d_equalityEngine.areDisequal(tt1.first, tt2.first, false))
1114 {
1115 if (!areCareDisequal(tt1.first, tt2.first))
1116 {
1117 addCarePairs(&tt1.second, &tt2.second, arity, depth + 1, n_pairs);
1118 }
1119 }
1120 }
1121 }
1122 }
1123 }
1124 }
1125
1126 void TheorySetsPrivate::computeCareGraph()
1127 {
1128 const std::map<Kind, std::vector<Node> >& ol = d_state.getOperatorList();
1129 for (const std::pair<const Kind, std::vector<Node> >& it : ol)
1130 {
1131 Kind k = it.first;
1132 if (k == kind::SINGLETON || k == kind::MEMBER)
1133 {
1134 unsigned n_pairs = 0;
1135 Trace("sets-cg-summary") << "Compute graph for sets, op=" << k << "..."
1136 << it.second.size() << std::endl;
1137 Trace("sets-cg") << "Build index for " << k << "..." << std::endl;
1138 std::map<TypeNode, TNodeTrie> index;
1139 unsigned arity = 0;
1140 // populate indices
1141 for (TNode f1 : it.second)
1142 {
1143 Assert(d_equalityEngine.hasTerm(f1));
1144 Trace("sets-cg-debug") << "...build for " << f1 << std::endl;
1145 Assert(d_equalityEngine.hasTerm(f1));
1146 // break into index based on operator, and type of first argument (since
1147 // some operators are parametric)
1148 TypeNode tn = f1[0].getType();
1149 std::vector<TNode> reps;
1150 bool hasCareArg = false;
1151 for (unsigned j = 0; j < f1.getNumChildren(); j++)
1152 {
1153 reps.push_back(d_equalityEngine.getRepresentative(f1[j]));
1154 if (isCareArg(f1, j))
1155 {
1156 hasCareArg = true;
1157 }
1158 }
1159 if (hasCareArg)
1160 {
1161 Trace("sets-cg-debug") << "......adding." << std::endl;
1162 index[tn].addTerm(f1, reps);
1163 arity = reps.size();
1164 }
1165 else
1166 {
1167 Trace("sets-cg-debug") << "......skip." << std::endl;
1168 }
1169 }
1170 if (arity > 0)
1171 {
1172 // for each index
1173 for (std::pair<const TypeNode, TNodeTrie>& tt : index)
1174 {
1175 Trace("sets-cg") << "Process index " << tt.first << "..."
1176 << std::endl;
1177 addCarePairs(&tt.second, nullptr, arity, 0, n_pairs);
1178 }
1179 }
1180 Trace("sets-cg-summary") << "...done, # pairs = " << n_pairs << std::endl;
1181 }
1182 }
1183 }
1184
1185 bool TheorySetsPrivate::isCareArg(Node n, unsigned a)
1186 {
1187 if (d_equalityEngine.isTriggerTerm(n[a], THEORY_SETS))
1188 {
1189 return true;
1190 }
1191 else if ((n.getKind() == kind::MEMBER || n.getKind() == kind::SINGLETON)
1192 && a == 0 && n[0].getType().isSet())
1193 {
1194 return true;
1195 }
1196 else
1197 {
1198 return false;
1199 }
1200 }
1201
1202 EqualityStatus TheorySetsPrivate::getEqualityStatus(TNode a, TNode b)
1203 {
1204 Assert(d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b));
1205 if (d_equalityEngine.areEqual(a, b))
1206 {
1207 // The terms are implied to be equal
1208 return EQUALITY_TRUE;
1209 }
1210 if (d_equalityEngine.areDisequal(a, b, false))
1211 {
1212 // The terms are implied to be dis-equal
1213 return EQUALITY_FALSE;
1214 }
1215 return EQUALITY_UNKNOWN;
1216 /*
1217 Node aModelValue = d_external.d_valuation.getModelValue(a);
1218 if(aModelValue.isNull()) { return EQUALITY_UNKNOWN; }
1219 Node bModelValue = d_external.d_valuation.getModelValue(b);
1220 if(bModelValue.isNull()) { return EQUALITY_UNKNOWN; }
1221 if( aModelValue == bModelValue ) {
1222 // The term are true in current model
1223 return EQUALITY_TRUE_IN_MODEL;
1224 } else {
1225 return EQUALITY_FALSE_IN_MODEL;
1226 }
1227 */
1228 // }
1229 // //TODO: can we be more precise sometimes?
1230 // return EQUALITY_UNKNOWN;
1231 }
1232
1233 /******************** Model generation ********************/
1234 /******************** Model generation ********************/
1235 /******************** Model generation ********************/
1236
1237 namespace {
1238 /**
1239 * This function is a helper function to print sets as
1240 * Set A = { a0, a1, a2, }
1241 * instead of
1242 * (union (singleton a0) (union (singleton a1) (singleton a2)))
1243 */
1244 void traceSetElementsRecursively(stringstream& stream, const Node& set)
1245 {
1246 Assert(set.getType().isSet());
1247 if (set.getKind() == SINGLETON)
1248 {
1249 stream << set[0] << ", ";
1250 }
1251 if (set.getKind() == UNION)
1252 {
1253 traceSetElementsRecursively(stream, set[0]);
1254 traceSetElementsRecursively(stream, set[1]);
1255 }
1256 }
1257
1258 std::string traceElements(const Node& set)
1259 {
1260 std::stringstream stream;
1261 traceSetElementsRecursively(stream, set);
1262 return stream.str();
1263 }
1264
1265 } // namespace
1266
1267 bool TheorySetsPrivate::collectModelInfo(TheoryModel* m)
1268 {
1269 Trace("sets-model") << "Set collect model info" << std::endl;
1270 set<Node> termSet;
1271 // Compute terms appearing in assertions and shared terms
1272 d_external.computeRelevantTerms(termSet);
1273
1274 // Assert equalities and disequalities to the model
1275 if (!m->assertEqualityEngine(&d_equalityEngine, &termSet))
1276 {
1277 return false;
1278 }
1279
1280 NodeManager* nm = NodeManager::currentNM();
1281 std::map<Node, Node> mvals;
1282 // If cardinality is enabled, we need to use the ordered equivalence class
1283 // list computed by the cardinality solver, where sets equivalence classes
1284 // are assigned model values based on their position in the cardinality
1285 // graph.
1286 const std::vector<Node>& sec = d_card_enabled
1287 ? d_cardSolver->getOrderedSetsEqClasses()
1288 : d_state.getSetsEqClasses();
1289 Valuation& val = getValuation();
1290 for (int i = (int)(sec.size() - 1); i >= 0; i--)
1291 {
1292 Node eqc = sec[i];
1293 if (termSet.find(eqc) == termSet.end())
1294 {
1295 Trace("sets-model") << "* Do not assign value for " << eqc
1296 << " since is not relevant." << std::endl;
1297 }
1298 else
1299 {
1300 std::vector<Node> els;
1301 bool is_base = !d_card_enabled || d_cardSolver->isModelValueBasic(eqc);
1302 if (is_base)
1303 {
1304 Trace("sets-model")
1305 << "Collect elements of base eqc " << eqc << std::endl;
1306 // members that must be in eqc
1307 const std::map<Node, Node>& emems = d_state.getMembers(eqc);
1308 if (!emems.empty())
1309 {
1310 for (const std::pair<const Node, Node>& itmm : emems)
1311 {
1312 Node t = nm->mkNode(kind::SINGLETON, itmm.first);
1313 els.push_back(t);
1314 }
1315 }
1316 }
1317 if (d_card_enabled)
1318 {
1319 // make the slack elements for the equivalence class based on set
1320 // cardinality
1321 d_cardSolver->mkModelValueElementsFor(val, eqc, els, mvals, m);
1322 }
1323 Node rep = NormalForm::mkBop(kind::UNION, els, eqc.getType());
1324 rep = Rewriter::rewrite(rep);
1325 Trace("sets-model") << "* Assign representative of " << eqc << " to "
1326 << rep << std::endl;
1327 mvals[eqc] = rep;
1328 if (!m->assertEquality(eqc, rep, true))
1329 {
1330 return false;
1331 }
1332 m->assertSkeleton(rep);
1333
1334 Trace("sets-model") << "Set " << eqc << " = { " << traceElements(rep)
1335 << " }" << std::endl;
1336 }
1337 }
1338
1339 // handle slack elements constraints for finite types
1340 if (d_card_enabled)
1341 {
1342 const std::map<TypeNode, std::vector<TNode> >& slackElements =
1343 d_cardSolver->getFiniteTypeSlackElements();
1344 for (const std::pair<TypeNode, std::vector<TNode> >& pair : slackElements)
1345 {
1346 const std::vector<Node>& members =
1347 d_cardSolver->getFiniteTypeMembers(pair.first);
1348 m->setAssignmentExclusionSetGroup(pair.second, members);
1349 Trace("sets-model") << "ExclusionSet: Group " << pair.second
1350 << " is excluded from set" << members << std::endl;
1351 }
1352 }
1353 return true;
1354 }
1355
1356 /********************** Helper functions ***************************/
1357 /********************** Helper functions ***************************/
1358 /********************** Helper functions ***************************/
1359
1360 Node mkAnd(const std::vector<TNode>& conjunctions)
1361 {
1362 Assert(conjunctions.size() > 0);
1363
1364 std::set<TNode> all;
1365 for (unsigned i = 0; i < conjunctions.size(); ++i)
1366 {
1367 TNode t = conjunctions[i];
1368 if (t.getKind() == kind::AND)
1369 {
1370 for (TNode::iterator child_it = t.begin(); child_it != t.end();
1371 ++child_it)
1372 {
1373 Assert((*child_it).getKind() != kind::AND);
1374 all.insert(*child_it);
1375 }
1376 }
1377 else
1378 {
1379 all.insert(t);
1380 }
1381 }
1382
1383 Assert(all.size() > 0);
1384 if (all.size() == 1)
1385 {
1386 // All the same, or just one
1387 return conjunctions[0];
1388 }
1389
1390 NodeBuilder<> conjunction(kind::AND);
1391 std::set<TNode>::const_iterator it = all.begin();
1392 std::set<TNode>::const_iterator it_end = all.end();
1393 while (it != it_end)
1394 {
1395 conjunction << *it;
1396 ++it;
1397 }
1398 return conjunction;
1399 } /* mkAnd() */
1400
1401 void TheorySetsPrivate::propagate(Theory::Effort effort) {}
1402
1403 bool TheorySetsPrivate::propagate(TNode literal)
1404 {
1405 Debug("sets-prop") << " propagate(" << literal << ")" << std::endl;
1406
1407 // If already in conflict, no more propagation
1408 if (d_state.isInConflict())
1409 {
1410 Debug("sets-prop") << "TheoryUF::propagate(" << literal
1411 << "): already in conflict" << std::endl;
1412 return false;
1413 }
1414
1415 // Propagate out
1416 bool ok = d_external.d_out->propagate(literal);
1417 if (!ok)
1418 {
1419 d_state.setConflict();
1420 }
1421
1422 return ok;
1423 } /* TheorySetsPrivate::propagate(TNode) */
1424
1425 OutputChannel* TheorySetsPrivate::getOutputChannel()
1426 {
1427 return d_external.d_out;
1428 }
1429
1430 Valuation& TheorySetsPrivate::getValuation() { return d_external.d_valuation; }
1431
1432 void TheorySetsPrivate::setMasterEqualityEngine(eq::EqualityEngine* eq)
1433 {
1434 d_equalityEngine.setMasterEqualityEngine(eq);
1435 }
1436
1437 void TheorySetsPrivate::conflict(TNode a, TNode b)
1438 {
1439 Node conf = explain(a.eqNode(b));
1440 d_state.setConflict(conf);
1441 Debug("sets") << "[sets] conflict: " << a << " iff " << b << ", explanation "
1442 << conf << std::endl;
1443 Trace("sets-lemma") << "Equality Conflict : " << conf << std::endl;
1444 }
1445
1446 Node TheorySetsPrivate::explain(TNode literal)
1447 {
1448 Debug("sets") << "TheorySetsPrivate::explain(" << literal << ")" << std::endl;
1449
1450 bool polarity = literal.getKind() != kind::NOT;
1451 TNode atom = polarity ? literal : literal[0];
1452 std::vector<TNode> assumptions;
1453
1454 if (atom.getKind() == kind::EQUAL)
1455 {
1456 d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions);
1457 }
1458 else if (atom.getKind() == kind::MEMBER)
1459 {
1460 d_equalityEngine.explainPredicate(atom, polarity, assumptions);
1461 }
1462 else
1463 {
1464 Debug("sets") << "unhandled: " << literal << "; (" << atom << ", "
1465 << polarity << "); kind" << atom.getKind() << std::endl;
1466 Unhandled();
1467 }
1468
1469 return mkAnd(assumptions);
1470 }
1471
1472 void TheorySetsPrivate::preRegisterTerm(TNode node)
1473 {
1474 Debug("sets") << "TheorySetsPrivate::preRegisterTerm(" << node << ")"
1475 << std::endl;
1476 switch (node.getKind())
1477 {
1478 case kind::EQUAL: d_equalityEngine.addTriggerEquality(node); break;
1479 case kind::MEMBER: d_equalityEngine.addTriggerPredicate(node); break;
1480 case kind::CARD: d_equalityEngine.addTriggerTerm(node, THEORY_SETS); break;
1481 default: d_equalityEngine.addTerm(node); break;
1482 }
1483 }
1484
1485 Node TheorySetsPrivate::expandDefinition(Node node)
1486 {
1487 Debug("sets-proc") << "expandDefinition : " << node << std::endl;
1488
1489 if (node.getKind() == kind::CHOOSE)
1490 {
1491 // (choose A) is expanded as
1492 // (witness ((x elementType))
1493 // (ite
1494 // (= A (as emptyset setType))
1495 // (= x chooseUf(A))
1496 // (and (member x A) (= x chooseUf(A)))
1497
1498 NodeManager* nm = NodeManager::currentNM();
1499 Node set = node[0];
1500 TypeNode setType = set.getType();
1501 Node chooseSkolem = getChooseFunction(setType);
1502 Node apply = NodeManager::currentNM()->mkNode(APPLY_UF, chooseSkolem, set);
1503
1504 Node witnessVariable = nm->mkBoundVar(setType.getSetElementType());
1505
1506 Node equal = witnessVariable.eqNode(apply);
1507 Node emptySet = nm->mkConst(EmptySet(setType.toType()));
1508 Node isEmpty = set.eqNode(emptySet);
1509 Node member = nm->mkNode(MEMBER, witnessVariable, set);
1510 Node memberAndEqual = member.andNode(equal);
1511 Node ite = nm->mkNode(kind::ITE, isEmpty, equal, memberAndEqual);
1512 Node witnessVariables = nm->mkNode(BOUND_VAR_LIST, witnessVariable);
1513 Node witness = nm->mkNode(WITNESS, witnessVariables, ite);
1514 return witness;
1515 }
1516
1517 return node;
1518 }
1519
1520 Node TheorySetsPrivate::getChooseFunction(const TypeNode& setType)
1521 {
1522 std::map<TypeNode, Node>::iterator it = d_chooseFunctions.find(setType);
1523 if (it != d_chooseFunctions.end())
1524 {
1525 return it->second;
1526 }
1527
1528 NodeManager* nm = NodeManager::currentNM();
1529 TypeNode chooseUf = nm->mkFunctionType(setType, setType.getSetElementType());
1530 stringstream stream;
1531 stream << "chooseUf" << setType.getId();
1532 string name = stream.str();
1533 Node chooseSkolem = nm->mkSkolem(
1534 name, chooseUf, "choose function", NodeManager::SKOLEM_EXACT_NAME);
1535 d_chooseFunctions[setType] = chooseSkolem;
1536 return chooseSkolem;
1537 }
1538
1539 void TheorySetsPrivate::presolve() { d_state.reset(); }
1540
1541 /**************************** eq::NotifyClass *****************************/
1542 /**************************** eq::NotifyClass *****************************/
1543 /**************************** eq::NotifyClass *****************************/
1544
1545 bool TheorySetsPrivate::NotifyClass::eqNotifyTriggerEquality(TNode equality,
1546 bool value)
1547 {
1548 Debug("sets-eq") << "[sets-eq] eqNotifyTriggerEquality: equality = "
1549 << equality << " value = " << value << std::endl;
1550 if (value)
1551 {
1552 return d_theory.propagate(equality);
1553 }
1554 else
1555 {
1556 // We use only literal triggers so taking not is safe
1557 return d_theory.propagate(equality.notNode());
1558 }
1559 }
1560
1561 bool TheorySetsPrivate::NotifyClass::eqNotifyTriggerPredicate(TNode predicate,
1562 bool value)
1563 {
1564 Debug("sets-eq") << "[sets-eq] eqNotifyTriggerPredicate: predicate = "
1565 << predicate << " value = " << value << std::endl;
1566 if (value)
1567 {
1568 return d_theory.propagate(predicate);
1569 }
1570 else
1571 {
1572 return d_theory.propagate(predicate.notNode());
1573 }
1574 }
1575
1576 bool TheorySetsPrivate::NotifyClass::eqNotifyTriggerTermEquality(TheoryId tag,
1577 TNode t1,
1578 TNode t2,
1579 bool value)
1580 {
1581 Debug("sets-eq") << "[sets-eq] eqNotifyTriggerTermEquality: tag = " << tag
1582 << " t1 = " << t1 << " t2 = " << t2 << " value = " << value
1583 << std::endl;
1584 d_theory.propagate(value ? t1.eqNode(t2) : t1.eqNode(t2).negate());
1585 return true;
1586 }
1587
1588 void TheorySetsPrivate::NotifyClass::eqNotifyConstantTermMerge(TNode t1,
1589 TNode t2)
1590 {
1591 Debug("sets-eq") << "[sets-eq] eqNotifyConstantTermMerge "
1592 << " t1 = " << t1 << " t2 = " << t2 << std::endl;
1593 d_theory.conflict(t1, t2);
1594 }
1595
1596 void TheorySetsPrivate::NotifyClass::eqNotifyNewClass(TNode t)
1597 {
1598 Debug("sets-eq") << "[sets-eq] eqNotifyNewClass:"
1599 << " t = " << t << std::endl;
1600 d_theory.eqNotifyNewClass(t);
1601 }
1602
1603 void TheorySetsPrivate::NotifyClass::eqNotifyPreMerge(TNode t1, TNode t2)
1604 {
1605 Debug("sets-eq") << "[sets-eq] eqNotifyPreMerge:"
1606 << " t1 = " << t1 << " t2 = " << t2 << std::endl;
1607 d_theory.eqNotifyPreMerge(t1, t2);
1608 }
1609
1610 void TheorySetsPrivate::NotifyClass::eqNotifyPostMerge(TNode t1, TNode t2)
1611 {
1612 Debug("sets-eq") << "[sets-eq] eqNotifyPostMerge:"
1613 << " t1 = " << t1 << " t2 = " << t2 << std::endl;
1614 d_theory.eqNotifyPostMerge(t1, t2);
1615 }
1616
1617 void TheorySetsPrivate::NotifyClass::eqNotifyDisequal(TNode t1,
1618 TNode t2,
1619 TNode reason)
1620 {
1621 Debug("sets-eq") << "[sets-eq] eqNotifyDisequal:"
1622 << " t1 = " << t1 << " t2 = " << t2 << " reason = " << reason
1623 << std::endl;
1624 d_theory.eqNotifyDisequal(t1, t2, reason);
1625 }
1626
1627 } // namespace sets
1628 } // namespace theory
1629 } // namespace CVC4