GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/prop/prop_engine.cpp Lines: 262 348 75.3 %
Date: 2021-08-16 Branches: 380 1196 31.8 %

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
15204
  ScopedBool(bool& reference) :
59
15204
    d_reference(reference) {
60
15204
    d_original = reference;
61
15204
  }
62
63
30408
  ~ScopedBool() {
64
15204
    d_reference = d_original;
65
15204
  }
66
};
67
68
9920
PropEngine::PropEngine(TheoryEngine* te,
69
                       Env& env,
70
9920
                       ProofNodeManager* pnm)
71
    : d_inCheckSat(false),
72
      d_theoryEngine(te),
73
      d_env(env),
74
9920
      d_skdm(new SkolemDefManager(d_env.getContext(), d_env.getUserContext())),
75
      d_theoryProxy(nullptr),
76
      d_satSolver(nullptr),
77
      d_pnm(pnm),
78
      d_cnfStream(nullptr),
79
      d_pfCnfStream(nullptr),
80
      d_ppm(nullptr),
81
      d_interrupted(false),
82
19840
      d_assumptions(d_env.getUserContext())
83
{
84
9920
  Debug("prop") << "Constructing the PropEngine" << std::endl;
85
9920
  context::Context* satContext = d_env.getContext();
86
9920
  context::UserContext* userContext = d_env.getUserContext();
87
9920
  ResourceManager* rm = d_env.getResourceManager();
88
89
9920
  options::DecisionMode dmode = options::decisionMode();
90
9920
  if (dmode == options::DecisionMode::JUSTIFICATION
91
2597
      || dmode == options::DecisionMode::STOPONLY)
92
  {
93
15478
    d_decisionEngine.reset(new decision::JustificationStrategy(
94
7739
        satContext, userContext, d_skdm.get(), rm));
95
  }
96
2181
  else if (dmode == options::DecisionMode::JUSTIFICATION_OLD
97
2179
           || dmode == options::DecisionMode::STOPONLY_OLD)
98
  {
99
2
    d_decisionEngine.reset(new DecisionEngineOld(satContext, userContext, rm));
100
  }
101
  else
102
  {
103
2179
    d_decisionEngine.reset(new decision::DecisionEngineEmpty(satContext, rm));
104
  }
105
106
9920
  d_satSolver = SatSolverFactory::createCDCLTMinisat(smtStatisticsRegistry());
107
108
  // CNF stream and theory proxy required pointers to each other, make the
109
  // theory proxy first
110
9920
  d_theoryProxy = new TheoryProxy(this,
111
                                  d_theoryEngine,
112
9920
                                  d_decisionEngine.get(),
113
9920
                                  d_skdm.get(),
114
                                  satContext,
115
                                  userContext,
116
9920
                                  pnm);
117
29760
  d_cnfStream = new CnfStream(d_satSolver,
118
9920
                              d_theoryProxy,
119
                              userContext,
120
9920
                              &d_env,
121
                              rm,
122
                              FormulaLitPolicy::TRACK,
123
19840
                              "prop");
124
125
  // connect theory proxy
126
9920
  d_theoryProxy->finishInit(d_cnfStream);
127
  // connect SAT solver
128
39680
  d_satSolver->initialize(
129
9920
      d_env.getContext(),
130
      d_theoryProxy,
131
9920
      d_env.getUserContext(),
132
9920
      options::unsatCoresMode() != options::UnsatCoresMode::ASSUMPTIONS
133
          ? pnm
134
9920
          : nullptr);
135
136
9920
  d_decisionEngine->finishInit(d_satSolver, d_cnfStream);
137
9920
  if (pnm && options::unsatCoresMode() != options::UnsatCoresMode::ASSUMPTIONS)
138
  {
139
2508
    d_pfCnfStream.reset(new ProofCnfStream(
140
        userContext,
141
1254
        *d_cnfStream,
142
1254
        static_cast<MinisatSatSolver*>(d_satSolver)->getProofManager(),
143
2508
        pnm));
144
2508
    d_ppm.reset(
145
1254
        new PropPfManager(userContext, pnm, d_satSolver, d_pfCnfStream.get()));
146
  }
147
9920
}
148
149
9920
void PropEngine::finishInit()
150
{
151
9920
  NodeManager* nm = NodeManager::currentNM();
152
9920
  d_cnfStream->convertAndAssert(nm->mkConst(true), false, false);
153
  // this is necessary because if True is later asserted to the prop engine the
154
  // CNF stream will ignore it since the SAT solver already had it registered,
155
  // thus not having True as an assumption for the SAT proof. To solve this
156
  // issue we track it directly here
157
9920
  if (isProofEnabled())
158
  {
159
1254
    static_cast<MinisatSatSolver*>(d_satSolver)
160
        ->getProofManager()
161
1254
        ->registerSatAssumptions({nm->mkConst(true)});
162
  }
163
9920
  d_cnfStream->convertAndAssert(nm->mkConst(false).notNode(), false, false);
164
9920
}
165
166
19840
PropEngine::~PropEngine() {
167
9920
  Debug("prop") << "Destructing the PropEngine" << std::endl;
168
9920
  d_decisionEngine.reset(nullptr);
169
9920
  delete d_cnfStream;
170
9920
  delete d_satSolver;
171
9920
  delete d_theoryProxy;
172
9920
}
173
174
105880
TrustNode PropEngine::preprocess(TNode node,
175
                                 std::vector<TrustNode>& newLemmas,
176
                                 std::vector<Node>& newSkolems)
