GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/proof_manager.cpp Lines: 86 148 58.1 %
Date: 2021-11-07 Branches: 117 534 21.9 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Haniel Barbosa, Diego Della Rocca de Camargos
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
 * The proof manager of the SMT engine.
14
 */
15
16
#include "smt/proof_manager.h"
17
18
#include "options/base_options.h"
19
#include "options/main_options.h"
20
#include "options/proof_options.h"
21
#include "options/smt_options.h"
22
#include "proof/alethe/alethe_node_converter.h"
23
#include "proof/alethe/alethe_post_processor.h"
24
#include "proof/dot/dot_printer.h"
25
#include "proof/lfsc/lfsc_post_processor.h"
26
#include "proof/lfsc/lfsc_printer.h"
27
#include "proof/proof_checker.h"
28
#include "proof/proof_node_algorithm.h"
29
#include "proof/proof_node_manager.h"
30
#include "smt/assertions.h"
31
#include "smt/difficulty_post_processor.h"
32
#include "smt/env.h"
33
#include "smt/preprocess_proof_generator.h"
34
#include "smt/proof_post_processor.h"
35
36
namespace cvc5 {
37
namespace smt {
38
39
7989
PfManager::PfManager(Env& env)
40
    : EnvObj(env),
41
      d_pchecker(new ProofChecker(
42
7989
          options().proof.proofCheck == options::ProofCheckMode::EAGER,
43
15978
          options().proof.proofPedantic)),
44
7989
      d_pnm(new ProofNodeManager(env.getRewriter(), d_pchecker.get())),
45
      d_pppg(new PreprocessProofGenerator(
46
15978
          d_pnm.get(), env.getUserContext(), "smt::PreprocessProofGenerator")),
47
      d_pfpp(nullptr),
48
47934
      d_finalProof(nullptr)
49
{
50
  // enable proof support in the environment/rewriter
51
7989
  d_env.setProofNodeManager(d_pnm.get());
52
  // Now, initialize the proof postprocessor with the environment.
53
  // By default the post-processor will update all assumptions, which
54
  // can lead to SCOPE subproofs of the form
55
  //   A
56
  //  ...
57
  //   B1    B2
58
  //  ...   ...
59
  // ------------
60
  //      C
61
  // ------------- SCOPE [B1, B2]
62
  // B1 ^ B2 => C
63
  //
64
  // where A is an available assumption from outside the scope (note
65
  // that B1 was an assumption of this SCOPE subproof but since it could
66
  // be inferred from A, it was updated). This shape is problematic for
67
  // the Alethe reconstruction, so we disable the update of scoped
68
  // assumptions (which would disable the update of B1 in this case).
69
15978
  d_pfpp.reset(new ProofPostproccess(
70
      env,
71
7989
      d_pppg.get(),
72
      nullptr,
73
7989
      options().proof.proofFormatMode != options::ProofFormatMode::ALETHE));
74
75
  // add rules to eliminate here
76
15978
  if (options().proof.proofGranularityMode
77
7989
      != options::ProofGranularityMode::OFF)
78
  {
79
5290
    d_pfpp->setEliminateRule(PfRule::MACRO_SR_EQ_INTRO);
80
5290
    d_pfpp->setEliminateRule(PfRule::MACRO_SR_PRED_INTRO);
81
5290
    d_pfpp->setEliminateRule(PfRule::MACRO_SR_PRED_ELIM);
82
5290
    d_pfpp->setEliminateRule(PfRule::MACRO_SR_PRED_TRANSFORM);
83
5290
    d_pfpp->setEliminateRule(PfRule::MACRO_RESOLUTION_TRUST);
84
5290
    d_pfpp->setEliminateRule(PfRule::MACRO_RESOLUTION);
85
5290
    d_pfpp->setEliminateRule(PfRule::MACRO_ARITH_SCALE_SUM_UB);
86
10580
    if (options().proof.proofGranularityMode
87
5290
        != options::ProofGranularityMode::REWRITE)
88
    {
89
5290
      d_pfpp->setEliminateRule(PfRule::SUBS);
90
5290
      d_pfpp->setEliminateRule(PfRule::REWRITE);
91
10580
      if (options().proof.proofGranularityMode
92
5290
          != options::ProofGranularityMode::THEORY_REWRITE)
93
      {
94
        // this eliminates theory rewriting steps with finer-grained DSL rules
95
        d_pfpp->setEliminateRule(PfRule::THEORY_REWRITE);
96
      }
97
    }
98
    // theory-specific lazy proof reconstruction
99
5290
    d_pfpp->setEliminateRule(PfRule::STRING_INFERENCE);
100
5290
    d_pfpp->setEliminateRule(PfRule::BV_BITBLAST);
101
  }
102
7989
  d_false = NodeManager::currentNM()->mkConst(false);
103
7989
}
104
105
15978
PfManager::~PfManager() {}
106
107
7663
void PfManager::setFinalProof(std::shared_ptr<ProofNode> pfn, Assertions& as)
108
{
109
  // Note this assumes that setFinalProof is only called once per unsat
110
  // response. This method would need to cache its result otherwise.
111
7663
  Trace("smt-proof") << "SolverEngine::setFinalProof(): get proof body...\n";
112
113
7663
  if (Trace.isOn("smt-proof-debug"))
114
  {
115
    Trace("smt-proof-debug")
116
        << "SolverEngine::setFinalProof(): Proof node for false:\n";
117
    Trace("smt-proof-debug") << *pfn.get() << std::endl;
118
    Trace("smt-proof-debug") << "=====" << std::endl;
119
  }
120
121
15326
  std::vector<Node> assertions;
122
7663
  getAssertions(as, assertions);
123
124
7663
  if (Trace.isOn("smt-proof"))
125
  {
126
    Trace("smt-proof")
127
        << "SolverEngine::setFinalProof(): get free assumptions..."
128
        << std::endl;
129
    std::vector<Node> fassumps;
130
    expr::getFreeAssumptions(pfn.get(), fassumps);
131
    Trace("smt-proof")
132
        << "SolverEngine::setFinalProof(): initial free assumptions are:\n";
133
    for (const Node& a : fassumps)
134
    {
135
      Trace("smt-proof") << "- " << a << std::endl;
136
    }
137
138
    Trace("smt-proof") << "SolverEngine::setFinalProof(): assertions are:\n";
139
    for (const Node& n : assertions)
140
    {
141
      Trace("smt-proof") << "- " << n << std::endl;
142
    }
143
    Trace("smt-proof") << "=====" << std::endl;
144
  }
145
146
7663
  Trace("smt-proof") << "SolverEngine::setFinalProof(): postprocess...\n";
147
7663
  Assert(d_pfpp != nullptr);
148
7663
  d_pfpp->process(pfn);
149
150
7663
  Trace("smt-proof") << "SolverEngine::setFinalProof(): make scope...\n";
151
152
  // Now make the final scope, which ensures that the only open leaves of the
153
  // proof are the assertions.
154
7663
  d_finalProof = d_pnm->mkScope(pfn, assertions);
155
7663
  Trace("smt-proof") << "SolverEngine::setFinalProof(): finished.\n";
156
7663
}
157
158
6
void PfManager::printProof(std::ostream& out,
159
                           std::shared_ptr<ProofNode> pfn,
160
                           Assertions& as)
161
{
162
6
  Trace("smt-proof") << "PfManager::printProof: start" << std::endl;
163
12
  std::shared_ptr<ProofNode> fp = getFinalProof(pfn, as);
164
  // if we are in incremental mode, we don't want to invalidate the proof
165
  // nodes in fp, since these may be reused in further check-sat calls
166
12
  if (options().base.incrementalSolving
167
6
      && options().proof.proofFormatMode != options::ProofFormatMode::NONE)
168
  {
169
    fp = d_pnm->clone(fp);
170
  }
171
172
  // according to the proof format, post process and print the proof node
173
6
  if (options().proof.proofFormatMode == options::ProofFormatMode::DOT)
174
  {
175
    proof::DotPrinter dotPrinter;
176
    dotPrinter.print(out, fp.get());
177
  }
178
6
  else if (options().proof.proofFormatMode == options::ProofFormatMode::ALETHE)
179
  {
180
    proof::AletheNodeConverter anc;
181
    proof::AletheProofPostprocess vpfpp(d_pnm.get(), anc);
182
    vpfpp.process(fp);
183
  }
184
6
  else if (options().proof.proofFormatMode == options::ProofFormatMode::LFSC)
185
  {
186
2
    std::vector<Node> assertions;
187
1
    getAssertions(as, assertions);
188
2
    proof::LfscNodeConverter ltp;
189
2
    proof::LfscProofPostprocess lpp(ltp, d_pnm.get());
190
1
    lpp.process(fp);
191
2
    proof::LfscPrinter lp(ltp);
192
1
    lp.print(out, assertions, fp.get());
193
  }
194
5
  else if (options().proof.proofFormatMode == options::ProofFormatMode::TPTP)
195
  {
196
    out << "% SZS output start Proof for " << options().driver.filename
197
        << std::endl;
198
    // TODO (proj #37) print in TPTP compliant format
199
    out << *fp << std::endl;
200
    out << "% SZS output end Proof for " << options().driver.filename
201
        << std::endl;
202
  }
203
  else
204
  {
205
    // otherwise, print using default printer
206
5
    out << "(proof\n";
207
5
    out << *fp;
208
5
    out << "\n)\n";
209
  }
210
6
}
211
3793
void PfManager::checkProof(std::shared_ptr<ProofNode> pfn, Assertions& as)
212
{
213
3793
  Trace("smt-proof") << "PfManager::checkProof: start" << std::endl;
214
7586
  std::shared_ptr<ProofNode> fp = getFinalProof(pfn, as);
215
7586
  Trace("smt-proof-debug") << "PfManager::checkProof: returned " << *fp.get()
216
3793
                           << std::endl;
217
3793
}
218
219
4
void PfManager::translateDifficultyMap(std::map<Node, Node>& dmap,
220
                                       Assertions& as)
221
{
222
4
  Trace("difficulty") << "PfManager::translateDifficultyMap" << std::endl;
223
4
  if (dmap.empty())
224
  {
225
4
    return;
226
  }
227
  std::map<Node, Node> dmapp = dmap;
228
  dmap.clear();
229
  std::vector<Node> ppAsserts;
230
  for (const std::pair<const Node, Node>& ppa : dmapp)
231
  {
232
    Trace("difficulty") << "  preprocess difficulty: " << ppa.second << " for "
233
                        << ppa.first << std::endl;
234
    ppAsserts.push_back(ppa.first);
235
  }
236
  // assume a SAT refutation from all input assertions that were marked
237
  // as having a difficulty
238
  CDProof cdp(d_pnm.get());
239
  Node fnode = NodeManager::currentNM()->mkConst(false);
240
  cdp.addStep(fnode, PfRule::SAT_REFUTATION, ppAsserts, {});
241
  std::shared_ptr<ProofNode> pf = cdp.getProofFor(fnode);
242
  std::shared_ptr<ProofNode> fpf = getFinalProof(pf, as);
243
  Trace("difficulty-debug") << "Final proof is " << *fpf.get() << std::endl;
244
  Assert(fpf->getRule() == PfRule::SCOPE);
245
  fpf = fpf->getChildren()[0];
246
  // analyze proof
247
  Assert(fpf->getRule() == PfRule::SAT_REFUTATION);
248
  const std::vector<std::shared_ptr<ProofNode>>& children = fpf->getChildren();
249
  DifficultyPostprocessCallback dpc;
250
  ProofNodeUpdater dpnu(d_pnm.get(), dpc);
251
  // For each child of SAT_REFUTATION, we increment the difficulty on all
252
  // "source" free assumptions (see DifficultyPostprocessCallback) by the
253
  // difficulty of the preprocessed assertion.
254
  for (const std::shared_ptr<ProofNode>& c : children)
255
  {
256
    Node res = c->getResult();
257
    Assert(dmapp.find(res) != dmapp.end());
258
    Trace("difficulty-debug") << "  process: " << res << std::endl;
259
    Trace("difficulty-debug") << "  .dvalue: " << dmapp[res] << std::endl;
260
    Trace("difficulty-debug") << "  ..proof: " << *c.get() << std::endl;
261
    if (!dpc.setCurrentDifficulty(dmapp[res]))
262
    {
263
      continue;
264
    }
265
    dpnu.process(c);
266
  }
267
  // get the accumulated difficulty map from the callback
268
  dpc.getDifficultyMap(dmap);
269
}
270
271
ProofChecker* PfManager::getProofChecker() const { return d_pchecker.get(); }
272
273
ProofNodeManager* PfManager::getProofNodeManager() const { return d_pnm.get(); }
274
275
rewriter::RewriteDb* PfManager::getRewriteDatabase() const { return nullptr; }
276
277
7989
smt::PreprocessProofGenerator* PfManager::getPreprocessProofGenerator() const
278
{
279
7989
  return d_pppg.get();
280
}
281
282
7663
std::shared_ptr<ProofNode> PfManager::getFinalProof(
283
    std::shared_ptr<ProofNode> pfn, Assertions& as)
284
{
285
7663
  setFinalProof(pfn, as);
286
7663
  Assert(d_finalProof);
287
7663
  return d_finalProof;
288
}
289
290
7664
void PfManager::getAssertions(Assertions& as,
291
                              std::vector<Node>& assertions)
292
{
293
7664
  const context::CDList<Node>& al = as.getAssertionList();
294
7664
  Assert(options().smt.produceAssertions)
295
      << "Expected produce assertions to be true when checking proof";
296
51156
  for (const Node& a : al)
297
  {
298
43492
    assertions.push_back(a);
299
  }
300
7664
}
301
302
}  // namespace smt
303
31137
}  // namespace cvc5