1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Mudathir Mohamed, Gereon Kremer |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* Implementation of an extension of the theory sets for handling |
14 |
|
* cardinality constraints. |
15 |
|
*/ |
16 |
|
|
17 |
|
#include "theory/sets/cardinality_extension.h" |
18 |
|
|
19 |
|
#include "expr/emptyset.h" |
20 |
|
#include "expr/node_algorithm.h" |
21 |
|
#include "expr/skolem_manager.h" |
22 |
|
#include "options/sets_options.h" |
23 |
|
#include "smt/logic_exception.h" |
24 |
|
#include "theory/rewriter.h" |
25 |
|
#include "theory/sets/normal_form.h" |
26 |
|
#include "theory/theory_model.h" |
27 |
|
#include "theory/valuation.h" |
28 |
|
#include "util/cardinality.h" |
29 |
|
#include "util/rational.h" |
30 |
|
|
31 |
|
using namespace std; |
32 |
|
using namespace cvc5::kind; |
33 |
|
|
34 |
|
namespace cvc5 { |
35 |
|
namespace theory { |
36 |
|
namespace sets { |
37 |
|
|
38 |
9928 |
CardinalityExtension::CardinalityExtension(SolverState& s, |
39 |
|
InferenceManager& im, |
40 |
9928 |
TermRegistry& treg) |
41 |
|
: d_state(s), |
42 |
|
d_im(im), |
43 |
|
d_treg(treg), |
44 |
9928 |
d_card_processed(s.getUserContext()), |
45 |
19856 |
d_finite_type_constants_processed(false) |
46 |
|
{ |
47 |
9928 |
d_true = NodeManager::currentNM()->mkConst(true); |
48 |
9928 |
d_zero = NodeManager::currentNM()->mkConst(Rational(0)); |
49 |
9928 |
} |
50 |
|
|
51 |
20831 |
void CardinalityExtension::reset() |
52 |
|
{ |
53 |
20831 |
d_eqc_to_card_term.clear(); |
54 |
20831 |
d_t_card_enabled.clear(); |
55 |
20831 |
d_finite_type_elements.clear(); |
56 |
20831 |
d_finite_type_slack_elements.clear(); |
57 |
20831 |
d_univProxy.clear(); |
58 |
20831 |
} |
59 |
52846 |
void CardinalityExtension::registerTerm(Node n) |
60 |
|
{ |
61 |
52846 |
Trace("sets-card-debug") << "Register term : " << n << std::endl; |
62 |
52846 |
Assert(n.getKind() == CARD); |
63 |
105692 |
TypeNode tnc = n[0].getType().getSetElementType(); |
64 |
52846 |
d_t_card_enabled[tnc] = true; |
65 |
105692 |
Node r = d_state.getRepresentative(n[0]); |
66 |
52846 |
if (d_eqc_to_card_term.find(r) == d_eqc_to_card_term.end()) |
67 |
|
{ |
68 |
32458 |
d_eqc_to_card_term[r] = n; |
69 |
32458 |
registerCardinalityTerm(n[0]); |
70 |
|
} |
71 |
52846 |
Trace("sets-card-debug") << "...finished register term" << std::endl; |
72 |
52846 |
} |
73 |
|
|
74 |
1799 |
void CardinalityExtension::checkCardinalityExtended() |
75 |
|
{ |
76 |
3597 |
for (std::pair<const TypeNode, bool>& pair : d_t_card_enabled) |
77 |
|
{ |
78 |
3598 |
TypeNode type = pair.first; |
79 |
1799 |
if (pair.second) |
80 |
|
{ |
81 |
1799 |
checkCardinalityExtended(type); |
82 |
|
} |
83 |
|
} |
84 |
1798 |
} |
85 |
|
|
86 |
1799 |
void CardinalityExtension::checkCardinalityExtended(TypeNode& t) |
87 |
|
{ |
88 |
1799 |
NodeManager* nm = NodeManager::currentNM(); |
89 |
2786 |
TypeNode setType = nm->mkSetType(t); |
90 |
1799 |
bool finiteType = d_state.isFiniteType(t); |
91 |
|
// skip infinite types that do not have univset terms |
92 |
1799 |
if (!finiteType && d_state.getUnivSetEqClass(setType).isNull()) |
93 |
|
{ |
94 |
812 |
return; |
95 |
|
} |
96 |
|
|
97 |
|
// get the cardinality of the finite type t |
98 |
1974 |
Cardinality card = t.getCardinality(); |
99 |
|
|
100 |
|
// cardinality of an interpreted finite type t is infinite when t |
101 |
|
// is infinite without --fmf |
102 |
987 |
if (finiteType && card.isInfinite()) |
103 |
|
{ |
104 |
|
// TODO (#1123): support uninterpreted sorts with --finite-model-find |
105 |
2 |
std::stringstream message; |
106 |
1 |
message << "The cardinality " << card << " of the finite type " << t |
107 |
1 |
<< " is not supported yet."; |
108 |
1 |
throw LogicException(message.str()); |
109 |
|
} |
110 |
|
|
111 |
|
// here we call getUnivSet instead of getUnivSetEqClass to generate |
112 |
|
// a univset term for finite types even if they are not used in the input |
113 |
1972 |
Node univ = d_treg.getUnivSet(setType); |
114 |
986 |
std::map<Node, Node>::iterator it = d_univProxy.find(univ); |
115 |
|
|
116 |
1972 |
Node proxy; |
117 |
|
|
118 |
986 |
if (it == d_univProxy.end()) |
119 |
|
{ |
120 |
|
// Force cvc5 to build the cardinality graph for the universe set |
121 |
986 |
proxy = d_treg.getProxy(univ); |
122 |
986 |
d_univProxy[univ] = proxy; |
123 |
|
} |
124 |
|
else |
125 |
|
{ |
126 |
|
proxy = it->second; |
127 |
|
} |
128 |
|
|
129 |
|
// get all equivalent classes of type t |
130 |
1972 |
vector<Node> representatives = d_state.getSetsEqClasses(t); |
131 |
|
|
132 |
986 |
if (finiteType) |
133 |
|
{ |
134 |
1508 |
Node typeCardinality = nm->mkConst(Rational(card.getFiniteCardinality())); |
135 |
1508 |
Node cardUniv = nm->mkNode(kind::CARD, proxy); |
136 |
1508 |
Node leq = nm->mkNode(kind::LEQ, cardUniv, typeCardinality); |
137 |
|
|
138 |
|
// (=> true (<= (card (as univset t)) cardUniv) |
139 |
754 |
if (!d_state.isEntailed(leq, true)) |
140 |
|
{ |
141 |
754 |
d_im.assertInference(leq, InferenceId::SETS_CARD_UNIV_TYPE, d_true, 1); |
142 |
|
} |
143 |
|
} |
144 |
|
|
145 |
|
// add subset lemmas for sets and membership lemmas for negative members |
146 |
9954 |
for (Node& representative : representatives) |
147 |
|
{ |
148 |
|
// the universe set is a subset of itself |
149 |
8968 |
if (representative != d_state.getRepresentative(univ)) |
150 |
|
{ |
151 |
|
// here we only add representatives with variables to avoid adding |
152 |
|
// infinite equivalent generated terms to the cardinality graph |
153 |
9992 |
Node variable = d_state.getVariableSet(representative); |
154 |
7993 |
if (variable.isNull()) |
155 |
|
{ |
156 |
5994 |
continue; |
157 |
|
} |
158 |
|
|
159 |
|
// (=> true (subset representative (as univset t)) |
160 |
3998 |
Node subset = nm->mkNode(kind::SUBSET, variable, proxy); |
161 |
|
// subset terms are rewritten as union terms: (subset A B) implies (= |
162 |
|
// (union A B) B) |
163 |
1999 |
subset = Rewriter::rewrite(subset); |
164 |
1999 |
if (!d_state.isEntailed(subset, true)) |
165 |
|
{ |
166 |
124 |
d_im.assertInference( |
167 |
|
subset, InferenceId::SETS_CARD_UNIV_SUPERSET, d_true, 1); |
168 |
|
} |
169 |
|
|
170 |
|
// negative members are members in the universe set |
171 |
|
const std::map<Node, Node>& negativeMembers = |
172 |
1999 |
d_state.getNegativeMembers(representative); |
173 |
|
|
174 |
4409 |
for (const auto& negativeMember : negativeMembers) |
175 |
|
{ |
176 |
4820 |
Node member = nm->mkNode(MEMBER, negativeMember.first, univ); |
177 |
|
// negativeMember.second is the reason for the negative membership and |
178 |
|
// has kind MEMBER. So we specify the negation as the reason for the |
179 |
|
// negative membership lemma |
180 |
4820 |
Node notMember = nm->mkNode(NOT, negativeMember.second); |
181 |
|
// (=> |
182 |
|
// (not (member negativeMember representative))) |
183 |
|
// (member negativeMember (as univset t))) |
184 |
2410 |
d_im.assertInference( |
185 |
|
member, InferenceId::SETS_CARD_NEGATIVE_MEMBER, notMember, 1); |
186 |
|
} |
187 |
|
} |
188 |
|
} |
189 |
|
} |
190 |
|
|
191 |
1799 |
void CardinalityExtension::check() |
192 |
|
{ |
193 |
1799 |
checkCardinalityExtended(); |
194 |
1798 |
checkRegister(); |
195 |
1798 |
if (d_im.hasSent()) |
196 |
|
{ |
197 |
2022 |
return; |
198 |
|
} |
199 |
1486 |
checkMinCard(); |
200 |
1486 |
if (d_im.hasSent()) |
201 |
|
{ |
202 |
432 |
return; |
203 |
|
} |
204 |
1054 |
checkCardCycles(); |
205 |
1054 |
if (d_im.hasSent()) |
206 |
|
{ |
207 |
445 |
return; |
208 |
|
} |
209 |
|
// The last step will either do nothing (in which case we are SAT), or request |
210 |
|
// that a new set term is introduced. |
211 |
697 |
std::vector<Node> intro_sets; |
212 |
609 |
checkNormalForms(intro_sets); |
213 |
609 |
if (intro_sets.empty()) |
214 |
|
{ |
215 |
521 |
return; |
216 |
|
} |
217 |
88 |
Assert(intro_sets.size() == 1); |
218 |
88 |
Trace("sets-intro") << "Introduce term : " << intro_sets[0] << std::endl; |
219 |
88 |
Trace("sets-intro") << " Actual Intro : "; |
220 |
88 |
d_treg.debugPrintSet(intro_sets[0], "sets-nf"); |
221 |
88 |
Trace("sets-nf") << std::endl; |
222 |
176 |
Node k = d_treg.getProxy(intro_sets[0]); |
223 |
88 |
AlwaysAssert(!k.isNull()); |
224 |
|
} |
225 |
|
|
226 |
1798 |
void CardinalityExtension::checkRegister() |
227 |
|
{ |
228 |
1798 |
Trace("sets") << "Cardinality graph..." << std::endl; |
229 |
1798 |
NodeManager* nm = NodeManager::currentNM(); |
230 |
|
// first, ensure cardinality relationships are added as lemmas for all |
231 |
|
// non-basic set terms |
232 |
1798 |
const std::vector<Node>& setEqc = d_state.getSetsEqClasses(); |
233 |
19375 |
for (const Node& eqc : setEqc) |
234 |
|
{ |
235 |
17577 |
const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc); |
236 |
39605 |
for (Node n : nvsets) |
237 |
|
{ |
238 |
22028 |
if (!d_state.isCongruent(n)) |
239 |
|
{ |
240 |
|
// if setminus, do for intersection instead |
241 |
21555 |
if (n.getKind() == SETMINUS) |
242 |
|
{ |
243 |
10694 |
n = Rewriter::rewrite(nm->mkNode(INTERSECTION, n[0], n[1])); |
244 |
|
} |
245 |
21555 |
registerCardinalityTerm(n); |
246 |
|
} |
247 |
|
} |
248 |
|
} |
249 |
1798 |
Trace("sets") << "Done cardinality graph" << std::endl; |
250 |
1798 |
} |
251 |
|
|
252 |
54013 |
void CardinalityExtension::registerCardinalityTerm(Node n) |
253 |
|
{ |
254 |
55774 |
TypeNode tnc = n.getType().getSetElementType(); |
255 |
54013 |
if (d_t_card_enabled.find(tnc) == d_t_card_enabled.end()) |
256 |
|
{ |
257 |
|
// if no cardinality constraints for sets of this type, we can ignore |
258 |
150 |
return; |
259 |
|
} |
260 |
53863 |
if (d_card_processed.find(n) != d_card_processed.end()) |
261 |
|
{ |
262 |
|
// already processed |
263 |
52102 |
return; |
264 |
|
} |
265 |
1761 |
d_card_processed.insert(n); |
266 |
1761 |
NodeManager* nm = NodeManager::currentNM(); |
267 |
1761 |
Trace("sets-card") << "Cardinality lemmas for " << n << " : " << std::endl; |
268 |
3522 |
std::vector<Node> cterms; |
269 |
1761 |
if (n.getKind() == INTERSECTION) |
270 |
|
{ |
271 |
1008 |
for (unsigned e = 0; e < 2; e++) |
272 |
|
{ |
273 |
1344 |
Node s = nm->mkNode(SETMINUS, n[e], n[1 - e]); |
274 |
672 |
cterms.push_back(s); |
275 |
|
} |
276 |
672 |
Node pos_lem = nm->mkNode(GEQ, nm->mkNode(CARD, n), d_zero); |
277 |
336 |
d_im.assertInference( |
278 |
|
pos_lem, InferenceId::SETS_CARD_POSITIVE, d_emp_exp, 1); |
279 |
|
} |
280 |
|
else |
281 |
|
{ |
282 |
1425 |
cterms.push_back(n); |
283 |
|
} |
284 |
3858 |
for (unsigned k = 0, csize = cterms.size(); k < csize; k++) |
285 |
|
{ |
286 |
4194 |
Node nn = cterms[k]; |
287 |
4194 |
Node nk = d_treg.getProxy(nn); |
288 |
4194 |
Node pos_lem = nm->mkNode(GEQ, nm->mkNode(CARD, nk), d_zero); |
289 |
2097 |
d_im.assertInference( |
290 |
|
pos_lem, InferenceId::SETS_CARD_POSITIVE, d_emp_exp, 1); |
291 |
2097 |
if (nn != nk) |
292 |
|
{ |
293 |
1972 |
Node lem = nm->mkNode(EQUAL, nm->mkNode(CARD, nk), nm->mkNode(CARD, nn)); |
294 |
986 |
lem = Rewriter::rewrite(lem); |
295 |
986 |
Trace("sets-card") << " " << k << " : " << lem << std::endl; |
296 |
986 |
d_im.assertInference(lem, InferenceId::SETS_CARD_EQUAL, d_emp_exp, 1); |
297 |
|
} |
298 |
|
} |
299 |
1761 |
d_im.doPendingLemmas(); |
300 |
|
} |
301 |
|
|
302 |
1054 |
void CardinalityExtension::checkCardCycles() |
303 |
|
{ |
304 |
1054 |
Trace("sets") << "Check cardinality cycles..." << std::endl; |
305 |
|
// build order of equivalence classes, also build cardinality graph |
306 |
1054 |
const std::vector<Node>& setEqc = d_state.getSetsEqClasses(); |
307 |
1054 |
d_oSetEqc.clear(); |
308 |
1054 |
d_cardParent.clear(); |
309 |
8724 |
for (const Node& s : setEqc) |
310 |
|
{ |
311 |
15785 |
std::vector<Node> curr; |
312 |
15785 |
std::vector<Node> exp; |
313 |
8115 |
checkCardCyclesRec(s, curr, exp); |
314 |
8115 |
if (d_im.hasSent()) |
315 |
|
{ |
316 |
445 |
return; |
317 |
|
} |
318 |
|
} |
319 |
|
|
320 |
609 |
Trace("sets") << "d_oSetEqc: " << d_oSetEqc << std::endl; |
321 |
609 |
Trace("sets") << "Done check cardinality cycles" << std::endl; |
322 |
|
} |
323 |
|
|
324 |
13961 |
void CardinalityExtension::checkCardCyclesRec(Node eqc, |
325 |
|
std::vector<Node>& curr, |
326 |
|
std::vector<Node>& exp) |
327 |
|
{ |
328 |
13961 |
Trace("sets-cycle-debug") << "Traverse eqc " << eqc << std::endl; |
329 |
13961 |
NodeManager* nm = NodeManager::currentNM(); |
330 |
13961 |
if (std::find(curr.begin(), curr.end(), eqc) != curr.end()) |
331 |
|
{ |
332 |
|
Trace("sets-debug") << "Found venn region loop..." << std::endl; |
333 |
|
if (curr.size() > 1) |
334 |
|
{ |
335 |
|
// all regions must be equal |
336 |
|
std::vector<Node> conc; |
337 |
|
bool foundLoopStart = false; |
338 |
|
for (const Node& cc : curr) |
339 |
|
{ |
340 |
|
if (cc == eqc) |
341 |
|
{ |
342 |
|
foundLoopStart = true; |
343 |
|
} |
344 |
|
else if (foundLoopStart && eqc != cc) |
345 |
|
{ |
346 |
|
conc.push_back(eqc.eqNode(cc)); |
347 |
|
} |
348 |
|
} |
349 |
|
Node fact = conc.size() == 1 ? conc[0] : nm->mkNode(AND, conc); |
350 |
|
Trace("sets-cycle-debug") |
351 |
|
<< "CYCLE: " << fact << " from " << exp << std::endl; |
352 |
|
d_im.assertInference(fact, InferenceId::SETS_CARD_CYCLE, exp); |
353 |
|
d_im.doPendingLemmas(); |
354 |
|
} |
355 |
|
else |
356 |
|
{ |
357 |
|
// should be guaranteed based on not exploring equal parents |
358 |
|
Assert(false); |
359 |
|
} |
360 |
7867 |
return; |
361 |
|
} |
362 |
13961 |
if (std::find(d_oSetEqc.begin(), d_oSetEqc.end(), eqc) != d_oSetEqc.end()) |
363 |
|
{ |
364 |
|
// already processed |
365 |
5809 |
return; |
366 |
|
} |
367 |
8152 |
const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc); |
368 |
8152 |
if (nvsets.empty()) |
369 |
|
{ |
370 |
|
// no non-variable sets, trivial |
371 |
1606 |
d_oSetEqc.push_back(eqc); |
372 |
1606 |
return; |
373 |
|
} |
374 |
6546 |
curr.push_back(eqc); |
375 |
12640 |
TypeNode tn = eqc.getType(); |
376 |
6546 |
bool is_empty = eqc == d_state.getEmptySetEqClass(tn); |
377 |
12640 |
Node emp_set = d_treg.getEmptySet(tn); |
378 |
16914 |
for (const Node& n : nvsets) |
379 |
|
{ |
380 |
10820 |
Kind nk = n.getKind(); |
381 |
10820 |
if (nk != INTERSECTION && nk != SETMINUS) |
382 |
|
{ |
383 |
7758 |
continue; |
384 |
|
} |
385 |
15472 |
Trace("sets-debug") << "Build cardinality parents for " << n << "..." |
386 |
7736 |
<< std::endl; |
387 |
13430 |
std::vector<Node> sib; |
388 |
7736 |
unsigned true_sib = 0; |
389 |
7736 |
if (n.getKind() == INTERSECTION) |
390 |
|
{ |
391 |
2938 |
d_localBase[n] = n; |
392 |
8814 |
for (unsigned e = 0; e < 2; e++) |
393 |
|
{ |
394 |
11752 |
Node sm = Rewriter::rewrite(nm->mkNode(SETMINUS, n[e], n[1 - e])); |
395 |
5876 |
sib.push_back(sm); |
396 |
|
} |
397 |
2938 |
true_sib = 2; |
398 |
|
} |
399 |
|
else |
400 |
|
{ |
401 |
9596 |
Node si = Rewriter::rewrite(nm->mkNode(INTERSECTION, n[0], n[1])); |
402 |
4798 |
sib.push_back(si); |
403 |
4798 |
d_localBase[n] = si; |
404 |
9596 |
Node osm = Rewriter::rewrite(nm->mkNode(SETMINUS, n[1], n[0])); |
405 |
4798 |
sib.push_back(osm); |
406 |
4798 |
true_sib = 1; |
407 |
|
} |
408 |
13430 |
Node u = Rewriter::rewrite(nm->mkNode(UNION, n[0], n[1])); |
409 |
7736 |
if (!d_state.hasTerm(u)) |
410 |
|
{ |
411 |
4606 |
u = Node::null(); |
412 |
|
} |
413 |
7736 |
unsigned n_parents = true_sib + (u.isNull() ? 0 : 1); |
414 |
|
// if this set is empty |
415 |
7736 |
if (is_empty) |
416 |
|
{ |
417 |
1789 |
Assert(d_state.areEqual(n, emp_set)); |
418 |
1789 |
Trace("sets-debug") << " empty, parents equal siblings" << std::endl; |
419 |
1789 |
std::vector<Node> conc; |
420 |
|
// parent equal siblings |
421 |
3937 |
for (unsigned e = 0; e < true_sib; e++) |
422 |
|
{ |
423 |
2148 |
if (d_state.hasTerm(sib[e]) && !d_state.areEqual(n[e], sib[e])) |
424 |
|
{ |
425 |
248 |
conc.push_back(n[e].eqNode(sib[e])); |
426 |
|
} |
427 |
|
} |
428 |
1789 |
d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_EMP, n.eqNode(emp_set)); |
429 |
1789 |
d_im.doPendingLemmas(); |
430 |
1789 |
if (d_im.hasSent()) |
431 |
|
{ |
432 |
199 |
return; |
433 |
|
} |
434 |
1590 |
continue; |
435 |
|
} |
436 |
11641 |
std::vector<Node> card_parents; |
437 |
11641 |
std::vector<int> card_parent_ids; |
438 |
|
// check if equal to a parent |
439 |
16401 |
for (unsigned e = 0; e < n_parents; e++) |
440 |
|
{ |
441 |
21168 |
Trace("sets-debug") << " check parent " << e << "/" << n_parents |
442 |
10584 |
<< std::endl; |
443 |
10584 |
bool is_union = e == true_sib; |
444 |
21038 |
Node p = (e == true_sib) ? u : n[e]; |
445 |
21168 |
Trace("sets-debug") << " check relation to parent " << p |
446 |
10584 |
<< ", isu=" << is_union << "..." << std::endl; |
447 |
|
// if parent is empty |
448 |
10584 |
if (d_state.areEqual(p, emp_set)) |
449 |
|
{ |
450 |
2 |
Trace("sets-debug") << " it is empty..." << std::endl; |
451 |
2 |
Assert(!d_state.areEqual(n, emp_set)); |
452 |
4 |
d_im.assertInference( |
453 |
4 |
n.eqNode(emp_set), InferenceId::SETS_CARD_GRAPH_EMP_PARENT, p.eqNode(emp_set)); |
454 |
2 |
d_im.doPendingLemmas(); |
455 |
2 |
if (d_im.hasSent()) |
456 |
|
{ |
457 |
2 |
return; |
458 |
|
} |
459 |
|
// if we are equal to a parent |
460 |
|
} |
461 |
10582 |
else if (d_state.areEqual(p, n)) |
462 |
|
{ |
463 |
2543 |
Trace("sets-debug") << " it is equal to this..." << std::endl; |
464 |
4958 |
std::vector<Node> conc; |
465 |
4958 |
std::vector<int> sib_emp_indices; |
466 |
2543 |
if (is_union) |
467 |
|
{ |
468 |
198 |
for (unsigned s = 0; s < sib.size(); s++) |
469 |
|
{ |
470 |
132 |
sib_emp_indices.push_back(s); |
471 |
|
} |
472 |
|
} |
473 |
|
else |
474 |
|
{ |
475 |
2477 |
sib_emp_indices.push_back(e); |
476 |
|
} |
477 |
|
// sibling(s) are empty |
478 |
5152 |
for (unsigned si : sib_emp_indices) |
479 |
|
{ |
480 |
2609 |
if (!d_state.areEqual(sib[si], emp_set)) |
481 |
|
{ |
482 |
116 |
conc.push_back(sib[si].eqNode(emp_set)); |
483 |
|
} |
484 |
|
else |
485 |
|
{ |
486 |
4986 |
Trace("sets-debug") |
487 |
2493 |
<< "Sibling " << sib[si] << " is already empty." << std::endl; |
488 |
|
} |
489 |
|
} |
490 |
2543 |
if (!is_union && nk == INTERSECTION && !u.isNull()) |
491 |
|
{ |
492 |
|
// union is equal to other parent |
493 |
1222 |
if (!d_state.areEqual(u, n[1 - e])) |
494 |
|
{ |
495 |
12 |
conc.push_back(u.eqNode(n[1 - e])); |
496 |
|
} |
497 |
|
} |
498 |
5086 |
Trace("sets-debug") |
499 |
2543 |
<< "...derived " << conc.size() << " conclusions" << std::endl; |
500 |
2543 |
d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_EQ_PARENT, n.eqNode(p)); |
501 |
2543 |
d_im.doPendingLemmas(); |
502 |
2543 |
if (d_im.hasSent()) |
503 |
|
{ |
504 |
128 |
return; |
505 |
|
} |
506 |
|
} |
507 |
|
else |
508 |
|
{ |
509 |
8039 |
Trace("sets-cdg") << "Card graph : " << n << " -> " << p << std::endl; |
510 |
|
// otherwise, we a syntactic subset of p |
511 |
8039 |
card_parents.push_back(p); |
512 |
8039 |
card_parent_ids.push_back(is_union ? 2 : e); |
513 |
|
} |
514 |
|
} |
515 |
5817 |
Assert(d_cardParent[n].empty()); |
516 |
5817 |
Trace("sets-debug") << "get parent representatives..." << std::endl; |
517 |
|
// for each parent, take their representatives |
518 |
13728 |
for (unsigned k = 0, numcp = card_parents.size(); k < numcp; k++) |
519 |
|
{ |
520 |
15938 |
Node cpk = card_parents[k]; |
521 |
15938 |
Node eqcc = d_state.getRepresentative(cpk); |
522 |
16054 |
Trace("sets-debug") << "Check card parent " << k << "/" |
523 |
8027 |
<< card_parents.size() << std::endl; |
524 |
|
|
525 |
|
// if parent is singleton, then we should either be empty to equal to it |
526 |
15938 |
Node eqccSingleton = d_state.getSingletonEqClass(eqcc); |
527 |
8027 |
if (!eqccSingleton.isNull()) |
528 |
|
{ |
529 |
4 |
bool eq_parent = false; |
530 |
8 |
std::vector<Node> exps; |
531 |
4 |
d_state.addEqualityToExp(cpk, eqccSingleton, exps); |
532 |
4 |
if (d_state.areDisequal(n, emp_set)) |
533 |
|
{ |
534 |
|
exps.push_back(n.eqNode(emp_set).negate()); |
535 |
|
eq_parent = true; |
536 |
|
} |
537 |
|
else |
538 |
|
{ |
539 |
4 |
const std::map<Node, Node>& pmemsE = d_state.getMembers(eqc); |
540 |
4 |
if (!pmemsE.empty()) |
541 |
|
{ |
542 |
8 |
Node pmem = pmemsE.begin()->second; |
543 |
4 |
exps.push_back(pmem); |
544 |
4 |
d_state.addEqualityToExp(n, pmem[1], exps); |
545 |
4 |
eq_parent = true; |
546 |
|
} |
547 |
|
} |
548 |
|
// must be equal to parent |
549 |
4 |
if (eq_parent) |
550 |
|
{ |
551 |
8 |
Node conc = n.eqNode(cpk); |
552 |
4 |
d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_PARENT_SINGLETON, exps); |
553 |
4 |
d_im.doPendingLemmas(); |
554 |
|
} |
555 |
|
else |
556 |
|
{ |
557 |
|
// split on empty |
558 |
|
Trace("sets-nf") << "Split empty : " << n << std::endl; |
559 |
|
d_im.split(n.eqNode(emp_set), InferenceId::SETS_CARD_SPLIT_EMPTY, 1); |
560 |
|
} |
561 |
4 |
Assert(d_im.hasSent()); |
562 |
4 |
return; |
563 |
|
} |
564 |
|
else |
565 |
|
{ |
566 |
8023 |
bool dup = false; |
567 |
11091 |
for (unsigned l = 0, numcpn = d_cardParent[n].size(); l < numcpn; l++) |
568 |
|
{ |
569 |
4158 |
Node cpnl = d_cardParent[n][l].first; |
570 |
3180 |
if (eqcc != cpnl) |
571 |
|
{ |
572 |
1238 |
continue; |
573 |
|
} |
574 |
3884 |
Trace("sets-debug") << " parents " << l << " and " << k |
575 |
1942 |
<< " are equal, ids = " << card_parent_ids[l] |
576 |
1942 |
<< " " << card_parent_ids[k] << std::endl; |
577 |
1942 |
dup = true; |
578 |
1942 |
if (n.getKind() != INTERSECTION) |
579 |
|
{ |
580 |
852 |
continue; |
581 |
|
} |
582 |
1090 |
Assert(card_parent_ids[l] != 2); |
583 |
2068 |
std::vector<Node> conc; |
584 |
1090 |
if (card_parent_ids[k] == 2) |
585 |
|
{ |
586 |
|
// intersection is equal to other parent |
587 |
1090 |
unsigned pid = 1 - card_parent_ids[l]; |
588 |
1090 |
if (!d_state.areEqual(n[pid], n)) |
589 |
|
{ |
590 |
224 |
Trace("sets-debug") |
591 |
112 |
<< " one of them is union, make equal to other..." |
592 |
112 |
<< std::endl; |
593 |
112 |
conc.push_back(n[pid].eqNode(n)); |
594 |
|
} |
595 |
|
} |
596 |
|
else |
597 |
|
{ |
598 |
|
if (!d_state.areEqual(cpk, n)) |
599 |
|
{ |
600 |
|
Trace("sets-debug") |
601 |
|
<< " neither is union, make equal to one parent..." |
602 |
|
<< std::endl; |
603 |
|
// intersection is equal to one of the parents |
604 |
|
conc.push_back(cpk.eqNode(n)); |
605 |
|
} |
606 |
|
} |
607 |
|
// use the original term, not the representative. |
608 |
|
// for example, we conclude T = (union T S) => (intersect T S) = S |
609 |
|
// here where we do not use the representative of T or (union T S). |
610 |
2068 |
Node cpnlb = d_cardParent[n][l].second; |
611 |
2180 |
d_im.assertInference(conc, |
612 |
|
InferenceId::SETS_CARD_GRAPH_EQ_PARENT_2, |
613 |
2180 |
cpk.eqNode(cpnlb)); |
614 |
1090 |
d_im.doPendingLemmas(); |
615 |
1090 |
if (d_im.hasSent()) |
616 |
|
{ |
617 |
112 |
return; |
618 |
|
} |
619 |
|
} |
620 |
7911 |
if (!dup) |
621 |
|
{ |
622 |
6081 |
d_cardParent[n].emplace_back(eqcc, cpk); |
623 |
|
} |
624 |
|
} |
625 |
|
} |
626 |
|
// now recurse on parents (to ensure their normal will be computed after |
627 |
|
// this eqc) |
628 |
5701 |
exp.push_back(eqc.eqNode(n)); |
629 |
11540 |
for (const std::pair<Node, Node>& cpnc : d_cardParent[n]) |
630 |
|
{ |
631 |
11692 |
Trace("sets-cycle-debug") << "Traverse card parent " << eqc << " -> " |
632 |
5846 |
<< cpnc.first << std::endl; |
633 |
5846 |
checkCardCyclesRec(cpnc.first, curr, exp); |
634 |
5846 |
if (d_im.hasSent()) |
635 |
|
{ |
636 |
7 |
return; |
637 |
|
} |
638 |
|
} |
639 |
5694 |
exp.pop_back(); |
640 |
|
} |
641 |
6094 |
curr.pop_back(); |
642 |
|
// parents now processed, can add to ordered list |
643 |
6094 |
d_oSetEqc.push_back(eqc); |
644 |
|
} |
645 |
|
|
646 |
609 |
void CardinalityExtension::checkNormalForms(std::vector<Node>& intro_sets) |
647 |
|
{ |
648 |
609 |
Trace("sets") << "Check normal forms..." << std::endl; |
649 |
|
// now, build normal form for each equivalence class |
650 |
|
// d_oSetEqc is now sorted such that for each d_oSetEqc[i], d_oSetEqc[j], |
651 |
|
// if d_oSetEqc[i] is a strict syntactic subterm of d_oSetEqc[j], then i<j. |
652 |
609 |
d_ff.clear(); |
653 |
609 |
d_nf.clear(); |
654 |
2708 |
for (int i = (int)(d_oSetEqc.size() - 1); i >= 0; i--) |
655 |
|
{ |
656 |
2574 |
checkNormalForm(d_oSetEqc[i], intro_sets); |
657 |
2574 |
if (d_im.hasSent() || !intro_sets.empty()) |
658 |
|
{ |
659 |
475 |
return; |
660 |
|
} |
661 |
|
} |
662 |
134 |
Trace("sets") << "Done check normal forms" << std::endl; |
663 |
|
} |
664 |
|
|
665 |
2574 |
void CardinalityExtension::checkNormalForm(Node eqc, |
666 |
|
std::vector<Node>& intro_sets) |
667 |
|
{ |
668 |
3742 |
TypeNode tn = eqc.getType(); |
669 |
2574 |
Trace("sets") << "Compute normal form for " << eqc << std::endl; |
670 |
2574 |
Trace("sets-nf") << "Compute N " << eqc << "..." << std::endl; |
671 |
2574 |
if (eqc == d_state.getEmptySetEqClass(tn)) |
672 |
|
{ |
673 |
405 |
d_nf[eqc].clear(); |
674 |
405 |
Trace("sets-nf") << "----> N " << eqc << " => {}" << std::endl; |
675 |
405 |
return; |
676 |
|
} |
677 |
|
// flat/normal forms are sets of equivalence classes |
678 |
3337 |
Node base; |
679 |
3337 |
std::vector<Node> comps; |
680 |
|
std::map<Node, std::map<Node, std::vector<Node> > >::iterator it = |
681 |
2169 |
d_ff.find(eqc); |
682 |
2169 |
if (it != d_ff.end()) |
683 |
|
{ |
684 |
686 |
for (std::pair<const Node, std::vector<Node> >& itf : it->second) |
685 |
|
{ |
686 |
398 |
std::sort(itf.second.begin(), itf.second.end()); |
687 |
398 |
if (base.isNull()) |
688 |
|
{ |
689 |
288 |
base = itf.first; |
690 |
|
} |
691 |
|
else |
692 |
|
{ |
693 |
110 |
comps.push_back(itf.first); |
694 |
|
} |
695 |
796 |
Trace("sets-nf") << " F " << itf.first << " : " << itf.second |
696 |
398 |
<< std::endl; |
697 |
398 |
Trace("sets-nf-debug") << " ..."; |
698 |
398 |
d_treg.debugPrintSet(itf.first, "sets-nf-debug"); |
699 |
398 |
Trace("sets-nf-debug") << std::endl; |
700 |
|
} |
701 |
|
} |
702 |
|
else |
703 |
|
{ |
704 |
1881 |
Trace("sets-nf") << "(no flat forms)" << std::endl; |
705 |
|
} |
706 |
2169 |
std::map<Node, std::vector<Node> >& ffeqc = d_ff[eqc]; |
707 |
2169 |
Assert(d_nf.find(eqc) == d_nf.end()); |
708 |
2169 |
std::vector<Node>& nfeqc = d_nf[eqc]; |
709 |
2169 |
NodeManager* nm = NodeManager::currentNM(); |
710 |
2169 |
bool success = true; |
711 |
3337 |
Node emp_set = d_treg.getEmptySet(tn); |
712 |
2169 |
if (!base.isNull()) |
713 |
|
{ |
714 |
310 |
for (unsigned j = 0, csize = comps.size(); j < csize; j++) |
715 |
|
{ |
716 |
|
// compare if equal |
717 |
132 |
std::vector<Node> c; |
718 |
110 |
c.push_back(base); |
719 |
110 |
c.push_back(comps[j]); |
720 |
330 |
std::vector<Node> only[2]; |
721 |
132 |
std::vector<Node> common; |
722 |
220 |
Trace("sets-nf-debug") << "Compare venn regions of " << base << " vs " |
723 |
110 |
<< comps[j] << std::endl; |
724 |
110 |
unsigned k[2] = {0, 0}; |
725 |
1038 |
while (k[0] < ffeqc[c[0]].size() || k[1] < ffeqc[c[1]].size()) |
726 |
|
{ |
727 |
464 |
bool proc = true; |
728 |
1392 |
for (unsigned e = 0; e < 2; e++) |
729 |
|
{ |
730 |
928 |
if (k[e] == ffeqc[c[e]].size()) |
731 |
|
{ |
732 |
310 |
for (; k[1 - e] < ffeqc[c[1 - e]].size(); ++k[1 - e]) |
733 |
|
{ |
734 |
90 |
only[1 - e].push_back(ffeqc[c[1 - e]][k[1 - e]]); |
735 |
|
} |
736 |
130 |
proc = false; |
737 |
|
} |
738 |
|
} |
739 |
464 |
if (proc) |
740 |
|
{ |
741 |
376 |
if (ffeqc[c[0]][k[0]] == ffeqc[c[1]][k[1]]) |
742 |
|
{ |
743 |
146 |
common.push_back(ffeqc[c[0]][k[0]]); |
744 |
146 |
k[0]++; |
745 |
146 |
k[1]++; |
746 |
|
} |
747 |
230 |
else if (ffeqc[c[0]][k[0]] < ffeqc[c[1]][k[1]]) |
748 |
|
{ |
749 |
113 |
only[0].push_back(ffeqc[c[0]][k[0]]); |
750 |
113 |
k[0]++; |
751 |
|
} |
752 |
|
else |
753 |
|
{ |
754 |
117 |
only[1].push_back(ffeqc[c[1]][k[1]]); |
755 |
117 |
k[1]++; |
756 |
|
} |
757 |
|
} |
758 |
|
} |
759 |
110 |
if (!only[0].empty() || !only[1].empty()) |
760 |
|
{ |
761 |
88 |
if (Trace.isOn("sets-nf-debug")) |
762 |
|
{ |
763 |
|
Trace("sets-nf-debug") << "Unique venn regions : " << std::endl; |
764 |
|
for (unsigned e = 0; e < 2; e++) |
765 |
|
{ |
766 |
|
Trace("sets-nf-debug") << " " << c[e] << " : { "; |
767 |
|
for (unsigned l = 0; l < only[e].size(); l++) |
768 |
|
{ |
769 |
|
if (l > 0) |
770 |
|
{ |
771 |
|
Trace("sets-nf-debug") << ", "; |
772 |
|
} |
773 |
|
Trace("sets-nf-debug") << "[" << only[e][l] << "]"; |
774 |
|
} |
775 |
|
Trace("sets-nf-debug") << " }" << std::endl; |
776 |
|
} |
777 |
|
} |
778 |
|
// try to make one empty, prefer the unique ones first |
779 |
352 |
for (unsigned e = 0; e < 3; e++) |
780 |
|
{ |
781 |
264 |
unsigned sz = e == 2 ? common.size() : only[e].size(); |
782 |
664 |
for (unsigned l = 0; l < sz; l++) |
783 |
|
{ |
784 |
800 |
Node r = e == 2 ? common[l] : only[e][l]; |
785 |
400 |
Trace("sets-nf-debug") << "Try split empty : " << r << std::endl; |
786 |
400 |
Trace("sets-nf-debug") << " actual : "; |
787 |
400 |
d_treg.debugPrintSet(r, "sets-nf-debug"); |
788 |
400 |
Trace("sets-nf-debug") << std::endl; |
789 |
400 |
Assert(!d_state.areEqual(r, emp_set)); |
790 |
400 |
if (!d_state.areDisequal(r, emp_set) && !d_state.hasMembers(r)) |
791 |
|
{ |
792 |
|
// guess that its equal empty if it has no explicit members |
793 |
|
Trace("sets-nf") << " Split empty : " << r << std::endl; |
794 |
|
Trace("sets-nf") << "Actual Split : "; |
795 |
|
d_treg.debugPrintSet(r, "sets-nf"); |
796 |
|
Trace("sets-nf") << std::endl; |
797 |
|
d_im.split( |
798 |
|
r.eqNode(emp_set), InferenceId::SETS_CARD_SPLIT_EMPTY, 1); |
799 |
|
Assert(d_im.hasSent()); |
800 |
|
return; |
801 |
|
} |
802 |
|
} |
803 |
|
} |
804 |
88 |
for (const Node& o0 : only[0]) |
805 |
|
{ |
806 |
124 |
for (const Node& o1 : only[1]) |
807 |
|
{ |
808 |
124 |
bool disjoint = false; |
809 |
248 |
Trace("sets-nf-debug") |
810 |
124 |
<< "Try split " << o0 << " against " << o1 << std::endl; |
811 |
|
// split them |
812 |
322 |
for (unsigned e = 0; e < 2; e++) |
813 |
|
{ |
814 |
432 |
Node r1 = e == 0 ? o0 : o1; |
815 |
432 |
Node r2 = e == 0 ? o1 : o0; |
816 |
|
// check if their intersection exists modulo equality |
817 |
432 |
Node r1r2i = d_state.getBinaryOpTerm(INTERSECTION, r1, r2); |
818 |
234 |
if (!r1r2i.isNull()) |
819 |
|
{ |
820 |
72 |
Trace("sets-nf-debug") |
821 |
|
<< "Split term already exists, but not in cardinality " |
822 |
36 |
"graph : " |
823 |
36 |
<< r1r2i << ", should be empty." << std::endl; |
824 |
|
// their intersection is empty (probably?) |
825 |
|
// e.g. these are two disjoint venn regions, proceed to next |
826 |
|
// pair |
827 |
36 |
Assert(d_state.areEqual(emp_set, r1r2i)); |
828 |
36 |
disjoint = true; |
829 |
36 |
break; |
830 |
|
} |
831 |
|
} |
832 |
124 |
if (!disjoint) |
833 |
|
{ |
834 |
|
// simply introduce their intersection |
835 |
88 |
Assert(o0 != o1); |
836 |
176 |
Node kca = d_treg.getProxy(o0); |
837 |
176 |
Node kcb = d_treg.getProxy(o1); |
838 |
|
Node intro = |
839 |
176 |
Rewriter::rewrite(nm->mkNode(INTERSECTION, kca, kcb)); |
840 |
176 |
Trace("sets-nf") << " Intro split : " << o0 << " against " << o1 |
841 |
88 |
<< ", term is " << intro << std::endl; |
842 |
88 |
intro_sets.push_back(intro); |
843 |
88 |
Assert(!d_state.hasTerm(intro)); |
844 |
88 |
return; |
845 |
|
} |
846 |
|
} |
847 |
|
} |
848 |
|
// should never get here |
849 |
|
success = false; |
850 |
|
} |
851 |
|
} |
852 |
200 |
if (success) |
853 |
|
{ |
854 |
|
// normal form is flat form of base |
855 |
200 |
nfeqc.insert(nfeqc.end(), ffeqc[base].begin(), ffeqc[base].end()); |
856 |
200 |
Trace("sets-nf") << "----> N " << eqc << " => F " << base << std::endl; |
857 |
|
} |
858 |
|
else |
859 |
|
{ |
860 |
|
Trace("sets-nf") << "failed to build N " << eqc << std::endl; |
861 |
|
} |
862 |
|
} |
863 |
|
else |
864 |
|
{ |
865 |
|
// must ensure disequal from empty |
866 |
5603 |
if (!eqc.isConst() && !d_state.areDisequal(eqc, emp_set) |
867 |
4688 |
&& !d_state.hasMembers(eqc)) |
868 |
|
{ |
869 |
387 |
Trace("sets-nf-debug") << "Split on leaf " << eqc << std::endl; |
870 |
387 |
d_im.split(eqc.eqNode(emp_set), InferenceId::SETS_CARD_SPLIT_EMPTY); |
871 |
387 |
success = false; |
872 |
|
} |
873 |
|
else |
874 |
|
{ |
875 |
|
// normal form is this equivalence class |
876 |
1494 |
nfeqc.push_back(eqc); |
877 |
2988 |
Trace("sets-nf") << "----> N " << eqc << " => { " << eqc << " }" |
878 |
1494 |
<< std::endl; |
879 |
|
} |
880 |
|
} |
881 |
2081 |
if (!success) |
882 |
|
{ |
883 |
387 |
Assert(d_im.hasSent()); |
884 |
387 |
return; |
885 |
|
} |
886 |
|
// Send to parents (a parent is a set that contains a term in this equivalence |
887 |
|
// class as a direct child). |
888 |
1694 |
const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc); |
889 |
1694 |
if (nvsets.empty()) |
890 |
|
{ |
891 |
|
// no non-variable sets |
892 |
526 |
return; |
893 |
|
} |
894 |
2336 |
std::map<Node, std::map<Node, bool> > parents_proc; |
895 |
2739 |
for (const Node& n : nvsets) |
896 |
|
{ |
897 |
1571 |
Trace("sets-nf-debug") << "Carry nf for term " << n << std::endl; |
898 |
1571 |
if (d_cardParent[n].empty()) |
899 |
|
{ |
900 |
|
// nothing to do |
901 |
409 |
continue; |
902 |
|
} |
903 |
1162 |
Assert(d_localBase.find(n) != d_localBase.end()); |
904 |
2324 |
Node cbase = d_localBase[n]; |
905 |
1162 |
Trace("sets-nf-debug") << "Card base is " << cbase << std::endl; |
906 |
2426 |
for (const std::pair<Node, Node>& cp : d_cardParent[n]) |
907 |
|
{ |
908 |
2528 |
Node p = cp.first; |
909 |
1264 |
Trace("sets-nf-debug") << "Check parent " << p << std::endl; |
910 |
1264 |
if (parents_proc[cbase].find(p) != parents_proc[cbase].end()) |
911 |
|
{ |
912 |
|
Trace("sets-nf-debug") << "..already processed parent " << p << " for " |
913 |
|
<< cbase << std::endl; |
914 |
|
continue; |
915 |
|
} |
916 |
1264 |
parents_proc[cbase][p] = true; |
917 |
2528 |
Trace("sets-nf-debug") << "Carry nf to parent ( " << cbase << ", [" << p |
918 |
1264 |
<< "] ), from " << n << "..." << std::endl; |
919 |
|
|
920 |
1264 |
std::vector<Node>& ffpc = d_ff[p][cbase]; |
921 |
2709 |
for (const Node& nfeqci : nfeqc) |
922 |
|
{ |
923 |
1445 |
if (std::find(ffpc.begin(), ffpc.end(), nfeqci) == ffpc.end()) |
924 |
|
{ |
925 |
1264 |
ffpc.insert(ffpc.end(), nfeqc.begin(), nfeqc.end()); |
926 |
|
} |
927 |
|
else |
928 |
|
{ |
929 |
|
// if it is a duplicate venn region, it must be empty since it is |
930 |
|
// coming from syntactically disjoint siblings |
931 |
|
} |
932 |
|
} |
933 |
|
} |
934 |
|
} |
935 |
|
} |
936 |
|
|
937 |
1486 |
void CardinalityExtension::checkMinCard() |
938 |
|
{ |
939 |
1486 |
NodeManager* nm = NodeManager::currentNM(); |
940 |
1486 |
const std::vector<Node>& setEqc = d_state.getSetsEqClasses(); |
941 |
16607 |
for (int i = (int)(setEqc.size() - 1); i >= 0; i--) |
942 |
|
{ |
943 |
23400 |
Node eqc = setEqc[i]; |
944 |
23400 |
TypeNode tn = eqc.getType().getSetElementType(); |
945 |
15121 |
if (d_t_card_enabled.find(tn) == d_t_card_enabled.end()) |
946 |
|
{ |
947 |
|
// cardinality is not enabled for this type, skip |
948 |
126 |
continue; |
949 |
|
} |
950 |
|
// get members in class |
951 |
14995 |
const std::map<Node, Node>& pmemsE = d_state.getMembers(eqc); |
952 |
14995 |
if (pmemsE.empty()) |
953 |
|
{ |
954 |
|
// no members, trivial |
955 |
6716 |
continue; |
956 |
|
} |
957 |
16558 |
std::vector<Node> exp; |
958 |
16558 |
std::vector<Node> members; |
959 |
16558 |
Node cardTerm; |
960 |
8279 |
std::map<Node, Node>::iterator it = d_eqc_to_card_term.find(eqc); |
961 |
8279 |
if (it != d_eqc_to_card_term.end()) |
962 |
|
{ |
963 |
8277 |
cardTerm = it->second; |
964 |
|
} |
965 |
|
else |
966 |
|
{ |
967 |
2 |
cardTerm = nm->mkNode(CARD, eqc); |
968 |
|
} |
969 |
21738 |
for (const std::pair<const Node, Node>& itmm : pmemsE) |
970 |
|
{ |
971 |
13459 |
members.push_back(itmm.first); |
972 |
13459 |
exp.push_back(nm->mkNode(MEMBER, itmm.first, cardTerm[0])); |
973 |
|
} |
974 |
8279 |
if (members.size() > 1) |
975 |
|
{ |
976 |
3066 |
exp.push_back(nm->mkNode(DISTINCT, members)); |
977 |
|
} |
978 |
8279 |
if (!members.empty()) |
979 |
|
{ |
980 |
|
Node conc = |
981 |
16558 |
nm->mkNode(GEQ, cardTerm, nm->mkConst(Rational(members.size()))); |
982 |
16558 |
Node expn = exp.size() == 1 ? exp[0] : nm->mkNode(AND, exp); |
983 |
8279 |
d_im.assertInference(conc, InferenceId::SETS_CARD_MINIMAL, expn, 1); |
984 |
|
} |
985 |
|
} |
986 |
|
// flush the lemmas |
987 |
1486 |
d_im.doPendingLemmas(); |
988 |
1486 |
} |
989 |
|
|
990 |
395 |
bool CardinalityExtension::isModelValueBasic(Node eqc) |
991 |
|
{ |
992 |
395 |
return d_nf[eqc].size() == 1 && d_nf[eqc][0] == eqc; |
993 |
|
} |
994 |
|
|
995 |
175 |
void CardinalityExtension::mkModelValueElementsFor( |
996 |
|
Valuation& val, |
997 |
|
Node eqc, |
998 |
|
std::vector<Node>& els, |
999 |
|
const std::map<Node, Node>& mvals, |
1000 |
|
TheoryModel* model) |
1001 |
|
{ |
1002 |
350 |
TypeNode elementType = eqc.getType().getSetElementType(); |
1003 |
175 |
bool elementTypeFinite = d_state.isFiniteType(elementType); |
1004 |
175 |
if (isModelValueBasic(eqc)) |
1005 |
|
{ |
1006 |
117 |
std::map<Node, Node>::iterator it = d_eqc_to_card_term.find(eqc); |
1007 |
117 |
if (it != d_eqc_to_card_term.end()) |
1008 |
|
{ |
1009 |
|
// slack elements from cardinality value |
1010 |
212 |
Node v = val.getModelValue(it->second); |
1011 |
212 |
Trace("sets-model") << "Cardinality of " << eqc << " is " << v |
1012 |
106 |
<< std::endl; |
1013 |
106 |
if (v.getConst<Rational>() > UINT32_MAX) |
1014 |
|
{ |
1015 |
|
std::stringstream ss; |
1016 |
|
ss << "The model for " << eqc << " was computed to have cardinality " |
1017 |
|
<< v << ". We only allow sets up to cardinality " << UINT32_MAX; |
1018 |
|
throw LogicException(ss.str()); |
1019 |
|
} |
1020 |
106 |
std::uint32_t vu = v.getConst<Rational>().getNumerator().toUnsignedInt(); |
1021 |
106 |
Assert(els.size() <= vu); |
1022 |
106 |
NodeManager* nm = NodeManager::currentNM(); |
1023 |
106 |
SkolemManager* sm = nm->getSkolemManager(); |
1024 |
106 |
if (elementTypeFinite) |
1025 |
|
{ |
1026 |
|
// get all members of this finite type |
1027 |
20 |
collectFiniteTypeSetElements(model); |
1028 |
|
} |
1029 |
266 |
while (els.size() < vu) |
1030 |
|
{ |
1031 |
80 |
if (elementTypeFinite) |
1032 |
|
{ |
1033 |
|
// At this point we are sure the formula is satisfiable and all |
1034 |
|
// cardinality constraints are satisfied. Since this type is finite, |
1035 |
|
// there is only one single cardinality graph for all sets of this |
1036 |
|
// type because the universe cardinality constraint has been added by |
1037 |
|
// CardinalityExtension::checkCardinalityExtended. This means we have |
1038 |
|
// enough slack elements of this finite type for all disjoint leaves |
1039 |
|
// in the cardinality graph. Therefore we can safely add new distinct |
1040 |
|
// slack elements for the leaves without worrying about conflicts with |
1041 |
|
// the current members of this finite type. |
1042 |
|
|
1043 |
90 |
Node slack = sm->mkDummySkolem("slack", elementType); |
1044 |
90 |
Node singleton = nm->mkSingleton(elementType, slack); |
1045 |
45 |
els.push_back(singleton); |
1046 |
45 |
d_finite_type_slack_elements[elementType].push_back(slack); |
1047 |
90 |
Trace("sets-model") << "Added slack element " << slack << " to set " |
1048 |
45 |
<< eqc << std::endl; |
1049 |
|
} |
1050 |
|
else |
1051 |
|
{ |
1052 |
35 |
els.push_back(nm->mkSingleton( |
1053 |
70 |
elementType, sm->mkDummySkolem("msde", elementType))); |
1054 |
|
} |
1055 |
|
} |
1056 |
|
} |
1057 |
|
else |
1058 |
|
{ |
1059 |
11 |
Trace("sets-model") << "No slack elements for " << eqc << std::endl; |
1060 |
|
} |
1061 |
|
} |
1062 |
|
else |
1063 |
|
{ |
1064 |
116 |
Trace("sets-model") << "Build value for " << eqc |
1065 |
116 |
<< " based on normal form, size = " << d_nf[eqc].size() |
1066 |
58 |
<< std::endl; |
1067 |
|
// it is union of venn regions |
1068 |
101 |
for (unsigned j = 0; j < d_nf[eqc].size(); j++) |
1069 |
|
{ |
1070 |
43 |
std::map<Node, Node>::const_iterator itm = mvals.find(d_nf[eqc][j]); |
1071 |
43 |
if (itm != mvals.end()) |
1072 |
|
{ |
1073 |
43 |
els.push_back(itm->second); |
1074 |
|
} |
1075 |
|
else |
1076 |
|
{ |
1077 |
|
Assert(false); |
1078 |
|
} |
1079 |
|
} |
1080 |
|
} |
1081 |
175 |
} |
1082 |
|
|
1083 |
20 |
void CardinalityExtension::collectFiniteTypeSetElements(TheoryModel* model) |
1084 |
|
{ |
1085 |
20 |
if (d_finite_type_constants_processed) |
1086 |
|
{ |
1087 |
10 |
return; |
1088 |
|
} |
1089 |
55 |
for (const Node& set : getOrderedSetsEqClasses()) |
1090 |
|
{ |
1091 |
45 |
if (!d_state.isFiniteType(set.getType())) |
1092 |
|
{ |
1093 |
|
continue; |
1094 |
|
} |
1095 |
45 |
if (!isModelValueBasic(set)) |
1096 |
|
{ |
1097 |
|
// only consider leaves in the cardinality graph |
1098 |
25 |
continue; |
1099 |
|
} |
1100 |
40 |
for (const std::pair<const Node, Node>& pair : d_state.getMembers(set)) |
1101 |
|
{ |
1102 |
40 |
Node member = pair.first; |
1103 |
40 |
Node modelRepresentative = model->getRepresentative(member); |
1104 |
20 |
std::vector<Node>& elements = d_finite_type_elements[member.getType()]; |
1105 |
60 |
if (std::find(elements.begin(), elements.end(), modelRepresentative) |
1106 |
60 |
== elements.end()) |
1107 |
|
{ |
1108 |
20 |
elements.push_back(modelRepresentative); |
1109 |
|
} |
1110 |
|
} |
1111 |
|
} |
1112 |
10 |
d_finite_type_constants_processed = true; |
1113 |
|
} |
1114 |
|
|
1115 |
10 |
const std::vector<Node>& CardinalityExtension::getFiniteTypeMembers( |
1116 |
|
TypeNode typeNode) |
1117 |
|
{ |
1118 |
10 |
return d_finite_type_elements[typeNode]; |
1119 |
|
} |
1120 |
|
|
1121 |
|
} // namespace sets |
1122 |
|
} // namespace theory |
1123 |
29505 |
} // namespace cvc5 |