GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sets/cardinality_extension.cpp Lines: 527 577 91.3 %
Date: 2021-11-07 Branches: 1240 2595 47.8 %

Line Exec Source
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
15273
CardinalityExtension::CardinalityExtension(Env& env,
39
                                           SolverState& s,
40
                                           InferenceManager& im,
41
15273
                                           TermRegistry& treg)
42
    : EnvObj(env),
43
      d_state(s),
44
      d_im(im),
45
      d_treg(treg),
46
15273
      d_card_processed(userContext()),
47
30546
      d_finite_type_constants_processed(false)
48
{
49
15273
  d_true = NodeManager::currentNM()->mkConst(true);
50
15273
  d_zero = NodeManager::currentNM()->mkConst(Rational(0));
51
15273
}
52
53
24101
void CardinalityExtension::reset()
54
{
55
24101
  d_eqc_to_card_term.clear();
56
24101
  d_t_card_enabled.clear();
57
24101
  d_finite_type_elements.clear();
58
24101
  d_finite_type_slack_elements.clear();
59
24101
  d_univProxy.clear();
60
24101
}
61
101292
void CardinalityExtension::registerTerm(Node n)
62
{
63
101292
  Trace("sets-card-debug") << "Register term : " << n << std::endl;
64
101292
  Assert(n.getKind() == CARD);
65
202584
  TypeNode tnc = n[0].getType().getSetElementType();
66
101292
  d_t_card_enabled[tnc] = true;
67
202584
  Node r = d_state.getRepresentative(n[0]);
68
101292
  if (d_eqc_to_card_term.find(r) == d_eqc_to_card_term.end())
69
  {
70
48440
    d_eqc_to_card_term[r] = n;
71
48440
    registerCardinalityTerm(n[0]);
72
  }
73
101292
  Trace("sets-card-debug") << "...finished register term" << std::endl;
74
101292
}
75
76
2166
void CardinalityExtension::checkCardinalityExtended()
77
{
78
4331
  for (std::pair<const TypeNode, bool>& pair : d_t_card_enabled)
79
  {
80
4332
    TypeNode type = pair.first;
81
2166
    if (pair.second)
82
    {
83
2166
      checkCardinalityExtended(type);
84
    }
85
  }
86
2165
}
87
88
2166
void CardinalityExtension::checkCardinalityExtended(TypeNode& t)
89
{
90
2166
  NodeManager* nm = NodeManager::currentNM();
91
3430
  TypeNode setType = nm->mkSetType(t);
92
2166
  bool finiteType = d_env.isFiniteType(t);
93
  // skip infinite types that do not have univset terms
94
2166
  if (!finiteType && d_state.getUnivSetEqClass(setType).isNull())
95
  {
96
902
    return;
97
  }
98
99
  // get the cardinality of the finite type t
100
2528
  Cardinality card = t.getCardinality();
101
102
  // cardinality of an interpreted finite type t is infinite when t
103
  // is infinite without --fmf
104
1264
  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
2526
  Node univ = d_treg.getUnivSet(setType);
116
1263
  std::map<Node, Node>::iterator it = d_univProxy.find(univ);
117
118
2526
  Node proxy;
119
120
1263
  if (it == d_univProxy.end())
121
  {
122
    // Force cvc5 to build the cardinality graph for the universe set
123
1263
    proxy = d_treg.getProxy(univ);
124
1263
    d_univProxy[univ] = proxy;
125
  }
126
  else
127
  {
128
    proxy = it->second;
129
  }
130
131
  // get all equivalent classes of type t
132
2526
  vector<Node> representatives = d_state.getSetsEqClasses(t);
133
134
1263
  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
16436
  for (Node& representative : representatives)
149
  {
150
    // the universe set is a subset of itself
151
15173
    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
16747
      Node variable = d_state.getVariableSet(representative);
156
13921
      if (variable.isNull())
157
      {
158
11095
        continue;
159
      }
160
161
      // (=> true (subset representative (as univset t))
162
5652
      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
2826
      subset = rewrite(subset);
166
2826
      if (!d_state.isEntailed(subset, true))
167
      {
168
128
        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
2826
          d_state.getNegativeMembers(representative);
175
176
9001
      for (const auto& negativeMember : negativeMembers)
177
      {
178
12350
        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
12350
        Node notMember = nm->mkNode(NOT, negativeMember.second);
183
        // (=>
184
        //    (not (member negativeMember representative)))
185
        //    (member negativeMember (as univset t)))
186
6175
        d_im.assertInference(
187
            member, InferenceId::SETS_CARD_NEGATIVE_MEMBER, notMember, 1);
188
      }
189
    }
190
  }
191
}
192
193
2166
void CardinalityExtension::check()
194
{
195
2166
  checkCardinalityExtended();
196
2165
  checkRegister();
197
2165
  if (d_im.hasSent())
198
  {
199
2413
    return;
200
  }
201
1802
  checkMinCard();
202
1802
  if (d_im.hasSent())
203
  {
204
550
    return;
205
  }
206
1252
  checkCardCycles();
207
1252
  if (d_im.hasSent())
208
  {
209
535
    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
832
  std::vector<Node> intro_sets;
214
717
  checkNormalForms(intro_sets);
215
717
  if (intro_sets.empty())
216
  {
217
602
    return;
218
  }
219
115
  Assert(intro_sets.size() == 1);
220
115
  Trace("sets-intro") << "Introduce term : " << intro_sets[0] << std::endl;
221
115
  Trace("sets-intro") << "  Actual Intro : ";
222
115
  d_treg.debugPrintSet(intro_sets[0], "sets-nf");
223
115
  Trace("sets-nf") << std::endl;
224
230
  Node k = d_treg.getProxy(intro_sets[0]);
225
115
  AlwaysAssert(!k.isNull());
226
}
227
228
2165
void CardinalityExtension::checkRegister()
229
{
230
2165
  Trace("sets") << "Cardinality graph..." << std::endl;
231
2165
  NodeManager* nm = NodeManager::currentNM();
232
  // first, ensure cardinality relationships are added as lemmas for all
233
  // non-basic set terms
234
2165
  const std::vector<Node>& setEqc = d_state.getSetsEqClasses();
235
26383
  for (const Node& eqc : setEqc)
236
  {
237
24218
    const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc);
238
64879
    for (Node n : nvsets)
239
    {
240
40661
      if (!d_state.isCongruent(n))
241
      {
242
        // if setminus, do for intersection instead
243
37368
        if (n.getKind() == SETMINUS)
244
        {
245
19528
          n = rewrite(nm->mkNode(INTERSECTION, n[0], n[1]));
246
        }
247
37368
        registerCardinalityTerm(n);
248
      }
249
    }
250
  }
251
2165
  Trace("sets") << "Done cardinality graph" << std::endl;
252
2165
}
253
254
85808
void CardinalityExtension::registerCardinalityTerm(Node n)
255
{
256
87783
  TypeNode tnc = n.getType().getSetElementType();
257
85808
  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
194
    return;
261
  }
