GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/prop/prop_engine.cpp Lines: 247 341 72.4 %
Date: 2021-05-21 Branches: 361 1202 30.0 %

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.h"
25
#include "decision/decision_engine_old.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
12748
  ScopedBool(bool& reference) :
59
12748
    d_reference(reference) {
60
12748
    d_original = reference;
61
12748
  }
62
63
25496
  ~ScopedBool() {
64
12748
    d_reference = d_original;
65
12748
  }
66
};
67
68
8988
PropEngine::PropEngine(TheoryEngine* te,
69
                       Env& env,
70
                       OutputManager& outMgr,
71
8988
                       ProofNodeManager* pnm)
72
    : d_inCheckSat(false),
73
      d_theoryEngine(te),
74
      d_env(env),
75
8988
      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
17976
      d_assumptions(d_env.getUserContext())
85
{
86
8988
  Debug("prop") << "Constructing the PropEngine" << std::endl;
87
8988
  context::Context* satContext = d_env.getContext();
88
8988
  context::UserContext* userContext = d_env.getUserContext();
89
8988
  ResourceManager* rm = d_env.getResourceManager();
90
91
17976
  d_decisionEngine.reset(
92
8988
      new decision::DecisionEngine(satContext, userContext, d_skdm.get(), rm));
93
94
8988
  d_satSolver = SatSolverFactory::createCDCLTMinisat(smtStatisticsRegistry());
95
96
  // CNF stream and theory proxy required pointers to each other, make the
97
  // theory proxy first
98
8988
  d_theoryProxy = new TheoryProxy(this,
99
                                  d_theoryEngine,
100
8988
                                  d_decisionEngine.get(),
101
8988
                                  d_skdm.get(),
102
                                  satContext,
103
                                  userContext,
104
8988
                                  pnm);
105
26964
  d_cnfStream = new CnfStream(d_satSolver,
106
8988
                              d_theoryProxy,
107
                              userContext,
108
8988
                              &d_outMgr,
109
                              rm,
110
17976
                              FormulaLitPolicy::TRACK);
111
112
  // connect theory proxy
113
8988
  d_theoryProxy->finishInit(d_cnfStream);
114
  // connect SAT solver
115
35952
  d_satSolver->initialize(
116
8988
      d_env.getContext(),
117
      d_theoryProxy,
118
8988
      d_env.getUserContext(),
119
8988
      options::unsatCoresMode() != options::UnsatCoresMode::ASSUMPTIONS
120
          ? pnm
121
8988
          : nullptr);
122
123
8988
  d_decisionEngine->finishInit(d_satSolver, d_cnfStream);
124
8988
  if (pnm && options::unsatCoresMode() != options::UnsatCoresMode::ASSUMPTIONS)
125
  {
126
2438
    d_pfCnfStream.reset(new ProofCnfStream(
127
        userContext,
128
1219
        *d_cnfStream,
129
1219
        static_cast<MinisatSatSolver*>(d_satSolver)->getProofManager(),
130
2438
        pnm));
131
2438
    d_ppm.reset(
132
1219
        new PropPfManager(userContext, pnm, d_satSolver, d_pfCnfStream.get()));
133
  }
134
8988
}
135
136
8988
void PropEngine::finishInit()
137
{
138
8988
  NodeManager* nm = NodeManager::currentNM();
139
8988
  d_cnfStream->convertAndAssert(nm->mkConst(true), false, false);
140
  // this is necessary because if True is later asserted to the prop engine the
141
  // CNF stream will ignore it since the SAT solver already had it registered,
142
  // thus not having True as an assumption for the SAT proof. To solve this
143
  // issue we track it directly here
144
8988
  if (isProofEnabled())
145
  {
146
1219
    static_cast<MinisatSatSolver*>(d_satSolver)
147
        ->getProofManager()
148
1219
        ->registerSatAssumptions({nm->mkConst(true)});
149
  }
150
8988
  d_cnfStream->convertAndAssert(nm->mkConst(false).notNode(), false, false);
151
8988
}
152
153
17976
PropEngine::~PropEngine() {
154
8988
  Debug("prop") << "Destructing the PropEngine" << std::endl;
155
8988
  d_decisionEngine.reset(nullptr);
156
8988
  delete d_cnfStream;
157
8988
  delete d_satSolver;
158
8988
  delete d_theoryProxy;
159
8988
}
160
161
99394
theory::TrustNode PropEngine::preprocess(
162
    TNode node,
163
    std::vector<theory::TrustNode>& newLemmas,
164
    std::vector<Node>& newSkolems)
