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 |
|
|
29 |
|
using namespace std; |
30 |
|
using namespace cvc5::kind; |
31 |
|
|
32 |
|
namespace cvc5 { |
33 |
|
namespace theory { |
34 |
|
namespace sets { |
35 |
|
|
36 |
8954 |
CardinalityExtension::CardinalityExtension(SolverState& s, |
37 |
|
InferenceManager& im, |
38 |
8954 |
TermRegistry& treg) |
39 |
|
: d_state(s), |
40 |
|
d_im(im), |
41 |
|
d_treg(treg), |
42 |
8954 |
d_card_processed(s.getUserContext()), |
43 |
17908 |
d_finite_type_constants_processed(false) |
44 |
|
{ |
45 |
8954 |
d_true = NodeManager::currentNM()->mkConst(true); |
46 |
8954 |
d_zero = NodeManager::currentNM()->mkConst(Rational(0)); |
47 |
8954 |
} |
48 |
|
|
49 |
16785 |
void CardinalityExtension::reset() |
50 |
|
{ |
51 |
16785 |
d_eqc_to_card_term.clear(); |
52 |
16785 |
d_t_card_enabled.clear(); |
53 |
16785 |
d_finite_type_elements.clear(); |
54 |
16785 |
d_finite_type_slack_elements.clear(); |
55 |
16785 |
d_univProxy.clear(); |
56 |
16785 |
} |
57 |
50125 |
void CardinalityExtension::registerTerm(Node n) |
58 |
|
{ |
59 |
50125 |
Trace("sets-card-debug") << "Register term : " << n << std::endl; |
60 |
50125 |
Assert(n.getKind() == CARD); |
61 |
100250 |
TypeNode tnc = n[0].getType().getSetElementType(); |
62 |
50125 |
d_t_card_enabled[tnc] = true; |
63 |
100250 |
Node r = d_state.getRepresentative(n[0]); |
64 |
50125 |
if (d_eqc_to_card_term.find(r) == d_eqc_to_card_term.end()) |
65 |
|
{ |
66 |
31260 |
d_eqc_to_card_term[r] = n; |
67 |
31260 |
registerCardinalityTerm(n[0]); |
68 |
|
} |
69 |
50125 |
Trace("sets-card-debug") << "...finished register term" << std::endl; |
70 |
50125 |
} |
71 |
|
|
72 |
1694 |
void CardinalityExtension::checkCardinalityExtended() |
73 |
|
{ |
74 |
3387 |
for (std::pair<const TypeNode, bool>& pair : d_t_card_enabled) |
75 |
|
{ |
76 |
3388 |
TypeNode type = pair.first; |
77 |
1694 |
if (pair.second) |
78 |
|
{ |
79 |
1694 |
checkCardinalityExtended(type); |
80 |
|
} |
81 |
|
} |
82 |
1693 |
} |
83 |
|
|
84 |
1694 |
void CardinalityExtension::checkCardinalityExtended(TypeNode& t) |
85 |
|
{ |
86 |
1694 |
NodeManager* nm = NodeManager::currentNM(); |
87 |
2665 |
TypeNode setType = nm->mkSetType(t); |
88 |
1694 |
bool finiteType = d_state.isFiniteType(t); |
89 |
|
// skip infinite types that do not have univset terms |
90 |
1694 |
if (!finiteType && d_state.getUnivSetEqClass(setType).isNull()) |
91 |
|
{ |
92 |
723 |
return; |
93 |
|
} |
94 |
|
|
95 |
|
// get the cardinality of the finite type t |
96 |
1942 |
Cardinality card = t.getCardinality(); |
97 |
|
|
98 |
|
// cardinality of an interpreted finite type t is infinite when t |
99 |
|
// is infinite without --fmf |
100 |
971 |
if (finiteType && card.isInfinite()) |
101 |
|
{ |
102 |
|
// TODO (#1123): support uninterpreted sorts with --finite-model-find |
103 |
2 |
std::stringstream message; |
104 |
1 |
message << "The cardinality " << card << " of the finite type " << t |
105 |
1 |
<< " is not supported yet."; |
106 |
1 |
throw LogicException(message.str()); |
107 |
|
} |
108 |
|
|
109 |
|
// here we call getUnivSet instead of getUnivSetEqClass to generate |
110 |
|
// a univset term for finite types even if they are not used in the input |
111 |
1940 |
Node univ = d_treg.getUnivSet(setType); |
112 |
970 |
std::map<Node, Node>::iterator it = d_univProxy.find(univ); |
113 |
|
|
114 |
1940 |
Node proxy; |
115 |
|
|
116 |
970 |
if (it == d_univProxy.end()) |
117 |
|
{ |
118 |
|
// Force cvc5 to build the cardinality graph for the universe set |
119 |
970 |
proxy = d_treg.getProxy(univ); |
120 |
970 |
d_univProxy[univ] = proxy; |
121 |
|
} |
122 |
|
else |
123 |
|
{ |
124 |
|
proxy = it->second; |
125 |
|
} |
126 |
|
|
127 |
|
// get all equivalent classes of type t |
128 |
1940 |
vector<Node> representatives = d_state.getSetsEqClasses(t); |
129 |
|
|
130 |
970 |
if (finiteType) |
131 |
|
{ |
132 |
1476 |
Node typeCardinality = nm->mkConst(Rational(card.getFiniteCardinality())); |
133 |
1476 |
Node cardUniv = nm->mkNode(kind::CARD, proxy); |
134 |
1476 |
Node leq = nm->mkNode(kind::LEQ, cardUniv, typeCardinality); |
135 |
|
|
136 |
|
// (=> true (<= (card (as univset t)) cardUniv) |
137 |
738 |
if (!d_state.isEntailed(leq, true)) |
138 |
|
{ |
139 |
738 |
d_im.assertInference(leq, InferenceId::SETS_CARD_UNIV_TYPE, d_true, 1); |
140 |
|
} |
141 |
|
} |
142 |
|
|
143 |
|
// add subset lemmas for sets and membership lemmas for negative members |
144 |
9725 |
for (Node& representative : representatives) |
145 |
|
{ |
146 |
|
// the universe set is a subset of itself |
147 |
8755 |
if (representative != d_state.getRepresentative(univ)) |
148 |
|
{ |
149 |
|
// here we only add representatives with variables to avoid adding |
150 |
|
// infinite equivalent generated terms to the cardinality graph |
151 |
9744 |
Node variable = d_state.getVariableSet(representative); |
152 |
7796 |
if (variable.isNull()) |
153 |
|
{ |
154 |
5848 |
continue; |
155 |
|
} |
156 |
|
|
157 |
|
// (=> true (subset representative (as univset t)) |
158 |
3896 |
Node subset = nm->mkNode(kind::SUBSET, variable, proxy); |
159 |
|
// subset terms are rewritten as union terms: (subset A B) implies (= |
160 |
|
// (union A B) B) |
161 |
1948 |
subset = Rewriter::rewrite(subset); |
162 |
1948 |
if (!d_state.isEntailed(subset, true)) |
163 |
|
{ |
164 |
124 |
d_im.assertInference( |
165 |
|
subset, InferenceId::SETS_CARD_UNIV_SUPERSET, d_true, 1); |
166 |
|
} |
167 |
|
|
168 |
|
// negative members are members in the universe set |
169 |
|
const std::map<Node, Node>& negativeMembers = |
170 |
1948 |
d_state.getNegativeMembers(representative); |
171 |
|
|
172 |
4185 |
for (const auto& negativeMember : negativeMembers) |
173 |
|
{ |
174 |
4474 |
Node member = nm->mkNode(MEMBER, negativeMember.first, univ); |
175 |
|
// negativeMember.second is the reason for the negative membership and |
176 |
|
// has kind MEMBER. So we specify the negation as the reason for the |
177 |
|
// negative membership lemma |
178 |
4474 |
Node notMember = nm->mkNode(NOT, negativeMember.second); |
179 |
|
// (=> |
180 |
|
// (not (member negativeMember representative))) |
181 |
|
// (member negativeMember (as univset t))) |
182 |
2237 |
d_im.assertInference( |
183 |
|
member, InferenceId::SETS_CARD_NEGATIVE_MEMBER, notMember, 1); |
184 |
|
} |
185 |
|
} |
186 |
|
} |
187 |
|
} |
188 |
|
|
189 |
1694 |
void CardinalityExtension::check() |
190 |
|
{ |
191 |
1694 |
checkCardinalityExtended(); |
192 |
1693 |
checkRegister(); |
193 |
1693 |
if (d_im.hasSent()) |
194 |
|
{ |
195 |
1905 |
return; |
196 |
|
} |
197 |
1393 |
checkMinCard(); |
198 |
1393 |
if (d_im.hasSent()) |
199 |
|
{ |
200 |
415 |
return; |
201 |
|
} |
202 |
978 |
checkCardCycles(); |
203 |
978 |
if (d_im.hasSent()) |
204 |
|
{ |
205 |
411 |
return; |
206 |
|
} |
207 |
|
// The last step will either do nothing (in which case we are SAT), or request |
208 |
|
// that a new set term is introduced. |
209 |
655 |
std::vector<Node> intro_sets; |
210 |
567 |
checkNormalForms(intro_sets); |
211 |
567 |
if (intro_sets.empty()) |
212 |
|
{ |
213 |
479 |
return; |
214 |
|
} |
215 |
88 |
Assert(intro_sets.size() == 1); |
216 |
88 |
Trace("sets-intro") << "Introduce term : " << intro_sets[0] << std::endl; |
217 |
88 |
Trace("sets-intro") << " Actual Intro : "; |
218 |
88 |
d_treg.debugPrintSet(intro_sets[0], "sets-nf"); |
219 |
88 |
Trace("sets-nf") << std::endl; |
220 |
176 |
Node k = d_treg.getProxy(intro_sets[0]); |
221 |
88 |
AlwaysAssert(!k.isNull()); |
222 |
|
} |
223 |
|
|
224 |
1693 |
void CardinalityExtension::checkRegister() |
225 |
|
{ |
226 |
1693 |
Trace("sets") << "Cardinality graph..." << std::endl; |
227 |
1693 |
NodeManager* nm = NodeManager::currentNM(); |
228 |
|
// first, ensure cardinality relationships are added as lemmas for all |
229 |
|
// non-basic set terms |
230 |
1693 |
const std::vector<Node>& setEqc = d_state.getSetsEqClasses(); |
231 |
18737 |
for (const Node& eqc : setEqc) |
232 |
|
{ |
233 |
17044 |
const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc); |
234 |
38187 |
for (Node n : nvsets) |
235 |
|
{ |
236 |
21143 |
if (!d_state.isCongruent(n)) |
237 |
|
{ |
238 |
|
// if setminus, do for intersection instead |
239 |
20775 |
if (n.getKind() == SETMINUS) |
240 |
|
{ |
241 |
10365 |
n = Rewriter::rewrite(nm->mkNode(INTERSECTION, n[0], n[1])); |
242 |
|
} |
243 |
20775 |
registerCardinalityTerm(n); |
244 |
|
} |
245 |
|
} |
246 |
|
} |
247 |
1693 |
Trace("sets") << "Done cardinality graph" << std::endl; |
248 |
1693 |
} |
249 |
|
|
250 |
52035 |
void CardinalityExtension::registerCardinalityTerm(Node n) |
251 |
|
{ |
252 |
53745 |
TypeNode tnc = n.getType().getSetElementType(); |
253 |
52035 |
if (d_t_card_enabled.find(tnc) == d_t_card_enabled.end()) |
254 |
|
{ |
255 |
|
// if no cardinality constraints for sets of this type, we can ignore |
256 |
150 |
return; |
257 |
|
} |
258 |
51885 |
if (d_card_processed.find(n) != d_card_processed.end()) |
259 |
|
{ |
260 |
|
// already processed |
261 |
50175 |
return; |
262 |
|
} |
263 |
1710 |
d_card_processed.insert(n); |
264 |
1710 |
NodeManager* nm = NodeManager::currentNM(); |
265 |
1710 |
Trace("sets-card") << "Cardinality lemmas for " << n << " : " << std::endl; |
266 |
3420 |
std::vector<Node> cterms; |
267 |
1710 |
if (n.getKind() == INTERSECTION) |
268 |
|
{ |
269 |
990 |
for (unsigned e = 0; e < 2; e++) |
270 |
|
{ |
271 |
1320 |
Node s = nm->mkNode(SETMINUS, n[e], n[1 - e]); |
272 |
660 |
cterms.push_back(s); |
273 |
|
} |
274 |
660 |
Node pos_lem = nm->mkNode(GEQ, nm->mkNode(CARD, n), d_zero); |
275 |
330 |
d_im.assertInference( |
276 |
|
pos_lem, InferenceId::SETS_CARD_POSITIVE, d_emp_exp, 1); |
277 |
|
} |
278 |
|
else |
279 |
|
{ |
280 |
1380 |
cterms.push_back(n); |
281 |
|
} |
282 |
3750 |
for (unsigned k = 0, csize = cterms.size(); k < csize; k++) |
283 |
|
{ |
284 |
4080 |
Node nn = cterms[k]; |
285 |
4080 |
Node nk = d_treg.getProxy(nn); |
286 |
4080 |
Node pos_lem = nm->mkNode(GEQ, nm->mkNode(CARD, nk), d_zero); |
287 |
2040 |
d_im.assertInference( |
288 |
|
pos_lem, InferenceId::SETS_CARD_POSITIVE, d_emp_exp, 1); |
289 |
2040 |
if (nn != nk) |
290 |
|
{ |
291 |
1924 |
Node lem = nm->mkNode(EQUAL, nm->mkNode(CARD, nk), nm->mkNode(CARD, nn)); |
292 |
962 |
lem = Rewriter::rewrite(lem); |
293 |
962 |
Trace("sets-card") << " " << k << " : " << lem << std::endl; |
294 |
962 |
d_im.assertInference(lem, InferenceId::SETS_CARD_EQUAL, d_emp_exp, 1); |
295 |
|
} |
296 |
|
} |
297 |
1710 |
d_im.doPendingLemmas(); |
298 |
|
} |
299 |
|
|
300 |
978 |
void CardinalityExtension::checkCardCycles() |
301 |
|
{ |
302 |
978 |
Trace("sets") << "Check cardinality cycles..." << std::endl; |
303 |
|
// build order of equivalence classes, also build cardinality graph |
304 |
978 |
const std::vector<Node>& setEqc = d_state.getSetsEqClasses(); |
305 |
978 |
d_oSetEqc.clear(); |
306 |
978 |
d_card_parent.clear(); |
307 |
8377 |
for (const Node& s : setEqc) |
308 |
|
{ |
309 |
15209 |
std::vector<Node> curr; |
310 |
15209 |
std::vector<Node> exp; |
311 |
7810 |
checkCardCyclesRec(s, curr, exp); |
312 |
7810 |
if (d_im.hasSent()) |
313 |
|
{ |
314 |
411 |
return; |
315 |
|
} |
316 |
|
} |
317 |
|
|
318 |
567 |
Trace("sets") << "d_card_parent: " << d_card_parent << std::endl; |
319 |
567 |
Trace("sets") << "d_oSetEqc: " << d_oSetEqc << std::endl; |
320 |
567 |
Trace("sets") << "Done check cardinality cycles" << std::endl; |
321 |
|
} |
322 |
|
|
323 |
13435 |
void CardinalityExtension::checkCardCyclesRec(Node eqc, |
324 |
|
std::vector<Node>& curr, |
325 |
|
std::vector<Node>& exp) |
326 |
|
{ |
327 |
13435 |
Trace("sets-cycle-debug") << "Traverse eqc " << eqc << std::endl; |
328 |
13435 |
NodeManager* nm = NodeManager::currentNM(); |
329 |
13435 |
if (std::find(curr.begin(), curr.end(), eqc) != curr.end()) |
330 |
|
{ |
331 |
|
Trace("sets-debug") << "Found venn region loop..." << std::endl; |
332 |
|
if (curr.size() > 1) |
333 |
|
{ |
334 |
|
// all regions must be equal |
335 |
|
std::vector<Node> conc; |
336 |
|
bool foundLoopStart = false; |
337 |
|
for (const Node& cc : curr) |
338 |
|
{ |
339 |
|
if (cc == eqc) |
340 |
|
{ |
341 |
|
foundLoopStart = true; |
342 |
|
} |
343 |
|
else if (foundLoopStart && eqc != cc) |
344 |
|
{ |
345 |
|
conc.push_back(eqc.eqNode(cc)); |
346 |
|
} |
347 |
|
} |
348 |
|
Node fact = conc.size() == 1 ? conc[0] : nm->mkNode(AND, conc); |
349 |
|
Trace("sets-cycle-debug") |
350 |
|
<< "CYCLE: " << fact << " from " << exp << std::endl; |
351 |
|
d_im.assertInference(fact, InferenceId::SETS_CARD_CYCLE, exp); |
352 |
|
d_im.doPendingLemmas(); |
353 |
|
} |
354 |
|
else |
355 |
|
{ |
356 |
|
// should be guaranteed based on not exploring equal parents |
357 |
|
Assert(false); |
358 |
|
} |
359 |
7607 |
return; |
360 |
|
} |
361 |
13435 |
if (std::find(d_oSetEqc.begin(), d_oSetEqc.end(), eqc) != d_oSetEqc.end()) |
362 |
|
{ |
363 |
|
// already processed |
364 |
5598 |
return; |
365 |
|
} |
366 |
7837 |
const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc); |
367 |
7837 |
if (nvsets.empty()) |
368 |
|
{ |
369 |
|
// no non-variable sets, trivial |
370 |
1591 |
d_oSetEqc.push_back(eqc); |
371 |
1591 |
return; |
372 |
|
} |
373 |
6246 |
curr.push_back(eqc); |
374 |
12074 |
TypeNode tn = eqc.getType(); |
375 |
6246 |
bool is_empty = eqc == d_state.getEmptySetEqClass(tn); |
376 |
12074 |
Node emp_set = d_treg.getEmptySet(tn); |
377 |
16114 |
for (const Node& n : nvsets) |
378 |
|
{ |
379 |
10286 |
Kind nk = n.getKind(); |
380 |
10286 |
if (nk != INTERSECTION && nk != SETMINUS) |
381 |
|
{ |
382 |
7304 |
continue; |
383 |
|
} |
384 |
14772 |
Trace("sets-debug") << "Build cardinality parents for " << n << "..." |
385 |
7386 |
<< std::endl; |
386 |
12850 |
std::vector<Node> sib; |
387 |
7386 |
unsigned true_sib = 0; |
388 |
7386 |
if (n.getKind() == INTERSECTION) |
389 |
|
{ |
390 |
2790 |
d_localBase[n] = n; |
391 |
8370 |
for (unsigned e = 0; e < 2; e++) |
392 |
|
{ |
393 |
11160 |
Node sm = Rewriter::rewrite(nm->mkNode(SETMINUS, n[e], n[1 - e])); |
394 |
5580 |
sib.push_back(sm); |
395 |
|
} |
396 |
2790 |
true_sib = 2; |
397 |
|
} |
398 |
|
else |
399 |
|
{ |
400 |
9192 |
Node si = Rewriter::rewrite(nm->mkNode(INTERSECTION, n[0], n[1])); |
401 |
4596 |
sib.push_back(si); |
402 |
4596 |
d_localBase[n] = si; |
403 |
9192 |
Node osm = Rewriter::rewrite(nm->mkNode(SETMINUS, n[1], n[0])); |
404 |
4596 |
sib.push_back(osm); |
405 |
4596 |
true_sib = 1; |
406 |
|
} |
407 |
12850 |
Node u = Rewriter::rewrite(nm->mkNode(UNION, n[0], n[1])); |
408 |
7386 |
if (!d_state.hasTerm(u)) |
409 |
|
{ |
410 |
4560 |
u = Node::null(); |
411 |
|
} |
412 |
7386 |
unsigned n_parents = true_sib + (u.isNull() ? 0 : 1); |
413 |
|
// if this set is empty |
414 |
7386 |
if (is_empty) |
415 |
|
{ |
416 |
1689 |
Assert(d_state.areEqual(n, emp_set)); |
417 |
1689 |
Trace("sets-debug") << " empty, parents equal siblings" << std::endl; |
418 |
1689 |
std::vector<Node> conc; |
419 |
|
// parent equal siblings |
420 |
3735 |
for (unsigned e = 0; e < true_sib; e++) |
421 |
|
{ |
422 |
2046 |
if (d_state.hasTerm(sib[e]) && !d_state.areEqual(n[e], sib[e])) |
423 |
|
{ |
424 |
234 |
conc.push_back(n[e].eqNode(sib[e])); |
425 |
|
} |
426 |
|
} |
427 |
1689 |
d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_EMP, n.eqNode(emp_set)); |
428 |
1689 |
d_im.doPendingLemmas(); |
429 |
1689 |
if (d_im.hasSent()) |
430 |
|
{ |
431 |
185 |
return; |
432 |
|
} |
433 |
|
else |
434 |
|
{ |
435 |
|
// justify why there is no edge to parents (necessary?) |
436 |
4006 |
for (unsigned e = 0; e < n_parents; e++) |
437 |
|
{ |
438 |
2502 |
Node p = (e == true_sib) ? u : n[e]; |
439 |
|
} |
440 |
|
} |
441 |
1504 |
continue; |
442 |
|
} |
443 |
11161 |
std::vector<Node> card_parents; |
444 |
11161 |
std::vector<int> card_parent_ids; |
445 |
|
// check if equal to a parent |
446 |
15589 |
for (unsigned e = 0; e < n_parents; e++) |
447 |
|
{ |
448 |
20016 |
Trace("sets-debug") << " check parent " << e << "/" << n_parents |
449 |
10008 |
<< std::endl; |
450 |
10008 |
bool is_union = e == true_sib; |
451 |
19900 |
Node p = (e == true_sib) ? u : n[e]; |
452 |
20016 |
Trace("sets-debug") << " check relation to parent " << p |
453 |
10008 |
<< ", isu=" << is_union << "..." << std::endl; |
454 |
|
// if parent is empty |
455 |
10008 |
if (d_state.areEqual(p, emp_set)) |
456 |
|
{ |
457 |
2 |
Trace("sets-debug") << " it is empty..." << std::endl; |
458 |
2 |
Assert(!d_state.areEqual(n, emp_set)); |
459 |
4 |
d_im.assertInference( |
460 |
4 |
n.eqNode(emp_set), InferenceId::SETS_CARD_GRAPH_EMP_PARENT, p.eqNode(emp_set)); |
461 |
2 |
d_im.doPendingLemmas(); |
462 |
2 |
if (d_im.hasSent()) |
463 |
|
{ |
464 |
2 |
return; |
465 |
|
} |
466 |
|
// if we are equal to a parent |
467 |
|
} |
468 |
10006 |
else if (d_state.areEqual(p, n)) |
469 |
|
{ |
470 |
2361 |
Trace("sets-debug") << " it is equal to this..." << std::endl; |
471 |
4608 |
std::vector<Node> conc; |
472 |
4608 |
std::vector<int> sib_emp_indices; |
473 |
2361 |
if (is_union) |
474 |
|
{ |
475 |
126 |
for (unsigned s = 0; s < sib.size(); s++) |
476 |
|
{ |
477 |
84 |
sib_emp_indices.push_back(s); |
478 |
|
} |
479 |
|
} |
480 |
|
else |
481 |
|
{ |
482 |
2319 |
sib_emp_indices.push_back(e); |
483 |
|
} |
484 |
|
// sibling(s) are empty |
485 |
4764 |
for (unsigned si : sib_emp_indices) |
486 |
|
{ |
487 |
2403 |
if (!d_state.areEqual(sib[si], emp_set)) |
488 |
|
{ |
489 |
110 |
conc.push_back(sib[si].eqNode(emp_set)); |
490 |
|
} |
491 |
|
else |
492 |
|
{ |
493 |
4586 |
Trace("sets-debug") |
494 |
2293 |
<< "Sibling " << sib[si] << " is already empty." << std::endl; |
495 |
|
} |
496 |
|
} |
497 |
2361 |
if (!is_union && nk == INTERSECTION && !u.isNull()) |
498 |
|
{ |
499 |
|
// union is equal to other parent |
500 |
1084 |
if (!d_state.areEqual(u, n[1 - e])) |
501 |
|
{ |
502 |
4 |
conc.push_back(u.eqNode(n[1 - e])); |
503 |
|
} |
504 |
|
} |
505 |
4722 |
Trace("sets-debug") |
506 |
2361 |
<< "...derived " << conc.size() << " conclusions" << std::endl; |
507 |
2361 |
d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_EQ_PARENT, n.eqNode(p)); |
508 |
2361 |
d_im.doPendingLemmas(); |
509 |
2361 |
if (d_im.hasSent()) |
510 |
|
{ |
511 |
114 |
return; |
512 |
|
} |
513 |
|
} |
514 |
|
else |
515 |
|
{ |
516 |
7645 |
Trace("sets-cdg") << "Card graph : " << n << " -> " << p << std::endl; |
517 |
|
// otherwise, we a syntactic subset of p |
518 |
7645 |
card_parents.push_back(p); |
519 |
7645 |
card_parent_ids.push_back(is_union ? 2 : e); |
520 |
|
} |
521 |
|
} |
522 |
5581 |
Assert(d_card_parent[n].empty()); |
523 |
5581 |
Trace("sets-debug") << "get parent representatives..." << std::endl; |
524 |
|
// for each parent, take their representatives |
525 |
13110 |
for (unsigned k = 0, numcp = card_parents.size(); k < numcp; k++) |
526 |
|
{ |
527 |
15168 |
Node cpk = card_parents[k]; |
528 |
15168 |
Node eqcc = d_state.getRepresentative(cpk); |
529 |
15278 |
Trace("sets-debug") << "Check card parent " << k << "/" |
530 |
7639 |
<< card_parents.size() << std::endl; |
531 |
|
|
532 |
|
// if parent is singleton, then we should either be empty to equal to it |
533 |
15168 |
Node eqccSingleton = d_state.getSingletonEqClass(eqcc); |
534 |
7639 |
if (!eqccSingleton.isNull()) |
535 |
|
{ |
536 |
4 |
bool eq_parent = false; |
537 |
8 |
std::vector<Node> exps; |
538 |
4 |
d_state.addEqualityToExp(cpk, eqccSingleton, exps); |
539 |
4 |
if (d_state.areDisequal(n, emp_set)) |
540 |
|
{ |
541 |
|
exps.push_back(n.eqNode(emp_set).negate()); |
542 |
|
eq_parent = true; |
543 |
|
} |
544 |
|
else |
545 |
|
{ |
546 |
4 |
const std::map<Node, Node>& pmemsE = d_state.getMembers(eqc); |
547 |
4 |
if (!pmemsE.empty()) |
548 |
|
{ |
549 |
8 |
Node pmem = pmemsE.begin()->second; |
550 |
4 |
exps.push_back(pmem); |
551 |
4 |
d_state.addEqualityToExp(n, pmem[1], exps); |
552 |
4 |
eq_parent = true; |
553 |
|
} |
554 |
|
} |
555 |
|
// must be equal to parent |
556 |
4 |
if (eq_parent) |
557 |
|
{ |
558 |
8 |
Node conc = n.eqNode(cpk); |
559 |
4 |
d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_PARENT_SINGLETON, exps); |
560 |
4 |
d_im.doPendingLemmas(); |
561 |
|
} |
562 |
|
else |
563 |
|
{ |
564 |
|
// split on empty |
565 |
|
Trace("sets-nf") << "Split empty : " << n << std::endl; |
566 |
|
d_im.split(n.eqNode(emp_set), InferenceId::SETS_CARD_SPLIT_EMPTY, 1); |
567 |
|
} |
568 |
4 |
Assert(d_im.hasSent()); |
569 |
4 |
return; |
570 |
|
} |
571 |
|
else |
572 |
|
{ |
573 |
7635 |
bool dup = false; |
574 |
10513 |
for (unsigned l = 0, numcpn = d_card_parent[n].size(); l < numcpn; l++) |
575 |
|
{ |
576 |
3878 |
Node cpnl = d_card_parent[n][l]; |
577 |
2984 |
if (eqcc != cpnl) |
578 |
|
{ |
579 |
1190 |
continue; |
580 |
|
} |
581 |
3588 |
Trace("sets-debug") << " parents " << l << " and " << k |
582 |
1794 |
<< " are equal, ids = " << card_parent_ids[l] |
583 |
1794 |
<< " " << card_parent_ids[k] << std::endl; |
584 |
1794 |
dup = true; |
585 |
1794 |
if (n.getKind() != INTERSECTION) |
586 |
|
{ |
587 |
794 |
continue; |
588 |
|
} |
589 |
1000 |
Assert(card_parent_ids[l] != 2); |
590 |
1894 |
std::vector<Node> conc; |
591 |
1000 |
if (card_parent_ids[k] == 2) |
592 |
|
{ |
593 |
|
// intersection is equal to other parent |
594 |
1000 |
unsigned pid = 1 - card_parent_ids[l]; |
595 |
1000 |
if (!d_state.areEqual(n[pid], n)) |
596 |
|
{ |
597 |
212 |
Trace("sets-debug") |
598 |
106 |
<< " one of them is union, make equal to other..." |
599 |
106 |
<< std::endl; |
600 |
106 |
conc.push_back(n[pid].eqNode(n)); |
601 |
|
} |
602 |
|
} |
603 |
|
else |
604 |
|
{ |
605 |
|
if (!d_state.areEqual(cpk, n)) |
606 |
|
{ |
607 |
|
Trace("sets-debug") |
608 |
|
<< " neither is union, make equal to one parent..." |
609 |
|
<< std::endl; |
610 |
|
// intersection is equal to one of the parents |
611 |
|
conc.push_back(cpk.eqNode(n)); |
612 |
|
} |
613 |
|
} |
614 |
1000 |
d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_EQ_PARENT_2, cpk.eqNode(cpnl)); |
615 |
1000 |
d_im.doPendingLemmas(); |
616 |
1000 |
if (d_im.hasSent()) |
617 |
|
{ |
618 |
106 |
return; |
619 |
|
} |
620 |
|
} |
621 |
7529 |
if (!dup) |
622 |
|
{ |
623 |
5841 |
d_card_parent[n].push_back(eqcc); |
624 |
|
} |
625 |
|
} |
626 |
|
} |
627 |
|
// now recurse on parents (to ensure their normal will be computed after |
628 |
|
// this eqc) |
629 |
5471 |
exp.push_back(eqc.eqNode(n)); |
630 |
11089 |
for (const Node& cpnc : d_card_parent[n]) |
631 |
|
{ |
632 |
11250 |
Trace("sets-cycle-debug") |
633 |
5625 |
<< "Traverse card parent " << eqc << " -> " << cpnc << std::endl; |
634 |
5625 |
checkCardCyclesRec(cpnc, curr, exp); |
635 |
5625 |
if (d_im.hasSent()) |
636 |
|
{ |
637 |
7 |
return; |
638 |
|
} |
639 |
|
} |
640 |
5464 |
exp.pop_back(); |
641 |
|
} |
642 |
5828 |
curr.pop_back(); |
643 |
|
// parents now processed, can add to ordered list |
644 |
5828 |
d_oSetEqc.push_back(eqc); |
645 |
|
} |
646 |
|
|
647 |
567 |
void CardinalityExtension::checkNormalForms(std::vector<Node>& intro_sets) |
648 |
|
{ |
649 |
567 |
Trace("sets") << "Check normal forms..." << std::endl; |
650 |
|
// now, build normal form for each equivalence class |
651 |
|
// d_oSetEqc is now sorted such that for each d_oSetEqc[i], d_oSetEqc[j], |
652 |
|
// if d_oSetEqc[i] is a strict syntactic subterm of d_oSetEqc[j], then i<j. |
653 |
567 |
d_ff.clear(); |
654 |
567 |
d_nf.clear(); |
655 |
2567 |
for (int i = (int)(d_oSetEqc.size() - 1); i >= 0; i--) |
656 |
|
{ |
657 |
2451 |
checkNormalForm(d_oSetEqc[i], intro_sets); |
658 |
2451 |
if (d_im.hasSent() || !intro_sets.empty()) |
659 |
|
{ |
660 |
451 |
return; |
661 |
|
} |
662 |
|
} |
663 |
116 |
Trace("sets") << "Done check normal forms" << std::endl; |
664 |
|
} |
665 |
|
|
666 |
2451 |
void CardinalityExtension::checkNormalForm(Node eqc, |
667 |
|
std::vector<Node>& intro_sets) |
668 |
|
{ |
669 |
3564 |
TypeNode tn = eqc.getType(); |
670 |
2451 |
Trace("sets") << "Compute normal form for " << eqc << std::endl; |
671 |
2451 |
Trace("sets-nf") << "Compute N " << eqc << "..." << std::endl; |
672 |
2451 |
if (eqc == d_state.getEmptySetEqClass(tn)) |
673 |
|
{ |
674 |
361 |
d_nf[eqc].clear(); |
675 |
361 |
Trace("sets-nf") << "----> N " << eqc << " => {}" << std::endl; |
676 |
361 |
return; |
677 |
|
} |
678 |
|
// flat/normal forms are sets of equivalence classes |
679 |
3203 |
Node base; |
680 |
3203 |
std::vector<Node> comps; |
681 |
|
std::map<Node, std::map<Node, std::vector<Node> > >::iterator it = |
682 |
2090 |
d_ff.find(eqc); |
683 |
2090 |
if (it != d_ff.end()) |
684 |
|
{ |
685 |
652 |
for (std::pair<const Node, std::vector<Node> >& itf : it->second) |
686 |
|
{ |
687 |
380 |
std::sort(itf.second.begin(), itf.second.end()); |
688 |
380 |
if (base.isNull()) |
689 |
|
{ |
690 |
272 |
base = itf.first; |
691 |
|
} |
692 |
|
else |
693 |
|
{ |
694 |
108 |
comps.push_back(itf.first); |
695 |
|
} |
696 |
760 |
Trace("sets-nf") << " F " << itf.first << " : " << itf.second |
697 |
380 |
<< std::endl; |
698 |
380 |
Trace("sets-nf-debug") << " ..."; |
699 |
380 |
d_treg.debugPrintSet(itf.first, "sets-nf-debug"); |
700 |
380 |
Trace("sets-nf-debug") << std::endl; |
701 |
|
} |
702 |
|
} |
703 |
|
else |
704 |
|
{ |
705 |
1818 |
Trace("sets-nf") << "(no flat forms)" << std::endl; |
706 |
|
} |
707 |
2090 |
std::map<Node, std::vector<Node> >& ffeqc = d_ff[eqc]; |
708 |
2090 |
Assert(d_nf.find(eqc) == d_nf.end()); |
709 |
2090 |
std::vector<Node>& nfeqc = d_nf[eqc]; |
710 |
2090 |
NodeManager* nm = NodeManager::currentNM(); |
711 |
2090 |
bool success = true; |
712 |
3203 |
Node emp_set = d_treg.getEmptySet(tn); |
713 |
2090 |
if (!base.isNull()) |
714 |
|
{ |
715 |
292 |
for (unsigned j = 0, csize = comps.size(); j < csize; j++) |
716 |
|
{ |
717 |
|
// compare if equal |
718 |
128 |
std::vector<Node> c; |
719 |
108 |
c.push_back(base); |
720 |
108 |
c.push_back(comps[j]); |
721 |
324 |
std::vector<Node> only[2]; |
722 |
128 |
std::vector<Node> common; |
723 |
216 |
Trace("sets-nf-debug") << "Compare venn regions of " << base << " vs " |
724 |
108 |
<< comps[j] << std::endl; |
725 |
108 |
unsigned k[2] = {0, 0}; |
726 |
1020 |
while (k[0] < ffeqc[c[0]].size() || k[1] < ffeqc[c[1]].size()) |
727 |
|
{ |
728 |
456 |
bool proc = true; |
729 |
1368 |
for (unsigned e = 0; e < 2; e++) |
730 |
|
{ |
731 |
912 |
if (k[e] == ffeqc[c[e]].size()) |
732 |
|
{ |
733 |
310 |
for (; k[1 - e] < ffeqc[c[1 - e]].size(); ++k[1 - e]) |
734 |
|
{ |
735 |
90 |
only[1 - e].push_back(ffeqc[c[1 - e]][k[1 - e]]); |
736 |
|
} |
737 |
130 |
proc = false; |
738 |
|
} |
739 |
|
} |
740 |
456 |
if (proc) |
741 |
|
{ |
742 |
368 |
if (ffeqc[c[0]][k[0]] == ffeqc[c[1]][k[1]]) |
743 |
|
{ |
744 |
138 |
common.push_back(ffeqc[c[0]][k[0]]); |
745 |
138 |
k[0]++; |
746 |
138 |
k[1]++; |
747 |
|
} |
748 |
230 |
else if (ffeqc[c[0]][k[0]] < ffeqc[c[1]][k[1]]) |
749 |
|
{ |
750 |
113 |
only[0].push_back(ffeqc[c[0]][k[0]]); |
751 |
113 |
k[0]++; |
752 |
|
} |
753 |
|
else |
754 |
|
{ |
755 |
117 |
only[1].push_back(ffeqc[c[1]][k[1]]); |
756 |
117 |
k[1]++; |
757 |
|
} |
758 |
|
} |
759 |
|
} |
760 |
108 |
if (!only[0].empty() || !only[1].empty()) |
761 |
|
{ |
762 |
88 |
if (Trace.isOn("sets-nf-debug")) |
763 |
|
{ |
764 |
|
Trace("sets-nf-debug") << "Unique venn regions : " << std::endl; |
765 |
|
for (unsigned e = 0; e < 2; e++) |
766 |
|
{ |
767 |
|
Trace("sets-nf-debug") << " " << c[e] << " : { "; |
768 |
|
for (unsigned l = 0; l < only[e].size(); l++) |
769 |
|
{ |
770 |
|
if (l > 0) |
771 |
|
{ |
772 |
|
Trace("sets-nf-debug") << ", "; |
773 |
|
} |
774 |
|
Trace("sets-nf-debug") << "[" << only[e][l] << "]"; |
775 |
|
} |
776 |
|
Trace("sets-nf-debug") << " }" << std::endl; |
777 |
|
} |
778 |
|
} |
779 |
|
// try to make one empty, prefer the unique ones first |
780 |
352 |
for (unsigned e = 0; e < 3; e++) |
781 |
|
{ |
782 |
264 |
unsigned sz = e == 2 ? common.size() : only[e].size(); |
783 |
664 |
for (unsigned l = 0; l < sz; l++) |
784 |
|
{ |
785 |
800 |
Node r = e == 2 ? common[l] : only[e][l]; |
786 |
400 |
Trace("sets-nf-debug") << "Try split empty : " << r << std::endl; |
787 |
400 |
Trace("sets-nf-debug") << " actual : "; |
788 |
400 |
d_treg.debugPrintSet(r, "sets-nf-debug"); |
789 |
400 |
Trace("sets-nf-debug") << std::endl; |
790 |
400 |
Assert(!d_state.areEqual(r, emp_set)); |
791 |
400 |
if (!d_state.areDisequal(r, emp_set) && !d_state.hasMembers(r)) |
792 |
|
{ |
793 |
|
// guess that its equal empty if it has no explicit members |
794 |
|
Trace("sets-nf") << " Split empty : " << r << std::endl; |
795 |
|
Trace("sets-nf") << "Actual Split : "; |
796 |
|
d_treg.debugPrintSet(r, "sets-nf"); |
797 |
|
Trace("sets-nf") << std::endl; |
798 |
|
d_im.split(r.eqNode(emp_set), InferenceId::UNKNOWN, 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 |
184 |
if (success) |
853 |
|
{ |
854 |
|
// normal form is flat form of base |
855 |
184 |
nfeqc.insert(nfeqc.end(), ffeqc[base].begin(), ffeqc[base].end()); |
856 |
184 |
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 |
5414 |
if (!eqc.isConst() && !d_state.areDisequal(eqc, emp_set) |
867 |
4511 |
&& !d_state.hasMembers(eqc)) |
868 |
|
{ |
869 |
363 |
Trace("sets-nf-debug") << "Split on leaf " << eqc << std::endl; |
870 |
363 |
d_im.split(eqc.eqNode(emp_set), InferenceId::UNKNOWN); |
871 |
363 |
success = false; |
872 |
|
} |
873 |
|
else |
874 |
|
{ |
875 |
|
// normal form is this equivalence class |
876 |
1455 |
nfeqc.push_back(eqc); |
877 |
2910 |
Trace("sets-nf") << "----> N " << eqc << " => { " << eqc << " }" |
878 |
1455 |
<< std::endl; |
879 |
|
} |
880 |
|
} |
881 |
2002 |
if (!success) |
882 |
|
{ |
883 |
363 |
Assert(d_im.hasSent()); |
884 |
363 |
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 |
1639 |
const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc); |
889 |
1639 |
if (nvsets.empty()) |
890 |
|
{ |
891 |
|
// no non-variable sets |
892 |
526 |
return; |
893 |
|
} |
894 |
2226 |
std::map<Node, std::map<Node, bool> > parents_proc; |
895 |
2597 |
for (const Node& n : nvsets) |
896 |
|
{ |
897 |
1484 |
Trace("sets-nf-debug") << "Carry nf for term " << n << std::endl; |
898 |
1484 |
if (d_card_parent[n].empty()) |
899 |
|
{ |
900 |
|
// nothing to do |
901 |
373 |
continue; |
902 |
|
} |
903 |
1111 |
Assert(d_localBase.find(n) != d_localBase.end()); |
904 |
2222 |
Node cbase = d_localBase[n]; |
905 |
1111 |
Trace("sets-nf-debug") << "Card base is " << cbase << std::endl; |
906 |
2322 |
for (const Node& p : d_card_parent[n]) |
907 |
|
{ |
908 |
1211 |
Trace("sets-nf-debug") << "Check parent " << p << std::endl; |
909 |
1211 |
if (parents_proc[cbase].find(p) != parents_proc[cbase].end()) |
910 |
|
{ |
911 |
|
Trace("sets-nf-debug") << "..already processed parent " << p << " for " |
912 |
|
<< cbase << std::endl; |
913 |
|
continue; |
914 |
|
} |
915 |
1211 |
parents_proc[cbase][p] = true; |
916 |
2422 |
Trace("sets-nf-debug") << "Carry nf to parent ( " << cbase << ", [" << p |
917 |
1211 |
<< "] ), from " << n << "..." << std::endl; |
918 |
|
|
919 |
1211 |
std::vector<Node>& ffpc = d_ff[p][cbase]; |
920 |
2595 |
for (const Node& nfeqci : nfeqc) |
921 |
|
{ |
922 |
1384 |
if (std::find(ffpc.begin(), ffpc.end(), nfeqci) == ffpc.end()) |
923 |
|
{ |
924 |
1211 |
ffpc.insert(ffpc.end(), nfeqc.begin(), nfeqc.end()); |
925 |
|
} |
926 |
|
else |
927 |
|
{ |
928 |
|
// if it is a duplicate venn region, it must be empty since it is |
929 |
|
// coming from syntactically disjoint siblings |
930 |
|
} |
931 |
|
} |
932 |
|
} |
933 |
|
} |
934 |
|
} |
935 |
|
|
936 |
1393 |
void CardinalityExtension::checkMinCard() |
937 |
|
{ |
938 |
1393 |
NodeManager* nm = NodeManager::currentNM(); |
939 |
1393 |
const std::vector<Node>& setEqc = d_state.getSetsEqClasses(); |
940 |
16025 |
for (int i = (int)(setEqc.size() - 1); i >= 0; i--) |
941 |
|
{ |
942 |
22710 |
Node eqc = setEqc[i]; |
943 |
22710 |
TypeNode tn = eqc.getType().getSetElementType(); |
944 |
14632 |
if (d_t_card_enabled.find(tn) == d_t_card_enabled.end()) |
945 |
|
{ |
946 |
|
// cardinality is not enabled for this type, skip |
947 |
126 |
continue; |
948 |
|
} |
949 |
|
// get members in class |
950 |
14506 |
const std::map<Node, Node>& pmemsE = d_state.getMembers(eqc); |
951 |
14506 |
if (pmemsE.empty()) |
952 |
|
{ |
953 |
|
// no members, trivial |
954 |
6428 |
continue; |
955 |
|
} |
956 |
16156 |
std::vector<Node> exp; |
957 |
16156 |
std::vector<Node> members; |
958 |
16156 |
Node cardTerm; |
959 |
8078 |
std::map<Node, Node>::iterator it = d_eqc_to_card_term.find(eqc); |
960 |
8078 |
if (it != d_eqc_to_card_term.end()) |
961 |
|
{ |
962 |
8076 |
cardTerm = it->second; |
963 |
|
} |
964 |
|
else |
965 |
|
{ |
966 |
2 |
cardTerm = nm->mkNode(CARD, eqc); |
967 |
|
} |
968 |
21125 |
for (const std::pair<const Node, Node>& itmm : pmemsE) |
969 |
|
{ |
970 |
13047 |
members.push_back(itmm.first); |
971 |
13047 |
exp.push_back(nm->mkNode(MEMBER, itmm.first, cardTerm[0])); |
972 |
|
} |
973 |
8078 |
if (members.size() > 1) |
974 |
|
{ |
975 |
2993 |
exp.push_back(nm->mkNode(DISTINCT, members)); |
976 |
|
} |
977 |
8078 |
if (!members.empty()) |
978 |
|
{ |
979 |
|
Node conc = |
980 |
16156 |
nm->mkNode(GEQ, cardTerm, nm->mkConst(Rational(members.size()))); |
981 |
16156 |
Node expn = exp.size() == 1 ? exp[0] : nm->mkNode(AND, exp); |
982 |
8078 |
d_im.assertInference(conc, InferenceId::SETS_CARD_MINIMAL, expn, 1); |
983 |
|
} |
984 |
|
} |
985 |
|
// flush the lemmas |
986 |
1393 |
d_im.doPendingLemmas(); |
987 |
1393 |
} |
988 |
|
|
989 |
371 |
bool CardinalityExtension::isModelValueBasic(Node eqc) |
990 |
|
{ |
991 |
371 |
return d_nf[eqc].size() == 1 && d_nf[eqc][0] == eqc; |
992 |
|
} |
993 |
|
|
994 |
163 |
void CardinalityExtension::mkModelValueElementsFor( |
995 |
|
Valuation& val, |
996 |
|
Node eqc, |
997 |
|
std::vector<Node>& els, |
998 |
|
const std::map<Node, Node>& mvals, |
999 |
|
TheoryModel* model) |
1000 |
|
{ |
1001 |
326 |
TypeNode elementType = eqc.getType().getSetElementType(); |
1002 |
163 |
bool elementTypeFinite = d_state.isFiniteType(elementType); |
1003 |
163 |
if (isModelValueBasic(eqc)) |
1004 |
|
{ |
1005 |
112 |
std::map<Node, Node>::iterator it = d_eqc_to_card_term.find(eqc); |
1006 |
112 |
if (it != d_eqc_to_card_term.end()) |
1007 |
|
{ |
1008 |
|
// slack elements from cardinality value |
1009 |
202 |
Node v = val.getModelValue(it->second); |
1010 |
202 |
Trace("sets-model") << "Cardinality of " << eqc << " is " << v |
1011 |
101 |
<< std::endl; |
1012 |
101 |
if (v.getConst<Rational>() > UINT32_MAX) |
1013 |
|
{ |
1014 |
|
std::stringstream ss; |
1015 |
|
ss << "The model for " << eqc << " was computed to have cardinality " |
1016 |
|
<< v << ". We only allow sets up to cardinality " << UINT32_MAX; |
1017 |
|
throw LogicException(ss.str()); |
1018 |
|
} |
1019 |
101 |
std::uint32_t vu = v.getConst<Rational>().getNumerator().toUnsignedInt(); |
1020 |
101 |
Assert(els.size() <= vu); |
1021 |
101 |
NodeManager* nm = NodeManager::currentNM(); |
1022 |
101 |
SkolemManager* sm = nm->getSkolemManager(); |
1023 |
101 |
if (elementTypeFinite) |
1024 |
|
{ |
1025 |
|
// get all members of this finite type |
1026 |
20 |
collectFiniteTypeSetElements(model); |
1027 |
|
} |
1028 |
259 |
while (els.size() < vu) |
1029 |
|
{ |
1030 |
79 |
if (elementTypeFinite) |
1031 |
|
{ |
1032 |
|
// At this point we are sure the formula is satisfiable and all |
1033 |
|
// cardinality constraints are satisfied. Since this type is finite, |
1034 |
|
// there is only one single cardinality graph for all sets of this |
1035 |
|
// type because the universe cardinality constraint has been added by |
1036 |
|
// CardinalityExtension::checkCardinalityExtended. This means we have |
1037 |
|
// enough slack elements of this finite type for all disjoint leaves |
1038 |
|
// in the cardinality graph. Therefore we can safely add new distinct |
1039 |
|
// slack elements for the leaves without worrying about conflicts with |
1040 |
|
// the current members of this finite type. |
1041 |
|
|
1042 |
86 |
Node slack = sm->mkDummySkolem("slack", elementType); |
1043 |
86 |
Node singleton = nm->mkSingleton(elementType, slack); |
1044 |
43 |
els.push_back(singleton); |
1045 |
43 |
d_finite_type_slack_elements[elementType].push_back(slack); |
1046 |
86 |
Trace("sets-model") << "Added slack element " << slack << " to set " |
1047 |
43 |
<< eqc << std::endl; |
1048 |
|
} |
1049 |
|
else |
1050 |
|
{ |
1051 |
36 |
els.push_back(nm->mkSingleton( |
1052 |
72 |
elementType, sm->mkDummySkolem("msde", elementType))); |
1053 |
|
} |
1054 |
|
} |
1055 |
|
} |
1056 |
|
else |
1057 |
|
{ |
1058 |
11 |
Trace("sets-model") << "No slack elements for " << eqc << std::endl; |
1059 |
|
} |
1060 |
|
} |
1061 |
|
else |
1062 |
|
{ |
1063 |
102 |
Trace("sets-model") << "Build value for " << eqc |
1064 |
102 |
<< " based on normal form, size = " << d_nf[eqc].size() |
1065 |
51 |
<< std::endl; |
1066 |
|
// it is union of venn regions |
1067 |
92 |
for (unsigned j = 0; j < d_nf[eqc].size(); j++) |
1068 |
|
{ |
1069 |
41 |
std::map<Node, Node>::const_iterator itm = mvals.find(d_nf[eqc][j]); |
1070 |
41 |
if (itm != mvals.end()) |
1071 |
|
{ |
1072 |
41 |
els.push_back(itm->second); |
1073 |
|
} |
1074 |
|
else |
1075 |
|
{ |
1076 |
|
Assert(false); |
1077 |
|
} |
1078 |
|
} |
1079 |
|
} |
1080 |
163 |
} |
1081 |
|
|
1082 |
20 |
void CardinalityExtension::collectFiniteTypeSetElements(TheoryModel* model) |
1083 |
|
{ |
1084 |
20 |
if (d_finite_type_constants_processed) |
1085 |
|
{ |
1086 |
10 |
return; |
1087 |
|
} |
1088 |
55 |
for (const Node& set : getOrderedSetsEqClasses()) |
1089 |
|
{ |
1090 |
45 |
if (!d_state.isFiniteType(set.getType())) |
1091 |
|
{ |
1092 |
|
continue; |
1093 |
|
} |
1094 |
45 |
if (!isModelValueBasic(set)) |
1095 |
|
{ |
1096 |
|
// only consider leaves in the cardinality graph |
1097 |
25 |
continue; |
1098 |
|
} |
1099 |
42 |
for (const std::pair<const Node, Node>& pair : d_state.getMembers(set)) |
1100 |
|
{ |
1101 |
44 |
Node member = pair.first; |
1102 |
44 |
Node modelRepresentative = model->getRepresentative(member); |
1103 |
22 |
std::vector<Node>& elements = d_finite_type_elements[member.getType()]; |
1104 |
66 |
if (std::find(elements.begin(), elements.end(), modelRepresentative) |
1105 |
66 |
== elements.end()) |
1106 |
|
{ |
1107 |
22 |
elements.push_back(modelRepresentative); |
1108 |
|
} |
1109 |
|
} |
1110 |
|
} |
1111 |
10 |
d_finite_type_constants_processed = true; |
1112 |
|
} |
1113 |
|
|
1114 |
8 |
const std::vector<Node>& CardinalityExtension::getFiniteTypeMembers( |
1115 |
|
TypeNode typeNode) |
1116 |
|
{ |
1117 |
8 |
return d_finite_type_elements[typeNode]; |
1118 |
|
} |
1119 |
|
|
1120 |
|
} // namespace sets |
1121 |
|
} // namespace theory |
1122 |
27735 |
} // namespace cvc5 |