GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sets/cardinality_extension.cpp Lines: 525 577 91.0 %
Date: 2021-08-16 Branches: 1229 2593 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
9853
CardinalityExtension::CardinalityExtension(SolverState& s,
39
                                           InferenceManager& im,
40
9853
                                           TermRegistry& treg)
41
    : d_state(s),
42
      d_im(im),
43
      d_treg(treg),
44
9853
      d_card_processed(s.getUserContext()),
45
19706
      d_finite_type_constants_processed(false)
46
{
47
9853
  d_true = NodeManager::currentNM()->mkConst(true);
48
9853
  d_zero = NodeManager::currentNM()->mkConst(Rational(0));
49
9853
}
50
51
20143
void CardinalityExtension::reset()
52
{
53
20143
  d_eqc_to_card_term.clear();
54
20143
  d_t_card_enabled.clear();
55
20143
  d_finite_type_elements.clear();
56
20143
  d_finite_type_slack_elements.clear();
57
20143
  d_univProxy.clear();
58
20143
}
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(
798
                  r.eqNode(emp_set), InferenceId::SETS_CARD_SPLIT_EMPTY, 1);
799
              Assert(d_im.hasSent());
800
              return;
801
            }
802
          }
803
        }
804
88
        for (const Node& o0 : only[0])
805
        {
806
124
          for (const Node& o1 : only[1])
807
          {
808
124
            bool disjoint = false;
809
248
            Trace("sets-nf-debug")
810
124
                << "Try split " << o0 << " against " << o1 << std::endl;
811
            // split them
812
322
            for (unsigned e = 0; e < 2; e++)
813
            {
814
432
              Node r1 = e == 0 ? o0 : o1;
815
432
              Node r2 = e == 0 ? o1 : o0;
816
              // check if their intersection exists modulo equality
817
432
              Node r1r2i = d_state.getBinaryOpTerm(INTERSECTION, r1, r2);
818
234
              if (!r1r2i.isNull())
819
              {
820
72
                Trace("sets-nf-debug")
821
                    << "Split term already exists, but not in cardinality "
822
36
                       "graph : "
823
36
                    << r1r2i << ", should be empty." << std::endl;
824
                // their intersection is empty (probably?)
825
                // e.g. these are two disjoint venn regions, proceed to next
826
                // pair
827
36
                Assert(d_state.areEqual(emp_set, r1r2i));
828
36
                disjoint = true;
829
36
                break;
830
              }
831
            }
832
124
            if (!disjoint)
833
            {
834
              // simply introduce their intersection
835
88
              Assert(o0 != o1);
836
176
              Node kca = d_treg.getProxy(o0);
837
176
              Node kcb = d_treg.getProxy(o1);
838
              Node intro =
839
176
                  Rewriter::rewrite(nm->mkNode(INTERSECTION, kca, kcb));
840
176
              Trace("sets-nf") << "   Intro split : " << o0 << " against " << o1
841
88
                               << ", term is " << intro << std::endl;
842
88
              intro_sets.push_back(intro);
843
88
              Assert(!d_state.hasTerm(intro));
844
88
              return;
845
            }
846
          }
847
        }
848
        // should never get here
849
        success = false;
850
      }
851
    }
852
200
    if (success)
853
    {
854
      // normal form is flat form of base
855
200
      nfeqc.insert(nfeqc.end(), ffeqc[base].begin(), ffeqc[base].end());
856
200
      Trace("sets-nf") << "----> N " << eqc << " => F " << base << std::endl;
857
    }
858
    else
859
    {
860
      Trace("sets-nf") << "failed to build N " << eqc << std::endl;
861
    }
862
  }
863
  else
864
  {
865
    // must ensure disequal from empty
866
5603
    if (!eqc.isConst() && !d_state.areDisequal(eqc, emp_set)
867
4688
        && !d_state.hasMembers(eqc))
868
    {
869
387
      Trace("sets-nf-debug") << "Split on leaf " << eqc << std::endl;
870
387
      d_im.split(eqc.eqNode(emp_set), InferenceId::SETS_CARD_SPLIT_EMPTY);
871
387
      success = false;
872
    }
873
    else
874
    {
875
      // normal form is this equivalence class
876
1494
      nfeqc.push_back(eqc);
877
2988
      Trace("sets-nf") << "----> N " << eqc << " => { " << eqc << " }"
878
1494
                       << std::endl;
879
    }
880
  }
881
2081
  if (!success)
882
  {
883
387
    Assert(d_im.hasSent());
884
387
    return;
885
  }
886
  // Send to parents (a parent is a set that contains a term in this equivalence
887
  // class as a direct child).
888
1694
  const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc);
889
1694
  if (nvsets.empty())
890
  {
891
    // no non-variable sets
892
526
    return;
893
  }
894
2336
  std::map<Node, std::map<Node, bool> > parents_proc;
