GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/prop/prop_engine.cpp Lines: 260 346 75.1 %
Date: 2021-09-17 Branches: 377 1194 31.6 %

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