GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/prop/prop_engine.cpp Lines: 259 339 76.4 %
Date: 2021-11-07 Branches: 378 1156 32.7 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Haniel Barbosa, 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
 * Implementation of the propositional engine of cvc5.
14
 */
15
16
#include "prop/prop_engine.h"
17
18
#include <iomanip>
19
#include <map>
20
#include <utility>
21
22
#include "base/check.h"
23
#include "base/output.h"
24
#include "decision/decision_engine_old.h"
25
#include "decision/justification_strategy.h"
26
#include "options/base_options.h"
27
#include "options/decision_options.h"
28
#include "options/main_options.h"
29
#include "options/options.h"
30
#include "options/proof_options.h"
31
#include "options/smt_options.h"
32
#include "prop/cnf_stream.h"
33
#include "prop/minisat/minisat.h"
34
#include "prop/prop_proof_manager.h"
35
#include "prop/sat_solver.h"
36
#include "prop/sat_solver_factory.h"
37
#include "prop/theory_proxy.h"
38
#include "smt/env.h"
39
#include "smt/smt_statistics_registry.h"
40
#include "theory/output_channel.h"
41
#include "theory/theory_engine.h"
42
#include "util/resource_manager.h"
43
#include "util/result.h"
44
45
namespace cvc5 {
46
namespace prop {
47
48
/** Keeps a boolean flag scoped */
49
class ScopedBool {
50
51
private:
52
53
  bool d_original;
54
  bool& d_reference;
55
56
public:
57
58
20560
  ScopedBool(bool& reference) :
59
20560
    d_reference(reference) {
60
20560
    d_original = reference;
61
20560
  }
62
63
41120
  ~ScopedBool() {
64
20560
    d_reference = d_original;
65
20560
  }
66
};
67
68
15340
PropEngine::PropEngine(TheoryEngine* te, Env& env)
69
    : d_inCheckSat(false),
70
      d_theoryEngine(te),
71
      d_env(env),
72
15340
      d_skdm(new SkolemDefManager(d_env.getContext(), d_env.getUserContext())),
73
      d_theoryProxy(nullptr),
74
      d_satSolver(nullptr),
75
      d_cnfStream(nullptr),
76
      d_pfCnfStream(nullptr),
77
      d_ppm(nullptr),
78
      d_interrupted(false),
79
30680
      d_assumptions(d_env.getUserContext())
80
{
81
15340
  Debug("prop") << "Constructing the PropEngine" << std::endl;
82
15340
  context::UserContext* userContext = d_env.getUserContext();
83
15340
  ProofNodeManager* pnm = d_env.getProofNodeManager();
84
15340
  ResourceManager* rm = d_env.getResourceManager();
85
86
15340
  options::DecisionMode dmode = options::decisionMode();
87
15340
  if (dmode == options::DecisionMode::JUSTIFICATION
88
3011
      || dmode == options::DecisionMode::STOPONLY)
89
  {
90
12754
    d_decisionEngine.reset(new decision::JustificationStrategy(env));
91
  }
92
2586
  else if (dmode == options::DecisionMode::JUSTIFICATION_OLD
93
2583
           || dmode == options::DecisionMode::STOPONLY_OLD)
94
  {
95
3
    d_decisionEngine.reset(new DecisionEngineOld(env));
96
  }
97
  else
98
  {
99
2583
    d_decisionEngine.reset(new decision::DecisionEngineEmpty(env));
100
  }
101
102
15340
  d_satSolver =
103
15340
      SatSolverFactory::createCDCLTMinisat(d_env, smtStatisticsRegistry());
104
105
  // CNF stream and theory proxy required pointers to each other, make the
106
  // theory proxy first
107
15340
  d_theoryProxy = new TheoryProxy(
108
15340
      this, d_theoryEngine, d_decisionEngine.get(), d_skdm.get(), d_env);
109
46020
  d_cnfStream = new CnfStream(d_satSolver,
110
15340
                              d_theoryProxy,
111
                              userContext,
112
15340
                              &d_env,
113
                              rm,
114
                              FormulaLitPolicy::TRACK,
115
30680
                              "prop");
116
117
  // connect theory proxy
118
15340
  d_theoryProxy->finishInit(d_cnfStream);
119
15340
  bool satProofs = d_env.isSatProofProducing();
120
  // connect SAT solver
121
46020
  d_satSolver->initialize(d_env.getContext(),
122
                          d_theoryProxy,
123
15340
                          d_env.getUserContext(),
124
15340
                          satProofs ? pnm : nullptr);
125
126
15340
  d_decisionEngine->finishInit(d_satSolver, d_cnfStream);
127
15340
  if (satProofs)
128
  {
129
10762
    d_pfCnfStream.reset(new ProofCnfStream(
130
        userContext,
131
5381
        *d_cnfStream,
132
5381
        static_cast<MinisatSatSolver*>(d_satSolver)->getProofManager(),
133
10762
        pnm));
134
10762
    d_ppm.reset(
135
5381
        new PropPfManager(userContext, pnm, d_satSolver, d_pfCnfStream.get()));
136
  }
137
15340
}
138
139
15340
void PropEngine::finishInit()
140
{
141
15340
  NodeManager* nm = NodeManager::currentNM();
142
15340
  d_cnfStream->convertAndAssert(nm->mkConst(true), false, false);
143
  // this is necessary because if True is later asserted to the prop engine the
144
  // CNF stream will ignore it since the SAT solver already had it registered,
145
  // thus not having True as an assumption for the SAT proof. To solve this
146
  // issue we track it directly here
147
15340
  if (isProofEnabled())
148
  {
149
5381
    static_cast<MinisatSatSolver*>(d_satSolver)
150
        ->getProofManager()
151
5381
        ->registerSatAssumptions({nm->mkConst(true)});
152
  }
153
15340
  d_cnfStream->convertAndAssert(nm->mkConst(false).notNode(), false, false);
154
15340
}
155
156
30670
PropEngine::~PropEngine() {
157
15335
  Debug("prop") << "Destructing the PropEngine" << std::endl;
158
15335
  d_decisionEngine.reset(nullptr);
159
15335
  delete d_cnfStream;
160
15335
  delete d_satSolver;
161
15335
  delete d_theoryProxy;
162
15335
}
163
164
117629
TrustNode PropEngine::preprocess(TNode node,
165
                                 std::vector<theory::SkolemLemma>& newLemmas)
166
{
167
117629
  return d_theoryProxy->preprocess(node, newLemmas);
168
}
169
170
2
TrustNode PropEngine::removeItes(TNode node,
171
                                 std::vector<theory::SkolemLemma>& newLemmas)
172
{
173
2
  return d_theoryProxy->removeItes(node, newLemmas);
174
}
175
176
19095
void PropEngine::assertInputFormulas(
177
    const std::vector<Node>& assertions,
178
    std::unordered_map<size_t, Node>& skolemMap)
179
{
180
19095
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
181
  // notify the theory engine of preprocessed assertions
182
19095
  d_theoryEngine->notifyPreprocessedAssertions(assertions);
183
  // Now, notify the theory proxy of the assertions and skolem definitions.
184
  // Notice we do this before asserting the formulas to the CNF stream below,
185
  // since (preregistration) lemmas may occur during calls to assertInternal.
186
  // These lemmas we want to be notified about after the theory proxy has
187
  // been notified about all input assertions.
188
19095
  std::unordered_map<size_t, Node>::iterator it;
189
154926
  for (size_t i = 0, asize = assertions.size(); i < asize; i++)
190
  {
191
    // is the assertion a skolem definition?
192
135831
    it = skolemMap.find(i);
193
271662
    Node skolem;
194
135831
    if (it != skolemMap.end())
195
    {
196
18544
      skolem = it->second;
197
    }
198
135831
    d_theoryProxy->notifyAssertion(assertions[i], skolem, false);
199
  }
200
154916
  for (const Node& node : assertions)
201
  {
202
135825
    Debug("prop") << "assertFormula(" << node << ")" << std::endl;
203
135829
    assertInternal(node, false, false, true);
204
  }
205
19091
}
206
207
518401
void PropEngine::assertLemma(TrustNode tlemma, theory::LemmaProperty p)
208
{
209
518401
  bool removable = isLemmaPropertyRemovable(p);
210
211
  // call preprocessor
212
1036802
  std::vector<theory::SkolemLemma> ppLemmas;
213
1036802
  TrustNode tplemma = d_theoryProxy->preprocessLemma(tlemma, ppLemmas);
214
215
  // do final checks on the lemmas we are about to send
216
1036798
  if (isProofEnabled()
217
518399
      && options::proofCheck() == options::ProofCheckMode::EAGER)
218
  {
219
106
    Assert(tplemma.getGenerator() != nullptr);
220
    // ensure closed, make the proof node eagerly here to debug
221
106
    tplemma.debugCheckClosed("te-proof-debug", "TheoryEngine::lemma");
222
106
    for (theory::SkolemLemma& lem : ppLemmas)
223
    {
224
      Assert(lem.d_lemma.getGenerator() != nullptr);
225
      lem.d_lemma.debugCheckClosed("te-proof-debug", "TheoryEngine::lemma_new");
226
    }
227
  }
228
229
518399
  if (Trace.isOn("te-lemma"))
230
  {
231
    Trace("te-lemma") << "Lemma, output: " << tplemma.getProven() << std::endl;
232
    for (const theory::SkolemLemma& lem : ppLemmas)
233
    {
234
      Trace("te-lemma") << "Lemma, new lemma: " << lem.d_lemma.getProven()
235
                        << " (skolem is " << lem.d_skolem << ")" << std::endl;
236
    }
237
  }
238
239
  // now, assert the lemmas
240
518399
  assertLemmasInternal(tplemma, ppLemmas, removable);
241
518399
}
242
243
529611
void PropEngine::assertTrustedLemmaInternal(TrustNode trn, bool removable)
244
{
245
1059222
  Node node = trn.getNode();
246
529611
  Debug("prop::lemmas") << "assertLemma(" << node << ")" << std::endl;
247
529611
  bool negated = trn.getKind() == TrustNodeKind::CONFLICT;
248
529611
  Assert(
249
      !isProofEnabled() || trn.getGenerator() != nullptr
250
      || options::unsatCores()
251
      || (options::unsatCores()
252
          && options::unsatCoresMode() != options::UnsatCoresMode::FULL_PROOF));
253
529611
  assertInternal(trn.getNode(), negated, removable, false, trn.getGenerator());
254
529611
}
255
256
665436
void PropEngine::assertInternal(
257
    TNode node, bool negated, bool removable, bool input, ProofGenerator* pg)
258
{
259
  // Assert as (possibly) removable
260
665436
  if (options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS)
261
  {
262
177403
    if (input)
263
    {
264
35489
      d_cnfStream->ensureLiteral(node);
265
35489
      if (negated)
266
      {
267
        d_assumptions.push_back(node.notNode());
268
      }
269
      else
270
      {
271
35489
        d_assumptions.push_back(node);
272
      }
273
    }
274
    else
275
    {
276
141914
      d_cnfStream->convertAndAssert(node, removable, negated, input);
277
    }
278
  }
279
488033
  else if (isProofEnabled())
280
  {
281
99111
    d_pfCnfStream->convertAndAssert(node, negated, removable, pg);
282
    // if input, register the assertion in the proof manager
283
99111
    if (input)
284
    {
285
26778
      d_ppm->registerAssertion(node);
286
    }
287
  }
288
  else
289
  {
290
388926
    d_cnfStream->convertAndAssert(node, removable, negated, input);
291
  }
292
665432
}
293
294
749590
void PropEngine::assertLemmasInternal(
295
    TrustNode trn,
296
    const std::vector<theory::SkolemLemma>& ppLemmas,
297
    bool removable)
298
{
299
749590
  if (!trn.isNull())
300
  {
301
518399
    assertTrustedLemmaInternal(trn, removable);
302
  }
303
760802
  for (const theory::SkolemLemma& lem : ppLemmas)
304
  {
305
11212
    assertTrustedLemmaInternal(lem.d_lemma, removable);
306
  }
307
  // assert to decision engine
308
749590
  if (!removable)
309
  {
310
    // also add to the decision engine, where notice we don't need proofs
311
596313
    if (!trn.isNull())
312
    {
313
      // notify the theory proxy of the lemma
314
365122
      d_theoryProxy->notifyAssertion(trn.getProven(), TNode::null(), true);
315
    }
316
607525
    for (const theory::SkolemLemma& lem : ppLemmas)
317
    {
318
11212
      d_theoryProxy->notifyAssertion(lem.getProven(), lem.d_skolem, true);
319
    }
320
  }
321
749590
}
322
323
81161
void PropEngine::requirePhase(TNode n, bool phase) {
324
81161
  Debug("prop") << "requirePhase(" << n << ", " << phase << ")" << std::endl;
325
326
81161
  Assert(n.getType().isBoolean());
327
81161
  SatLiteral lit = d_cnfStream->getLiteral(n);
328
81161
  d_satSolver->requirePhase(phase ? lit : ~lit);
329
81161
}
330
331
171751
bool PropEngine::isDecision(Node lit) const {
332
171751
  Assert(isSatLiteral(lit));
333
171751
  return d_satSolver->isDecision(d_cnfStream->getLiteral(lit).getSatVariable());
334
}
335
336
8
int32_t PropEngine::getDecisionLevel(Node lit) const
337
{
338
8
  Assert(isSatLiteral(lit));
339
16
  return d_satSolver->getDecisionLevel(
340
16
      d_cnfStream->getLiteral(lit).getSatVariable());
341
}
342
343
8
int32_t PropEngine::getIntroLevel(Node lit) const
344
{
345
8
  Assert(isSatLiteral(lit));
346
16
  return d_satSolver->getIntroLevel(
347
16
      d_cnfStream->getLiteral(lit).getSatVariable());
348
}
349
350
void PropEngine::printSatisfyingAssignment(){
351
  const CnfStream::NodeToLiteralMap& transCache =
352
    d_cnfStream->getTranslationCache();
353
  Debug("prop-value") << "Literal | Value | Expr" << std::endl
354
                      << "----------------------------------------"
355
                      << "-----------------" << std::endl;
356
  for(CnfStream::NodeToLiteralMap::const_iterator i = transCache.begin(),
357
      end = transCache.end();
358
      i != end;
359
      ++i) {
360
    std::pair<Node, SatLiteral> curr = *i;
361
    SatLiteral l = curr.second;
362
    if(!l.isNegated()) {
363
      Node n = curr.first;
364
      SatValue value = d_satSolver->modelValue(l);
365
      Debug("prop-value") << "'" << l << "' " << value << " " << n << std::endl;
366
    }
367
  }
368
}
369
370
20560
Result PropEngine::checkSat() {
371
20560
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
372
20560
  Debug("prop") << "PropEngine::checkSat()" << std::endl;
373
374
  // Mark that we are in the checkSat
375
41120
  ScopedBool scopedBool(d_inCheckSat);
376
20560
  d_inCheckSat = true;
377
378
  // Note this currently ignores conflicts (a dangerous practice).
379
20560
  d_theoryProxy->presolve();
380
381
20560
  if(options::preprocessOnly()) {
382
3
    return Result(Result::SAT_UNKNOWN, Result::REQUIRES_FULL_CHECK);
383
  }
384
385
  // Reset the interrupted flag
386
20557
  d_interrupted = false;
387
388
  // Check the problem
389
  SatValue result;
390
20557
  if (d_assumptions.size() == 0)
391
  {
392
16842
    result = d_satSolver->solve();
393
  }
394
  else
395
  {
396
7430
    std::vector<SatLiteral> assumptions;
397
53960
    for (const Node& node : d_assumptions)
398
    {
399
50245
      assumptions.push_back(d_cnfStream->getLiteral(node));
400
    }
401
3715
    result = d_satSolver->solve(assumptions);
402
  }
403
404
20534
  if( result == SAT_VALUE_UNKNOWN ) {
405
    ResourceManager* rm = d_env.getResourceManager();
406
    Result::UnknownExplanation why = Result::INTERRUPTED;
407
    if (rm->outOfTime())
408
    {
409
      why = Result::TIMEOUT;
410
    }
411
    if (rm->outOfResources())
412
    {
413
      why = Result::RESOURCEOUT;
414
    }
415
    return Result(Result::SAT_UNKNOWN, why);
416
  }
417
418
20534
  if( result == SAT_VALUE_TRUE && Debug.isOn("prop") ) {
419
    printSatisfyingAssignment();
420
  }
421
422
20534
  Debug("prop") << "PropEngine::checkSat() => " << result << std::endl;
423
20534
  if(result == SAT_VALUE_TRUE && d_theoryEngine->isIncomplete()) {
424
147
    return Result(Result::SAT_UNKNOWN, Result::INCOMPLETE);
425
  }
426
20387
  return Result(result == SAT_VALUE_TRUE ? Result::SAT : Result::UNSAT);
427
}
428
429
50905
Node PropEngine::getValue(TNode node) const
430
{
431
50905
  Assert(node.getType().isBoolean());
432
50905
  Assert(d_cnfStream->hasLiteral(node));
433
434
50905
  SatLiteral lit = d_cnfStream->getLiteral(node);
435
436
50905
  SatValue v = d_satSolver->value(lit);
437
50905
  if (v == SAT_VALUE_TRUE)
438
  {
439
50872
    return NodeManager::currentNM()->mkConst(true);
440
  }
441
33
  else if (v == SAT_VALUE_FALSE)
442
  {
443
33
    return NodeManager::currentNM()->mkConst(false);
444
  }
445
  else
446
  {
447
    Assert(v == SAT_VALUE_UNKNOWN);
448
    return Node::null();
449
  }
450
}
451
452
36088791
bool PropEngine::isSatLiteral(TNode node) const
453
{
454
36088791
  return d_cnfStream->hasLiteral(node);
455
}
456
457
13020856
bool PropEngine::hasValue(TNode node, bool& value) const
458
{
459
13020856
  Assert(node.getType().isBoolean());
460
13020856
  Assert(d_cnfStream->hasLiteral(node)) << node;
461
462
13020856
  SatLiteral lit = d_cnfStream->getLiteral(node);
463
464
13020856
  SatValue v = d_satSolver->value(lit);
465
13020856
  if (v == SAT_VALUE_TRUE)
466
  {
467
7876188
    value = true;
468
7876188
    return true;
469
  }
470
5144668
  else if (v == SAT_VALUE_FALSE)
471
  {
472
168326
    value = false;
473
168326
    return true;
474
  }
475
  else
476
  {
477
4976342
    Assert(v == SAT_VALUE_UNKNOWN);
478
4976342
    return false;
479
  }
480
}
481
482
24989
void PropEngine::getBooleanVariables(std::vector<TNode>& outputVariables) const
483
{
484
24989
  d_cnfStream->getBooleanVariables(outputVariables);
485
24989
}
486
487
225995
Node PropEngine::ensureLiteral(TNode n)
488
{
489
  // must preprocess
490
225995
  Node preprocessed = getPreprocessedTerm(n);
491
451990
  Trace("ensureLiteral") << "ensureLiteral preprocessed: " << preprocessed
492
225995
                         << std::endl;
493
225995
  if (isProofEnabled())
494
  {
495
26683
    d_pfCnfStream->ensureLiteral(preprocessed);
496
  }
497
  else
498
  {
499
199312
    d_cnfStream->ensureLiteral(preprocessed);
500
  }
501
225995
  return preprocessed;
502
}
503
504
231191
Node PropEngine::getPreprocessedTerm(TNode n)
505
{
506
  // must preprocess
507
462382
  std::vector<theory::SkolemLemma> newLemmas;
508
462382
  TrustNode tpn = d_theoryProxy->preprocess(n, newLemmas);
509
  // send lemmas corresponding to the skolems introduced by preprocessing n
510
462382
  TrustNode trnNull;
511
231191
  assertLemmasInternal(trnNull, newLemmas, false);
512
462382
  return tpn.isNull() ? Node(n) : tpn.getNode();
513
}
514
515
2499
Node PropEngine::getPreprocessedTerm(TNode n,
516
                                     std::vector<Node>& skAsserts,
517
                                     std::vector<Node>& sks)
518
{
519
  // get the preprocessed form of the term
520
2499
  Node pn = getPreprocessedTerm(n);
521
  // initialize the set of skolems and assertions to process
522
4998
  std::vector<Node> toProcessAsserts;
523
4998
  std::vector<Node> toProcess;
524
2499
  d_theoryProxy->getSkolems(pn, toProcessAsserts, toProcess);
525
2499
  size_t index = 0;
526
  // until fixed point is reached
527
7545
  while (index < toProcess.size())
528
  {
529
3701
    Node ka = toProcessAsserts[index];
530
3701
    Node k = toProcess[index];
531
2523
    index++;
532
2523
    if (std::find(sks.begin(), sks.end(), k) != sks.end())
533
    {
534
      // already added the skolem to the list
535
1345
      continue;
536
    }
537
    // must preprocess lemmas as well
538
2356
    Node kap = getPreprocessedTerm(ka);
539
1178
    skAsserts.push_back(kap);
540
1178
    sks.push_back(k);
541
    // get the skolems in the preprocessed form of the lemma ka
542
1178
    d_theoryProxy->getSkolems(kap, toProcessAsserts, toProcess);
543
  }
544
  // return the preprocessed term
545
4998
  return pn;
546
}
547
548
4937
void PropEngine::push()
549
{
550
4937
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
551
4937
  d_satSolver->push();
552
4937
  Debug("prop") << "push()" << std::endl;
553
4937
}
554
555
4937
void PropEngine::pop()
556
{
557
4937
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
558
4937
  d_satSolver->pop();
559
4937
  Debug("prop") << "pop()" << std::endl;
560
4937
}
561
562
20537
void PropEngine::resetTrail()
563
{
564
20537
  d_satSolver->resetTrail();
565
20537
  Debug("prop") << "resetTrail()" << std::endl;
566
20537
}
567
568
24392
unsigned PropEngine::getAssertionLevel() const
569
{
570
24392
  return d_satSolver->getAssertionLevel();
571
}
572
573
bool PropEngine::isRunning() const { return d_inCheckSat; }
574
void PropEngine::interrupt()
575
{
576
  if (!d_inCheckSat)
577
  {
578
    return;
579
  }
580
581
  d_interrupted = true;
582
  d_satSolver->interrupt();
583
  Debug("prop") << "interrupt()" << std::endl;
584
}
585
586
2701
void PropEngine::spendResource(Resource r)
587
{
588
2701
  d_env.getResourceManager()->spendResource(r);
589
2701
}
590
591
bool PropEngine::properExplanation(TNode node, TNode expl) const
592
{
593
  if (!d_cnfStream->hasLiteral(node))
594
  {
595
    Trace("properExplanation")
596
        << "properExplanation(): Failing because node "
597
        << "being explained doesn't have a SAT literal ?!" << std::endl
598
        << "properExplanation(): The node is: " << node << std::endl;
599
    return false;
600
  }
601
602
  SatLiteral nodeLit = d_cnfStream->getLiteral(node);
603
604
  for (TNode::kinded_iterator i = expl.begin(kind::AND),
605
                              i_end = expl.end(kind::AND);
606
       i != i_end;
607
       ++i)
608
  {
609
    if (!d_cnfStream->hasLiteral(*i))
610
    {
611
      Trace("properExplanation")
612
          << "properExplanation(): Failing because one of explanation "
613
          << "nodes doesn't have a SAT literal" << std::endl
614
          << "properExplanation(): The explanation node is: " << *i
615
          << std::endl;
616
      return false;
617
    }
618
619
    SatLiteral iLit = d_cnfStream->getLiteral(*i);
620
621
    if (iLit == nodeLit)
622
    {
623
      Trace("properExplanation")
624
          << "properExplanation(): Failing because the node" << std::endl
625
          << "properExplanation(): " << node << std::endl
626
          << "properExplanation(): cannot be made to explain itself!"
627
          << std::endl;
628
      return false;
629
    }
630
631
    if (!d_satSolver->properExplanation(nodeLit, iLit))
632
    {
633
      Trace("properExplanation")
634
          << "properExplanation(): SAT solver told us that node" << std::endl
635
          << "properExplanation(): " << *i << std::endl
636
          << "properExplanation(): is not part of a proper explanation node for"
637
          << std::endl
638
          << "properExplanation(): " << node << std::endl
639
          << "properExplanation(): Perhaps it one of the two isn't assigned or "
640
             "the explanation"
641
          << std::endl
642
          << "properExplanation(): node wasn't propagated before the node "
643
             "being explained"
644
          << std::endl;
645
      return false;
646
    }
647
  }
648
649
  return true;
650
}
651
652
3
void PropEngine::checkProof(const context::CDList<Node>& assertions)
653
{
654
3
  if (!d_env.isSatProofProducing())
655
  {
656
    return;
657
  }
658
3
  return d_ppm->checkProof(assertions);
659
}
660
661
15234
ProofCnfStream* PropEngine::getProofCnfStream() { return d_pfCnfStream.get(); }
662
663
10061
std::shared_ptr<ProofNode> PropEngine::getProof()
664
{
665
10061
  if (!d_env.isSatProofProducing())
666
  {
667
    return nullptr;
668
  }
669
10061
  return d_ppm->getProof();
670
}
671
672
1777378
bool PropEngine::isProofEnabled() const { return d_pfCnfStream != nullptr; }
673
674
1410
void PropEngine::getUnsatCore(std::vector<Node>& core)
675
{
676
1410
  Assert(options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS);
677
2820
  std::vector<SatLiteral> unsat_assumptions;
678
1410
  d_satSolver->getUnsatAssumptions(unsat_assumptions);
679
8363
  for (const SatLiteral& lit : unsat_assumptions)
680
  {
681
6953
    core.push_back(d_cnfStream->getNode(lit));
682
  }
683
1410
}
684
685
1410
std::shared_ptr<ProofNode> PropEngine::getRefutation()
686
{
687
1410
  Assert(options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS);
688
2820
  std::vector<Node> core;
689
1410
  getUnsatCore(core);
690
2820
  CDProof cdp(d_env.getProofNodeManager());
691
2820
  Node fnode = NodeManager::currentNM()->mkConst(false);
692
1410
  cdp.addStep(fnode, PfRule::SAT_REFUTATION, core, {});
693
2820
  return cdp.getProofFor(fnode);
694
}
695
696
}  // namespace prop
697
31137
}  // namespace cvc5