GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/strings/solver_state.cpp Lines: 102 106 96.2 %
Date: 2021-08-16 Branches: 158 336 47.0 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Tianyi Liang, Mathias Preiner
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 solver state of the theory of strings.
14
 */
15
16
#include "theory/strings/solver_state.h"
17
18
#include "theory/rewriter.h"
19
#include "theory/strings/theory_strings_utils.h"
20
#include "theory/strings/word.h"
21
#include "util/rational.h"
22
23
using namespace std;
24
using namespace cvc5::context;
25
using namespace cvc5::kind;
26
27
namespace cvc5 {
28
namespace theory {
29
namespace strings {
30
31
9853
SolverState::SolverState(context::Context* c,
32
                         context::UserContext* u,
33
9853
                         Valuation& v)
34
9853
    : TheoryState(c, u, v), d_eeDisequalities(c), d_pendingConflictSet(c, false), d_pendingConflict(InferenceId::UNKNOWN)
35
{
36
9853
  d_zero = NodeManager::currentNM()->mkConst(Rational(0));
37
9853
  d_false = NodeManager::currentNM()->mkConst(false);
38
9853
}
39
40
19706
SolverState::~SolverState()
41
{
42
37984
  for (std::pair<const Node, EqcInfo*>& it : d_eqcInfo)
43
  {
44
28131
    delete it.second;
45
  }
46
9853
}
47
48
11114
const context::CDList<Node>& SolverState::getDisequalityList() const
49
{
50
11114
  return d_eeDisequalities;
51
}
52
53
73265
void SolverState::addDisequality(TNode t1, TNode t2)
54
{
55
73265
  d_eeDisequalities.push_back(t1.eqNode(t2));
56
73265
}
57
58
1833754
EqcInfo* SolverState::getOrMakeEqcInfo(Node eqc, bool doMake)
59
{
60
1833754
  std::map<Node, EqcInfo*>::iterator eqc_i = d_eqcInfo.find(eqc);
61
1833754
  if (eqc_i != d_eqcInfo.end())
62
  {
63
854142
    return eqc_i->second;
64
  }
65
979612
  if (doMake)
66
  {
67
28131
    EqcInfo* ei = new EqcInfo(d_context);
68
28131
    d_eqcInfo[eqc] = ei;
69
28131
    return ei;
70
  }
71
951481
  return nullptr;
72
}
73
74
TheoryModel* SolverState::getModel() { return d_valuation.getModel(); }
75
76
597640
Node SolverState::getLengthExp(Node t, std::vector<Node>& exp, Node te)
77
{
78
597640
  Assert(areEqual(t, te));
79
1195280
  Node lt = utils::mkNLength(te);
80
597640
  if (hasTerm(lt))
81
  {
82
    // use own length if it exists, leads to shorter explanation
83
595200
    return lt;
84
  }
85
2440
  EqcInfo* ei = getOrMakeEqcInfo(t, false);
86
4880
  Node lengthTerm = ei ? ei->d_lengthTerm : Node::null();
87
2440
  if (lengthTerm.isNull())
88
  {
89
    // typically shouldnt be necessary
90
2398
    lengthTerm = t;
91
  }
92
4880
  Debug("strings") << "SolverState::getLengthTerm " << t << " is " << lengthTerm
93
2440
                   << std::endl;
94
2440
  if (te != lengthTerm)
95
  {
96
42
    exp.push_back(te.eqNode(lengthTerm));
97
  }
98
  return Rewriter::rewrite(
99
2440
      NodeManager::currentNM()->mkNode(STRING_LENGTH, lengthTerm));
100
}
101
102
597636
Node SolverState::getLength(Node t, std::vector<Node>& exp)
103
{
104
597636
  return getLengthExp(t, exp, t);
105
}
106
107
14473
Node SolverState::explainNonEmpty(Node s)
108
{
109
14473
  Assert(s.getType().isStringLike());
110
28946
  Node emp = Word::mkEmptyWord(s.getType());
111
14473
  if (areDisequal(s, emp))
112
  {
113
6334
    return s.eqNode(emp).negate();
114
  }
115
16278
  Node sLen = utils::mkNLength(s);
116
8139
  if (areDisequal(sLen, d_zero))
117
  {
118
8123
    return sLen.eqNode(d_zero).negate();
119
  }
120
16
  return Node::null();
121
}
122
123
718958
bool SolverState::isEqualEmptyWord(Node s, Node& emps)
124
{
125
1437916
  Node sr = getRepresentative(s);
126
718958
  if (sr.isConst())
127
  {
128
198721
    if (Word::getLength(sr) == 0)
129
    {
130
29762
      emps = sr;
131
29762
      return true;
132
    }
133
  }
134
689196
  return false;
135
}
136
137
93460
void SolverState::setPendingPrefixConflictWhen(Node conf)
138
{
139
93460
  if (conf.isNull() || d_pendingConflictSet.get())
140
  {
141
92967
    return;
142
  }
143
986
  InferInfo iiPrefixConf(InferenceId::STRINGS_PREFIX_CONFLICT);
144
493
  iiPrefixConf.d_conc = d_false;
145
493
  utils::flattenOp(AND, conf, iiPrefixConf.d_premises);
146
493
  setPendingConflict(iiPrefixConf);
147
}
148
149
493
void SolverState::setPendingConflict(InferInfo& ii)
150
{
151
493
  if (!d_pendingConflictSet.get())
152
  {
153
493
    d_pendingConflict = ii;
154
493
    d_pendingConflictSet.set(true);
155
  }
156
493
}
157
158
943334
bool SolverState::hasPendingConflict() const { return d_pendingConflictSet; }
159
160
420
bool SolverState::getPendingConflict(InferInfo& ii) const
161
{
162
420
  if (d_pendingConflictSet)
163
  {
164
420
    ii = d_pendingConflict;
165
420
    return true;
166
  }
167
  return false;
168
}
169
170
6549
std::pair<bool, Node> SolverState::entailmentCheck(options::TheoryOfMode mode,
171
                                                   TNode lit)
172
{
173
6549
  return d_valuation.entailmentCheck(mode, lit);
174
}
175
176
19608
void SolverState::separateByLength(
177
    const std::vector<Node>& n,
178
    std::map<TypeNode, std::vector<std::vector<Node>>>& cols,
179
    std::map<TypeNode, std::vector<Node>>& lts)
180
{
181
19608
  unsigned leqc_counter = 0;
182
  // map (length, type) to an equivalence class identifier
183
39216
  std::map<std::pair<Node, TypeNode>, unsigned> eqc_to_leqc;
184
  // backwards map
185
39216
  std::map<unsigned, std::pair<Node, TypeNode>> leqc_to_eqc;
186
  // Collection of eqc for each identifier. Notice that some identifiers may
187
  // not have an associated length in the mappings above, if the length of
188
  // an equivalence class is unknown.
189
39216
  std::map<unsigned, std::vector<Node> > eqc_to_strings;
190
19608
  NodeManager* nm = NodeManager::currentNM();
191
80421
  for (const Node& eqc : n)
192
  {
193
60813
    Assert(d_ee->getRepresentative(eqc) == eqc);
194
121626
    TypeNode tnEqc = eqc.getType();
195
60813
    EqcInfo* ei = getOrMakeEqcInfo(eqc, false);
196
121626
    Node lt = ei ? ei->d_lengthTerm : Node::null();
197
60813
    if (!lt.isNull())
198
    {
199
60813
      lt = nm->mkNode(STRING_LENGTH, lt);
200
121626
      Node r = d_ee->getRepresentative(lt);
201
121626
      std::pair<Node, TypeNode> lkey(r, tnEqc);
202
60813
      if (eqc_to_leqc.find(lkey) == eqc_to_leqc.end())
203
      {
204
40133
        eqc_to_leqc[lkey] = leqc_counter;
205
40133
        leqc_to_eqc[leqc_counter] = lkey;
206
40133
        leqc_counter++;
207
      }
208
60813
      eqc_to_strings[eqc_to_leqc[lkey]].push_back(eqc);
209
    }
210
    else
211
    {
212
      eqc_to_strings[leqc_counter].push_back(eqc);
213
      leqc_counter++;
214
    }
215
  }
216
59741
  for (const std::pair<const unsigned, std::vector<Node> >& p : eqc_to_strings)
217
  {
218
40133
    Assert(!p.second.empty());
219
    // get the type of the collection
220
80266
    TypeNode stn = p.second[0].getType();
221
40133
    cols[stn].emplace_back(p.second.begin(), p.second.end());
222
40133
    lts[stn].push_back(leqc_to_eqc[p.first].first);
223
  }
224
19608
}
225
226
}  // namespace strings
227
}  // namespace theory
228
29340
}  // namespace cvc5