262
85614
  if (d_card_processed.find(n) != d_card_processed.end())
263
  {
264
    // already processed
265
83639
    return;
266
  }
267
1975
  d_card_processed.insert(n);
268
1975
  NodeManager* nm = NodeManager::currentNM();
269
1975
  Trace("sets-card") << "Cardinality lemmas for " << n << " : " << std::endl;
270
3950
  std::vector<Node> cterms;
271
1975
  if (n.getKind() == INTERSECTION)
272
  {
273
1134
    for (unsigned e = 0; e < 2; e++)
274
    {
275
1512
      Node s = nm->mkNode(SETMINUS, n[e], n[1 - e]);
276
756
      cterms.push_back(s);
277
    }
278
756
    Node pos_lem = nm->mkNode(GEQ, nm->mkNode(CARD, n), d_zero);
279
378
    d_im.assertInference(
280
        pos_lem, InferenceId::SETS_CARD_POSITIVE, d_emp_exp, 1);
281
  }
282
  else
283
  {
284
1597
    cterms.push_back(n);
285
  }
286
4328
  for (unsigned k = 0, csize = cterms.size(); k < csize; k++)
287
  {
288
4706
    Node nn = cterms[k];
289
4706
    Node nk = d_treg.getProxy(nn);
290
4706
    Node pos_lem = nm->mkNode(GEQ, nm->mkNode(CARD, nk), d_zero);
291
2353
    d_im.assertInference(
292
        pos_lem, InferenceId::SETS_CARD_POSITIVE, d_emp_exp, 1);
293
2353
    if (nn != nk)
294
    {
295
2214
      Node lem = nm->mkNode(EQUAL, nm->mkNode(CARD, nk), nm->mkNode(CARD, nn));
296
1107
      lem = rewrite(lem);
297
1107
      Trace("sets-card") << "  " << k << " : " << lem << std::endl;
298
1107
      d_im.assertInference(lem, InferenceId::SETS_CARD_EQUAL, d_emp_exp, 1);
299
    }
300
  }
301
1975
  d_im.doPendingLemmas();
302
}
303
304
1252
void CardinalityExtension::checkCardCycles()
305
{
306
1252
  Trace("sets") << "Check cardinality cycles..." << std::endl;
307
  // build order of equivalence classes, also build cardinality graph
308
1252
  const std::vector<Node>& setEqc = d_state.getSetsEqClasses();
309
1252
  d_oSetEqc.clear();
310
1252
  d_cardParent.clear();
311
11467
  for (const Node& s : setEqc)
312
  {
313
20965
    std::vector<Node> curr;
314
20965
    std::vector<Node> exp;
315
10750
    checkCardCyclesRec(s, curr, exp);
316
10750
    if (d_im.hasSent())
317
    {
318
535
      return;
319
    }
320
  }
321
322
717
  Trace("sets") << "d_oSetEqc: " << d_oSetEqc << std::endl;
323
717
  Trace("sets") << "Done check cardinality cycles" << std::endl;
324
}
325
326
20371
void CardinalityExtension::checkCardCyclesRec(Node eqc,
327
                                              std::vector<Node>& curr,
328
                                              std::vector<Node>& exp)
