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