GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/strings/theory_strings.cpp Lines: 483 588 82.1 %
Date: 2021-08-16 Branches: 1016 2441 41.6 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Tianyi Liang, Andres Noetzli
4
 *
5
 * This file is part of the cvc5 project.
6
 *
7
 * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 * in the top-level source directory and their institutional affiliations.
9
 * All rights reserved.  See the file COPYING in the top-level source
10
 * directory for licensing information.
11
 * ****************************************************************************
12
 *
13
 * Implementation of the theory of strings.
14
 */
15
16
#include "theory/strings/theory_strings.h"
17
18
#include "expr/attribute.h"
19
#include "expr/bound_var_manager.h"
20
#include "expr/kind.h"
21
#include "expr/sequence.h"
22
#include "options/smt_options.h"
23
#include "options/strings_options.h"
24
#include "options/theory_options.h"
25
#include "smt/logic_exception.h"
26
#include "theory/decision_manager.h"
27
#include "theory/ext_theory.h"
28
#include "theory/rewriter.h"
29
#include "theory/strings/theory_strings_utils.h"
30
#include "theory/strings/type_enumerator.h"
31
#include "theory/strings/word.h"
32
#include "theory/theory_model.h"
33
#include "theory/valuation.h"
34
35
using namespace std;
36
using namespace cvc5::context;
37
using namespace cvc5::kind;
38
39
namespace cvc5 {
40
namespace theory {
41
namespace strings {
42
43
/**
44
 * Attribute used for making unique (bound variables) which correspond to
45
 * unique element values used in sequence models. See use in collectModelValues
46
 * below.
47
 */
48
struct SeqModelVarAttributeId
49
{
50
};
51
using SeqModelVarAttribute = expr::Attribute<SeqModelVarAttributeId, Node>;
52
53
9853
TheoryStrings::TheoryStrings(context::Context* c,
54
                             context::UserContext* u,
55
                             OutputChannel& out,
56
                             Valuation valuation,
57
                             const LogicInfo& logicInfo,
58
9853
                             ProofNodeManager* pnm)
59
    : Theory(THEORY_STRINGS, c, u, out, valuation, logicInfo, pnm),
60
      d_notify(*this),
61
      d_statistics(),
62
      d_state(c, u, d_valuation),
63
      d_eagerSolver(d_state),
64
      d_termReg(d_state, d_statistics, pnm),
65
      d_extTheoryCb(),
66
      d_extTheory(d_extTheoryCb, c, u, out),
67
      d_im(*this, d_state, d_termReg, d_extTheory, d_statistics, pnm),
68
      d_rewriter(&d_statistics.d_rewrites),
69
      d_bsolver(d_state, d_im),
70
      d_csolver(d_state, d_im, d_termReg, d_bsolver),
71
      d_esolver(d_state,
72
                d_im,
73
                d_termReg,
74
                d_rewriter,
75
                d_bsolver,
76
                d_csolver,
77
                d_extTheory,
78
                d_statistics),
79
      d_rsolver(d_state,
80
                d_im,
81
                d_termReg.getSkolemCache(),
82
                d_csolver,
83
                d_esolver,
84
                d_statistics),
85
9853
      d_regexp_elim(options::regExpElimAgg(), pnm, u),
86
19706
      d_stringsFmf(c, u, valuation, d_termReg)
87
{
88
9853
  d_termReg.finishInit(&d_im);
89
90
9853
  d_zero = NodeManager::currentNM()->mkConst( Rational( 0 ) );
91
9853
  d_one = NodeManager::currentNM()->mkConst( Rational( 1 ) );
92
9853
  d_neg_one = NodeManager::currentNM()->mkConst(Rational(-1));
93
9853
  d_true = NodeManager::currentNM()->mkConst( true );
94
9853
  d_false = NodeManager::currentNM()->mkConst( false );
95
96
9853
  d_cardSize = utils::getAlphabetCardinality();
97
98
  // set up the extended function callback
99
9853
  d_extTheoryCb.d_esolver = &d_esolver;
100
101
  // use the state object as the official theory state
102
9853
  d_theoryState = &d_state;
103
  // use the inference manager as the official inference manager
104
9853
  d_inferManager = &d_im;
105
9853
}
106
107
19706
TheoryStrings::~TheoryStrings() {
108
109
19706
}
110
111
9853
TheoryRewriter* TheoryStrings::getTheoryRewriter() { return &d_rewriter; }
112
113
3768
ProofRuleChecker* TheoryStrings::getProofChecker() { return &d_checker; }
114
115
9853
bool TheoryStrings::needsEqualityEngine(EeSetupInfo& esi)
116
{
117
9853
  esi.d_notify = &d_notify;
118
9853
  esi.d_name = "theory::strings::ee";
119
9853
  esi.d_notifyNewClass = true;
120
9853
  esi.d_notifyMerge = true;
121
9853
  esi.d_notifyDisequal = true;
122
9853
  return true;
123
}
124
125
9853
void TheoryStrings::finishInit()
126
{
127
9853
  Assert(d_equalityEngine != nullptr);
128
129
  // witness is used to eliminate str.from_code
130
9853
  d_valuation.setUnevaluatedKind(WITNESS);
131
132
9853
  bool eagerEval = options::stringEagerEval();
133
  // The kinds we are treating as function application in congruence
134
9853
  d_equalityEngine->addFunctionKind(kind::STRING_LENGTH, eagerEval);
135
9853
  d_equalityEngine->addFunctionKind(kind::STRING_CONCAT, eagerEval);
136
9853
  d_equalityEngine->addFunctionKind(kind::STRING_IN_REGEXP, eagerEval);
137
9853
  d_equalityEngine->addFunctionKind(kind::STRING_TO_CODE, eagerEval);
138
9853
  d_equalityEngine->addFunctionKind(kind::SEQ_UNIT, eagerEval);
139
  // `seq.nth` is not always defined, and so we do not evaluate it eagerly.
140
9853
  d_equalityEngine->addFunctionKind(kind::SEQ_NTH, false);
141
  // extended functions
142
9853
  d_equalityEngine->addFunctionKind(kind::STRING_CONTAINS, eagerEval);
143
9853
  d_equalityEngine->addFunctionKind(kind::STRING_LEQ, eagerEval);
144
9853
  d_equalityEngine->addFunctionKind(kind::STRING_SUBSTR, eagerEval);
145
9853
  d_equalityEngine->addFunctionKind(kind::STRING_UPDATE, eagerEval);
146
9853
  d_equalityEngine->addFunctionKind(kind::STRING_ITOS, eagerEval);
147
9853
  d_equalityEngine->addFunctionKind(kind::STRING_STOI, eagerEval);
148
9853
  d_equalityEngine->addFunctionKind(kind::STRING_INDEXOF, eagerEval);
149
9853
  d_equalityEngine->addFunctionKind(kind::STRING_INDEXOF_RE, eagerEval);
150
9853
  d_equalityEngine->addFunctionKind(kind::STRING_REPLACE, eagerEval);
151
9853
  d_equalityEngine->addFunctionKind(kind::STRING_REPLACE_ALL, eagerEval);
152
9853
  d_equalityEngine->addFunctionKind(kind::STRING_REPLACE_RE, eagerEval);
153
9853
  d_equalityEngine->addFunctionKind(kind::STRING_REPLACE_RE_ALL, eagerEval);
154
9853
  d_equalityEngine->addFunctionKind(kind::STRING_REPLACE_ALL, eagerEval);
155
9853
  d_equalityEngine->addFunctionKind(kind::STRING_TOLOWER, eagerEval);
156
9853
  d_equalityEngine->addFunctionKind(kind::STRING_TOUPPER, eagerEval);
157
9853
  d_equalityEngine->addFunctionKind(kind::STRING_REV, eagerEval);
158
9853
}
159
160
std::string TheoryStrings::identify() const
161
{
162
  return std::string("TheoryStrings");
163
}
164
165
4313
bool TheoryStrings::areCareDisequal( TNode x, TNode y ) {
166
4313
  Assert(d_equalityEngine->hasTerm(x));
167
4313
  Assert(d_equalityEngine->hasTerm(y));
168
12939
  if (d_equalityEngine->isTriggerTerm(x, THEORY_STRINGS)
169
12939
      && d_equalityEngine->isTriggerTerm(y, THEORY_STRINGS))
170
  {
171
    TNode x_shared =
172
4971
        d_equalityEngine->getTriggerTermRepresentative(x, THEORY_STRINGS);
173
    TNode y_shared =
174
4971
        d_equalityEngine->getTriggerTermRepresentative(y, THEORY_STRINGS);
175
3231
    EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
176
3231
    if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
177
1491
      return true;
178
    }
179
  }
180
2822
  return false;
181
}
182
183
946328
bool TheoryStrings::propagateLit(TNode literal)
184
{
185
946328
  return d_im.propagateLit(literal);
186
}
187
188
40935
TrustNode TheoryStrings::explain(TNode literal)
189
{
190
40935
  Debug("strings-explain") << "explain called on " << literal << std::endl;
191
40935
  return d_im.explainLit(literal);
192
}
193
194
15204
void TheoryStrings::presolve() {
195
15204
  Debug("strings-presolve") << "TheoryStrings::Presolving : get fmf options " << (options::stringFMF() ? "true" : "false") << std::endl;
196
15204
  d_strat.initializeStrategy();
197
198
  // if strings fmf is enabled, register the strategy
199
15204
  if (options::stringFMF())
200
  {
201
78
    d_stringsFmf.presolve();
202
    // This strategy is local to a check-sat call, since we refresh the strategy
203
    // on every call to presolve.
204
78
    d_im.getDecisionManager()->registerStrategy(
205
        DecisionManager::STRAT_STRINGS_SUM_LENGTHS,
206
        d_stringsFmf.getDecisionStrategy(),
207
        DecisionManager::STRAT_SCOPE_LOCAL_SOLVE);
208
  }
209
15204
  Debug("strings-presolve") << "Finished presolve" << std::endl;
210
15204
}
211
212
213
/////////////////////////////////////////////////////////////////////////////
214
// MODEL GENERATION
215
/////////////////////////////////////////////////////////////////////////////
216
217
5449
bool TheoryStrings::collectModelValues(TheoryModel* m,
218
                                       const std::set<Node>& termSet)
219
{
220
5449
  if (Trace.isOn("strings-debug-model"))
221
  {
222
    Trace("strings-debug-model")
223
        << "TheoryStrings::collectModelValues" << std::endl;
224
    Trace("strings-debug-model") << "Equivalence classes are:" << std::endl;
225
    Trace("strings-debug-model") << debugPrintStringsEqc() << std::endl;
226
    Trace("strings-debug-model") << "Extended functions are:" << std::endl;
227
    Trace("strings-debug-model") << d_esolver.debugPrintModel() << std::endl;
228
  }
229
5449
  Trace("strings-model") << "TheoryStrings::collectModelValues" << std::endl;
230
  // Collects representatives by types and orders sequence types by how nested
231
  // they are
232
10898
  std::map<TypeNode, std::unordered_set<Node> > repSet;
233
10898
  std::unordered_set<TypeNode> toProcess;
234
  // Generate model
235
  // get the relevant string equivalence classes
236
82400
  for (const Node& s : termSet)
237
  {
238
153902
    TypeNode tn = s.getType();
239
76951
    if (tn.isStringLike())
240
    {
241
75374
      Node r = d_state.getRepresentative(s);
242
37687
      repSet[tn].insert(r);
243
37687
      toProcess.insert(tn);
244
    }
245
  }
246
247
7109
  while (!toProcess.empty())
248
  {
249
    // Pick one of the remaining types to collect model values for
250
1662
    TypeNode tn = *toProcess.begin();
251
832
    if (!collectModelInfoType(tn, toProcess, repSet, m))
252
    {
253
      return false;
254
    }
255
  }
256
257
5448
  return true;
258
}
259
260
831
bool TheoryStrings::collectModelInfoType(
261
    TypeNode tn,
262
    std::unordered_set<TypeNode>& toProcess,
263
    const std::map<TypeNode, std::unordered_set<Node> >& repSet,
264
    TheoryModel* m)
265
{
266
  // Make sure that the model values for the element type of sequences are
267
  // computed first
268
831
  if (tn.isSequence() && tn.getSequenceElementType().isSequence())
269
  {
270
6
    TypeNode tnElem = tn.getSequenceElementType();
271
6
    if (toProcess.find(tnElem) != toProcess.end()
272
6
        && !collectModelInfoType(tnElem, toProcess, repSet, m))
273
    {
274
      return false;
275
    }
276
  }
277
831
  toProcess.erase(tn);
278
279
  // get partition of strings of equal lengths for the representatives of the
280
  // current type
281
1662
  std::map<TypeNode, std::vector<std::vector<Node> > > colT;
282
1662
  std::map<TypeNode, std::vector<Node> > ltsT;
283
1662
  const std::vector<Node> repVec(repSet.at(tn).begin(), repSet.at(tn).end());
284
831
  d_state.separateByLength(repVec, colT, ltsT);
285
831
  const std::vector<std::vector<Node> >& col = colT[tn];
286
831
  const std::vector<Node>& lts = ltsT[tn];
287
288
831
  NodeManager* nm = NodeManager::currentNM();
289
1662
  std::map< Node, Node > processed;
290
  //step 1 : get all values for known lengths
291
1662
  std::vector< Node > lts_values;
292
1662
  std::map<std::size_t, Node> values_used;
293
1662
  std::vector<Node> len_splits;
294
5489
  for( unsigned i=0; i<col.size(); i++ ) {
295
4659
    Trace("strings-model") << "Checking length for {";
296
11660
    for( unsigned j=0; j<col[i].size(); j++ ) {
297
7001
      if( j>0 ) {
298
2342
        Trace("strings-model") << ", ";
299
      }
300
7001
      Trace("strings-model") << col[i][j];
301
    }
302
4659
    Trace("strings-model") << " } (length is " << lts[i] << ")" << std::endl;
303
9318
    Node len_value;
304
4659
    if( lts[i].isConst() ) {
305
3185
      len_value = lts[i];
306
    }
307
1474
    else if (!lts[i].isNull())
308
    {
309
      // get the model value for lts[i]
310
1474
      len_value = d_valuation.getModelValue(lts[i]);
311
    }
312
4659
    if (len_value.isNull())
313
    {
314
      lts_values.push_back(Node::null());
315
    }
316
    else
317
    {
318
      // must throw logic exception if we cannot construct the string
319
4659
      if (len_value.getConst<Rational>() > String::maxSize())
320
      {
321
2
        std::stringstream ss;
322
2
        ss << "The model was computed to have strings of length " << len_value
323
1
           << ". We only allow strings up to length " << String::maxSize();
324
1
        throw LogicException(ss.str());
325
      }
326
      std::size_t lvalue =
327
4658
          len_value.getConst<Rational>().getNumerator().toUnsignedInt();
328
4658
      auto itvu = values_used.find(lvalue);
329
4658
      if (itvu == values_used.end())
330
      {
331
3588
        values_used[lvalue] = lts[i];
332
      }
333
      else
334
      {
335
1070
        len_splits.push_back(lts[i].eqNode(itvu->second));
336
      }
337
4658
      lts_values.push_back(len_value);
338
    }
339
  }
340
  ////step 2 : assign arbitrary values for unknown lengths?
341
  // confirmed by calculus invariant, see paper
342
830
  Trace("strings-model") << "Assign to equivalence classes..." << std::endl;
343
1660
  std::map<Node, Node> pure_eq_assign;
344
  //step 3 : assign values to equivalence classes that are pure variables
345
5487
  for( unsigned i=0; i<col.size(); i++ ){
346
9314
    std::vector< Node > pure_eq;
347
9314
    Trace("strings-model") << "The (" << col[i].size()
348
4657
                           << ") equivalence classes ";
349
11656
    for (const Node& eqc : col[i])
350
    {
351
6999
      Trace("strings-model") << eqc << " ";
352
      //check if col[i][j] has only variables
353
6999
      if (!eqc.isConst())
354
      {
355
2915
        NormalForm& nfe = d_csolver.getNormalForm(eqc);
356
2915
        if (nfe.d_nf.size() == 1)
357
        {
358
          // is it an equivalence class with a seq.unit term?
359
982
          if (nfe.d_nf[0].getKind() == SEQ_UNIT)
360
          {
361
28
            Node argVal;
362
14
            if (nfe.d_nf[0][0].getType().isStringLike())
363
            {
364
              // By this point, we should have assigned model values for the
365
              // elements of this sequence type because of the check in the
366
              // beginning of this method
367
3
              argVal = m->getRepresentative(nfe.d_nf[0][0]);
368
            }
369
            else
370
            {
371
              // Otherwise, we use the term itself. We cannot get the model
372
              // value of this term, since it might not be available yet, as
373
              // it may belong to a theory that has not built its model yet.
374
              // Hence, we assign a (non-constant) skeleton (seq.unit argVal).
375
11
              argVal = nfe.d_nf[0][0];
376
            }
377
14
            Assert(!argVal.isNull()) << "No value for " << nfe.d_nf[0][0];
378
28
            Node c = Rewriter::rewrite(nm->mkNode(SEQ_UNIT, argVal));
379
14
            pure_eq_assign[eqc] = c;
380
14
            Trace("strings-model") << "(unit: " << nfe.d_nf[0] << ") ";
381
14
            m->getEqualityEngine()->addTerm(c);
382
          }
383
          // does it have a code and the length of these equivalence classes are
384
          // one?
385
968
          else if (d_termReg.hasStringCode() && lts_values[i] == d_one)
386
          {
387
311
            EqcInfo* eip = d_state.getOrMakeEqcInfo(eqc, false);
388
311
            if (eip && !eip->d_codeTerm.get().isNull())
389
            {
390
              // its value must be equal to its code
391
346
              Node ct = nm->mkNode(kind::STRING_TO_CODE, eip->d_codeTerm.get());
392
346
              Node ctv = d_valuation.getModelValue(ct);
393
              unsigned cvalue =
394
173
                  ctv.getConst<Rational>().getNumerator().toUnsignedInt();
395
173
              Trace("strings-model") << "(code: " << cvalue << ") ";
396
346
              std::vector<unsigned> vec;
397
173
              vec.push_back(cvalue);
398
346
              Node mv = nm->mkConst(String(vec));
399
173
              pure_eq_assign[eqc] = mv;
400
173
              m->getEqualityEngine()->addTerm(mv);
401
            }
402
          }
403
982
          pure_eq.push_back(eqc);
404
        }
405
      }
406
      else
407
      {
408
4084
        processed[eqc] = eqc;
409
        // Make sure that constants are asserted to the theory model that we
410
        // are building. It is possible that new constants were introduced by
411
        // the eager evaluation in the equality engine. These terms are missing
412
        // in the term set and, as a result, are skipped when the equality
413
        // engine is asserted to the theory model.
414
4084
        m->getEqualityEngine()->addTerm(eqc);
415
      }
416
    }
417
4657
    Trace("strings-model") << "have length " << lts_values[i] << std::endl;
418
419
    //assign a new length if necessary
420
4657
    if( !pure_eq.empty() ){
421
686
      if( lts_values[i].isNull() ){
422
        // start with length two (other lengths have special precendence)
423
        std::size_t lvalue = 2;
424
        while( values_used.find( lvalue )!=values_used.end() ){
425
          lvalue++;
426
        }
427
        Trace("strings-model") << "*** Decide to make length of " << lvalue << std::endl;
428
        lts_values[i] = nm->mkConst(Rational(lvalue));
429
        values_used[lvalue] = Node::null();
430
      }
431
686
      Trace("strings-model") << "Need to assign values of length " << lts_values[i] << " to equivalence classes ";
432
1668
      for( unsigned j=0; j<pure_eq.size(); j++ ){
433
982
        Trace("strings-model") << pure_eq[j] << " ";
434
      }
435
686
      Trace("strings-model") << std::endl;
436
437
      //use type enumerator
438
686
      Assert(lts_values[i].getConst<Rational>() <= Rational(String::maxSize()))
439
          << "Exceeded UINT32_MAX in string model";
440
      uint32_t currLen =
441
686
          lts_values[i].getConst<Rational>().getNumerator().toUnsignedInt();
442
1372
      std::unique_ptr<SEnumLen> sel;
443
1372
      Trace("strings-model") << "Cardinality of alphabet is "
444
686
                             << utils::getAlphabetCardinality() << std::endl;
445
686
      if (tn.isString())  // string-only
446
      {
447
666
        sel.reset(new StringEnumLen(
448
666
            currLen, currLen, utils::getAlphabetCardinality()));
449
      }
450
      else
451
      {
452
20
        sel.reset(new SeqEnumLen(tn, nullptr, currLen, currLen));
453
      }
454
1668
      for (const Node& eqc : pure_eq)
455
      {
456
1964
        Node c;
457
982
        std::map<Node, Node>::iterator itp = pure_eq_assign.find(eqc);
458
982
        if (itp == pure_eq_assign.end())
459
        {
460
659
          do
461
          {
462
1454
            if (sel->isFinished())
463
            {
464
              // We are in a case where model construction is impossible due to
465
              // an insufficient number of constants of a given length.
466
467
              // Consider an integer equivalence class E whose value is assigned
468
              // n in the model. Let { S_1, ..., S_m } be the set of string
469
              // equivalence classes such that len( x ) is a member of E for
470
              // some member x of each class S1, ...,Sm. Since our calculus is
471
              // saturated with respect to cardinality inference (see Liang
472
              // et al, Figure 6, CAV 2014), we have that m <= A^n, where A is
473
              // the cardinality of our alphabet.
474
475
              // Now, consider the case where there exists two integer
476
              // equivalence classes E1 and E2 that are assigned n, and moreover
477
              // we did not received notification from arithmetic that E1 = E2.
478
              // This typically should never happen, but assume in the following
479
              // that it does.
480
481
              // Now, it may be the case that there are string equivalence
482
              // classes { S_1, ..., S_m1 } whose lengths are in E1,
483
              // and classes { S'_1, ..., S'_m2 } whose lengths are in E2, where
484
              // m1 + m2 > A^n. In this case, we have insufficient strings to
485
              // assign to { S_1, ..., S_m1, S'_1, ..., S'_m2 }. If this
486
              // happens, we add a split on len( u1 ) = len( u2 ) for some
487
              // len( u1 ) in E1, len( u2 ) in E2. We do this for each pair of
488
              // integer equivalence classes that are assigned to the same value
489
              // in the model.
490
              AlwaysAssert(!len_splits.empty());
491
              for (const Node& sl : len_splits)
492
              {
493
                Node spl = nm->mkNode(OR, sl, sl.negate());
494
                d_im.lemma(spl, InferenceId::STRINGS_CMI_SPLIT);
495
                Trace("strings-lemma")
496
                    << "Strings::CollectModelInfoSplit: " << spl << std::endl;
497
              }
498
              // we added a lemma, so can return here
499
              return false;
500
            }
501
1454
            c = sel->getCurrent();
502
            // if we are a sequence with infinite element type
503
2908
            if (tn.isSequence()
504
2908
                && !d_state.isFiniteType(tn.getSequenceElementType()))
505
            {
506
              // Make a skeleton instead. In particular, this means that
507
              // a value:
508
              //   (seq.++ (seq.unit 0) (seq.unit 1) (seq.unit 2))
509
              // becomes:
510
              //   (seq.++ (seq.unit k_0) (seq.unit k_1) (seq.unit k_2))
511
              // where k_0, k_1, k_2 are fresh integer variables. These
512
              // variables will be assigned values in the standard way by the
513
              // model. This construction is necessary since the strings solver
514
              // must constrain the length of the model of an equivalence class
515
              // (e.g. in this case to length 3); moreover we cannot assign a
516
              // concrete value since it may conflict with other skeletons we
517
              // have assigned, e.g. for the case of (seq.unit argVal) above.
518
11
              SkolemManager* sm = nm->getSkolemManager();
519
11
              BoundVarManager* bvm = nm->getBoundVarManager();
520
11
              Assert(c.getKind() == CONST_SEQUENCE);
521
11
              const Sequence& sn = c.getConst<Sequence>();
522
11
              const std::vector<Node>& snvec = sn.getVec();
523
22
              std::vector<Node> skChildren;
524
37
              for (const Node& snv : snvec)
525
              {
526
52
                TypeNode etn = snv.getType();
527
52
                Node v = bvm->mkBoundVar<SeqModelVarAttribute>(snv, etn);
528
                // use a skolem, not a bound variable
529
52
                Node kv = sm->mkPurifySkolem(v, "smv");
530
26
                skChildren.push_back(nm->mkNode(SEQ_UNIT, kv));
531
              }
532
11
              c = utils::mkConcat(skChildren, tn);
533
            }
534
            // increment
535
1454
            sel->increment();
536
1454
          } while (m->hasTerm(c));
537
        }
538
        else
539
        {
540
187
          c = itp->second;
541
        }
542
1964
        Trace("strings-model") << "*** Assigned constant " << c << " for "
543
982
                               << eqc << std::endl;
544
982
        processed[eqc] = c;
545
982
        if (!m->assertEquality(eqc, c, true))
546
        {
547
          // this should never happen due to the model soundness argument
548
          // for strings
549
          Unreachable()
550
              << "TheoryStrings::collectModelInfoType: Inconsistent equality"
551
              << std::endl;
552
          return false;
553
        }
554
      }
555
    }
556
  }
557
830
  Trace("strings-model") << "String Model : Pure Assigned." << std::endl;
558
  //step 4 : assign constants to all other equivalence classes
559
7829
  for (const Node& rn : repVec)
560
  {
561
6999
    if (processed.find(rn) == processed.end())
562
    {
563
1933
      NormalForm& nf = d_csolver.getNormalForm(rn);
564
1933
      if (Trace.isOn("strings-model"))
565
      {
566
        Trace("strings-model")
567
            << "Construct model for " << rn << " based on normal form ";
568
        for (unsigned j = 0, size = nf.d_nf.size(); j < size; j++)
569
        {
570
          Node n = nf.d_nf[j];
571
          if (j > 0)
572
          {
573
            Trace("strings-model") << " ++ ";
574
          }
575
          Trace("strings-model") << n;
576
          Node r = d_state.getRepresentative(n);
577
          if (!r.isConst() && processed.find(r) == processed.end())
578
          {
579
            Trace("strings-model") << "(UNPROCESSED)";
580
          }
581
        }
582
      }
583
1933
      Trace("strings-model") << std::endl;
584
3866
      std::vector< Node > nc;
585
9043
      for (const Node& n : nf.d_nf)
586
      {
587
14220
        Node r = d_state.getRepresentative(n);
588
7110
        Assert(r.isConst() || processed.find(r) != processed.end());
589
7110
        nc.push_back(r.isConst() ? r : processed[r]);
590
      }
591
3866
      Node cc = utils::mkNConcat(nc, tn);
592
3866
      Trace("strings-model")
593
1933
          << "*** Determined constant " << cc << " for " << rn << std::endl;
594
1933
      processed[rn] = cc;
595
1933
      if (!m->assertEquality(rn, cc, true))
596
      {
597
        // this should never happen due to the model soundness argument
598
        // for strings
599
        Unreachable() << "TheoryStrings::collectModelInfoType: "
600
                         "Inconsistent equality (unprocessed eqc)"
601
                      << std::endl;
602
        return false;
603
      }
604
1933
      else if (!cc.isConst())
605
      {
606
        // the value may be specified by seq.unit components, ensure this
607
        // is marked as the skeleton for constructing values in this class.
608
3
        m->assertSkeleton(cc);
609
      }
610
    }
611
  }
612
  //Trace("strings-model") << "String Model : Assigned." << std::endl;
613
830
  Trace("strings-model") << "String Model : Finished." << std::endl;
614
830
  return true;
615
}
616
617
/////////////////////////////////////////////////////////////////////////////
618
// MAIN SOLVER
619
/////////////////////////////////////////////////////////////////////////////
620
621
145061
void TheoryStrings::preRegisterTerm(TNode n)
622
{
623
290122
  Trace("strings-preregister")
624
145061
      << "TheoryStrings::preRegisterTerm: " << n << std::endl;
625
145061
  d_termReg.preRegisterTerm(n);
626
  // Register the term with the extended theory. Notice we do not recurse on
627
  // this term here since preRegisterTerm is already called recursively on all
628
  // subterms in preregistered literals.
629
145061
  d_extTheory.registerTerm(n);
630
145061
}
631
632
946267
bool TheoryStrings::preNotifyFact(
633
    TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal)
634
{
635
  // this is only required for internal facts, others are already registered
636
946267
  if (isInternal && atom.getKind() == EQUAL)
637
  {
638
    // We must ensure these terms are registered. We register eagerly here for
639
    // performance reasons. Alternatively, terms could be registered at full
640
    // effort in e.g. BaseSolver::init.
641
88590
    for (const Node& t : atom)
642
    {
643
59060
      d_termReg.registerTerm(t, 0);
644
    }
645
  }
646
946267
  return false;
647
}
648
649
946267
void TheoryStrings::notifyFact(TNode atom,
650
                               bool polarity,
651
                               TNode fact,
652
                               bool isInternal)
653
{
654
946267
  d_eagerSolver.notifyFact(atom, polarity, fact, isInternal);
655
  // process pending conflicts due to reasoning about endpoints
656
946267
  if (!d_state.isInConflict() && d_state.hasPendingConflict())
657
  {
658
840
    InferInfo iiPendingConf(InferenceId::UNKNOWN);
659
420
    d_state.getPendingConflict(iiPendingConf);
660
840
    Trace("strings-pending")
661
420
        << "Process pending conflict " << iiPendingConf.d_premises << std::endl;
662
840
    Trace("strings-conflict")
663
420
        << "CONFLICT: Eager : " << iiPendingConf.d_premises << std::endl;
664
420
    ++(d_statistics.d_conflictsEager);
665
    // call the inference manager to send the conflict
666
420
    d_im.processConflict(iiPendingConf);
667
420
    return;
668
  }
669
945847
  Trace("strings-pending-debug") << "  Now collect terms" << std::endl;
670
945847
  Trace("strings-pending-debug") << "  Finished collect terms" << std::endl;
671
}
672
673
399908
void TheoryStrings::postCheck(Effort e)
674
{
675
399908
  d_im.doPendingFacts();
676
677
399908
  Assert(d_strat.isStrategyInit());
678
1197647
  if (!d_state.isInConflict() && !d_valuation.needCheck()
679
501033
      && d_strat.hasStrategyEffort(e))
680
  {
681
48756
    Trace("strings-check-debug")
682
24378
        << "Theory of strings " << e << " effort check " << std::endl;
683
24378
    if (Trace.isOn("strings-eqc"))
684
    {
685
      Trace("strings-eqc") << debugPrintStringsEqc() << std::endl;
686
    }
687
24378
    ++(d_statistics.d_checkRuns);
688
24378
    bool sentLemma = false;
689
24378
    bool hadPending = false;
690
24378
    Trace("strings-check") << "Full effort check..." << std::endl;
691
12671
    do{
692
37049
      d_im.reset();
693
37049
      ++(d_statistics.d_strategyRuns);
694
37049
      Trace("strings-check") << "  * Run strategy..." << std::endl;
695
37049
      runStrategy(e);
696
      // remember if we had pending facts or lemmas
697
37049
      hadPending = d_im.hasPending();
698
      // Send the facts *and* the lemmas. We send lemmas regardless of whether
699
      // we send facts since some lemmas cannot be dropped. Other lemmas are
700
      // otherwise avoided by aborting the strategy when a fact is ready.
701
37049
      d_im.doPending();
702
      // Did we successfully send a lemma? Notice that if hasPending = true
703
      // and sentLemma = false, then the above call may have:
704
      // (1) had no pending lemmas, but successfully processed pending facts,
705
      // (2) unsuccessfully processed pending lemmas.
706
      // In either case, we repeat the strategy if we are not in conflict.
707
37049
      sentLemma = d_im.hasSentLemma();
708
37049
      if (Trace.isOn("strings-check"))
709
      {
710
        Trace("strings-check") << "  ...finish run strategy: ";
711
        Trace("strings-check") << (hadPending ? "hadPending " : "");
712
        Trace("strings-check") << (sentLemma ? "sentLemma " : "");
713
        Trace("strings-check") << (d_state.isInConflict() ? "conflict " : "");
714
        if (!hadPending && !sentLemma && !d_state.isInConflict())
715
        {
716
          Trace("strings-check") << "(none)";
717
        }
718
        Trace("strings-check") << std::endl;
719
      }
720
      // repeat if we did not add a lemma or conflict, and we had pending
721
      // facts or lemmas.
722
37049
    } while (!d_state.isInConflict() && !sentLemma && hadPending);
723
  }
724
399908
  Trace("strings-check") << "Theory of strings, done check : " << e << std::endl;
725
399908
  Assert(!d_im.hasPendingFact());
726
399908
  Assert(!d_im.hasPendingLemma());
727
399908
}
728
729
6591
bool TheoryStrings::needsCheckLastEffort() {
730
6591
  if( options::stringGuessModel() ){
731
    return d_esolver.hasExtendedFunctions();
732
  }
733
6591
  return false;
734
}
735
736
/** Conflict when merging two constants */
737
1032
void TheoryStrings::conflict(TNode a, TNode b){
738
1032
  if (d_state.isInConflict())
739
  {
740
    // already in conflict
741
    return;
742
  }
743
1032
  d_im.conflictEqConstantMerge(a, b);
744
1032
  Trace("strings-conflict") << "CONFLICT: Eq engine conflict" << std::endl;
745
1032
  ++(d_statistics.d_conflictsEqEngine);
746
}
747
748
119502
void TheoryStrings::eqNotifyNewClass(TNode t){
749
119502
  Kind k = t.getKind();
750
119502
  if (k == STRING_LENGTH || k == STRING_TO_CODE)
751
  {
752
34023
    Trace("strings-debug") << "New length eqc : " << t << std::endl;
753
    //we care about the length of this string
754
34023
    d_termReg.registerTerm(t[0], 1);
755
  }
756
119502
  d_eagerSolver.eqNotifyNewClass(t);
757
119502
}
758
759
10923
void TheoryStrings::addCarePairs(TNodeTrie* t1,
760
                                 TNodeTrie* t2,
761
                                 unsigned arity,
762
                                 unsigned depth)
763
{
764
10923
  if( depth==arity ){
765
739
    if( t2!=NULL ){
766
1478
      Node f1 = t1->getData();
767
1478
      Node f2 = t2->getData();
768
739
      if (!d_equalityEngine->areEqual(f1, f2))
769
      {
770
419
        Trace("strings-cg-debug") << "TheoryStrings::computeCareGraph(): checking function " << f1 << " and " << f2 << std::endl;
771
838
        vector< pair<TNode, TNode> > currentPairs;
772
1229
        for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
773
1620
          TNode x = f1[k];
774
1620
          TNode y = f2[k];
775
810
          Assert(d_equalityEngine->hasTerm(x));
776
810
          Assert(d_equalityEngine->hasTerm(y));
777
810
          Assert(!d_equalityEngine->areDisequal(x, y, false));
778
810
          Assert(!areCareDisequal(x, y));
779
810
          if (!d_equalityEngine->areEqual(x, y))
780
          {
781
1293
            if (d_equalityEngine->isTriggerTerm(x, THEORY_STRINGS)
782
1293
                && d_equalityEngine->isTriggerTerm(y, THEORY_STRINGS))
783
            {
784
186
              TNode x_shared = d_equalityEngine->getTriggerTermRepresentative(
785
372
                  x, THEORY_STRINGS);
786
186
              TNode y_shared = d_equalityEngine->getTriggerTermRepresentative(
787
372
                  y, THEORY_STRINGS);
788
186
              currentPairs.push_back(make_pair(x_shared, y_shared));
789
            }
790
          }
791
        }
792
605
        for (unsigned c = 0; c < currentPairs.size(); ++ c) {
793
186
          Trace("strings-cg-pair") << "TheoryStrings::computeCareGraph(): pair : " << currentPairs[c].first << " " << currentPairs[c].second << std::endl;
794
186
          addCarePair(currentPairs[c].first, currentPairs[c].second);
795
        }
796
      }
797
    }
798
  }else{
799
10184
    if( t2==NULL ){
800
8911
      if( depth<(arity-1) ){
801
        //add care pairs internal to each child
802
9325
        for (std::pair<const TNode, TNodeTrie>& tt : t1->d_data)
803
        {
804
5965
          addCarePairs(&tt.second, nullptr, arity, depth + 1);
805
        }
806
      }
807
      //add care pairs based on each pair of non-disequal arguments
808
26463
      for (std::map<TNode, TNodeTrie>::iterator it = t1->d_data.begin();
809
26463
           it != t1->d_data.end();
810
           ++it)
811
      {
812
17552
        std::map<TNode, TNodeTrie>::iterator it2 = it;
813
17552
        ++it2;
814
103766
        for( ; it2 != t1->d_data.end(); ++it2 ){
815
43107
          if (!d_equalityEngine->areDisequal(it->first, it2->first, false))
816
          {
817
2200
            if( !areCareDisequal(it->first, it2->first) ){
818
1177
              addCarePairs( &it->second, &it2->second, arity, depth+1 );
819
            }
820
          }
821
        }
822
      }
823
    }else{
824
      //add care pairs based on product of indices, non-disequal arguments
825
3289
      for (std::pair<const TNode, TNodeTrie>& tt1 : t1->d_data)
826
      {
827
5282
        for (std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data)
828
        {
829
3266
          if (!d_equalityEngine->areDisequal(tt1.first, tt2.first, false))
830
          {
831
1303
            if (!areCareDisequal(tt1.first, tt2.first))
832
            {
833
835
              addCarePairs(&tt1.second, &tt2.second, arity, depth + 1);
834
            }
835
          }
836
        }
837
      }
838
    }
839
  }
840
10923
}
841
842
7217
void TheoryStrings::computeCareGraph(){
843
  //computing the care graph here is probably still necessary, due to operators that take non-string arguments  TODO: verify
844
7217
  Trace("strings-cg") << "TheoryStrings::computeCareGraph(): Build term indices..." << std::endl;
845
  // Term index for each (type, operator) pair. We require the operator here
846
  // since operators are polymorphic, taking strings/sequences.
847
14434
  std::map<std::pair<TypeNode, Node>, TNodeTrie> index;
848
14434
  std::map< Node, unsigned > arity;
849
7217
  const context::CDList<TNode>& fterms = d_termReg.getFunctionTerms();
850
7217
  size_t functionTerms = fterms.size();
851
46249
  for (unsigned i = 0; i < functionTerms; ++ i) {
852
78064
    TNode f1 = fterms[i];
853
39032
    Trace("strings-cg") << "...build for " << f1 << std::endl;
854
78064
    Node op = f1.getOperator();
855
78064
    std::vector< TNode > reps;
856
39032
    bool has_trigger_arg = false;
857
88485
    for( unsigned j=0; j<f1.getNumChildren(); j++ ){
858
49453
      reps.push_back(d_equalityEngine->getRepresentative(f1[j]));
859
49453
      if (d_equalityEngine->isTriggerTerm(f1[j], THEORY_STRINGS))
860
      {
861
35149
        has_trigger_arg = true;
862
      }
863
    }
864
39032
    if( has_trigger_arg ){
865
56772
      TypeNode ft = utils::getOwnerStringType(f1);
866
56772
      std::pair<TypeNode, Node> ikey = std::pair<TypeNode, Node>(ft, op);
867
28386
      index[ikey].addTerm(f1, reps);
868
28386
      arity[op] = reps.size();
869
    }
870
  }
871
  //for each index
872
10163
  for (std::pair<const std::pair<TypeNode, Node>, TNodeTrie>& ti : index)
873
  {
874
5892
    Trace("strings-cg") << "TheoryStrings::computeCareGraph(): Process index "
875
2946
                        << ti.first << "..." << std::endl;
876
5892
    Node op = ti.first.second;
877
2946
    addCarePairs(&ti.second, nullptr, arity[op], 0);
878
  }
879
7217
}
880
881
void TheoryStrings::checkRegisterTermsPreNormalForm()
882
{
883
  const std::vector<Node>& seqc = d_bsolver.getStringEqc();
884
  for (const Node& eqc : seqc)
885
  {
886
    eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, d_equalityEngine);
887
    while (!eqc_i.isFinished())
888
    {
889
      Node n = (*eqc_i);
890
      if (!d_bsolver.isCongruent(n))
891
      {
892
        d_termReg.registerTerm(n, 2);
893
      }
894
      ++eqc_i;
895
    }
896
  }
897
}
898
899
10642
void TheoryStrings::checkCodes()
900
{
901
  // ensure that lemmas regarding str.code been added for each constant string
902
  // of length one
903
10642
  if (d_termReg.hasStringCode())
904
  {
905
1089
    NodeManager* nm = NodeManager::currentNM();
906
    // str.code applied to the code term for each equivalence class that has a
907
    // code term but is not a constant
908
1995
    std::vector<Node> nconst_codes;
909
    // str.code applied to the proxy variables for each equivalence classes that
910
    // are constants of size one
911
1995
    std::vector<Node> const_codes;
912
1089
    const std::vector<Node>& seqc = d_bsolver.getStringEqc();
913
13547
    for (const Node& eqc : seqc)
914
    {
915
12458
      NormalForm& nfe = d_csolver.getNormalForm(eqc);
916
12458
      if (nfe.d_nf.size() == 1 && nfe.d_nf[0].isConst())
917
      {
918
10748
        Node c = nfe.d_nf[0];
919
10748
        Trace("strings-code-debug") << "Get proxy variable for " << c
920
5374
                                    << std::endl;
921
10748
        Node cc = nm->mkNode(kind::STRING_TO_CODE, c);
922
5374
        cc = Rewriter::rewrite(cc);
923
5374
        Assert(cc.isConst());
924
10748
        Node cp = d_termReg.ensureProxyVariableFor(c);
925
10748
        Node vc = nm->mkNode(STRING_TO_CODE, cp);
926
5374
        if (!d_state.areEqual(cc, vc))
927
        {
928
1190
          std::vector<Node> emptyVec;
929
595
          d_im.sendInference(emptyVec, cc.eqNode(vc), InferenceId::STRINGS_CODE_PROXY);
930
        }
931
5374
        const_codes.push_back(vc);
932
      }
933
      else
934
      {
935
7084
        EqcInfo* ei = d_state.getOrMakeEqcInfo(eqc, false);
936
7084
        if (ei && !ei->d_codeTerm.get().isNull())
937
        {
938
3940
          Node vc = nm->mkNode(kind::STRING_TO_CODE, ei->d_codeTerm.get());
939
1970
          nconst_codes.push_back(vc);
940
        }
941
      }
942
    }
943
1089
    if (d_im.hasProcessed())
944
    {
945
183
      return;
946
    }
947
    // now, ensure that str.code is injective
948
1812
    std::vector<Node> cmps;
949
906
    cmps.insert(cmps.end(), const_codes.rbegin(), const_codes.rend());
950
906
    cmps.insert(cmps.end(), nconst_codes.rbegin(), nconst_codes.rend());
951
2569
    for (unsigned i = 0, num_ncc = nconst_codes.size(); i < num_ncc; i++)
952
    {
953
3326
      Node c1 = nconst_codes[i];
954
1663
      cmps.pop_back();
955
9732
      for (const Node& c2 : cmps)
956
      {
957
16138
        Trace("strings-code-debug")
958
8069
            << "Compare codes : " << c1 << " " << c2 << std::endl;
959
8069
        if (!d_state.areDisequal(c1, c2) && !d_state.areEqual(c1, d_neg_one))
960
        {
961
2116
          Node eq_no = c1.eqNode(d_neg_one);
962
2116
          Node deq = c1.eqNode(c2).negate();
963
2116
          Node eqn = c1[0].eqNode(c2[0]);
964
          // str.code(x)==-1 V str.code(x)!=str.code(y) V x==y
965
2116
          Node inj_lem = nm->mkNode(kind::OR, eq_no, deq, eqn);
966
1058
          deq = Rewriter::rewrite(deq);
967
1058
          d_im.addPendingPhaseRequirement(deq, false);
968
2116
          std::vector<Node> emptyVec;
969
1058
          d_im.sendInference(emptyVec, inj_lem, InferenceId::STRINGS_CODE_INJ);
970
        }
971
      }
972
    }
973
  }
974
}
975
976
void TheoryStrings::checkRegisterTermsNormalForms()
977
{
978
  const std::vector<Node>& seqc = d_bsolver.getStringEqc();
979
  for (const Node& eqc : seqc)
980
  {
981
    NormalForm& nfi = d_csolver.getNormalForm(eqc);
982
    // check if there is a length term for this equivalence class
983
    EqcInfo* ei = d_state.getOrMakeEqcInfo(eqc, false);
984
    Node lt = ei ? ei->d_lengthTerm : Node::null();
985
    if (lt.isNull())
986
    {
987
      Node c = utils::mkNConcat(nfi.d_nf, eqc.getType());
988
      d_termReg.registerTerm(c, 3);
989
    }
990
  }
991
}
992
993
116519
TrustNode TheoryStrings::ppRewrite(TNode atom, std::vector<SkolemLemma>& lems)
994
{
995
116519
  Trace("strings-ppr") << "TheoryStrings::ppRewrite " << atom << std::endl;
996
116519
  if (atom.getKind() == EQUAL)
997
  {
998
    // always apply aggressive equality rewrites here
999
3745
    Node ret = d_rewriter.rewriteEqualityExt(atom);
1000
1936
    if (ret != atom)
1001
    {
1002
127
      return TrustNode::mkTrustRewrite(atom, ret, nullptr);
1003
    }
1004
  }
1005
116392
  if (atom.getKind() == STRING_FROM_CODE)
1006
  {
1007
    // str.from_code(t) --->
1008
    //   witness k. ite(0 <= t < |A|, t = str.to_code(k), k = "")
1009
59
    NodeManager* nm = NodeManager::currentNM();
1010
118
    Node t = atom[0];
1011
118
    Node card = nm->mkConst(Rational(utils::getAlphabetCardinality()));
1012
    Node cond =
1013
118
        nm->mkNode(AND, nm->mkNode(LEQ, d_zero, t), nm->mkNode(LT, t, card));
1014
118
    Node v = nm->mkBoundVar(nm->stringType());
1015
118
    Node emp = Word::mkEmptyWord(atom.getType());
1016
    Node pred = nm->mkNode(
1017
118
        ITE, cond, t.eqNode(nm->mkNode(STRING_TO_CODE, v)), v.eqNode(emp));
1018
59
    SkolemManager* sm = nm->getSkolemManager();
1019
118
    Node ret = sm->mkSkolem(v, pred, "kFromCode");
1020
59
    lems.push_back(SkolemLemma(ret, nullptr));
1021
59
    return TrustNode::mkTrustRewrite(atom, ret, nullptr);
1022
  }
1023
232666
  TrustNode ret;
1024
232666
  Node atomRet = atom;
1025
116333
  if (options::regExpElim() && atom.getKind() == STRING_IN_REGEXP)
1026
  {
1027
    // aggressive elimination of regular expression membership
1028
134
    ret = d_regexp_elim.eliminateTrusted(atomRet);
1029
134
    if (!ret.isNull())
1030
    {
1031
184
      Trace("strings-ppr") << "  rewrote " << atom << " -> " << ret.getNode()
1032
92
                           << " via regular expression elimination."
1033
92
                           << std::endl;
1034
92
      atomRet = ret.getNode();
1035
    }
1036
  }
1037
116333
  return ret;
1038
}
1039
1040
/** run the given inference step */
1041
263936
void TheoryStrings::runInferStep(InferStep s, int effort)
1042
{
1043
263936
  Trace("strings-process") << "Run " << s;
1044
263936
  if (effort > 0)
1045
  {
1046
38628
    Trace("strings-process") << ", effort = " << effort;
1047
  }
1048
263936
  Trace("strings-process") << "..." << std::endl;
1049
263936
  switch (s)
1050
  {
1051
37049
    case CHECK_INIT: d_bsolver.checkInit(); break;
1052
31103
    case CHECK_CONST_EQC: d_bsolver.checkConstantEquivalenceClasses(); break;
1053
42614
    case CHECK_EXTF_EVAL: d_esolver.checkExtfEval(effort); break;
1054
29196
    case CHECK_CYCLES: d_csolver.checkCycles(); break;
1055
29192
    case CHECK_FLAT_FORMS: d_csolver.checkFlatForms(); break;
1056
    case CHECK_REGISTER_TERMS_PRE_NF: checkRegisterTermsPreNormalForm(); break;
1057
19312
    case CHECK_NORMAL_FORMS_EQ: d_csolver.checkNormalFormsEq(); break;
1058
11114
    case CHECK_NORMAL_FORMS_DEQ: d_csolver.checkNormalFormsDeq(); break;
1059
10642
    case CHECK_CODES: checkCodes(); break;
1060
10290
    case CHECK_LENGTH_EQC: d_csolver.checkLengthsEqc(); break;
1061
    case CHECK_REGISTER_TERMS_NF: checkRegisterTermsNormalForms(); break;
1062
27117
    case CHECK_EXTF_REDUCTION: d_esolver.checkExtfReductions(effort); break;
1063
8348
    case CHECK_MEMBERSHIP: d_rsolver.checkMemberships(); break;
1064
7959
    case CHECK_CARDINALITY: d_bsolver.checkCardinality(); break;
1065
    default: Unreachable(); break;
1066
  }
1067
527872
  Trace("strings-process") << "Done " << s
1068
527872
                           << ", addedFact = " << d_im.hasPendingFact()
1069
527872
                           << ", addedLemma = " << d_im.hasPendingLemma()
1070
527872
                           << ", conflict = " << d_state.isInConflict()
1071
263936
                           << std::endl;
1072
263936
}
1073
1074
37049
void TheoryStrings::runStrategy(Theory::Effort e)
1075
{
1076
37049
  std::vector<std::pair<InferStep, int> >::iterator it = d_strat.stepBegin(e);
1077
  std::vector<std::pair<InferStep, int> >::iterator stepEnd =
1078
37049
      d_strat.stepEnd(e);
1079
1080
37049
  Trace("strings-process") << "----check, next round---" << std::endl;
1081
1016299
  while (it != stepEnd)
1082
  {
1083
518703
    InferStep curr = it->first;
1084
518703
    if (curr == BREAK)
1085
    {
1086
254767
      if (d_im.hasProcessed())
1087
      {
1088
27880
        break;
1089
      }
1090
    }
1091
    else
1092
    {
1093
263936
      runInferStep(curr, it->second);
1094
263936
      if (d_state.isInConflict())
1095
      {
1096
1198
        break;
1097
      }
1098
    }
1099
489625
    ++it;
1100
  }
1101
37049
  Trace("strings-process") << "----finished round---" << std::endl;
1102
37049
}
1103
1104
std::string TheoryStrings::debugPrintStringsEqc()
1105
{
1106
  std::stringstream ss;
1107
  for (unsigned t = 0; t < 2; t++)
1108
  {
1109
    eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator(d_equalityEngine);
1110
    ss << (t == 0 ? "STRINGS:" : "OTHER:") << std::endl;
1111
    while (!eqcs2_i.isFinished())
1112
    {
1113
      Node eqc = (*eqcs2_i);
1114
      bool print = (t == 0 && eqc.getType().isStringLike())
1115
                   || (t == 1 && !eqc.getType().isStringLike());
1116
      if (print)
1117
      {
1118
        eq::EqClassIterator eqc2_i = eq::EqClassIterator(eqc, d_equalityEngine);
1119
        ss << "Eqc( " << eqc << " ) : { ";
1120
        while (!eqc2_i.isFinished())
1121
        {
1122
          if ((*eqc2_i) != eqc && (*eqc2_i).getKind() != kind::EQUAL)
1123
          {
1124
            ss << (*eqc2_i) << " ";
1125
          }
1126
          ++eqc2_i;
1127
        }
1128
        ss << " } " << std::endl;
1129
        EqcInfo* ei = d_state.getOrMakeEqcInfo(eqc, false);
1130
        if (ei)
1131
        {
1132
          Trace("strings-eqc-debug")
1133
              << "* Length term : " << ei->d_lengthTerm.get() << std::endl;
1134
          Trace("strings-eqc-debug")
1135
              << "* Cardinality lemma k : " << ei->d_cardinalityLemK.get()
1136
              << std::endl;
1137
          Trace("strings-eqc-debug")
1138
              << "* Normalization length lemma : "
1139
              << ei->d_normalizedLength.get() << std::endl;
1140
        }
1141
      }
1142
      ++eqcs2_i;
1143
    }
1144
    ss << std::endl;
1145
  }
1146
  ss << std::endl;
1147
  return ss.str();
1148
}
1149
1150
}  // namespace strings
1151
}  // namespace theory
1152
29340
}  // namespace cvc5