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