Branch data Line data Source code
1 : : /******************************************************************************
2 : : * This file is part of the cvc5 project.
3 : : *
4 : : * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
5 : : * in the top-level source directory and their institutional affiliations.
6 : : * All rights reserved. See the file COPYING in the top-level source
7 : : * directory for licensing information.
8 : : * ****************************************************************************
9 : : *
10 : : * A proof as produced by the equality engine.
11 : : */
12 : :
13 : : #include "cvc5_private.h"
14 : : #include "expr/node.h"
15 : : #include "theory/uf/equality_engine_types.h"
16 : :
17 : : namespace cvc5::internal {
18 : :
19 : : class CDProof;
20 : :
21 : : namespace theory {
22 : : namespace eq {
23 : :
24 : : /**
25 : : * An equality proof.
26 : : *
27 : : * This represents the reasoning performed by the Equality Engine to derive
28 : : * facts, represented in terms of the rules in MergeReasonType. Each proof step
29 : : * is annotated with the rule id, the conclusion node and a vector of proofs of
30 : : * the rule's premises.
31 : : **/
32 : : class EqProof
33 : : {
34 : : public:
35 : 9713548 : EqProof() : d_id(MERGED_THROUGH_REFLEXIVITY) {}
36 : : /** The proof rule for concluding d_node */
37 : : MergeReasonType d_id;
38 : : /** The conclusion of this EqProof */
39 : : Node d_node;
40 : : /** The proofs of the premises for deriving d_node with d_id */
41 : : std::vector<std::shared_ptr<EqProof>> d_children;
42 : : /**
43 : : * Debug print this proof on debug trace c with tabulation tb.
44 : : */
45 : : void debug_print(const char* c, unsigned tb = 0) const;
46 : : /**
47 : : * Debug print this proof on output stream os with tabulation tb.
48 : : */
49 : : void debug_print(std::ostream& os, unsigned tb = 0) const;
50 : :
51 : : /** Add to proof
52 : : *
53 : : * Converts EqProof into ProofNode via a series of steps to be stored in
54 : : * CDProof* p.
55 : : *
56 : : * This method can be seen as a best-effort solution until the EqualityEngine
57 : : * is updated to produce ProofNodes directly, if ever. Note that since the
58 : : * original EqProof steps can be coarse-grained (e.g. without proper order,
59 : : * implicit inferences related to disequelaties) and are phrased over curried
60 : : * terms, the transformation requires significant, although cheap (mostly
61 : : * linear on the DAG-size of EqProof), post-processing.
62 : : *
63 : : * An important invariant of the resulting ProofNode is that neither its
64 : : * assumptions nor its conclusion are predicate equalities, i.e. of the form
65 : : * (= t true/false), modulo symmetry. This is so that users of the converted
66 : : * ProofNode don't need to do case analysis on whether assumptions/conclusion
67 : : * are either t or (= t true/false).
68 : : *
69 : : * @param p a pointer to a CDProof to store the conversion of this EqProof
70 : : * @return the node that is the conclusion of the proof as added to p.
71 : : */
72 : : Node addToProof(CDProof* p) const;
73 : :
74 : : private:
75 : : /**
76 : : * As above, but with a cache of previously processed nodes and their results
77 : : * (for DAG traversal). The caching is in terms of the original conclusions of
78 : : * EqProof.
79 : : *
80 : : * @param p a pointer to a CDProof to store the conversion of this EqProof
81 : : * @param visited a cache of the original EqProof conclusions and the
82 : : * resulting conclusion after conversion.
83 : : * @param assumptions the assumptions of the original EqProof (and their
84 : : * variations in terms of symmetry and conversion to/from predicate
85 : : * equalities)
86 : : * @return the node that is the conclusion of the proof as added to p.
87 : : */
88 : : Node addToProof(CDProof* p,
89 : : std::unordered_map<Node, Node>& visited,
90 : : std::unordered_set<Node>& assumptions) const;
91 : :
92 : : /** Removes all reflexivity steps, i.e. (= t t), from premises. */
93 : : void cleanReflPremises(std::vector<Node>& premises) const;
94 : :
95 : : /** Expand coarse-grained transitivity steps for disequalities
96 : : *
97 : : * Currently the equality engine can represent disequality reasoning in a
98 : : * rather coarse-grained manner with EqProof. This is always the case when the
99 : : * transitivity step contains a disequality, (= (= t t') false) or its
100 : : * symmetric, as a premise.
101 : : *
102 : : * There are two cases. In the simplest one the general shape of the EqProof
103 : : * is
104 : : * (= t1 t2) (= t3 t2) (= (t1 t3) false)
105 : : * ------------------------------------- EQP::TR
106 : : * false = true
107 : : *
108 : : * which is expanded into
109 : : * (= t3 t2)
110 : : * --------- SYMM
111 : : * (= t1 t2) (= t2 t3)
112 : : * ------------------- TRANS
113 : : * (= (= t1 t3) false) (= t1 t3)
114 : : * --------------------- SYMM ------------------ TRUE_INTRO
115 : : * (= false (= t1 t3)) (= (= t1 t3) true)
116 : : * ----------------------------------------------- TRANS
117 : : * false = true
118 : : *
119 : : * by explicitly adding the transitivity step for inferring (= t1 t3) and its
120 : : * predicate equality. Note that we differentiate (from now on) the EqProof
121 : : * rules ids from those of ProofRule by adding the prefix EQP:: to the former.
122 : : *
123 : : * In the other case, the general shape of the EqProof is
124 : : *
125 : : * (= (= t1 t2) false) (= t1 x1) ... (= xn t3) (= t2 y1) ... (= ym t4)
126 : : * ------------------------------------------------------------------- EQP::TR
127 : : * (= (= t4 t3) false)
128 : : *
129 : : * which is converted into
130 : : *
131 : : * (= t1 x1) ... (= xn t3) (= t2 y1) ... (= ym t4)
132 : : * ------------------------ TR ------------------------ TR
133 : : * (= t1 t3) (= t2 t4)
134 : : * ----------- SYMM ----------- SYMM
135 : : * (= t3 t1) (= t4 t2)
136 : : * ---------------------------------------- CONG
137 : : * (= (= t3 t4) (= t1 t2)) (= (= t1 t2) false)
138 : : * --------------------------------------------------------------------- TR
139 : : * (= (= t3 t4) false)
140 : : * --------------------- MACRO_SR_PRED_TRANSFORM
141 : : * (= (= t4 t3) false)
142 : : *
143 : : * whereas the last step is only necessary if the conclusion has the arguments
144 : : * in reverse order than expected. Note that the original step represents two
145 : : * substitutions happening on the disequality, from t1->t3 and t2->t4, which
146 : : * are implicitly justified by transitivity steps that need to be made
147 : : * explicity. Since there is no sense of ordering among which premisis (other
148 : : * than (= (= t1 t2) false)) are used for which substitution, the transitivity
149 : : * proofs are built greedly by searching the sets of premises.
150 : : *
151 : : * If in either of the above cases then the conclusion is directly derived
152 : : * in the call, so only in the other cases we try to build a transitivity
153 : : * step below
154 : : *
155 : : * @param conclusion the conclusion of the (possibly) coarse-grained
156 : : * transitivity step
157 : : * @param premises the premises of the (possibly) coarse-grained
158 : : * transitivity step
159 : : * @param p a pointer to a CDProof to store the conversion of this EqProof
160 : : * @param assumptions the assumptions (and variants) of the original
161 : : * EqProof. These are necessary to avoid cyclic proofs, which could be
162 : : * generated by creating transitivity steps for assumptions (which depend on
163 : : * themselves).
164 : : * @return True if the EqProof transitivity step is in either of the above
165 : : * cases, symbolizing that the ProofNode justifying the conclusion has already
166 : : * been produced.
167 : : */
168 : : bool expandTransitivityForDisequalities(
169 : : Node conclusion,
170 : : std::vector<Node>& premises,
171 : : CDProof* p,
172 : : std::unordered_set<Node>& assumptions) const;
173 : :
174 : : /** Expand coarse-grained transitivity steps for theory disequalities
175 : : *
176 : : * Currently the equality engine can represent disequality reasoning of theory
177 : : * symbols in a rather coarse-grained manner with EqProof. This is the case
178 : : * when EqProof is
179 : : * (= t1 c1) (= t2 c2)
180 : : * ------------------------------------- EQP::TR
181 : : * (= (t1 t2) false)
182 : : *
183 : : * which is converted into
184 : : *
185 : : * (= t1 c1) (= t2 c2)
186 : : * -------------------------- CONG --------------------- MACRO_SR_PRED_INTRO
187 : : * (= (= t1 t2) (= c1 t2)) (= (= c1 c2) false)
188 : : * --------------------------------------------------------- TR
189 : : * (= (= t1 t2) false)
190 : : *
191 : : * @param conclusion the conclusion of the (possibly) coarse-grained
192 : : * transitivity step
193 : : * @param premises the premises of the (possibly) coarse-grained
194 : : * transitivity step
195 : : * @param p a pointer to a CDProof to store the conversion of this EqProof
196 : : * @return True if the EqProof transitivity step is the above case,
197 : : * indicating that the ProofNode justifying the conclusion has already been
198 : : * produced.
199 : : */
200 : : bool expandTransitivityForTheoryDisequalities(Node conclusion,
201 : : std::vector<Node>& premises,
202 : : CDProof* p) const;
203 : :
204 : : /** Builds a transitivity chain from equalities to derive a conclusion
205 : : *
206 : : * Given an equality (= t1 tn), and a list of equalities premises, attempts to
207 : : * build a chain (= t1 t2) ... (= tn-1 tn) from premises. This is done in a
208 : : * greedy manner by finding one "link" in the chain at a time, updating the
209 : : * conclusion to be the next link and the premises by removing the used
210 : : * premise, and searching recursively.
211 : : *
212 : : * Consider for example
213 : : * - conclusion: (= t1 t4)
214 : : * - premises: (= t4 t2), (= t2 t3), (= t2 t1), (= t3 t4)
215 : : *
216 : : * It proceeds by searching for t1 in an equality in the premises, in order,
217 : : * which is found in the equality (= t2 t1). Since t2 != t4, it attempts to
218 : : * build a chain with
219 : : * - conclusion (= t2 t4)
220 : : * - premises (= t4 t2), (= t2 t3), (= t3 t4)
221 : : *
222 : : * In the first equality it finds t2 and also t4, which closes the chain, so
223 : : * that premises is updated to (= t2 t4) and the method returns true. Since
224 : : * the recursive call was successful, the original conclusion (= t1 t4) is
225 : : * justified with (= t1 t2) plus the chain built in the recursive call,
226 : : * i.e. (= t1 t2), (= t2 t4).
227 : : *
228 : : * Note that not all the premises were necessary to build a successful
229 : : * chain. Moreover, note that building a successful chain can depend on the
230 : : * order in which the equalities are chosen. When a recursive call fails to
231 : : * close a chain, the chosen equality is dismissed and another is searched for
232 : : * among the remaining ones.
233 : : *
234 : : * This method assumes that premises does not contain reflexivity premises.
235 : : * This is without loss of generality since such premises are spurious for a
236 : : * transitivity step.
237 : : *
238 : : * @param conclusion the conclusion of the transitivity chain of equalities
239 : : * @param premises the list of equalities to build a chain with
240 : : * @return whether premises successfully build a transitivity chain for the
241 : : * conclusion
242 : : */
243 : : bool buildTransitivityChain(Node conclusion,
244 : : std::vector<Node>& premises) const;
245 : :
246 : : /** Reduce a congruence EqProof into a transitivity matrix
247 : : *
248 : : * Given a congruence EqProof of (= (f a0 ... an-1) (f b0 ... bn-1)), reduce
249 : : * its justification into a matrix
250 : : *
251 : : * [0] -> p_{0,0} ... p_{m_0,0}
252 : : * ...
253 : : * [n-1] -> p_{0,n} ... p_{m_n-1,n-1}
254 : : *
255 : : * where f has arity n and each p_{0,i} ... p_{m_i, i} is a transitivity chain
256 : : * (modulo ordering) justifying (= ai bi).
257 : : *
258 : : * Congruence steps in EqProof are binary, representing reasoning over curried
259 : : * applications. In the simplest case the general shape of a congruence
260 : : * EqProof is:
261 : : * P0
262 : : * ------- EQP::REFL ----------
263 : : * P1 [] (= a0 b0)
264 : : * --------- ----------------------- EQP::CONG
265 : : * (= a1 b1) [] P2
266 : : * ------------------------- EQP::CONG -----------
267 : : * [] (= a2 b2)
268 : : * ------------------------------------------------ EQP::CONG
269 : : * (= (f a0 a1 a2) (f b0 b1 b2))
270 : : *
271 : : * where [] stands for the null node, symbolizing "equality between partial
272 : : * applications".
273 : : *
274 : : * The reduction of such a proof is done by
275 : : * - converting the proof of the second CONG premise (via addToProof) and
276 : : * adding the resulting node to row i of the matrix
277 : : * - recursively reducing the first proof with i-1
278 : : *
279 : : * In the above case the transitivity matrix would thus be
280 : : * [0] -> (= a0 b0)
281 : : * [1] -> (= a1 b1)
282 : : * [2] -> (= a2 b2)
283 : : *
284 : : * The more complex case of congruence proofs has transitivity steps as the
285 : : * first child of CONG steps. For example
286 : : * P0
287 : : * ------- EQP::REFL ----------
288 : : * P' [] (= a0 c)
289 : : * --------- ----------------------------- EQP::CONG
290 : : * (= b0 c) [] P1
291 : : * ------------------------- EQP::TRANS -----------
292 : : * [] (= a1 b1)
293 : : * ----------------------------------------------------- EQP::CONG
294 : : * (= (f a0 a1) (f b0 b1))
295 : : *
296 : : * where when the first child of CONG is a transitivity step
297 : : * - the premises that are CONG steps are recursively reduced with *the same*
298 : : * argument i
299 : : * - the other premises are processed with addToProof and added to the i row
300 : : * in the matrix
301 : : *
302 : : * In the above example the corresponding transitivity matrix is
303 : : * [0] -> (= a0 c), (= b0 c)
304 : : * [1] -> (= a1 b1)
305 : : *
306 : : * The remaining complication is when the conclusion is an equality of n-ary
307 : : * applications of *different* arities. Then there necessarily is a
308 : : * transitivity step as a first child a CONG step whose conclusion is an
309 : : * equality of n-ary applications of different arities. For example
310 : : *
311 : : * P0 P1
312 : : * -------------------------- EQP::TRANS -----------
313 : : * (= (f a0 a1) (f b0)) (= a2 b1)
314 : : * -------------------------------------------------- EQP::CONG
315 : : * (= (f a0 a1 a2) (f b0 b1))
316 : : *
317 : : * will be first reduced with i = 2 (maximal arity among the original
318 : : * conclusion's applications), adding (= a2 b1) to row 2 after processing
319 : : * P1. The first child is reduced with i = 1. Since it is a TRANS step whose
320 : : * conclusion is an equality of n-ary applications with mismatching arity, P0
321 : : * is processed with addToProof and the result is added to row 1. Thus the
322 : : * transitivity matrix is
323 : : * [0] ->
324 : : * [1] -> (= (f a0 a1) (f b0))
325 : : * [2] -> (= a2 b1)
326 : : *
327 : : * The empty row 0 is used by the original caller of reduceNestedCongruence to
328 : : * compute that the above congruence proof's conclusion is
329 : : * (= (f (f a0 a1) a2) (f (f b0) b1))
330 : : *
331 : : * @param i the i-th argument of the congruent applications, initially being
332 : : * the maximal arity among conclusion's applications.
333 : : * @param conclusion the original congruence conclusion
334 : : * @param transitivityMatrix a matrix of equalities with each row justifying
335 : : * an equality between the congruent applications
336 : : * @param p a pointer to a CDProof to store the conversion of this EqProof
337 : : * @param visited a cache of the original EqProof conclusions and the
338 : : * resulting conclusion after conversion.
339 : : * @param assumptions the assumptions (and variants) of the original EqProof
340 : : * @param isNary whether conclusion is an equality of n-ary applications
341 : : */
342 : : void reduceNestedCongruence(
343 : : unsigned i,
344 : : Node conclusion,
345 : : std::vector<std::vector<Node>>& transitivityMatrix,
346 : : CDProof* p,
347 : : std::unordered_map<Node, Node>& visited,
348 : : std::unordered_set<Node>& assumptions,
349 : : bool isNary) const;
350 : :
351 : : }; /* class EqProof */
352 : :
353 : : } // Namespace eq
354 : : } // Namespace theory
355 : : } // namespace cvc5::internal
|