GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/strings/solver_state.cpp Lines: 101 105 96.2 %
Date: 2021-09-17 Branches: 161 342 47.1 %

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
9942
SolverState::SolverState(Env& env, Valuation& v)
32
    : TheoryState(env, v),
33
      d_eeDisequalities(env.getContext()),
34
      d_pendingConflictSet(env.getContext(), false),
35
9942
      d_pendingConflict(InferenceId::UNKNOWN)
36
{
37
9942
  d_zero = NodeManager::currentNM()->mkConst(Rational(0));
38
9942
  d_false = NodeManager::currentNM()->mkConst(false);
39
9942
}
40
41
19878
SolverState::~SolverState()
42
{
43
40063
  for (std::pair<const Node, EqcInfo*>& it : d_eqcInfo)
44
  {
45
30124
    delete it.second;
46
  }
47
9939
}
48
49
11398
const context::CDList<Node>& SolverState::getDisequalityList() const
50
{
51
11398
  return d_eeDisequalities;
52
}
53
54
83183
void SolverState::addDisequality(TNode t1, TNode t2)
55
{
56
83183
  d_eeDisequalities.push_back(t1.eqNode(t2));
57
83183
}
58
59
2058142
EqcInfo* SolverState::getOrMakeEqcInfo(Node eqc, bool doMake)
60
{
61
2058142
  std::map<Node, EqcInfo*>::iterator eqc_i = d_eqcInfo.find(eqc);
62
2058142
  if (eqc_i != d_eqcInfo.end())
63
  {
64
979790
    return eqc_i->second;
65
  }
66
1078352
  if (doMake)
67
  {
68
30124
    EqcInfo* ei = new EqcInfo(d_env.getContext());
69
30124
    d_eqcInfo[eqc] = ei;
70
30124
    return ei;
71
  }
72
1048228
  return nullptr;
73
}
74
75
TheoryModel* SolverState::getModel() { return d_valuation.getModel(); }
76
77
1140687
Node SolverState::getLengthExp(Node t, std::vector<Node>& exp, Node te)
78
{
79
1140687
  Assert(areEqual(t, te));
80
2281374
  Node lt = utils::mkNLength(te);
81
1140687
  if (hasTerm(lt))
82
  {
83
    // use own length if it exists, leads to shorter explanation
84
1138243
    return lt;
85
  }
86
2444
  EqcInfo* ei = getOrMakeEqcInfo(t, false);
87
4888
  Node lengthTerm = ei ? ei->d_lengthTerm : Node::null();
88
2444
  if (lengthTerm.isNull())
89
  {
90
    // typically shouldnt be necessary
91
2402
    lengthTerm = t;
92
  }
93
4888
  Debug("strings") << "SolverState::getLengthTerm " << t << " is " << lengthTerm
94
2444
                   << std::endl;
95
2444
  if (te != lengthTerm)
96
  {
97
42
    exp.push_back(te.eqNode(lengthTerm));
98
  }
99
  return Rewriter::rewrite(
100
2444
      NodeManager::currentNM()->mkNode(STRING_LENGTH, lengthTerm));
101
}
102
103
1140683
Node SolverState::getLength(Node t, std::vector<Node>& exp)
104
{
105
1140683
  return getLengthExp(t, exp, t);
106
}
107
108
17276
Node SolverState::explainNonEmpty(Node s)
109
{
110
17276
  Assert(s.getType().isStringLike());
111
34552
  Node emp = Word::mkEmptyWord(s.getType());
112
17276
  if (areDisequal(s, emp))
113
  {
114
7416
    return s.eqNode(emp).negate();
115
  }
116
19720
  Node sLen = utils::mkNLength(s);
117
9860
  if (areDisequal(sLen, d_zero))
118
  {
119
9844
    return sLen.eqNode(d_zero).negate();
120
  }
121
16
  return Node::null();
122
}
123
124
949162
bool SolverState::isEqualEmptyWord(Node s, Node& emps)
125
{
126
1898324
  Node sr = getRepresentative(s);
127
949162
  if (sr.isConst())
128
  {
129
249049
    if (Word::getLength(sr) == 0)
130
    {
131
35045
      emps = sr;
132
35045
      return true;
133
    }
134
  }
135
914117
  return false;
136
}
137
138
97170
void SolverState::setPendingPrefixConflictWhen(Node conf)
139
{
140
97170
  if (conf.isNull() || d_pendingConflictSet.get())
141
  {
142
96634
    return;
143
  }
144
1072
  InferInfo iiPrefixConf(InferenceId::STRINGS_PREFIX_CONFLICT);
145
536
  iiPrefixConf.d_conc = d_false;
146
536
  utils::flattenOp(AND, conf, iiPrefixConf.d_premises);
147
536
  setPendingConflict(iiPrefixConf);
148
}
149
150
536
void SolverState::setPendingConflict(InferInfo& ii)
151
{
152
536
  if (!d_pendingConflictSet.get())
153
  {
154
536
    d_pendingConflict = ii;
155
536
    d_pendingConflictSet.set(true);
156
  }
157
536
}
158
159
1069857
bool SolverState::hasPendingConflict() const { return d_pendingConflictSet; }
160
161
443
bool SolverState::getPendingConflict(InferInfo& ii) const
162
{
163
443
  if (d_pendingConflictSet)
164
  {
165
443
    ii = d_pendingConflict;
166
443
    return true;
167
  }
168
  return false;
169
}
170
171
8475
std::pair<bool, Node> SolverState::entailmentCheck(options::TheoryOfMode mode,
172
                                                   TNode lit)
