GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/shared_terms_database.cpp Lines: 133 156 85.3 %
Date: 2021-11-07 Branches: 228 704 32.4 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Dejan Jovanovic, Morgan Deters
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
 * [[ Add lengthier description here ]]
14
 * \todo document this file
15
 */
16
17
#include "theory/shared_terms_database.h"
18
19
#include "smt/smt_statistics_registry.h"
20
#include "theory/theory_engine.h"
21
22
using namespace std;
23
using namespace cvc5::theory;
24
25
namespace cvc5 {
26
27
15273
SharedTermsDatabase::SharedTermsDatabase(Env& env, TheoryEngine* theoryEngine)
28
    : ContextNotifyObj(env.getContext()),
29
      d_env(env),
30
      d_statSharedTerms(
31
30546
          smtStatisticsRegistry().registerInt("theory::shared_terms")),
32
      d_addedSharedTermsSize(env.getContext(), 0),
33
      d_termsToTheories(env.getContext()),
34
      d_alreadyNotifiedMap(env.getContext()),
35
      d_registeredEqualities(env.getContext()),
36
      d_EENotify(*this),
37
      d_theoryEngine(theoryEngine),
38
      d_inConflict(env.getContext(), false),
39
      d_conflictPolarity(),
40
      d_equalityEngine(nullptr),
41
45819
      d_pfee(nullptr)
42
{
43
15273
}
44
45
15273
void SharedTermsDatabase::setEqualityEngine(eq::EqualityEngine* ee)
46
{
47
15273
  Assert(ee != nullptr);
48
15273
  d_equalityEngine = ee;
49
  // if proofs are enabled, make the proof equality engine if necessary
50
15273
  if (d_env.isTheoryProofProducing())
51
  {
52
5372
    d_pfee = d_equalityEngine->getProofEqualityEngine();
53
5372
    if (d_pfee == nullptr)
54
    {
55
5364
      d_pfeeAlloc = std::make_unique<eq::ProofEqEngine>(d_env, *ee);
56
5364
      d_pfee = d_pfeeAlloc.get();
57
5364
      d_equalityEngine->setProofEqualityEngine(d_pfee);
58
    }
59
  }
60
15273
}
61
62
15273
bool SharedTermsDatabase::needsEqualityEngine(EeSetupInfo& esi)
63
{
64
15273
  esi.d_notify = &d_EENotify;
65
15273
  esi.d_name = "shared::ee";
66
15273
  return true;
67
}
68
69
522840
void SharedTermsDatabase::addEqualityToPropagate(TNode equality) {
70
522840
  Assert(d_equalityEngine != nullptr);
71
522840
  d_registeredEqualities.insert(equality);
72
522840
  d_equalityEngine->addTriggerPredicate(equality);
73
522840
  checkForConflict();
74
522840
}
75
76
1397679
void SharedTermsDatabase::addSharedTerm(TNode atom,
77
                                        TNode term,
78
                                        TheoryIdSet theories)
79
{
80
2795358
  Debug("register") << "SharedTermsDatabase::addSharedTerm(" << atom << ", "
81
2795358
                    << term << ", " << TheoryIdSetUtil::setToString(theories)
82
1397679
                    << ")" << std::endl;
83
84
2795358
  std::pair<TNode, TNode> search_pair(atom, term);
85
1397679
  SharedTermsTheoriesMap::iterator find = d_termsToTheories.find(search_pair);
86
1397679
  if (find == d_termsToTheories.end()) {
87
    // First time for this term and this atom
88
1394764
    d_atomsToTerms[atom].push_back(term);
89
1394764
    d_addedSharedTerms.push_back(atom);
90
1394764
    d_addedSharedTermsSize = d_addedSharedTermsSize + 1;
91
1394764
    d_termsToTheories[search_pair] = theories;
92
  } else {
93
2915
    Assert(theories != (*find).second);
94
2915
    d_termsToTheories[search_pair] =
95
5830
        TheoryIdSetUtil::setUnion(theories, (*find).second);
96
  }
97
1397679
}
98
99
8215500
SharedTermsDatabase::shared_terms_iterator SharedTermsDatabase::begin(TNode atom) const {
100
8215500
  Assert(hasSharedTerms(atom));
101
8215500
  return d_atomsToTerms.find(atom)->second.begin();
102
}
103
104
8215500
SharedTermsDatabase::shared_terms_iterator SharedTermsDatabase::end(TNode atom) const {
105
8215500
  Assert(hasSharedTerms(atom));
106
8215500
  return d_atomsToTerms.find(atom)->second.end();
107
}
108
109
28068586
bool SharedTermsDatabase::hasSharedTerms(TNode atom) const {
110
28068586
  return d_atomsToTerms.find(atom) != d_atomsToTerms.end();
111
}
112
113
3808038
void SharedTermsDatabase::backtrack() {
114
5202802
  for (int i = d_addedSharedTerms.size() - 1, i_end = (int)d_addedSharedTermsSize; i >= i_end; -- i) {
115
2789528
    TNode atom = d_addedSharedTerms[i];
116
1394764
    shared_terms_list& list = d_atomsToTerms[atom];
117
1394764
    list.pop_back();
118
1394764
    if (list.empty()) {
119
548760
      d_atomsToTerms.erase(atom);
120
    }
121
  }
122
3808038
  d_addedSharedTerms.resize(d_addedSharedTermsSize);
123
3808038
}
124
125
20608540
TheoryIdSet SharedTermsDatabase::getTheoriesToNotify(TNode atom,
126
                                                     TNode term) const
127
{
128
  // Get the theories that share this term from this atom
129
41217080
  std::pair<TNode, TNode> search_pair(atom, term);
130
20608540
  SharedTermsTheoriesMap::iterator find = d_termsToTheories.find(search_pair);
131
20608540
  Assert(find != d_termsToTheories.end());
132
133
  // Get the theories that were already notified
134
20608540
  TheoryIdSet alreadyNotified = 0;
135
20608540
  AlreadyNotifiedMap::iterator theoriesFind = d_alreadyNotifiedMap.find(term);
136
20608540
  if (theoriesFind != d_alreadyNotifiedMap.end()) {
137
19361922
    alreadyNotified = (*theoriesFind).second;
138
  }
139
140
  // Return the ones that haven't been notified yet
141
41217080
  return TheoryIdSetUtil::setDifference((*find).second, alreadyNotified);
142
}
143
144
TheoryIdSet SharedTermsDatabase::getNotifiedTheories(TNode term) const
145
{
146
  // Get the theories that were already notified
147
  AlreadyNotifiedMap::iterator theoriesFind = d_alreadyNotifiedMap.find(term);
148
  if (theoriesFind != d_alreadyNotifiedMap.end()) {
149
    return (*theoriesFind).second;
150
  } else {
151
    return 0;
152
  }
153
}
154
155
4845789
bool SharedTermsDatabase::propagateSharedEquality(TheoryId theory, TNode a, TNode b, bool value)
156
{
157
4845789
  Debug("shared-terms-database") << "SharedTermsDatabase::newEquality(" << theory << "," << a << "," << b << ", " << (value ? "true" : "false") << ")" << endl;
158
159
4845789
  if (d_inConflict) {
160
    return false;
161
  }
162
163
  // Propagate away
164
9691578
  Node equality = a.eqNode(b);
165
4845789
  if (value) {
166
2989147
    d_theoryEngine->assertToTheory(equality, equality, theory, THEORY_BUILTIN);
167
  } else {
168
1856642
    d_theoryEngine->assertToTheory(equality.notNode(), equality.notNode(), theory, THEORY_BUILTIN);
169
  }
170
171
  // As you were
172
4845789
  return true;
173
}
174
175
20608540
void SharedTermsDatabase::markNotified(TNode term, TheoryIdSet theories)
176
{
177
  // Find out if there are any new theories that were notified about this term
178
20608540
  TheoryIdSet alreadyNotified = 0;
179
20608540
  AlreadyNotifiedMap::iterator theoriesFind = d_alreadyNotifiedMap.find(term);
180
20608540
  if (theoriesFind != d_alreadyNotifiedMap.end()) {
181
19361922
    alreadyNotified = (*theoriesFind).second;
182
  }
183
  TheoryIdSet newlyNotified =
184
20608540
      TheoryIdSetUtil::setDifference(theories, alreadyNotified);
185
186
  // If no new theories were notified, we are done
187
20608540
  if (newlyNotified == 0) {
188
38659550
    return;
189
  }
190
191
1278765
  Debug("shared-terms-database") << "SharedTermsDatabase::markNotified(" << term << ")" << endl;
192
193
  // First update the set of notified theories for this term
194
1278765
  d_alreadyNotifiedMap[term] =
195
2557530
      TheoryIdSetUtil::setUnion(newlyNotified, alreadyNotified);
196
197
1278765
  if (d_equalityEngine == nullptr)
198
  {
199
    // if we are not assigned an equality engine, there is nothing to do
200
    return;
201
  }
202
203
  // Mark the shared terms in the equality engine
204
  theory::TheoryId currentTheory;
205
2570273
  while ((currentTheory = TheoryIdSetUtil::setPop(newlyNotified))
206
3849038
         != THEORY_LAST)
207
  {
208
2570273
    d_equalityEngine->addTriggerTerm(term, currentTheory);
209
  }
210
211
  // Check for any conflits
212
1278765
  checkForConflict();
213
}
214
215
1292821
bool SharedTermsDatabase::areEqual(TNode a, TNode b) const {
216
1292821
  Assert(d_equalityEngine != nullptr);
217
1292821
  if (d_equalityEngine->hasTerm(a) && d_equalityEngine->hasTerm(b))
218
  {
219
1292821
    return d_equalityEngine->areEqual(a, b);
220
  } else {
221
    Assert(d_equalityEngine->hasTerm(a) || a.isConst());
222
    Assert(d_equalityEngine->hasTerm(b) || b.isConst());
223
    // since one (or both) of them is a constant, and the other is in the equality engine, they are not same
224
    return false;
225
  }
226
}
227
228
1118299
bool SharedTermsDatabase::areDisequal(TNode a, TNode b) const {
229
1118299
  Assert(d_equalityEngine != nullptr);
230
1118299
  if (d_equalityEngine->hasTerm(a) && d_equalityEngine->hasTerm(b))
231
  {
232
1118299
    return d_equalityEngine->areDisequal(a, b, false);
233
  } else {
234
    Assert(d_equalityEngine->hasTerm(a) || a.isConst());
235
    Assert(d_equalityEngine->hasTerm(b) || b.isConst());
236
    // one (or both) are in the equality engine
237
    return false;
238
  }
239
}
240
241
theory::eq::EqualityEngine* SharedTermsDatabase::getEqualityEngine()
242
{
243
  return d_equalityEngine;
244
}
245
246
7897718
void SharedTermsDatabase::assertShared(TNode n, bool polarity, TNode reason)
247
{
248
7897718
  Assert(d_equalityEngine != nullptr);
249
15795436
  Debug("shared-terms-database::assert")
250
7897718
      << "SharedTermsDatabase::assertShared(" << n << ", "
251
7897718
      << (polarity ? "true" : "false") << ", " << reason << ")" << endl;
252
  // Add it to the equality engine
253
7897718
  if (n.getKind() == kind::EQUAL)
254
  {
255
7897718
    d_equalityEngine->assertEquality(n, polarity, reason);
256
  }
257
  else
258
  {
259
    d_equalityEngine->assertPredicate(n, polarity, reason);
260
  }
261
  // Check for conflict
262
7897718
  checkForConflict();
263
7897718
}
264
265
6247794
bool SharedTermsDatabase::propagateEquality(TNode equality, bool polarity) {
266
6247794
  if (polarity) {
267
2356760
    d_theoryEngine->propagate(equality, THEORY_BUILTIN);
268
  } else {
269
3891034
    d_theoryEngine->propagate(equality.notNode(), THEORY_BUILTIN);
270
  }
271
6247794
  return true;
272
}
273
274
9699323
void SharedTermsDatabase::checkForConflict()
275
{
276
9699323
  if (!d_inConflict)
277
  {
278
9685202
    return;
279
  }
280
14121
  d_inConflict = false;
281
28242
  TrustNode trnc;
282
14121
  if (d_pfee != nullptr)
283
  {
284
2066
    Node conflict = d_conflictLHS.eqNode(d_conflictRHS);
285
1033
    conflict = d_conflictPolarity ? conflict : conflict.notNode();
286
1033
    trnc = d_pfee->assertConflict(conflict);
287
  }
288
  else
289
  {
290
    // standard explain
291
26176
    std::vector<TNode> assumptions;
292
26176
    d_equalityEngine->explainEquality(
293
13088
        d_conflictLHS, d_conflictRHS, d_conflictPolarity, assumptions);
294
26176
    Node conflictNode = NodeManager::currentNM()->mkAnd(assumptions);
295
13088
    trnc = TrustNode::mkTrustConflict(conflictNode, nullptr);
296
  }
297
14121
  d_theoryEngine->conflict(trnc, THEORY_BUILTIN);
298
14121
  d_conflictLHS = d_conflictRHS = Node::null();
299
}
300
301
bool SharedTermsDatabase::isKnown(TNode literal) const {
302
  Assert(d_equalityEngine != nullptr);
303
  bool polarity = literal.getKind() != kind::NOT;
304
  TNode equality = polarity ? literal : literal[0];
305
  if (polarity) {
306
    return d_equalityEngine->areEqual(equality[0], equality[1]);
307
  } else {
308
    return d_equalityEngine->areDisequal(equality[0], equality[1], false);
309
  }
310
}
311
312
148554
TrustNode SharedTermsDatabase::explain(TNode literal) const
313
{
314
148554
  if (d_pfee != nullptr)
315
  {
316
    // use the proof equality engine if it exists
317
15239
    return d_pfee->explain(literal);
318
  }
319
  // otherwise, explain without proofs
320
266630
  Node exp = d_equalityEngine->mkExplainLit(literal);
321
  // no proof generator
322
133315
  return TrustNode::mkTrustPropExp(literal, exp, nullptr);
323
}
324
325
31137
}  // namespace cvc5