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
,
40 : d_members(state
.getSatContext()),
41 d_deq(state
.getSatContext()),
42 d_termProcessed(state
.getUserContext()),
43 d_full_check_incomplete(false),
47 d_rels(new TheorySetsRels(d_state
, d_im
)),
48 d_cardSolver(new CardinalityExtension(d_state
, d_im
)),
49 d_rels_enabled(false),
52 d_true
= NodeManager::currentNM()->mkConst(true);
53 d_false
= NodeManager::currentNM()->mkConst(false);
54 d_zero
= NodeManager::currentNM()->mkConst(Rational(0));
57 TheorySetsPrivate::~TheorySetsPrivate()
59 for (std::pair
<const Node
, EqcInfo
*>& current_pair
: d_eqc_info
)
61 delete current_pair
.second
;
65 void TheorySetsPrivate::finishInit()
67 d_equalityEngine
= d_external
.getEqualityEngine();
68 Assert(d_equalityEngine
!= nullptr);
71 void TheorySetsPrivate::eqNotifyNewClass(TNode t
)
73 if (t
.getKind() == kind::SINGLETON
|| t
.getKind() == kind::EMPTYSET
)
75 EqcInfo
* e
= getOrMakeEqcInfo(t
, true);
80 void TheorySetsPrivate::eqNotifyMerge(TNode t1
, TNode t2
)
82 if (!d_state
.isInConflict())
84 Trace("sets-prop-debug")
85 << "Merge " << t1
<< " and " << t2
<< "..." << std::endl
;
87 EqcInfo
* e2
= getOrMakeEqcInfo(t2
);
91 EqcInfo
* e1
= getOrMakeEqcInfo(t1
);
92 Trace("sets-prop-debug") << "Merging singletons..." << std::endl
;
96 if (!s1
.isNull() && !s2
.isNull())
98 if (s1
.getKind() == s2
.getKind())
100 Trace("sets-prop") << "Propagate eq inference : " << s1
101 << " == " << s2
<< std::endl
;
102 // infer equality between elements of singleton
103 Node exp
= s1
.eqNode(s2
);
104 Node eq
= s1
[0].eqNode(s2
[0]);
105 d_im
.assertInternalFact(eq
, true, exp
);
109 // singleton equal to emptyset, conflict
111 << "Propagate conflict : " << s1
<< " == " << s2
<< std::endl
;
120 e1
= getOrMakeEqcInfo(t1
, true);
121 e1
->d_singleton
.set(e2
->d_singleton
);
124 // merge membership list
125 Trace("sets-prop-debug") << "Copying membership list..." << std::endl
;
126 NodeIntMap::iterator mem_i2
= d_members
.find(t2
);
127 if (mem_i2
!= d_members
.end())
129 NodeIntMap::iterator mem_i1
= d_members
.find(t1
);
131 if (mem_i1
!= d_members
.end())
133 n_members
= (*mem_i1
).second
;
135 for (int i
= 0; i
< (*mem_i2
).second
; i
++)
137 Assert(i
< (int)d_members_data
[t2
].size()
138 && d_members_data
[t2
][i
].getKind() == kind::MEMBER
);
139 Node m2
= d_members_data
[t2
][i
];
140 // check if redundant
142 for (int j
= 0; j
< n_members
; j
++)
144 Assert(j
< (int)d_members_data
[t1
].size()
145 && d_members_data
[t1
][j
].getKind() == kind::MEMBER
);
146 if (d_state
.areEqual(m2
[0], d_members_data
[t1
][j
][0]))
154 if (!s1
.isNull() && s2
.isNull())
156 Assert(m2
[1].getType().isComparableTo(s1
.getType()));
157 Assert(d_state
.areEqual(m2
[1], s1
));
158 Node exp
= NodeManager::currentNM()->mkNode(
159 kind::AND
, m2
[1].eqNode(s1
), m2
);
160 if (s1
.getKind() == kind::SINGLETON
)
164 Node eq
= s1
[0].eqNode(m2
[0]);
165 Trace("sets-prop") << "Propagate eq-mem eq inference : " << exp
166 << " => " << eq
<< std::endl
;
167 d_im
.assertInternalFact(eq
, true, exp
);
174 << "Propagate eq-mem conflict : " << exp
<< std::endl
;
179 if (n_members
< (int)d_members_data
[t1
].size())
181 d_members_data
[t1
][n_members
] = m2
;
185 d_members_data
[t1
].push_back(m2
);
190 d_members
[t1
] = n_members
;
195 void TheorySetsPrivate::eqNotifyDisequal(TNode t1
, TNode t2
, TNode reason
)
197 if (t1
.getType().isSet())
199 Node eq
= t1
.eqNode(t2
);
200 if (d_deq
.find(eq
) == d_deq
.end())
207 TheorySetsPrivate::EqcInfo::EqcInfo(context::Context
* c
) : d_singleton(c
) {}
209 TheorySetsPrivate::EqcInfo
* TheorySetsPrivate::getOrMakeEqcInfo(TNode n
,
212 std::map
<Node
, EqcInfo
*>::iterator eqc_i
= d_eqc_info
.find(n
);
213 if (eqc_i
== d_eqc_info
.end())
218 ei
= new EqcInfo(d_external
.getSatContext());
225 return eqc_i
->second
;
229 bool TheorySetsPrivate::areCareDisequal(Node a
, Node b
)
231 if (d_equalityEngine
->isTriggerTerm(a
, THEORY_SETS
)
232 && d_equalityEngine
->isTriggerTerm(b
, THEORY_SETS
))
235 d_equalityEngine
->getTriggerTermRepresentative(a
, THEORY_SETS
);
237 d_equalityEngine
->getTriggerTermRepresentative(b
, THEORY_SETS
);
238 EqualityStatus eqStatus
=
239 d_external
.d_valuation
.getEqualityStatus(a_shared
, b_shared
);
240 if (eqStatus
== EQUALITY_FALSE_AND_PROPAGATED
|| eqStatus
== EQUALITY_FALSE
241 || eqStatus
== EQUALITY_FALSE_IN_MODEL
)
249 bool TheorySetsPrivate::isMember(Node x
, Node s
)
251 Assert(d_equalityEngine
->hasTerm(s
)
252 && d_equalityEngine
->getRepresentative(s
) == s
);
253 NodeIntMap::iterator mem_i
= d_members
.find(s
);
254 if (mem_i
!= d_members
.end())
256 for (int i
= 0; i
< (*mem_i
).second
; i
++)
258 if (d_state
.areEqual(d_members_data
[s
][i
][0], x
))
267 void TheorySetsPrivate::fullEffortReset()
269 Assert(d_equalityEngine
->consistent());
270 d_full_check_incomplete
= false;
271 d_most_common_type
.clear();
272 d_most_common_type_term
.clear();
273 d_card_enabled
= false;
274 d_rels_enabled
= false;
275 // reset the state object
277 // reset the inference manager
279 d_im
.clearPendingLemmas();
280 // reset the cardinality solver
281 d_cardSolver
->reset();
284 void TheorySetsPrivate::fullEffortCheck()
286 Trace("sets") << "----- Full effort check ------" << std::endl
;
289 Assert(!d_im
.hasPendingLemma() || d_im
.hasProcessed());
291 Trace("sets") << "...iterate full effort check..." << std::endl
;
294 Trace("sets-eqc") << "Equality Engine:" << std::endl
;
295 std::map
<TypeNode
, unsigned> eqcTypeCount
;
296 eq::EqClassesIterator eqcs_i
= eq::EqClassesIterator(d_equalityEngine
);
297 while (!eqcs_i
.isFinished())
299 Node eqc
= (*eqcs_i
);
301 TypeNode tn
= eqc
.getType();
302 d_state
.registerEqc(tn
, eqc
);
304 // common type node and term
310 tnc
= tn
.getSetElementType();
313 Trace("sets-eqc") << "[" << eqc
<< "] : ";
314 eq::EqClassIterator eqc_i
= eq::EqClassIterator(eqc
, d_equalityEngine
);
315 while (!eqc_i
.isFinished())
320 Trace("sets-eqc") << n
<< " ";
322 TypeNode tnn
= n
.getType();
326 TypeNode tnnel
= tnn
.getSetElementType();
327 tnc
= TypeNode::mostCommonTypeNode(tnc
, tnnel
);
328 Assert(!tnc
.isNull());
329 // update the common type term
335 // register it with the state
336 d_state
.registerTerm(eqc
, tnn
, n
);
337 if (n
.getKind() == kind::CARD
)
339 d_card_enabled
= true;
340 // register it with the cardinality solver
341 d_cardSolver
->registerTerm(n
);
342 // if we do not handle the kind, set incomplete
343 Kind nk
= n
[0].getKind();
344 // some kinds of cardinality we cannot handle
345 if (d_rels
->isRelationKind(nk
))
347 d_full_check_incomplete
= true;
348 Trace("sets-incomplete")
349 << "Sets : incomplete because of " << n
<< "." << std::endl
;
350 // TODO (#1124): The issue can be divided into 4 parts
351 // 1- Supporting the universe cardinality for finite types with
352 // finite cardinality (done)
353 // 2- Supporting the universe cardinality for uninterpreted sorts
354 // with finite-model-find (pending) See the implementation of
355 // CardinalityExtension::checkCardinalityExtended
356 // 3- Supporting the universe cardinality for non-finite types
358 // 4- Supporting cardinality for relations (hard)
363 if (d_rels
->isRelationKind(n
.getKind()))
365 d_rels_enabled
= true;
372 Assert(tnct
.getType().getSetElementType() == tnc
);
373 d_most_common_type
[eqc
] = tnc
;
374 d_most_common_type_term
[eqc
] = tnct
;
376 Trace("sets-eqc") << std::endl
;
380 Trace("sets-eqc") << "...finished equality engine." << std::endl
;
382 if (Trace
.isOn("sets-state"))
384 Trace("sets-state") << "Equivalence class counters:" << std::endl
;
385 for (std::pair
<const TypeNode
, unsigned>& ec
: eqcTypeCount
)
388 << " " << ec
.first
<< " -> " << ec
.second
<< std::endl
;
392 // We may have sent lemmas while registering the terms in the loop above,
393 // e.g. the cardinality solver.
394 if (d_im
.hasProcessed())
398 if (Trace
.isOn("sets-mem"))
400 const std::vector
<Node
>& sec
= d_state
.getSetsEqClasses();
401 for (const Node
& s
: sec
)
403 Trace("sets-mem") << "Eqc " << s
<< " : ";
404 const std::map
<Node
, Node
>& smem
= d_state
.getMembers(s
);
407 Trace("sets-mem") << "Memberships : ";
408 for (const std::pair
<const Node
, Node
>& it2
: smem
)
410 Trace("sets-mem") << it2
.first
<< " ";
413 Node ss
= d_state
.getSingletonEqClass(s
);
416 Trace("sets-mem") << " : Singleton : " << ss
;
418 Trace("sets-mem") << std::endl
;
423 d_im
.doPendingLemmas();
424 if (d_im
.hasProcessed())
428 // check downwards closure
429 checkDownwardsClosure();
430 d_im
.doPendingLemmas();
431 if (d_im
.hasProcessed())
435 // check upwards closure
436 checkUpwardsClosure();
437 d_im
.doPendingLemmas();
438 if (d_im
.hasProcessed())
442 // check disequalities
443 checkDisequalities();
444 d_im
.doPendingLemmas();
445 if (d_im
.hasProcessed())
449 // check reduce comprehensions
450 checkReduceComprehensions();
451 d_im
.doPendingLemmas();
452 if (d_im
.hasProcessed())
458 // call the check method of the cardinality solver
459 d_cardSolver
->check();
460 if (d_im
.hasProcessed())
467 // call the check method of the relations solver
468 d_rels
->check(Theory::EFFORT_FULL
);
470 } while (!d_im
.hasSentLemma() && !d_state
.isInConflict()
471 && d_im
.hasSentFact());
472 Assert(!d_im
.hasPendingLemma() || d_im
.hasProcessed());
473 Trace("sets") << "----- End full effort check, conflict="
474 << d_state
.isInConflict() << ", lemma=" << d_im
.hasSentLemma()
478 void TheorySetsPrivate::checkSubtypes()
480 Trace("sets") << "TheorySetsPrivate: check Subtypes..." << std::endl
;
481 const std::vector
<Node
>& sec
= d_state
.getSetsEqClasses();
482 for (const Node
& s
: sec
)
484 TypeNode mct
= d_most_common_type
[s
];
485 Assert(!mct
.isNull());
486 const std::map
<Node
, Node
>& smems
= d_state
.getMembers(s
);
489 for (const std::pair
<const Node
, Node
>& it2
: smems
)
491 Trace("sets") << " check subtype " << it2
.first
<< " " << it2
.second
493 Trace("sets") << " types : " << it2
.first
.getType() << " " << mct
495 if (!it2
.first
.getType().isSubtypeOf(mct
))
497 Node mctt
= d_most_common_type_term
[s
];
498 Assert(!mctt
.isNull());
499 Trace("sets") << " most common type term is " << mctt
<< std::endl
;
500 std::vector
<Node
> exp
;
501 exp
.push_back(it2
.second
);
502 Assert(d_state
.areEqual(mctt
, it2
.second
[1]));
503 exp
.push_back(mctt
.eqNode(it2
.second
[1]));
504 Node tc_k
= d_state
.getTypeConstraintSkolem(it2
.first
, mct
);
507 Node etc
= tc_k
.eqNode(it2
.first
);
508 d_im
.assertInference(etc
, exp
, "subtype-clash");
509 if (d_state
.isInConflict())
518 Trace("sets") << "TheorySetsPrivate: finished." << std::endl
;
521 void TheorySetsPrivate::checkDownwardsClosure()
523 Trace("sets") << "TheorySetsPrivate: check downwards closure..." << std::endl
;
525 const std::vector
<Node
>& sec
= d_state
.getSetsEqClasses();
526 for (const Node
& s
: sec
)
528 const std::vector
<Node
>& nvsets
= d_state
.getNonVariableSets(s
);
531 const std::map
<Node
, Node
>& smem
= d_state
.getMembers(s
);
532 for (const Node
& nv
: nvsets
)
534 if (!d_state
.isCongruent(nv
))
536 for (const std::pair
<const Node
, Node
>& it2
: smem
)
538 Node mem
= it2
.second
;
540 Assert(d_equalityEngine
->areEqual(mem
[1], eq_set
));
541 if (mem
[1] != eq_set
)
543 Trace("sets-debug") << "Downwards closure based on " << mem
544 << ", eq_set = " << eq_set
<< std::endl
;
545 if (!options::setsProxyLemmas())
547 Node nmem
= NodeManager::currentNM()->mkNode(
548 kind::MEMBER
, mem
[0], eq_set
);
549 nmem
= Rewriter::rewrite(nmem
);
550 std::vector
<Node
> exp
;
552 exp
.push_back(mem
[1].eqNode(eq_set
));
553 d_im
.assertInference(nmem
, exp
, "downc");
554 if (d_state
.isInConflict())
562 Node k
= d_state
.getProxy(eq_set
);
564 NodeManager::currentNM()->mkNode(kind::MEMBER
, mem
[0], k
);
565 Node nmem
= NodeManager::currentNM()->mkNode(
566 kind::MEMBER
, mem
[0], eq_set
);
567 nmem
= Rewriter::rewrite(nmem
);
568 std::vector
<Node
> exp
;
569 if (d_state
.areEqual(mem
, pmem
))
575 nmem
= NodeManager::currentNM()->mkNode(
576 kind::OR
, pmem
.negate(), nmem
);
578 d_im
.assertInference(nmem
, exp
, "downc");
588 void TheorySetsPrivate::checkUpwardsClosure()
591 NodeManager
* nm
= NodeManager::currentNM();
592 const std::map
<Kind
, std::map
<Node
, std::map
<Node
, Node
> > >& boi
=
593 d_state
.getBinaryOpIndex();
594 for (const std::pair
<const Kind
, std::map
<Node
, std::map
<Node
, Node
> > >&
598 Trace("sets") << "TheorySetsPrivate: check upwards closure " << k
<< "..."
600 for (const std::pair
<const Node
, std::map
<Node
, Node
> >& it
: itb
.second
)
603 // see if there are members in first argument r1
604 const std::map
<Node
, Node
>& r1mem
= d_state
.getMembers(r1
);
605 if (!r1mem
.empty() || k
== kind::UNION
)
607 for (const std::pair
<const Node
, Node
>& it2
: it
.second
)
610 Node term
= it2
.second
;
611 // see if there are members in second argument
612 const std::map
<Node
, Node
>& r2mem
= d_state
.getMembers(r2
);
613 const std::map
<Node
, Node
>& r2nmem
= d_state
.getNegativeMembers(r2
);
614 if (!r2mem
.empty() || k
!= kind::INTERSECTION
)
617 << "Checking " << term
<< ", members = " << (!r1mem
.empty())
618 << ", " << (!r2mem
.empty()) << std::endl
;
619 // for all members of r1
622 for (const std::pair
<const Node
, Node
>& itm1m
: r1mem
)
624 Node xr
= itm1m
.first
;
625 Node x
= itm1m
.second
[0];
626 Trace("sets-debug") << "checking membership " << xr
<< " "
627 << itm1m
.second
<< std::endl
;
628 std::vector
<Node
> exp
;
629 exp
.push_back(itm1m
.second
);
630 d_state
.addEqualityToExp(term
[0], itm1m
.second
[1], exp
);
633 if (k
== kind::UNION
)
637 else if (k
== kind::INTERSECTION
)
639 // conclude x is in term
640 // if also existing in members of r2
641 std::map
<Node
, Node
>::const_iterator itm
= r2mem
.find(xr
);
642 if (itm
!= r2mem
.end())
644 exp
.push_back(itm
->second
);
645 d_state
.addEqualityToExp(term
[1], itm
->second
[1], exp
);
646 d_state
.addEqualityToExp(x
, itm
->second
[0], exp
);
651 // if not, check whether it is definitely not a member, if
653 if (r2nmem
.find(xr
) == r2nmem
.end())
655 exp
.push_back(nm
->mkNode(kind::MEMBER
, x
, term
[1]));
663 Assert(k
== kind::SETMINUS
);
664 std::map
<Node
, Node
>::const_iterator itm
= r2mem
.find(xr
);
665 if (itm
== r2mem
.end())
667 // must add lemma for set minus since non-membership in this
668 // case is not explained
670 nm
->mkNode(kind::MEMBER
, x
, term
[1]).negate());
677 Node rr
= d_equalityEngine
->getRepresentative(term
);
678 if (!isMember(x
, rr
))
680 Node kk
= d_state
.getProxy(term
);
681 Node fact
= nm
->mkNode(kind::MEMBER
, x
, kk
);
682 d_im
.assertInference(fact
, exp
, "upc", inferType
);
683 if (d_state
.isInConflict())
689 Trace("sets-debug") << "done checking membership " << xr
<< " "
690 << itm1m
.second
<< std::endl
;
693 if (k
== kind::UNION
)
697 // for all members of r2
698 for (const std::pair
<const Node
, Node
>& itm2m
: r2mem
)
700 Node x
= itm2m
.second
[0];
701 Node rr
= d_equalityEngine
->getRepresentative(term
);
702 if (!isMember(x
, rr
))
704 std::vector
<Node
> exp
;
705 exp
.push_back(itm2m
.second
);
706 d_state
.addEqualityToExp(term
[1], itm2m
.second
[1], exp
);
707 Node r
= d_state
.getProxy(term
);
708 Node fact
= nm
->mkNode(kind::MEMBER
, x
, r
);
709 d_im
.assertInference(fact
, exp
, "upc2");
710 if (d_state
.isInConflict())
723 if (!d_im
.hasProcessed())
725 if (options::setsExt())
728 Trace("sets-debug") << "Check universe sets..." << std::endl
;
729 // all elements must be in universal set
730 const std::vector
<Node
>& sec
= d_state
.getSetsEqClasses();
731 for (const Node
& s
: sec
)
733 // if equivalence class contains a variable
734 Node v
= d_state
.getVariableSet(s
);
737 // the variable in the equivalence class
738 std::map
<TypeNode
, Node
> univ_set
;
739 const std::map
<Node
, Node
>& smems
= d_state
.getMembers(s
);
740 for (const std::pair
<const Node
, Node
>& it2
: smems
)
742 Node e
= it2
.second
[0];
743 TypeNode tn
= NodeManager::currentNM()->mkSetType(e
.getType());
745 std::map
<TypeNode
, Node
>::iterator itu
= univ_set
.find(tn
);
746 if (itu
== univ_set
.end())
748 Node ueqc
= d_state
.getUnivSetEqClass(tn
);
749 // if the universe does not yet exist, or is not in this
753 u
= d_state
.getUnivSet(tn
);
763 Assert(it2
.second
.getKind() == kind::MEMBER
);
764 std::vector
<Node
> exp
;
765 exp
.push_back(it2
.second
);
766 if (v
!= it2
.second
[1])
768 exp
.push_back(v
.eqNode(it2
.second
[1]));
770 Node fact
= nm
->mkNode(kind::MEMBER
, it2
.second
[0], u
);
771 d_im
.assertInference(fact
, exp
, "upuniv");
772 if (d_state
.isInConflict())
784 void TheorySetsPrivate::checkDisequalities()
787 Trace("sets") << "TheorySetsPrivate: check disequalities..." << std::endl
;
788 NodeManager
* nm
= NodeManager::currentNM();
789 for (NodeBoolMap::const_iterator it
= d_deq
.begin(); it
!= d_deq
.end(); ++it
)
796 Node deq
= (*it
).first
;
797 // check if it is already satisfied
798 Assert(d_equalityEngine
->hasTerm(deq
[0])
799 && d_equalityEngine
->hasTerm(deq
[1]));
800 Node r1
= d_equalityEngine
->getRepresentative(deq
[0]);
801 Node r2
= d_equalityEngine
->getRepresentative(deq
[1]);
802 bool is_sat
= d_state
.isSetDisequalityEntailed(r1
, r2
);
803 Trace("sets-debug") << "Check disequality " << deq
804 << ", is_sat = " << is_sat
<< std::endl
;
805 // will process regardless of sat/processed/unprocessed
813 if (d_termProcessed
.find(deq
) != d_termProcessed
.end())
815 // already added lemma
818 d_termProcessed
.insert(deq
);
819 d_termProcessed
.insert(deq
[1].eqNode(deq
[0]));
820 Trace("sets") << "Process Disequality : " << deq
.negate() << std::endl
;
821 TypeNode elementType
= deq
[0].getType().getSetElementType();
822 Node x
= d_state
.getSkolemCache().mkTypedSkolemCached(
823 elementType
, deq
[0], deq
[1], SkolemCache::SK_DISEQUAL
, "sde");
824 Node mem1
= nm
->mkNode(MEMBER
, x
, deq
[0]);
825 Node mem2
= nm
->mkNode(MEMBER
, x
, deq
[1]);
826 Node lem
= nm
->mkNode(OR
, deq
, nm
->mkNode(EQUAL
, mem1
, mem2
).negate());
827 lem
= Rewriter::rewrite(lem
);
828 d_im
.assertInference(lem
, d_true
, "diseq", 1);
829 d_im
.doPendingLemmas();
830 if (d_im
.hasProcessed())
837 void TheorySetsPrivate::checkReduceComprehensions()
839 NodeManager
* nm
= NodeManager::currentNM();
840 const std::vector
<Node
>& comps
= d_state
.getComprehensionSets();
841 for (const Node
& n
: comps
)
843 if (d_termProcessed
.find(n
) != d_termProcessed
.end())
845 // already reduced it
848 d_termProcessed
.insert(n
);
849 Node v
= nm
->mkBoundVar(n
[2].getType());
850 Node body
= nm
->mkNode(AND
, n
[1], v
.eqNode(n
[2]));
851 // must do substitution
852 std::vector
<Node
> vars
;
853 std::vector
<Node
> subs
;
854 for (const Node
& cv
: n
[0])
857 Node cvs
= nm
->mkBoundVar(cv
.getType());
860 body
= body
.substitute(vars
.begin(), vars
.end(), subs
.begin(), subs
.end());
861 Node bvl
= nm
->mkNode(BOUND_VAR_LIST
, subs
);
862 body
= nm
->mkNode(EXISTS
, bvl
, body
);
863 Node mem
= nm
->mkNode(MEMBER
, v
, n
);
865 nm
->mkNode(FORALL
, nm
->mkNode(BOUND_VAR_LIST
, v
), body
.eqNode(mem
));
866 Trace("sets-comprehension")
867 << "Comprehension reduction: " << lem
<< std::endl
;
872 //--------------------------------- standard check
874 void TheorySetsPrivate::postCheck(Theory::Effort level
)
876 Trace("sets-check") << "Sets finished assertions effort " << level
878 // invoke full effort check, relations check
879 if (!d_state
.isInConflict())
881 if (level
== Theory::EFFORT_FULL
)
883 if (!d_external
.d_valuation
.needCheck())
886 if (!d_state
.isInConflict() && !d_im
.hasSentLemma()
887 && d_full_check_incomplete
)
889 d_external
.d_out
->setIncomplete();
894 Trace("sets-check") << "Sets finish Check effort " << level
<< std::endl
;
897 void TheorySetsPrivate::notifyFact(TNode atom
, bool polarity
, TNode fact
)
899 if (d_state
.isInConflict())
903 if (atom
.getKind() == kind::MEMBER
&& polarity
)
905 // check if set has a value, if so, we can propagate
906 Node r
= d_equalityEngine
->getRepresentative(atom
[1]);
907 EqcInfo
* e
= getOrMakeEqcInfo(r
, true);
910 Node s
= e
->d_singleton
;
913 Node pexp
= NodeManager::currentNM()->mkNode(
914 kind::AND
, atom
, atom
[1].eqNode(s
));
915 if (s
.getKind() == kind::SINGLETON
)
919 Trace("sets-prop") << "Propagate mem-eq : " << pexp
<< std::endl
;
920 Node eq
= s
[0].eqNode(atom
[0]);
921 // triggers an internal inference
922 d_im
.assertInternalFact(eq
, true, pexp
);
928 << "Propagate mem-eq conflict : " << pexp
<< std::endl
;
933 // add to membership list
934 NodeIntMap::iterator mem_i
= d_members
.find(r
);
936 if (mem_i
!= d_members
.end())
938 n_members
= (*mem_i
).second
;
940 d_members
[r
] = n_members
+ 1;
941 if (n_members
< (int)d_members_data
[r
].size())
943 d_members_data
[r
][n_members
] = atom
;
947 d_members_data
[r
].push_back(atom
);
951 //--------------------------------- end standard check
953 /************************ Sharing ************************/
954 /************************ Sharing ************************/
955 /************************ Sharing ************************/
957 void TheorySetsPrivate::addCarePairs(TNodeTrie
* t1
,
967 Node f1
= t1
->getData();
968 Node f2
= t2
->getData();
969 if (!d_state
.areEqual(f1
, f2
))
971 Trace("sets-cg") << "Check " << f1
<< " and " << f2
<< std::endl
;
972 vector
<pair
<TNode
, TNode
> > currentPairs
;
973 for (unsigned k
= 0; k
< f1
.getNumChildren(); ++k
)
977 Assert(d_equalityEngine
->hasTerm(x
));
978 Assert(d_equalityEngine
->hasTerm(y
));
979 Assert(!d_state
.areDisequal(x
, y
));
980 Assert(!areCareDisequal(x
, y
));
981 if (!d_equalityEngine
->areEqual(x
, y
))
984 << "Arg #" << k
<< " is " << x
<< " " << y
<< std::endl
;
985 if (d_equalityEngine
->isTriggerTerm(x
, THEORY_SETS
)
986 && d_equalityEngine
->isTriggerTerm(y
, THEORY_SETS
))
988 TNode x_shared
= d_equalityEngine
->getTriggerTermRepresentative(
990 TNode y_shared
= d_equalityEngine
->getTriggerTermRepresentative(
992 currentPairs
.push_back(make_pair(x_shared
, y_shared
));
994 else if (isCareArg(f1
, k
) && isCareArg(f2
, k
))
996 // splitting on sets (necessary for handling set of sets properly)
997 if (x
.getType().isSet())
999 Assert(y
.getType().isSet());
1000 if (!d_state
.areDisequal(x
, y
))
1002 Trace("sets-cg-lemma")
1003 << "Should split on : " << x
<< "==" << y
<< std::endl
;
1004 d_im
.split(x
.eqNode(y
));
1010 for (unsigned c
= 0; c
< currentPairs
.size(); ++c
)
1012 Trace("sets-cg-pair") << "Pair : " << currentPairs
[c
].first
<< " "
1013 << currentPairs
[c
].second
<< std::endl
;
1014 d_external
.addCarePair(currentPairs
[c
].first
, currentPairs
[c
].second
);
1024 if (depth
< (arity
- 1))
1026 // add care pairs internal to each child
1027 for (std::pair
<const TNode
, TNodeTrie
>& t
: t1
->d_data
)
1029 addCarePairs(&t
.second
, NULL
, arity
, depth
+ 1, n_pairs
);
1032 // add care pairs based on each pair of non-disequal arguments
1033 for (std::map
<TNode
, TNodeTrie
>::iterator it
= t1
->d_data
.begin();
1034 it
!= t1
->d_data
.end();
1037 std::map
<TNode
, TNodeTrie
>::iterator it2
= it
;
1039 for (; it2
!= t1
->d_data
.end(); ++it2
)
1041 if (!d_equalityEngine
->areDisequal(it
->first
, it2
->first
, false))
1043 if (!areCareDisequal(it
->first
, it2
->first
))
1046 &it
->second
, &it2
->second
, arity
, depth
+ 1, n_pairs
);
1054 // add care pairs based on product of indices, non-disequal arguments
1055 for (std::pair
<const TNode
, TNodeTrie
>& tt1
: t1
->d_data
)
1057 for (std::pair
<const TNode
, TNodeTrie
>& tt2
: t2
->d_data
)
1059 if (!d_equalityEngine
->areDisequal(tt1
.first
, tt2
.first
, false))
1061 if (!areCareDisequal(tt1
.first
, tt2
.first
))
1063 addCarePairs(&tt1
.second
, &tt2
.second
, arity
, depth
+ 1, n_pairs
);
1072 void TheorySetsPrivate::computeCareGraph()
1074 const std::map
<Kind
, std::vector
<Node
> >& ol
= d_state
.getOperatorList();
1075 for (const std::pair
<const Kind
, std::vector
<Node
> >& it
: ol
)
1078 if (k
== kind::SINGLETON
|| k
== kind::MEMBER
)
1080 unsigned n_pairs
= 0;
1081 Trace("sets-cg-summary") << "Compute graph for sets, op=" << k
<< "..."
1082 << it
.second
.size() << std::endl
;
1083 Trace("sets-cg") << "Build index for " << k
<< "..." << std::endl
;
1084 std::map
<TypeNode
, TNodeTrie
> index
;
1087 for (TNode f1
: it
.second
)
1089 Assert(d_equalityEngine
->hasTerm(f1
));
1090 Trace("sets-cg-debug") << "...build for " << f1
<< std::endl
;
1091 Assert(d_equalityEngine
->hasTerm(f1
));
1092 // break into index based on operator, and type of first argument (since
1093 // some operators are parametric)
1094 TypeNode tn
= f1
[0].getType();
1095 std::vector
<TNode
> reps
;
1096 bool hasCareArg
= false;
1097 for (unsigned j
= 0; j
< f1
.getNumChildren(); j
++)
1099 reps
.push_back(d_equalityEngine
->getRepresentative(f1
[j
]));
1100 if (isCareArg(f1
, j
))
1107 Trace("sets-cg-debug") << "......adding." << std::endl
;
1108 index
[tn
].addTerm(f1
, reps
);
1109 arity
= reps
.size();
1113 Trace("sets-cg-debug") << "......skip." << std::endl
;
1119 for (std::pair
<const TypeNode
, TNodeTrie
>& tt
: index
)
1121 Trace("sets-cg") << "Process index " << tt
.first
<< "..."
1123 addCarePairs(&tt
.second
, nullptr, arity
, 0, n_pairs
);
1126 Trace("sets-cg-summary") << "...done, # pairs = " << n_pairs
<< std::endl
;
1131 bool TheorySetsPrivate::isCareArg(Node n
, unsigned a
)
1133 if (d_equalityEngine
->isTriggerTerm(n
[a
], THEORY_SETS
))
1137 else if ((n
.getKind() == kind::MEMBER
|| n
.getKind() == kind::SINGLETON
)
1138 && a
== 0 && n
[0].getType().isSet())
1148 /******************** Model generation ********************/
1149 /******************** Model generation ********************/
1150 /******************** Model generation ********************/
1154 * This function is a helper function to print sets as
1155 * Set A = { a0, a1, a2, }
1157 * (union (singleton a0) (union (singleton a1) (singleton a2)))
1159 void traceSetElementsRecursively(stringstream
& stream
, const Node
& set
)
1161 Assert(set
.getType().isSet());
1162 if (set
.getKind() == SINGLETON
)
1164 stream
<< set
[0] << ", ";
1166 if (set
.getKind() == UNION
)
1168 traceSetElementsRecursively(stream
, set
[0]);
1169 traceSetElementsRecursively(stream
, set
[1]);
1173 std::string
traceElements(const Node
& set
)
1175 std::stringstream stream
;
1176 traceSetElementsRecursively(stream
, set
);
1177 return stream
.str();
1182 bool TheorySetsPrivate::collectModelValues(TheoryModel
* m
,
1183 const std::set
<Node
>& termSet
)
1185 Trace("sets-model") << "Set collect model values" << std::endl
;
1187 NodeManager
* nm
= NodeManager::currentNM();
1188 std::map
<Node
, Node
> mvals
;
1189 // If cardinality is enabled, we need to use the ordered equivalence class
1190 // list computed by the cardinality solver, where sets equivalence classes
1191 // are assigned model values based on their position in the cardinality
1193 const std::vector
<Node
>& sec
= d_card_enabled
1194 ? d_cardSolver
->getOrderedSetsEqClasses()
1195 : d_state
.getSetsEqClasses();
1196 Valuation
& val
= getValuation();
1197 for (int i
= (int)(sec
.size() - 1); i
>= 0; i
--)
1200 if (termSet
.find(eqc
) == termSet
.end())
1202 Trace("sets-model") << "* Do not assign value for " << eqc
1203 << " since is not relevant." << std::endl
;
1207 std::vector
<Node
> els
;
1208 bool is_base
= !d_card_enabled
|| d_cardSolver
->isModelValueBasic(eqc
);
1212 << "Collect elements of base eqc " << eqc
<< std::endl
;
1213 // members that must be in eqc
1214 const std::map
<Node
, Node
>& emems
= d_state
.getMembers(eqc
);
1217 for (const std::pair
<const Node
, Node
>& itmm
: emems
)
1219 Node t
= nm
->mkNode(kind::SINGLETON
, itmm
.first
);
1226 // make the slack elements for the equivalence class based on set
1228 d_cardSolver
->mkModelValueElementsFor(val
, eqc
, els
, mvals
, m
);
1230 Node rep
= NormalForm::mkBop(kind::UNION
, els
, eqc
.getType());
1231 rep
= Rewriter::rewrite(rep
);
1232 Trace("sets-model") << "* Assign representative of " << eqc
<< " to "
1233 << rep
<< std::endl
;
1235 if (!m
->assertEquality(eqc
, rep
, true))
1239 m
->assertSkeleton(rep
);
1241 Trace("sets-model") << "Set " << eqc
<< " = { " << traceElements(rep
)
1242 << " }" << std::endl
;
1246 // handle slack elements constraints for finite types
1249 const std::map
<TypeNode
, std::vector
<TNode
> >& slackElements
=
1250 d_cardSolver
->getFiniteTypeSlackElements();
1251 for (const std::pair
<TypeNode
, std::vector
<TNode
> >& pair
: slackElements
)
1253 const std::vector
<Node
>& members
=
1254 d_cardSolver
->getFiniteTypeMembers(pair
.first
);
1255 m
->setAssignmentExclusionSetGroup(pair
.second
, members
);
1256 Trace("sets-model") << "ExclusionSet: Group " << pair
.second
1257 << " is excluded from set" << members
<< std::endl
;
1263 /********************** Helper functions ***************************/
1264 /********************** Helper functions ***************************/
1265 /********************** Helper functions ***************************/
1267 Node
mkAnd(const std::vector
<TNode
>& conjunctions
)
1269 Assert(conjunctions
.size() > 0);
1271 std::set
<TNode
> all
;
1272 for (unsigned i
= 0; i
< conjunctions
.size(); ++i
)
1274 TNode t
= conjunctions
[i
];
1275 if (t
.getKind() == kind::AND
)
1277 for (TNode::iterator child_it
= t
.begin(); child_it
!= t
.end();
1280 Assert((*child_it
).getKind() != kind::AND
);
1281 all
.insert(*child_it
);
1290 Assert(all
.size() > 0);
1291 if (all
.size() == 1)
1293 // All the same, or just one
1294 return conjunctions
[0];
1297 NodeBuilder
<> conjunction(kind::AND
);
1298 std::set
<TNode
>::const_iterator it
= all
.begin();
1299 std::set
<TNode
>::const_iterator it_end
= all
.end();
1300 while (it
!= it_end
)
1308 bool TheorySetsPrivate::propagate(TNode literal
)
1310 Debug("sets-prop") << " propagate(" << literal
<< ")" << std::endl
;
1312 // If already in conflict, no more propagation
1313 if (d_state
.isInConflict())
1315 Debug("sets-prop") << "TheoryUF::propagate(" << literal
1316 << "): already in conflict" << std::endl
;
1321 bool ok
= d_external
.d_out
->propagate(literal
);
1324 d_state
.notifyInConflict();
1328 } /* TheorySetsPrivate::propagate(TNode) */
1330 OutputChannel
* TheorySetsPrivate::getOutputChannel()
1332 return d_external
.d_out
;
1335 Valuation
& TheorySetsPrivate::getValuation() { return d_external
.d_valuation
; }
1337 void TheorySetsPrivate::conflict(TNode a
, TNode b
)
1339 Node conf
= explain(a
.eqNode(b
));
1340 d_im
.conflict(conf
);
1341 Debug("sets") << "[sets] conflict: " << a
<< " iff " << b
<< ", explanation "
1342 << conf
<< std::endl
;
1343 Trace("sets-lemma") << "Equality Conflict : " << conf
<< std::endl
;
1346 Node
TheorySetsPrivate::explain(TNode literal
)
1348 Debug("sets") << "TheorySetsPrivate::explain(" << literal
<< ")" << std::endl
;
1350 bool polarity
= literal
.getKind() != kind::NOT
;
1351 TNode atom
= polarity
? literal
: literal
[0];
1352 std::vector
<TNode
> assumptions
;
1354 if (atom
.getKind() == kind::EQUAL
)
1356 d_equalityEngine
->explainEquality(atom
[0], atom
[1], polarity
, assumptions
);
1358 else if (atom
.getKind() == kind::MEMBER
)
1360 d_equalityEngine
->explainPredicate(atom
, polarity
, assumptions
);
1364 Debug("sets") << "unhandled: " << literal
<< "; (" << atom
<< ", "
1365 << polarity
<< "); kind" << atom
.getKind() << std::endl
;
1369 return mkAnd(assumptions
);
1372 void TheorySetsPrivate::preRegisterTerm(TNode node
)
1374 Debug("sets") << "TheorySetsPrivate::preRegisterTerm(" << node
<< ")"
1376 switch (node
.getKind())
1381 // add trigger predicate for equality and membership
1382 d_equalityEngine
->addTriggerPredicate(node
);
1385 case kind::CARD
: d_equalityEngine
->addTriggerTerm(node
, THEORY_SETS
); break;
1386 default: d_equalityEngine
->addTerm(node
); break;
1390 TrustNode
TheorySetsPrivate::expandDefinition(Node node
)
1392 Debug("sets-proc") << "expandDefinition : " << node
<< std::endl
;
1394 if (node
.getKind() == kind::CHOOSE
)
1396 // (choose A) is expanded as
1397 // (witness ((x elementType))
1399 // (= A (as emptyset setType))
1400 // (= x chooseUf(A))
1401 // (and (member x A) (= x chooseUf(A)))
1403 NodeManager
* nm
= NodeManager::currentNM();
1405 TypeNode setType
= set
.getType();
1406 Node chooseSkolem
= getChooseFunction(setType
);
1407 Node apply
= NodeManager::currentNM()->mkNode(APPLY_UF
, chooseSkolem
, set
);
1409 Node witnessVariable
= nm
->mkBoundVar(setType
.getSetElementType());
1411 Node equal
= witnessVariable
.eqNode(apply
);
1412 Node emptySet
= nm
->mkConst(EmptySet(setType
));
1413 Node isEmpty
= set
.eqNode(emptySet
);
1414 Node member
= nm
->mkNode(MEMBER
, witnessVariable
, set
);
1415 Node memberAndEqual
= member
.andNode(equal
);
1416 Node ite
= nm
->mkNode(kind::ITE
, isEmpty
, equal
, memberAndEqual
);
1417 Node witnessVariables
= nm
->mkNode(BOUND_VAR_LIST
, witnessVariable
);
1418 Node witness
= nm
->mkNode(WITNESS
, witnessVariables
, ite
);
1419 return TrustNode::mkTrustRewrite(node
, witness
, nullptr);
1422 return TrustNode::null();
1425 Node
TheorySetsPrivate::getChooseFunction(const TypeNode
& setType
)
1427 std::map
<TypeNode
, Node
>::iterator it
= d_chooseFunctions
.find(setType
);
1428 if (it
!= d_chooseFunctions
.end())
1433 NodeManager
* nm
= NodeManager::currentNM();
1434 TypeNode chooseUf
= nm
->mkFunctionType(setType
, setType
.getSetElementType());
1435 stringstream stream
;
1436 stream
<< "chooseUf" << setType
.getId();
1437 string name
= stream
.str();
1438 Node chooseSkolem
= nm
->mkSkolem(
1439 name
, chooseUf
, "choose function", NodeManager::SKOLEM_EXACT_NAME
);
1440 d_chooseFunctions
[setType
] = chooseSkolem
;
1441 return chooseSkolem
;
1444 void TheorySetsPrivate::presolve() { d_state
.reset(); }
1447 } // namespace theory