GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_inference_manager.cpp Lines: 178 215 82.8 %
Date: 2021-05-22 Branches: 217 518 41.9 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Gereon Kremer, 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
 * An inference manager for Theory.
14
 */
15
16
#include "theory/theory_inference_manager.h"
17
18
#include "smt/smt_engine_scope.h"
19
#include "smt/smt_statistics_registry.h"
20
#include "theory/output_channel.h"
21
#include "theory/rewriter.h"
22
#include "theory/theory.h"
23
#include "theory/theory_state.h"
24
#include "theory/uf/equality_engine.h"
25
#include "theory/uf/proof_equality_engine.h"
26
27
using namespace cvc5::kind;
28
29
namespace cvc5 {
30
namespace theory {
31
32
104060
TheoryInferenceManager::TheoryInferenceManager(Theory& t,
33
                                               TheoryState& state,
34
                                               ProofNodeManager* pnm,
35
                                               const std::string& statsName,
36
104060
                                               bool cacheLemmas)
37
    : d_theory(t),
38
      d_theoryState(state),
39
104060
      d_out(t.getOutputChannel()),
40
      d_ee(nullptr),
41
      d_decManager(nullptr),
42
      d_pnm(pnm),
43
      d_cacheLemmas(cacheLemmas),
44
      d_keep(t.getSatContext()),
45
104060
      d_lemmasSent(t.getUserContext()),
46
      d_numConflicts(0),
47
      d_numCurrentLemmas(0),
48
      d_numCurrentFacts(0),
49
104060
      d_conflictIdStats(smtStatisticsRegistry().registerHistogram<InferenceId>(
50
208120
          statsName + "inferencesConflict")),
51
104060
      d_factIdStats(smtStatisticsRegistry().registerHistogram<InferenceId>(
52
208120
          statsName + "inferencesFact")),
53
104060
      d_lemmaIdStats(smtStatisticsRegistry().registerHistogram<InferenceId>(
54
624360
          statsName + "inferencesLemma"))
55
{
56
  // don't add true lemma
57
208120
  Node truen = NodeManager::currentNM()->mkConst(true);
58
104060
  d_lemmasSent.insert(truen);
59
104060
}
60
61
104060
TheoryInferenceManager::~TheoryInferenceManager()
62
{
63
104060
}
64
65
104060
void TheoryInferenceManager::setEqualityEngine(eq::EqualityEngine* ee)
66
{
67
104060
  d_ee = ee;
68
  // if proofs are enabled, also make a proof equality engine to wrap ee
69
  // if it is non-null
70
104060
  if (d_pnm != nullptr && d_ee != nullptr)
71
  {
72
15714
    d_pfee.reset(new eq::ProofEqEngine(d_theoryState.getSatContext(),
73
7857
                                       d_theoryState.getUserContext(),
74
7857
                                       *d_ee,
75
15714
                                       d_pnm));
76
  }
77
104060
}
78
79
104060
void TheoryInferenceManager::setDecisionManager(DecisionManager* dm)
80
{
81
104060
  d_decManager = dm;
82
104060
}
83
84
19097
bool TheoryInferenceManager::isProofEnabled() const { return d_pnm != nullptr; }
85
86
734432
void TheoryInferenceManager::reset()
87
{
88
734432
  d_numConflicts = 0;
89
734432
  d_numCurrentLemmas = 0;
90
734432
  d_numCurrentFacts = 0;
91
734432
}
92
93
191034
bool TheoryInferenceManager::hasSent() const
94
{
95
382068
  return d_theoryState.isInConflict() || d_numCurrentLemmas > 0
96
372854
         || d_numCurrentFacts > 0;
97
}
98
99
9460
eq::ProofEqEngine* TheoryInferenceManager::getProofEqEngine()
100
{
101
9460
  return d_pfee.get();
102
}
103
104
11317
void TheoryInferenceManager::conflictEqConstantMerge(TNode a, TNode b)
105
{
106
11317
  if (!d_theoryState.isInConflict())
107
  {
108
22444
    TrustNode tconf = explainConflictEqConstantMerge(a, b);
109
11222
    trustedConflict(tconf, InferenceId::EQ_CONSTANT_MERGE);
110
  }
111
11317
}
112
113
75447
void TheoryInferenceManager::conflict(TNode conf, InferenceId id)
114
{
115
150894
  TrustNode tconf = TrustNode::mkTrustConflict(conf, nullptr);
116
150894
  return trustedConflict(tconf, id);
117
}
118
119
103505
void TheoryInferenceManager::trustedConflict(TrustNode tconf, InferenceId id)
120
{
121
103505
  d_conflictIdStats << id;
122
103505
  smt::currentResourceManager()->spendResource(id);
123
207010
  Trace("im") << "(conflict " << id << " " << tconf.getProven() << ")"
124
103505
              << std::endl;
125
103505
  d_theoryState.notifyInConflict();
126
103505
  d_out.trustedConflict(tconf);
127
103505
  ++d_numConflicts;
128
103505
}
129
130
void TheoryInferenceManager::conflictExp(InferenceId id,
131
                                         PfRule pfr,
132
                                         const std::vector<Node>& exp,
133
                                         const std::vector<Node>& args)
134
{
135
  if (!d_theoryState.isInConflict())
136
  {
137
    // make the trust node
138
    TrustNode tconf = mkConflictExp(pfr, exp, args);
139
    // send it on the output channel
140
    trustedConflict(tconf, id);
141
  }
142
}
143
144
TrustNode TheoryInferenceManager::mkConflictExp(PfRule id,
145
                                                const std::vector<Node>& exp,
146
                                                const std::vector<Node>& args)
147
{
148
  if (d_pfee != nullptr)
149
  {
150
    // use proof equality engine to construct the trust node
151
    return d_pfee->assertConflict(id, exp, args);
152
  }
153
  // version without proofs
154
  Node conf = mkExplainPartial(exp, {});
155
  return TrustNode::mkTrustConflict(conf, nullptr);
156
}
157
158
4520
void TheoryInferenceManager::conflictExp(InferenceId id,
159
                                         const std::vector<Node>& exp,
160
                                         ProofGenerator* pg)
161
{
162
4520
  if (!d_theoryState.isInConflict())
163
  {
164
    // make the trust node
165
8856
    TrustNode tconf = mkConflictExp(exp, pg);
166
    // send it on the output channel
167
4428
    trustedConflict(tconf, id);
168
  }
169
4520
}
170
171
5371
TrustNode TheoryInferenceManager::mkConflictExp(const std::vector<Node>& exp,
172
                                                ProofGenerator* pg)
173
{
174
5371
  if (d_pfee != nullptr)
175
  {
176
929
    Assert(pg != nullptr);
177
    // use proof equality engine to construct the trust node
178
929
    return d_pfee->assertConflict(exp, pg);
179
  }
180
  // version without proofs
181
8884
  Node conf = mkExplainPartial(exp, {});
182
4442
  return TrustNode::mkTrustConflict(conf, nullptr);
183
}
184
185
8610854
bool TheoryInferenceManager::propagateLit(TNode lit)
186
{
187
  // If already in conflict, no more propagation
188
8610854
  if (d_theoryState.isInConflict())
189
  {
190
2980
    return false;
191
  }
192
  // Propagate out
193
8607874
  bool ok = d_out.propagate(lit);
194
8607874
  if (!ok)
195
  {
196
60010
    d_theoryState.notifyInConflict();
197
  }
198
8607874
  return ok;
199
}
200
201
227531
TrustNode TheoryInferenceManager::explainLit(TNode lit)
202
{
203
227531
  if (d_pfee != nullptr)
204
  {
205
41673
    return d_pfee->explain(lit);
206
  }
207
185858
  if (d_ee != nullptr)
208
  {
209
371716
    Node exp = d_ee->mkExplainLit(lit);
210
185858
    return TrustNode::mkTrustPropExp(lit, exp, nullptr);
211
  }
212
  Unimplemented() << "Inference manager for " << d_theory.getId()
213
                  << " was asked to explain a propagation but doesn't have an "
214
                     "equality engine or implement the "
215
                     "TheoryInferenceManager::explainLit interface!";
216
}
217
218
11222
TrustNode TheoryInferenceManager::explainConflictEqConstantMerge(TNode a,
219
                                                                 TNode b)
220
{
221
22444
  Node lit = a.eqNode(b);
222
11222
  if (d_pfee != nullptr)
223
  {
224
1586
    return d_pfee->assertConflict(lit);
225
  }
226
9636
  if (d_ee != nullptr)
227
  {
228
19272
    Node conf = d_ee->mkExplainLit(lit);
229
9636
    return TrustNode::mkTrustConflict(conf, nullptr);
230
  }
231
  Unimplemented() << "Inference manager for " << d_theory.getId()
232
                  << " mkTrustedConflictEqConstantMerge";
233
}
234
235
449830
bool TheoryInferenceManager::lemma(TNode lem, InferenceId id, LemmaProperty p)
236
{
237
899659
  TrustNode tlem = TrustNode::mkTrustLemma(lem, nullptr);
238
899659
  return trustedLemma(tlem, id, p);
239
}
240
241
663786
bool TheoryInferenceManager::trustedLemma(const TrustNode& tlem,
242
                                          InferenceId id,
243
                                          LemmaProperty p)
244
{
245
  // if the policy says to cache lemmas, check the cache and return false if
246
  // we are a duplicate
247
663786
  if (d_cacheLemmas)
248
  {
249
619945
    if (!cacheLemma(tlem.getNode(), p))
250
    {
251
393724
      return false;
252
    }
253
  }
254
270062
  d_lemmaIdStats << id;
255
270062
  smt::currentResourceManager()->spendResource(id);
256
270062
  Trace("im") << "(lemma " << id << " " << tlem.getProven() << ")" << std::endl;
257
270062
  d_numCurrentLemmas++;
258
270064
  d_out.trustedLemma(tlem, p);
259
270060
  return true;
260
}
261
262
bool TheoryInferenceManager::lemmaExp(Node conc,
263
                                      InferenceId id,
264
                                      PfRule pfr,
265
                                      const std::vector<Node>& exp,
266
                                      const std::vector<Node>& noExplain,
267
                                      const std::vector<Node>& args,
268
                                      LemmaProperty p)
269
{
270
  // make the trust node
271
  TrustNode trn = mkLemmaExp(conc, pfr, exp, noExplain, args);
272
  // send it on the output channel
273
  return trustedLemma(trn, id, p);
274
}
275
276
TrustNode TheoryInferenceManager::mkLemmaExp(Node conc,
277
                                             PfRule id,
278
                                             const std::vector<Node>& exp,
279
                                             const std::vector<Node>& noExplain,
280
                                             const std::vector<Node>& args)
281
{
282
  if (d_pfee != nullptr)
283
  {
284
    // make the trust node from the proof equality engine
285
    return d_pfee->assertLemma(conc, id, exp, noExplain, args);
286
  }
287
  // otherwise, not using proofs, explain and make trust node
288
  Node ant = mkExplainPartial(exp, noExplain);
289
  Node lem = NodeManager::currentNM()->mkNode(kind::IMPLIES, ant, conc);
290
  return TrustNode::mkTrustLemma(lem, nullptr);
291
}
292
293
bool TheoryInferenceManager::lemmaExp(Node conc,
294
                                      InferenceId id,
295
                                      const std::vector<Node>& exp,
296
                                      const std::vector<Node>& noExplain,
297
                                      ProofGenerator* pg,
298
                                      LemmaProperty p)
299
{
300
  // make the trust node
301
  TrustNode trn = mkLemmaExp(conc, exp, noExplain, pg);
302
  // send it on the output channel
303
  return trustedLemma(trn, id, p);
304
}
305
306
15490
TrustNode TheoryInferenceManager::mkLemmaExp(Node conc,
307
                                             const std::vector<Node>& exp,
308
                                             const std::vector<Node>& noExplain,
309
                                             ProofGenerator* pg)
310
{
311
15490
  if (d_pfee != nullptr)
312
  {
313
    // make the trust node from the proof equality engine
314
947
    return d_pfee->assertLemma(conc, exp, noExplain, pg);
315
  }
316
  // otherwise, not using proofs, explain and make trust node
317
29086
  Node ant = mkExplainPartial(exp, noExplain);
318
29086
  Node lem = NodeManager::currentNM()->mkNode(kind::IMPLIES, ant, conc);
319
14543
  return TrustNode::mkTrustLemma(lem, nullptr);
320
}
321
322
120471
bool TheoryInferenceManager::hasCachedLemma(TNode lem, LemmaProperty p)
323
{
324
240942
  Node rewritten = Rewriter::rewrite(lem);
325
240942
  return d_lemmasSent.find(rewritten) != d_lemmasSent.end();
326
}
327
328
uint32_t TheoryInferenceManager::numSentLemmas() const
329
{
330
  return d_numCurrentLemmas;
331
}
332
333
463007
bool TheoryInferenceManager::hasSentLemma() const
334
{
335
463007
  return d_numCurrentLemmas != 0;
336
}
337
338
23608
bool TheoryInferenceManager::assertInternalFact(TNode atom,
339
                                                bool pol,
340
                                                InferenceId id,
341
                                                TNode exp)
342
{
343
70824
  return processInternalFact(
344
70824
      atom, pol, id, PfRule::UNKNOWN, {exp}, {}, nullptr);
345
}
346
347
2404
bool TheoryInferenceManager::assertInternalFact(TNode atom,
348
                                                bool pol,
349
                                                InferenceId id,
350
                                                PfRule pfr,
351
                                                const std::vector<Node>& exp,
352
                                                const std::vector<Node>& args)
353
{
354
2404
  Assert(pfr != PfRule::UNKNOWN);
355
2404
  return processInternalFact(atom, pol, id, pfr, exp, args, nullptr);
356
}
357
358
304279
bool TheoryInferenceManager::assertInternalFact(TNode atom,
359
                                                bool pol,
360
                                                InferenceId id,
361
                                                const std::vector<Node>& exp,
362
                                                ProofGenerator* pg)
363
{
364
304279
  return processInternalFact(atom, pol, id, PfRule::ASSUME, exp, {}, pg);
365
}
366
367
330291
bool TheoryInferenceManager::processInternalFact(TNode atom,
368
                                                 bool pol,
369
                                                 InferenceId iid,
370
                                                 PfRule id,
371
                                                 const std::vector<Node>& exp,
372
                                                 const std::vector<Node>& args,
373
                                                 ProofGenerator* pg)
374
{
375
330291
  d_factIdStats << iid;
376
330291
  smt::currentResourceManager()->spendResource(iid);
377
660582
  Trace("im") << "(fact " << iid << " " << (pol ? Node(atom) : atom.notNode())
378
330291
              << ")" << std::endl;
379
  // make the node corresponding to the explanation
380
660582
  Node expn = NodeManager::currentNM()->mkAnd(exp);
381
  // call the pre-notify fact method with preReg = false, isInternal = true
382
330291
  if (d_theory.preNotifyFact(atom, pol, expn, false, true))
383
  {
384
    // Handled in a theory-specific way that doesn't require equality engine,
385
    // notice we return true, indicating that the fact was processed.
386
    return true;
387
  }
388
330291
  Assert(d_ee != nullptr);
389
660582
  Trace("infer-manager") << "TheoryInferenceManager::assertInternalFact: "
390
330291
                         << expn << std::endl;
391
330291
  d_numCurrentFacts++;
392
  // Now, assert the fact. How to do so depends on whether proofs are enabled.
393
  // If no proof production, or no proof rule was given
394
330291
  bool ret = false;
395
330291
  if (d_pfee == nullptr || id == PfRule::UNKNOWN)
396
  {
397
317563
    if (atom.getKind() == kind::EQUAL)
398
    {
399
267120
      ret = d_ee->assertEquality(atom, pol, expn);
400
    }
401
    else
402
    {
403
50443
      ret = d_ee->assertPredicate(atom, pol, expn);
404
    }
405
    // Must reference count the equality and its explanation, which is not done
406
    // by the equality engine. Notice that we do *not* need to do this for
407
    // external assertions, which enter as facts in theory check. This is also
408
    // not done if we are asserting to the proof equality engine, which does
409
    // this caching itself within ProofEqEngine::assertFact.
410
317563
    d_keep.insert(atom);
411
317563
    d_keep.insert(expn);
412
  }
413
  else
414
  {
415
    // Note that we reconstruct the original literal lit here, since both the
416
    // original literal is needed for bookkeeping proofs. It is possible to
417
    // optimize this so that a few less nodes are created, but at the cost
418
    // of a more verbose interface to proof equality engine.
419
25456
    Node lit = pol ? Node(atom) : atom.notNode();
420
12728
    if (pg != nullptr)
421
    {
422
      // use the proof generator interface
423
11330
      ret = d_pfee->assertFact(lit, expn, pg);
424
    }
425
    else
426
    {
427
      // use the explict proof step interface
428
1398
      ret = d_pfee->assertFact(lit, id, expn, args);
429
    }
430
  }
431
  // call the notify fact method with isInternal = true
432
330291
  d_theory.notifyFact(atom, pol, expn, true);
433
660582
  Trace("infer-manager")
434
330291
      << "TheoryInferenceManager::finished assertInternalFact" << std::endl;
435
330291
  return ret;
436
}
437
438
35207
void TheoryInferenceManager::explain(TNode n, std::vector<TNode>& assumptions)
439
{
440
35207
  if (n.getKind() == kind::AND)
441
  {
442
    for (const Node& nc : n)
443
    {
444
      d_ee->explainLit(nc, assumptions);
445
    }
446
  }
447
  else
448
  {
449
35207
    d_ee->explainLit(n, assumptions);
450
  }
451
35207
}
452
453
Node TheoryInferenceManager::mkExplain(TNode n)
454
{
455
  std::vector<TNode> assumptions;
456
  explain(n, assumptions);
457
  return NodeManager::currentNM()->mkAnd(assumptions);
458
}
459
460
18985
Node TheoryInferenceManager::mkExplainPartial(
461
    const std::vector<Node>& exp, const std::vector<Node>& noExplain)
462
{
463
37970
  std::vector<TNode> assumps;
464
56643
  for (const Node& e : exp)
465
  {
466
40109
    if (std::find(noExplain.begin(), noExplain.end(), e) != noExplain.end())
467
    {
468
2451
      if (std::find(assumps.begin(), assumps.end(), e) == assumps.end())
469
      {
470
        // a non-explained literal
471
2451
        assumps.push_back(e);
472
      }
473
2451
      continue;
474
    }
475
    // otherwise, explain it
476
35207
    explain(e, assumps);
477
  }
478
37970
  return NodeManager::currentNM()->mkAnd(assumps);
479
}
480
481
uint32_t TheoryInferenceManager::numSentFacts() const
482
{
483
  return d_numCurrentFacts;
484
}
485
486
57194
bool TheoryInferenceManager::hasSentFact() const
487
{
488
57194
  return d_numCurrentFacts != 0;
489
}
490
491
619945
bool TheoryInferenceManager::cacheLemma(TNode lem, LemmaProperty p)
492
{
493
1239890
  Node rewritten = Rewriter::rewrite(lem);
494
619945
  if (d_lemmasSent.find(rewritten) != d_lemmasSent.end())
495
  {
496
393724
    return false;
497
  }
498
226221
  d_lemmasSent.insert(rewritten);
499
226221
  return true;
500
}
501
502
13306
DecisionManager* TheoryInferenceManager::getDecisionManager()
503
{
504
13306
  return d_decManager;
505
}
506
507
24386
void TheoryInferenceManager::requirePhase(TNode n, bool pol)
508
{
509
24386
  return d_out.requirePhase(n, pol);
510
}
511
512
728065
void TheoryInferenceManager::spendResource(Resource r)
513
{
514
728065
  d_out.spendResource(r);
515
728065
}
516
517
22244238
void TheoryInferenceManager::safePoint(Resource r)
518
{
519
22244238
  d_out.safePoint(r);
520
22244238
}
521
522
2091
void TheoryInferenceManager::setIncomplete(IncompleteId id)
523
{
524
2091
  d_out.setIncomplete(id);
525
2091
}
526
527
}  // namespace theory
528
28194
}  // namespace cvc5