GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/strings/base_solver.cpp Lines: 331 387 85.5 %
Date: 2021-11-07 Branches: 685 1629 42.1 %

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/quantifiers_options.h"
21
#include "options/strings_options.h"
22
#include "theory/rewriter.h"
23
#include "theory/strings/theory_strings_utils.h"
24
#include "theory/strings/word.h"
25
#include "util/rational.h"
26
27
using namespace std;
28
using namespace cvc5::context;
29
using namespace cvc5::kind;
30
31
namespace cvc5 {
32
namespace theory {
33
namespace strings {
34
35
15273
BaseSolver::BaseSolver(Env& env, SolverState& s, InferenceManager& im)
36
15273
    : EnvObj(env), d_state(s), d_im(im), d_congruent(context())
37
{
38
15273
  d_false = NodeManager::currentNM()->mkConst(false);
39
15273
  d_cardSize = options().strings.stringsAlphaCard;
40
15273
}
41
42
15268
BaseSolver::~BaseSolver() {}
43
44
44123
void BaseSolver::checkInit()
45
{
46
  // build term index
47
44123
  d_eqcInfo.clear();
48
44123
  d_termIndex.clear();
49
44123
  d_stringsEqc.clear();
50
51
44123
  Trace("strings-base") << "BaseSolver::checkInit" << std::endl;
52
  // count of congruent, non-congruent per operator (independent of type),
53
  // for debugging.
54
88246
  std::map<Kind, std::pair<uint32_t, uint32_t>> congruentCount;
55
44123
  eq::EqualityEngine* ee = d_state.getEqualityEngine();
56
44123
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee);
57
4439777
  while (!eqcs_i.isFinished())
58
  {
59
4395654
    Node eqc = (*eqcs_i);
60
4395654
    TypeNode tn = eqc.getType();
61
2197827
    if (!tn.isRegExp())
62
    {
63
4030498
      Node emps;
64
      // get the term index for type tn
65
2015249
      std::map<Kind, TermIndex>& tti = d_termIndex[tn];
66
2015249
      if (tn.isStringLike())
67
      {
68
769080
        d_stringsEqc.push_back(eqc);
69
769080
        emps = Word::mkEmptyWord(tn);
70
      }
71
4030498
      Node var;
72
2015249
      eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, ee);
73
27130803
      while (!eqc_i.isFinished())
74
      {
75
25115554
        Node n = *eqc_i;
76
12557777
        Kind k = n.getKind();
77
12557777
        Trace("strings-base") << "initialize term: " << n << std::endl;
78
        // process constant-like terms
79
12557777
        if (utils::isConstantLike(n))
80
        {
81
1081510
          Node prev = d_eqcInfo[eqc].d_bestContent;
82
540755
          if (!prev.isNull())
83
          {
84
            // we have either (seq.unit x) = C, or (seq.unit x) = (seq.unit y)
85
            // where C is a sequence constant.
86
            Node cval =
87
258
                prev.isConst() ? prev : (n.isConst() ? n : Node::null());
88
258
            std::vector<Node> exp;
89
129
            exp.push_back(prev.eqNode(n));
90
258
            Node s, t;
91
129
            if (cval.isNull())
92
            {
93
              // injectivity of seq.unit
94
20
              s = prev[0];
95
20
              t = n[0];
96
            }
97
            else
98
            {
99
              // should not have two constants in the same equivalence class
100
109
              Assert(cval.getType().isSequence());
101
218
              std::vector<Node> cchars = Word::getChars(cval);
102
109
              if (cchars.size() == 1)
103
              {
104
218
                Node oval = prev.isConst() ? n : prev;
105
109
                Assert(oval.getKind() == SEQ_UNIT);
106
109
                s = oval[0];
107
109
                t = cchars[0].getConst<Sequence>().getVec()[0];
108
                // oval is congruent (ignored) in this context
109
109
                d_congruent.insert(oval);
110
              }
111
              else
112
              {
113
                // (seq.unit x) = C => false if |C| != 1.
114
                d_im.sendInference(
115
                    exp, d_false, InferenceId::STRINGS_UNIT_CONST_CONFLICT);
116
                return;
117
              }
118
            }
119
129
            if (!d_state.areEqual(s, t))
120
            {
121
              // (seq.unit x) = (seq.unit y) => x=y, or
122
              // (seq.unit x) = (seq.unit c) => x=c
123
32
              Assert(s.getType() == t.getType());
124
32
              d_im.sendInference(exp, s.eqNode(t), InferenceId::STRINGS_UNIT_INJ);
125
            }
126
          }
127
          // update best content
128
540755
          if (prev.isNull() || n.isConst())
129
          {
130
540626
            d_eqcInfo[eqc].d_bestContent = n;
131
540626
            d_eqcInfo[eqc].d_bestScore = 0;
132
540626
            d_eqcInfo[eqc].d_base = n;
133
540626
            d_eqcInfo[eqc].d_exp = Node::null();
134
          }
135
        }
136
12557777
        if (tn.isInteger())
137
        {
138
          // do nothing
139
        }
140
        // process indexing
141
9568727
        else if (n.getNumChildren() > 0)
142
        {
143
7078892
          if (k != EQUAL)
144
          {
145
1589381
            if (d_congruent.find(n) == d_congruent.end())
146
            {
147
2472898
              std::vector<Node> c;
148
2472898
              Node nc = tti[k].add(n, 0, d_state, emps, c);
149
1236449
              if (nc != n)
150
              {
151
220744
                Trace("strings-base-debug")
152
110372
                    << "...found congruent term " << nc << std::endl;
153
                // check if we have inferred a new equality by removal of empty
154
                // components
155
110372
                if (k == STRING_CONCAT && !d_state.areEqual(nc, n))
156
                {
157
14262
                  std::vector<Node> exp;
158
                  // the number of empty components of n, nc
159
7131
                  size_t count[2] = {0, 0};
160
44401
                  while (count[0] < nc.getNumChildren()
161
25766
                         || count[1] < n.getNumChildren())
162
                  {
163
                    // explain empty prefixes
164
55905
                    for (unsigned t = 0; t < 2; t++)
165
                    {
166
74540
                      Node nn = t == 0 ? nc : n;
167
58478
                      while (count[t] < nn.getNumChildren()
168
154226
                             && (nn[count[t]] == emps
169
85752
                                 || d_state.areEqual(nn[count[t]], emps)))
170
                      {
171
10604
                        if (nn[count[t]] != emps)
172
                        {
173
10604
                          exp.push_back(nn[count[t]].eqNode(emps));
174
                        }
175
10604
                        count[t]++;
176
                      }
177
                    }
178
37270
                    Trace("strings-base-debug")
179
18635
                        << "  counts = " << count[0] << ", " << count[1]
180
18635
                        << std::endl;
181
                    // explain equal components
182
18635
                    if (count[0] < nc.getNumChildren())
183
                    {
184
13637
                      Assert(count[1] < n.getNumChildren());
185
13637
                      if (nc[count[0]] != n[count[1]])
186
                      {
187
246
                        exp.push_back(nc[count[0]].eqNode(n[count[1]]));
188
                      }
189
13637
                      count[0]++;
190
13637
                      count[1]++;
191
                    }
192
                  }
193
                  // infer the equality
194
7131
                  d_im.sendInference(exp, n.eqNode(nc), InferenceId::STRINGS_I_NORM);
195
                }
196
                else
197
                {
198
                  // We cannot mark one of the terms as reduced here (via
199
                  // ExtTheory::markCongruent) since extended function terms
200
                  // rely on reductions to other extended function terms. We
201
                  // may have a pair of extended function terms f(a)=f(b) where
202
                  // the reduction of argument a depends on the term b.
203
                  // Thus, marking f(b) as reduced by virtue of the fact we
204
                  // have f(a) is incorrect, since then we are effectively
205
                  // assuming that the reduction of f(a) depends on itself.
206
                }
207
                // this node is congruent to another one, we can ignore it
208
220744
                Trace("strings-base-debug")
209
110372
                    << "  congruent term : " << n << " (via " << nc << ")"
210
110372
                    << std::endl;
211
110372
                d_congruent.insert(n);
212
110372
                congruentCount[k].first++;
213
              }
214
1126077
              else if (k == STRING_CONCAT && c.size() == 1)
215
              {
216
70390
                Trace("strings-base-debug")
217
35195
                    << "  congruent term by singular : " << n << " " << c[0]
218
35195
                    << std::endl;
219
                // singular case
220
35195
                if (!d_state.areEqual(c[0], n))
221
                {
222
28400
                  Node ns;
223
28400
                  std::vector<Node> exp;
224
                  // explain empty components
225
14200
                  bool foundNEmpty = false;
226
45018
                  for (const Node& nnc : n)
227
                  {
228
30818
                    if (d_state.areEqual(nnc, emps))
229
                    {
230
16618
                      if (nnc != emps)
231
                      {
232
16618
                        exp.push_back(nnc.eqNode(emps));
233
                      }
234
                    }
235
                    else
236
                    {
237
14200
                      Assert(!foundNEmpty);
238
14200
                      ns = nnc;
239
14200
                      foundNEmpty = true;
240
                    }
241
                  }
242
14200
                  AlwaysAssert(foundNEmpty);
243
                  // infer the equality
244
14200
                  d_im.sendInference(exp, n.eqNode(ns), InferenceId::STRINGS_I_NORM_S);
245
                }
246
35195
                d_congruent.insert(n);
247
35195
                congruentCount[k].first++;
248
              }
249
              else
250
              {
251
1090882
                congruentCount[k].second++;
252
              }
253
            }
254
            else
255
            {
256
352932
              congruentCount[k].first++;
257
            }
258
          }
259
        }
260
2489835
        else if (!n.isConst())
261
        {
262
2171371
          if (d_congruent.find(n) == d_congruent.end())
263
          {
264
            // We mark all but the oldest variable in the equivalence class as
265
            // congruent.
266
1143537
            if (var.isNull())
267
            {
268
759028
              var = n;
269
            }
270
384509
            else if (var > n)
271
            {
272
409832
              Trace("strings-base-debug")
273
204916
                  << "  congruent variable : " << var << std::endl;
274
204916
              d_congruent.insert(var);
275
204916
              var = n;
276
            }
277
            else
278
            {
279
359186
              Trace("strings-base-debug")
280
179593
                  << "  congruent variable : " << n << std::endl;
281
179593
              d_congruent.insert(n);
282
            }
283
          }
284
        }
285
12557777
        ++eqc_i;
286
      }
287
    }
288
2197827
    ++eqcs_i;
289
  }
290
44123
  if (Trace.isOn("strings-base"))
291
  {
292
    for (const std::pair<const Kind, std::pair<uint32_t, uint32_t>>& cc :
293
         congruentCount)
294
    {
295
      Trace("strings-base")
296
          << "  Terms[" << cc.first << "] = " << cc.second.second << "/"
297
          << (cc.second.first + cc.second.second) << std::endl;
298
    }
299
  }
300
44123
  Trace("strings-base") << "BaseSolver::checkInit finished" << std::endl;
301
}
302
303
37370
void BaseSolver::checkConstantEquivalenceClasses()
304
{
305
  // do fixed point
306
37370
  size_t prevSize = 0;
307
74740
  std::vector<Node> vecc;
308
  do
309
  {
310
37370
    vecc.clear();
311
74740
    Trace("strings-base-debug")
312
37370
        << "Check constant equivalence classes..." << std::endl;
313
37370
    prevSize = d_eqcInfo.size();
314
95736
    for (std::pair<const TypeNode, std::map<Kind, TermIndex>>& tindex :
315
37370
         d_termIndex)
316
    {
317
95736
      checkConstantEquivalenceClasses(
318
191472
          &tindex.second[STRING_CONCAT], vecc, true);
319
    }
320
37370
  } while (!d_im.hasProcessed() && d_eqcInfo.size() > prevSize);
321
322
37370
  if (!d_im.hasProcessed())
323
  {
324
    // now, go back and set "most content" terms
325
37370
    vecc.clear();
326
95736
    for (std::pair<const TypeNode, std::map<Kind, TermIndex>>& tindex :
327
37370
         d_termIndex)
328
    {
329
95736
      checkConstantEquivalenceClasses(
330
191472
          &tindex.second[STRING_CONCAT], vecc, false);
331
    }
332
  }
333
37370
}
334
335
1020239
void BaseSolver::checkConstantEquivalenceClasses(TermIndex* ti,
336
                                                 std::vector<Node>& vecc,
337
                                                 bool ensureConst,
338
                                                 bool isConst)
339
{
340
2040478
  Node n = ti->d_data;
341
1020239
  if (!n.isNull())
342
  {
343
    // construct the constant if applicable
344
982344
    Node c;
345
491172
    if (isConst)
346
    {
347
108692
      c = utils::mkNConcat(vecc, n.getType());
348
    }
349
491172
    if (!isConst || !d_state.areEqual(n, c))
350
    {
351
382480
      if (Trace.isOn("strings-debug"))
352
      {
353
        Trace("strings-debug")
354
            << "Constant eqc : " << c << " for " << n << std::endl;
355
        Trace("strings-debug") << "  ";
356
        for (const Node& v : vecc)
357
        {
358
          Trace("strings-debug") << v << " ";
359
        }
360
        Trace("strings-debug") << std::endl;
361
      }
362
382480
      size_t countc = 0;
363
764960
      std::vector<Node> exp;
364
      // non-constant vector
365
764960
      std::vector<Node> vecnc;
366
382480
      size_t contentSize = 0;
367
1326896
      for (size_t count = 0, nchild = n.getNumChildren(); count < nchild;
368
           ++count)
369
      {
370
        // Add explanations for the empty children
371
1024409
        Node emps;
372
978630
        if (d_state.isEqualEmptyWord(n[count], emps))
373
        {
374
34214
          d_im.addToExplanation(n[count], emps, exp);
375
34214
          continue;
376
        }
377
1740411
        else if (vecc[countc].isNull())
378
        {
379
830209
          Assert(!isConst);
380
          // no constant for this component, leave it as is
381
830209
          vecnc.push_back(n[count]);
382
830209
          continue;
383
        }
384
        // if we are not entirely a constant
385
79993
        if (!isConst)
386
        {
387
          // use the constant component
388
79993
          vecnc.push_back(vecc[countc]);
389
79993
          Assert(vecc[countc].isConst());
390
79993
          contentSize += Word::getLength(vecc[countc]);
391
        }
392
159986
        Trace("strings-debug")
393
79993
            << "...explain " << n[count] << " " << vecc[countc] << std::endl;
394
79993
        if (!d_state.areEqual(n[count], vecc[countc]))
395
        {
396
          Node nrr = d_state.getRepresentative(n[count]);
397
          Assert(!d_eqcInfo[nrr].d_bestContent.isNull()
398
                 && d_eqcInfo[nrr].d_bestContent.isConst());
399
          // must flatten to avoid nested AND in explanations
400
          utils::flattenOp(AND, d_eqcInfo[nrr].d_exp, exp);
401
          // now explain equality to base
402
          d_im.addToExplanation(n[count], d_eqcInfo[nrr].d_base, exp);
403
        }
404
        else
405
        {
406
79993
          d_im.addToExplanation(n[count], vecc[countc], exp);
407
        }
408
79993
        countc++;
409
      }
410
      // exp contains an explanation of n==c
411
382480
      Assert(!isConst || countc == vecc.size());
412
382480
      if (!isConst)
413
      {
414
        // no use storing something with no content
415
382480
        if (contentSize > 0)
416
        {
417
142970
          Node nr = d_state.getRepresentative(n);
418
71485
          BaseEqcInfo& bei = d_eqcInfo[nr];
419
142970
          if (!bei.d_bestContent.isConst()
420
71485
              && (bei.d_bestContent.isNull() || contentSize > bei.d_bestScore))
421
          {
422
            // The equivalence class is not entailed to be equal to a constant
423
            // and we found a better concatenation
424
118970
            Node nct = utils::mkNConcat(vecnc, n.getType());
425
59485
            Assert(!nct.isConst());
426
59485
            bei.d_bestContent = nct;
427
59485
            bei.d_bestScore = contentSize;
428
59485
            bei.d_base = n;
429
59485
            if (!exp.empty())
430
            {
431
25419
              bei.d_exp = utils::mkAnd(exp);
432
            }
433
118970
            Trace("strings-debug")
434
59485
                << "Set eqc best content " << n << " to " << nct
435
59485
                << ", explanation = " << bei.d_exp << std::endl;
436
          }
437
        }
438
      }
439
      else if (d_state.hasTerm(c))
440
      {
441
        d_im.sendInference(exp, n.eqNode(c), InferenceId::STRINGS_I_CONST_MERGE);
442
        return;
443
      }
444
      else if (!d_im.hasProcessed())
445
      {
446
        Node nr = d_state.getRepresentative(n);
447
        BaseEqcInfo& bei = d_eqcInfo[nr];
448
        if (!bei.d_bestContent.isConst())
449
        {
450
          bei.d_bestContent = c;
451
          bei.d_base = n;
452
          bei.d_exp = utils::mkAnd(exp);
453
          Trace("strings-debug")
454
              << "Set eqc const " << n << " to " << c
455
              << ", explanation = " << bei.d_exp << std::endl;
456
        }
457
        else if (c != bei.d_bestContent)
458
        {
459
          // conflict
460
          Trace("strings-debug")
461
              << "Conflict, other constant was " << bei.d_bestContent
462
              << ", this constant was " << c << std::endl;
463
          if (bei.d_exp.isNull())
464
          {
465
            // n==c ^ n == c' => false
466
            d_im.addToExplanation(n, bei.d_bestContent, exp);
467
          }
468
          else
469
          {
470
            // n==c ^ n == d_base == c' => false
471
            exp.push_back(bei.d_exp);
472
            d_im.addToExplanation(n, bei.d_base, exp);
473
          }
474
          d_im.sendInference(exp, d_false, InferenceId::STRINGS_I_CONST_CONFLICT);
475
          return;
476
        }
477
        else
478
        {
479
          Trace("strings-debug") << "Duplicate constant." << std::endl;
480
        }
481
      }
482
    }
483
  }
484
2073467
  for (std::pair<const TNode, TermIndex>& p : ti->d_children)
485
  {
486
1053228
    std::map<Node, BaseEqcInfo>::const_iterator it = d_eqcInfo.find(p.first);
487
1053228
    if (it != d_eqcInfo.end() && it->second.d_bestContent.isConst())
488
    {
489
314773
      vecc.push_back(it->second.d_bestContent);
490
314773
      checkConstantEquivalenceClasses(&p.second, vecc, ensureConst, isConst);
491
314773
      vecc.pop_back();
492
    }
493
738455
    else if (!ensureConst)
494
    {
495
      // can still proceed, with null
496
513994
      vecc.push_back(Node::null());
497
513994
      checkConstantEquivalenceClasses(&p.second, vecc, ensureConst, false);
498
513994
      vecc.pop_back();
499
    }
500
1053228
    if (d_im.hasProcessed())
501
    {
502
      break;
503
    }
504
  }
505
}
506
507
10205
void BaseSolver::checkCardinality()
508
{
509
  // This will create a partition of eqc, where each collection has length that
510
  // are pairwise propagated to be equal. We do not require disequalities
511
  // between the lengths of each collection, since we split on disequalities
512
  // between lengths of string terms that are disequal (DEQ-LENGTH-SP).
513
20410
  std::map<TypeNode, std::vector<std::vector<Node> > > cols;
514
20410
  std::map<TypeNode, std::vector<Node> > lts;
515
10205
  d_state.separateByLength(d_stringsEqc, cols, lts);
516
12015
  for (std::pair<const TypeNode, std::vector<std::vector<Node> > >& c : cols)
517
  {
518
1810
    checkCardinalityType(c.first, c.second, lts[c.first]);
519
  }
520
10205
}
521
522
1810
void BaseSolver::checkCardinalityType(TypeNode tn,
523
                                      std::vector<std::vector<Node> >& cols,
524
                                      std::vector<Node>& lts)
525
{
526
3620
  Trace("strings-card") << "Check cardinality (type " << tn << ")..."
527
1810
                        << std::endl;
528
1810
  NodeManager* nm = NodeManager::currentNM();
529
  uint32_t typeCardSize;
530
1810
  if (tn.isString())  // string-only
531
  {
532
1712
    typeCardSize = d_cardSize;
533
  }
534
  else
535
  {
536
98
    Assert(tn.isSequence());
537
108
    TypeNode etn = tn.getSequenceElementType();
538
98
    if (!d_env.isFiniteType(etn))
539
    {
540
      // infinite cardinality, we are fine
541
88
      return;
542
    }
543
    // we check the cardinality class of the type, assuming that FMF is
544
    // disabled.
545
10
    if (isCardinalityClassFinite(etn.getCardinalityClass(), false))
546
    {
547
20
      Cardinality c = etn.getCardinality();
548
10
      bool smallCardinality = false;
549
10
      if (!c.isLargeFinite())
550
      {
551
20
        Integer ci = c.getFiniteCardinality();
552
10
        if (ci.fitsUnsignedInt())
553
        {
554
10
          smallCardinality = true;
555
10
          typeCardSize = ci.toUnsignedInt();
556
        }
557
      }
558
10
      if (!smallCardinality)
559
      {
560
        // if it is large finite, then there is no way we could have
561
        // constructed that many terms in memory, hence there is nothing
562
        // to do.
563
        return;
564
      }
565
    }
566
    else
567
    {
568
      Assert(options().quantifiers.finiteModelFind);
569
      // we are in a case where the cardinality of the type is infinite
570
      // if not FMF, and finite given the Env's option value for FMF. In this
571
      // case, FMF must be true, and the cardinality is finite and dynamic
572
      // (i.e. it depends on the model's finite interpretation for uninterpreted
573
      // sorts). We do not know how to handle this case, we set incomplete.
574
      // TODO (cvc4-projects #23): how to handle sequence for finite types?
575
      d_im.setIncomplete(IncompleteId::SEQ_FINITE_DYNAMIC_CARDINALITY);
576
      return;
577
    }
578
  }
579
  // for each collection
580
11404
  for (unsigned i = 0, csize = cols.size(); i < csize; ++i)
581
  {
582
9689
    Node lr = lts[i];
583
19378
    Trace("strings-card") << "Number of strings with length equal to " << lr
584
9689
                          << " is " << cols[i].size() << std::endl;
585
9689
    if (cols[i].size() <= 1)
586
    {
587
      // no restriction on sets in the partition of size 1
588
7621
      continue;
589
    }
590
    // size > c^k
591
2068
    unsigned card_need = 1;
592
2068
    double curr = static_cast<double>(cols[i].size());
593
2082
    while (curr > typeCardSize)
594
    {
595
7
      curr = curr / static_cast<double>(typeCardSize);
596
7
      card_need++;
597
    }
598
4136
    Trace("strings-card")
599
2068
        << "Need length " << card_need
600
2068
        << " for this number of strings (where alphabet size is "
601
2068
        << typeCardSize << ") given type " << tn << "." << std::endl;
602
    // check if we need to split
603
2068
    bool needsSplit = true;
604
2068
    if (lr.isConst())
605
    {
606
      // if constant, compare
607
3894
      Node cmp = nm->mkNode(GEQ, lr, nm->mkConst(Rational(card_need)));
608
1947
      cmp = rewrite(cmp);
609
1947
      needsSplit = !cmp.getConst<bool>();
610
    }
611
    else
612
    {
613
      // find the minimimum constant that we are unknown to be disequal from, or
614
      // otherwise stop if we increment such that cardinality does not apply.
615
      // We always start with r=1 since by the invariants of our term registry,
616
      // a term is either equal to the empty string, or has length >= 1.
617
121
      unsigned r = 1;
618
121
      bool success = true;
619
121
      while (r < card_need && success)
620
      {
621
        Node rr = nm->mkConst(Rational(r));
622
        if (d_state.areDisequal(rr, lr))
623
        {
624
          r++;
625
        }
626
        else
627
        {
628
          success = false;
629
        }
630
      }
631
121
      if (r > 0)
632
      {
633
242
        Trace("strings-card")
634
121
            << "Symbolic length " << lr << " must be at least " << r
635
121
            << " due to constant disequalities." << std::endl;
636
      }
637
121
      needsSplit = r < card_need;
638
    }
639
640
2068
    if (!needsSplit)
641
    {
642
      // don't need to split
643
2061
      continue;
644
    }
645
    // first, try to split to merge equivalence classes
646
406
    for (std::vector<Node>::iterator itr1 = cols[i].begin();
647
406
         itr1 != cols[i].end();
648
         ++itr1)
649
    {
650
25179
      for (std::vector<Node>::iterator itr2 = itr1 + 1; itr2 != cols[i].end();
651
           ++itr2)
652
      {
653
24780
        if (!d_state.areDisequal(*itr1, *itr2))
654
        {
655
          // add split lemma
656
          if (d_im.sendSplit(*itr1, *itr2, InferenceId::STRINGS_CARD_SP))
657
          {
658
            return;
659
          }
660
        }
661
      }
662
    }
663
    // otherwise, we need a length constraint
664
7
    uint32_t int_k = static_cast<uint32_t>(card_need);
665
7
    EqcInfo* ei = d_state.getOrMakeEqcInfo(lr, true);
666
14
    Trace("strings-card") << "Previous cardinality used for " << lr << " is "
667
14
                          << ((int)ei->d_cardinalityLemK.get() - 1)
668
7
                          << std::endl;
669
7
    if (int_k + 1 > ei->d_cardinalityLemK.get())
670
    {
671
7
      Node k_node = nm->mkConst(Rational(int_k));
672
      // add cardinality lemma
673
7
      Node dist = nm->mkNode(DISTINCT, cols[i]);
674
7
      std::vector<Node> expn;
675
7
      expn.push_back(dist);
676
406
      for (std::vector<Node>::iterator itr1 = cols[i].begin();
677
406
           itr1 != cols[i].end();
678
           ++itr1)
679
      {
680
798
        Node len = nm->mkNode(STRING_LENGTH, *itr1);
681
399
        if (len != lr)
682
        {
683
798
          Node len_eq_lr = len.eqNode(lr);
684
399
          expn.push_back(len_eq_lr);
685
        }
686
      }
687
7
      Node len = nm->mkNode(STRING_LENGTH, cols[i][0]);
688
7
      Node cons = nm->mkNode(GEQ, len, k_node);
689
7
      cons = rewrite(cons);
690
7
      ei->d_cardinalityLemK.set(int_k + 1);
691
7
      if (!cons.isConst() || !cons.getConst<bool>())
692
      {
693
7
        d_im.sendInference(
694
            expn, expn, cons, InferenceId::STRINGS_CARDINALITY, false, true);
695
7
        return;
696
      }
697
    }
698
  }
699
1715
  Trace("strings-card") << "...end check cardinality" << std::endl;
700
}
701
702
3827920
bool BaseSolver::isCongruent(Node n)
703
{
704
3827920
  return d_congruent.find(n) != d_congruent.end();
705
}
706
707
2252274
Node BaseSolver::getConstantEqc(Node eqc)
708
{
709
2252274
  std::map<Node, BaseEqcInfo>::const_iterator it = d_eqcInfo.find(eqc);
710
2252274
  if (it != d_eqcInfo.end() && it->second.d_bestContent.isConst())
711
  {
712
665312
    return it->second.d_bestContent;
713
  }
714
1586962
  return Node::null();
715
}
716
717
88058
Node BaseSolver::explainConstantEqc(Node n, Node eqc, std::vector<Node>& exp)
718
{
719
88058
  std::map<Node, BaseEqcInfo>::const_iterator it = d_eqcInfo.find(eqc);
720
88058
  if (it != d_eqcInfo.end())
721
  {
722
88058
    BaseEqcInfo& bei = d_eqcInfo[eqc];
723
88058
    if (!bei.d_bestContent.isConst())
724
    {
725
      return Node::null();
726
    }
727
88058
    if (!bei.d_exp.isNull())
728
    {
729
      utils::flattenOp(AND, bei.d_exp, exp);
730
    }
731
88058
    if (!bei.d_base.isNull())
732
    {
733
88058
      d_im.addToExplanation(n, bei.d_base, exp);
734
    }
735
88058
    return bei.d_bestContent;
736
  }
737
  return Node::null();
738
}
739
740
1141915
Node BaseSolver::explainBestContentEqc(Node n, Node eqc, std::vector<Node>& exp)
741
{
742
1141915
  std::map<Node, BaseEqcInfo>::const_iterator it = d_eqcInfo.find(eqc);
743
1141915
  if (it != d_eqcInfo.end())
744
  {
745
600776
    BaseEqcInfo& bei = d_eqcInfo[eqc];
746
600776
    Assert(!bei.d_bestContent.isNull());
747
600776
    if (!bei.d_exp.isNull())
748
    {
749
58365
      utils::flattenOp(AND, bei.d_exp, exp);
750
    }
751
600776
    if (!bei.d_base.isNull())
752
    {
753
600776
      d_im.addToExplanation(n, bei.d_base, exp);
754
    }
755
600776
    return bei.d_bestContent;
756
  }
757
758
541139
  return Node::null();
759
}
760
761
36868
const std::vector<Node>& BaseSolver::getStringEqc() const
762
{
763
36868
  return d_stringsEqc;
764
}
765
766
4237757
Node BaseSolver::TermIndex::add(TNode n,
767
                                unsigned index,
768
                                const SolverState& s,
769
                                Node er,
770
                                std::vector<Node>& c)
771
{
772
4237757
  if (index == n.getNumChildren())
773
  {
774
1236449
    if (d_data.isNull())
775
    {
776
1126077
      d_data = n;
777
    }
778
1236449
    return d_data;
779
  }
780
3001308
  Assert(index < n.getNumChildren());
781
6002616
  TNode nir = s.getRepresentative(n[index]);
782
  // if it is empty, and doing CONCAT, ignore
783
3001308
  if (nir == er && n.getKind() == STRING_CONCAT)
784
  {
785
248530
    return add(n, index + 1, s, er, c);
786
  }
787
2752778
  c.push_back(nir);
788
2752778
  return d_children[nir].add(n, index + 1, s, er, c);
789
}
790
791
}  // namespace strings
792
}  // namespace theory
793
31137
}  // namespace cvc5