1 /********************* */
2 /*! \file theory_sets_private.cpp
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
12 ** \brief Sets theory implementation.
14 ** Sets theory implementation.
17 #include "theory/sets/theory_sets_private.h"
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"
31 using namespace CVC4::kind
;
37 TheorySetsPrivate::TheorySetsPrivate(TheorySets
& external
,
39 context::UserContext
* u
)
44 d_full_check_incomplete(false),
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
)),
52 new CardinalityExtension(d_state
, d_im
, d_equalityEngine
, c
, u
)),
53 d_rels_enabled(false),
56 d_true
= NodeManager::currentNM()->mkConst(true);
57 d_false
= NodeManager::currentNM()->mkConst(false);
58 d_zero
= NodeManager::currentNM()->mkConst(Rational(0));
60 d_equalityEngine
.addFunctionKind(kind::SINGLETON
);
61 d_equalityEngine
.addFunctionKind(kind::UNION
);
62 d_equalityEngine
.addFunctionKind(kind::INTERSECTION
);
63 d_equalityEngine
.addFunctionKind(kind::SETMINUS
);
65 d_equalityEngine
.addFunctionKind(kind::MEMBER
);
66 d_equalityEngine
.addFunctionKind(kind::SUBSET
);
69 TheorySetsPrivate::~TheorySetsPrivate()
71 for (std::pair
<const Node
, EqcInfo
*>& current_pair
: d_eqc_info
)
73 delete current_pair
.second
;
77 void TheorySetsPrivate::eqNotifyNewClass(TNode t
)
79 if (t
.getKind() == kind::SINGLETON
|| t
.getKind() == kind::EMPTYSET
)
81 EqcInfo
* e
= getOrMakeEqcInfo(t
, true);
86 void TheorySetsPrivate::eqNotifyPreMerge(TNode t1
, TNode t2
) {}
88 void TheorySetsPrivate::eqNotifyPostMerge(TNode t1
, TNode t2
)
90 if (!d_state
.isInConflict())
92 Trace("sets-prop-debug")
93 << "Merge " << t1
<< " and " << t2
<< "..." << std::endl
;
95 EqcInfo
* e2
= getOrMakeEqcInfo(t2
);
99 EqcInfo
* e1
= getOrMakeEqcInfo(t1
);
100 Trace("sets-prop-debug") << "Merging singletons..." << std::endl
;
103 s1
= e1
->d_singleton
;
104 if (!s1
.isNull() && !s2
.isNull())
106 if (s1
.getKind() == s2
.getKind())
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]);
119 // singleton equal to emptyset, conflict
121 << "Propagate conflict : " << s1
<< " == " << s2
<< std::endl
;
130 e1
= getOrMakeEqcInfo(t1
, true);
131 e1
->d_singleton
.set(e2
->d_singleton
);
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())
139 NodeIntMap::iterator mem_i1
= d_members
.find(t1
);
141 if (mem_i1
!= d_members
.end())
143 n_members
= (*mem_i1
).second
;
145 for (int i
= 0; i
< (*mem_i2
).second
; i
++)
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
152 for (int j
= 0; j
< n_members
; j
++)
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]))
164 if (!s1
.isNull() && s2
.isNull())
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
)
174 Node eq
= s1
[0].eqNode(m2
[0]);
177 Trace("sets-prop") << "Propagate eq-mem eq inference : " << exp
178 << " => " << eq
<< std::endl
;
186 << "Propagate eq-mem conflict : " << exp
<< std::endl
;
187 d_state
.setConflict(exp
);
191 if (n_members
< (int)d_members_data
[t1
].size())
193 d_members_data
[t1
][n_members
] = m2
;
197 d_members_data
[t1
].push_back(m2
);
202 d_members
[t1
] = n_members
;
207 void TheorySetsPrivate::eqNotifyDisequal(TNode t1
, TNode t2
, TNode reason
)
209 if (t1
.getType().isSet())
211 Node eq
= t1
.eqNode(t2
);
212 if (d_deq
.find(eq
) == d_deq
.end())
219 TheorySetsPrivate::EqcInfo::EqcInfo(context::Context
* c
) : d_singleton(c
) {}
221 TheorySetsPrivate::EqcInfo
* TheorySetsPrivate::getOrMakeEqcInfo(TNode n
,
224 std::map
<Node
, EqcInfo
*>::iterator eqc_i
= d_eqc_info
.find(n
);
225 if (eqc_i
== d_eqc_info
.end())
230 ei
= new EqcInfo(d_external
.getSatContext());
237 return eqc_i
->second
;
241 bool TheorySetsPrivate::areCareDisequal(Node a
, Node b
)
243 if (d_equalityEngine
.isTriggerTerm(a
, THEORY_SETS
)
244 && d_equalityEngine
.isTriggerTerm(b
, THEORY_SETS
))
247 d_equalityEngine
.getTriggerTermRepresentative(a
, THEORY_SETS
);
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
)
261 bool TheorySetsPrivate::isMember(Node x
, Node s
)
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())
268 for (int i
= 0; i
< (*mem_i
).second
; i
++)
270 if (d_state
.areEqual(d_members_data
[s
][i
][0], x
))
279 bool TheorySetsPrivate::assertFact(Node fact
, Node exp
)
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
))
287 if (atom
.getKind() == kind::EQUAL
)
289 d_equalityEngine
.assertEquality(atom
, polarity
, exp
);
293 d_equalityEngine
.assertPredicate(atom
, polarity
, exp
);
295 if (!d_state
.isInConflict())
297 if (atom
.getKind() == kind::MEMBER
&& polarity
)
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);
304 Node s
= e
->d_singleton
;
307 Node pexp
= NodeManager::currentNM()->mkNode(
308 kind::AND
, atom
, atom
[1].eqNode(s
));
310 if (s
.getKind() == kind::SINGLETON
)
315 << "Propagate mem-eq : " << pexp
<< std::endl
;
316 Node eq
= s
[0].eqNode(atom
[0]);
318 assertFact(eq
, pexp
);
324 << "Propagate mem-eq conflict : " << pexp
<< std::endl
;
325 d_state
.setConflict(pexp
);
329 // add to membership list
330 NodeIntMap::iterator mem_i
= d_members
.find(r
);
332 if (mem_i
!= d_members
.end())
334 n_members
= (*mem_i
).second
;
336 d_members
[r
] = n_members
+ 1;
337 if (n_members
< (int)d_members_data
[r
].size())
339 d_members_data
[r
][n_members
] = atom
;
343 d_members_data
[r
].push_back(atom
);
355 void TheorySetsPrivate::fullEffortReset()
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
365 // reset the inference manager
367 // reset the cardinality solver
368 d_cardSolver
->reset();
371 void TheorySetsPrivate::fullEffortCheck()
373 Trace("sets") << "----- Full effort check ------" << std::endl
;
376 Assert(!d_im
.hasPendingLemmas() || d_im
.hasProcessed());
378 Trace("sets") << "...iterate full effort check..." << std::endl
;
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())
386 Node eqc
= (*eqcs_i
);
388 TypeNode tn
= eqc
.getType();
389 d_state
.registerEqc(tn
, eqc
);
391 // common type node and term
397 tnc
= tn
.getSetElementType();
400 Trace("sets-eqc") << "[" << eqc
<< "] : ";
401 eq::EqClassIterator eqc_i
= eq::EqClassIterator(eqc
, &d_equalityEngine
);
402 while (!eqc_i
.isFinished())
407 Trace("sets-eqc") << n
<< " ";
409 TypeNode tnn
= n
.getType();
413 TypeNode tnnel
= tnn
.getSetElementType();
414 tnc
= TypeNode::mostCommonTypeNode(tnc
, tnnel
);
415 Assert(!tnc
.isNull());
416 // update the common type term
422 // register it with the state
423 d_state
.registerTerm(eqc
, tnn
, n
);
424 if (n
.getKind() == kind::CARD
)
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
))
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
445 // 4- Supporting cardinality for relations (hard)
450 if (d_rels
->isRelationKind(n
.getKind()))
452 d_rels_enabled
= true;
459 Assert(tnct
.getType().getSetElementType() == tnc
);
460 d_most_common_type
[eqc
] = tnc
;
461 d_most_common_type_term
[eqc
] = tnct
;
463 Trace("sets-eqc") << std::endl
;
467 Trace("sets-eqc") << "...finished equality engine." << std::endl
;
469 if (Trace
.isOn("sets-state"))
471 Trace("sets-state") << "Equivalence class counters:" << std::endl
;
472 for (std::pair
<const TypeNode
, unsigned>& ec
: eqcTypeCount
)
475 << " " << ec
.first
<< " -> " << ec
.second
<< std::endl
;
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())
485 if (Trace
.isOn("sets-mem"))
487 const std::vector
<Node
>& sec
= d_state
.getSetsEqClasses();
488 for (const Node
& s
: sec
)
490 Trace("sets-mem") << "Eqc " << s
<< " : ";
491 const std::map
<Node
, Node
>& smem
= d_state
.getMembers(s
);
494 Trace("sets-mem") << "Memberships : ";
495 for (const std::pair
<const Node
, Node
>& it2
: smem
)
497 Trace("sets-mem") << it2
.first
<< " ";
500 Node ss
= d_state
.getSingletonEqClass(s
);
503 Trace("sets-mem") << " : Singleton : " << ss
;
505 Trace("sets-mem") << std::endl
;
510 d_im
.flushPendingLemmas(true);
511 if (d_im
.hasProcessed())
515 // check downwards closure
516 checkDownwardsClosure();
517 d_im
.flushPendingLemmas();
518 if (d_im
.hasProcessed())
522 // check upwards closure
523 checkUpwardsClosure();
524 d_im
.flushPendingLemmas();
525 if (d_im
.hasProcessed())
529 // check disequalities
530 checkDisequalities();
531 d_im
.flushPendingLemmas();
532 if (d_im
.hasProcessed())
536 // check reduce comprehensions
537 checkReduceComprehensions();
538 d_im
.flushPendingLemmas();
539 if (d_im
.hasProcessed())
545 // call the check method of the cardinality solver
546 d_cardSolver
->check();
547 if (d_im
.hasProcessed())
554 // call the check method of the relations solver
555 d_rels
->check(Theory::EFFORT_FULL
);
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()
565 void TheorySetsPrivate::checkSubtypes()
567 Trace("sets") << "TheorySetsPrivate: check Subtypes..." << std::endl
;
568 const std::vector
<Node
>& sec
= d_state
.getSetsEqClasses();
569 for (const Node
& s
: sec
)
571 TypeNode mct
= d_most_common_type
[s
];
572 Assert(!mct
.isNull());
573 const std::map
<Node
, Node
>& smems
= d_state
.getMembers(s
);
576 for (const std::pair
<const Node
, Node
>& it2
: smems
)
578 Trace("sets") << " check subtype " << it2
.first
<< " " << it2
.second
580 Trace("sets") << " types : " << it2
.first
.getType() << " " << mct
582 if (!it2
.first
.getType().isSubtypeOf(mct
))
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
);
594 Node etc
= tc_k
.eqNode(it2
.first
);
595 d_im
.assertInference(etc
, exp
, "subtype-clash");
596 if (d_state
.isInConflict())
605 Trace("sets") << "TheorySetsPrivate: finished." << std::endl
;
608 void TheorySetsPrivate::checkDownwardsClosure()
610 Trace("sets") << "TheorySetsPrivate: check downwards closure..." << std::endl
;
612 const std::vector
<Node
>& sec
= d_state
.getSetsEqClasses();
613 for (const Node
& s
: sec
)
615 const std::vector
<Node
>& nvsets
= d_state
.getNonVariableSets(s
);
618 const std::map
<Node
, Node
>& smem
= d_state
.getMembers(s
);
619 for (const Node
& nv
: nvsets
)
621 if (!d_state
.isCongruent(nv
))
623 for (const std::pair
<const Node
, Node
>& it2
: smem
)
625 Node mem
= it2
.second
;
627 Assert(d_equalityEngine
.areEqual(mem
[1], eq_set
));
628 if (mem
[1] != eq_set
)
630 Trace("sets-debug") << "Downwards closure based on " << mem
631 << ", eq_set = " << eq_set
<< std::endl
;
632 if (!options::setsProxyLemmas())
634 Node nmem
= NodeManager::currentNM()->mkNode(
635 kind::MEMBER
, mem
[0], eq_set
);
636 nmem
= Rewriter::rewrite(nmem
);
637 std::vector
<Node
> exp
;
639 exp
.push_back(mem
[1].eqNode(eq_set
));
640 d_im
.assertInference(nmem
, exp
, "downc");
641 if (d_state
.isInConflict())
649 Node k
= d_state
.getProxy(eq_set
);
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
))
662 nmem
= NodeManager::currentNM()->mkNode(
663 kind::OR
, pmem
.negate(), nmem
);
665 d_im
.assertInference(nmem
, exp
, "downc");
675 void TheorySetsPrivate::checkUpwardsClosure()
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
> > >&
685 Trace("sets") << "TheorySetsPrivate: check upwards closure " << k
<< "..."
687 for (const std::pair
<const Node
, std::map
<Node
, Node
> >& it
: itb
.second
)
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
)
694 for (const std::pair
<const Node
, Node
>& it2
: it
.second
)
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
)
704 << "Checking " << term
<< ", members = " << (!r1mem
.empty())
705 << ", " << (!r2mem
.empty()) << std::endl
;
706 // for all members of r1
709 for (const std::pair
<const Node
, Node
>& itm1m
: r1mem
)
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
);
720 if (k
== kind::UNION
)
724 else if (k
== kind::INTERSECTION
)
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())
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
);
738 // if not, check whether it is definitely not a member, if
740 if (r2nmem
.find(xr
) == r2nmem
.end())
742 exp
.push_back(nm
->mkNode(kind::MEMBER
, x
, term
[1]));
750 Assert(k
== kind::SETMINUS
);
751 std::map
<Node
, Node
>::const_iterator itm
= r2mem
.find(xr
);
752 if (itm
== r2mem
.end())
754 // must add lemma for set minus since non-membership in this
755 // case is not explained
757 nm
->mkNode(kind::MEMBER
, x
, term
[1]).negate());
764 Node rr
= d_equalityEngine
.getRepresentative(term
);
765 if (!isMember(x
, rr
))
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())
776 Trace("sets-debug") << "done checking membership " << xr
<< " "
777 << itm1m
.second
<< std::endl
;
780 if (k
== kind::UNION
)
784 // for all members of r2
785 for (const std::pair
<const Node
, Node
>& itm2m
: r2mem
)
787 Node x
= itm2m
.second
[0];
788 Node rr
= d_equalityEngine
.getRepresentative(term
);
789 if (!isMember(x
, rr
))
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())
810 if (!d_im
.hasProcessed())
812 if (options::setsExt())
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
)
820 // if equivalence class contains a variable
821 Node v
= d_state
.getVariableSet(s
);
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
)
829 Node e
= it2
.second
[0];
830 TypeNode tn
= NodeManager::currentNM()->mkSetType(e
.getType());
832 std::map
<TypeNode
, Node
>::iterator itu
= univ_set
.find(tn
);
833 if (itu
== univ_set
.end())
835 Node ueqc
= d_state
.getUnivSetEqClass(tn
);
836 // if the universe does not yet exist, or is not in this
840 u
= d_state
.getUnivSet(tn
);
850 Assert(it2
.second
.getKind() == kind::MEMBER
);
851 std::vector
<Node
> exp
;
852 exp
.push_back(it2
.second
);
853 if (v
!= it2
.second
[1])
855 exp
.push_back(v
.eqNode(it2
.second
[1]));
857 Node fact
= nm
->mkNode(kind::MEMBER
, it2
.second
[0], u
);
858 d_im
.assertInference(fact
, exp
, "upuniv");
859 if (d_state
.isInConflict())
871 void TheorySetsPrivate::checkDisequalities()
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
)
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
900 if (d_termProcessed
.find(deq
) != d_termProcessed
.end())
902 // already added lemma
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())
924 void TheorySetsPrivate::checkReduceComprehensions()
926 NodeManager
* nm
= NodeManager::currentNM();
927 const std::vector
<Node
>& comps
= d_state
.getComprehensionSets();
928 for (const Node
& n
: comps
)
930 if (d_termProcessed
.find(n
) != d_termProcessed
.end())
932 // already reduced it
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])
944 Node cvs
= nm
->mkBoundVar(cv
.getType());
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
);
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
);
959 /**************************** TheorySetsPrivate *****************************/
960 /**************************** TheorySetsPrivate *****************************/
961 /**************************** TheorySetsPrivate *****************************/
963 void TheorySetsPrivate::check(Theory::Effort level
)
965 Trace("sets-check") << "Sets check effort " << level
<< std::endl
;
966 if (level
== Theory::EFFORT_LAST_CALL
)
970 while (!d_external
.done() && !d_state
.isInConflict())
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
;
977 assertFact(fact
, fact
);
979 Trace("sets-check") << "Sets finished assertions effort " << level
981 // invoke full effort check, relations check
982 if (!d_state
.isInConflict())
984 if (level
== Theory::EFFORT_FULL
)
986 if (!d_external
.d_valuation
.needCheck())
989 if (!d_state
.isInConflict() && !d_im
.hasSentLemma()
990 && d_full_check_incomplete
)
992 d_external
.d_out
->setIncomplete();
997 Trace("sets-check") << "Sets finish Check effort " << level
<< std::endl
;
998 } /* TheorySetsPrivate::check() */
1000 /************************ Sharing ************************/
1001 /************************ Sharing ************************/
1002 /************************ Sharing ************************/
1004 void TheorySetsPrivate::addSharedTerm(TNode n
)
1006 Debug("sets") << "[sets] TheorySetsPrivate::addSharedTerm( " << n
<< ")"
1008 d_equalityEngine
.addTriggerTerm(n
, THEORY_SETS
);
1011 void TheorySetsPrivate::addCarePairs(TNodeTrie
* t1
,
1021 Node f1
= t1
->getData();
1022 Node f2
= t2
->getData();
1023 if (!d_state
.areEqual(f1
, f2
))
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
)
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
))
1038 << "Arg #" << k
<< " is " << x
<< " " << y
<< std::endl
;
1039 if (d_equalityEngine
.isTriggerTerm(x
, THEORY_SETS
)
1040 && d_equalityEngine
.isTriggerTerm(y
, THEORY_SETS
))
1043 d_equalityEngine
.getTriggerTermRepresentative(x
, THEORY_SETS
);
1045 d_equalityEngine
.getTriggerTermRepresentative(y
, THEORY_SETS
);
1046 currentPairs
.push_back(make_pair(x_shared
, y_shared
));
1048 else if (isCareArg(f1
, k
) && isCareArg(f2
, k
))
1050 // splitting on sets (necessary for handling set of sets properly)
1051 if (x
.getType().isSet())
1053 Assert(y
.getType().isSet());
1054 if (!d_state
.areDisequal(x
, y
))
1056 Trace("sets-cg-lemma")
1057 << "Should split on : " << x
<< "==" << y
<< std::endl
;
1058 d_im
.split(x
.eqNode(y
));
1064 for (unsigned c
= 0; c
< currentPairs
.size(); ++c
)
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
);
1078 if (depth
< (arity
- 1))
1080 // add care pairs internal to each child
1081 for (std::pair
<const TNode
, TNodeTrie
>& t
: t1
->d_data
)
1083 addCarePairs(&t
.second
, NULL
, arity
, depth
+ 1, n_pairs
);
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();
1091 std::map
<TNode
, TNodeTrie
>::iterator it2
= it
;
1093 for (; it2
!= t1
->d_data
.end(); ++it2
)
1095 if (!d_equalityEngine
.areDisequal(it
->first
, it2
->first
, false))
1097 if (!areCareDisequal(it
->first
, it2
->first
))
1100 &it
->second
, &it2
->second
, arity
, depth
+ 1, n_pairs
);
1108 // add care pairs based on product of indices, non-disequal arguments
1109 for (std::pair
<const TNode
, TNodeTrie
>& tt1
: t1
->d_data
)
1111 for (std::pair
<const TNode
, TNodeTrie
>& tt2
: t2
->d_data
)
1113 if (!d_equalityEngine
.areDisequal(tt1
.first
, tt2
.first
, false))
1115 if (!areCareDisequal(tt1
.first
, tt2
.first
))
1117 addCarePairs(&tt1
.second
, &tt2
.second
, arity
, depth
+ 1, n_pairs
);
1126 void TheorySetsPrivate::computeCareGraph()
1128 const std::map
<Kind
, std::vector
<Node
> >& ol
= d_state
.getOperatorList();
1129 for (const std::pair
<const Kind
, std::vector
<Node
> >& it
: ol
)
1132 if (k
== kind::SINGLETON
|| k
== kind::MEMBER
)
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
;
1141 for (TNode f1
: it
.second
)
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
++)
1153 reps
.push_back(d_equalityEngine
.getRepresentative(f1
[j
]));
1154 if (isCareArg(f1
, j
))
1161 Trace("sets-cg-debug") << "......adding." << std::endl
;
1162 index
[tn
].addTerm(f1
, reps
);
1163 arity
= reps
.size();
1167 Trace("sets-cg-debug") << "......skip." << std::endl
;
1173 for (std::pair
<const TypeNode
, TNodeTrie
>& tt
: index
)
1175 Trace("sets-cg") << "Process index " << tt
.first
<< "..."
1177 addCarePairs(&tt
.second
, nullptr, arity
, 0, n_pairs
);
1180 Trace("sets-cg-summary") << "...done, # pairs = " << n_pairs
<< std::endl
;
1185 bool TheorySetsPrivate::isCareArg(Node n
, unsigned a
)
1187 if (d_equalityEngine
.isTriggerTerm(n
[a
], THEORY_SETS
))
1191 else if ((n
.getKind() == kind::MEMBER
|| n
.getKind() == kind::SINGLETON
)
1192 && a
== 0 && n
[0].getType().isSet())
1202 EqualityStatus
TheorySetsPrivate::getEqualityStatus(TNode a
, TNode b
)
1204 Assert(d_equalityEngine
.hasTerm(a
) && d_equalityEngine
.hasTerm(b
));
1205 if (d_equalityEngine
.areEqual(a
, b
))
1207 // The terms are implied to be equal
1208 return EQUALITY_TRUE
;
1210 if (d_equalityEngine
.areDisequal(a
, b
, false))
1212 // The terms are implied to be dis-equal
1213 return EQUALITY_FALSE
;
1215 return EQUALITY_UNKNOWN
;
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;
1225 return EQUALITY_FALSE_IN_MODEL;
1229 // //TODO: can we be more precise sometimes?
1230 // return EQUALITY_UNKNOWN;
1233 /******************** Model generation ********************/
1234 /******************** Model generation ********************/
1235 /******************** Model generation ********************/
1239 * This function is a helper function to print sets as
1240 * Set A = { a0, a1, a2, }
1242 * (union (singleton a0) (union (singleton a1) (singleton a2)))
1244 void traceSetElementsRecursively(stringstream
& stream
, const Node
& set
)
1246 Assert(set
.getType().isSet());
1247 if (set
.getKind() == SINGLETON
)
1249 stream
<< set
[0] << ", ";
1251 if (set
.getKind() == UNION
)
1253 traceSetElementsRecursively(stream
, set
[0]);
1254 traceSetElementsRecursively(stream
, set
[1]);
1258 std::string
traceElements(const Node
& set
)
1260 std::stringstream stream
;
1261 traceSetElementsRecursively(stream
, set
);
1262 return stream
.str();
1267 bool TheorySetsPrivate::collectModelInfo(TheoryModel
* m
)
1269 Trace("sets-model") << "Set collect model info" << std::endl
;
1271 // Compute terms appearing in assertions and shared terms
1272 d_external
.computeRelevantTerms(termSet
);
1274 // Assert equalities and disequalities to the model
1275 if (!m
->assertEqualityEngine(&d_equalityEngine
, &termSet
))
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
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
--)
1293 if (termSet
.find(eqc
) == termSet
.end())
1295 Trace("sets-model") << "* Do not assign value for " << eqc
1296 << " since is not relevant." << std::endl
;
1300 std::vector
<Node
> els
;
1301 bool is_base
= !d_card_enabled
|| d_cardSolver
->isModelValueBasic(eqc
);
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
);
1310 for (const std::pair
<const Node
, Node
>& itmm
: emems
)
1312 Node t
= nm
->mkNode(kind::SINGLETON
, itmm
.first
);
1319 // make the slack elements for the equivalence class based on set
1321 d_cardSolver
->mkModelValueElementsFor(val
, eqc
, els
, mvals
, m
);
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
;
1328 if (!m
->assertEquality(eqc
, rep
, true))
1332 m
->assertSkeleton(rep
);
1334 Trace("sets-model") << "Set " << eqc
<< " = { " << traceElements(rep
)
1335 << " }" << std::endl
;
1339 // handle slack elements constraints for finite types
1342 const std::map
<TypeNode
, std::vector
<TNode
> >& slackElements
=
1343 d_cardSolver
->getFiniteTypeSlackElements();
1344 for (const std::pair
<TypeNode
, std::vector
<TNode
> >& pair
: slackElements
)
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
;
1356 /********************** Helper functions ***************************/
1357 /********************** Helper functions ***************************/
1358 /********************** Helper functions ***************************/
1360 Node
mkAnd(const std::vector
<TNode
>& conjunctions
)
1362 Assert(conjunctions
.size() > 0);
1364 std::set
<TNode
> all
;
1365 for (unsigned i
= 0; i
< conjunctions
.size(); ++i
)
1367 TNode t
= conjunctions
[i
];
1368 if (t
.getKind() == kind::AND
)
1370 for (TNode::iterator child_it
= t
.begin(); child_it
!= t
.end();
1373 Assert((*child_it
).getKind() != kind::AND
);
1374 all
.insert(*child_it
);
1383 Assert(all
.size() > 0);
1384 if (all
.size() == 1)
1386 // All the same, or just one
1387 return conjunctions
[0];
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
)
1401 void TheorySetsPrivate::propagate(Theory::Effort effort
) {}
1403 bool TheorySetsPrivate::propagate(TNode literal
)
1405 Debug("sets-prop") << " propagate(" << literal
<< ")" << std::endl
;
1407 // If already in conflict, no more propagation
1408 if (d_state
.isInConflict())
1410 Debug("sets-prop") << "TheoryUF::propagate(" << literal
1411 << "): already in conflict" << std::endl
;
1416 bool ok
= d_external
.d_out
->propagate(literal
);
1419 d_state
.setConflict();
1423 } /* TheorySetsPrivate::propagate(TNode) */
1425 OutputChannel
* TheorySetsPrivate::getOutputChannel()
1427 return d_external
.d_out
;
1430 Valuation
& TheorySetsPrivate::getValuation() { return d_external
.d_valuation
; }
1432 void TheorySetsPrivate::setMasterEqualityEngine(eq::EqualityEngine
* eq
)
1434 d_equalityEngine
.setMasterEqualityEngine(eq
);
1437 void TheorySetsPrivate::conflict(TNode a
, TNode b
)
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
;
1446 Node
TheorySetsPrivate::explain(TNode literal
)
1448 Debug("sets") << "TheorySetsPrivate::explain(" << literal
<< ")" << std::endl
;
1450 bool polarity
= literal
.getKind() != kind::NOT
;
1451 TNode atom
= polarity
? literal
: literal
[0];
1452 std::vector
<TNode
> assumptions
;
1454 if (atom
.getKind() == kind::EQUAL
)
1456 d_equalityEngine
.explainEquality(atom
[0], atom
[1], polarity
, assumptions
);
1458 else if (atom
.getKind() == kind::MEMBER
)
1460 d_equalityEngine
.explainPredicate(atom
, polarity
, assumptions
);
1464 Debug("sets") << "unhandled: " << literal
<< "; (" << atom
<< ", "
1465 << polarity
<< "); kind" << atom
.getKind() << std::endl
;
1469 return mkAnd(assumptions
);
1472 void TheorySetsPrivate::preRegisterTerm(TNode node
)
1474 Debug("sets") << "TheorySetsPrivate::preRegisterTerm(" << node
<< ")"
1476 switch (node
.getKind())
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;
1485 Node
TheorySetsPrivate::expandDefinition(Node node
)
1487 Debug("sets-proc") << "expandDefinition : " << node
<< std::endl
;
1489 if (node
.getKind() == kind::CHOOSE
)
1491 // (choose A) is expanded as
1492 // (witness ((x elementType))
1494 // (= A (as emptyset setType))
1495 // (= x chooseUf(A))
1496 // (and (member x A) (= x chooseUf(A)))
1498 NodeManager
* nm
= NodeManager::currentNM();
1500 TypeNode setType
= set
.getType();
1501 Node chooseSkolem
= getChooseFunction(setType
);
1502 Node apply
= NodeManager::currentNM()->mkNode(APPLY_UF
, chooseSkolem
, set
);
1504 Node witnessVariable
= nm
->mkBoundVar(setType
.getSetElementType());
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
);
1520 Node
TheorySetsPrivate::getChooseFunction(const TypeNode
& setType
)
1522 std::map
<TypeNode
, Node
>::iterator it
= d_chooseFunctions
.find(setType
);
1523 if (it
!= d_chooseFunctions
.end())
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
;
1539 void TheorySetsPrivate::presolve() { d_state
.reset(); }
1541 /**************************** eq::NotifyClass *****************************/
1542 /**************************** eq::NotifyClass *****************************/
1543 /**************************** eq::NotifyClass *****************************/
1545 bool TheorySetsPrivate::NotifyClass::eqNotifyTriggerEquality(TNode equality
,
1548 Debug("sets-eq") << "[sets-eq] eqNotifyTriggerEquality: equality = "
1549 << equality
<< " value = " << value
<< std::endl
;
1552 return d_theory
.propagate(equality
);
1556 // We use only literal triggers so taking not is safe
1557 return d_theory
.propagate(equality
.notNode());
1561 bool TheorySetsPrivate::NotifyClass::eqNotifyTriggerPredicate(TNode predicate
,
1564 Debug("sets-eq") << "[sets-eq] eqNotifyTriggerPredicate: predicate = "
1565 << predicate
<< " value = " << value
<< std::endl
;
1568 return d_theory
.propagate(predicate
);
1572 return d_theory
.propagate(predicate
.notNode());
1576 bool TheorySetsPrivate::NotifyClass::eqNotifyTriggerTermEquality(TheoryId tag
,
1581 Debug("sets-eq") << "[sets-eq] eqNotifyTriggerTermEquality: tag = " << tag
1582 << " t1 = " << t1
<< " t2 = " << t2
<< " value = " << value
1584 d_theory
.propagate(value
? t1
.eqNode(t2
) : t1
.eqNode(t2
).negate());
1588 void TheorySetsPrivate::NotifyClass::eqNotifyConstantTermMerge(TNode t1
,
1591 Debug("sets-eq") << "[sets-eq] eqNotifyConstantTermMerge "
1592 << " t1 = " << t1
<< " t2 = " << t2
<< std::endl
;
1593 d_theory
.conflict(t1
, t2
);
1596 void TheorySetsPrivate::NotifyClass::eqNotifyNewClass(TNode t
)
1598 Debug("sets-eq") << "[sets-eq] eqNotifyNewClass:"
1599 << " t = " << t
<< std::endl
;
1600 d_theory
.eqNotifyNewClass(t
);
1603 void TheorySetsPrivate::NotifyClass::eqNotifyPreMerge(TNode t1
, TNode t2
)
1605 Debug("sets-eq") << "[sets-eq] eqNotifyPreMerge:"
1606 << " t1 = " << t1
<< " t2 = " << t2
<< std::endl
;
1607 d_theory
.eqNotifyPreMerge(t1
, t2
);
1610 void TheorySetsPrivate::NotifyClass::eqNotifyPostMerge(TNode t1
, TNode t2
)
1612 Debug("sets-eq") << "[sets-eq] eqNotifyPostMerge:"
1613 << " t1 = " << t1
<< " t2 = " << t2
<< std::endl
;
1614 d_theory
.eqNotifyPostMerge(t1
, t2
);
1617 void TheorySetsPrivate::NotifyClass::eqNotifyDisequal(TNode t1
,
1621 Debug("sets-eq") << "[sets-eq] eqNotifyDisequal:"
1622 << " t1 = " << t1
<< " t2 = " << t2
<< " reason = " << reason
1624 d_theory
.eqNotifyDisequal(t1
, t2
, reason
);
1628 } // namespace theory