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