177
{
178
105880
  return d_theoryProxy->preprocess(node, newLemmas, newSkolems);
179
}
180
181
4
TrustNode PropEngine::removeItes(TNode node,
182
                                 std::vector<TrustNode>& newLemmas,
183
                                 std::vector<Node>& newSkolems)
184
{
185
4
  return d_theoryProxy->removeItes(node, newLemmas, newSkolems);
186
}
187
188
13740
void PropEngine::assertInputFormulas(
189
    const std::vector<Node>& assertions,
190
    std::unordered_map<size_t, Node>& skolemMap)
191
{
192
13740
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
193
  // notify the theory engine of preprocessed assertions
194
13740
  d_theoryEngine->notifyPreprocessedAssertions(assertions);
195
  // Now, notify the theory proxy of the assertions and skolem definitions.
196
  // Notice we do this before asserting the formulas to the CNF stream below,
197
  // since (preregistration) lemmas may occur during calls to assertInternal.
198
  // These lemmas we want to be notified about after the theory proxy has
199
  // been notified about all input assertions.
200
13740
  std::unordered_map<size_t, Node>::iterator it;
201
138577
  for (size_t i = 0, asize = assertions.size(); i < asize; i++)
202
  {
203
    // is the assertion a skolem definition?
204
124837
    it = skolemMap.find(i);
205
249674
    Node skolem;
206
124837
    if (it != skolemMap.end())
207
    {
208
19619
      skolem = it->second;
209
    }
210
124837
    d_theoryProxy->notifyAssertion(assertions[i], skolem);
211
  }
212
138567
  for (const Node& node : assertions)
213
  {
214
124831
    Debug("prop") << "assertFormula(" << node << ")" << std::endl;
215
124835
    assertInternal(node, false, false, true);
216
  }
217
13736
}
218
219
430308
void PropEngine::assertLemma(TrustNode tlemma, theory::LemmaProperty p)
220
{
221
430308
  bool removable = isLemmaPropertyRemovable(p);
222
223
  // call preprocessor
224
860616
  std::vector<TrustNode> ppLemmas;
225
860616
  std::vector<Node> ppSkolems;
226
  TrustNode tplemma =
227
860616
      d_theoryProxy->preprocessLemma(tlemma, ppLemmas, ppSkolems);
228
229
430306
  Assert(ppSkolems.size() == ppLemmas.size());
230
231
  // do final checks on the lemmas we are about to send
232
430306
  if (isProofEnabled() && options::proofEagerChecking())
233
  {
234
    Assert(tplemma.getGenerator() != nullptr);
235
    // ensure closed, make the proof node eagerly here to debug
236
    tplemma.debugCheckClosed("te-proof-debug", "TheoryEngine::lemma");
237
    for (size_t i = 0, lsize = ppLemmas.size(); i < lsize; ++i)
238
    {
239
      Assert(ppLemmas[i].getGenerator() != nullptr);
240
      ppLemmas[i].debugCheckClosed("te-proof-debug", "TheoryEngine::lemma_new");
241
    }
242
  }
243
244
430306
  if (Trace.isOn("te-lemma"))
245
  {
246
    Trace("te-lemma") << "Lemma, output: " << tplemma.getProven() << std::endl;
247
    for (size_t i = 0, lsize = ppLemmas.size(); i < lsize; ++i)
248
    {
249
      Trace("te-lemma") << "Lemma, new lemma: " << ppLemmas[i].getProven()
250
                        << " (skolem is " << ppSkolems[i] << ")" << std::endl;
251
    }
252
  }
253
254
  // now, assert the lemmas
255
430306
  assertLemmasInternal(tplemma, ppLemmas, ppSkolems, removable);
256
430306
}
257
258
440377
void PropEngine::assertTrustedLemmaInternal(TrustNode trn, bool removable)
259
{
260
880754
  Node node = trn.getNode();
261
440377
  Debug("prop::lemmas") << "assertLemma(" << node << ")" << std::endl;
262
440377
  bool negated = trn.getKind() == TrustNodeKind::CONFLICT;
263
440377
  Assert(
264
      !isProofEnabled() || trn.getGenerator() != nullptr
265
      || options::unsatCores()
266
      || (options::unsatCores()
267
          && options::unsatCoresMode() != options::UnsatCoresMode::FULL_PROOF));
268
440377
  assertInternal(trn.getNode(), negated, removable, false, trn.getGenerator());
269
440377
}
270
271
565208
void PropEngine::assertInternal(
272
    TNode node, bool negated, bool removable, bool input, ProofGenerator* pg)