329
{
330
20371
  Trace("sets-cycle-debug") << "Traverse eqc " << eqc << std::endl;
331
20371
  NodeManager* nm = NodeManager::currentNM();
332
20371
  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
11732
    return;
363
  }
364
20371
  if (std::find(d_oSetEqc.begin(), d_oSetEqc.end(), eqc) != d_oSetEqc.end())
365
  {
366
    // already processed
367
9549
    return;
368
  }
369
10822
  const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc);
370
10822
  if (nvsets.empty())
371
  {
372
    // no non-variable sets, trivial
373
1641
    d_oSetEqc.push_back(eqc);
374
1641
    return;
375
  }
376
9181
  curr.push_back(eqc);
377
17820
  TypeNode tn = eqc.getType();
378
9181
  bool is_empty = eqc == d_state.getEmptySetEqClass(tn);
379
17820
  Node emp_set = d_treg.getEmptySet(tn);
380
26947
  for (const Node& n : nvsets)
381
  {
382
18308
    Kind nk = n.getKind();
383
18308
    if (nk != INTERSECTION && nk != SETMINUS)
384
    {
385
12141
      continue;
386
    }
387
27966
    Trace("sets-debug") << "Build cardinality parents for " << n << "..."
388
13983
                        << std::endl;
389
23933
    std::vector<Node> sib;
390
13983
    unsigned true_sib = 0;
391
13983
    if (n.getKind() == INTERSECTION)
392
    {
393
5136
      d_localBase[n] = n;
394
15408
      for (unsigned e = 0; e < 2; e++)
395
      {
396
20544
        Node sm = rewrite(nm->mkNode(SETMINUS, n[e], n[1 - e]));
397
10272
        sib.push_back(sm);
398
      }
399
5136
      true_sib = 2;
400
    }
401
    else
402
    {
403
17694
      Node si = rewrite(nm->mkNode(INTERSECTION, n[0], n[1]));
404
8847
      sib.push_back(si);
405
8847
      d_localBase[n] = si;
406
17694
      Node osm = rewrite(nm->mkNode(SETMINUS, n[1], n[0]));
407
8847
      sib.push_back(osm);
408
8847
      true_sib = 1;
409
    }
410
23933
    Node u = rewrite(nm->mkNode(UNION, n[0], n[1]));
411
13983
    if (!d_state.hasTerm(u))
412
    {
413
8611
      u = Node::null();
414
    }
415
13983
    unsigned n_parents = true_sib + (u.isNull() ? 0 : 1);
416
    // if this set is empty
417
13983
    if (is_empty)
418
    {
419
3753
      Assert(d_state.areEqual(n, emp_set));
420
3753
      Trace("sets-debug") << "  empty, parents equal siblings" << std::endl;
421
3753
      std::vector<Node> conc;
422
      // parent equal siblings
423
8326
      for (unsigned e = 0; e < true_sib; e++)
424
      {
425
4573
        if (d_state.hasTerm(sib[e]) && !d_state.areEqual(n[e], sib[e]))
426
        {
427
321
          conc.push_back(n[e].eqNode(sib[e]));
428
        }
429
      }
430
3753
      d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_EMP, n.eqNode(emp_set));
431
3753
      d_im.doPendingLemmas();
432
3753
      if (d_im.hasSent())
433
      {
434
262
        return;
435
      }
436
3491
      continue;
437
    }
438
20180
    std::vector<Node> card_parents;
439
20180
    std::vector<int> card_parent_ids;
440
    // check if equal to a parent
441
28307
    for (unsigned e = 0; e < n_parents; e++)
