GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sets/theory_sets_private.cpp Lines: 670 713 94.0 %
Date: 2021-05-21 Branches: 1463 3119 46.9 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Mudathir Mohamed, Kshitij Bansal
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
 * Sets theory implementation.
14
 */
15
16
#include "theory/sets/theory_sets_private.h"
17
18
#include <algorithm>
19
#include <climits>
20
21
#include "expr/emptyset.h"
22
#include "expr/node_algorithm.h"
23
#include "expr/skolem_manager.h"
24
#include "options/sets_options.h"
25
#include "smt/smt_statistics_registry.h"
26
#include "theory/sets/normal_form.h"
27
#include "theory/sets/theory_sets.h"
28
#include "theory/theory_model.h"
29
#include "util/result.h"
30
31
using namespace std;
32
using namespace cvc5::kind;
33
34
namespace cvc5 {
35
namespace theory {
36
namespace sets {
37
38
8954
TheorySetsPrivate::TheorySetsPrivate(TheorySets& external,
39
                                     SolverState& state,
40
                                     InferenceManager& im,
41
                                     SkolemCache& skc,
42
8954
                                     ProofNodeManager* pnm)
43
    : d_deq(state.getSatContext()),
44
8954
      d_termProcessed(state.getUserContext()),
45
      d_fullCheckIncomplete(false),
46
      d_fullCheckIncompleteId(IncompleteId::UNKNOWN),
47
      d_external(external),
48
      d_state(state),
49
      d_im(im),
50
      d_skCache(skc),
51
      d_treg(state, im, skc, pnm),
52
8954
      d_rels(new TheorySetsRels(state, im, skc, d_treg)),
53
8954
      d_cardSolver(new CardinalityExtension(state, im, d_treg)),
54
      d_rels_enabled(false),
55
35816
      d_card_enabled(false)
56
{
57
8954
  d_true = NodeManager::currentNM()->mkConst(true);
58
8954
  d_false = NodeManager::currentNM()->mkConst(false);
59
8954
  d_zero = NodeManager::currentNM()->mkConst(Rational(0));
60
8954
}
61
62
17908
TheorySetsPrivate::~TheorySetsPrivate()
63
{
64
13815
  for (std::pair<const Node, EqcInfo*>& current_pair : d_eqc_info)
65
  {
66
4861
    delete current_pair.second;
67
  }
68
8954
}
69
70
8954
void TheorySetsPrivate::finishInit()
71
{
72
8954
  d_equalityEngine = d_external.getEqualityEngine();
73
8954
  Assert(d_equalityEngine != nullptr);
74
8954
}
75
76
72815
void TheorySetsPrivate::eqNotifyNewClass(TNode t)
77
{
78
72815
  if (t.getKind() == kind::SINGLETON || t.getKind() == kind::EMPTYSET)
79
  {
80
3696
    EqcInfo* e = getOrMakeEqcInfo(t, true);
81
3696
    e->d_singleton = t;
82
  }
83
72815
}
84
85
182283
void TheorySetsPrivate::eqNotifyMerge(TNode t1, TNode t2)
86
{
87
182283
  if (!d_state.isInConflict())
88
  {
89
364554
    Trace("sets-prop-debug")
90
182277
        << "Merge " << t1 << " and " << t2 << "..." << std::endl;
91
364389
    Node s1, s2;
92
182277
    EqcInfo* e2 = getOrMakeEqcInfo(t2);
93
182277
    if (e2)
94
    {
95
15135
      s2 = e2->d_singleton;
96
15135
      EqcInfo* e1 = getOrMakeEqcInfo(t1);
97
15135
      Trace("sets-prop-debug") << "Merging singletons..." << std::endl;
98
15135
      if (e1)
99
      {
100
15004
        s1 = e1->d_singleton;
101
15004
        if (!s1.isNull() && !s2.isNull())
102
        {
103
11720
          if (s1.getKind() == s2.getKind())
104
          {
105
23298
            Trace("sets-prop") << "Propagate eq inference : " << s1
106
11649
                               << " == " << s2 << std::endl;
107
            // infer equality between elements of singleton
108
23298
            Node exp = s1.eqNode(s2);
109
23298
            Node eq = s1[0].eqNode(s2[0]);
110
11649
            d_im.assertInternalFact(eq, true, InferenceId::SETS_SINGLETON_EQ, exp);
111
          }
112
          else
113
          {
114
            // singleton equal to emptyset, conflict
115
142
            Trace("sets-prop")
116
71
                << "Propagate conflict : " << s1 << " == " << s2 << std::endl;
117
71
            d_im.conflictEqConstantMerge(s1, s2);
118
71
            return;
119
          }
120
        }
121
      }
122
      else
123
      {
124
        // copy information
125
131
        e1 = getOrMakeEqcInfo(t1, true);
126
131
        e1->d_singleton.set(e2->d_singleton);
127
      }
128
    }
129
    // merge membership list
130
182206
    Trace("sets-prop-debug") << "Copying membership list..." << std::endl;
131
    // if s1 has a singleton or empty set and s2 does not, we may have new
132
    // inferences to process.
133
364318
    Node checkSingleton = s2.isNull() ? s1 : Node::null();
134
364318
    std::vector<Node> facts;
135
    // merge the membership list in the state, which may produce facts or
136
    // conflicts to propagate
137
182206
    if (!d_state.merge(t1, t2, facts, checkSingleton))
138
    {
139
      // conflict case
140
94
      Assert(facts.size() == 1);
141
188
      Trace("sets-prop") << "Propagate eq-mem conflict : " << facts[0]
142
94
                         << std::endl;
143
94
      d_im.conflict(facts[0], InferenceId::SETS_EQ_MEM_CONFLICT);
144
94
      return;
145
    }
146
182256
    for (const Node& f : facts)
147
    {
148
144
      Assert(f.getKind() == kind::IMPLIES);
149
288
      Trace("sets-prop") << "Propagate eq-mem eq inference : " << f[0] << " => "
150
144
                         << f[1] << std::endl;
151
144
      d_im.assertInternalFact(f[1], true, InferenceId::SETS_EQ_MEM, f[0]);
152
    }
153
  }
154
}
155
156
23542
void TheorySetsPrivate::eqNotifyDisequal(TNode t1, TNode t2, TNode reason)
157
{
158
23542
  if (t1.getType().isSet())
159
  {
160
25578
    Node eq = t1.eqNode(t2);
161
12789
    if (d_deq.find(eq) == d_deq.end())
162
    {
163
12789
      d_deq[eq] = true;
164
    }
165
  }
166
23542
}
167
168
4861
TheorySetsPrivate::EqcInfo::EqcInfo(context::Context* c) : d_singleton(c) {}
169
170
251620
TheorySetsPrivate::EqcInfo* TheorySetsPrivate::getOrMakeEqcInfo(TNode n,
171
                                                                bool doMake)
172
{
173
251620
  std::map<Node, EqcInfo*>::iterator eqc_i = d_eqc_info.find(n);
174
251620
  if (eqc_i == d_eqc_info.end())
175
  {
176
172134
    EqcInfo* ei = NULL;
177
172134
    if (doMake)
178
    {
179
4861
      ei = new EqcInfo(d_external.getSatContext());
180
4861
      d_eqc_info[n] = ei;
181
    }
182
172134
    return ei;
183
  }
184
  else
185
  {
186
79486
    return eqc_i->second;
187
  }
188
}
189
190
35623
bool TheorySetsPrivate::areCareDisequal(Node a, Node b)
191
{
192
106869
  if (d_equalityEngine->isTriggerTerm(a, THEORY_SETS)
193
106869
      && d_equalityEngine->isTriggerTerm(b, THEORY_SETS))
194
  {
195
    TNode a_shared =
196
33761
        d_equalityEngine->getTriggerTermRepresentative(a, THEORY_SETS);
197
    TNode b_shared =
198
33761
        d_equalityEngine->getTriggerTermRepresentative(b, THEORY_SETS);
199
    EqualityStatus eqStatus =
200
21121
        d_external.d_valuation.getEqualityStatus(a_shared, b_shared);
201
21121
    if (eqStatus == EQUALITY_FALSE_AND_PROPAGATED || eqStatus == EQUALITY_FALSE
202
21121
        || eqStatus == EQUALITY_FALSE_IN_MODEL)
203
    {
204
8481
      return true;
205
    }
206
  }
207
27142
  return false;
208
}
209
210
16785
void TheorySetsPrivate::fullEffortReset()
211
{
212
16785
  Assert(d_equalityEngine->consistent());
213
16785
  d_fullCheckIncomplete = false;
214
16785
  d_fullCheckIncompleteId = IncompleteId::UNKNOWN;
215
16785
  d_most_common_type.clear();
216
16785
  d_most_common_type_term.clear();
217
16785
  d_card_enabled = false;
218
16785
  d_rels_enabled = false;
219
  // reset the state object
220
16785
  d_state.reset();
221
  // reset the inference manager
222
16785
  d_im.reset();
223
16785
  d_im.clearPendingLemmas();
224
  // reset the cardinality solver
225
16785
  d_cardSolver->reset();
226
16785
}
227
228
16785
void TheorySetsPrivate::fullEffortCheck()
229
{
230
16785
  Trace("sets") << "----- Full effort check ------" << std::endl;
231
  do
232
  {
233
16785
    Assert(!d_im.hasPendingLemma() || d_im.hasSent());
234
235
16785
    Trace("sets") << "...iterate full effort check..." << std::endl;
236
16785
    fullEffortReset();
237
238
16785
    Trace("sets-eqc") << "Equality Engine:" << std::endl;
239
29214
    std::map<TypeNode, unsigned> eqcTypeCount;
240
16785
    eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine);
241
318483
    while (!eqcs_i.isFinished())
242
    {
243
301698
      Node eqc = (*eqcs_i);
244
150849
      bool isSet = false;
245
301698
      TypeNode tn = eqc.getType();
246
150849
      d_state.registerEqc(tn, eqc);
247
150849
      eqcTypeCount[tn]++;
248
      // common type node and term
249
301698
      TypeNode tnc;
250
301698
      Node tnct;
251
150849
      if (tn.isSet())
252
      {
253
54059
        isSet = true;
254
54059
        tnc = tn.getSetElementType();
255
54059
        tnct = eqc;
256
      }
257
150849
      Trace("sets-eqc") << "[" << eqc << "] : ";
258
150849
      eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, d_equalityEngine);
259
1168215
      while (!eqc_i.isFinished())
260
      {
261
1018464
        Node n = (*eqc_i);
262
509781
        if (n != eqc)
263
        {
264
358932
          Trace("sets-eqc") << n << " (" << n.isConst() << ") ";
265
        }
266
1018464
        TypeNode tnn = n.getType();
267
509781
        if (isSet)
268
        {
269
139527
          Assert(tnn.isSet());
270
279054
          TypeNode tnnel = tnn.getSetElementType();
271
139527
          tnc = TypeNode::mostCommonTypeNode(tnc, tnnel);
272
139527
          Assert(!tnc.isNull());
273
          // update the common type term
274
139527
          if (tnc == tnnel)
275
          {
276
139527
            tnct = n;
277
          }
278
        }
279
        // register it with the state
280
509781
        d_state.registerTerm(eqc, tnn, n);
281
509781
        Kind nk = n.getKind();
282
509781
        if (nk == kind::SINGLETON)
283
        {
284
          // ensure the proxy has been introduced
285
10281
          d_treg.getProxy(n);
286
        }
287
499500
        else if (nk == kind::CARD)
288
        {
289
50125
          d_card_enabled = true;
290
          // register it with the cardinality solver
291
50125
          d_cardSolver->registerTerm(n);
292
50125
          if (d_im.hasSent())
293
          {
294
1098
            break;
295
          }
296
          // if we do not handle the kind, set incomplete
297
49027
          Kind nk0 = n[0].getKind();
298
          // some kinds of cardinality we cannot handle
299
49027
          if (d_rels->isRelationKind(nk0))
300
          {
301
28
            d_fullCheckIncomplete = true;
302
28
            d_fullCheckIncompleteId = IncompleteId::SETS_RELS_CARD;
303
56
            Trace("sets-incomplete")
304
28
                << "Sets : incomplete because of " << n << "." << std::endl;
305
            // TODO (#1124):  The issue can be divided into 4 parts
306
            // 1- Supporting the universe cardinality for finite types with
307
            // finite cardinality (done)
308
            // 2- Supporting the universe cardinality for uninterpreted sorts
309
            // with finite-model-find (pending) See the implementation of
310
            //    CardinalityExtension::checkCardinalityExtended
311
            // 3- Supporting the universe cardinality for non-finite types
312
            // (done)
313
            // 4- Supporting cardinality for relations (hard)
314
          }
315
        }
316
449375
        else if (d_rels->isRelationKind(nk))
317
        {
318
2242
          d_rels_enabled = true;
319
        }
320
508683
        ++eqc_i;
321
      }
322
150849
      if (isSet)
323
      {
324
54059
        Assert(tnct.getType().getSetElementType() == tnc);
325
54059
        d_most_common_type[eqc] = tnc;
326
54059
        d_most_common_type_term[eqc] = tnct;
327
      }
328
150849
      Trace("sets-eqc") << std::endl;
329
150849
      ++eqcs_i;
330
    }
331
332
16785
    Trace("sets-eqc") << "...finished equality engine." << std::endl;
333
334
16785
    if (Trace.isOn("sets-state"))
335
    {
336
      Trace("sets-state") << "Equivalence class counters:" << std::endl;
337
      for (std::pair<const TypeNode, unsigned>& ec : eqcTypeCount)
338
      {
339
        Trace("sets-state")
340
            << "  " << ec.first << " -> " << ec.second << std::endl;
341
      }
342
    }
343
344
    // We may have sent lemmas while registering the terms in the loop above,
345
    // e.g. the cardinality solver.
346
16785
    if (d_im.hasSent())
347
    {
348
527
      continue;
349
    }
350
16258
    if (Trace.isOn("sets-mem"))
351
    {
352
      const std::vector<Node>& sec = d_state.getSetsEqClasses();
353
      for (const Node& s : sec)
354
      {
355
        Trace("sets-mem") << "Eqc " << s << " : ";
356
        const std::map<Node, Node>& smem = d_state.getMembers(s);
357
        if (!smem.empty())
358
        {
359
          Trace("sets-mem") << "Memberships : ";
360
          for (const std::pair<const Node, Node>& it2 : smem)
361
          {
362
            Trace("sets-mem") << it2.first << " ";
363
          }
364
        }
365
        Node ss = d_state.getSingletonEqClass(s);
366
        if (!ss.isNull())
367
        {
368
          Trace("sets-mem") << " : Singleton : " << ss;
369
        }
370
        Trace("sets-mem") << std::endl;
371
      }
372
    }
373
16258
    d_im.doPendingLemmas();
374
16258
    if (d_im.hasSent())
375
    {
376
      continue;
377
    }
378
    // check downwards closure
379
16258
    checkDownwardsClosure();
380
16258
    d_im.doPendingLemmas();
381
16258
    if (d_im.hasSent())
382
    {
383
536
      continue;
384
    }
385
    // check upwards closure
386
15722
    checkUpwardsClosure();
387
15722
    d_im.doPendingLemmas();
388
15722
    if (d_im.hasSent())
389
    {
390
1128
      continue;
391
    }
392
    // check disequalities
393
14594
    checkDisequalities();
394
14594
    d_im.doPendingLemmas();
395
14594
    if (d_im.hasSent())
396
    {
397
570
      continue;
398
    }
399
    // check reduce comprehensions
400
14024
    checkReduceComprehensions();
401
402
14024
    d_im.doPendingLemmas();
403
14024
    if (d_im.hasSent())
404
    {
405
18
      continue;
406
    }
407
14006
    if (d_card_enabled)
408
    {
409
      // call the check method of the cardinality solver
410
1694
      d_cardSolver->check();
411
1693
      if (d_im.hasSent())
412
      {
413
1577
        continue;
414
      }
415
    }
416
12428
    if (d_rels_enabled)
417
    {
418
      // call the check method of the relations solver
419
737
      d_rels->check(Theory::EFFORT_FULL);
420
    }
421
28599
  } while (!d_im.hasSentLemma() && !d_state.isInConflict()
422
28599
           && d_im.hasSentFact());
423
16784
  Assert(!d_im.hasPendingLemma() || d_im.hasSent());
424
33568
  Trace("sets") << "----- End full effort check, conflict="
425
33568
                << d_state.isInConflict() << ", lemma=" << d_im.hasSentLemma()
426
16784
                << std::endl;
427
16784
}
428
429
16258
void TheorySetsPrivate::checkDownwardsClosure()
430
{
431
16258
  Trace("sets") << "TheorySetsPrivate: check downwards closure..." << std::endl;
432
  // downwards closure
433
16258
  const std::vector<Node>& sec = d_state.getSetsEqClasses();
434
65016
  for (const Node& s : sec)
435
  {
436
48758
    const std::vector<Node>& nvsets = d_state.getNonVariableSets(s);
437
48758
    if (!nvsets.empty())
438
    {
439
36522
      const std::map<Node, Node>& smem = d_state.getMembers(s);
440
96281
      for (const Node& nv : nvsets)
441
      {
442
59759
        if (!d_state.isCongruent(nv))
443
        {
444
107934
          for (const std::pair<const Node, Node>& it2 : smem)
445
          {
446
106108
            Node mem = it2.second;
447
106108
            Node eq_set = nv;
448
53054
            Assert(d_equalityEngine->areEqual(mem[1], eq_set));
449
53054
            if (mem[1] != eq_set)
450
            {
451
103298
              Trace("sets-debug") << "Downwards closure based on " << mem
452
51649
                                  << ", eq_set = " << eq_set << std::endl;
453
103298
              if (!options::setsProxyLemmas())
454
              {
455
                Node nmem = NodeManager::currentNM()->mkNode(
456
103298
                    kind::MEMBER, mem[0], eq_set);
457
51649
                nmem = Rewriter::rewrite(nmem);
458
103298
                std::vector<Node> exp;
459
51649
                exp.push_back(mem);
460
51649
                exp.push_back(mem[1].eqNode(eq_set));
461
51649
                d_im.assertInference(nmem, InferenceId::SETS_DOWN_CLOSURE, exp);
462
51649
                if (d_state.isInConflict())
463
                {
464
                  return;
465
                }
466
              }
467
              else
468
              {
469
                // use proxy set
470
                Node k = d_treg.getProxy(eq_set);
471
                Node pmem =
472
                    NodeManager::currentNM()->mkNode(kind::MEMBER, mem[0], k);
473
                Node nmem = NodeManager::currentNM()->mkNode(
474
                    kind::MEMBER, mem[0], eq_set);
475
                nmem = Rewriter::rewrite(nmem);
476
                std::vector<Node> exp;
477
                if (d_state.areEqual(mem, pmem))
478
                {
479
                  exp.push_back(pmem);
480
                }
481
                else
482
                {
483
                  nmem = NodeManager::currentNM()->mkNode(
484
                      kind::OR, pmem.negate(), nmem);
485
                }
486
                d_im.assertInference(nmem, InferenceId::SETS_DOWN_CLOSURE, exp);
487
              }
488
            }
489
          }
490
        }
491
      }
492
    }
493
  }
494
}
495
496
15722
void TheorySetsPrivate::checkUpwardsClosure()
497
{
498
  // upwards closure
499
15722
  NodeManager* nm = NodeManager::currentNM();
500
  const std::map<Kind, std::map<Node, std::map<Node, Node> > >& boi =
501
15722
      d_state.getBinaryOpIndex();
502
7860
  for (const std::pair<const Kind, std::map<Node, std::map<Node, Node> > >&
503
15722
           itb : boi)
504
  {
505
7860
    Kind k = itb.first;
506
15720
    Trace("sets") << "TheorySetsPrivate: check upwards closure " << k << "..."
507
7860
                  << std::endl;
508
32636
    for (const std::pair<const Node, std::map<Node, Node> >& it : itb.second)
509
    {
510
49552
      Node r1 = it.first;
511
      // see if there are members in first argument r1
512
24776
      const std::map<Node, Node>& r1mem = d_state.getMembers(r1);
513
24776
      if (!r1mem.empty() || k == kind::UNION)
514
      {
515
49107
        for (const std::pair<const Node, Node>& it2 : it.second)
516
        {
517
57686
          Node r2 = it2.first;
518
57686
          Node term = it2.second;
519
          // see if there are members in second argument
520
28843
          const std::map<Node, Node>& r2mem = d_state.getMembers(r2);
521
28843
          const std::map<Node, Node>& r2nmem = d_state.getNegativeMembers(r2);
522
28843
          if (!r2mem.empty() || k != kind::INTERSECTION)
523
          {
524
56436
            Trace("sets-debug")
525
56436
                << "Checking " << term << ", members = " << (!r1mem.empty())
526
28218
                << ", " << (!r2mem.empty()) << std::endl;
527
            // for all members of r1
528
28218
            if (!r1mem.empty())
529
            {
530
73572
              for (const std::pair<const Node, Node>& itm1m : r1mem)
531
              {
532
95550
                Node xr = itm1m.first;
533
95550
                Node x = itm1m.second[0];
534
95550
                Trace("sets-debug") << "checking membership " << xr << " "
535
47775
                                    << itm1m.second << std::endl;
536
95550
                std::vector<Node> exp;
537
47775
                exp.push_back(itm1m.second);
538
47775
                d_state.addEqualityToExp(term[0], itm1m.second[1], exp);
539
47775
                bool valid = false;
540
47775
                int inferType = 0;
541
47775
                if (k == kind::UNION)
542
                {
543
8164
                  valid = true;
544
                }
545
39611
                else if (k == kind::INTERSECTION)
546
                {
547
                  // conclude x is in term
548
                  // if also existing in members of r2
549
12884
                  std::map<Node, Node>::const_iterator itm = r2mem.find(xr);
550
12884
                  if (itm != r2mem.end())
551
                  {
552
8021
                    exp.push_back(itm->second);
553
8021
                    d_state.addEqualityToExp(term[1], itm->second[1], exp);
554
8021
                    d_state.addEqualityToExp(x, itm->second[0], exp);
555
8021
                    valid = true;
556
                  }
557
                  else
558
                  {
559
                    // if not, check whether it is definitely not a member, if
560
                    // unknown, split
561
4863
                    if (r2nmem.find(xr) == r2nmem.end())
562
                    {
563
731
                      exp.push_back(nm->mkNode(kind::MEMBER, x, term[1]));
564
731
                      valid = true;
565
731
                      inferType = 1;
566
                    }
567
                  }
568
                }
569
                else
570
                {
571
26727
                  Assert(k == kind::SETMINUS);
572
26727
                  std::map<Node, Node>::const_iterator itm = r2mem.find(xr);
573
26727
                  if (itm == r2mem.end())
574
                  {
575
                    // must add lemma for set minus since non-membership in this
576
                    // case is not explained
577
11654
                    exp.push_back(
578
23308
                        nm->mkNode(kind::MEMBER, x, term[1]).negate());
579
11654
                    valid = true;
580
11654
                    inferType = 1;
581
                  }
582
                }
583
47775
                if (valid)
584
                {
585
57140
                  Node rr = d_equalityEngine->getRepresentative(term);
586
28570
                  if (!d_state.isMember(x, rr))
587
                  {
588
4602
                    Node kk = d_treg.getProxy(term);
589
4602
                    Node fact = nm->mkNode(kind::MEMBER, x, kk);
590
2301
                    d_im.assertInference(
591
                        fact, InferenceId::SETS_UP_CLOSURE, exp, inferType);
592
2301
                    if (d_state.isInConflict())
593
                    {
594
                      return;
595
                    }
596
                  }
597
                }
598
95550
                Trace("sets-debug") << "done checking membership " << xr << " "
599
47775
                                    << itm1m.second << std::endl;
600
              }
601
            }
602
28218
            if (k == kind::UNION)
603
            {
604
7884
              if (!r2mem.empty())
605
              {
606
                // for all members of r2
607
18566
                for (const std::pair<const Node, Node>& itm2m : r2mem)
608
                {
609
25036
                  Node x = itm2m.second[0];
610
25036
                  Node rr = d_equalityEngine->getRepresentative(term);
611
12518
                  if (!d_state.isMember(x, rr))
612
                  {
613
1084
                    std::vector<Node> exp;
614
542
                    exp.push_back(itm2m.second);
615
542
                    d_state.addEqualityToExp(term[1], itm2m.second[1], exp);
616
1084
                    Node r = d_treg.getProxy(term);
617
1084
                    Node fact = nm->mkNode(kind::MEMBER, x, r);
618
542
                    d_im.assertInference(fact, InferenceId::SETS_UP_CLOSURE_2, exp);
619
542
                    if (d_state.isInConflict())
620
                    {
621
                      return;
622
                    }
623
                  }
624
                }
625
              }
626
            }
627
          }
628
        }
629
      }
630
    }
631
  }
632
15722
  if (!d_im.hasSent())
633
  {
634
15271
    if (options::setsExt())
635
    {
636
      // universal sets
637
1556
      Trace("sets-debug") << "Check universe sets..." << std::endl;
638
      // all elements must be in universal set
639
1556
      const std::vector<Node>& sec = d_state.getSetsEqClasses();
640
14656
      for (const Node& s : sec)
641
      {
642
        // if equivalence class contains a variable
643
26200
        Node v = d_state.getVariableSet(s);
644
13100
        if (!v.isNull())
645
        {
646
          // the variable in the equivalence class
647
8064
          std::map<TypeNode, Node> univ_set;
648
4032
          const std::map<Node, Node>& smems = d_state.getMembers(s);
649
8703
          for (const std::pair<const Node, Node>& it2 : smems)
650
          {
651
9342
            Node e = it2.second[0];
652
9342
            TypeNode tn = NodeManager::currentNM()->mkSetType(e.getType());
653
9342
            Node u;
654
4671
            std::map<TypeNode, Node>::iterator itu = univ_set.find(tn);
655
4671
            if (itu == univ_set.end())
656
            {
657
4948
              Node ueqc = d_state.getUnivSetEqClass(tn);
658
              // if the universe does not yet exist, or is not in this
659
              // equivalence class
660
2474
              if (s != ueqc)
661
              {
662
1799
                u = d_treg.getUnivSet(tn);
663
              }
664
2474
              univ_set[tn] = u;
665
            }
666
            else
667
            {
668
2197
              u = itu->second;
669
            }
670
4671
            if (!u.isNull())
671
            {
672
2962
              Assert(it2.second.getKind() == kind::MEMBER);
673
5924
              std::vector<Node> exp;
674
2962
              exp.push_back(it2.second);
675
2962
              if (v != it2.second[1])
676
              {
677
789
                exp.push_back(v.eqNode(it2.second[1]));
678
              }
679
5924
              Node fact = nm->mkNode(kind::MEMBER, it2.second[0], u);
680
2962
              d_im.assertInference(fact, InferenceId::SETS_UP_UNIV, exp);
681
2962
              if (d_state.isInConflict())
682
              {
683
                return;
684
              }
685
            }
686
          }
687
        }
688
      }
689
    }
690
  }
691
}
692
693
14594
void TheorySetsPrivate::checkDisequalities()
694
{
695
  // disequalities
696
14594
  Trace("sets") << "TheorySetsPrivate: check disequalities..." << std::endl;
697
14594
  NodeManager* nm = NodeManager::currentNM();
698
23810
  for (NodeBoolMap::const_iterator it = d_deq.begin(); it != d_deq.end(); ++it)
699
  {
700
9786
    if (!(*it).second)
701
    {
702
      // not active
703
12356
      continue;
704
    }
705
6646
    Node deq = (*it).first;
706
    // check if it is already satisfied
707
6646
    Assert(d_equalityEngine->hasTerm(deq[0])
708
           && d_equalityEngine->hasTerm(deq[1]));
709
6646
    Node r1 = d_equalityEngine->getRepresentative(deq[0]);
710
6646
    Node r2 = d_equalityEngine->getRepresentative(deq[1]);
711
6646
    bool is_sat = d_state.isSetDisequalityEntailed(r1, r2);
712
13292
    Trace("sets-debug") << "Check disequality " << deq
713
6646
                        << ", is_sat = " << is_sat << std::endl;
714
    // will process regardless of sat/processed/unprocessed
715
6646
    d_deq[deq] = false;
716
717
6646
    if (is_sat)
718
    {
719
      // already satisfied
720
5929
      continue;
721
    }
722
717
    if (d_termProcessed.find(deq) != d_termProcessed.end())
723
    {
724
      // already added lemma
725
147
      continue;
726
    }
727
570
    d_termProcessed.insert(deq);
728
570
    d_termProcessed.insert(deq[1].eqNode(deq[0]));
729
570
    Trace("sets") << "Process Disequality : " << deq.negate() << std::endl;
730
570
    TypeNode elementType = deq[0].getType().getSetElementType();
731
570
    Node x = d_skCache.mkTypedSkolemCached(
732
570
        elementType, deq[0], deq[1], SkolemCache::SK_DISEQUAL, "sde");
733
570
    Node mem1 = nm->mkNode(MEMBER, x, deq[0]);
734
570
    Node mem2 = nm->mkNode(MEMBER, x, deq[1]);
735
570
    Node lem = nm->mkNode(OR, deq, nm->mkNode(EQUAL, mem1, mem2).negate());
736
570
    lem = Rewriter::rewrite(lem);
737
570
    d_im.assertInference(lem, InferenceId::SETS_DEQ, d_true, 1);
738
570
    d_im.doPendingLemmas();
739
570
    if (d_im.hasSent())
740
    {
741
570
      return;
742
    }
743
  }
744
}
745
746
14024
void TheorySetsPrivate::checkReduceComprehensions()
747
{
748
14024
  NodeManager* nm = NodeManager::currentNM();
749
14024
  const std::vector<Node>& comps = d_state.getComprehensionSets();
750
14092
  for (const Node& n : comps)
751
  {
752
68
    if (d_termProcessed.find(n) != d_termProcessed.end())
753
    {
754
      // already reduced it
755
46
      continue;
756
    }
757
22
    d_termProcessed.insert(n);
758
44
    Node v = nm->mkBoundVar(n[2].getType());
759
44
    Node body = nm->mkNode(AND, n[1], v.eqNode(n[2]));
760
    // must do substitution
761
44
    std::vector<Node> vars;
762
44
    std::vector<Node> subs;
763
44
    for (const Node& cv : n[0])
764
    {
765
22
      vars.push_back(cv);
766
44
      Node cvs = nm->mkBoundVar(cv.getType());
767
22
      subs.push_back(cvs);
768
    }
769
22
    body = body.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
770
44
    Node bvl = nm->mkNode(BOUND_VAR_LIST, subs);
771
22
    body = nm->mkNode(EXISTS, bvl, body);
772
44
    Node mem = nm->mkNode(MEMBER, v, n);
773
    Node lem =
774
44
        nm->mkNode(FORALL, nm->mkNode(BOUND_VAR_LIST, v), body.eqNode(mem));
775
44
    Trace("sets-comprehension")
776
22
        << "Comprehension reduction: " << lem << std::endl;
777
22
    d_im.lemma(lem, InferenceId::SETS_COMPREHENSION);
778
  }
779
14024
}
780
781
//--------------------------------- standard check
782
783
81489
void TheorySetsPrivate::postCheck(Theory::Effort level)
784
{
785
162978
  Trace("sets-check") << "Sets finished assertions effort " << level
786
81489
                      << std::endl;
787
  // invoke full effort check, relations check
788
81489
  if (!d_state.isInConflict())
789
  {
790
78671
    if (level == Theory::EFFORT_FULL)
791
    {
792
20894
      if (!d_external.d_valuation.needCheck())
793
      {
794
16785
        fullEffortCheck();
795
50352
        if (!d_state.isInConflict() && !d_im.hasSentLemma()
796
28599
            && d_fullCheckIncomplete)
797
        {
798
4
          d_im.setIncomplete(d_fullCheckIncompleteId);
799
        }
800
      }
801
    }
802
  }
803
81488
  Trace("sets-check") << "Sets finish Check effort " << level << std::endl;
804
81488
}
805
806
169025
void TheorySetsPrivate::notifyFact(TNode atom, bool polarity, TNode fact)
807
{
808
169025
  if (d_state.isInConflict())
809
  {
810
2671
    return;
811
  }
812
166354
  if (atom.getKind() == kind::MEMBER && polarity)
813
  {
814
    // check if set has a value, if so, we can propagate
815
100762
    Node r = d_equalityEngine->getRepresentative(atom[1]);
816
50381
    EqcInfo* e = getOrMakeEqcInfo(r, true);
817
50381
    if (e)
818
    {
819
100762
      Node s = e->d_singleton;
820
50381
      if (!s.isNull())
821
      {
822
        Node pexp = NodeManager::currentNM()->mkNode(
823
5098
            kind::AND, atom, atom[1].eqNode(s));
824
2549
        if (s.getKind() == kind::SINGLETON)
825
        {
826
2402
          if (s[0] != atom[0])
827
          {
828
411
            Trace("sets-prop") << "Propagate mem-eq : " << pexp << std::endl;
829
822
            Node eq = s[0].eqNode(atom[0]);
830
            // triggers an internal inference
831
411
            d_im.assertInternalFact(eq, true, InferenceId::SETS_MEM_EQ, pexp);
832
          }
833
        }
834
        else
835
        {
836
294
          Trace("sets-prop")
837
147
              << "Propagate mem-eq conflict : " << pexp << std::endl;
838
147
          d_im.conflict(pexp, InferenceId::SETS_MEM_EQ_CONFLICT);
839
        }
840
      }
841
    }
842
    // add to membership list
843
50381
    d_state.addMember(r, atom);
844
  }
845
}
846
//--------------------------------- end standard check
847
848
/************************ Sharing ************************/
849
/************************ Sharing ************************/
850
/************************ Sharing ************************/
851
852
15757
void TheorySetsPrivate::addCarePairs(TNodeTrie* t1,
853
                                     TNodeTrie* t2,
854
                                     unsigned arity,
855
                                     unsigned depth,
856
                                     unsigned& n_pairs)
857
{
858
15757
  if (depth == arity)
859
  {
860
8950
    if (t2 != NULL)
861
    {
862
17900
      Node f1 = t1->getData();
863
17900
      Node f2 = t2->getData();
864
865
      // Usually when (= (f x) (f y)), we don't care whether (= x y) is true or
866
      // not for the shared variables x, y in the care graph.
867
      // However, this does not apply to the membership operator since the
868
      // equality or disequality between members affects the number of elements
869
      // in a set. Therefore we need to split on (= x y) for kind MEMBER.
870
      // Example:
871
      // Suppose (= (member x S) member( y, S)) is true and there are
872
      // no other members in S. We would get S = {x} if (= x y) is true.
873
      // Otherwise we would get S = {x, y}.
874
8950
      if (f1.getKind() == MEMBER || !d_state.areEqual(f1, f2))
875
      {
876
8950
        Trace("sets-cg") << "Check " << f1 << " and " << f2 << std::endl;
877
17900
        vector<pair<TNode, TNode> > currentPairs;
878
26429
        for (unsigned k = 0; k < f1.getNumChildren(); ++k)
879
        {
880
34958
          TNode x = f1[k];
881
34958
          TNode y = f2[k];
882
17479
          Assert(d_equalityEngine->hasTerm(x));
883
17479
          Assert(d_equalityEngine->hasTerm(y));
884
17479
          Assert(!d_state.areDisequal(x, y));
885
17479
          Assert(!areCareDisequal(x, y));
886
17479
          if (!d_equalityEngine->areEqual(x, y))
887
          {
888
20648
            Trace("sets-cg")
889
10324
                << "Arg #" << k << " is " << x << " " << y << std::endl;
890
30972
            if (d_equalityEngine->isTriggerTerm(x, THEORY_SETS)
891
30972
                && d_equalityEngine->isTriggerTerm(y, THEORY_SETS))
892
            {
893
3138
              TNode x_shared = d_equalityEngine->getTriggerTermRepresentative(
894
6276
                  x, THEORY_SETS);
895
3138
              TNode y_shared = d_equalityEngine->getTriggerTermRepresentative(
896
6276
                  y, THEORY_SETS);
897
3138
              currentPairs.push_back(make_pair(x_shared, y_shared));
898
            }
899
7186
            else if (isCareArg(f1, k) && isCareArg(f2, k))
900
            {
901
              // splitting on sets (necessary for handling set of sets properly)
902
6
              if (x.getType().isSet())
903
              {
904
6
                Assert(y.getType().isSet());
905
6
                if (!d_state.areDisequal(x, y))
906
                {
907
12
                  Trace("sets-cg-lemma")
908
6
                      << "Should split on : " << x << "==" << y << std::endl;
909
6
                  d_im.split(x.eqNode(y), InferenceId::UNKNOWN);
910
                }
911
              }
912
            }
913
          }
914
        }
915
12088
        for (unsigned c = 0; c < currentPairs.size(); ++c)
916
        {
917
6276
          Trace("sets-cg-pair") << "Pair : " << currentPairs[c].first << " "
918
3138
                                << currentPairs[c].second << std::endl;
919
3138
          d_external.addCarePair(currentPairs[c].first, currentPairs[c].second);
920
3138
          n_pairs++;
921
        }
922
      }
923
    }
924
  }
925
  else
926
  {
927
6807
    if (t2 == NULL)
928
    {
929
6094
      if (depth < (arity - 1))
930
      {
931
        // add care pairs internal to each child
932
5567
        for (std::pair<const TNode, TNodeTrie>& t : t1->d_data)
933
        {
934
4584
          addCarePairs(&t.second, NULL, arity, depth + 1, n_pairs);
935
        }
936
      }
937
      // add care pairs based on each pair of non-disequal arguments
938
21096
      for (std::map<TNode, TNodeTrie>::iterator it = t1->d_data.begin();
939
21096
           it != t1->d_data.end();
940
           ++it)
941
      {
942
15002
        std::map<TNode, TNodeTrie>::iterator it2 = it;
943
15002
        ++it2;
944
144014
        for (; it2 != t1->d_data.end(); ++it2)
945
        {
946
64506
          if (!d_equalityEngine->areDisequal(it->first, it2->first, false))
947
          {
948
16555
            if (!areCareDisequal(it->first, it2->first))
949
            {
950
24222
              addCarePairs(
951
16148
                  &it->second, &it2->second, arity, depth + 1, n_pairs);
952
            }
953
          }
954
        }
955
      }
956
    }
957
    else
958
    {
959
      // add care pairs based on product of indices, non-disequal arguments
960
1783
      for (std::pair<const TNode, TNodeTrie>& tt1 : t1->d_data)
961
      {
962
2918
        for (std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data)
963
        {
964
1848
          if (!d_equalityEngine->areDisequal(tt1.first, tt2.first, false))
965
          {
966
1589
            if (!areCareDisequal(tt1.first, tt2.first))
967
            {
968
1589
              addCarePairs(&tt1.second, &tt2.second, arity, depth + 1, n_pairs);
969
            }
970
          }
971
        }
972
      }
973
    }
974
  }
975
15757
}
976
977
5942
void TheorySetsPrivate::computeCareGraph()
978
{
979
5942
  const std::map<Kind, std::vector<Node> >& ol = d_state.getOperatorList();
980
7813
  for (const std::pair<const Kind, std::vector<Node> >& it : ol)
981
  {
982
1871
    Kind k = it.first;
983
1871
    if (k == kind::SINGLETON || k == kind::MEMBER)
984
    {
985
1212
      unsigned n_pairs = 0;
986
2424
      Trace("sets-cg-summary") << "Compute graph for sets, op=" << k << "..."
987
1212
                               << it.second.size() << std::endl;
988
1212
      Trace("sets-cg") << "Build index for " << k << "..." << std::endl;
989
2424
      std::map<TypeNode, TNodeTrie> index;
990
1212
      unsigned arity = 0;
991
      // populate indices
992
11630
      for (TNode f1 : it.second)
993
      {
994
10418
        Trace("sets-cg-debug") << "...build for " << f1 << std::endl;
995
10418
        Assert(d_equalityEngine->hasTerm(f1));
996
        // break into index based on operator, and the type of the element
997
        // type of the proper set, which notice must be safe wrt subtyping.
998
20836
        TypeNode tn;
999
10418
        if (k == kind::SINGLETON)
1000
        {
1001
          // get the type of the singleton set (not the type of its element)
1002
2530
          tn = f1.getType().getSetElementType();
1003
        }
1004
        else
1005
        {
1006
7888
          Assert (k == kind::MEMBER);
1007
          // get the element type of the set (not the type of the element)
1008
7888
          tn = f1[1].getType().getSetElementType();
1009
        }
1010
20836
        std::vector<TNode> reps;
1011
10418
        bool hasCareArg = false;
1012
28724
        for (unsigned j = 0; j < f1.getNumChildren(); j++)
1013
        {
1014
18306
          reps.push_back(d_equalityEngine->getRepresentative(f1[j]));
1015
18306
          if (isCareArg(f1, j))
1016
          {
1017
14314
            hasCareArg = true;
1018
          }
1019
        }
1020
10418
        if (hasCareArg)
1021
        {
1022
10418
          Trace("sets-cg-debug") << "......adding." << std::endl;
1023
10418
          index[tn].addTerm(f1, reps);
1024
10418
          arity = reps.size();
1025
        }
1026
        else
1027
        {
1028
          Trace("sets-cg-debug") << "......skip." << std::endl;
1029
        }
1030
      }
1031
1212
      if (arity > 0)
1032
      {
1033
        // for each index
1034
2722
        for (std::pair<const TypeNode, TNodeTrie>& tt : index)
1035
        {
1036
3020
          Trace("sets-cg") << "Process index " << tt.first << "..."
1037
1510
                           << std::endl;
1038
1510
          addCarePairs(&tt.second, nullptr, arity, 0, n_pairs);
1039
        }
1040
      }
1041
1212
      Trace("sets-cg-summary") << "...done, # pairs = " << n_pairs << std::endl;
1042
    }
1043
  }
1044
5942
}
1045
1046
28377
bool TheorySetsPrivate::isCareArg(Node n, unsigned a)
1047
{
1048
28377
  if (d_equalityEngine->isTriggerTerm(n[a], THEORY_SETS))
1049
  {
1050
17185
    return true;
1051
  }
1052
22384
  else if ((n.getKind() == kind::MEMBER || n.getKind() == kind::SINGLETON)
1053
33576
           && a == 0 && n[0].getType().isSet())
1054
  {
1055
20
    return true;
1056
  }
1057
  else
1058
  {
1059
11172
    return false;
1060
  }
1061
}
1062
1063
/******************** Model generation ********************/
1064
/******************** Model generation ********************/
1065
/******************** Model generation ********************/
1066
1067
namespace {
1068
/**
1069
 * This function is a helper function to print sets as
1070
 * Set A = { a0, a1, a2, }
1071
 * instead of
1072
 * (union (singleton a0) (union (singleton a1) (singleton a2)))
1073
 */
1074
4846
void traceSetElementsRecursively(stringstream& stream, const Node& set)
1075
{
1076
4846
  Assert(set.getType().isSet());
1077
4846
  if (set.getKind() == SINGLETON)
1078
  {
1079
3587
    stream << set[0] << ", ";
1080
  }
1081
4846
  if (set.getKind() == UNION)
1082
  {
1083
870
    traceSetElementsRecursively(stream, set[0]);
1084
870
    traceSetElementsRecursively(stream, set[1]);
1085
  }
1086
4846
}
1087
1088
3106
std::string traceElements(const Node& set)
1089
{
1090
6212
  std::stringstream stream;
1091
3106
  traceSetElementsRecursively(stream, set);
1092
6212
  return stream.str();
1093
}
1094
1095
}  // namespace
1096
1097
4488
bool TheorySetsPrivate::collectModelValues(TheoryModel* m,
1098
                                           const std::set<Node>& termSet)
1099
{
1100
4488
  Trace("sets-model") << "Set collect model values" << std::endl;
1101
1102
4488
  NodeManager* nm = NodeManager::currentNM();
1103
8976
  std::map<Node, Node> mvals;
1104
  // If cardinality is enabled, we need to use the ordered equivalence class
1105
  // list computed by the cardinality solver, where sets equivalence classes
1106
  // are assigned model values based on their position in the cardinality
1107
  // graph.
1108
4488
  const std::vector<Node>& sec = d_card_enabled
1109
8911
                                     ? d_cardSolver->getOrderedSetsEqClasses()
1110
8911
                                     : d_state.getSetsEqClasses();
1111
4488
  Valuation& val = getValuation();
1112
7636
  for (int i = (int)(sec.size() - 1); i >= 0; i--)
1113
  {
1114
6296
    Node eqc = sec[i];
1115
3148
    if (termSet.find(eqc) == termSet.end())
1116
    {
1117
84
      Trace("sets-model") << "* Do not assign value for " << eqc
1118
42
                          << " since is not relevant." << std::endl;
1119
    }
1120
    else
1121
    {
1122
6212
      std::vector<Node> els;
1123
3106
      bool is_base = !d_card_enabled || d_cardSolver->isModelValueBasic(eqc);
1124
3106
      if (is_base)
1125
      {
1126
6110
        Trace("sets-model")
1127
3055
            << "Collect elements of base eqc " << eqc << std::endl;
1128
        // members that must be in eqc
1129
3055
        const std::map<Node, Node>& emems = d_state.getMembers(eqc);
1130
3055
        if (!emems.empty())
1131
        {
1132
5398
          TypeNode elementType = eqc.getType().getSetElementType();
1133
6097
          for (const std::pair<const Node, Node>& itmm : emems)
1134
          {
1135
6796
            Trace("sets-model")
1136
3398
                << "m->getRepresentative(" << itmm.first
1137
3398
                << ")= " << m->getRepresentative(itmm.first) << std::endl;
1138
6796
            Node t = nm->mkSingleton(elementType, itmm.first);
1139
3398
            els.push_back(t);
1140
          }
1141
        }
1142
      }
1143
3106
      if (d_card_enabled)
1144
      {
1145
        // make the slack elements for the equivalence class based on set
1146
        // cardinality
1147
163
        d_cardSolver->mkModelValueElementsFor(val, eqc, els, mvals, m);
1148
      }
1149
1150
6212
      Node rep = NormalForm::mkBop(kind::UNION, els, eqc.getType());
1151
3106
      rep = Rewriter::rewrite(rep);
1152
6212
      Trace("sets-model") << "* Assign representative of " << eqc << " to "
1153
3106
                          << rep << std::endl;
1154
3106
      mvals[eqc] = rep;
1155
3106
      if (!m->assertEquality(eqc, rep, true))
1156
      {
1157
        return false;
1158
      }
1159
3106
      m->assertSkeleton(rep);
1160
1161
      // we add the element terms (singletons) as representatives to tell the
1162
      // model builder to evaluate them along with their union (rep).
1163
      // This is needed to account for cases when members and rep are not enough
1164
      // for the model builder to evaluate set terms.
1165
      // e.g.
1166
      // eqc(rep) = [(union (singleton skolem) (singleton 0))]
1167
      // eqc(skolem) = [0]
1168
      // The model builder would fail to evaluate rep as (singleton 0)
1169
      // if (singleton skolem) is not registered as a representative in the
1170
      // model
1171
6624
      for (const Node& el : els)
1172
      {
1173
3518
        m->assertSkeleton(el);
1174
      }
1175
1176
6212
      Trace("sets-model") << "Set " << eqc << " = { " << traceElements(rep)
1177
3106
                          << " }" << std::endl;
1178
    }
1179
  }
1180
1181
  // handle slack elements constraints for finite types
1182
4488
  if (d_card_enabled)
1183
  {
1184
    const std::map<TypeNode, std::vector<TNode> >& slackElements =
1185
65
        d_cardSolver->getFiniteTypeSlackElements();
1186
73
    for (const auto& pair : slackElements)
1187
    {
1188
      const std::vector<Node>& members =
1189
8
          d_cardSolver->getFiniteTypeMembers(pair.first);
1190
8
      m->setAssignmentExclusionSetGroup(pair.second, members);
1191
16
      Trace("sets-model") << "ExclusionSet: Group " << pair.second
1192
8
                          << " is excluded from set" << members << std::endl;
1193
    }
1194
  }
1195
4488
  return true;
1196
}
1197
1198
/********************** Helper functions ***************************/
1199
/********************** Helper functions ***************************/
1200
/********************** Helper functions ***************************/
1201
1202
2069
Node mkAnd(const std::vector<TNode>& conjunctions)
1203
{
1204
2069
  Assert(conjunctions.size() > 0);
1205
1206
4138
  std::set<TNode> all;
1207
8696
  for (unsigned i = 0; i < conjunctions.size(); ++i)
1208
  {
1209
13254
    TNode t = conjunctions[i];
1210
6627
    if (t.getKind() == kind::AND)
1211
    {
1212
549
      for (TNode::iterator child_it = t.begin(); child_it != t.end();
1213
           ++child_it)
1214
      {
1215
366
        Assert((*child_it).getKind() != kind::AND);
1216
366
        all.insert(*child_it);
1217
      }
1218
    }
1219
    else
1220
    {
1221
6444
      all.insert(t);
1222
    }
1223
  }
1224
1225
2069
  Assert(all.size() > 0);
1226
2069
  if (all.size() == 1)
1227
  {
1228
    // All the same, or just one
1229
336
    return conjunctions[0];
1230
  }
1231
1232
3466
  NodeBuilder conjunction(kind::AND);
1233
1733
  std::set<TNode>::const_iterator it = all.begin();
1234
1733
  std::set<TNode>::const_iterator it_end = all.end();
1235
14017
  while (it != it_end)
1236
  {
1237
6142
    conjunction << *it;
1238
6142
    ++it;
1239
  }
1240
1733
  return conjunction;
1241
} /* mkAnd() */
1242
1243
4488
Valuation& TheorySetsPrivate::getValuation() { return d_external.d_valuation; }
1244
1245
2069
Node TheorySetsPrivate::explain(TNode literal)
1246
{
1247
2069
  Debug("sets") << "TheorySetsPrivate::explain(" << literal << ")" << std::endl;
1248
1249
2069
  bool polarity = literal.getKind() != kind::NOT;
1250
4138
  TNode atom = polarity ? literal : literal[0];
1251
4138
  std::vector<TNode> assumptions;
1252
1253
2069
  if (atom.getKind() == kind::EQUAL)
1254
  {
1255
1591
    d_equalityEngine->explainEquality(atom[0], atom[1], polarity, assumptions);
1256
  }
1257
478
  else if (atom.getKind() == kind::MEMBER)
1258
  {
1259
478
    d_equalityEngine->explainPredicate(atom, polarity, assumptions);
1260
  }
1261
  else
1262
  {
1263
    Debug("sets") << "unhandled: " << literal << "; (" << atom << ", "
1264
                  << polarity << "); kind" << atom.getKind() << std::endl;
1265
    Unhandled();
1266
  }
1267
1268
4138
  return mkAnd(assumptions);
1269
}
1270
1271
74839
void TheorySetsPrivate::preRegisterTerm(TNode node)
1272
{
1273
149678
  Debug("sets") << "TheorySetsPrivate::preRegisterTerm(" << node << ")"
1274
74839
                << std::endl;
1275
74839
  switch (node.getKind())
1276
  {
1277
40867
    case kind::EQUAL:
1278
    case kind::MEMBER:
1279
    {
1280
      // add trigger predicate for equality and membership
1281
40867
      d_equalityEngine->addTriggerPredicate(node);
1282
    }
1283
40867
    break;
1284
32
    case kind::JOIN_IMAGE:
1285
    {
1286
      // these are logic exceptions, not type checking exceptions
1287
32
      if (node[1].getKind() != kind::CONST_RATIONAL)
1288
      {
1289
        throw LogicException(
1290
            "JoinImage cardinality constraint must be a constant");
1291
      }
1292
64
      cvc5::Rational r(INT_MAX);
1293
32
      if (node[1].getConst<Rational>() > r)
1294
      {
1295
        throw LogicException(
1296
            "JoinImage Exceeded INT_MAX in cardinality constraint");
1297
      }
1298
32
      if (node[1].getConst<Rational>().getNumerator().getSignedInt() < 0)
1299
      {
1300
        throw LogicException(
1301
            "JoinImage cardinality constraint must be non-negative");
1302
32
      }
1303
    }
1304
32
    break;
1305
33940
    default: d_equalityEngine->addTerm(node); break;
1306
  }
1307
74839
}
1308
1309
45027
TrustNode TheorySetsPrivate::ppRewrite(Node node,
1310
                                       std::vector<SkolemLemma>& lems)
1311
{
1312
45027
  Debug("sets-proc") << "ppRewrite : " << node << std::endl;
1313
1314
45027
  switch (node.getKind())
1315
  {
1316
6
    case kind::CHOOSE: return expandChooseOperator(node, lems);
1317
17
    case kind::IS_SINGLETON: return expandIsSingletonOperator(node);
1318
45004
    default: return TrustNode::null();
1319
  }
1320
}
1321
1322
6
TrustNode TheorySetsPrivate::expandChooseOperator(
1323
    const Node& node, std::vector<SkolemLemma>& lems)
1324
{
1325
6
  Assert(node.getKind() == CHOOSE);
1326
1327
  // (choose A) is expanded as
1328
  // (witness ((x elementType))
1329
  //    (ite
1330
  //      (= A (as emptyset setType))
1331
  //      (= x chooseUf(A))
1332
  //      (and (member x A) (= x chooseUf(A)))
1333
1334
6
  NodeManager* nm = NodeManager::currentNM();
1335
12
  Node set = node[0];
1336
12
  TypeNode setType = set.getType();
1337
12
  Node chooseSkolem = getChooseFunction(setType);
1338
12
  Node apply = NodeManager::currentNM()->mkNode(APPLY_UF, chooseSkolem, set);
1339
1340
12
  Node witnessVariable = nm->mkBoundVar(setType.getSetElementType());
1341
1342
12
  Node equal = witnessVariable.eqNode(apply);
1343
12
  Node emptySet = nm->mkConst(EmptySet(setType));
1344
12
  Node isEmpty = set.eqNode(emptySet);
1345
12
  Node member = nm->mkNode(MEMBER, witnessVariable, set);
1346
12
  Node memberAndEqual = member.andNode(equal);
1347
12
  Node ite = nm->mkNode(ITE, isEmpty, equal, memberAndEqual);
1348
6
  SkolemManager* sm = nm->getSkolemManager();
1349
12
  Node ret = sm->mkSkolem(witnessVariable, ite, "kSetChoose");
1350
6
  lems.push_back(SkolemLemma(ret, nullptr));
1351
12
  return TrustNode::mkTrustRewrite(node, ret, nullptr);
1352
}
1353
1354
17
TrustNode TheorySetsPrivate::expandIsSingletonOperator(const Node& node)
1355
{
1356
17
  Assert(node.getKind() == IS_SINGLETON);
1357
1358
  // we call the rewriter here to handle the pattern
1359
  // (is_singleton (singleton x)) because the rewriter is called after expansion
1360
34
  Node rewritten = Rewriter::rewrite(node);
1361
17
  if (rewritten.getKind() != IS_SINGLETON)
1362
  {
1363
    return TrustNode::mkTrustRewrite(node, rewritten, nullptr);
1364
  }
1365
1366
  // (is_singleton A) is expanded as
1367
  // (exists ((x: T)) (= A (singleton x)))
1368
  // where T is the sort of elements of A
1369
1370
17
  NodeManager* nm = NodeManager::currentNM();
1371
34
  Node set = rewritten[0];
1372
1373
17
  std::map<Node, Node>::iterator it = d_isSingletonNodes.find(rewritten);
1374
1375
17
  if (it != d_isSingletonNodes.end())
1376
  {
1377
    return TrustNode::mkTrustRewrite(rewritten, it->second, nullptr);
1378
  }
1379
1380
34
  TypeNode setType = set.getType();
1381
34
  Node boundVar = nm->mkBoundVar(setType.getSetElementType());
1382
34
  Node singleton = nm->mkSingleton(setType.getSetElementType(), boundVar);
1383
34
  Node equal = set.eqNode(singleton);
1384
34
  std::vector<Node> variables = {boundVar};
1385
34
  Node boundVars = nm->mkNode(BOUND_VAR_LIST, variables);
1386
34
  Node exists = nm->mkNode(kind::EXISTS, boundVars, equal);
1387
17
  d_isSingletonNodes[rewritten] = exists;
1388
1389
17
  return TrustNode::mkTrustRewrite(node, exists, nullptr);
1390
}
1391
1392
6
Node TheorySetsPrivate::getChooseFunction(const TypeNode& setType)
1393
{
1394
6
  std::map<TypeNode, Node>::iterator it = d_chooseFunctions.find(setType);
1395
6
  if (it != d_chooseFunctions.end())
1396
  {
1397
    return it->second;
1398
  }
1399
1400
6
  NodeManager* nm = NodeManager::currentNM();
1401
6
  SkolemManager* sm = nm->getSkolemManager();
1402
12
  TypeNode chooseUf = nm->mkFunctionType(setType, setType.getSetElementType());
1403
12
  stringstream stream;
1404
6
  stream << "chooseUf" << setType.getId();
1405
12
  string name = stream.str();
1406
  Node chooseSkolem = sm->mkDummySkolem(
1407
12
      name, chooseUf, "choose function", NodeManager::SKOLEM_EXACT_NAME);
1408
6
  d_chooseFunctions[setType] = chooseSkolem;
1409
6
  return chooseSkolem;
1410
}
1411
1412
12744
void TheorySetsPrivate::presolve() { d_state.reset(); }
1413
1414
}  // namespace sets
1415
}  // namespace theory
1416
27735
}  // namespace cvc5