273
{
274
  // Assert as (possibly) removable
275
565208
  if (options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS)
276
  {
277
175142
    if (input)
278
    {
279
33488
      d_cnfStream->ensureLiteral(node);
280
33488
      if (negated)
281
      {
282
        d_assumptions.push_back(node.notNode());
283
      }
284
      else
285
      {
286
33488
        d_assumptions.push_back(node);
287
      }
288
    }
289
    else
290
    {
291
141654
      d_cnfStream->convertAndAssert(node, removable, negated, input);
292
    }
293
  }
294
390066
  else if (isProofEnabled())
295
  {
296
84292
    d_pfCnfStream->convertAndAssert(node, negated, removable, pg);
297
    // if input, register the assertion in the proof manager
298
84292
    if (input)
299
    {
300
19904
      d_ppm->registerAssertion(node);
301
    }
302
  }
303
  else
304
  {
305
305778
    d_cnfStream->convertAndAssert(node, removable, negated, input);
306
  }
307
565204
}
308
309
636774
void PropEngine::assertLemmasInternal(TrustNode trn,
310
                                      const std::vector<TrustNode>& ppLemmas,
311
                                      const std::vector<Node>& ppSkolems,
312
                                      bool removable)
313
{
314
636774
  if (!trn.isNull())
315
  {
316
430306
    assertTrustedLemmaInternal(trn, removable);
317
  }
318
646845
  for (const TrustNode& tnl : ppLemmas)
319
  {
320
10071
    assertTrustedLemmaInternal(tnl, removable);
321
  }
322
  // assert to decision engine
323
636774
  if (!removable)
324
  {
325
    // also add to the decision engine, where notice we don't need proofs
326
516054
    if (!trn.isNull())
327
    {
328
      // notify the theory proxy of the lemma
329
309586
      d_theoryProxy->notifyAssertion(trn.getProven());
330
    }
331
516054
    Assert(ppSkolems.size() == ppLemmas.size());
332
526125
    for (size_t i = 0, lsize = ppLemmas.size(); i < lsize; ++i)
333
    {
334
20142
      Node lem = ppLemmas[i].getProven();
335
10071
      d_theoryProxy->notifyAssertion(ppLemmas[i].getProven(), ppSkolems[i]);
336
    }
337
  }
338
636774
}
339
340
76595
void PropEngine::requirePhase(TNode n, bool phase) {
341
76595
  Debug("prop") << "requirePhase(" << n << ", " << phase << ")" << std::endl;
342
343
76595
  Assert(n.getType().isBoolean());
344
76595
  SatLiteral lit = d_cnfStream->getLiteral(n);
345
76595
  d_satSolver->requirePhase(phase ? lit : ~lit);
346
76595
}
347
348
176861
bool PropEngine::isDecision(Node lit) const {
349
176861
  Assert(isSatLiteral(lit));
350
176861
  return d_satSolver->isDecision(d_cnfStream->getLiteral(lit).getSatVariable());
351
}
352
353
16
int32_t PropEngine::getDecisionLevel(Node lit) const
354
{
355
16
  Assert(isSatLiteral(lit));
356
32
  return d_satSolver->getDecisionLevel(
357
32
      d_cnfStream->getLiteral(lit).getSatVariable());
358
}
359
360
8
int32_t PropEngine::getIntroLevel(Node lit) const
361
{
362
8
  Assert(isSatLiteral(lit));
363
16
  return d_satSolver->getIntroLevel(
364
16
      d_cnfStream->getLiteral(lit).getSatVariable());
365
}
366
367
void PropEngine::printSatisfyingAssignment(){
368
  const CnfStream::NodeToLiteralMap& transCache =
369
    d_cnfStream->getTranslationCache();
370
  Debug("prop-value") << "Literal | Value | Expr" << std::endl
371
                      << "----------------------------------------"
372
                      << "-----------------" << std::endl;
373
  for(CnfStream::NodeToLiteralMap::const_iterator i = transCache.begin(),
374
      end = transCache.end();
375
      i != end;
376
      ++i) {
377
    std::pair<Node, SatLiteral> curr = *i;
378
    SatLiteral l = curr.second;
379
    if(!l.isNegated()) {
380
      Node n = curr.first;
381
      SatValue value = d_satSolver->modelValue(l);
382
      Debug("prop-value") << "'" << l << "' " << value << " " << n << std::endl;
383
    }
384
  }
385
}
386
387
15204
Result PropEngine::checkSat() {
388
15204
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
389
15204
  Debug("prop") << "PropEngine::checkSat()" << std::endl;
390
391
  // Mark that we are in the checkSat
392
30408
  ScopedBool scopedBool(d_inCheckSat);
393
15204
  d_inCheckSat = true;
394
395
  // TODO This currently ignores conflicts (a dangerous practice).
396
15204
  d_decisionEngine->presolve();
397
15204
  d_theoryEngine->presolve();
398
399
15204
  if(options::preprocessOnly()) {
400
3
    return Result(Result::SAT_UNKNOWN, Result::REQUIRES_FULL_CHECK);
401
  }
402
403
  // Reset the interrupted flag
404
15201
  d_interrupted = false;
405
406
  // Check the problem
407
  SatValue result;
408
15201
  if (d_assumptions.size() == 0)
409
  {
410
11570
    result = d_satSolver->solve();
411
  }
412
  else
413
  {
414
7262
    std::vector<SatLiteral> assumptions;
415
51936
    for (const Node& node : d_assumptions)
416
    {
417
48305
      assumptions.push_back(d_cnfStream->getLiteral(node));
418
    }
419
3631
    result = d_satSolver->solve(assumptions);
420
  }
421
422
15185
  if( result == SAT_VALUE_UNKNOWN ) {
423
    ResourceManager* rm = d_env.getResourceManager();
424
    Result::UnknownExplanation why = Result::INTERRUPTED;
425
    if (rm->outOfTime())
426
    {
427
      why = Result::TIMEOUT;
428
    }
429
    if (rm->outOfResources())
430
    {
431
      why = Result::RESOURCEOUT;
432
    }
433
    return Result(Result::SAT_UNKNOWN, why);
434
  }
435
436
15185
  if( result == SAT_VALUE_TRUE && Debug.isOn("prop") ) {
437
    printSatisfyingAssignment();
438
  }
439
440
15185
  Debug("prop") << "PropEngine::checkSat() => " << result << std::endl;
441
15185
  if(result == SAT_VALUE_TRUE && d_theoryEngine->isIncomplete()) {
442
107
    return Result(Result::SAT_UNKNOWN, Result::INCOMPLETE);
443
  }
444
15078
  return Result(result == SAT_VALUE_TRUE ? Result::SAT : Result::UNSAT);
445
}
446
447
35078
Node PropEngine::getValue(TNode node) const
448
{
449
35078
  Assert(node.getType().isBoolean());
450
35078
  Assert(d_cnfStream->hasLiteral(node));
451
452
35078
  SatLiteral lit = d_cnfStream->getLiteral(node);
453
454
35078
  SatValue v = d_satSolver->value(lit);
455
35078
  if (v == SAT_VALUE_TRUE)
456
  {
457
35062
    return NodeManager::currentNM()->mkConst(true);
458
  }
459
16
  else if (v == SAT_VALUE_FALSE)
460
  {
461
16
    return NodeManager::currentNM()->mkConst(false);
462
  }
463
  else
464
  {
465
    Assert(v == SAT_VALUE_UNKNOWN);
466
    return Node::null();
467
  }
468
}
469
470
25641928
bool PropEngine::isSatLiteral(TNode node) const
471
{
472
25641928
  return d_cnfStream->hasLiteral(node);
473
}
474
475
9615756
bool PropEngine::hasValue(TNode node, bool& value) const
476
{
477
9615756
  Assert(node.getType().isBoolean());
478
9615756
  Assert(d_cnfStream->hasLiteral(node)) << node;
479
480
9615756
  SatLiteral lit = d_cnfStream->getLiteral(node);
481
482
9615756
  SatValue v = d_satSolver->value(lit);
483
9615756
  if (v == SAT_VALUE_TRUE)
484
  {
485
6094975
    value = true;
486
6094975
    return true;
487
  }
488
3520781
  else if (v == SAT_VALUE_FALSE)
489
  {
490
181103
    value = false;
491
181103
    return true;
492
  }
493
  else
494
  {
495
3339678
    Assert(v == SAT_VALUE_UNKNOWN);
496
3339678
    return false;
497
  }
498
}
499
500
16515
void PropEngine::getBooleanVariables(std::vector<TNode>& outputVariables) const
501
{
502
16515
  d_cnfStream->getBooleanVariables(outputVariables);
503
16515
}
504
505
202199
Node PropEngine::ensureLiteral(TNode n)
506
{
507
  // must preprocess
508
202199
  Node preprocessed = getPreprocessedTerm(n);
509
404398
  Trace("ensureLiteral") << "ensureLiteral preprocessed: " << preprocessed
510
202199
                         << std::endl;
511
202199
  if (isProofEnabled())
512
  {
513
23704
    d_pfCnfStream->ensureLiteral(preprocessed);
514
  }
515
  else
516
  {
517
178495
    d_cnfStream->ensureLiteral(preprocessed);
518
  }
519
202199
  return preprocessed;
520
}
521
522
206468
Node PropEngine::getPreprocessedTerm(TNode n)
523
{
524
  // must preprocess
525
412936
  std::vector<TrustNode> newLemmas;
526
412936
  std::vector<Node> newSkolems;
527
412936
  TrustNode tpn = d_theoryProxy->preprocess(n, newLemmas, newSkolems);
528
  // send lemmas corresponding to the skolems introduced by preprocessing n
529
412936
  TrustNode trnNull;
530
206468
  assertLemmasInternal(trnNull, newLemmas, newSkolems, false);
531
412936
  return tpn.isNull() ? Node(n) : tpn.getNode();
532
}
533
534
1611
Node PropEngine::getPreprocessedTerm(TNode n,
535
                                     std::vector<Node>& skAsserts,
536
                                     std::vector<Node>& sks)