442
    {
443
36440
      Trace("sets-debug") << "  check parent " << e << "/" << n_parents
444
18220
                          << std::endl;
445
18220
      bool is_union = e == true_sib;
446
36297
      Node p = (e == true_sib) ? u : n[e];
447
36440
      Trace("sets-debug") << "  check relation to parent " << p
448
18220
                          << ", isu=" << is_union << "..." << std::endl;
449
      // if parent is empty
450
18220
      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
18218
      else if (d_state.areEqual(p, n))
464
      {
465
5275
        Trace("sets-debug") << "  it is equal to this..." << std::endl;
466
10409
        std::vector<Node> conc;
467
10409
        std::vector<int> sib_emp_indices;
468
5275
        if (is_union)
469
        {
470
708
          for (unsigned s = 0; s < sib.size(); s++)
471
          {
472
472
            sib_emp_indices.push_back(s);
473
          }
474
        }
475
        else
476
        {
477
5039
          sib_emp_indices.push_back(e);
478
        }
479
        // sibling(s) are empty
480
10786
        for (unsigned si : sib_emp_indices)
481
        {
482
5511
          if (!d_state.areEqual(sib[si], emp_set))
483
          {
484
126
            conc.push_back(sib[si].eqNode(emp_set));
485
          }
486
          else
487
          {
488
10770
            Trace("sets-debug")
489
5385
                << "Sibling " << sib[si] << " is already empty." << std::endl;
490
          }
491
        }
492
5275
        if (!is_union && nk == INTERSECTION && !u.isNull())
493
        {
494
          // union is equal to other parent
495
2058
          if (!d_state.areEqual(u, n[1 - e]))
496
          {
497
15
            conc.push_back(u.eqNode(n[1 - e]));
498
          }
499
        }
500
10550
        Trace("sets-debug")
501
5275
            << "...derived " << conc.size() << " conclusions" << std::endl;
502
5275
        d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_EQ_PARENT, n.eqNode(p));
503
5275
        d_im.doPendingLemmas();
504
5275
        if (d_im.hasSent())
505
        {
506
141
          return;
507
        }
508
      }
509
      else
510
      {
511
12943
        Trace("sets-cdg") << "Card graph : " << n << " -> " << p << std::endl;
512
        // otherwise, we a syntactic subset of p
513
12943
        card_parents.push_back(p);
514
12943
        card_parent_ids.push_back(is_union ? 2 : e);
515
      }
516
    }
517
10087
    Assert(d_cardParent[n].empty());
518
10087
    Trace("sets-debug") << "get parent representatives..." << std::endl;
519
    // for each parent, take their representatives
520
22877
    for (unsigned k = 0, numcp = card_parents.size(); k < numcp; k++)
521
    {
522
25710
      Node cpk = card_parents[k];
523
25710
      Node eqcc = d_state.getRepresentative(cpk);
524
25840
      Trace("sets-debug") << "Check card parent " << k << "/"
525
12920
                          << card_parents.size() << std::endl;
526
527
      // if parent is singleton, then we should either be empty to equal to it
528
25710
      Node eqccSingleton = d_state.getSingletonEqClass(eqcc);
529
12920
      if (!eqccSingleton.isNull())
530
      {
531
8
        bool eq_parent = false;
532
16
        std::vector<Node> exps;
533
8
        d_state.addEqualityToExp(cpk, eqccSingleton, exps);
534
8
        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
8
          const std::map<Node, Node>& pmemsE = d_state.getMembers(eqc);
542
8
          if (!pmemsE.empty())
543
          {
544
12
            Node pmem = pmemsE.begin()->second;
545
6
            exps.push_back(pmem);
546
6
            d_state.addEqualityToExp(n, pmem[1], exps);
547
6
            eq_parent = true;
548
          }
549
        }
550
        // must be equal to parent
551
8
        if (eq_parent)
552
        {
553
12
          Node conc = n.eqNode(cpk);
554
6
          d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_PARENT_SINGLETON, exps);
555
6
          d_im.doPendingLemmas();
556
        }
557
        else
558
        {
559
          // split on empty
560
2
          Trace("sets-nf") << "Split empty : " << n << std::endl;
561
2
          d_im.split(n.eqNode(emp_set), InferenceId::SETS_CARD_SPLIT_EMPTY, 1);
562
        }
563
8
        Assert(d_im.hasSent());
564
8
        return;
565
      }
566
      else