895
2739
  for (const Node& n : nvsets)
896
  {
897
1571
    Trace("sets-nf-debug") << "Carry nf for term " << n << std::endl;
898
1571
    if (d_cardParent[n].empty())
899
    {
900
      // nothing to do
901
409
      continue;
902
    }
903
1162
    Assert(d_localBase.find(n) != d_localBase.end());
904
2324
    Node cbase = d_localBase[n];
905
1162
    Trace("sets-nf-debug") << "Card base is " << cbase << std::endl;
906
2426
    for (const std::pair<Node, Node>& cp : d_cardParent[n])
907
    {
908
2528
      Node p = cp.first;
909
1264
      Trace("sets-nf-debug") << "Check parent " << p << std::endl;
910
1264
      if (parents_proc[cbase].find(p) != parents_proc[cbase].end())
911
      {
912
        Trace("sets-nf-debug") << "..already processed parent " << p << " for "
913
                               << cbase << std::endl;
914
        continue;
915
      }
916
1264
      parents_proc[cbase][p] = true;
917
2528
      Trace("sets-nf-debug") << "Carry nf to parent ( " << cbase << ", [" << p
918
1264
                             << "] ), from " << n << "..." << std::endl;
919
920
1264
      std::vector<Node>& ffpc = d_ff[p][cbase];
921
2709
      for (const Node& nfeqci : nfeqc)
922
      {
923
1445
        if (std::find(ffpc.begin(), ffpc.end(), nfeqci) == ffpc.end())
924
        {
925
1264
          ffpc.insert(ffpc.end(), nfeqc.begin(), nfeqc.end());
926
        }
927
        else
928
        {
929
          // if it is a duplicate venn region, it must be empty since it is
930
          // coming from syntactically disjoint siblings
931
        }
932
      }
933
    }
934
  }
935
}
936
937
1486
void CardinalityExtension::checkMinCard()
938
{
939
1486
  NodeManager* nm = NodeManager::currentNM();
940
1486
  const std::vector<Node>& setEqc = d_state.getSetsEqClasses();
941
16607
  for (int i = (int)(setEqc.size() - 1); i >= 0; i--)
942
  {
943
23400
    Node eqc = setEqc[i];
944
23400
    TypeNode tn = eqc.getType().getSetElementType();
945
15121
    if (d_t_card_enabled.find(tn) == d_t_card_enabled.end())
946
    {
947
      // cardinality is not enabled for this type, skip
948
126
      continue;
949
    }
950
    // get members in class
951
14995
    const std::map<Node, Node>& pmemsE = d_state.getMembers(eqc);
952
14995
    if (pmemsE.empty())
953
    {
954
      // no members, trivial
955
6716
      continue;
956
    }
957
16558
    std::vector<Node> exp;
958
16558
    std::vector<Node> members;
959
16558
    Node cardTerm;
960
8279
    std::map<Node, Node>::iterator it = d_eqc_to_card_term.find(eqc);
961
8279
    if (it != d_eqc_to_card_term.end())
962
    {
963
8277
      cardTerm = it->second;
964
    }
965
    else
966
    {
967
2
      cardTerm = nm->mkNode(CARD, eqc);
968
    }
969
21738
    for (const std::pair<const Node, Node>& itmm : pmemsE)
970
    {
971
13459
      members.push_back(itmm.first);
972
13459
      exp.push_back(nm->mkNode(MEMBER, itmm.first, cardTerm[0]));
973
    }
974
8279
    if (members.size() > 1)
975
    {
976
3066
      exp.push_back(nm->mkNode(DISTINCT, members));
977
    }
978
8279
    if (!members.empty())
979
    {
980
      Node conc =
981
16558
          nm->mkNode(GEQ, cardTerm, nm->mkConst(Rational(members.size())));
982
16558
      Node expn = exp.size() == 1 ? exp[0] : nm->mkNode(AND, exp);
983
8279
      d_im.assertInference(conc, InferenceId::SETS_CARD_MINIMAL, expn, 1);
984
    }
985
  }
986
  // flush the lemmas
987
1486
  d_im.doPendingLemmas();
988
1486
}
989
990
395
bool CardinalityExtension::isModelValueBasic(Node eqc)
991
{
992
395
  return d_nf[eqc].size() == 1 && d_nf[eqc][0] == eqc;
993
}
994
995
175
void CardinalityExtension::mkModelValueElementsFor(
996
    Valuation& val,
997
    Node eqc,
998
    std::vector<Node>& els,
999
    const std::map<Node, Node>& mvals,
1000
    TheoryModel* model)