537
{
538
  // get the preprocessed form of the term
539
1611
  Node pn = getPreprocessedTerm(n);
540
  // initialize the set of skolems and assertions to process
541
3222
  std::vector<Node> toProcessAsserts;
542
3222
  std::vector<Node> toProcess;
543
1611
  d_theoryProxy->getSkolems(pn, toProcessAsserts, toProcess);
544
1611
  size_t index = 0;
545
  // until fixed point is reached
546
6427
  while (index < toProcess.size())
547
  {
548
3531
    Node ka = toProcessAsserts[index];
549
3531
    Node k = toProcess[index];
550
2408
    index++;
551
2408
    if (std::find(sks.begin(), sks.end(), k) != sks.end())
552
    {
553
      // already added the skolem to the list
554
1285
      continue;
555
    }
556
    // must preprocess lemmas as well
557
2246
    Node kap = getPreprocessedTerm(ka);
558
1123
    skAsserts.push_back(kap);
559
1123
    sks.push_back(k);
560
    // get the skolems in the preprocessed form of the lemma ka
561
1123
    d_theoryProxy->getSkolems(kap, toProcessAsserts, toProcess);
562
  }
563
  // return the preprocessed term
564
3222
  return pn;
565
}
566
567
4869
void PropEngine::push()
568
{
569
4869
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
570
4869
  d_satSolver->push();
571
4869
  Debug("prop") << "push()" << std::endl;
572
4869
}
573
574
4869
void PropEngine::pop()
575
{
576
4869
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
577
4869
  d_satSolver->pop();
578
4869
  Debug("prop") << "pop()" << std::endl;
579
4869
}
580
581
15188
void PropEngine::resetTrail()
582
{
583
15188
  d_satSolver->resetTrail();
584
15188
  Debug("prop") << "resetTrail()" << std::endl;
585
15188
}
586
587
18877
unsigned PropEngine::getAssertionLevel() const
588
{
589
18877
  return d_satSolver->getAssertionLevel();
590
}
591
592
bool PropEngine::isRunning() const { return d_inCheckSat; }
593
void PropEngine::interrupt()
594
{
595
  if (!d_inCheckSat)
596
  {
597
    return;
598
  }
599
600
  d_interrupted = true;
601
  d_satSolver->interrupt();
602
  Debug("prop") << "interrupt()" << std::endl;
603
}
604
605
2700
void PropEngine::spendResource(Resource r)
606
{
607
2700
  d_env.getResourceManager()->spendResource(r);
608
2700
}
609
610
bool PropEngine::properExplanation(TNode node, TNode expl) const
611
{
612
  if (!d_cnfStream->hasLiteral(node))
613
  {
614
    Trace("properExplanation")
615
        << "properExplanation(): Failing because node "
616
        << "being explained doesn't have a SAT literal ?!" << std::endl
617
        << "properExplanation(): The node is: " << node << std::endl;
618
    return false;
619
  }
620
621
  SatLiteral nodeLit = d_cnfStream->getLiteral(node);
622
623
  for (TNode::kinded_iterator i = expl.begin(kind::AND),
624
                              i_end = expl.end(kind::AND);
625
       i != i_end;
626
       ++i)
627
  {
628
    if (!d_cnfStream->hasLiteral(*i))
629
    {
630
      Trace("properExplanation")
631
          << "properExplanation(): Failing because one of explanation "
632
          << "nodes doesn't have a SAT literal" << std::endl
633
          << "properExplanation(): The explanation node is: " << *i
634
          << std::endl;
635
      return false;
636
    }
637
638
    SatLiteral iLit = d_cnfStream->getLiteral(*i);
639
640
    if (iLit == nodeLit)
641
    {
642
      Trace("properExplanation")
643
          << "properExplanation(): Failing because the node" << std::endl
644
          << "properExplanation(): " << node << std::endl
645
          << "properExplanation(): cannot be made to explain itself!"
646
          << std::endl;
647
      return false;
648
    }
649
650
    if (!d_satSolver->properExplanation(nodeLit, iLit))
651
    {
652
      Trace("properExplanation")
653
          << "properExplanation(): SAT solver told us that node" << std::endl
654
          << "properExplanation(): " << *i << std::endl
655
          << "properExplanation(): is not part of a proper explanation node for"
656
          << std::endl
657
          << "properExplanation(): " << node << std::endl
658
          << "properExplanation(): Perhaps it one of the two isn't assigned or "
659
             "the explanation"
660
          << std::endl
661
          << "properExplanation(): node wasn't propagated before the node "
662
             "being explained"
663
          << std::endl;
664
      return false;
665
    }
666
  }
667
668
  return true;
669
}
670
671
void PropEngine::checkProof(context::CDList<Node>* assertions)
672
{
673
  if (!d_pnm)
674
  {
675
    return;
676
  }
677
  return d_ppm->checkProof(assertions);
678
}
679
680
18299
ProofCnfStream* PropEngine::getProofCnfStream() { return d_pfCnfStream.get(); }
681
682
2811
std::shared_ptr<ProofNode> PropEngine::getProof()
683
{
684
2811
  if (!d_pnm)
685
  {
686
    return nullptr;
687
  }
688
2811
  return d_ppm->getProof();
689
}
690
691
1472868
bool PropEngine::isProofEnabled() const { return d_pfCnfStream != nullptr; }
692
693
1371
void PropEngine::getUnsatCore(std::vector<Node>& core)
694
{
695
1371
  Assert(options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS);
696
2742
  std::vector<SatLiteral> unsat_assumptions;
697
1371
  d_satSolver->getUnsatAssumptions(unsat_assumptions);
698
8110
  for (const SatLiteral& lit : unsat_assumptions)
699
  {
700
6739
    core.push_back(d_cnfStream->getNode(lit));
701
  }
702
1371
}
703
704
1371
std::shared_ptr<ProofNode> PropEngine::getRefutation()
705
{
706
1371
  Assert(options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS);
707
2742
  std::vector<Node> core;
708
1371
  getUnsatCore(core);
709
2742
  CDProof cdp(d_pnm);
710
2742
  Node fnode = NodeManager::currentNM()->mkConst(false);
711
1371
  cdp.addStep(fnode, PfRule::SAT_REFUTATION, core, {});
712
2742
  return cdp.getProofFor(fnode);
713
}
714
715
}  // namespace prop
716
29340
}  // namespace cvc5