GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_inference_manager.cpp Lines: 219 244 89.8 %
Date: 2021-11-05 Branches: 359 844 42.5 %

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_statistics_registry.h"
19
#include "theory/output_channel.h"
20
#include "theory/rewriter.h"
21
#include "theory/theory.h"
22
#include "theory/theory_state.h"
23
#include "theory/uf/equality_engine.h"
24
#include "theory/uf/proof_equality_engine.h"
25
26
using namespace cvc5::kind;
27
28
namespace cvc5 {
29
namespace theory {
30
31
183252
TheoryInferenceManager::TheoryInferenceManager(Env& env,
32
                                               Theory& t,
33
                                               TheoryState& state,
34
                                               const std::string& statsName,
35
183252
                                               bool cacheLemmas)
36
    : EnvObj(env),
37
      d_theory(t),
38
      d_theoryState(state),
39
183252
      d_out(t.getOutputChannel()),
40
      d_ee(nullptr),
41
      d_decManager(nullptr),
42
      d_pfee(nullptr),
43
      d_cacheLemmas(cacheLemmas),
44
      d_keep(context()),
45
183252
      d_lemmasSent(userContext()),
46
      d_numConflicts(0),
47
      d_numCurrentLemmas(0),
48
      d_numCurrentFacts(0),
49
183252
      d_conflictIdStats(statisticsRegistry().registerHistogram<InferenceId>(
50
366504
          statsName + "inferencesConflict")),
51
183252
      d_factIdStats(statisticsRegistry().registerHistogram<InferenceId>(
52
366504
          statsName + "inferencesFact")),
53
183252
      d_lemmaIdStats(statisticsRegistry().registerHistogram<InferenceId>(
54
1099512
          statsName + "inferencesLemma"))
55
{
56
  // don't add true lemma
57
366504
  Node truen = NodeManager::currentNM()->mkConst(true);
58
183252
  d_lemmasSent.insert(truen);
59
183252
}
60
61
183192
TheoryInferenceManager::~TheoryInferenceManager()
62
{
63
183192
}
64
65
183252
void TheoryInferenceManager::setEqualityEngine(eq::EqualityEngine* ee)
66
{
67
183252
  d_ee = ee;
68
  // if proofs are enabled, also make a proof equality engine to wrap ee
69
  // if it is non-null. If its proof equality engine has already been assigned,
70
  // use it. This is to ensure that all theories use the same proof equality
71
  // engine when in ee-mode=central.
72
183252
  if (isProofEnabled() && d_ee != nullptr)
73
  {
74
58580
    d_pfee = d_ee->getProofEqualityEngine();
75
58580
    if (d_pfee == nullptr)
76
    {
77
58492
      d_pfeeAlloc = std::make_unique<eq::ProofEqEngine>(d_env, *d_ee);
78
58492
      d_pfee = d_pfeeAlloc.get();
79
58492
      d_ee->setProofEqualityEngine(d_pfee);
80
    }
81
  }
82
183252
}
83
84
183252
void TheoryInferenceManager::setDecisionManager(DecisionManager* dm)
85
{
86
183252
  d_decManager = dm;
87
183252
}
88
89
857414
bool TheoryInferenceManager::isProofEnabled() const
90
{
91
857414
  return d_env.isTheoryProofProducing();
92
}
93
94
3972124
void TheoryInferenceManager::reset()
95
{
96
3972124
  d_numConflicts = 0;
97
3972124
  d_numCurrentLemmas = 0;
98
3972124
  d_numCurrentFacts = 0;
99
3972124
}
100
101
2733383
bool TheoryInferenceManager::hasSent() const
102
{
103
5466766
  return d_theoryState.isInConflict() || d_numCurrentLemmas > 0
104
5455003
         || d_numCurrentFacts > 0;
105
}
106
107
eq::ProofEqEngine* TheoryInferenceManager::getProofEqEngine() { return d_pfee; }
108
109
15108
void TheoryInferenceManager::conflictEqConstantMerge(TNode a, TNode b)
110
{
111
15108
  if (!d_theoryState.isInConflict())
112
  {
113
29876
    TrustNode tconf = explainConflictEqConstantMerge(a, b);
114
14938
    trustedConflict(tconf, InferenceId::EQ_CONSTANT_MERGE);
115
  }
116
15108
}
117
118
96315
void TheoryInferenceManager::conflict(TNode conf, InferenceId id)
119
{
120
192630
  TrustNode tconf = TrustNode::mkTrustConflict(conf, nullptr);
121
192630
  return trustedConflict(tconf, id);
122
}
123
124
130499
void TheoryInferenceManager::trustedConflict(TrustNode tconf, InferenceId id)
125
{
126
130499
  d_conflictIdStats << id;
127
130499
  resourceManager()->spendResource(id);
128
260998
  Trace("im") << "(conflict " << id << " " << tconf.getProven() << ")"
129
130499
              << std::endl;
130
130499
  d_out.trustedConflict(tconf);
131
130499
  ++d_numConflicts;
132
130499
}
133
134
8
void TheoryInferenceManager::conflictExp(InferenceId id,
135
                                         PfRule pfr,
136
                                         const std::vector<Node>& exp,
137
                                         const std::vector<Node>& args)
138
{
139
8
  if (!d_theoryState.isInConflict())
140
  {
141
    // make the trust node
142
16
    TrustNode tconf = mkConflictExp(pfr, exp, args);
143
    // send it on the output channel
144
8
    trustedConflict(tconf, id);
145
  }
146
8
}
147
148
8
TrustNode TheoryInferenceManager::mkConflictExp(PfRule id,
149
                                                const std::vector<Node>& exp,
150
                                                const std::vector<Node>& args)
151
{
152
8
  if (d_pfee != nullptr)
153
  {
154
    // use proof equality engine to construct the trust node
155
2
    return d_pfee->assertConflict(id, exp, args);
156
  }
157
  // version without proofs
158
12
  Node conf = mkExplainPartial(exp, {});
159
6
  return TrustNode::mkTrustConflict(conf, nullptr);
160
}
161
162
4027
void TheoryInferenceManager::conflictExp(InferenceId id,
163
                                         const std::vector<Node>& exp,
164
                                         ProofGenerator* pg)
165
{
166
4027
  if (!d_theoryState.isInConflict())
167
  {
168
    // make the trust node
169
7632
    TrustNode tconf = mkConflictExp(exp, pg);
170
    // send it on the output channel
171
3816
    trustedConflict(tconf, id);
172
  }
173
4027
}
174
175
5768
TrustNode TheoryInferenceManager::mkConflictExp(const std::vector<Node>& exp,
176
                                                ProofGenerator* pg)
177
{
178
5768
  if (d_pfee != nullptr)
179
  {
180
477
    Assert(pg != nullptr);
181
    // use proof equality engine to construct the trust node
182
477
    return d_pfee->assertConflict(exp, pg);
183
  }
184
  // version without proofs
185
10582
  Node conf = mkExplainPartial(exp, {});
186
5291
  return TrustNode::mkTrustConflict(conf, nullptr);
187
}
188
189
13058268
bool TheoryInferenceManager::propagateLit(TNode lit)
190
{
191
  // If already in conflict, no more propagation
192
13058268
  if (d_theoryState.isInConflict())
193
  {
194
2305
    return false;
195
  }
196
  // Propagate out
197
13055963
  bool ok = d_out.propagate(lit);
198
13055963
  if (!ok)
199
  {
200
57530
    d_theoryState.notifyInConflict();
201
  }
202
13055963
  return ok;
203
}
204
205
218937
TrustNode TheoryInferenceManager::explainLit(TNode lit)
206
{
207
218937
  if (d_pfee != nullptr)
208
  {
209
32954
    return d_pfee->explain(lit);
210
  }
211
185983
  if (d_ee != nullptr)
212
  {
213
371966
    Node exp = d_ee->mkExplainLit(lit);
214
185983
    return TrustNode::mkTrustPropExp(lit, exp, nullptr);
215
  }
216
  Unimplemented() << "Inference manager for " << d_theory.getId()
217
                  << " was asked to explain a propagation but doesn't have an "
218
                     "equality engine or implement the "
219
                     "TheoryInferenceManager::explainLit interface!";
220
}
221
222
14938
TrustNode TheoryInferenceManager::explainConflictEqConstantMerge(TNode a,
223
                                                                 TNode b)
224
{
225
29876
  Node lit = a.eqNode(b);
226
14938
  if (d_pfee != nullptr)
227
  {
228
1204
    return d_pfee->assertConflict(lit);
229
  }
230
13734
  if (d_ee != nullptr)
231
  {
232
27468
    Node conf = d_ee->mkExplainLit(lit);
233
13734
    return TrustNode::mkTrustConflict(conf, nullptr);
234
  }
235
  Unimplemented() << "Inference manager for " << d_theory.getId()
236
                  << " mkTrustedConflictEqConstantMerge";
237
}
238
239
2094980
bool TheoryInferenceManager::lemma(TNode lem, InferenceId id, LemmaProperty p)
240
{
241
4189959
  TrustNode tlem = TrustNode::mkTrustLemma(lem, nullptr);
242
4189959
  return trustedLemma(tlem, id, p);
243
}
244
245
2496120
bool TheoryInferenceManager::trustedLemma(const TrustNode& tlem,
246
                                          InferenceId id,
247
                                          LemmaProperty p)
248
{
249
  // if the policy says to cache lemmas, check the cache and return false if
250
  // we are a duplicate
251
2496120
  if (d_cacheLemmas)
252
  {
253
2435208
    if (!cacheLemma(tlem.getNode(), p))
254
    {
255
2131726
      return false;
256
    }
257
  }
258
364394
  d_lemmaIdStats << id;
259
364394
  resourceManager()->spendResource(id);
260
364394
  Trace("im") << "(lemma " << id << " " << tlem.getProven() << ")" << std::endl;
261
  // shouldn't send trivially true or false lemmas
262
364394
  Assert(!Rewriter::rewrite(tlem.getProven()).isConst());
263
364394
  d_numCurrentLemmas++;
264
364396
  d_out.trustedLemma(tlem, p);
265
364392
  return true;
266
}
267
268
bool TheoryInferenceManager::lemmaExp(Node conc,
269
                                      InferenceId id,
270
                                      PfRule pfr,
271
                                      const std::vector<Node>& exp,
272
                                      const std::vector<Node>& noExplain,
273
                                      const std::vector<Node>& args,
274
                                      LemmaProperty p)
275
{
276
  // make the trust node
277
  TrustNode trn = mkLemmaExp(conc, pfr, exp, noExplain, args);
278
  // send it on the output channel
279
  return trustedLemma(trn, id, p);
280
}
281
282
386
TrustNode TheoryInferenceManager::mkLemmaExp(Node conc,
283
                                             PfRule id,
284
                                             const std::vector<Node>& exp,
285
                                             const std::vector<Node>& noExplain,
286
                                             const std::vector<Node>& args)
287
{
288
386
  if (d_pfee != nullptr)
289
  {
290
    // make the trust node from the proof equality engine
291
51
    return d_pfee->assertLemma(conc, id, exp, noExplain, args);
292
  }
293
  // otherwise, not using proofs, explain and make trust node
294
670
  Node ant = mkExplainPartial(exp, noExplain);
295
670
  Node lem = NodeManager::currentNM()->mkNode(kind::IMPLIES, ant, conc);
296
335
  return TrustNode::mkTrustLemma(lem, nullptr);
297
}
298
299
bool TheoryInferenceManager::lemmaExp(Node conc,
300
                                      InferenceId id,
301
                                      const std::vector<Node>& exp,
302
                                      const std::vector<Node>& noExplain,
303
                                      ProofGenerator* pg,
304
                                      LemmaProperty p)
305
{
306
  // make the trust node
307
  TrustNode trn = mkLemmaExp(conc, exp, noExplain, pg);
308
  // send it on the output channel
309
  return trustedLemma(trn, id, p);
310
}
311
312
25693
TrustNode TheoryInferenceManager::mkLemmaExp(Node conc,
313
                                             const std::vector<Node>& exp,
314
                                             const std::vector<Node>& noExplain,
315
                                             ProofGenerator* pg)
316
{
317
25693
  if (d_pfee != nullptr)
318
  {
319
    // make the trust node from the proof equality engine
320
5168
    return d_pfee->assertLemma(conc, exp, noExplain, pg);
321
  }
322
  // otherwise, not using proofs, explain and make trust node
323
41050
  Node ant = mkExplainPartial(exp, noExplain);
324
41050
  Node lem = NodeManager::currentNM()->mkNode(kind::IMPLIES, ant, conc);
325
20525
  return TrustNode::mkTrustLemma(lem, nullptr);
326
}
327
328
172764
bool TheoryInferenceManager::hasCachedLemma(TNode lem, LemmaProperty p)
329
{
330
345528
  Node rewritten = Rewriter::rewrite(lem);
331
345528
  return d_lemmasSent.find(rewritten) != d_lemmasSent.end();
332
}
333
334
uint32_t TheoryInferenceManager::numSentLemmas() const
335
{
336
  return d_numCurrentLemmas;
337
}
338
339
697544
bool TheoryInferenceManager::hasSentLemma() const
340
{
341
697544
  return d_numCurrentLemmas != 0;
342
}
343
344
14511
bool TheoryInferenceManager::assertInternalFact(TNode atom,
345
                                                bool pol,
346
                                                InferenceId id,
347
                                                TNode exp)
348
{
349
43533
  return processInternalFact(
350
43533
      atom, pol, id, PfRule::UNKNOWN, {exp}, {}, nullptr);
351
}
352
353
30662
bool TheoryInferenceManager::assertInternalFact(TNode atom,
354
                                                bool pol,
355
                                                InferenceId id,
356
                                                PfRule pfr,
357
                                                const std::vector<Node>& exp,
358
                                                const std::vector<Node>& args)
359
{
360
30662
  Assert(pfr != PfRule::UNKNOWN);
361
30662
  return processInternalFact(atom, pol, id, pfr, exp, args, nullptr);
362
}
363
364
548102
bool TheoryInferenceManager::assertInternalFact(TNode atom,
365
                                                bool pol,
366
                                                InferenceId id,
367
                                                const std::vector<Node>& exp,
368
                                                ProofGenerator* pg)
369
{
370
548102
  return processInternalFact(atom, pol, id, PfRule::ASSUME, exp, {}, pg);
371
}
372
373
593275
bool TheoryInferenceManager::processInternalFact(TNode atom,
374
                                                 bool pol,
375
                                                 InferenceId iid,
376
                                                 PfRule id,
377
                                                 const std::vector<Node>& exp,
378
                                                 const std::vector<Node>& args,
379
                                                 ProofGenerator* pg)
380
{
381
593275
  d_factIdStats << iid;
382
593275
  resourceManager()->spendResource(iid);
383
  // make the node corresponding to the explanation
384
1186550
  Node expn = NodeManager::currentNM()->mkAnd(exp);
385
1186550
  Trace("im") << "(fact " << iid << " " << (pol ? Node(atom) : atom.notNode())
386
593275
              << " " << expn << ")" << std::endl;
387
  // call the pre-notify fact method with preReg = false, isInternal = true
388
593275
  if (d_theory.preNotifyFact(atom, pol, expn, false, true))
389
  {
390
    // Handled in a theory-specific way that doesn't require equality engine,
391
    // notice we return true, indicating that the fact was processed.
392
    return true;
393
  }
394
593275
  Assert(d_ee != nullptr);
395
1186550
  Trace("infer-manager") << "TheoryInferenceManager::assertInternalFact: "
396
1186550
                         << (pol ? Node(atom) : atom.notNode()) << " from "
397
593275
                         << expn << " / " << iid << " " << id << std::endl;
398
593275
  if (Configuration::isAssertionBuild())
399
  {
400
    // check that all facts hold in the equality engine, to ensure that we
401
    // aren't processing a stale fact
402
1186550
    std::vector<Node> expc = exp;
403
1615203
    for (size_t i = 0; i < expc.size(); i++)
404
    {
405
1972901
      Node e = expc[i];
406
1021928
      bool epol = e.getKind() != NOT;
407
1972901
      Node eatom = epol ? e : e[0];
408
2043856
      Trace("infer-manager")
409
1021928
          << "...check " << eatom << " " << epol << std::endl;
410
1021928
      if (eatom.getKind() == AND)
411
      {
412
70955
        Assert(epol);
413
494366
        for (const Node& ea : eatom)
414
        {
415
423411
          expc.push_back(ea);
416
        }
417
70955
        continue;
418
      }
419
950973
      else if (eatom.getKind() == EQUAL)
420
      {
421
356747
        Assert(d_ee->hasTerm(eatom[0]));
422
356747
        Assert(d_ee->hasTerm(eatom[1]));
423
356747
        Assert(!epol || d_ee->areEqual(eatom[0], eatom[1]));
424
356747
        Assert(epol || d_ee->areDisequal(eatom[0], eatom[1], false));
425
      }
426
      else
427
      {
428
594226
        Assert(d_ee->hasTerm(eatom));
429
594226
        Assert(d_ee->areEqual(eatom, NodeManager::currentNM()->mkConst(epol)));
430
      }
431
    }
432
  }
433
593275
  d_numCurrentFacts++;
434
  // Now, assert the fact. How to do so depends on whether proofs are enabled.
435
593275
  bool ret = false;
436
593275
  if (d_pfee == nullptr)
437
  {
438
571786
    Trace("infer-manager") << "...assert without proofs..." << std::endl;
439
571786
    if (atom.getKind() == kind::EQUAL)
440
    {
441
480070
      ret = d_ee->assertEquality(atom, pol, expn);
442
    }
443
    else
444
    {
445
91716
      ret = d_ee->assertPredicate(atom, pol, expn);
446
    }
447
    // Must reference count the equality and its explanation, which is not done
448
    // by the equality engine. Notice that we do *not* need to do this for
449
    // external assertions, which enter as facts in theory check. This is also
450
    // not done if we are asserting to the proof equality engine, which does
451
    // this caching itself within ProofEqEngine::assertFact.
452
571786
    d_keep.insert(atom);
453
571786
    d_keep.insert(expn);
454
  }
455
  else
456
  {
457
21489
    Assert(id != PfRule::UNKNOWN);
458
21489
    Trace("infer-manager") << "...assert with proofs..." << std::endl;
459
    // Note that we reconstruct the original literal lit here, since both the
460
    // original literal is needed for bookkeeping proofs. It is possible to
461
    // optimize this so that a few less nodes are created, but at the cost
462
    // of a more verbose interface to proof equality engine.
463
42978
    Node lit = pol ? Node(atom) : atom.notNode();
464
21489
    if (pg != nullptr)
465
    {
466
      // use the proof generator interface
467
19899
      ret = d_pfee->assertFact(lit, expn, pg);
468
    }
469
    else
470
    {
471
      // use the explict proof step interface
472
1590
      ret = d_pfee->assertFact(lit, id, expn, args);
473
    }
474
  }
475
  // call the notify fact method with isInternal = true
476
593275
  d_theory.notifyFact(atom, pol, expn, true);
477
1186550
  Trace("infer-manager")
478
593275
      << "TheoryInferenceManager::finished assertInternalFact, ret=" << ret
479
593275
      << std::endl;
480
593275
  return ret;
481
}
482
483
48669
void TheoryInferenceManager::explain(TNode n, std::vector<TNode>& assumptions)
484
{
485
48669
  if (n.getKind() == kind::AND)
486
  {
487
    for (const Node& nc : n)
488
    {
489
      d_ee->explainLit(nc, assumptions);
490
    }
491
  }
492
  else
493
  {
494
48669
    d_ee->explainLit(n, assumptions);
495
  }
496
48669
}
497
498
Node TheoryInferenceManager::mkExplain(TNode n)
499
{
500
  std::vector<TNode> assumptions;
501
  explain(n, assumptions);
502
  return NodeManager::currentNM()->mkAnd(assumptions);
503
}
504
505
26157
Node TheoryInferenceManager::mkExplainPartial(
506
    const std::vector<Node>& exp, const std::vector<Node>& noExplain)
507
{
508
52314
  std::vector<TNode> assumps;
509
79727
  for (const Node& e : exp)
510
  {
511
58471
    if (std::find(noExplain.begin(), noExplain.end(), e) != noExplain.end())
512
    {
513
4901
      if (std::find(assumps.begin(), assumps.end(), e) == assumps.end())
514
      {
515
        // a non-explained literal
516
4901
        assumps.push_back(e);
517
      }
518
4901
      continue;
519
    }
520
    // otherwise, explain it
521
48669
    explain(e, assumps);
522
  }
523
52314
  return NodeManager::currentNM()->mkAnd(assumps);
524
}
525
526
uint32_t TheoryInferenceManager::numSentFacts() const
527
{
528
  return d_numCurrentFacts;
529
}
530
531
92983
bool TheoryInferenceManager::hasSentFact() const
532
{
533
92983
  return d_numCurrentFacts != 0;
534
}
535
536
2435208
bool TheoryInferenceManager::cacheLemma(TNode lem, LemmaProperty p)
537
{
538
4870416
  Node rewritten = Rewriter::rewrite(lem);
539
2435208
  if (d_lemmasSent.find(rewritten) != d_lemmasSent.end())
540
  {
541
2131726
    return false;
542
  }
543
303482
  d_lemmasSent.insert(rewritten);
544
303482
  return true;
545
}
546
547
20154
DecisionManager* TheoryInferenceManager::getDecisionManager()
548
{
549
20154
  return d_decManager;
550
}
551
552
36108
void TheoryInferenceManager::requirePhase(TNode n, bool pol)
553
{
554
36108
  return d_out.requirePhase(n, pol);
555
}
556
557
void TheoryInferenceManager::spendResource(Resource r)
558
{
559
  d_out.spendResource(r);
560
}
561
562
181865
void TheoryInferenceManager::safePoint(Resource r)
563
{
564
181865
  d_out.safePoint(r);
565
181865
}
566
567
4986
void TheoryInferenceManager::setIncomplete(IncompleteId id)
568
{
569
4986
  d_out.setIncomplete(id);
570
4986
}
571
572
1069450
void TheoryInferenceManager::notifyInConflict()
573
{
574
1069450
  d_theoryState.notifyInConflict();
575
1069450
}
576
577
}  // namespace theory
578
31125
}  // namespace cvc5