GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_inference_manager.cpp Lines: 222 244 91.0 %
Date: 2021-09-10 Branches: 358 844 42.4 %

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