GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sets/cardinality_extension.cpp Lines: 525 576 91.1 %
Date: 2021-05-22 Branches: 1234 2603 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
29
using namespace std;
30
using namespace cvc5::kind;
31
32
namespace cvc5 {
33
namespace theory {
34
namespace sets {
35
36
9460
CardinalityExtension::CardinalityExtension(SolverState& s,
37
                                           InferenceManager& im,
38
9460
                                           TermRegistry& treg)
39
    : d_state(s),
40
      d_im(im),
41
      d_treg(treg),
42
9460
      d_card_processed(s.getUserContext()),
43
18920
      d_finite_type_constants_processed(false)
44
{
45
9460
  d_true = NodeManager::currentNM()->mkConst(true);
46
9460
  d_zero = NodeManager::currentNM()->mkConst(Rational(0));
47
9460
}
48
49
16920
void CardinalityExtension::reset()
50
{
51
16920
  d_eqc_to_card_term.clear();
52
16920
  d_t_card_enabled.clear();
53
16920
  d_finite_type_elements.clear();
54
16920
  d_finite_type_slack_elements.clear();
55
16920
  d_univProxy.clear();
56
16920
}
57
50125
void CardinalityExtension::registerTerm(Node n)
58
{
59
50125
  Trace("sets-card-debug") << "Register term : " << n << std::endl;
60
50125
  Assert(n.getKind() == CARD);
61
100250
  TypeNode tnc = n[0].getType().getSetElementType();
62
50125
  d_t_card_enabled[tnc] = true;
63
100250
  Node r = d_state.getRepresentative(n[0]);
64
50125
  if (d_eqc_to_card_term.find(r) == d_eqc_to_card_term.end())
65
  {
66
31260
    d_eqc_to_card_term[r] = n;
67
31260
    registerCardinalityTerm(n[0]);
68
  }
69
50125
  Trace("sets-card-debug") << "...finished register term" << std::endl;
70
50125
}
71
72
1694
void CardinalityExtension::checkCardinalityExtended()
73
{
74
3387
  for (std::pair<const TypeNode, bool>& pair : d_t_card_enabled)
75
  {
76
3388
    TypeNode type = pair.first;
77
1694
    if (pair.second)
78
    {
79
1694
      checkCardinalityExtended(type);
80
    }
81
  }
82
1693
}
83
84
1694
void CardinalityExtension::checkCardinalityExtended(TypeNode& t)
85
{
86
1694
  NodeManager* nm = NodeManager::currentNM();
87
2665
  TypeNode setType = nm->mkSetType(t);
88
1694
  bool finiteType = d_state.isFiniteType(t);
89
  // skip infinite types that do not have univset terms
90
1694
  if (!finiteType && d_state.getUnivSetEqClass(setType).isNull())
91
  {
92
723
    return;
93
  }
94
95
  // get the cardinality of the finite type t
96
1942
  Cardinality card = t.getCardinality();
97
98
  // cardinality of an interpreted finite type t is infinite when t
99
  // is infinite without --fmf
100
971
  if (finiteType && card.isInfinite())
101
  {
102
    // TODO (#1123): support uninterpreted sorts with --finite-model-find
103
2
    std::stringstream message;
104
1
    message << "The cardinality " << card << " of the finite type " << t
105
1
            << " is not supported yet.";
106
1
    throw LogicException(message.str());
107
  }
108
109
  // here we call getUnivSet instead of getUnivSetEqClass to generate
110
  // a univset term for finite types even if they are not used in the input
111
1940
  Node univ = d_treg.getUnivSet(setType);
112
970
  std::map<Node, Node>::iterator it = d_univProxy.find(univ);
113
114
1940
  Node proxy;
115
116
970
  if (it == d_univProxy.end())
117
  {
118
    // Force cvc5 to build the cardinality graph for the universe set
119
970
    proxy = d_treg.getProxy(univ);
120
970
    d_univProxy[univ] = proxy;
121
  }
122
  else
123
  {
124
    proxy = it->second;
125
  }
126
127
  // get all equivalent classes of type t
128
1940
  vector<Node> representatives = d_state.getSetsEqClasses(t);
129
130
970
  if (finiteType)
131
  {
132
1476
    Node typeCardinality = nm->mkConst(Rational(card.getFiniteCardinality()));
133
1476
    Node cardUniv = nm->mkNode(kind::CARD, proxy);
134
1476
    Node leq = nm->mkNode(kind::LEQ, cardUniv, typeCardinality);
135
136
    // (=> true (<= (card (as univset t)) cardUniv)
137
738
    if (!d_state.isEntailed(leq, true))
138
    {
139
738
      d_im.assertInference(leq, InferenceId::SETS_CARD_UNIV_TYPE, d_true, 1);
140
    }
141
  }
142
143
  // add subset lemmas for sets and membership lemmas for negative members
144
9725
  for (Node& representative : representatives)
145
  {
146
    // the universe set is a subset of itself
147
8755
    if (representative != d_state.getRepresentative(univ))
148
    {
149
      // here we only add representatives with variables to avoid adding
150
      // infinite equivalent generated terms to the cardinality graph
151
9744
      Node variable = d_state.getVariableSet(representative);
152
7796
      if (variable.isNull())
153
      {
154
5848
        continue;
155
      }
156
157
      // (=> true (subset representative (as univset t))
158
3896
      Node subset = nm->mkNode(kind::SUBSET, variable, proxy);
159
      // subset terms are rewritten as union terms: (subset A B) implies (=
160
      // (union A B) B)
161
1948
      subset = Rewriter::rewrite(subset);
162
1948
      if (!d_state.isEntailed(subset, true))
163
      {
164
124
        d_im.assertInference(
165
            subset, InferenceId::SETS_CARD_UNIV_SUPERSET, d_true, 1);
166
      }
167
168
      // negative members are members in the universe set
169
      const std::map<Node, Node>& negativeMembers =
170
1948
          d_state.getNegativeMembers(representative);
171
172
4185
      for (const auto& negativeMember : negativeMembers)
173
      {
174
4474
        Node member = nm->mkNode(MEMBER, negativeMember.first, univ);
175
        // negativeMember.second is the reason for the negative membership and
176
        // has kind MEMBER. So we specify the negation as the reason for the
177
        // negative membership lemma
178
4474
        Node notMember = nm->mkNode(NOT, negativeMember.second);
179
        // (=>
180
        //    (not (member negativeMember representative)))
181
        //    (member negativeMember (as univset t)))
182
2237
        d_im.assertInference(
183
            member, InferenceId::SETS_CARD_NEGATIVE_MEMBER, notMember, 1);
184
      }
185
    }
186
  }
187
}
188
189
1694
void CardinalityExtension::check()
190
{
191
1694
  checkCardinalityExtended();
192
1693
  checkRegister();
193
1693
  if (d_im.hasSent())
194
  {
195
1905
    return;
196
  }
197
1393
  checkMinCard();
198
1393
  if (d_im.hasSent())
199
  {
200
415
    return;
201
  }
202
978
  checkCardCycles();
203
978
  if (d_im.hasSent())
204
  {
205
411
    return;
206
  }
207
  // The last step will either do nothing (in which case we are SAT), or request
208
  // that a new set term is introduced.
209
655
  std::vector<Node> intro_sets;
210
567
  checkNormalForms(intro_sets);
211
567
  if (intro_sets.empty())
212
  {
213
479
    return;
214
  }
215
88
  Assert(intro_sets.size() == 1);
216
88
  Trace("sets-intro") << "Introduce term : " << intro_sets[0] << std::endl;
217
88
  Trace("sets-intro") << "  Actual Intro : ";
218
88
  d_treg.debugPrintSet(intro_sets[0], "sets-nf");
219
88
  Trace("sets-nf") << std::endl;
220
176
  Node k = d_treg.getProxy(intro_sets[0]);
221
88
  AlwaysAssert(!k.isNull());
222
}
223
224
1693
void CardinalityExtension::checkRegister()
225
{
226
1693
  Trace("sets") << "Cardinality graph..." << std::endl;
227
1693
  NodeManager* nm = NodeManager::currentNM();
228
  // first, ensure cardinality relationships are added as lemmas for all
229
  // non-basic set terms
230
1693
  const std::vector<Node>& setEqc = d_state.getSetsEqClasses();
231
18737
  for (const Node& eqc : setEqc)
232
  {
233
17044
    const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc);
234
38187
    for (Node n : nvsets)
235
    {
236
21143
      if (!d_state.isCongruent(n))
237
      {
238
        // if setminus, do for intersection instead
239
20775
        if (n.getKind() == SETMINUS)
240
        {
241
10365
          n = Rewriter::rewrite(nm->mkNode(INTERSECTION, n[0], n[1]));
242
        }
243
20775
        registerCardinalityTerm(n);
244
      }
245
    }
246
  }
247
1693
  Trace("sets") << "Done cardinality graph" << std::endl;
248
1693
}
249
250
52035
void CardinalityExtension::registerCardinalityTerm(Node n)
251
{
252
53745
  TypeNode tnc = n.getType().getSetElementType();
253
52035
  if (d_t_card_enabled.find(tnc) == d_t_card_enabled.end())
254
  {
255
    // if no cardinality constraints for sets of this type, we can ignore
256
150
    return;
257
  }
258
51885
  if (d_card_processed.find(n) != d_card_processed.end())
259
  {
260
    // already processed
261
50175
    return;
262
  }
263
1710
  d_card_processed.insert(n);
264
1710
  NodeManager* nm = NodeManager::currentNM();
265
1710
  Trace("sets-card") << "Cardinality lemmas for " << n << " : " << std::endl;
266
3420
  std::vector<Node> cterms;
267
1710
  if (n.getKind() == INTERSECTION)
268
  {
269
990
    for (unsigned e = 0; e < 2; e++)
270
    {
271
1320
      Node s = nm->mkNode(SETMINUS, n[e], n[1 - e]);
272
660
      cterms.push_back(s);
273
    }
274
660
    Node pos_lem = nm->mkNode(GEQ, nm->mkNode(CARD, n), d_zero);
275
330
    d_im.assertInference(
276
        pos_lem, InferenceId::SETS_CARD_POSITIVE, d_emp_exp, 1);
277
  }
278
  else
279
  {
280
1380
    cterms.push_back(n);
281
  }
282
3750
  for (unsigned k = 0, csize = cterms.size(); k < csize; k++)
283
  {
284
4080
    Node nn = cterms[k];
285
4080
    Node nk = d_treg.getProxy(nn);
286
4080
    Node pos_lem = nm->mkNode(GEQ, nm->mkNode(CARD, nk), d_zero);
287
2040
    d_im.assertInference(
288
        pos_lem, InferenceId::SETS_CARD_POSITIVE, d_emp_exp, 1);
289
2040
    if (nn != nk)
290
    {
291
1924
      Node lem = nm->mkNode(EQUAL, nm->mkNode(CARD, nk), nm->mkNode(CARD, nn));
292
962
      lem = Rewriter::rewrite(lem);
293
962
      Trace("sets-card") << "  " << k << " : " << lem << std::endl;
294
962
      d_im.assertInference(lem, InferenceId::SETS_CARD_EQUAL, d_emp_exp, 1);
295
    }
296
  }
297
1710
  d_im.doPendingLemmas();
298
}
299
300
978
void CardinalityExtension::checkCardCycles()
301
{
302
978
  Trace("sets") << "Check cardinality cycles..." << std::endl;
303
  // build order of equivalence classes, also build cardinality graph
304
978
  const std::vector<Node>& setEqc = d_state.getSetsEqClasses();
305
978
  d_oSetEqc.clear();
306
978
  d_card_parent.clear();
307
8377
  for (const Node& s : setEqc)
308
  {
309
15209
    std::vector<Node> curr;
310
15209
    std::vector<Node> exp;
311
7810
    checkCardCyclesRec(s, curr, exp);
312
7810
    if (d_im.hasSent())
313
    {
314
411
      return;
315
    }
316
  }
317
318
567
  Trace("sets") << "d_card_parent: " << d_card_parent << std::endl;
319
567
  Trace("sets") << "d_oSetEqc: " << d_oSetEqc << std::endl;
320
567
  Trace("sets") << "Done check cardinality cycles" << std::endl;
321
}
322
323
13435
void CardinalityExtension::checkCardCyclesRec(Node eqc,
324
                                              std::vector<Node>& curr,
325
                                              std::vector<Node>& exp)
326
{
327
13435
  Trace("sets-cycle-debug") << "Traverse eqc " << eqc << std::endl;
328
13435
  NodeManager* nm = NodeManager::currentNM();
329
13435
  if (std::find(curr.begin(), curr.end(), eqc) != curr.end())
330
  {
331
    Trace("sets-debug") << "Found venn region loop..." << std::endl;
332
    if (curr.size() > 1)
333
    {
334
      // all regions must be equal
335
      std::vector<Node> conc;
336
      bool foundLoopStart = false;
337
      for (const Node& cc : curr)
338
      {
339
        if (cc == eqc)
340
        {
341
          foundLoopStart = true;
342
        }
343
        else if (foundLoopStart && eqc != cc)
344
        {
345
          conc.push_back(eqc.eqNode(cc));
346
        }
347
      }
348
      Node fact = conc.size() == 1 ? conc[0] : nm->mkNode(AND, conc);
349
      Trace("sets-cycle-debug")
350
          << "CYCLE: " << fact << " from " << exp << std::endl;
351
      d_im.assertInference(fact, InferenceId::SETS_CARD_CYCLE, exp);
352
      d_im.doPendingLemmas();
353
    }
354
    else
355
    {
356
      // should be guaranteed based on not exploring equal parents
357
      Assert(false);
358
    }
359
7607
    return;
360
  }
361
13435
  if (std::find(d_oSetEqc.begin(), d_oSetEqc.end(), eqc) != d_oSetEqc.end())
362
  {
363
    // already processed
364
5598
    return;
365
  }
366
7837
  const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc);
367
7837
  if (nvsets.empty())
368
  {
369
    // no non-variable sets, trivial
370
1591
    d_oSetEqc.push_back(eqc);
371
1591
    return;
372
  }
373
6246
  curr.push_back(eqc);
374
12074
  TypeNode tn = eqc.getType();
375
6246
  bool is_empty = eqc == d_state.getEmptySetEqClass(tn);
376
12074
  Node emp_set = d_treg.getEmptySet(tn);
377
16114
  for (const Node& n : nvsets)
378
  {
379
10286
    Kind nk = n.getKind();
380
10286
    if (nk != INTERSECTION && nk != SETMINUS)
381
    {
382
7304
      continue;
383
    }
384
14772
    Trace("sets-debug") << "Build cardinality parents for " << n << "..."
385
7386
                        << std::endl;
386
12850
    std::vector<Node> sib;
387
7386
    unsigned true_sib = 0;
388
7386
    if (n.getKind() == INTERSECTION)
389
    {
390
2790
      d_localBase[n] = n;
391
8370
      for (unsigned e = 0; e < 2; e++)
392
      {
393
11160
        Node sm = Rewriter::rewrite(nm->mkNode(SETMINUS, n[e], n[1 - e]));
394
5580
        sib.push_back(sm);
395
      }
396
2790
      true_sib = 2;
397
    }
398
    else
399
    {
400
9192
      Node si = Rewriter::rewrite(nm->mkNode(INTERSECTION, n[0], n[1]));
401
4596
      sib.push_back(si);
402
4596
      d_localBase[n] = si;
403
9192
      Node osm = Rewriter::rewrite(nm->mkNode(SETMINUS, n[1], n[0]));
404
4596
      sib.push_back(osm);
405
4596
      true_sib = 1;
406
    }
407
12850
    Node u = Rewriter::rewrite(nm->mkNode(UNION, n[0], n[1]));
408
7386
    if (!d_state.hasTerm(u))
409
    {
410
4560
      u = Node::null();
411
    }
412
7386
    unsigned n_parents = true_sib + (u.isNull() ? 0 : 1);
413
    // if this set is empty
414
7386
    if (is_empty)
415
    {
416
1689
      Assert(d_state.areEqual(n, emp_set));
417
1689
      Trace("sets-debug") << "  empty, parents equal siblings" << std::endl;
418
1689
      std::vector<Node> conc;
419
      // parent equal siblings
420
3735
      for (unsigned e = 0; e < true_sib; e++)
421
      {
422
2046
        if (d_state.hasTerm(sib[e]) && !d_state.areEqual(n[e], sib[e]))
423
        {
424
234
          conc.push_back(n[e].eqNode(sib[e]));
425
        }
426
      }
427
1689
      d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_EMP, n.eqNode(emp_set));
428
1689
      d_im.doPendingLemmas();
429
1689
      if (d_im.hasSent())
430
      {
431
185
        return;
432
      }
433
      else
434
      {
435
        // justify why there is no edge to parents (necessary?)
436
4006
        for (unsigned e = 0; e < n_parents; e++)
437
        {
438
2502
          Node p = (e == true_sib) ? u : n[e];
439
        }
440
      }
441
1504
      continue;
442
    }
443
11161
    std::vector<Node> card_parents;
444
11161
    std::vector<int> card_parent_ids;
445
    // check if equal to a parent
446
15589
    for (unsigned e = 0; e < n_parents; e++)
447
    {
448
20016
      Trace("sets-debug") << "  check parent " << e << "/" << n_parents
449
10008
                          << std::endl;
450
10008
      bool is_union = e == true_sib;
451
19900
      Node p = (e == true_sib) ? u : n[e];
452
20016
      Trace("sets-debug") << "  check relation to parent " << p
453
10008
                          << ", isu=" << is_union << "..." << std::endl;
454
      // if parent is empty
455
10008
      if (d_state.areEqual(p, emp_set))
456
      {
457
2
        Trace("sets-debug") << "  it is empty..." << std::endl;
458
2
        Assert(!d_state.areEqual(n, emp_set));
459
4
        d_im.assertInference(
460
4
            n.eqNode(emp_set), InferenceId::SETS_CARD_GRAPH_EMP_PARENT, p.eqNode(emp_set));
461
2
        d_im.doPendingLemmas();
462
2
        if (d_im.hasSent())
463
        {
464
2
          return;
465
        }
466
        // if we are equal to a parent
467
      }
468
10006
      else if (d_state.areEqual(p, n))
469
      {
470
2361
        Trace("sets-debug") << "  it is equal to this..." << std::endl;
471
4608
        std::vector<Node> conc;
472
4608
        std::vector<int> sib_emp_indices;
473
2361
        if (is_union)
474
        {
475
126
          for (unsigned s = 0; s < sib.size(); s++)
476
          {
477
84
            sib_emp_indices.push_back(s);
478
          }
479
        }
480
        else
481
        {
482
2319
          sib_emp_indices.push_back(e);
483
        }
484
        // sibling(s) are empty
485
4764
        for (unsigned si : sib_emp_indices)
486
        {
487
2403
          if (!d_state.areEqual(sib[si], emp_set))
488
          {
489
110
            conc.push_back(sib[si].eqNode(emp_set));
490
          }
491
          else
492
          {
493
4586
            Trace("sets-debug")
494
2293
                << "Sibling " << sib[si] << " is already empty." << std::endl;
495
          }
496
        }
497
2361
        if (!is_union && nk == INTERSECTION && !u.isNull())
498
        {
499
          // union is equal to other parent
500
1084
          if (!d_state.areEqual(u, n[1 - e]))
501
          {
502
4
            conc.push_back(u.eqNode(n[1 - e]));
503
          }
504
        }
505
4722
        Trace("sets-debug")
506
2361
            << "...derived " << conc.size() << " conclusions" << std::endl;
507
2361
        d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_EQ_PARENT, n.eqNode(p));
508
2361
        d_im.doPendingLemmas();
509
2361
        if (d_im.hasSent())
510
        {
511
114
          return;
512
        }
513
      }
514
      else
515
      {
516
7645
        Trace("sets-cdg") << "Card graph : " << n << " -> " << p << std::endl;
517
        // otherwise, we a syntactic subset of p
518
7645
        card_parents.push_back(p);
519
7645
        card_parent_ids.push_back(is_union ? 2 : e);
520
      }
521
    }
522
5581
    Assert(d_card_parent[n].empty());
523
5581
    Trace("sets-debug") << "get parent representatives..." << std::endl;
524
    // for each parent, take their representatives
525
13110
    for (unsigned k = 0, numcp = card_parents.size(); k < numcp; k++)
526
    {
527
15168
      Node cpk = card_parents[k];
528
15168
      Node eqcc = d_state.getRepresentative(cpk);
529
15278
      Trace("sets-debug") << "Check card parent " << k << "/"
530
7639
                          << card_parents.size() << std::endl;
531
532
      // if parent is singleton, then we should either be empty to equal to it
533
15168
      Node eqccSingleton = d_state.getSingletonEqClass(eqcc);
534
7639
      if (!eqccSingleton.isNull())
535
      {
536
4
        bool eq_parent = false;
537
8
        std::vector<Node> exps;
538
4
        d_state.addEqualityToExp(cpk, eqccSingleton, exps);
539
4
        if (d_state.areDisequal(n, emp_set))
540
        {
541
          exps.push_back(n.eqNode(emp_set).negate());
542
          eq_parent = true;
543
        }
544
        else
545
        {
546
4
          const std::map<Node, Node>& pmemsE = d_state.getMembers(eqc);
547
4
          if (!pmemsE.empty())
548
          {
549
8
            Node pmem = pmemsE.begin()->second;
550
4
            exps.push_back(pmem);
551
4
            d_state.addEqualityToExp(n, pmem[1], exps);
552
4
            eq_parent = true;
553
          }
554
        }
555
        // must be equal to parent
556
4
        if (eq_parent)
557
        {
558
8
          Node conc = n.eqNode(cpk);
559
4
          d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_PARENT_SINGLETON, exps);
560
4
          d_im.doPendingLemmas();
561
        }
562
        else
563
        {
564
          // split on empty
565
          Trace("sets-nf") << "Split empty : " << n << std::endl;
566
          d_im.split(n.eqNode(emp_set), InferenceId::SETS_CARD_SPLIT_EMPTY, 1);
567
        }
568
4
        Assert(d_im.hasSent());
569
4
        return;
570
      }
571
      else
572
      {
573
7635
        bool dup = false;
574
10513
        for (unsigned l = 0, numcpn = d_card_parent[n].size(); l < numcpn; l++)
575
        {
576
3878
          Node cpnl = d_card_parent[n][l];
577
2984
          if (eqcc != cpnl)
578
          {
579
1190
            continue;
580
          }
581
3588
          Trace("sets-debug") << "  parents " << l << " and " << k
582
1794
                              << " are equal, ids = " << card_parent_ids[l]
583
1794
                              << " " << card_parent_ids[k] << std::endl;
584
1794
          dup = true;
585
1794
          if (n.getKind() != INTERSECTION)
586
          {
587
794
            continue;
588
          }
589
1000
          Assert(card_parent_ids[l] != 2);
590
1894
          std::vector<Node> conc;
591
1000
          if (card_parent_ids[k] == 2)
592
          {
593
            // intersection is equal to other parent
594
1000
            unsigned pid = 1 - card_parent_ids[l];
595
1000
            if (!d_state.areEqual(n[pid], n))
596
            {
597
212
              Trace("sets-debug")
598
106
                  << "  one of them is union, make equal to other..."
599
106
                  << std::endl;
600
106
              conc.push_back(n[pid].eqNode(n));
601
            }
602
          }
603
          else
604
          {
605
            if (!d_state.areEqual(cpk, n))
606
            {
607
              Trace("sets-debug")
608
                  << "  neither is union, make equal to one parent..."
609
                  << std::endl;
610
              // intersection is equal to one of the parents
611
              conc.push_back(cpk.eqNode(n));
612
            }
613
          }
614
1000
          d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_EQ_PARENT_2, cpk.eqNode(cpnl));
615
1000
          d_im.doPendingLemmas();
616
1000
          if (d_im.hasSent())
617
          {
618
106
            return;
619
          }
620
        }
621
7529
        if (!dup)
622
        {
623
5841
          d_card_parent[n].push_back(eqcc);
624
        }
625
      }