165
{
166
99394
  return d_theoryProxy->preprocess(node, newLemmas, newSkolems);
167
}
168
169
4
theory::TrustNode PropEngine::removeItes(
170
    TNode node,
171
    std::vector<theory::TrustNode>& newLemmas,
172
    std::vector<Node>& newSkolems)
173
{
174
4
  return d_theoryProxy->removeItes(node, newLemmas, newSkolems);
175
}
176
177
11631
void PropEngine::assertInputFormulas(
178
    const std::vector<Node>& assertions,
179
    std::unordered_map<size_t, Node>& skolemMap)
180
{
181
11631
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
182
  // notify the theory engine of preprocessed assertions
183
11631
  d_theoryEngine->notifyPreprocessedAssertions(assertions);
184
  // Now, notify the theory proxy of the assertions and skolem definitions.
185
  // Notice we do this before asserting the formulas to the CNF stream below,
186
  // since (preregistration) lemmas may occur during calls to assertInternal.
187
  // These lemmas we want to be notified about after the theory proxy has
188
  // been notified about all input assertions.
189
11631
  std::unordered_map<size_t, Node>::iterator it;
190
128924
  for (size_t i = 0, asize = assertions.size(); i < asize; i++)
191
  {
192
    // is the assertion a skolem definition?
193
117293
    it = skolemMap.find(i);
194
234586
    Node skolem;
195
117293
    if (it != skolemMap.end())
196
    {
197
18561
      skolem = it->second;
198
    }
199
117293
    d_theoryProxy->notifyAssertion(assertions[i], skolem);
200
  }
201
128914
  for (const Node& node : assertions)
202
  {
203
117287
    Debug("prop") << "assertFormula(" << node << ")" << std::endl;
204
117291
    assertInternal(node, false, false, true);
205
  }
206
11627
}
207
208
400790
void PropEngine::assertLemma(theory::TrustNode tlemma, theory::LemmaProperty p)
209
{
210
400790
  bool removable = isLemmaPropertyRemovable(p);
211
212
  // call preprocessor
213
801580
  std::vector<theory::TrustNode> ppLemmas;
214
801580
  std::vector<Node> ppSkolems;
215
  theory::TrustNode tplemma =
216
801580
      d_theoryProxy->preprocessLemma(tlemma, ppLemmas, ppSkolems);
217
218
400788
  Assert(ppSkolems.size() == ppLemmas.size());
219
220
  // do final checks on the lemmas we are about to send
221
14038141
  if (isProofEnabled() && options::proofEagerChecking())
222
  {
223
    Assert(tplemma.getGenerator() != nullptr);
224
    // ensure closed, make the proof node eagerly here to debug
225
    tplemma.debugCheckClosed("te-proof-debug", "TheoryEngine::lemma");
226
    for (size_t i = 0, lsize = ppLemmas.size(); i < lsize; ++i)
227
    {
228
      Assert(ppLemmas[i].getGenerator() != nullptr);
229
      ppLemmas[i].debugCheckClosed("te-proof-debug", "TheoryEngine::lemma_new");
230
    }
231
  }
232
233
400788
  if (Trace.isOn("te-lemma"))
234
  {
235
    Trace("te-lemma") << "Lemma, output: " << tplemma.getProven() << std::endl;
236
    for (size_t i = 0, lsize = ppLemmas.size(); i < lsize; ++i)
237
    {
238
      Trace("te-lemma") << "Lemma, new lemma: " << ppLemmas[i].getProven()
239
                        << " (skolem is " << ppSkolems[i] << ")" << std::endl;
240
    }
241
  }
242
243
  // now, assert the lemmas
244
400788
  assertLemmasInternal(tplemma, ppLemmas, ppSkolems, removable);
245
400788
}
246
247
410738
void PropEngine::assertTrustedLemmaInternal(theory::TrustNode trn,
248
                                            bool removable)
