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