GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/strings/theory_strings.cpp Lines: 482 587 82.1 %
Date: 2021-09-07 Branches: 1021 2451 41.7 %

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