567
      {
568
12912
        bool dup = false;
569
17884
        for (unsigned l = 0, numcpn = d_cardParent[n].size(); l < numcpn; l++)
570
        {
571
6621
          Node cpnl = d_cardParent[n][l].first;
572
5094
          if (eqcc != cpnl)
573
          {
574
2060
            continue;
575
          }
576
6068
          Trace("sets-debug") << "  parents " << l << " and " << k
577
3034
                              << " are equal, ids = " << card_parent_ids[l]
578
3034
                              << " " << card_parent_ids[k] << std::endl;
579
3034
          dup = true;
580
3034
          if (n.getKind() != INTERSECTION)
581
          {
582
1385
            continue;
583
          }
584
1649
          Assert(card_parent_ids[l] != 2);
585
3176
          std::vector<Node> conc;
586
1649
          if (card_parent_ids[k] == 2)
587
          {
588
            // intersection is equal to other parent
589
1649
            unsigned pid = 1 - card_parent_ids[l];
590
1649
            if (!d_state.areEqual(n[pid], n))
591
            {
592
244
              Trace("sets-debug")
593
122
                  << "  one of them is union, make equal to other..."
594
122
                  << std::endl;
595
122
              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
3176
          Node cpnlb = d_cardParent[n][l].second;
613
3298
          d_im.assertInference(conc,
614
                               InferenceId::SETS_CARD_GRAPH_EQ_PARENT_2,
615
3298
                               cpk.eqNode(cpnlb));
616
1649
          d_im.doPendingLemmas();
617
1649
          if (d_im.hasSent())
618
          {
619
122
            return;
620
          }
621
        }
622
12790
        if (!dup)
623
        {
624
9878
          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
9957
    exp.push_back(eqc.eqNode(n));
631
19571
    for (const std::pair<Node, Node>& cpnc : d_cardParent[n])
632
    {
633
19242
      Trace("sets-cycle-debug") << "Traverse card parent " << eqc << " -> "
634
9621
                                << cpnc.first << std::endl;
635
9621
      checkCardCyclesRec(cpnc.first, curr, exp);
636
9621
      if (d_im.hasSent())
637
      {
638
7
        return;
639
      }
640
    }
641
9950
    exp.pop_back();
642
  }
643
8639
  curr.pop_back();
644
  // parents now processed, can add to ordered list
645
8639
  d_oSetEqc.push_back(eqc);
646
}
647
648
717
void CardinalityExtension::checkNormalForms(std::vector<Node>& intro_sets)
649
{
650
717
  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
717
  d_ff.clear();
655
717
  d_nf.clear();
656
3241
  for (int i = (int)(d_oSetEqc.size() - 1); i >= 0; i--)
657
  {
658
3099
    checkNormalForm(d_oSetEqc[i], intro_sets);
659
3099
    if (d_im.hasSent() || !intro_sets.empty())
660
    {
661
575
      return;
662
    }
663
  }
664
142
  Trace("sets") << "Done check normal forms" << std::endl;
665
}
666
667
3099
void CardinalityExtension::checkNormalForm(Node eqc,
668
                                           std::vector<Node>& intro_sets)
669
{
670
4634
  TypeNode tn = eqc.getType();
671
3099
  Trace("sets") << "Compute normal form for " << eqc << std::endl;
672
3099
  Trace("sets-nf") << "Compute N " << eqc << "..." << std::endl;
673
3099
  if (eqc == d_state.getEmptySetEqClass(tn))
674
  {
675
463
    d_nf[eqc].clear();
676
463
    Trace("sets-nf") << "----> N " << eqc << " => {}" << std::endl;
677
463
    return;
678
  }
679
  // flat/normal forms are sets of equivalence classes
680
4171
  Node base;
681
4171
  std::vector<Node> comps;
682
  std::map<Node, std::map<Node, std::vector<Node> > >::iterator it =
683
2636
      d_ff.find(eqc);
684
2636
  if (it != d_ff.end())
685
  {
686
871
    for (std::pair<const Node, std::vector<Node> >& itf : it->second)
687
    {
688
519
      std::sort(itf.second.begin(), itf.second.end());
689
519
      if (base.isNull())
690
      {
691
352
        base = itf.first;
692
      }
693
      else
694
      {
695
167
        comps.push_back(itf.first);
696
      }
697
1038
      Trace("sets-nf") << "  F " << itf.first << " : " << itf.second
698
519
                       << std::endl;
699
519
      Trace("sets-nf-debug") << " ...";
700
519
      d_treg.debugPrintSet(itf.first, "sets-nf-debug");
701
519
      Trace("sets-nf-debug") << std::endl;
702
    }
703
  }
704
  else
705
  {
706
2284
    Trace("sets-nf") << "(no flat forms)" << std::endl;
707
  }
708
2636
  std::map<Node, std::vector<Node> >& ffeqc = d_ff[eqc];
709
2636
  Assert(d_nf.find(eqc) == d_nf.end());
710
2636
  std::vector<Node>& nfeqc = d_nf[eqc];
711
2636
  NodeManager* nm = NodeManager::currentNM();
712
2636
  bool success = true;
713
4171
  Node emp_set = d_treg.getEmptySet(tn);
714
2636
  if (!base.isNull())
715
  {
716
394
    for (unsigned j = 0, csize = comps.size(); j < csize; j++)
717
    {
718
      // compare if equal
719
199
      std::vector<Node> c;
720
157
      c.push_back(base);
721
157
      c.push_back(comps[j]);
722
471
      std::vector<Node> only[2];
723
199
      std::vector<Node> common;
724
314
      Trace("sets-nf-debug") << "Compare venn regions of " << base << " vs "
725
157
                             << comps[j] << std::endl;
726
157
      unsigned k[2] = {0, 0};
727
1379
      while (k[0] < ffeqc[c[0]].size() || k[1] < ffeqc[c[1]].size())
728
      {
729
611
        bool proc = true;
730
1833
        for (unsigned e = 0; e < 2; e++)
731
        {
732
1222
          if (k[e] == ffeqc[c[e]].size())
733
          {
734
419
            for (; k[1 - e] < ffeqc[c[1 - e]].size(); ++k[1 - e])
735
            {
736
122
              only[1 - e].push_back(ffeqc[c[1 - e]][k[1 - e]]);
737
            }
738
175
            proc = false;
739
          }
740
        }
741
611
        if (proc)
742
        {
743
497
          if (ffeqc[c[0]][k[0]] == ffeqc[c[1]][k[1]])
744
          {
745
205
            common.push_back(ffeqc[c[0]][k[0]]);
746
205
            k[0]++;
747
205
            k[1]++;
748
          }
749
292
          else if (ffeqc[c[0]][k[0]] < ffeqc[c[1]][k[1]])
750
          {
751
154
            only[0].push_back(ffeqc[c[0]][k[0]]);
752
154
            k[0]++;
753
          }
754
          else
755
          {
756
138
            only[1].push_back(ffeqc[c[1]][k[1]]);
757
138
            k[1]++;
758
          }
759
        }
760
      }
761
157
      if (!only[0].empty() || !only[1].empty())
762
      {
763
115
        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
460
        for (unsigned e = 0; e < 3; e++)
782
        {
783
345
          unsigned sz = e == 2 ? common.size() : only[e].size();
784
852
          for (unsigned l = 0; l < sz; l++)
785
          {
786
1014
            Node r = e == 2 ? common[l] : only[e][l];
787
507
            Trace("sets-nf-debug") << "Try split empty : " << r << std::endl;
788
507
            Trace("sets-nf-debug") << "         actual : ";
789
507
            d_treg.debugPrintSet(r, "sets-nf-debug");
790
507
            Trace("sets-nf-debug") << std::endl;
791
507
            Assert(!d_state.areEqual(r, emp_set));
792
507
            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
115
        for (const Node& o0 : only[0])
807
        {
808
160
          for (const Node& o1 : only[1])
809
          {
810
160
            bool disjoint = false;
811
320
            Trace("sets-nf-debug")
812
160
                << "Try split " << o0 << " against " << o1 << std::endl;
813
            // split them
814
420
            for (unsigned e = 0; e < 2; e++)
815
            {
816
565
              Node r1 = e == 0 ? o0 : o1;
817
565
              Node r2 = e == 0 ? o1 : o0;
818
              // check if their intersection exists modulo equality
819
565
              Node r1r2i = d_state.getBinaryOpTerm(INTERSECTION, r1, r2);
820
305
              if (!r1r2i.isNull())
821
              {
822
90
                Trace("sets-nf-debug")
823
                    << "Split term already exists, but not in cardinality "
824
45
                       "graph : "
825
45
                    << 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
45
                Assert(d_state.areEqual(emp_set, r1r2i));
830
45
                disjoint = true;
831
45
                break;
832
              }
833
            }
834
160
            if (!disjoint)
835
            {
836
              // simply introduce their intersection
837
115
              Assert(o0 != o1);
838
230
              Node kca = d_treg.getProxy(o0);
839
230
              Node kcb = d_treg.getProxy(o1);
840
230
              Node intro = rewrite(nm->mkNode(INTERSECTION, kca, kcb));
841
230
              Trace("sets-nf") << "   Intro split : " << o0 << " against " << o1
842
115
                               << ", term is " << intro << std::endl;
843
115
              intro_sets.push_back(intro);
844
115
              Assert(!d_state.hasTerm(intro));
845
115
              return;
846
            }
847
          }
848
        }
849
        // should never get here
850
        success = false;
851
      }
852
    }
853
237
    if (success)
854
    {
855
      // normal form is flat form of base
856
237
      nfeqc.insert(nfeqc.end(), ffeqc[base].begin(), ffeqc[base].end());
857
237
      Trace("sets-nf") << "----> N " << eqc << " => F " << base << std::endl;
858
    }
859
    else
860
    {
861
      Trace("sets-nf") << "failed to build N " << eqc << std::endl;
862
    }
863
  }
864
  else
865
  {
866
    // must ensure disequal from empty
867
6802
    if (!eqc.isConst() && !d_state.areDisequal(eqc, emp_set)
868
5678
        && !d_state.hasMembers(eqc))
869
    {
870
460
      Trace("sets-nf-debug") << "Split on leaf " << eqc << std::endl;
871
460
      d_im.split(eqc.eqNode(emp_set), InferenceId::SETS_CARD_SPLIT_EMPTY);
872
460
      success = false;
873
    }
874
    else
875
    {
876
      // normal form is this equivalence class
877
1824
      nfeqc.push_back(eqc);
878
3648
      Trace("sets-nf") << "----> N " << eqc << " => { " << eqc << " }"
879
1824
                       << std::endl;
880
    }
881
  }
882
2521
  if (!success)
883
  {
884
460
    Assert(d_im.hasSent());
885
460
    return;
886
  }
887
  // Send to parents (a parent is a set that contains a term in this equivalence
888
  // class as a direct child).
889
2061
  const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc);
890
2061
  if (nvsets.empty())
891
  {
892
    // no non-variable sets
893
526
    return;
894
  }
895
3070
  std::map<Node, std::map<Node, bool> > parents_proc;
896
3845
  for (const Node& n : nvsets)
897
  {
898
2310
    Trace("sets-nf-debug") << "Carry nf for term " << n << std::endl;
899
2310
    if (d_cardParent[n].empty())
900
    {
901
      // nothing to do
902
612
      continue;
903
    }
904
1698
    Assert(d_localBase.find(n) != d_localBase.end());
905
3396
    Node cbase = d_localBase[n];
906
1698
    Trace("sets-nf-debug") << "Card base is " << cbase << std::endl;
907
3594
    for (const std::pair<Node, Node>& cp : d_cardParent[n])
908
    {
909
3792
      Node p = cp.first;
910
1896
      Trace("sets-nf-debug") << "Check parent " << p << std::endl;
911
1896
      if (parents_proc[cbase].find(p) != parents_proc[cbase].end())
912
      {
913
        Trace("sets-nf-debug") << "..already processed parent " << p << " for "
914
                               << cbase << std::endl;
915
        continue;
916
      }
917
1896
      parents_proc[cbase][p] = true;
918
3792
      Trace("sets-nf-debug") << "Carry nf to parent ( " << cbase << ", [" << p
919
1896
                             << "] ), from " << n << "..." << std::endl;
920
921
1896
      std::vector<Node>& ffpc = d_ff[p][cbase];
922
4038
      for (const Node& nfeqci : nfeqc)
923
      {
924
2142
        if (std::find(ffpc.begin(), ffpc.end(), nfeqci) == ffpc.end())
925
        {
926
1896
          ffpc.insert(ffpc.end(), nfeqc.begin(), nfeqc.end());
927
        }
928
        else
929
        {
930
          // if it is a duplicate venn region, it must be empty since it is
931
          // coming from syntactically disjoint siblings
932
        }
933
      }
934
    }
935
  }
936
}
937
938
1802
void CardinalityExtension::checkMinCard()
939
{
940
1802
  NodeManager* nm = NodeManager::currentNM();
941
1802
  const std::vector<Node>& setEqc = d_state.getSetsEqClasses();
942
22858
  for (int i = (int)(setEqc.size() - 1); i >= 0; i--)
943
  {
944
34264
    Node eqc = setEqc[i];
945
34264
    TypeNode tn = eqc.getType().getSetElementType();
946
21056
    if (d_t_card_enabled.find(tn) == d_t_card_enabled.end())
947
    {
948
      // cardinality is not enabled for this type, skip
949
150
      continue;
950
    }
951
    // get members in class
952
20906
    const std::map<Node, Node>& pmemsE = d_state.getMembers(eqc);
953
20906
    if (pmemsE.empty())
954
    {
955
      // no members, trivial
956
7698
      continue;
957
    }
958
26416
    std::vector<Node> exp;
959
26416
    std::vector<Node> members;
960
26416
    Node cardTerm;
961
13208
    std::map<Node, Node>::iterator it = d_eqc_to_card_term.find(eqc);
962
13208
    if (it != d_eqc_to_card_term.end())
963
    {
964
13206
      cardTerm = it->second;
965
    }
966
    else
967
    {
968
2
      cardTerm = nm->mkNode(CARD, eqc);
969
    }
970
39506
    for (const std::pair<const Node, Node>& itmm : pmemsE)
971
    {
972
26298
      members.push_back(itmm.first);
973
26298
      exp.push_back(nm->mkNode(MEMBER, itmm.first, cardTerm[0]));
974
    }
975
13208
    if (members.size() > 1)
976
    {
977
5984
      exp.push_back(nm->mkNode(DISTINCT, members));
978
    }
979
13208
    if (!members.empty())
980
    {
981
      Node conc =
982
26416
          nm->mkNode(GEQ, cardTerm, nm->mkConst(Rational(members.size())));
983
26416
      Node expn = exp.size() == 1 ? exp[0] : nm->mkNode(AND, exp);
984
13208
      d_im.assertInference(conc, InferenceId::SETS_CARD_MINIMAL, expn, 1);
985
    }
986
  }
987
  // flush the lemmas
988
1802
  d_im.doPendingLemmas();
989
1802
}
990
991
427
bool CardinalityExtension::isModelValueBasic(Node eqc)
992
{
993
427
  return d_nf[eqc].size() == 1 && d_nf[eqc][0] == eqc;
994
}
995
996
191
void CardinalityExtension::mkModelValueElementsFor(
997
    Valuation& val,
998
    Node eqc,
999
    std::vector<Node>& els,
1000
    const std::map<Node, Node>& mvals,
1001
    TheoryModel* model)
1002
{
1003
382
  TypeNode elementType = eqc.getType().getSetElementType();
1004
191
  bool elementTypeFinite = d_env.isFiniteType(elementType);
1005
191
  if (isModelValueBasic(eqc))
1006
  {
1007
123
    std::map<Node, Node>::iterator it = d_eqc_to_card_term.find(eqc);
1008
123
    if (it != d_eqc_to_card_term.end())
1009
    {
1010
      // slack elements from cardinality value
1011
224
      Node v = val.getModelValue(it->second);
1012
224
      Trace("sets-model") << "Cardinality of " << eqc << " is " << v
1013
112
                          << std::endl;
1014
112
      if (v.getConst<Rational>() > UINT32_MAX)
1015
      {
1016
        std::stringstream ss;
1017
        ss << "The model for " << eqc << " was computed to have cardinality "
1018
           << v << ". We only allow sets up to cardinality " << UINT32_MAX;
1019
        throw LogicException(ss.str());
1020
      }
1021
112
      std::uint32_t vu = v.getConst<Rational>().getNumerator().toUnsignedInt();
1022
112
      Assert(els.size() <= vu);
1023
112
      NodeManager* nm = NodeManager::currentNM();
1024
112
      SkolemManager* sm = nm->getSkolemManager();
1025
112
      if (elementTypeFinite)
1026
      {
1027
        // get all members of this finite type
1028
20
        collectFiniteTypeSetElements(model);
1029
      }
1030
272
      while (els.size() < vu)
1031
      {
1032
80
        if (elementTypeFinite)
1033
        {
1034
          // At this point we are sure the formula is satisfiable and all
1035
          // cardinality constraints are satisfied. Since this type is finite,
1036
          // there is only one single cardinality graph for all sets of this
1037
          // type because the universe cardinality constraint has been added by
1038
          // CardinalityExtension::checkCardinalityExtended. This means we have
1039
          // enough slack elements of this finite type for all disjoint leaves
1040
          // in the cardinality graph. Therefore we can safely add new distinct
1041
          // slack elements for the leaves without worrying about conflicts with
1042
          // the current members of this finite type.
1043
1044
90
          Node slack = sm->mkDummySkolem("slack", elementType);
1045
90
          Node singleton = nm->mkSingleton(elementType, slack);
1046
45
          els.push_back(singleton);
1047
45
          d_finite_type_slack_elements[elementType].push_back(slack);
1048
90
          Trace("sets-model") << "Added slack element " << slack << " to set "
1049
45
                              << eqc << std::endl;
1050
        }
1051
        else
1052
        {
1053
35
          els.push_back(nm->mkSingleton(
1054
70
              elementType, sm->mkDummySkolem("msde", elementType)));
1055
        }
1056
      }
1057
    }
1058
    else
1059
    {
1060
11
      Trace("sets-model") << "No slack elements for " << eqc << std::endl;
1061
    }
1062
  }
1063
  else
1064
  {
1065
136
    Trace("sets-model") << "Build value for " << eqc
1066
136
                        << " based on normal form, size = " << d_nf[eqc].size()
1067
68
                        << std::endl;
1068
    // it is union of venn regions
1069
113
    for (unsigned j = 0; j < d_nf[eqc].size(); j++)
1070
    {
1071
45
      std::map<Node, Node>::const_iterator itm = mvals.find(d_nf[eqc][j]);
1072
45
      if (itm != mvals.end())
1073
      {
1074
45
        els.push_back(itm->second);
1075
      }
1076
      else
1077
      {
1078
        Assert(false);
1079
      }
1080
    }
1081
  }
1082
191
}
1083
1084
20
void CardinalityExtension::collectFiniteTypeSetElements(TheoryModel* model)
1085
{
1086
20
  if (d_finite_type_constants_processed)
1087
  {
1088
10
    return;
1089
  }
1090
55
  for (const Node& set : getOrderedSetsEqClasses())
1091
  {
1092
45
    if (!d_env.isFiniteType(set.getType()))
1093
    {
1094
      continue;
1095
    }
1096
45
    if (!isModelValueBasic(set))
1097
    {
1098
      // only consider leaves in the cardinality graph
1099
25
      continue;
1100
    }
1101
40
    for (const std::pair<const Node, Node>& pair : d_state.getMembers(set))
1102
    {
1103
40
      Node member = pair.first;
1104
40
      Node modelRepresentative = model->getRepresentative(member);
1105
20
      std::vector<Node>& elements = d_finite_type_elements[member.getType()];
1106
60
      if (std::find(elements.begin(), elements.end(), modelRepresentative)
1107
60
          == elements.end())
1108
      {
1109
20
        elements.push_back(modelRepresentative);
1110
      }
1111
    }
1112
  }
1113
10
  d_finite_type_constants_processed = true;
1114
}
1115
1116
10
const std::vector<Node>& CardinalityExtension::getFiniteTypeMembers(
1117
    TypeNode typeNode)
1118
{
1119
10
  return d_finite_type_elements[typeNode];
1120
}
1121
1122
}  // namespace sets
1123
}  // namespace theory
1124
31137
}  // namespace cvc5