1001
{
1002
350
  TypeNode elementType = eqc.getType().getSetElementType();
1003
175
  bool elementTypeFinite = d_state.isFiniteType(elementType);
1004
175
  if (isModelValueBasic(eqc))
1005
  {
1006
117
    std::map<Node, Node>::iterator it = d_eqc_to_card_term.find(eqc);
1007
117
    if (it != d_eqc_to_card_term.end())
1008
    {
1009
      // slack elements from cardinality value
1010
212
      Node v = val.getModelValue(it->second);
1011
212
      Trace("sets-model") << "Cardinality of " << eqc << " is " << v
1012
106
                          << std::endl;
1013
106
      if (v.getConst<Rational>() > UINT32_MAX)
1014
      {
1015
        std::stringstream ss;
1016
        ss << "The model for " << eqc << " was computed to have cardinality "
1017
           << v << ". We only allow sets up to cardinality " << UINT32_MAX;
1018
        throw LogicException(ss.str());
1019
      }
1020
106
      std::uint32_t vu = v.getConst<Rational>().getNumerator().toUnsignedInt();
1021
106
      Assert(els.size() <= vu);
1022
106
      NodeManager* nm = NodeManager::currentNM();
1023
106
      SkolemManager* sm = nm->getSkolemManager();
1024
106
      if (elementTypeFinite)
1025
      {
1026
        // get all members of this finite type
1027
20
        collectFiniteTypeSetElements(model);
1028
      }
1029
266
      while (els.size() < vu)
1030
      {
1031
80
        if (elementTypeFinite)
1032
        {
1033
          // At this point we are sure the formula is satisfiable and all
1034
          // cardinality constraints are satisfied. Since this type is finite,
1035
          // there is only one single cardinality graph for all sets of this
1036
          // type because the universe cardinality constraint has been added by
1037
          // CardinalityExtension::checkCardinalityExtended. This means we have
1038
          // enough slack elements of this finite type for all disjoint leaves
1039
          // in the cardinality graph. Therefore we can safely add new distinct
1040
          // slack elements for the leaves without worrying about conflicts with
1041
          // the current members of this finite type.
1042
1043
90
          Node slack = sm->mkDummySkolem("slack", elementType);
1044
90
          Node singleton = nm->mkSingleton(elementType, slack);
1045
45
          els.push_back(singleton);
1046
45
          d_finite_type_slack_elements[elementType].push_back(slack);
1047
90
          Trace("sets-model") << "Added slack element " << slack << " to set "
1048
45
                              << eqc << std::endl;
1049
        }
1050
        else
1051
        {
1052
35
          els.push_back(nm->mkSingleton(
1053
70
              elementType, sm->mkDummySkolem("msde", elementType)));
1054
        }
1055
      }
1056
    }
1057
    else
1058
    {
1059
11
      Trace("sets-model") << "No slack elements for " << eqc << std::endl;
1060
    }
1061
  }
1062
  else
1063
  {
1064
116
    Trace("sets-model") << "Build value for " << eqc
1065
116
                        << " based on normal form, size = " << d_nf[eqc].size()
1066
58
                        << std::endl;
1067
    // it is union of venn regions
1068
101
    for (unsigned j = 0; j < d_nf[eqc].size(); j++)
1069
    {
1070
43
      std::map<Node, Node>::const_iterator itm = mvals.find(d_nf[eqc][j]);
1071
43
      if (itm != mvals.end())
1072
      {
1073
43
        els.push_back(itm->second);
1074
      }
1075
      else
1076
      {
1077
        Assert(false);
1078
      }
1079
    }
1080
  }
1081
175
}
1082
1083
20
void CardinalityExtension::collectFiniteTypeSetElements(TheoryModel* model)
1084
{
1085
20
  if (d_finite_type_constants_processed)
1086
  {
1087
10
    return;
1088
  }
1089
55
  for (const Node& set : getOrderedSetsEqClasses())
1090
  {
1091
45
    if (!d_state.isFiniteType(set.getType()))
1092
    {
1093
      continue;
1094
    }
1095
45
    if (!isModelValueBasic(set))
1096
    {
1097
      // only consider leaves in the cardinality graph
1098
25
      continue;
1099
    }
1100
40
    for (const std::pair<const Node, Node>& pair : d_state.getMembers(set))
1101
    {
1102
40
      Node member = pair.first;
1103
40
      Node modelRepresentative = model->getRepresentative(member);
1104
20
      std::vector<Node>& elements = d_finite_type_elements[member.getType()];
1105
60
      if (std::find(elements.begin(), elements.end(), modelRepresentative)
1106
60
          == elements.end())
1107
      {
1108
20
        elements.push_back(modelRepresentative);
1109
      }
1110
    }
1111
  }
1112
10
  d_finite_type_constants_processed = true;
1113
}
1114
1115
10
const std::vector<Node>& CardinalityExtension::getFiniteTypeMembers(
1116
    TypeNode typeNode)
1117
{
1118
10
  return d_finite_type_elements[typeNode];
1119
}
1120
1121
}  // namespace sets
1122
}  // namespace theory
1123
29340
}  // namespace cvc5