GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/proof_post_processor.h Lines: 2 2 100.0 %
Date: 2021-08-06 Branches: 0 0 0.0 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Haniel Barbosa, Gereon Kremer
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 module for processing proof nodes.
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__SMT__PROOF_POST_PROCESSOR_H
19
#define CVC5__SMT__PROOF_POST_PROCESSOR_H
20
21
#include <map>
22
#include <sstream>
23
#include <unordered_set>
24
25
#include "proof/proof_node_updater.h"
26
#include "smt/witness_form.h"
27
#include "theory/inference_id.h"
28
#include "util/statistics_stats.h"
29
30
namespace cvc5 {
31
32
class SmtEngine;
33
34
namespace smt {
35
36
/**
37
 * A callback class used by SmtEngine for post-processing proof nodes by
38
 * connecting proofs of preprocessing, and expanding macro PfRule applications.
39
 */
40
class ProofPostprocessCallback : public ProofNodeUpdaterCallback
41
{
42
 public:
43
  ProofPostprocessCallback(ProofNodeManager* pnm,
44
                           SmtEngine* smte,
45
                           ProofGenerator* pppg,
46
                           bool updateScopedAssumptions);
47
3768
  ~ProofPostprocessCallback() {}
48
  /**
49
   * Initialize, called once for each new ProofNode to process. This initializes
50
   * static information to be used by successive calls to update.
51
   */
52
  void initializeUpdate();
53
  /**
54
   * Set eliminate rule, which adds rule to the list of rules we will eliminate
55
   * during update. This adds rule to d_elimRules. Supported rules for
56
   * elimination include MACRO_*, SUBS and REWRITE. Otherwise, this method
57
   * has no effect.
58
   */
59
  void setEliminateRule(PfRule rule);
60
  /** Should proof pn be updated? */
61
  bool shouldUpdate(std::shared_ptr<ProofNode> pn,
62
                    const std::vector<Node>& fa,
63
                    bool& continueUpdate) override;
64
  /** Update the proof rule application. */
65
  bool update(Node res,
66
              PfRule id,
67
              const std::vector<Node>& children,
68
              const std::vector<Node>& args,
69
              CDProof* cdp,
70
              bool& continueUpdate) override;
71
72
 private:
73
  /** Common constants */
74
  Node d_true;
75
  /** The proof node manager */
76
  ProofNodeManager* d_pnm;
77
  /** Pointer to the SmtEngine, which should have proofs enabled */
78
  SmtEngine* d_smte;
79
  /** The preprocessing proof generator */
80
  ProofGenerator* d_pppg;
81
  /** The witness form proof generator */
82
  WitnessFormGenerator d_wfpm;
83
  /** The witness form assumptions used in the proof */
84
  std::vector<Node> d_wfAssumptions;
85
  /** Kinds of proof rules we are eliminating */
86
  std::unordered_set<PfRule, PfRuleHashFunction> d_elimRules;
87
  /** Whether we post-process assumptions in scope. */
88
  bool d_updateScopedAssumptions;
89
  //---------------------------------reset at the begining of each update
90
  /** Mapping assumptions to their proof from preprocessing */
91
  std::map<Node, std::shared_ptr<ProofNode> > d_assumpToProof;
92
  //---------------------------------end reset at the begining of each update
93
  /**
94
   * Expand rules in the given application, add the expanded proof to cdp.
95
   * The set of rules we expand is configured by calls to setEliminateRule
96
   * above. This method calls update to perform possible post-processing in the
97
   * rules it introduces as a result of the expansion.
98
   *
99
   * @param id The rule of the application
100
   * @param children The children of the application
101
   * @param args The arguments of the application
102
   * @param cdp The proof to add to
103
   * @return The conclusion of the rule, or null if this rule is not eliminated.
104
   */
105
  Node expandMacros(PfRule id,
106
                    const std::vector<Node>& children,
107
                    const std::vector<Node>& args,
108
                    CDProof* cdp);
109
  /**
110
   * Update the proof rule application, called during expand macros when
111
   * we wish to apply the update method. This method has the same behavior
112
   * as update apart from ignoring the continueUpdate flag.
113
   */
114
  bool updateInternal(Node res,
115
                      PfRule id,
116
                      const std::vector<Node>& children,
117
                      const std::vector<Node>& args,
118
                      CDProof* cdp);
119
  /**
120
   * Add proof for witness form. This returns the equality t = toWitness(t)
121
   * and ensures that the proof of this equality has been added to cdp.
122
   * Notice the proof of this fact may have open assumptions of the form:
123
   *   k = toWitness(k)
124
   * where k is a skolem. Furthermore, note that all open assumptions of this
125
   * form are available via d_wfpm.getWitnessFormEqs() in the remainder of
126
   * the lifetime of this class.
127
   */
128
  Node addProofForWitnessForm(Node t, CDProof* cdp);
129
  /**
130
   * Apply transivity if necessary for the arguments. The nodes in
131
   * tchildren have been ordered such that they are legal arguments to TRANS.
132
   *
133
   * Returns the conclusion of the transitivity step, which is null if
134
   * tchildren is empty. Also note if tchildren contains a single element,
135
   * then no TRANS step is necessary to add to cdp.
136
   *
137
   * @param tchildren The children of a TRANS step
138
   * @param cdp The proof to add the TRANS step to
139
   * @return The conclusion of the TRANS step.
140
   */
141
  Node addProofForTrans(const std::vector<Node>& tchildren, CDProof* cdp);
142
  /**
143
   * Add proof for substitution step. Some substitutions are derived based
144
   * on viewing a formula as a Boolean assignment (see MethodId::SB_LITERAL for
145
   * example). This method ensures that the proof of var == subs exists
146
   * in cdp, where var, subs were derived from BuiltinProofRuleChecker's
147
   * getSubstitution method.
148
   *
149
   * @param var The variable of the substitution
150
   * @param subs The substituted term
151
   * @param assump The formula the substitution was derived from
152
   * @param cdp The proof to add to
153
   * @return var == subs, the conclusion of the substitution step.
154
   */
155
  Node addProofForSubsStep(Node var, Node subs, Node assump, CDProof* cdp);
156
  /** Add eq (or its symmetry) to transivity children, if not reflexive */
157
  bool addToTransChildren(Node eq,
158
                          std::vector<Node>& tchildren,
159
                          bool isSymm = false);
160
161
  /**
162
   * When given children and args lead to different sets of literals in a
163
   * conclusion depending on whether macro resolution or chain resolution is
164
   * applied, the literals that appear in the chain resolution result, but not
165
   * in the macro resolution result, from now on "crowding literals", are
166
   * literals removed implicitly by macro resolution. For example
167
   *
168
   *      l0 v l0 v l0 v l1 v l2    ~l0 v l1   ~l1
169
   * (1)  ----------------------------------------- MACRO_RES
170
   *                 l2
171
   *
172
   * but
173
   *
174
   *      l0 v l0 v l0 v l1 v l2    ~l0 v l1   ~l1
175
   * (2)  ---------------------------------------- CHAIN_RES
176
   *                l0 v l0 v l1 v l2
177
   *
178
   * where l0 and l1 are crowding literals in the second proof.
179
   *
180
   * There are two views for how MACRO_RES implicitly removes the crowding
181
   * literal, i.e., how MACRO_RES can be expanded into CHAIN_RES so that
182
   * crowding literals are removed. The first is that (1) becomes
183
   *
184
   *  l0 v l0 v l0 v l1 v l2  ~l0 v l1  ~l0 v l1  ~l0 v l1  ~l1  ~l1  ~l1  ~l1
185
   *  ---------------------------------------------------------------- CHAIN_RES
186
   *                                 l2
187
   *
188
   * via the repetition of the premise responsible for removing more than one
189
   * occurrence of the crowding literal. The issue however is that this
190
   * expansion is exponential. Note that (2) has two occurrences of l0 and one
191
   * of l1 as crowding literals. However, by repeating ~l0 v l1 two times to
192
   * remove l0, the clause ~l1, which would originally need to be repeated only
193
   * one time, now has to be repeated two extra times on top of that one. With
194
   * multiple crowding literals and their elimination depending on premises that
195
   * themselves add crowding literals one can easily end up with resolution
196
   * chains going from dozens to thousands of premises. Such examples do occur
197
   * in practice, even in our regressions.
198
   *
199
   * The second way of expanding MACRO_RES, which avoids this exponential
200
   * behavior, is so that (1) becomes
201
   *
202
   *      l0 v l0 v l0 v l1 v l2
203
   * (4)  ---------------------- FACTORING
204
   *      l0 v l1 v l2                       ~l0 v l1
205
   *      ------------------------------------------- CHAIN_RES
206
   *                   l1 v l1 v l2
207
   *                  ------------- FACTORING
208
   *                     l1 v l2                   ~l1
209
   *                    ------------------------------ CHAIN_RES
210
   *                                 l2
211
   *
212
   * This method first determines what are the crowding literals by checking
213
   * what literals occur in clauseLits that do not occur in targetClauseLits
214
   * (the latter contains the literals from the original MACRO_RES conclusion
215
   * while the former the literals from a direct application of CHAIN_RES). Then
216
   * it builds a proof such as (4) and adds the steps to cdp. The final
217
   * conclusion is returned.
218
   *
219
   * Note that in the example the CHAIN_RES steps introduced had only two
220
   * premises, and could thus be replaced by a RESOLUTION step, but since we
221
   * general there can be more than two premises we always use CHAIN_RES.
222
   *
223
   * @param clauseLits literals in the conclusion of a CHAIN_RESOLUTION step
224
   * with children and args[1:]
225
   * @param clauseLits literals in the conclusion of a MACRO_RESOLUTION step
226
   * with children and args
227
   * @param children a list of clauses
228
   * @param args a list of arguments to a MACRO_RESOLUTION step
229
   * @param cdp a CDProof
230
   * @return The resulting node of transforming MACRO_RESOLUTION into
231
   * CHAIN_RESOLUTION according to the above idea.
232
   */
233
  Node eliminateCrowdingLits(const std::vector<Node>& clauseLits,
234
                             const std::vector<Node>& targetClauseLits,
235
                             const std::vector<Node>& children,
236
                             const std::vector<Node>& args,
237
                             CDProof* cdp);
238
};
239
240
/** Final callback class, for stats and pedantic checking */
241
3768
class ProofPostprocessFinalCallback : public ProofNodeUpdaterCallback
242
{
243
 public:
244
  ProofPostprocessFinalCallback(ProofNodeManager* pnm);
245
  /**
246
   * Initialize, called once for each new ProofNode to process. This initializes
247
   * static information to be used by successive calls to update.
248
   */
249
  void initializeUpdate();
250
  /** Should proof pn be updated? Returns false, adds to stats. */
251
  bool shouldUpdate(std::shared_ptr<ProofNode> pn,
252
                    const std::vector<Node>& fa,
253
                    bool& continueUpdate) override;
254
  /** was pedantic failure */
255
  bool wasPedanticFailure(std::ostream& out) const;
256
257
 private:
258
  /** Counts number of postprocessed proof nodes for each kind of proof rule */
259
  HistogramStat<PfRule> d_ruleCount;
260
  /**
261
   * Counts number of postprocessed proof nodes of rule INSTANTIATE that were
262
   * marked with the given inference id.
263
   */
264
  HistogramStat<theory::InferenceId> d_instRuleIds;
265
  /** Total number of postprocessed rule applications */
266
  IntStat d_totalRuleCount;
267
  /** The minimum pedantic level of any rule encountered */
268
  IntStat d_minPedanticLevel;
269
  /** The total number of final proofs */
270
  IntStat d_numFinalProofs;
271
  /** Proof node manager (used for pedantic checking) */
272
  ProofNodeManager* d_pnm;
273
  /** Was there a pedantic failure? */
274
  bool d_pedanticFailure;
275
  /** The pedantic failure string for debugging */
276
  std::stringstream d_pedanticFailureOut;
277
};
278
279
/**
280
 * The proof postprocessor module. This postprocesses the final proof
281
 * produced by an SmtEngine. Its main two tasks are to:
282
 * (1) Connect proofs of preprocessing,
283
 * (2) Expand macro PfRule applications.
284
 */
285
class ProofPostproccess
286
{
287
 public:
288
  /**
289
   * @param pnm The proof node manager we are using
290
   * @param smte The SMT engine whose proofs are being post-processed
291
   * @param pppg The proof generator for pre-processing proofs
292
   * @param updateScopedAssumptions Whether we post-process assumptions in
293
   * scope. Since doing so is sound and only problematic depending on who is
294
   * consuming the proof, it's true by default.
295
   */
296
  ProofPostproccess(ProofNodeManager* pnm,
297
                    SmtEngine* smte,
298
                    ProofGenerator* pppg,
299
                    bool updateScopedAssumptions = true);
300
  ~ProofPostproccess();
301
  /** post-process */
302
  void process(std::shared_ptr<ProofNode> pf);
303
  /** set eliminate rule */
304
  void setEliminateRule(PfRule rule);
305
306
 private:
307
  /** The proof node manager */
308
  ProofNodeManager* d_pnm;
309
  /** The post process callback */
310
  ProofPostprocessCallback d_cb;
311
  /**
312
   * The updater, which is responsible for expanding macros in the final proof
313
   * and connecting preprocessed assumptions to input assumptions.
314
   */
315
  ProofNodeUpdater d_updater;
316
  /** The post process callback for finalization */
317
  ProofPostprocessFinalCallback d_finalCb;
318
  /**
319
   * The finalizer, which is responsible for taking stats and checking for
320
   * (lazy) pedantic failures.
321
   */
322
  ProofNodeUpdater d_finalizer;
323
};
324
325
}  // namespace smt
326
}  // namespace cvc5
327
328
#endif