249
{
250
821476
  Node node = trn.getNode();
251
410738
  Debug("prop::lemmas") << "assertLemma(" << node << ")" << std::endl;
252
410738
  bool negated = trn.getKind() == theory::TrustNodeKind::CONFLICT;
253
410738
  Assert(
254
      !isProofEnabled() || trn.getGenerator() != nullptr
255
      || options::unsatCores()
256
      || (options::unsatCores()
257
          && options::unsatCoresMode() != options::UnsatCoresMode::FULL_PROOF));
258
410738
  assertInternal(trn.getNode(), negated, removable, false, trn.getGenerator());
259
410738
}
260
261
528025
void PropEngine::assertInternal(
262
    TNode node, bool negated, bool removable, bool input, ProofGenerator* pg)
263
{
264
  // Assert as (possibly) removable
265
528025
  if (options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS)
266
  {
267
142181
    if (input)
268
    {
269
27174
      d_cnfStream->ensureLiteral(node);
270
27174
      if (negated)
271
      {
272
        d_assumptions.push_back(node.notNode());
273
      }
274
      else
275
      {
276
27174
        d_assumptions.push_back(node);
277
      }
278
    }
279
    else
280
    {
281
115007
      d_cnfStream->convertAndAssert(node, removable, negated, input);
282
    }
283
  }
284
385844
  else if (isProofEnabled())
285
  {
286
90921
    d_pfCnfStream->convertAndAssert(node, negated, removable, pg);
287
    // if input, register the assertion in the proof manager
288
90921
    if (input)
289
    {
290
20984
      d_ppm->registerAssertion(node);
291
    }
292
  }
293
  else
294
  {
295
294927
    d_cnfStream->convertAndAssert(node, removable, negated, input);
296
  }
297
528021
}
298
299
558028
void PropEngine::assertLemmasInternal(
300
    theory::TrustNode trn,
301
    const std::vector<theory::TrustNode>& ppLemmas,
302
    const std::vector<Node>& ppSkolems,
303
    bool removable)
