GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sets/cardinality_extension.cpp Lines: 525 577 91.0 %
Date: 2021-09-17 Branches: 1230 2595 47.4 %

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
9942
CardinalityExtension::CardinalityExtension(Env& env,
39
                                           SolverState& s,
40
                                           InferenceManager& im,
41
9942
                                           TermRegistry& treg)
42
    : EnvObj(env),
43
      d_state(s),
44
      d_im(im),
45
      d_treg(treg),
46
9942
      d_card_processed(userContext()),
47
19884
      d_finite_type_constants_processed(false)
48
{
49
9942
  d_true = NodeManager::currentNM()->mkConst(true);
50
9942
  d_zero = NodeManager::currentNM()->mkConst(Rational(0));
51
9942
}
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
29577
}  // namespace cvc5