GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sets/theory_sets_private.cpp Lines: 670 713 94.0 %
Date: 2021-05-22 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
9460
TheorySetsPrivate::TheorySetsPrivate(TheorySets& external,
39
                                     SolverState& state,
40
                                     InferenceManager& im,
41
                                     SkolemCache& skc,
42
9460
                                     ProofNodeManager* pnm)
43
    : d_deq(state.getSatContext()),
44
9460
      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
9460
      d_rels(new TheorySetsRels(state, im, skc, d_treg)),
53
9460
      d_cardSolver(new CardinalityExtension(state, im, d_treg)),
54
      d_rels_enabled(false),
55
37840
      d_card_enabled(false)
56
{
57
9460
  d_true = NodeManager::currentNM()->mkConst(true);
58
9460
  d_false = NodeManager::currentNM()->mkConst(false);
59
9460
  d_zero = NodeManager::currentNM()->mkConst(Rational(0));
60
9460
}
61
62
18920
TheorySetsPrivate::~TheorySetsPrivate()
63
{
64
14349
  for (std::pair<const Node, EqcInfo*>& current_pair : d_eqc_info)
65
  {
66
4889
    delete current_pair.second;
67
  }
68
9460
}
69
70
9460
void TheorySetsPrivate::finishInit()
71
{
72
9460
  d_equalityEngine = d_external.getEqualityEngine();
73
9460
  Assert(d_equalityEngine != nullptr);
74
9460
}
75
76
73251
void TheorySetsPrivate::eqNotifyNewClass(TNode t)
77
{
78
73251
  if (t.getKind() == kind::SINGLETON || t.getKind() == kind::EMPTYSET)
79
  {
80
3698
    EqcInfo* e = getOrMakeEqcInfo(t, true);
81
3698
    e->d_singleton = t;
82
  }
83
73251
}
84
85
197225
void TheorySetsPrivate::eqNotifyMerge(TNode t1, TNode t2)
86
{
87
197225
  if (!d_state.isInConflict())
88
  {
89
394438
    Trace("sets-prop-debug")
90
197219
        << "Merge " << t1 << " and " << t2 << "..." << std::endl;
91
394273
    Node s1, s2;
92
197219
    EqcInfo* e2 = getOrMakeEqcInfo(t2);
93
197219
    if (e2)
94
    {
95
15137
      s2 = e2->d_singleton;
96
15137
      EqcInfo* e1 = getOrMakeEqcInfo(t1);
97
15137
      Trace("sets-prop-debug") << "Merging singletons..." << std::endl;
98
15137
      if (e1)
99
      {
100
15006
        s1 = e1->d_singleton;
101
15006
        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
197148
    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
394202
    Node checkSingleton = s2.isNull() ? s1 : Node::null();
134
394202
    std::vector<Node> facts;
135
    // merge the membership list in the state, which may produce facts or
136
    // conflicts to propagate
137
197148
    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
197198
    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
26756
void TheorySetsPrivate::eqNotifyDisequal(TNode t1, TNode t2, TNode reason)
157
{
158
26756
  if (t1.getType().isSet())
159
  {
160
26124
    Node eq = t1.eqNode(t2);
161
13062
    if (d_deq.find(eq) == d_deq.end())
162
    {
163
13062
      d_deq[eq] = true;
164
    }
165
  }
166
26756
}
167
168
4889
TheorySetsPrivate::EqcInfo::EqcInfo(context::Context* c) : d_singleton(c) {}
169
170
270136
TheorySetsPrivate::EqcInfo* TheorySetsPrivate::getOrMakeEqcInfo(TNode n,
171
                                                                bool doMake)
172
{
173
270136
  std::map<Node, EqcInfo*>::iterator eqc_i = d_eqc_info.find(n);
174
270136
  if (eqc_i == d_eqc_info.end())
175
  {
176
187102
    EqcInfo* ei = NULL;
177
187102
    if (doMake)
178
    {
179
4889
      ei = new EqcInfo(d_external.getSatContext());
180
4889
      d_eqc_info[n] = ei;
181
    }
182
187102
    return ei;
183
  }
184
  else
185
  {
186
83034
    return eqc_i->second;
187
  }
188
}
189
190
35638
bool TheorySetsPrivate::areCareDisequal(Node a, Node b)
191
{
192
106914
  if (d_equalityEngine->isTriggerTerm(a, THEORY_SETS)
193
106914
      && d_equalityEngine->isTriggerTerm(b, THEORY_SETS))
194
  {
195
    TNode a_shared =
196
33771
        d_equalityEngine->getTriggerTermRepresentative(a, THEORY_SETS);
197
    TNode b_shared =
198
33771
        d_equalityEngine->getTriggerTermRepresentative(b, THEORY_SETS);
199
    EqualityStatus eqStatus =
200
21126
        d_external.d_valuation.getEqualityStatus(a_shared, b_shared);
201
21126
    if (eqStatus == EQUALITY_FALSE_AND_PROPAGATED || eqStatus == EQUALITY_FALSE
202
21126
        || eqStatus == EQUALITY_FALSE_IN_MODEL)
203
    {
204
8481
      return true;
205
    }
206
  }
207
27157
  return false;
208
}
209
210
16920
void TheorySetsPrivate::fullEffortReset()
211
{
212
16920
  Assert(d_equalityEngine->consistent());
213
16920
  d_fullCheckIncomplete = false;
214
16920
  d_fullCheckIncompleteId = IncompleteId::UNKNOWN;
215
16920
  d_most_common_type.clear();
216
16920
  d_most_common_type_term.clear();
217
16920
  d_card_enabled = false;
218
16920
  d_rels_enabled = false;
219
  // reset the state object
220
16920
  d_state.reset();
221
  // reset the inference manager
222
16920
  d_im.reset();
223
16920
  d_im.clearPendingLemmas();
224
  // reset the cardinality solver
225
16920
  d_cardSolver->reset();
226
16920
}
227
228
16920
void TheorySetsPrivate::fullEffortCheck()
229
{
230
16920
  Trace("sets") << "----- Full effort check ------" << std::endl;
231
  do
232
  {
233
16920
    Assert(!d_im.hasPendingLemma() || d_im.hasSent());
234
235
16920
    Trace("sets") << "...iterate full effort check..." << std::endl;
236
16920
    fullEffortReset();
237
238
16920
    Trace("sets-eqc") << "Equality Engine:" << std::endl;
239
29458
    std::map<TypeNode, unsigned> eqcTypeCount;
240
16920
    eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine);
241
319526
    while (!eqcs_i.isFinished())
242
    {
243
302606
      Node eqc = (*eqcs_i);
244
151303
      bool isSet = false;
245
302606
      TypeNode tn = eqc.getType();
246
151303
      d_state.registerEqc(tn, eqc);
247
151303
      eqcTypeCount[tn]++;
248
      // common type node and term
249
302606
      TypeNode tnc;
250
302606
      Node tnct;
251
151303
      if (tn.isSet())
252
      {
253
54189
        isSet = true;
254
54189
        tnc = tn.getSetElementType();
255
54189
        tnct = eqc;
256
      }
257
151303
      Trace("sets-eqc") << "[" << eqc << "] : ";
258
151303
      eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, d_equalityEngine);
259
1170727
      while (!eqc_i.isFinished())
260
      {
261
1020522
        Node n = (*eqc_i);
262
510810
        if (n != eqc)
263
        {
264
359507
          Trace("sets-eqc") << n << " (" << n.isConst() << ") ";
265
        }
266
1020522
        TypeNode tnn = n.getType();
267
510810
        if (isSet)
268
        {
269
139681
          Assert(tnn.isSet());
270
279362
          TypeNode tnnel = tnn.getSetElementType();
271
139681
          tnc = TypeNode::mostCommonTypeNode(tnc, tnnel);
272
139681
          Assert(!tnc.isNull());
273
          // update the common type term
274
139681
          if (tnc == tnnel)
275
          {
276
139681
            tnct = n;
277
          }
278
        }
279
        // register it with the state
280
510810
        d_state.registerTerm(eqc, tnn, n);
281
510810
        Kind nk = n.getKind();
282
510810
        if (nk == kind::SINGLETON)
283
        {
284
          // ensure the proxy has been introduced
285
10285
          d_treg.getProxy(n);
286
        }
287
500525
        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
450400
        else if (d_rels->isRelationKind(nk))
317
        {
318
2242
          d_rels_enabled = true;
319
        }
320
509712
        ++eqc_i;
321
      }
322
151303
      if (isSet)
323
      {
324
54189
        Assert(tnct.getType().getSetElementType() == tnc);
325
54189
        d_most_common_type[eqc] = tnc;
326
54189
        d_most_common_type_term[eqc] = tnct;
327
      }
328
151303
      Trace("sets-eqc") << std::endl;
329
151303
      ++eqcs_i;
330
    }
331
332
16920
    Trace("sets-eqc") << "...finished equality engine." << std::endl;
333
334
16920
    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
16920
    if (d_im.hasSent())
347
    {
348
529
      continue;
349
    }
350
16391
    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
16391
    d_im.doPendingLemmas();
374
16391
    if (d_im.hasSent())
375
    {
376
      continue;
377
    }
378
    // check downwards closure
379
16391
    checkDownwardsClosure();
380
16391
    d_im.doPendingLemmas();
381
16391
    if (d_im.hasSent())
382
    {
383
540
      continue;
384
    }
385
    // check upwards closure
386
15851
    checkUpwardsClosure();
387
15851
    d_im.doPendingLemmas();
388
15851
    if (d_im.hasSent())
389
    {
390
1128
      continue;
391
    }
392
    // check disequalities
393
14723
    checkDisequalities();
394
14723
    d_im.doPendingLemmas();
395
14723
    if (d_im.hasSent())
396
    {
397
590
      continue;
398
    }
399
    // check reduce comprehensions
400
14133
    checkReduceComprehensions();
401
402
14133
    d_im.doPendingLemmas();
403
14133
    if (d_im.hasSent())
404
    {
405
18
      continue;
406
    }
407
14115
    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
12537
    if (d_rels_enabled)
417
    {
418
      // call the check method of the relations solver
419
737
      d_rels->check(Theory::EFFORT_FULL);
420
    }
421
28843
  } while (!d_im.hasSentLemma() && !d_state.isInConflict()
422
28843
           && d_im.hasSentFact());
423
16919
  Assert(!d_im.hasPendingLemma() || d_im.hasSent());
424
33838
  Trace("sets") << "----- End full effort check, conflict="
425
33838
                << d_state.isInConflict() << ", lemma=" << d_im.hasSentLemma()
426
16919
                << std::endl;
427
16919
}
428
429
16391
void TheorySetsPrivate::checkDownwardsClosure()
430
{
431
16391
  Trace("sets") << "TheorySetsPrivate: check downwards closure..." << std::endl;
432
  // downwards closure
433
16391
  const std::vector<Node>& sec = d_state.getSetsEqClasses();
434
65271
  for (const Node& s : sec)
435
  {
436
48880
    const std::vector<Node>& nvsets = d_state.getNonVariableSets(s);
437
48880
    if (!nvsets.empty())
438
    {
439
36530
      const std::map<Node, Node>& smem = d_state.getMembers(s);
440
96301
      for (const Node& nv : nvsets)
441
      {
442
59771
        if (!d_state.isCongruent(nv))
443
        {
444
107956
          for (const std::pair<const Node, Node>& it2 : smem)
445
          {
446
106128
            Node mem = it2.second;
447
106128
            Node eq_set = nv;
448
53064
            Assert(d_equalityEngine->areEqual(mem[1], eq_set));
449
53064
            if (mem[1] != eq_set)
450
            {
451
103318
              Trace("sets-debug") << "Downwards closure based on " << mem
452
51659
                                  << ", eq_set = " << eq_set << std::endl;
453
103318
              if (!options::setsProxyLemmas())
454
              {
455
                Node nmem = NodeManager::currentNM()->mkNode(
456
103318
                    kind::MEMBER, mem[0], eq_set);
457
51659
                nmem = Rewriter::rewrite(nmem);
458
103318
                std::vector<Node> exp;
459
51659
                exp.push_back(mem);
460
51659
                exp.push_back(mem[1].eqNode(eq_set));
461
51659
                d_im.assertInference(nmem, InferenceId::SETS_DOWN_CLOSURE, exp);
462
51659
                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
15851
void TheorySetsPrivate::checkUpwardsClosure()
497
{
498
  // upwards closure
499
15851
  NodeManager* nm = NodeManager::currentNM();
500
  const std::map<Kind, std::map<Node, std::map<Node, Node> > >& boi =
501
15851
      d_state.getBinaryOpIndex();
502
7860
  for (const std::pair<const Kind, std::map<Node, std::map<Node, Node> > >&
503
15851
           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
15851
  if (!d_im.hasSent())
633
  {
634
15400
    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
14723
void TheorySetsPrivate::checkDisequalities()
694
{
695
  // disequalities
696
14723
  Trace("sets") << "TheorySetsPrivate: check disequalities..." << std::endl;
697
14723
  NodeManager* nm = NodeManager::currentNM();
698
24044
  for (NodeBoolMap::const_iterator it = d_deq.begin(); it != d_deq.end(); ++it)
699
  {
700
9911
    if (!(*it).second)
701
    {
702
      // not active
703
12461
      continue;
704
    }
705
6771
    Node deq = (*it).first;
706
    // check if it is already satisfied
707
6771
    Assert(d_equalityEngine->hasTerm(deq[0])
708
           && d_equalityEngine->hasTerm(deq[1]));
709
6771
    Node r1 = d_equalityEngine->getRepresentative(deq[0]);
710
6771
    Node r2 = d_equalityEngine->getRepresentative(deq[1]);
711
6771
    bool is_sat = d_state.isSetDisequalityEntailed(r1, r2);
712
13542
    Trace("sets-debug") << "Check disequality " << deq
713
6771
                        << ", is_sat = " << is_sat << std::endl;
714
    // will process regardless of sat/processed/unprocessed
715
6771
    d_deq[deq] = false;
716
717
6771
    if (is_sat)
718
    {
719
      // already satisfied
720
6034
      continue;
721
    }
722
737
    if (d_termProcessed.find(deq) != d_termProcessed.end())
723
    {
724
      // already added lemma
725
147
      continue;
726
    }
727
590
    d_termProcessed.insert(deq);
728
590
    d_termProcessed.insert(deq[1].eqNode(deq[0]));
729
590
    Trace("sets") << "Process Disequality : " << deq.negate() << std::endl;
730
590
    TypeNode elementType = deq[0].getType().getSetElementType();
731
590
    Node x = d_skCache.mkTypedSkolemCached(
732
590
        elementType, deq[0], deq[1], SkolemCache::SK_DISEQUAL, "sde");
733
590
    Node mem1 = nm->mkNode(MEMBER, x, deq[0]);
734
590
    Node mem2 = nm->mkNode(MEMBER, x, deq[1]);
735
590
    Node lem = nm->mkNode(OR, deq, nm->mkNode(EQUAL, mem1, mem2).negate());
736
590
    lem = Rewriter::rewrite(lem);
737
590
    d_im.assertInference(lem, InferenceId::SETS_DEQ, d_true, 1);
738
590
    d_im.doPendingLemmas();
739
590
    if (d_im.hasSent())
740
    {
741
590
      return;
742
    }
743
  }
744
}
745
746
14133
void TheorySetsPrivate::checkReduceComprehensions()
747
{
748
14133
  NodeManager* nm = NodeManager::currentNM();
749
14133
  const std::vector<Node>& comps = d_state.getComprehensionSets();
750
14201
  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
14133
}
780
781
//--------------------------------- standard check
782
783
87926
void TheorySetsPrivate::postCheck(Theory::Effort level)
784
{
785
175852
  Trace("sets-check") << "Sets finished assertions effort " << level
786
87926
                      << std::endl;
787
  // invoke full effort check, relations check
788
87926
  if (!d_state.isInConflict())
789
  {
790
83190
    if (level == Theory::EFFORT_FULL)
791
    {
792
21203
      if (!d_external.d_valuation.needCheck())
793
      {
794
16920
        fullEffortCheck();
795
50757
        if (!d_state.isInConflict() && !d_im.hasSentLemma()
796
28843
            && d_fullCheckIncomplete)
797
        {
798
4
          d_im.setIncomplete(d_fullCheckIncompleteId);
799
        }
800
      }
801
    }
802
  }
803
87925
  Trace("sets-check") << "Sets finish Check effort " << level << std::endl;
804
87925
}
805
806
183854
void TheorySetsPrivate::notifyFact(TNode atom, bool polarity, TNode fact)
807
{
808
183854
  if (d_state.isInConflict())
809
  {
810
4589
    return;
811
  }
812
179265
  if (atom.getKind() == kind::MEMBER && polarity)
813
  {
814
    // check if set has a value, if so, we can propagate
815
107902
    Node r = d_equalityEngine->getRepresentative(atom[1]);
816
53951
    EqcInfo* e = getOrMakeEqcInfo(r, true);
817
53951
    if (e)
818
    {
819
107902
      Node s = e->d_singleton;
820
53951
      if (!s.isNull())
821
      {
822
        Node pexp = NodeManager::currentNM()->mkNode(
823
5110
            kind::AND, atom, atom[1].eqNode(s));
824
2555
        if (s.getKind() == kind::SINGLETON)
825
        {
826
2408
          if (s[0] != atom[0])
827
          {
828
415
            Trace("sets-prop") << "Propagate mem-eq : " << pexp << std::endl;
829
830
            Node eq = s[0].eqNode(atom[0]);
830
            // triggers an internal inference
831
415
            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
53951
    d_state.addMember(r, atom);
844
  }
845
}
846
//--------------------------------- end standard check
847
848
/************************ Sharing ************************/
849
/************************ Sharing ************************/
850
/************************ Sharing ************************/
851
852
15780
void TheorySetsPrivate::addCarePairs(TNodeTrie* t1,
853
                                     TNodeTrie* t2,
854
                                     unsigned arity,
855
                                     unsigned depth,
856
                                     unsigned& n_pairs)
857
{
858
15780
  if (depth == arity)
859
  {
860
8955
    if (t2 != NULL)
861
    {
862
17910
      Node f1 = t1->getData();
863
17910
      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
8955
      if (f1.getKind() == MEMBER || !d_state.areEqual(f1, f2))
875
      {
876
8955
        Trace("sets-cg") << "Check " << f1 << " and " << f2 << std::endl;
877
17910
        vector<pair<TNode, TNode> > currentPairs;
878
26444
        for (unsigned k = 0; k < f1.getNumChildren(); ++k)
879
        {
880
34978
          TNode x = f1[k];
881
34978
          TNode y = f2[k];
882
17489
          Assert(d_equalityEngine->hasTerm(x));
883
17489
          Assert(d_equalityEngine->hasTerm(y));
884
17489
          Assert(!d_state.areDisequal(x, y));
885
17489
          Assert(!areCareDisequal(x, y));
886
17489
          if (!d_equalityEngine->areEqual(x, y))
887
          {
888
20658
            Trace("sets-cg")
889
10329
                << "Arg #" << k << " is " << x << " " << y << std::endl;
890
30987
            if (d_equalityEngine->isTriggerTerm(x, THEORY_SETS)
891
30987
                && 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
7191
            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
12093
        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
6825
    if (t2 == NULL)
928
    {
929
6112
      if (depth < (arity - 1))
930
      {
931
        // add care pairs internal to each child
932
5585
        for (std::pair<const TNode, TNodeTrie>& t : t1->d_data)
933
        {
934
4594
          addCarePairs(&t.second, NULL, arity, depth + 1, n_pairs);
935
        }
936
      }
937
      // add care pairs based on each pair of non-disequal arguments
938
21151
      for (std::map<TNode, TNodeTrie>::iterator it = t1->d_data.begin();
939
21151
           it != t1->d_data.end();
940
           ++it)
941
      {
942
15039
        std::map<TNode, TNodeTrie>::iterator it2 = it;
943
15039
        ++it2;
944
144125
        for (; it2 != t1->d_data.end(); ++it2)
945
        {
946
64543
          if (!d_equalityEngine->areDisequal(it->first, it2->first, false))
947
          {
948
16560
            if (!areCareDisequal(it->first, it2->first))
949
            {
950
24237
              addCarePairs(
951
16158
                  &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
15780
}
976
977
6056
void TheorySetsPrivate::computeCareGraph()
978
{
979
6056
  const std::map<Kind, std::vector<Node> >& ol = d_state.getOperatorList();
980
7935
  for (const std::pair<const Kind, std::vector<Node> >& it : ol)
981
  {
982
1879
    Kind k = it.first;
983
1879
    if (k == kind::SINGLETON || k == kind::MEMBER)
984
    {
985
1220
      unsigned n_pairs = 0;
986
2440
      Trace("sets-cg-summary") << "Compute graph for sets, op=" << k << "..."
987
1220
                               << it.second.size() << std::endl;
988
1220
      Trace("sets-cg") << "Build index for " << k << "..." << std::endl;
989
2440
      std::map<TypeNode, TNodeTrie> index;
990
1220
      unsigned arity = 0;
991
      // populate indices
992
11665
      for (TNode f1 : it.second)
993
      {
994
10445
        Trace("sets-cg-debug") << "...build for " << f1 << std::endl;
995
10445
        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
20890
        TypeNode tn;
999
10445
        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
7915
          Assert (k == kind::MEMBER);
1007
          // get the element type of the set (not the type of the element)
1008
7915
          tn = f1[1].getType().getSetElementType();
1009
        }
1010
20890
        std::vector<TNode> reps;
1011
10445
        bool hasCareArg = false;
1012
28805
        for (unsigned j = 0; j < f1.getNumChildren(); j++)
1013
        {
1014
18360
          reps.push_back(d_equalityEngine->getRepresentative(f1[j]));
1015
18360
          if (isCareArg(f1, j))
1016
          {
1017
14341
            hasCareArg = true;
1018
          }
1019
        }
1020
10445
        if (hasCareArg)
1021
        {
1022
10445
          Trace("sets-cg-debug") << "......adding." << std::endl;
1023
10445
          index[tn].addTerm(f1, reps);
1024
10445
          arity = reps.size();
1025
        }
1026
        else
1027
        {
1028
          Trace("sets-cg-debug") << "......skip." << std::endl;
1029
        }
1030
      }
1031
1220
      if (arity > 0)
1032
      {
1033
        // for each index
1034
2738
        for (std::pair<const TypeNode, TNodeTrie>& tt : index)
1035
        {
1036
3036
          Trace("sets-cg") << "Process index " << tt.first << "..."
1037
1518
                           << std::endl;
1038
1518
          addCarePairs(&tt.second, nullptr, arity, 0, n_pairs);
1039
        }
1040
      }
1041
1220
      Trace("sets-cg-summary") << "...done, # pairs = " << n_pairs << std::endl;
1042
    }
1043
  }
1044
6056
}
1045
1046
28436
bool TheorySetsPrivate::isCareArg(Node n, unsigned a)
1047
{
1048
28436
  if (d_equalityEngine->isTriggerTerm(n[a], THEORY_SETS))
1049
  {
1050
17212
    return true;
1051
  }
1052
22448
  else if ((n.getKind() == kind::MEMBER || n.getKind() == kind::SINGLETON)
1053
33672
           && a == 0 && n[0].getType().isSet())
1054
  {
1055
20
    return true;
1056
  }
1057
  else
1058
  {
1059
11204
    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
4505
bool TheorySetsPrivate::collectModelValues(TheoryModel* m,
1098
                                           const std::set<Node>& termSet)
1099
{
1100
4505
  Trace("sets-model") << "Set collect model values" << std::endl;
1101
1102
4505
  NodeManager* nm = NodeManager::currentNM();
1103
9010
  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
4505
  const std::vector<Node>& sec = d_card_enabled
1109
8945
                                     ? d_cardSolver->getOrderedSetsEqClasses()
1110
8945
                                     : d_state.getSetsEqClasses();
1111
4505
  Valuation& val = getValuation();
1112
7653
  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
4505
  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
4505
  return true;
1196
}
1197
1198
/********************** Helper functions ***************************/
1199
/********************** Helper functions ***************************/
1200
/********************** Helper functions ***************************/
1201
1202
2143
Node mkAnd(const std::vector<TNode>& conjunctions)
1203
{
1204
2143
  Assert(conjunctions.size() > 0);
1205
1206
4286
  std::set<TNode> all;
1207
8959
  for (unsigned i = 0; i < conjunctions.size(); ++i)
1208
  {
1209
13632
    TNode t = conjunctions[i];
1210
6816
    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
6633
      all.insert(t);
1222
    }
1223
  }
1224
1225
2143
  Assert(all.size() > 0);
1226
2143
  if (all.size() == 1)
1227
  {
1228
    // All the same, or just one
1229
340
    return conjunctions[0];
1230
  }
1231
1232
3606
  NodeBuilder conjunction(kind::AND);
1233
1803
  std::set<TNode>::const_iterator it = all.begin();
1234
1803
  std::set<TNode>::const_iterator it_end = all.end();
1235
14455
  while (it != it_end)
1236
  {
1237
6326
    conjunction << *it;
1238
6326
    ++it;
1239
  }
1240
1803
  return conjunction;
1241
} /* mkAnd() */
1242
1243
4505
Valuation& TheorySetsPrivate::getValuation() { return d_external.d_valuation; }
1244
1245
2143
Node TheorySetsPrivate::explain(TNode literal)
1246
{
1247
2143
  Debug("sets") << "TheorySetsPrivate::explain(" << literal << ")" << std::endl;
1248
1249
2143
  bool polarity = literal.getKind() != kind::NOT;
1250
4286
  TNode atom = polarity ? literal : literal[0];
1251
4286
  std::vector<TNode> assumptions;
1252
1253
2143
  if (atom.getKind() == kind::EQUAL)
1254
  {
1255
1595
    d_equalityEngine->explainEquality(atom[0], atom[1], polarity, assumptions);
1256
  }
1257
548
  else if (atom.getKind() == kind::MEMBER)
1258
  {
1259
548
    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
4286
  return mkAnd(assumptions);
1269
}
1270
1271
75286
void TheorySetsPrivate::preRegisterTerm(TNode node)
1272
{
1273
150572
  Debug("sets") << "TheorySetsPrivate::preRegisterTerm(" << node << ")"
1274
75286
                << std::endl;
1275
75286
  switch (node.getKind())
1276
  {
1277
41120
    case kind::EQUAL:
1278
    case kind::MEMBER:
1279
    {
1280
      // add trigger predicate for equality and membership
1281
41120
      d_equalityEngine->addTriggerPredicate(node);
1282
    }
1283
41120
    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
34134
    default: d_equalityEngine->addTerm(node); break;
1306
  }
1307
75286
}
1308
1309
45417
TrustNode TheorySetsPrivate::ppRewrite(Node node,
1310
                                       std::vector<SkolemLemma>& lems)
1311
{
1312
45417
  Debug("sets-proc") << "ppRewrite : " << node << std::endl;
1313
1314
45417
  switch (node.getKind())
1315
  {
1316
6
    case kind::CHOOSE: return expandChooseOperator(node, lems);
1317
17
    case kind::IS_SINGLETON: return expandIsSingletonOperator(node);
1318
45394
    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
14310
void TheorySetsPrivate::presolve() { d_state.reset(); }
1413
1414
}  // namespace sets
1415
}  // namespace theory
1416
28194
}  // namespace cvc5