304
{
305
558028
  if (!trn.isNull())
306
  {
307
400788
    assertTrustedLemmaInternal(trn, removable);
308
  }
309
567978
  for (const theory::TrustNode& tnl : ppLemmas)
310
  {
311
9950
    assertTrustedLemmaInternal(tnl, removable);
312
  }
313
  // assert to decision engine
314
558028
  if (!removable)
315
  {
316
    // also add to the decision engine, where notice we don't need proofs
317
449465
    if (!trn.isNull())
318
    {
319
      // notify the theory proxy of the lemma
320
292225
      d_theoryProxy->notifyAssertion(trn.getProven());
321
    }
322
449465
    Assert(ppSkolems.size() == ppLemmas.size());
323
459415
    for (size_t i = 0, lsize = ppLemmas.size(); i < lsize; ++i)
324
    {
325
19900
      Node lem = ppLemmas[i].getProven();
326
9950
      d_theoryProxy->notifyAssertion(ppLemmas[i].getProven(), ppSkolems[i]);
327
    }
328
  }
329
558028
}
330
331
59017
void PropEngine::requirePhase(TNode n, bool phase) {
332
59017
  Debug("prop") << "requirePhase(" << n << ", " << phase << ")" << std::endl;
333
334
59017
  Assert(n.getType().isBoolean());
335
59017
  SatLiteral lit = d_cnfStream->getLiteral(n);
336
59017
  d_satSolver->requirePhase(phase ? lit : ~lit);
337
59017
}
338
339
225678
bool PropEngine::isDecision(Node lit) const {
340
225678
  Assert(isSatLiteral(lit));
341
225678
  return d_satSolver->isDecision(d_cnfStream->getLiteral(lit).getSatVariable());
342
}
343
344
int32_t PropEngine::getDecisionLevel(Node lit) const
345
{
346
  Assert(isSatLiteral(lit));
347
  return d_satSolver->getDecisionLevel(
348
      d_cnfStream->getLiteral(lit).getSatVariable());
349
}
350
351
int32_t PropEngine::getIntroLevel(Node lit) const
352
{
353
  Assert(isSatLiteral(lit));
354
  return d_satSolver->getIntroLevel(
355
      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
12748
Result PropEngine::checkSat() {
379
12748
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
380
12748
  Debug("prop") << "PropEngine::checkSat()" << std::endl;
381
382
  // Mark that we are in the checkSat
383
25496
  ScopedBool scopedBool(d_inCheckSat);
384
12748
  d_inCheckSat = true;
385
386
  // TODO This currently ignores conflicts (a dangerous practice).
387
12748
  d_decisionEngine->presolve();
388
12748
  d_theoryEngine->presolve();
389
390
25499
  if(options::preprocessOnly()) {
391
3
    return Result(Result::SAT_UNKNOWN, Result::REQUIRES_FULL_CHECK);
392
  }
393
394
  // Reset the interrupted flag
395
12745
  d_interrupted = false;
396
397
  // Check the problem
398
  SatValue result;
399
12745
  if (d_assumptions.size() == 0)
400
  {
401
10739
    result = d_satSolver->solve();
402
  }
403
  else
404
  {
405
4012
    std::vector<SatLiteral> assumptions;
406
36258
    for (const Node& node : d_assumptions)
407
    {
408
34252
      assumptions.push_back(d_cnfStream->getLiteral(node));
409
    }
410
2006
    result = d_satSolver->solve(assumptions);
411
  }
412
413
12729
  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
12729
  if( result == SAT_VALUE_TRUE && Debug.isOn("prop") ) {
428
    printSatisfyingAssignment();
429
  }
430
431
12729
  Debug("prop") << "PropEngine::checkSat() => " << result << std::endl;
432
12729
  if(result == SAT_VALUE_TRUE && d_theoryEngine->isIncomplete()) {
433
88
    return Result(Result::SAT_UNKNOWN, Result::INCOMPLETE);
434
  }
435
12641
  return Result(result == SAT_VALUE_TRUE ? Result::SAT : Result::UNSAT);
436
}
437
438
35074
Node PropEngine::getValue(TNode node) const
439
{
440
35074
  Assert(node.getType().isBoolean());
441
35074
  Assert(d_cnfStream->hasLiteral(node));
442
443
35074
  SatLiteral lit = d_cnfStream->getLiteral(node);
444
445
35074
  SatValue v = d_satSolver->value(lit);
446
35074
  if (v == SAT_VALUE_TRUE)
447
  {
448
35058
    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
21672699
bool PropEngine::isSatLiteral(TNode node) const
462
{
463
21672699
  return d_cnfStream->hasLiteral(node);
464
}
465
466
8677018
bool PropEngine::hasValue(TNode node, bool& value) const
467
{
468
8677018
  Assert(node.getType().isBoolean());
469
8677018
  Assert(d_cnfStream->hasLiteral(node)) << node;
470
471
8677018
  SatLiteral lit = d_cnfStream->getLiteral(node);
472
473
8677018
  SatValue v = d_satSolver->value(lit);
474
8677018
  if (v == SAT_VALUE_TRUE)
475
  {
476
5180538
    value = true;
477
5180538
    return true;
478
  }
479
3496480
  else if (v == SAT_VALUE_FALSE)
480
  {
481
139265
    value = false;
482
139265
    return true;
483
  }
484
  else
485
  {
486
3357215
    Assert(v == SAT_VALUE_UNKNOWN);
487
3357215
    return false;
488
  }
489
}
490
491
15147
void PropEngine::getBooleanVariables(std::vector<TNode>& outputVariables) const
492
{
493
15147
  d_cnfStream->getBooleanVariables(outputVariables);
494
15147
}
495
496
153225
Node PropEngine::ensureLiteral(TNode n)
497
{
498
  // must preprocess
499
153225
  Node preprocessed = getPreprocessedTerm(n);
500
306450
  Trace("ensureLiteral") << "ensureLiteral preprocessed: " << preprocessed
501
153225
                         << std::endl;
502
153225
  if (isProofEnabled())
503
  {
504
19112
    d_pfCnfStream->ensureLiteral(preprocessed);
505
  }
506
  else
507
  {
508
134113
    d_cnfStream->ensureLiteral(preprocessed);
509
  }
510
153225
  return preprocessed;
511
}
512
513
157240
Node PropEngine::getPreprocessedTerm(TNode n)
514
{
515
  // must preprocess
516
314480
  std::vector<theory::TrustNode> newLemmas;
517
314480
  std::vector<Node> newSkolems;
518
314480
  theory::TrustNode tpn = d_theoryProxy->preprocess(n, newLemmas, newSkolems);
519
  // send lemmas corresponding to the skolems introduced by preprocessing n
520
314480
  theory::TrustNode trnNull;
521
157240
  assertLemmasInternal(trnNull, newLemmas, newSkolems, false);
522
314480
  return tpn.isNull() ? Node(n) : tpn.getNode();
523
}
524
525
1584
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
1584
  Node pn = getPreprocessedTerm(n);
531
  // initialize the set of skolems and assertions to process
532
3168
  std::vector<Node> toProcessAsserts;
533
3168
  std::vector<Node> toProcess;
534
1584
  d_theoryProxy->getSkolems(pn, toProcessAsserts, toProcess);
535
1584
  size_t index = 0;
536
  // until fixed point is reached
537
5786
  while (index < toProcess.size())
538
  {
539
3096
    Node ka = toProcessAsserts[index];
540
3096
    Node k = toProcess[index];
541
2101
    index++;
542
2101
    if (std::find(sks.begin(), sks.end(), k) != sks.end())
543
    {
544
      // already added the skolem to the list
545
1106
      continue;
546
    }
547
    // must preprocess lemmas as well
548
1990
    Node kap = getPreprocessedTerm(ka);
549
995
    skAsserts.push_back(kap);
550
995
    sks.push_back(k);
551
    // get the skolems in the preprocessed form of the lemma ka
552
995
    d_theoryProxy->getSkolems(kap, toProcessAsserts, toProcess);
553
  }
554
  // return the preprocessed term
555
3168
  return pn;
556
}
557
558
3596
void PropEngine::push()
559
{
560
3596
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
561
3596
  d_satSolver->push();
562
3596
  Debug("prop") << "push()" << std::endl;
563
3596
}
564
565
3596
void PropEngine::pop()
566
{
567
3596
  Assert(!d_inCheckSat) << "Sat solver in solve()!";
568
3596
  d_satSolver->pop();
569
3596
  Debug("prop") << "pop()" << std::endl;
570
3596
}
571
572
12732
void PropEngine::resetTrail()
573
{
574
12732
  d_satSolver->resetTrail();
575
12732
  Debug("prop") << "resetTrail()" << std::endl;
576
12732
}
577
578
18073
unsigned PropEngine::getAssertionLevel() const
579
{
580
18073
  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
2480
void PropEngine::spendResource(Resource r)
597
{
598
2480
  d_env.getResourceManager()->spendResource(r);
599
2480
}
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_pnm)
665
  {
666
    return;
667
  }
668
  return d_ppm->checkProof(assertions);
669
}
670
671
21509
ProofCnfStream* PropEngine::getProofCnfStream() { return d_pfCnfStream.get(); }
672
673
2709
std::shared_ptr<ProofNode> PropEngine::getProof()
674
{
675
2709
  if (!d_pnm)
676
  {
677
    return nullptr;
678
  }
679
2709
  return d_ppm->getProof();
680
}
681
682
1359583
bool PropEngine::isProofEnabled() const { return d_pfCnfStream != nullptr; }
683
684
963
void PropEngine::getUnsatCore(std::vector<Node>& core)
685
{
686
963
  Assert(options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS);
687
1926
  std::vector<SatLiteral> unsat_assumptions;
688
963
  d_satSolver->getUnsatAssumptions(unsat_assumptions);
689
6267
  for (const SatLiteral& lit : unsat_assumptions)
690
  {
691
5304
    core.push_back(d_cnfStream->getNode(lit));
692
  }
693
963
}
694
695
963
std::shared_ptr<ProofNode> PropEngine::getRefutation()
696
{
697
963
  Assert(options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS);
698
1926
  std::vector<Node> core;
699
963
  getUnsatCore(core);
700
1926
  CDProof cdp(d_pnm);
701
1926
  Node fnode = NodeManager::currentNM()->mkConst(false);
702
963
  cdp.addStep(fnode, PfRule::SAT_REFUTATION, core, {});
703
1926
  return cdp.getProofFor(fnode);
704
}
705
706
}  // namespace prop
707
27735
}  // namespace cvc5