GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/strings/base_solver.cpp Lines: 297 378 78.6 %
Date: 2021-05-22 Branches: 626 1595 39.2 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Andres Noetzli, Tianyi Liang
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
 * Base solver for the theory of strings. This class implements term
14
 * indexing and constant inference for the theory of strings.
15
 */
16
17
#include "theory/strings/base_solver.h"
18
19
#include "expr/sequence.h"
20
#include "options/strings_options.h"
21
#include "theory/rewriter.h"
22
#include "theory/strings/theory_strings_utils.h"
23
#include "theory/strings/word.h"
24
25
using namespace std;
26
using namespace cvc5::context;
27
using namespace cvc5::kind;
28
29
namespace cvc5 {
30
namespace theory {
31
namespace strings {
32
33
9460
BaseSolver::BaseSolver(SolverState& s, InferenceManager& im)
34
9460
    : d_state(s), d_im(im), d_congruent(s.getSatContext())
35
{
36
9460
  d_false = NodeManager::currentNM()->mkConst(false);
37
9460
  d_cardSize = utils::getAlphabetCardinality();
38
9460
}
39
40
9460
BaseSolver::~BaseSolver() {}
41
42
25224
void BaseSolver::checkInit()
43
{
44
  // build term index
45
25224
  d_eqcInfo.clear();
46
25224
  d_termIndex.clear();
47
25224
  d_stringsEqc.clear();
48
49
25224
  Trace("strings-base") << "BaseSolver::checkInit" << std::endl;
50
  // count of congruent, non-congruent per operator (independent of type),
51
  // for debugging.
52
50448
  std::map<Kind, std::pair<uint32_t, uint32_t>> congruentCount;
53
25224
  eq::EqualityEngine* ee = d_state.getEqualityEngine();
54
25224
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee);
55
2075496
  while (!eqcs_i.isFinished())
56
  {
57
2050272
    Node eqc = (*eqcs_i);
58
2050272
    TypeNode tn = eqc.getType();
59
1025136
    if (!tn.isRegExp())
60
    {
61
1978446
      Node emps;
62
      // get the term index for type tn
63
989223
      std::map<Kind, TermIndex>& tti = d_termIndex[tn];
64
989223
      if (tn.isStringLike())
65
      {
66
418352
        d_stringsEqc.push_back(eqc);
67
418352
        emps = Word::mkEmptyWord(tn);
68
      }
69
1978446
      Node var;
70
989223
      eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, ee);
71
12840577
      while (!eqc_i.isFinished())
72
      {
73
11851354
        Node n = *eqc_i;
74
5925677
        Kind k = n.getKind();
75
5925677
        Trace("strings-base") << "initialize term: " << n << std::endl;
76
        // process constant-like terms
77
5925677
        if (utils::isConstantLike(n))
78
        {
79
644760
          Node prev = d_eqcInfo[eqc].d_bestContent;
80
322380
          if (!prev.isNull())
81
          {
82
            // we have either (seq.unit x) = C, or (seq.unit x) = (seq.unit y)
83
            // where C is a sequence constant.
84
            Node cval =
85
340
                prev.isConst() ? prev : (n.isConst() ? n : Node::null());
86
340
            std::vector<Node> exp;
87
170
            exp.push_back(prev.eqNode(n));
88
340
            Node s, t;
89
170
            if (cval.isNull())
90
            {
91
              // injectivity of seq.unit
92
32
              s = prev[0];
93
32
              t = n[0];
94
            }
95
            else
96
            {
97
              // should not have two constants in the same equivalence class
98
138
              Assert(cval.getType().isSequence());
99
276
              std::vector<Node> cchars = Word::getChars(cval);
100
138
              if (cchars.size() == 1)
101
              {
102
276
                Node oval = prev.isConst() ? n : prev;
103
138
                Assert(oval.getKind() == SEQ_UNIT);
104
138
                s = oval[0];
105
138
                t = cchars[0].getConst<Sequence>().getVec()[0];
106
                // oval is congruent (ignored) in this context
107
138
                d_congruent.insert(oval);
108
              }
109
              else
110
              {
111
                // (seq.unit x) = C => false if |C| != 1.
112
                d_im.sendInference(
113
                    exp, d_false, InferenceId::STRINGS_UNIT_CONST_CONFLICT);
114
                return;
115
              }
116
            }
117
170
            if (!d_state.areEqual(s, t))
118
            {
119
              // (seq.unit x) = (seq.unit y) => x=y, or
120
              // (seq.unit x) = (seq.unit c) => x=c
121
42
              Assert(s.getType() == t.getType());
122
42
              d_im.sendInference(exp, s.eqNode(t), InferenceId::STRINGS_UNIT_INJ);
123
            }
124
          }
125
          // update best content
126
322380
          if (prev.isNull() || n.isConst())
127
          {
128
322210
            d_eqcInfo[eqc].d_bestContent = n;
129
322210
            d_eqcInfo[eqc].d_bestScore = 0;
130
322210
            d_eqcInfo[eqc].d_base = n;
131
322210
            d_eqcInfo[eqc].d_exp = Node::null();
132
          }
133
        }
134
5925677
        if (tn.isInteger())
135
        {
136
          // do nothing
137
        }
138
        // process indexing
139
4493722
        else if (n.getNumChildren() > 0)
140
        {
141
3252695
          if (k != EQUAL)
142
          {
143
678768
            if (d_congruent.find(n) == d_congruent.end())
144
            {
145
1127572
              std::vector<Node> c;
146
1127572
              Node nc = tti[k].add(n, 0, d_state, emps, c);
147
563786
              if (nc != n)
148
              {
149
79346
                Trace("strings-base-debug")
150
39673
                    << "...found congruent term " << nc << std::endl;
151
                // check if we have inferred a new equality by removal of empty
152
                // components
153
39673
                if (k == STRING_CONCAT && !d_state.areEqual(nc, n))
154
                {
155
2322
                  std::vector<Node> exp;
156
                  // the number of empty components of n, nc
157
1161
                  size_t count[2] = {0, 0};
158
7577
                  while (count[0] < nc.getNumChildren()
159
4369
                         || count[1] < n.getNumChildren())
160
                  {
161
                    // explain empty prefixes
162
9624
                    for (unsigned t = 0; t < 2; t++)
163
                    {
164
12832
                      Node nn = t == 0 ? nc : n;
165
9972
                      while (count[t] < nn.getNumChildren()
166
26360
                             && (nn[count[t]] == emps
167
14178
                                 || d_state.areEqual(nn[count[t]], emps)))
168
                      {
169
1778
                        if (nn[count[t]] != emps)
170
                        {
171
1778
                          exp.push_back(nn[count[t]].eqNode(emps));
172
                        }
173
1778
                        count[t]++;
174
                      }
175
                    }
176
6416
                    Trace("strings-base-debug")
177
3208
                        << "  counts = " << count[0] << ", " << count[1]
178
3208
                        << std::endl;
179
                    // explain equal components
180
3208
                    if (count[0] < nc.getNumChildren())
181
                    {
182
2103
                      Assert(count[1] < n.getNumChildren());
183
2103
                      if (nc[count[0]] != n[count[1]])
184
                      {
185
57
                        exp.push_back(nc[count[0]].eqNode(n[count[1]]));
186
                      }
187
2103
                      count[0]++;
188
2103
                      count[1]++;
189
                    }
190
                  }
191
                  // infer the equality
192
1161
                  d_im.sendInference(exp, n.eqNode(nc), InferenceId::STRINGS_I_NORM);
193
                }
194
                else
195
                {
196
                  // We cannot mark one of the terms as reduced here (via
197
                  // ExtTheory::markCongruent) since extended function terms
198
                  // rely on reductions to other extended function terms. We
199
                  // may have a pair of extended function terms f(a)=f(b) where
200
                  // the reduction of argument a depends on the term b.
201
                  // Thus, marking f(b) as reduced by virtue of the fact we
202
                  // have f(a) is incorrect, since then we are effectively
203
                  // assuming that the reduction of f(a) depends on itself.
204
                }
205
                // this node is congruent to another one, we can ignore it
206
79346
                Trace("strings-base-debug")
207
39673
                    << "  congruent term : " << n << " (via " << nc << ")"
208
39673
                    << std::endl;
209
39673
                d_congruent.insert(n);
210
39673
                congruentCount[k].first++;
211
              }
212
524113
              else if (k == STRING_CONCAT && c.size() == 1)
213
              {
214
30046
                Trace("strings-base-debug")
215
15023
                    << "  congruent term by singular : " << n << " " << c[0]
216
15023
                    << std::endl;
217
                // singular case
218
15023
                if (!d_state.areEqual(c[0], n))
219
                {
220
8902
                  Node ns;
221
8902
                  std::vector<Node> exp;
222
                  // explain empty components
223
4451
                  bool foundNEmpty = false;
224
14498
                  for (const Node& nnc : n)
225
                  {
226
10047
                    if (d_state.areEqual(nnc, emps))
227
                    {
228
5596
                      if (nnc != emps)
229
                      {
230
5596
                        exp.push_back(nnc.eqNode(emps));
231
                      }
232
                    }
233
                    else
234
                    {
235
4451
                      Assert(!foundNEmpty);
236
4451
                      ns = nnc;
237
4451
                      foundNEmpty = true;
238
                    }
239
                  }
240
4451
                  AlwaysAssert(foundNEmpty);
241
                  // infer the equality
242
4451
                  d_im.sendInference(exp, n.eqNode(ns), InferenceId::STRINGS_I_NORM_S);
243
                }
244
15023
                d_congruent.insert(n);
245
15023
                congruentCount[k].first++;
246
              }
247
              else
248
              {
249
509090
                congruentCount[k].second++;
250
              }
251
            }
252
            else
253
            {
254
114982
              congruentCount[k].first++;
255
            }
256
          }
257
        }
258
1241027
        else if (!n.isConst())
259
        {
260
1043054
          if (d_congruent.find(n) == d_congruent.end())
261
          {
262
            // We mark all but the oldest variable in the equivalence class as
263
            // congruent.
264
594997
            if (var.isNull())
265
            {
266
411941
              var = n;
267
            }
268
183056
            else if (var > n)
269
            {
270
193474
              Trace("strings-base-debug")
271
96737
                  << "  congruent variable : " << var << std::endl;
272
96737
              d_congruent.insert(var);
273
96737
              var = n;
274
            }
275
            else
276
            {
277
172638
              Trace("strings-base-debug")
278
86319
                  << "  congruent variable : " << n << std::endl;
279
86319
              d_congruent.insert(n);
280
            }
281
          }
282
        }
283
5925677
        ++eqc_i;
284
      }
285
    }
286
1025136
    ++eqcs_i;
287
  }
288
25224
  if (Trace.isOn("strings-base"))
289
  {
290
    for (const std::pair<const Kind, std::pair<uint32_t, uint32_t>>& cc :
291
         congruentCount)
292
    {
293
      Trace("strings-base")
294
          << "  Terms[" << cc.first << "] = " << cc.second.second << "/"
295
          << (cc.second.first + cc.second.second) << std::endl;
296
    }
297
  }
298
25224
  Trace("strings-base") << "BaseSolver::checkInit finished" << std::endl;
299
}
300
301
22075
void BaseSolver::checkConstantEquivalenceClasses()
302
{
303
  // do fixed point
304
22075
  size_t prevSize = 0;
305
44150
  std::vector<Node> vecc;
306
  do
307
  {
308
22075
    vecc.clear();
309
44150
    Trace("strings-base-debug")
310
22075
        << "Check constant equivalence classes..." << std::endl;
311
22075
    prevSize = d_eqcInfo.size();
312
54143
    for (std::pair<const TypeNode, std::map<Kind, TermIndex>>& tindex :
313
22075
         d_termIndex)
314
    {
315
54143
      checkConstantEquivalenceClasses(
316
108286
          &tindex.second[STRING_CONCAT], vecc, true);
317
    }
318
22075
  } while (!d_im.hasProcessed() && d_eqcInfo.size() > prevSize);
319
320
22075
  if (!d_im.hasProcessed())
321
  {
322
    // now, go back and set "most content" terms
323
22075
    vecc.clear();
324
54143
    for (std::pair<const TypeNode, std::map<Kind, TermIndex>>& tindex :
325
22075
         d_termIndex)
326
    {
327
54143
      checkConstantEquivalenceClasses(
328
108286
          &tindex.second[STRING_CONCAT], vecc, false);
329
    }
330
  }
331
22075
}
332
333
583564
void BaseSolver::checkConstantEquivalenceClasses(TermIndex* ti,
334
                                                 std::vector<Node>& vecc,
335
                                                 bool ensureConst,
336
                                                 bool isConst)
337
{
338
1167128
  Node n = ti->d_data;
339
583564
  if (!n.isNull())
340
  {
341
    // construct the constant if applicable
342
541332
    Node c;
343
270666
    if (isConst)
344
    {
345
64406
      c = utils::mkNConcat(vecc, n.getType());
346
    }
347
270666
    if (!isConst || !d_state.areEqual(n, c))
348
    {
349
206260
      if (Trace.isOn("strings-debug"))
350
      {
351
        Trace("strings-debug")
352
            << "Constant eqc : " << c << " for " << n << std::endl;
353
        Trace("strings-debug") << "  ";
354
        for (const Node& v : vecc)
355
        {
356
          Trace("strings-debug") << v << " ";
357
        }
358
        Trace("strings-debug") << std::endl;
359
      }
360
206260
      size_t count = 0;
361
206260
      size_t countc = 0;
362
412520
      std::vector<Node> exp;
363
      // non-constant vector
364
412520
      std::vector<Node> vecnc;
365
206260
      size_t contentSize = 0;
366
1170204
      while (count < n.getNumChildren())
367
      {
368
        // Add explanations for the empty children
369
963944
        Node emps;
370
512818
        while (count < n.getNumChildren()
371
994790
               && d_state.isEqualEmptyWord(n[count], emps))
372
        {
373
15423
          d_im.addToExplanation(n[count], emps, exp);
374
15423
          count++;
375
        }
376
481972
        if (count < n.getNumChildren())
377
        {
378
471487
          if (vecc[countc].isNull())
379
          {
380
434109
            Assert(!isConst);
381
            // no constant for this component, leave it as is
382
434109
            vecnc.push_back(n[count]);
383
          }
384
          else
385
          {
386
37378
            if (!isConst)
387
            {
388
              // use the constant
389
37378
              vecnc.push_back(vecc[countc]);
390
37378
              Assert(vecc[countc].isConst());
391
37378
              contentSize += Word::getLength(vecc[countc]);
392
            }
393
74756
            Trace("strings-debug") << "...explain " << n[count] << " "
394
37378
                                   << vecc[countc] << std::endl;
395
37378
            if (!d_state.areEqual(n[count], vecc[countc]))
396
            {
397
              Node nrr = d_state.getRepresentative(n[count]);
398
              Assert(!d_eqcInfo[nrr].d_bestContent.isNull()
399
                     && d_eqcInfo[nrr].d_bestContent.isConst());
400
              // must flatten to avoid nested AND in explanations
401
              utils::flattenOp(AND, d_eqcInfo[nrr].d_exp, exp);
402
              // now explain equality to base
403
              d_im.addToExplanation(n[count], d_eqcInfo[nrr].d_base, exp);
404
            }
405
            else
406
            {
407
37378
              d_im.addToExplanation(n[count], vecc[countc], exp);
408
            }
409
37378
            countc++;
410
          }
411
471487
          count++;
412
        }
413
      }
414
      // exp contains an explanation of n==c
415
206260
      Assert(!isConst || countc == vecc.size());
416
206260
      if (!isConst)
417
      {
418
        // no use storing something with no content
419
206260
        if (contentSize > 0)
420
        {
421
69064
          Node nr = d_state.getRepresentative(n);
422
34532
          BaseEqcInfo& bei = d_eqcInfo[nr];
423
69064
          if (!bei.d_bestContent.isConst()
424
34532
              && (bei.d_bestContent.isNull() || contentSize > bei.d_bestScore))
425
          {
426
            // The equivalence class is not entailed to be equal to a constant
427
            // and we found a better concatenation
428
54712
            Node nct = utils::mkNConcat(vecnc, n.getType());
429
27356
            Assert(!nct.isConst());
430
27356
            bei.d_bestContent = nct;
431
27356
            bei.d_bestScore = contentSize;
432
27356
            bei.d_base = n;
433
27356
            if (!exp.empty())
434
            {
435
10797
              bei.d_exp = utils::mkAnd(exp);
436
            }
437
54712
            Trace("strings-debug")
438
27356
                << "Set eqc best content " << n << " to " << nct
439
27356
                << ", explanation = " << bei.d_exp << std::endl;
440
          }
441
        }
442
      }
443
      else if (d_state.hasTerm(c))
444
      {
445
        d_im.sendInference(exp, n.eqNode(c), InferenceId::STRINGS_I_CONST_MERGE);
446
        return;
447
      }
448
      else if (!d_im.hasProcessed())
449
      {
450
        Node nr = d_state.getRepresentative(n);
451
        BaseEqcInfo& bei = d_eqcInfo[nr];
452
        if (!bei.d_bestContent.isConst())
453
        {
454
          bei.d_bestContent = c;
455
          bei.d_base = n;
456
          bei.d_exp = utils::mkAnd(exp);
457
          Trace("strings-debug")
458
              << "Set eqc const " << n << " to " << c
459
              << ", explanation = " << bei.d_exp << std::endl;
460
        }
461
        else if (c != bei.d_bestContent)
462
        {
463
          // conflict
464
          Trace("strings-debug")
465
              << "Conflict, other constant was " << bei.d_bestContent
466
              << ", this constant was " << c << std::endl;
467
          if (bei.d_exp.isNull())
468
          {
469
            // n==c ^ n == c' => false
470
            d_im.addToExplanation(n, bei.d_bestContent, exp);
471
          }
472
          else
473
          {
474
            // n==c ^ n == d_base == c' => false
475
            exp.push_back(bei.d_exp);
476
            d_im.addToExplanation(n, bei.d_base, exp);
477
          }
478
          d_im.sendInference(exp, d_false, InferenceId::STRINGS_I_CONST_CONFLICT);
479
          return;
480
        }
481
        else
482
        {
483
          Trace("strings-debug") << "Duplicate constant." << std::endl;
484
        }
485
      }
486
    }
487
  }
488
1184755
  for (std::pair<const TNode, TermIndex>& p : ti->d_children)
489
  {
490
601191
    std::map<Node, BaseEqcInfo>::const_iterator it = d_eqcInfo.find(p.first);
491
601191
    if (it != d_eqcInfo.end() && it->second.d_bestContent.isConst())
492
    {
493
192378
      vecc.push_back(it->second.d_bestContent);
494
192378
      checkConstantEquivalenceClasses(&p.second, vecc, ensureConst, isConst);
495
192378
      vecc.pop_back();
496
    }
497
408813
    else if (!ensureConst)
498
    {
499
      // can still proceed, with null
500
282900
      vecc.push_back(Node::null());
501
282900
      checkConstantEquivalenceClasses(&p.second, vecc, ensureConst, false);
502
282900
      vecc.pop_back();
503
    }
504
601191
    if (d_im.hasProcessed())
505
    {
506
      break;
507
    }
508
  }
509
}
510
511
7202
void BaseSolver::checkCardinality()
512
{
513
  // This will create a partition of eqc, where each collection has length that
514
  // are pairwise propagated to be equal. We do not require disequalities
515
  // between the lengths of each collection, since we split on disequalities
516
  // between lengths of string terms that are disequal (DEQ-LENGTH-SP).
517
14404
  std::map<TypeNode, std::vector<std::vector<Node> > > cols;
518
14404
  std::map<TypeNode, std::vector<Node> > lts;
519
7202
  d_state.separateByLength(d_stringsEqc, cols, lts);
520
8351
  for (std::pair<const TypeNode, std::vector<std::vector<Node> > >& c : cols)
521
  {
522
1149
    checkCardinalityType(c.first, c.second, lts[c.first]);
523
  }
524
7202
}
525
526
1149
void BaseSolver::checkCardinalityType(TypeNode tn,
527
                                      std::vector<std::vector<Node> >& cols,
528
                                      std::vector<Node>& lts)
529
{
530
2298
  Trace("strings-card") << "Check cardinality (type " << tn << ")..."
531
1149
                        << std::endl;
532
1149
  NodeManager* nm = NodeManager::currentNM();
533
  uint32_t typeCardSize;
534
1149
  if (tn.isString())  // string-only
535
  {
536
1081
    typeCardSize = d_cardSize;
537
  }
538
  else
539
  {
540
68
    Assert(tn.isSequence());
541
136
    TypeNode etn = tn.getSequenceElementType();
542
68
    if (d_state.isFiniteType(etn))
543
    {
544
      // infinite cardinality, we are fine
545
6
      return;
546
    }
547
    // TODO (cvc4-projects #23): how to handle sequence for finite types?
548
62
    return;
549
  }
550
  // for each collection
551
7144
  for (unsigned i = 0, csize = cols.size(); i < csize; ++i)
552
  {
553
6063
    Node lr = lts[i];
554
12126
    Trace("strings-card") << "Number of strings with length equal to " << lr
555
6063
                          << " is " << cols[i].size() << std::endl;
556
6063
    if (cols[i].size() <= 1)
557
    {
558
      // no restriction on sets in the partition of size 1
559
4549
      continue;
560
    }
561
    // size > c^k
562
1514
    unsigned card_need = 1;
563
1514
    double curr = static_cast<double>(cols[i].size());
564
1514
    while (curr > typeCardSize)
565
    {
566
      curr = curr / static_cast<double>(typeCardSize);
567
      card_need++;
568
    }
569
3028
    Trace("strings-card")
570
1514
        << "Need length " << card_need
571
1514
        << " for this number of strings (where alphabet size is "
572
1514
        << typeCardSize << ") given type " << tn << "." << std::endl;
573
    // check if we need to split
574
1514
    bool needsSplit = true;
575
1514
    if (lr.isConst())
576
    {
577
      // if constant, compare
578
2862
      Node cmp = nm->mkNode(GEQ, lr, nm->mkConst(Rational(card_need)));
579
1431
      cmp = Rewriter::rewrite(cmp);
580
1431
      needsSplit = !cmp.getConst<bool>();
581
    }
582
    else
583
    {
584
      // find the minimimum constant that we are unknown to be disequal from, or
585
      // otherwise stop if we increment such that cardinality does not apply.
586
      // We always start with r=1 since by the invariants of our term registry,
587
      // a term is either equal to the empty string, or has length >= 1.
588
83
      unsigned r = 1;
589
83
      bool success = true;
590
83
      while (r < card_need && success)
591
      {
592
        Node rr = nm->mkConst(Rational(r));
593
        if (d_state.areDisequal(rr, lr))
594
        {
595
          r++;
596
        }
597
        else
598
        {
599
          success = false;
600
        }
601
      }
602
83
      if (r > 0)
603
      {
604
166
        Trace("strings-card")
605
83
            << "Symbolic length " << lr << " must be at least " << r
606
83
            << " due to constant disequalities." << std::endl;
607
      }
608
83
      needsSplit = r < card_need;
609
    }
610
611
1514
    if (!needsSplit)
612
    {
613
      // don't need to split
614
1514
      continue;
615
    }
616
    // first, try to split to merge equivalence classes
617
    for (std::vector<Node>::iterator itr1 = cols[i].begin();
618
         itr1 != cols[i].end();
619
         ++itr1)
620
    {
621
      for (std::vector<Node>::iterator itr2 = itr1 + 1; itr2 != cols[i].end();
622
           ++itr2)
623
      {
624
        if (!d_state.areDisequal(*itr1, *itr2))
625
        {
626
          // add split lemma
627
          if (d_im.sendSplit(*itr1, *itr2, InferenceId::STRINGS_CARD_SP))
628
          {
629
            return;
630
          }
631
        }
632
      }
633
    }
634
    // otherwise, we need a length constraint
635
    uint32_t int_k = static_cast<uint32_t>(card_need);
636
    EqcInfo* ei = d_state.getOrMakeEqcInfo(lr, true);
637
    Trace("strings-card") << "Previous cardinality used for " << lr << " is "
638
                          << ((int)ei->d_cardinalityLemK.get() - 1)
639
                          << std::endl;
640
    if (int_k + 1 > ei->d_cardinalityLemK.get())
641
    {
642
      Node k_node = nm->mkConst(Rational(int_k));
643
      // add cardinality lemma
644
      Node dist = nm->mkNode(DISTINCT, cols[i]);
645
      std::vector<Node> expn;
646
      expn.push_back(dist);
647
      for (std::vector<Node>::iterator itr1 = cols[i].begin();
648
           itr1 != cols[i].end();
649
           ++itr1)
650
      {
651
        Node len = nm->mkNode(STRING_LENGTH, *itr1);
652
        if (len != lr)
653
        {
654
          Node len_eq_lr = len.eqNode(lr);
655
          expn.push_back(len_eq_lr);
656
        }
657
      }
658
      Node len = nm->mkNode(STRING_LENGTH, cols[i][0]);
659
      Node cons = nm->mkNode(GEQ, len, k_node);
660
      cons = Rewriter::rewrite(cons);
661
      ei->d_cardinalityLemK.set(int_k + 1);
662
      if (!cons.isConst() || !cons.getConst<bool>())
663
      {
664
        d_im.sendInference(
665
            expn, expn, cons, InferenceId::STRINGS_CARDINALITY, false, true);
666
        return;
667
      }
668
    }
669
  }
670
1081
  Trace("strings-card") << "...end check cardinality" << std::endl;
671
}
672
673
2030688
bool BaseSolver::isCongruent(Node n)
674
{
675
2030688
  return d_congruent.find(n) != d_congruent.end();
676
}
677
678
1051191
Node BaseSolver::getConstantEqc(Node eqc)
679
{
680
1051191
  std::map<Node, BaseEqcInfo>::const_iterator it = d_eqcInfo.find(eqc);
681
1051191
  if (it != d_eqcInfo.end() && it->second.d_bestContent.isConst())
682
  {
683
366487
    return it->second.d_bestContent;
684
  }
685
684704
  return Node::null();
686
}
687
688
38810
Node BaseSolver::explainConstantEqc(Node n, Node eqc, std::vector<Node>& exp)
689
{
690
38810
  std::map<Node, BaseEqcInfo>::const_iterator it = d_eqcInfo.find(eqc);
691
38810
  if (it != d_eqcInfo.end())
692
  {
693
38810
    BaseEqcInfo& bei = d_eqcInfo[eqc];
694
38810
    if (!bei.d_bestContent.isConst())
695
    {
696
      return Node::null();
697
    }
698
38810
    if (!bei.d_exp.isNull())
699
    {
700
      utils::flattenOp(AND, bei.d_exp, exp);
701
    }
702
38810
    if (!bei.d_base.isNull())
703
    {
704
38810
      d_im.addToExplanation(n, bei.d_base, exp);
705
    }
706
38810
    return bei.d_bestContent;
707
  }
708
  return Node::null();
709
}
710
711
545454
Node BaseSolver::explainBestContentEqc(Node n, Node eqc, std::vector<Node>& exp)
712
{
713
545454
  std::map<Node, BaseEqcInfo>::const_iterator it = d_eqcInfo.find(eqc);
714
545454
  if (it != d_eqcInfo.end())
715
  {
716
314142
    BaseEqcInfo& bei = d_eqcInfo[eqc];
717
314142
    Assert(!bei.d_bestContent.isNull());
718
314142
    if (!bei.d_exp.isNull())
719
    {
720
27471
      utils::flattenOp(AND, bei.d_exp, exp);
721
    }
722
314142
    if (!bei.d_base.isNull())
723
    {
724
314142
      d_im.addToExplanation(n, bei.d_base, exp);
725
    }
726
314142
    return bei.d_bestContent;
727
  }
728
729
231312
  return Node::null();
730
}
731
732
21807
const std::vector<Node>& BaseSolver::getStringEqc() const
733
{
734
21807
  return d_stringsEqc;
735
}
736
737
1903066
Node BaseSolver::TermIndex::add(TNode n,
738
                                unsigned index,
739
                                const SolverState& s,
740
                                Node er,
741
                                std::vector<Node>& c)
742
{
743
1903066
  if (index == n.getNumChildren())
744
  {
745
563786
    if (d_data.isNull())
746
    {
747
524113
      d_data = n;
748
    }
749
563786
    return d_data;
750
  }
751
1339280
  Assert(index < n.getNumChildren());
752
2678560
  TNode nir = s.getRepresentative(n[index]);
753
  // if it is empty, and doing CONCAT, ignore
754
1339280
  if (nir == er && n.getKind() == STRING_CONCAT)
755
  {
756
88799
    return add(n, index + 1, s, er, c);
757
  }
758
1250481
  c.push_back(nir);
759
1250481
  return d_children[nir].add(n, index + 1, s, er, c);
760
}
761
762
}  // namespace strings
763
}  // namespace theory
764
28194
}  // namespace cvc5