626
    }
627
    // now recurse on parents (to ensure their normal will be computed after
628
    // this eqc)
629
5471
    exp.push_back(eqc.eqNode(n));
630
11089
    for (const Node& cpnc : d_card_parent[n])
631
    {
632
11250
      Trace("sets-cycle-debug")
633
5625
          << "Traverse card parent " << eqc << " -> " << cpnc << std::endl;
634
5625
      checkCardCyclesRec(cpnc, curr, exp);
635
5625
      if (d_im.hasSent())
636
      {
637
7
        return;
638
      }
639
    }
640
5464
    exp.pop_back();
641
  }
642
5828
  curr.pop_back();
643
  // parents now processed, can add to ordered list
644
5828
  d_oSetEqc.push_back(eqc);
645
}
646
647
567
void CardinalityExtension::checkNormalForms(std::vector<Node>& intro_sets)
648
{
649
567
  Trace("sets") << "Check normal forms..." << std::endl;
650
  // now, build normal form for each equivalence class
651
  // d_oSetEqc is now sorted such that for each d_oSetEqc[i], d_oSetEqc[j],
652
  // if d_oSetEqc[i] is a strict syntactic subterm of d_oSetEqc[j], then i<j.
653
567
  d_ff.clear();
654
567
  d_nf.clear();
655
2567
  for (int i = (int)(d_oSetEqc.size() - 1); i >= 0; i--)
656
  {
657
2451
    checkNormalForm(d_oSetEqc[i], intro_sets);
658
2451
    if (d_im.hasSent() || !intro_sets.empty())
659
    {
660
451
      return;
661
    }
662
  }
663
116
  Trace("sets") << "Done check normal forms" << std::endl;
664
}
665
666
2451
void CardinalityExtension::checkNormalForm(Node eqc,
667
                                           std::vector<Node>& intro_sets)
