GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/prop/prop_engine.cpp Lines: 262 348 75.3 %
Date: 2021-08-03 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
15192
  ScopedBool(bool& reference) :
59
15192
    d_reference(reference) {
60
15192
    d_original = reference;
61
15192
  }
62
63
30384
  ~ScopedBool() {
64
15192
    d_reference = d_original;
65
15192
  }
66
};
67
68
9908
PropEngine::PropEngine(TheoryEngine* te,
69
                       Env& env,
70
                       OutputManager& outMgr,
71
9908
                       ProofNodeManager* pnm)
72
    : d_inCheckSat(false),
73
      d_theoryEngine(te),
74
      d_env(env),
75
9908
      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
19816
      d_assumptions(d_env.getUserContext())
85
{
86
9908
  Debug("prop") << "Constructing the PropEngine" << std::endl;
87
9908
  context::Context* satContext = d_env.getContext();
88
9908
  context::UserContext* userContext = d_env.getUserContext();
89
9908
  ResourceManager* rm = d_env.getResourceManager();
90
91
9908
  options::DecisionMode dmode = options::decisionMode();
92
9908
  if (dmode == options::DecisionMode::JUSTIFICATION
93
2596
      || dmode == options::DecisionMode::STOPONLY)
94
  {
95
15456
    d_decisionEngine.reset(new decision::JustificationStrategy(
96
7728
        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
9908
  d_satSolver = SatSolverFactory::createCDCLTMinisat(smtStatisticsRegistry());
109
110
  // CNF stream and theory proxy required pointers to each other, make the
111
  // theory proxy first
112
9908
  d_theoryProxy = new TheoryProxy(this,
113
                                  d_theoryEngine,
114
9908
                                  d_decisionEngine.get(),
115
9908
                                  d_skdm.get(),
116
                                  satContext,
117
                                  userContext,
118
9908
                                  pnm);
119
29724
  d_cnfStream = new CnfStream(d_satSolver,
120
9908
                              d_theoryProxy,
121
                              userContext,
122
9908
                              &d_outMgr,
123
                              rm,
124
                              FormulaLitPolicy::TRACK,
125
19816
                              "prop");
126
127
  // connect theory proxy
128
9908
  d_theoryProxy->finishInit(d_cnfStream);
129
  // connect SAT solver
130
39632
  d_satSolver->initialize(
131
9908
      d_env.getContext(),
132
      d_theoryProxy,
133
9908
      d_env.getUserContext(),
134
9908
      options::unsatCoresMode() != options::UnsatCoresMode::ASSUMPTIONS
135
          ? pnm
136
9908
          : nullptr);
137
138
9908
  d_decisionEngine->finishInit(d_satSolver, d_cnfStream);
139
9908
  if (pnm && options::unsatCoresMode() != options::UnsatCoresMode::ASSUMPTIONS)
140
  {
141
2498
    d_pfCnfStream.reset(new ProofCnfStream(
142
        userContext,
143
1249
        *d_cnfStream,
144
1249
        static_cast<MinisatSatSolver*>(d_satSolver)->getProofManager(),
145
2498
        pnm));
146
2498
    d_ppm.reset(
147
1249
        new PropPfManager(userContext, pnm, d_satSolver, d_pfCnfStream.get()));
148
  }
149
9908
}
150
151
9908
void PropEngine::finishInit()
152
{
153
9908
  NodeManager* nm = NodeManager::currentNM();
154
9908
  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
9908
  if (isProofEnabled())
160
  {
161
1249
    static_cast<MinisatSatSolver*>(d_satSolver)
162
        ->getProofManager()
163
1249
        ->registerSatAssumptions({nm->mkConst(true)});
164
  }
165
9908
  d_cnfStream->convertAndAssert(nm->mkConst(false).notNode(), false, false);
166
9908
}
167
168
19816
PropEngine::~PropEngine() {
169
9908
  Debug("prop") << "Destructing the PropEngine" << std::endl;
170
9908
  d_decisionEngine.reset(nullptr);
171
9908
  delete d_cnfStream;
172
9908
  delete d_satSolver;
173
9908
  delete d_theoryProxy;
174
9908
}
175
176
106400
TrustNode PropEngine::preprocess(TNode node,
177
                                 std::vector<TrustNode>& newLemmas,
178
                                 std::vector<Node>& newSkolems)
179
{
180
106400
  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
13728
void PropEngine::assertInputFormulas(
191
    const std::vector<Node>& assertions,
192
    std::unordered_map<size_t, Node>& skolemMap)
193
{
194
13728
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
195
  // notify the theory engine of preprocessed assertions
196
13728
  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
13728
  std::unordered_map<size_t, Node>::iterator it;
203
139073
  for (size_t i = 0, asize = assertions.size(); i < asize; i++)
204
  {
205
    // is the assertion a skolem definition?
206
125345
    it = skolemMap.find(i);
207
250690
    Node skolem;
208
125345
    if (it != skolemMap.end())
209
    {
210
19607
      skolem = it->second;
211
    }
212
125345
    d_theoryProxy->notifyAssertion(assertions[i], skolem);
213
  }
214
139063
  for (const Node& node : assertions)
215
  {
216
125339
    Debug("prop") << "assertFormula(" << node << ")" << std::endl;
217
125343
    assertInternal(node, false, false, true);
218
  }
219
13724
}
220
221
445043
void PropEngine::assertLemma(TrustNode tlemma, theory::LemmaProperty p)
222
{
223
445043
  bool removable = isLemmaPropertyRemovable(p);
224
225
  // call preprocessor
226
890086
  std::vector<TrustNode> ppLemmas;
227
890086
  std::vector<Node> ppSkolems;
228
  TrustNode tplemma =
229
890086
      d_theoryProxy->preprocessLemma(tlemma, ppLemmas, ppSkolems);
230
231
445041
  Assert(ppSkolems.size() == ppLemmas.size());
232
233
  // do final checks on the lemmas we are about to send
234
445041
  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
445041
  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
445041
  assertLemmasInternal(tplemma, ppLemmas, ppSkolems, removable);
258
445041
}
259
260
455332
void PropEngine::assertTrustedLemmaInternal(TrustNode trn, bool removable)
261
{
262
910664
  Node node = trn.getNode();
263
455332
  Debug("prop::lemmas") << "assertLemma(" << node << ")" << std::endl;
264
455332
  bool negated = trn.getKind() == TrustNodeKind::CONFLICT;
265
455332
  Assert(
266
      !isProofEnabled() || trn.getGenerator() != nullptr
267
      || options::unsatCores()
268
      || (options::unsatCores()
269
          && options::unsatCoresMode() != options::UnsatCoresMode::FULL_PROOF));
270
455332
  assertInternal(trn.getNode(), negated, removable, false, trn.getGenerator());
271
455332
}
272
273
580671
void PropEngine::assertInternal(
274
    TNode node, bool negated, bool removable, bool input, ProofGenerator* pg)
275
{
276
  // Assert as (possibly) removable
277
580671
  if (options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS)
278
  {
279
171509
    if (input)
280
    {
281
33483
      d_cnfStream->ensureLiteral(node);
282
33483
      if (negated)
283
      {
284
        d_assumptions.push_back(node.notNode());
285
      }
286
      else
287
      {
288
33483
        d_assumptions.push_back(node);
289
      }
290
    }
291
    else
292
    {
293
138026
      d_cnfStream->convertAndAssert(node, removable, negated, input);
294
    }
295
  }
296
409162
  else if (isProofEnabled())
297
  {
298
93644
    d_pfCnfStream->convertAndAssert(node, negated, removable, pg);
299
    // if input, register the assertion in the proof manager
300
93644
    if (input)
301
    {
302
20433
      d_ppm->registerAssertion(node);
303
    }
304
  }
305
  else
306
  {
307
315522
    d_cnfStream->convertAndAssert(node, removable, negated, input);
308
  }
309
580667
}
310
311
641983
void PropEngine::assertLemmasInternal(TrustNode trn,
312
                                      const std::vector<TrustNode>& ppLemmas,
313
                                      const std::vector<Node>& ppSkolems,
314
                                      bool removable)
315
{
316
641983
  if (!trn.isNull())
317
  {
318
445041
    assertTrustedLemmaInternal(trn, removable);
319
  }
320
652274
  for (const TrustNode& tnl : ppLemmas)
321
  {
322
10291
    assertTrustedLemmaInternal(tnl, removable);
323
  }
324
  // assert to decision engine
325
641983
  if (!removable)
326
  {
327
    // also add to the decision engine, where notice we don't need proofs
328
526665
    if (!trn.isNull())
329
    {
330
      // notify the theory proxy of the lemma
331
329723
      d_theoryProxy->notifyAssertion(trn.getProven());
332
    }
333
526665
    Assert(ppSkolems.size() == ppLemmas.size());
334
536956
    for (size_t i = 0, lsize = ppLemmas.size(); i < lsize; ++i)
335
    {
336
20582
      Node lem = ppLemmas[i].getProven();
337
10291
      d_theoryProxy->notifyAssertion(ppLemmas[i].getProven(), ppSkolems[i]);
338
    }
339
  }
340
641983
}
341
342
66319
void PropEngine::requirePhase(TNode n, bool phase) {
343
66319
  Debug("prop") << "requirePhase(" << n << ", " << phase << ")" << std::endl;
344
345
66319
  Assert(n.getType().isBoolean());
346
66319
  SatLiteral lit = d_cnfStream->getLiteral(n);
347
66319
  d_satSolver->requirePhase(phase ? lit : ~lit);
348
66319
}
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
15192
Result PropEngine::checkSat() {
390
15192
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
391
15192
  Debug("prop") << "PropEngine::checkSat()" << std::endl;
392
393
  // Mark that we are in the checkSat
394
30384
  ScopedBool scopedBool(d_inCheckSat);
395
15192
  d_inCheckSat = true;
396
397
  // TODO This currently ignores conflicts (a dangerous practice).
398
15192
  d_decisionEngine->presolve();
399
15192
  d_theoryEngine->presolve();
400
401
30384
  if(options::preprocessOnly()) {
402
3
    return Result(Result::SAT_UNKNOWN, Result::REQUIRES_FULL_CHECK);
403
  }
404
405
  // Reset the interrupted flag
406
15189
  d_interrupted = false;
407
408
  // Check the problem
409
  SatValue result;
410
15189
  if (d_assumptions.size() == 0)
411
  {
412
11562
    result = d_satSolver->solve();
413
  }
414
  else
415
  {
416
7254
    std::vector<SatLiteral> assumptions;
417
51927
    for (const Node& node : d_assumptions)
418
    {
419
48300
      assumptions.push_back(d_cnfStream->getLiteral(node));
420
    }
421
3627
    result = d_satSolver->solve(assumptions);
422
  }
423
424
15173
  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
15173
  if( result == SAT_VALUE_TRUE && Debug.isOn("prop") ) {
439
    printSatisfyingAssignment();
440
  }
441
442
15173
  Debug("prop") << "PropEngine::checkSat() => " << result << std::endl;
443
15173
  if(result == SAT_VALUE_TRUE && d_theoryEngine->isIncomplete()) {
444
107
    return Result(Result::SAT_UNKNOWN, Result::INCOMPLETE);
445
  }
446
15066
  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
23513324
bool PropEngine::isSatLiteral(TNode node) const
473
{
474
23513324
  return d_cnfStream->hasLiteral(node);
475
}
476
477
9029262
bool PropEngine::hasValue(TNode node, bool& value) const
478
{
479
9029262
  Assert(node.getType().isBoolean());
480
9029262
  Assert(d_cnfStream->hasLiteral(node)) << node;
481
482
9029262
  SatLiteral lit = d_cnfStream->getLiteral(node);
483
484
9029262
  SatValue v = d_satSolver->value(lit);
485
9029262
  if (v == SAT_VALUE_TRUE)
486
  {
487
5786907
    value = true;
488
5786907
    return true;
489
  }
490
3242355
  else if (v == SAT_VALUE_FALSE)
491
  {
492
180635
    value = false;
493
180635
    return true;
494
  }
495
  else
496
  {
497
3061720
    Assert(v == SAT_VALUE_UNKNOWN);
498
3061720
    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
192673
Node PropEngine::ensureLiteral(TNode n)
508
{
509
  // must preprocess
510
192673
  Node preprocessed = getPreprocessedTerm(n);
511
385346
  Trace("ensureLiteral") << "ensureLiteral preprocessed: " << preprocessed
512
192673
                         << std::endl;
513
192673
  if (isProofEnabled())
514
  {
515
23788
    d_pfCnfStream->ensureLiteral(preprocessed);
516
  }
517
  else
518
  {
519
168885
    d_cnfStream->ensureLiteral(preprocessed);
520
  }
521
192673
  return preprocessed;
522
}
523
524
196942
Node PropEngine::getPreprocessedTerm(TNode n)
525
{
526
  // must preprocess
527
393884
  std::vector<TrustNode> newLemmas;
528
393884
  std::vector<Node> newSkolems;
529
393884
  TrustNode tpn = d_theoryProxy->preprocess(n, newLemmas, newSkolems);
530
  // send lemmas corresponding to the skolems introduced by preprocessing n
531
393884
  TrustNode trnNull;
532
196942
  assertLemmasInternal(trnNull, newLemmas, newSkolems, false);
533
393884
  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
15176
void PropEngine::resetTrail()
584
{
585
15176
  d_satSolver->resetTrail();
586
15176
  Debug("prop") << "resetTrail()" << std::endl;
587
15176
}
588
589
18865
unsigned PropEngine::getAssertionLevel() const
590
{
591
18865
  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
2738
void PropEngine::spendResource(Resource r)
608
{
609
2738
  d_env.getResourceManager()->spendResource(r);
610
2738
}
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
18235
ProofCnfStream* PropEngine::getProofCnfStream() { return d_pfCnfStream.get(); }
683
684
2799
std::shared_ptr<ProofNode> PropEngine::getProof()
685
{
686
2799
  if (!d_pnm)
687
  {
688
    return nullptr;
689
  }
690
2799
  return d_ppm->getProof();
691
}
692
693
1512116
bool PropEngine::isProofEnabled() const { return d_pfCnfStream != nullptr; }
694
695
1369
void PropEngine::getUnsatCore(std::vector<Node>& core)
696
{
697
1369
  Assert(options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS);
698
2738
  std::vector<SatLiteral> unsat_assumptions;
699
1369
  d_satSolver->getUnsatAssumptions(unsat_assumptions);
700
8106
  for (const SatLiteral& lit : unsat_assumptions)
701
  {
702
6737
    core.push_back(d_cnfStream->getNode(lit));
703
  }
704
1369
}
705
706
1369
std::shared_ptr<ProofNode> PropEngine::getRefutation()
707
{
708
1369
  Assert(options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS);
709
2738
  std::vector<Node> core;
710
1369
  getUnsatCore(core);
711
2738
  CDProof cdp(d_pnm);
712
2738
  Node fnode = NodeManager::currentNM()->mkConst(false);
713
1369
  cdp.addStep(fnode, PfRule::SAT_REFUTATION, core, {});
714
2738
  return cdp.getProofFor(fnode);
715
}
716
717
}  // namespace prop
718
29286
}  // namespace cvc5