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