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 |
|
* Proof node manager utility. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__PROOF__PROOF_NODE_MANAGER_H |
19 |
|
#define CVC5__PROOF__PROOF_NODE_MANAGER_H |
20 |
|
|
21 |
|
#include <vector> |
22 |
|
|
23 |
|
#include "expr/node.h" |
24 |
|
#include "proof/proof_rule.h" |
25 |
|
|
26 |
|
namespace cvc5 { |
27 |
|
|
28 |
|
class ProofChecker; |
29 |
|
class ProofNode; |
30 |
|
|
31 |
|
namespace theory { |
32 |
|
class Rewriter; |
33 |
|
} |
34 |
|
|
35 |
|
/** |
36 |
|
* A manager for proof node objects. This is a trusted interface for creating |
37 |
|
* and updating ProofNode objects. |
38 |
|
* |
39 |
|
* In more detail, we say a ProofNode is "well-formed (with respect to checker |
40 |
|
* X)" if its d_proven field is non-null, and corresponds to the formula that |
41 |
|
* the ProofNode proves according to X. The ProofNodeManager class constructs |
42 |
|
* and update nodes that are well-formed with respect to its underlying checker. |
43 |
|
* |
44 |
|
* If no checker is provided, then the ProofNodeManager assigns the d_proven |
45 |
|
* field of ProofNode based on the provided "expected" argument in mkNode below, |
46 |
|
* which must be provided in this case. |
47 |
|
* |
48 |
|
* The ProofNodeManager is used as a trusted way of updating ProofNode objects |
49 |
|
* via updateNode below. In particular, this method leaves the d_proven field |
50 |
|
* unchanged and updates (if possible) the remaining content of a given proof |
51 |
|
* node. |
52 |
|
* |
53 |
|
* Notice that ProofNode objects are mutable, and hence this class does not |
54 |
|
* cache the results of mkNode. A version of this class that caches |
55 |
|
* immutable version of ProofNode objects could be built as an extension |
56 |
|
* or layer on top of this class. |
57 |
|
*/ |
58 |
|
class ProofNodeManager |
59 |
|
{ |
60 |
|
public: |
61 |
|
ProofNodeManager(theory::Rewriter* rr, ProofChecker* pc = nullptr); |
62 |
7989 |
~ProofNodeManager() {} |
63 |
|
/** |
64 |
|
* This constructs a ProofNode with the given arguments. The expected |
65 |
|
* argument, when provided, indicates the formula that the returned node |
66 |
|
* is expected to prove. If we find that it does not, based on the underlying |
67 |
|
* checker, this method returns nullptr. |
68 |
|
* |
69 |
|
* @param id The id of the proof node. |
70 |
|
* @param children The children of the proof node. |
71 |
|
* @param args The arguments of the proof node. |
72 |
|
* @param expected (Optional) the expected conclusion of the proof node. |
73 |
|
* @return the proof node, or nullptr if the given arguments do not |
74 |
|
* consistute a proof of the expected conclusion according to the underlying |
75 |
|
* checker, if both are provided. It also returns nullptr if neither the |
76 |
|
* checker nor the expected field is provided, since in this case the |
77 |
|
* conclusion is unknown. |
78 |
|
*/ |
79 |
|
std::shared_ptr<ProofNode> mkNode( |
80 |
|
PfRule id, |
81 |
|
const std::vector<std::shared_ptr<ProofNode>>& children, |
82 |
|
const std::vector<Node>& args, |
83 |
|
Node expected = Node::null()); |
84 |
|
/** |
85 |
|
* Make the proof node corresponding to the assumption of fact. |
86 |
|
* |
87 |
|
* @param fact The fact to assume. |
88 |
|
* @return The ASSUME proof of fact. |
89 |
|
*/ |
90 |
|
std::shared_ptr<ProofNode> mkAssume(Node fact); |
91 |
|
/** |
92 |
|
* Make symm, which accounts for whether the child is already a SYMM |
93 |
|
* node, in which case we return its child. |
94 |
|
*/ |
95 |
|
std::shared_ptr<ProofNode> mkSymm(std::shared_ptr<ProofNode> child, |
96 |
|
Node expected = Node::null()); |
97 |
|
/** |
98 |
|
* Make transitivity proof, where children contains one or more proofs of |
99 |
|
* equalities that form an ordered chain. In other words, the vector children |
100 |
|
* is a legal set of children for an application of TRANS. |
101 |
|
*/ |
102 |
|
std::shared_ptr<ProofNode> mkTrans( |
103 |
|
const std::vector<std::shared_ptr<ProofNode>>& children, |
104 |
|
Node expected = Node::null()); |
105 |
|
|
106 |
|
/** |
107 |
|
* Make scope having body pf and arguments (assumptions-to-close) assumps. |
108 |
|
* If ensureClosed is true, then this method throws an assertion failure if |
109 |
|
* the returned proof is not closed. This is the case if a free assumption |
110 |
|
* of pf is missing from the vector assumps. |
111 |
|
* |
112 |
|
* For conveinence, the proof pf may be modified to ensure that the overall |
113 |
|
* result is closed. For instance, given input: |
114 |
|
* pf = TRANS( ASSUME( x=y ), ASSUME( y=z ) ) |
115 |
|
* assumps = { y=x, y=z } |
116 |
|
* This method will modify pf to be: |
117 |
|
* pf = TRANS( SYMM( ASSUME( y=x ) ), ASSUME( y=z ) ) |
118 |
|
* so that y=x matches the free assumption. The returned proof is: |
119 |
|
* SCOPE(TRANS( SYMM( ASSUME( y=x ) ), ASSUME( y=z ) ) :args { y=x, y=z }) |
120 |
|
* |
121 |
|
* When ensureClosed is true, duplicates are eliminated from assumps. The |
122 |
|
* reason for this is due to performance, since in this method, assumps is |
123 |
|
* converted to an unordered_set to do the above check and hence it is a |
124 |
|
* convienient time to eliminate duplicate literals. |
125 |
|
* |
126 |
|
* Additionally, if both ensureClosed and doMinimize are true, assumps is |
127 |
|
* updated to contain exactly the free asumptions of pf. This also includes |
128 |
|
* having no duplicates. Furthermore, if assumps is empty after minimization, |
129 |
|
* this method is a no-op. |
130 |
|
* |
131 |
|
* In each case, the update vector assumps is passed as arguments to SCOPE. |
132 |
|
* |
133 |
|
* @param pf The body of the proof, |
134 |
|
* @param assumps The assumptions-to-close of the scope, |
135 |
|
* @param ensureClosed Whether to ensure that the proof is closed, |
136 |
|
* @param doMinimize Whether to minimize assumptions. |
137 |
|
* @param expected the node that the scope should prove. |
138 |
|
* @return The scoped proof. |
139 |
|
*/ |
140 |
|
std::shared_ptr<ProofNode> mkScope(std::shared_ptr<ProofNode> pf, |
141 |
|
std::vector<Node>& assumps, |
142 |
|
bool ensureClosed = true, |
143 |
|
bool doMinimize = false, |
144 |
|
Node expected = Node::null()); |
145 |
|
/** |
146 |
|
* This method updates pn to be a proof of the form <id>( children, args ), |
147 |
|
* while maintaining its d_proven field. This method returns false if this |
148 |
|
* proof manager is using a checker, and we compute that the above proof |
149 |
|
* is not a proof of the fact that pn previously proved. |
150 |
|
* |
151 |
|
* @param pn The proof node to update. |
152 |
|
* @param id The updated id of the proof node. |
153 |
|
* @param children The updated children of the proof node. |
154 |
|
* @param args The updated arguments of the proof node. |
155 |
|
* @return true if the update was successful. |
156 |
|
* |
157 |
|
* Notice that updateNode always returns true if there is no underlying |
158 |
|
* checker. |
159 |
|
*/ |
160 |
|
bool updateNode(ProofNode* pn, |
161 |
|
PfRule id, |
162 |
|
const std::vector<std::shared_ptr<ProofNode>>& children, |
163 |
|
const std::vector<Node>& args); |
164 |
|
/** |
165 |
|
* Update node pn to have the contents of pnr. It should be the case that |
166 |
|
* pn and pnr prove the same fact, otherwise false is returned and pn is |
167 |
|
* unchanged. |
168 |
|
*/ |
169 |
|
bool updateNode(ProofNode* pn, ProofNode* pnr); |
170 |
|
/** |
171 |
|
* Ensure that pn is checked, regardless of the proof check format. |
172 |
|
*/ |
173 |
|
void ensureChecked(ProofNode* pn); |
174 |
|
/** Get the underlying proof checker */ |
175 |
|
ProofChecker* getChecker() const; |
176 |
|
/** |
177 |
|
* Clone a proof node, which creates a deep copy of pn and returns it. The |
178 |
|
* dag structure of pn is the same as that in the returned proof node. |
179 |
|
* |
180 |
|
* @param pn The proof node to clone |
181 |
|
* @return the cloned proof node. |
182 |
|
*/ |
183 |
|
std::shared_ptr<ProofNode> clone(std::shared_ptr<ProofNode> pn) const; |
184 |
|
/** |
185 |
|
* Cancel double SYMM. Returns a proof node that is not a double application |
186 |
|
* of SYMM, e.g. for (SYMM (SYMM (r P))), this returns (r P) where r != SYMM. |
187 |
|
*/ |
188 |
|
static ProofNode* cancelDoubleSymm(ProofNode* pn); |
189 |
|
|
190 |
|
private: |
191 |
|
/** The rewriter */ |
192 |
|
theory::Rewriter* d_rewriter; |
193 |
|
/** The (optional) proof checker */ |
194 |
|
ProofChecker* d_checker; |
195 |
|
/** the true node */ |
196 |
|
Node d_true; |
197 |
|
/** Check internal |
198 |
|
* |
199 |
|
* This returns the result of proof checking a ProofNode with the provided |
200 |
|
* arguments with an expected conclusion, which may not null if there is |
201 |
|
* no expected conclusion. |
202 |
|
* |
203 |
|
* This throws an assertion error if we fail to check such a proof node, or |
204 |
|
* if expected is provided (non-null) and is different what is proven by the |
205 |
|
* other arguments. |
206 |
|
* |
207 |
|
* The flag didCheck is set to true if the underlying proof checker was |
208 |
|
* invoked. This may be false if e.g. the proof checking mode is lazy. |
209 |
|
*/ |
210 |
|
Node checkInternal(PfRule id, |
211 |
|
const std::vector<std::shared_ptr<ProofNode>>& children, |
212 |
|
const std::vector<Node>& args, |
213 |
|
Node expected, |
214 |
|
bool& didCheck); |
215 |
|
/** |
216 |
|
* Update node internal, return true if successful. This is called by |
217 |
|
* the update node methods above. The argument needsCheck is whether we |
218 |
|
* need to check the correctness of the rule application. This is false |
219 |
|
* for the updateNode routine where pnr is an (already checked) proof node. |
220 |
|
*/ |
221 |
|
bool updateNodeInternal( |
222 |
|
ProofNode* pn, |
223 |
|
PfRule id, |
224 |
|
const std::vector<std::shared_ptr<ProofNode>>& children, |
225 |
|
const std::vector<Node>& args, |
226 |
|
bool needsCheck); |
227 |
|
}; |
228 |
|
|
229 |
|
} // namespace cvc5 |
230 |
|
|
231 |
|
#endif /* CVC5__PROOF__PROOF_NODE_H */ |