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 |
|
* Rewriter for the theory of inductive quantifiers. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H |
19 |
|
#define CVC5__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H |
20 |
|
|
21 |
|
#include "proof/trust_node.h" |
22 |
|
#include "theory/theory_rewriter.h" |
23 |
|
|
24 |
|
namespace cvc5 { |
25 |
|
namespace theory { |
26 |
|
namespace quantifiers { |
27 |
|
|
28 |
|
struct QAttributes; |
29 |
|
|
30 |
|
/** |
31 |
|
* List of steps used by the quantifiers rewriter, details on these steps |
32 |
|
* can be found in the class below. |
33 |
|
*/ |
34 |
|
enum RewriteStep |
35 |
|
{ |
36 |
|
/** Eliminate symbols (e.g. implies, xor) */ |
37 |
|
COMPUTE_ELIM_SYMBOLS = 0, |
38 |
|
/** Miniscoping */ |
39 |
|
COMPUTE_MINISCOPING, |
40 |
|
/** Aggressive miniscoping */ |
41 |
|
COMPUTE_AGGRESSIVE_MINISCOPING, |
42 |
|
/** Apply the extended rewriter to quantified formula bodies */ |
43 |
|
COMPUTE_EXT_REWRITE, |
44 |
|
/** |
45 |
|
* Term processing (e.g. simplifying terms based on ITE lifting, |
46 |
|
* eliminating extended arithmetic symbols). |
47 |
|
*/ |
48 |
|
COMPUTE_PROCESS_TERMS, |
49 |
|
/** Prenexing */ |
50 |
|
COMPUTE_PRENEX, |
51 |
|
/** Variable elimination */ |
52 |
|
COMPUTE_VAR_ELIMINATION, |
53 |
|
/** Conditional splitting */ |
54 |
|
COMPUTE_COND_SPLIT, |
55 |
|
/** Placeholder for end of steps */ |
56 |
|
COMPUTE_LAST |
57 |
|
}; |
58 |
|
std::ostream& operator<<(std::ostream& out, RewriteStep s); |
59 |
|
|
60 |
19851 |
class QuantifiersRewriter : public TheoryRewriter |
61 |
|
{ |
62 |
|
public: |
63 |
|
static bool isLiteral( Node n ); |
64 |
|
//-------------------------------------variable elimination utilities |
65 |
|
/** is variable elimination |
66 |
|
* |
67 |
|
* Returns true if v is not a subterm of s, and the type of s is a subtype of |
68 |
|
* the type of v. |
69 |
|
*/ |
70 |
|
static bool isVarElim(Node v, Node s); |
71 |
|
/** get variable elimination literal |
72 |
|
* |
73 |
|
* If n asserted with polarity pol in body, and is equivalent to an equality |
74 |
|
* of the form v = s for some v in args, where isVariableElim( v, s ) holds, |
75 |
|
* then this method removes v from args, adds v to vars, adds s to subs, and |
76 |
|
* returns true. Otherwise, it returns false. |
77 |
|
*/ |
78 |
|
static bool getVarElimLit(Node body, |
79 |
|
Node n, |
80 |
|
bool pol, |
81 |
|
std::vector<Node>& args, |
82 |
|
std::vector<Node>& vars, |
83 |
|
std::vector<Node>& subs); |
84 |
|
/** |
85 |
|
* Get variable eliminate for an equality based on theory-specific reasoning. |
86 |
|
*/ |
87 |
|
static Node getVarElimEq(Node lit, const std::vector<Node>& args, Node& var); |
88 |
|
/** variable eliminate for real equalities |
89 |
|
* |
90 |
|
* If this returns a non-null value ret, then var is updated to a member of |
91 |
|
* args, lit is equivalent to ( var = ret ). |
92 |
|
*/ |
93 |
|
static Node getVarElimEqReal(Node lit, |
94 |
|
const std::vector<Node>& args, |
95 |
|
Node& var); |
96 |
|
/** variable eliminate for bit-vector equalities |
97 |
|
* |
98 |
|
* If this returns a non-null value ret, then var is updated to a member of |
99 |
|
* args, lit is equivalent to ( var = ret ). |
100 |
|
*/ |
101 |
|
static Node getVarElimEqBv(Node lit, |
102 |
|
const std::vector<Node>& args, |
103 |
|
Node& var); |
104 |
|
/** variable eliminate for string equalities |
105 |
|
* |
106 |
|
* If this returns a non-null value ret, then var is updated to a member of |
107 |
|
* args, lit is equivalent to ( var = ret ). |
108 |
|
*/ |
109 |
|
static Node getVarElimEqString(Node lit, |
110 |
|
const std::vector<Node>& args, |
111 |
|
Node& var); |
112 |
|
/** get variable elimination |
113 |
|
* |
114 |
|
* If there exists an n with some polarity in body, and entails a literal that |
115 |
|
* corresponds to a variable elimination for some v via the above method |
116 |
|
* getVarElimLit, we return true. In this case, we update args/vars/subs |
117 |
|
* based on eliminating v. |
118 |
|
*/ |
119 |
|
static bool getVarElim(Node body, |
120 |
|
std::vector<Node>& args, |
121 |
|
std::vector<Node>& vars, |
122 |
|
std::vector<Node>& subs); |
123 |
|
/** has variable elimination |
124 |
|
* |
125 |
|
* Returns true if n asserted with polarity pol entails a literal for |
126 |
|
* which variable elimination is possible. |
127 |
|
*/ |
128 |
|
static bool hasVarElim(Node n, bool pol, std::vector<Node>& args); |
129 |
|
/** compute variable elimination inequality |
130 |
|
* |
131 |
|
* This method eliminates variables from the body of quantified formula |
132 |
|
* "body" using (global) reasoning about inequalities. In particular, if there |
133 |
|
* exists a variable x that only occurs in body or annotation qa in literals |
134 |
|
* of the form x>=t with a fixed polarity P, then we may replace all such |
135 |
|
* literals with P. For example, note that: |
136 |
|
* forall xy. x>y OR P(y) is equivalent to forall y. P(y). |
137 |
|
* |
138 |
|
* In the case that a variable x from args can be eliminated in this way, |
139 |
|
* we remove x from args, add x >= t1, ..., x >= tn to bounds, add false, ..., |
140 |
|
* false to subs, and return true. |
141 |
|
*/ |
142 |
|
static bool getVarElimIneq(Node body, |
143 |
|
std::vector<Node>& args, |
144 |
|
std::vector<Node>& bounds, |
145 |
|
std::vector<Node>& subs, |
146 |
|
QAttributes& qa); |
147 |
|
//-------------------------------------end variable elimination utilities |
148 |
|
private: |
149 |
|
/** |
150 |
|
* Helper method for getVarElim, called when n has polarity pol in body. |
151 |
|
*/ |
152 |
|
static bool getVarElimInternal(Node body, |
153 |
|
Node n, |
154 |
|
bool pol, |
155 |
|
std::vector<Node>& args, |
156 |
|
std::vector<Node>& vars, |
157 |
|
std::vector<Node>& subs); |
158 |
|
static int getPurifyIdLit2(Node n, std::map<Node, int>& visited); |
159 |
|
static bool addCheckElimChild(std::vector<Node>& children, |
160 |
|
Node c, |
161 |
|
Kind k, |
162 |
|
std::map<Node, bool>& lit_pol, |
163 |
|
bool& childrenChanged); |
164 |
|
static void addNodeToOrBuilder(Node n, NodeBuilder& t); |
165 |
|
static void computeArgs(const std::vector<Node>& args, |
166 |
|
std::map<Node, bool>& activeMap, |
167 |
|
Node n, |
168 |
|
std::map<Node, bool>& visited); |
169 |
|
static void computeArgVec(const std::vector<Node>& args, |
170 |
|
std::vector<Node>& activeArgs, |
171 |
|
Node n); |
172 |
|
static void computeArgVec2(const std::vector<Node>& args, |
173 |
|
std::vector<Node>& activeArgs, |
174 |
|
Node n, |
175 |
|
Node ipl); |
176 |
|
static Node computeProcessTerms2(Node body, |
177 |
|
std::map<Node, Node>& cache, |
178 |
|
std::vector<Node>& new_vars, |
179 |
|
std::vector<Node>& new_conds); |
180 |
|
static void computeDtTesterIteSplit( |
181 |
|
Node n, |
182 |
|
std::map<Node, Node>& pcons, |
183 |
|
std::map<Node, std::map<int, Node> >& ncons, |
184 |
|
std::vector<Node>& conj); |
185 |
|
|
186 |
|
//-------------------------------------variable elimination |
187 |
|
/** compute variable elimination |
188 |
|
* |
189 |
|
* This computes variable elimination rewrites for a body of a quantified |
190 |
|
* formula with bound variables args. This method updates args to args' and |
191 |
|
* returns a node body' such that (forall args. body) is equivalent to |
192 |
|
* (forall args'. body'). An example of a variable elimination rewrite is: |
193 |
|
* forall xy. x != a V P( x,y ) ---> forall y. P( a, y ) |
194 |
|
*/ |
195 |
|
static Node computeVarElimination(Node body, |
196 |
|
std::vector<Node>& args, |
197 |
|
QAttributes& qa); |
198 |
|
//-------------------------------------end variable elimination |
199 |
|
//-------------------------------------conditional splitting |
200 |
|
/** compute conditional splitting |
201 |
|
* |
202 |
|
* This computes conditional splitting rewrites for a body of a quantified |
203 |
|
* formula with bound variables args. It returns a body' that is equivalent |
204 |
|
* to body. We split body into a conjunction if variable elimination can |
205 |
|
* occur in one of the conjuncts. Examples of this are: |
206 |
|
* ite( x=a, P(x), Q(x) ) ----> ( x!=a V P(x) ) ^ ( x=a V Q(x) ) |
207 |
|
* (x=a) = P(x) ----> ( x!=a V P(x) ) ^ ( x=a V ~P(x) ) |
208 |
|
* ( x!=a ^ P(x) ) V Q(x) ---> ( x!=a V Q(x) ) ^ ( P(x) V Q(x) ) |
209 |
|
* where in each case, x can be eliminated in the first conjunct. |
210 |
|
*/ |
211 |
|
static Node computeCondSplit(Node body, |
212 |
|
const std::vector<Node>& args, |
213 |
|
QAttributes& qa); |
214 |
|
//-------------------------------------end conditional splitting |
215 |
|
//------------------------------------- process terms |
216 |
|
/** compute process terms |
217 |
|
* |
218 |
|
* This takes as input a quantified formula q with attributes qa whose |
219 |
|
* body is body. |
220 |
|
* |
221 |
|
* This rewrite eliminates problematic terms from the bodies of |
222 |
|
* quantified formulas, which includes performing: |
223 |
|
* - Certain cases of ITE lifting, |
224 |
|
* - Elimination of extended arithmetic functions like to_int/is_int/div/mod, |
225 |
|
* - Elimination of select over store. |
226 |
|
* |
227 |
|
* It may introduce new variables V into new_vars and new conditions C into |
228 |
|
* new_conds. It returns a node retBody such that q of the form |
229 |
|
* forall X. body |
230 |
|
* is equivalent to: |
231 |
|
* forall X, V. ( C => retBody ) |
232 |
|
*/ |
233 |
|
static Node computeProcessTerms(Node body, |
234 |
|
std::vector<Node>& new_vars, |
235 |
|
std::vector<Node>& new_conds, |
236 |
|
Node q, |
237 |
|
QAttributes& qa); |
238 |
|
//------------------------------------- end process terms |
239 |
|
//------------------------------------- extended rewrite |
240 |
|
/** compute extended rewrite |
241 |
|
* |
242 |
|
* This returns the result of applying the extended rewriter on the body |
243 |
|
* of quantified formula q. |
244 |
|
*/ |
245 |
|
static Node computeExtendedRewrite(Node q); |
246 |
|
//------------------------------------- end extended rewrite |
247 |
|
public: |
248 |
|
static Node computeElimSymbols( Node body ); |
249 |
|
/** |
250 |
|
* Compute miniscoping in quantified formula q with attributes in qa. |
251 |
|
*/ |
252 |
|
static Node computeMiniscoping(Node q, QAttributes& qa); |
253 |
|
static Node computeAggressiveMiniscoping( std::vector< Node >& args, Node body ); |
254 |
|
/** |
255 |
|
* This function removes top-level quantifiers from subformulas of body |
256 |
|
* appearing with overall polarity pol. It adds quantified variables that |
257 |
|
* appear in positive polarity positions into args, and those at negative |
258 |
|
* polarity positions in nargs. |
259 |
|
* |
260 |
|
* If prenexAgg is true, we ensure that all top-level quantifiers are |
261 |
|
* eliminated from subformulas. This means that we must expand ITE and |
262 |
|
* Boolean equalities to ensure that quantifiers are at fixed polarities. |
263 |
|
* |
264 |
|
* For example, calling this function on: |
265 |
|
* (or (forall ((x Int)) (P x z)) (not (forall ((y Int)) (Q y z)))) |
266 |
|
* would return: |
267 |
|
* (or (P x z) (not (Q y z))) |
268 |
|
* and add {x} to args, and {y} to nargs. |
269 |
|
*/ |
270 |
|
static Node computePrenex(Node q, |
271 |
|
Node body, |
272 |
|
std::unordered_set<Node>& args, |
273 |
|
std::unordered_set<Node>& nargs, |
274 |
|
bool pol, |
275 |
|
bool prenexAgg); |
276 |
|
/** |
277 |
|
* Apply prenexing aggressively. Returns the prenex normal form of n. |
278 |
|
*/ |
279 |
|
static Node computePrenexAgg(Node n, std::map<Node, Node>& visited); |
280 |
|
static Node computeSplit( std::vector< Node >& args, Node body, QAttributes& qa ); |
281 |
|
private: |
282 |
|
static Node computeOperation(Node f, |
283 |
|
RewriteStep computeOption, |
284 |
|
QAttributes& qa); |
285 |
|
|
286 |
|
public: |
287 |
|
RewriteResponse preRewrite(TNode in) override; |
288 |
|
RewriteResponse postRewrite(TNode in) override; |
289 |
|
|
290 |
|
private: |
291 |
|
/** options */ |
292 |
|
static bool doOperation(Node f, RewriteStep computeOption, QAttributes& qa); |
293 |
|
|
294 |
|
private: |
295 |
|
static Node preSkolemizeQuantifiers(Node n, bool polarity, std::vector< TypeNode >& fvTypes, std::vector<TNode>& fvs); |
296 |
|
public: |
297 |
|
static bool isPrenexNormalForm( Node n ); |
298 |
|
/** preprocess |
299 |
|
* |
300 |
|
* This returns the result of applying simple quantifiers-specific |
301 |
|
* preprocessing to n, including but not limited to: |
302 |
|
* - rewrite rule elimination, |
303 |
|
* - pre-skolemization, |
304 |
|
* - aggressive prenexing. |
305 |
|
* The argument isInst is set to true if n is an instance of a previously |
306 |
|
* registered quantified formula. If this flag is true, we do not apply |
307 |
|
* certain steps like pre-skolemization since we know they will have no |
308 |
|
* effect. |
309 |
|
* |
310 |
|
* The result is wrapped in a trust node of kind TrustNodeKind::REWRITE. |
311 |
|
*/ |
312 |
|
static TrustNode preprocess(Node n, bool isInst = false); |
313 |
|
static Node mkForAll(const std::vector<Node>& args, |
314 |
|
Node body, |
315 |
|
QAttributes& qa); |
316 |
|
static Node mkForall(const std::vector<Node>& args, |
317 |
|
Node body, |
318 |
|
bool marked = false); |
319 |
|
static Node mkForall(const std::vector<Node>& args, |
320 |
|
Node body, |
321 |
|
std::vector<Node>& iplc, |
322 |
|
bool marked = false); |
323 |
|
}; /* class QuantifiersRewriter */ |
324 |
|
|
325 |
|
} // namespace quantifiers |
326 |
|
} // namespace theory |
327 |
|
} // namespace cvc5 |
328 |
|
|
329 |
|
#endif /* CVC5__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H */ |