668
{
669
3564
  TypeNode tn = eqc.getType();
670
2451
  Trace("sets") << "Compute normal form for " << eqc << std::endl;
671
2451
  Trace("sets-nf") << "Compute N " << eqc << "..." << std::endl;
672
2451
  if (eqc == d_state.getEmptySetEqClass(tn))
673
  {
674
361
    d_nf[eqc].clear();
675
361
    Trace("sets-nf") << "----> N " << eqc << " => {}" << std::endl;
676
361
    return;
677
  }
678
  // flat/normal forms are sets of equivalence classes
679
3203
  Node base;
680
3203
  std::vector<Node> comps;
681
  std::map<Node, std::map<Node, std::vector<Node> > >::iterator it =
682
2090
      d_ff.find(eqc);
683
2090
  if (it != d_ff.end())
684
  {
685
652
    for (std::pair<const Node, std::vector<Node> >& itf : it->second)
686
    {
687
380
      std::sort(itf.second.begin(), itf.second.end());
688
380
      if (base.isNull())
689
      {
690
272
        base = itf.first;
691
      }
692
      else
693
      {
694
108
        comps.push_back(itf.first);
695
      }
696
760
      Trace("sets-nf") << "  F " << itf.first << " : " << itf.second
697
380
                       << std::endl;
698
380
      Trace("sets-nf-debug") << " ...";
699
380
      d_treg.debugPrintSet(itf.first, "sets-nf-debug");
700
380
      Trace("sets-nf-debug") << std::endl;
701
    }
702
  }
703
  else
704
  {
705
1818
    Trace("sets-nf") << "(no flat forms)" << std::endl;
706
  }
707
2090
  std::map<Node, std::vector<Node> >& ffeqc = d_ff[eqc];
708
2090
  Assert(d_nf.find(eqc) == d_nf.end());
709
2090
  std::vector<Node>& nfeqc = d_nf[eqc];
710
2090
  NodeManager* nm = NodeManager::currentNM();
711
2090
  bool success = true;
712
3203
  Node emp_set = d_treg.getEmptySet(tn);
713
2090
  if (!base.isNull())
714
  {
715
292
    for (unsigned j = 0, csize = comps.size(); j < csize; j++)
716
    {
717
      // compare if equal
718
128
      std::vector<Node> c;
719
108
      c.push_back(base);
720
108
      c.push_back(comps[j]);
721
324
      std::vector<Node> only[2];
722
128
      std::vector<Node> common;
723
216
      Trace("sets-nf-debug") << "Compare venn regions of " << base << " vs "
724
108
                             << comps[j] << std::endl;
725
108
      unsigned k[2] = {0, 0};
726
1020
      while (k[0] < ffeqc[c[0]].size() || k[1] < ffeqc[c[1]].size())
727
      {
728
456
        bool proc = true;
729
1368
        for (unsigned e = 0; e < 2; e++)
730
        {
731
912
          if (k[e] == ffeqc[c[e]].size())
732
          {
733
310
            for (; k[1 - e] < ffeqc[c[1 - e]].size(); ++k[1 - e])
734
            {
735
90
              only[1 - e].push_back(ffeqc[c[1 - e]][k[1 - e]]);
736
            }
737
130
            proc = false;
738
          }
739
        }
740
456
        if (proc)
741
        {
742
368
          if (ffeqc[c[0]][k[0]] == ffeqc[c[1]][k[1]])
743
          {
744
138
            common.push_back(ffeqc[c[0]][k[0]]);
745
138
            k[0]++;
746
138
            k[1]++;
747
          }
748
230
          else if (ffeqc[c[0]][k[0]] < ffeqc[c[1]][k[1]])
749
          {
750
113
            only[0].push_back(ffeqc[c[0]][k[0]]);
751
113
            k[0]++;
752
          }
753
          else
754
          {
755
117
            only[1].push_back(ffeqc[c[1]][k[1]]);
756
117
            k[1]++;
757
          }
758
        }
759
      }
760
108
      if (!only[0].empty() || !only[1].empty())
761
      {
762
88
        if (Trace.isOn("sets-nf-debug"))
763
        {
764
          Trace("sets-nf-debug") << "Unique venn regions : " << std::endl;
765
          for (unsigned e = 0; e < 2; e++)
766
          {
767
            Trace("sets-nf-debug") << "  " << c[e] << " : { ";
768
            for (unsigned l = 0; l < only[e].size(); l++)
769
            {
770
              if (l > 0)
771
              {
772
                Trace("sets-nf-debug") << ", ";
773
              }
774
              Trace("sets-nf-debug") << "[" << only[e][l] << "]";
775
            }
776
            Trace("sets-nf-debug") << " }" << std::endl;
777
          }
778
        }
779
        // try to make one empty, prefer the unique ones first
780
352
        for (unsigned e = 0; e < 3; e++)
781
        {
782
264
          unsigned sz = e == 2 ? common.size() : only[e].size();
783
664
          for (unsigned l = 0; l < sz; l++)
784
          {
785
800
            Node r = e == 2 ? common[l] : only[e][l];
786
400
            Trace("sets-nf-debug") << "Try split empty : " << r << std::endl;
787
400
            Trace("sets-nf-debug") << "         actual : ";
788
400
            d_treg.debugPrintSet(r, "sets-nf-debug");
789
400
            Trace("sets-nf-debug") << std::endl;
790
400
            Assert(!d_state.areEqual(r, emp_set));
791
400
            if (!d_state.areDisequal(r, emp_set) && !d_state.hasMembers(r))
792
            {
793
              // guess that its equal empty if it has no explicit members
794
              Trace("sets-nf") << " Split empty : " << r << std::endl;
795
              Trace("sets-nf") << "Actual Split : ";
796
              d_treg.debugPrintSet(r, "sets-nf");
797
              Trace("sets-nf") << std::endl;
798
              d_im.split(r.eqNode(emp_set), InferenceId::UNKNOWN, 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
184
    if (success)
853
    {
854
      // normal form is flat form of base
855
184
      nfeqc.insert(nfeqc.end(), ffeqc[base].begin(), ffeqc[base].end());
856
184
      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
5414
    if (!eqc.isConst() && !d_state.areDisequal(eqc, emp_set)
867
4511
        && !d_state.hasMembers(eqc))
868
    {
869
363
      Trace("sets-nf-debug") << "Split on leaf " << eqc << std::endl;
870
363
      d_im.split(eqc.eqNode(emp_set), InferenceId::UNKNOWN);
871
363
      success = false;
872
    }
873
    else
874
    {
875
      // normal form is this equivalence class
876
1455
      nfeqc.push_back(eqc);
877
2910
      Trace("sets-nf") << "----> N " << eqc << " => { " << eqc << " }"
878
1455
                       << std::endl;
879
    }
880
  }
881
2002
  if (!success)
882
  {
883
363
    Assert(d_im.hasSent());
884
363
    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
1639
  const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc);
889
1639
  if (nvsets.empty())
890
  {
891
    // no non-variable sets
892
526
    return;
893
  }
894
2226
  std::map<Node, std::map<Node, bool> > parents_proc;
895
2597
  for (const Node& n : nvsets)
896
  {
897
1484
    Trace("sets-nf-debug") << "Carry nf for term " << n << std::endl;
898
1484
    if (d_card_parent[n].empty())
899
    {
900
      // nothing to do
901
373
      continue;
902
    }
903
1111
    Assert(d_localBase.find(n) != d_localBase.end());
904
2222
    Node cbase = d_localBase[n];
905
1111
    Trace("sets-nf-debug") << "Card base is " << cbase << std::endl;
906
2322
    for (const Node& p : d_card_parent[n])
907
    {
908
1211
      Trace("sets-nf-debug") << "Check parent " << p << std::endl;
909
1211
      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
1211
      parents_proc[cbase][p] = true;
916
2422
      Trace("sets-nf-debug") << "Carry nf to parent ( " << cbase << ", [" << p
917
1211
                             << "] ), from " << n << "..." << std::endl;
918
919
1211
      std::vector<Node>& ffpc = d_ff[p][cbase];
920
2595
      for (const Node& nfeqci : nfeqc)
921
      {
922
1384
        if (std::find(ffpc.begin(), ffpc.end(), nfeqci) == ffpc.end())
923
        {
924
1211
          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
1393
void CardinalityExtension::checkMinCard()
937
{
938
1393
  NodeManager* nm = NodeManager::currentNM();
939
1393
  const std::vector<Node>& setEqc = d_state.getSetsEqClasses();
940
16025
  for (int i = (int)(setEqc.size() - 1); i >= 0; i--)
941
  {
942
22710
    Node eqc = setEqc[i];
943
22710
    TypeNode tn = eqc.getType().getSetElementType();
944
14632
    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
14506
    const std::map<Node, Node>& pmemsE = d_state.getMembers(eqc);
951
14506
    if (pmemsE.empty())
952
    {
953
      // no members, trivial
954
6428
      continue;
955
    }
956
16156
    std::vector<Node> exp;
957
16156
    std::vector<Node> members;
958
16156
    Node cardTerm;
959
8078
    std::map<Node, Node>::iterator it = d_eqc_to_card_term.find(eqc);
960
8078
    if (it != d_eqc_to_card_term.end())
961
    {
962
8076
      cardTerm = it->second;
963
    }
964
    else
965
    {
966
2
      cardTerm = nm->mkNode(CARD, eqc);
967
    }
968
21125
    for (const std::pair<const Node, Node>& itmm : pmemsE)
969
    {
970
13047
      members.push_back(itmm.first);
971
13047
      exp.push_back(nm->mkNode(MEMBER, itmm.first, cardTerm[0]));
972
    }
973
8078
    if (members.size() > 1)
974
    {
975
2993
      exp.push_back(nm->mkNode(DISTINCT, members));
976
    }
977
8078
    if (!members.empty())
978
    {
979
      Node conc =
980
16156
          nm->mkNode(GEQ, cardTerm, nm->mkConst(Rational(members.size())));
981
16156
      Node expn = exp.size() == 1 ? exp[0] : nm->mkNode(AND, exp);
982
8078
      d_im.assertInference(conc, InferenceId::SETS_CARD_MINIMAL, expn, 1);
983
    }
984
  }
985
  // flush the lemmas
986
1393
  d_im.doPendingLemmas();
987
1393
}
988
989
371
bool CardinalityExtension::isModelValueBasic(Node eqc)
990
{
991
371
  return d_nf[eqc].size() == 1 && d_nf[eqc][0] == eqc;
992
}
993
994
163
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
326
  TypeNode elementType = eqc.getType().getSetElementType();
1002
163
  bool elementTypeFinite = d_state.isFiniteType(elementType);
1003
163
  if (isModelValueBasic(eqc))
1004
  {
1005
112
    std::map<Node, Node>::iterator it = d_eqc_to_card_term.find(eqc);
1006
112
    if (it != d_eqc_to_card_term.end())
1007
    {
1008
      // slack elements from cardinality value
1009
202
      Node v = val.getModelValue(it->second);
1010
202
      Trace("sets-model") << "Cardinality of " << eqc << " is " << v
1011
101
                          << std::endl;
1012
101
      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
101
      std::uint32_t vu = v.getConst<Rational>().getNumerator().toUnsignedInt();
1020
101
      Assert(els.size() <= vu);
1021
101
      NodeManager* nm = NodeManager::currentNM();
1022
101
      SkolemManager* sm = nm->getSkolemManager();
1023
101
      if (elementTypeFinite)
1024
      {
1025
        // get all members of this finite type
1026
20
        collectFiniteTypeSetElements(model);
1027
      }
1028
259
      while (els.size() < vu)
1029
      {
1030
79
        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
86
          Node slack = sm->mkDummySkolem("slack", elementType);
1043
86
          Node singleton = nm->mkSingleton(elementType, slack);
1044
43
          els.push_back(singleton);
1045
43
          d_finite_type_slack_elements[elementType].push_back(slack);
1046
86
          Trace("sets-model") << "Added slack element " << slack << " to set "
1047
43
                              << eqc << std::endl;
1048
        }
1049
        else
1050
        {
1051
36
          els.push_back(nm->mkSingleton(
1052
72
              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
102
    Trace("sets-model") << "Build value for " << eqc
1064
102
                        << " based on normal form, size = " << d_nf[eqc].size()
1065
51
                        << std::endl;
1066
    // it is union of venn regions
1067
92
    for (unsigned j = 0; j < d_nf[eqc].size(); j++)
1068
    {
1069
41
      std::map<Node, Node>::const_iterator itm = mvals.find(d_nf[eqc][j]);
1070
41
      if (itm != mvals.end())
1071
      {
1072
41
        els.push_back(itm->second);
1073
      }
1074
      else
1075
      {
1076
        Assert(false);
1077
      }
1078
    }
1079
  }
1080
163
}
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
42
    for (const std::pair<const Node, Node>& pair : d_state.getMembers(set))
1100
    {
1101
44
      Node member = pair.first;
1102
44
      Node modelRepresentative = model->getRepresentative(member);
1103
22
      std::vector<Node>& elements = d_finite_type_elements[member.getType()];
1104
66
      if (std::find(elements.begin(), elements.end(), modelRepresentative)
1105
66
          == elements.end())
1106
      {
1107
22
        elements.push_back(modelRepresentative);
1108
      }
1109
    }
1110
  }
1111
10
  d_finite_type_constants_processed = true;
1112
}
1113
1114
8
const std::vector<Node>& CardinalityExtension::getFiniteTypeMembers(
1115
    TypeNode typeNode)
1116
{
1117
8
  return d_finite_type_elements[typeNode];
1118
}
1119
1120
}  // namespace sets
1121
}  // namespace theory
1122
28194
}  // namespace cvc5