173
{
174
8475
  return d_valuation.entailmentCheck(mode, lit);
175
}
176
177
19737
void SolverState::separateByLength(
178
    const std::vector<Node>& n,
179
    std::map<TypeNode, std::vector<std::vector<Node>>>& cols,
180
    std::map<TypeNode, std::vector<Node>>& lts)
181
{
182
19737
  unsigned leqc_counter = 0;
183
  // map (length, type) to an equivalence class identifier
184
39474
  std::map<std::pair<Node, TypeNode>, unsigned> eqc_to_leqc;
185
  // backwards map
186
39474
  std::map<unsigned, std::pair<Node, TypeNode>> leqc_to_eqc;
187
  // Collection of eqc for each identifier. Notice that some identifiers may
188
  // not have an associated length in the mappings above, if the length of
189
  // an equivalence class is unknown.
190
39474
  std::map<unsigned, std::vector<Node> > eqc_to_strings;
191
19737
  NodeManager* nm = NodeManager::currentNM();
192
94851
  for (const Node& eqc : n)
193
  {
194
75114
    Assert(d_ee->getRepresentative(eqc) == eqc);
195
150228
    TypeNode tnEqc = eqc.getType();
196
75114
    EqcInfo* ei = getOrMakeEqcInfo(eqc, false);
197
150228
    Node lt = ei ? ei->d_lengthTerm : Node::null();
198
75114
    if (!lt.isNull())
199
    {
200
75114
      lt = nm->mkNode(STRING_LENGTH, lt);
201
150228
      Node r = d_ee->getRepresentative(lt);
202
150228
      std::pair<Node, TypeNode> lkey(r, tnEqc);
203
75114
      if (eqc_to_leqc.find(lkey) == eqc_to_leqc.end())
204
      {
205
47241
        eqc_to_leqc[lkey] = leqc_counter;
206
47241
        leqc_to_eqc[leqc_counter] = lkey;
207
47241
        leqc_counter++;
208
      }
209
75114
      eqc_to_strings[eqc_to_leqc[lkey]].push_back(eqc);
210
    }
211
    else
212
    {
213
      eqc_to_strings[leqc_counter].push_back(eqc);
214
      leqc_counter++;
215
    }
216
  }
217
66978
  for (const std::pair<const unsigned, std::vector<Node> >& p : eqc_to_strings)
218
  {
219
47241
    Assert(!p.second.empty());
220
    // get the type of the collection
221
94482
    TypeNode stn = p.second[0].getType();
222
47241
    cols[stn].emplace_back(p.second.begin(), p.second.end());
223
47241
    lts[stn].push_back(leqc_to_eqc[p.first].first);
224
  }
225
19737
}
226
227
}  // namespace strings
228
}  // namespace theory
229
29577
}  // namespace cvc5