Branch data Line data Source code
1 : : /******************************************************************************
2 : : * Top contributors (to current version):
3 : : * Andrew Reynolds, Aina Niemetz, Morgan Deters
4 : : *
5 : : * This file is part of the cvc5 project.
6 : : *
7 : : * Copyright (c) 2009-2024 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 : : * Implementation of QuantifiersRewriter class.
14 : : */
15 : :
16 : : #include "theory/quantifiers/quantifiers_rewriter.h"
17 : :
18 : : #include "expr/ascription_type.h"
19 : : #include "expr/bound_var_manager.h"
20 : : #include "expr/dtype.h"
21 : : #include "expr/dtype_cons.h"
22 : : #include "expr/elim_shadow_converter.h"
23 : : #include "expr/node_algorithm.h"
24 : : #include "expr/skolem_manager.h"
25 : : #include "options/quantifiers_options.h"
26 : : #include "theory/arith/arith_msum.h"
27 : : #include "theory/booleans/theory_bool_rewriter.h"
28 : : #include "theory/datatypes/theory_datatypes_utils.h"
29 : : #include "theory/quantifiers/bv_inverter.h"
30 : : #include "theory/quantifiers/ematching/trigger.h"
31 : : #include "theory/quantifiers/extended_rewrite.h"
32 : : #include "theory/quantifiers/quantifiers_attributes.h"
33 : : #include "theory/quantifiers/skolemize.h"
34 : : #include "theory/quantifiers/term_database.h"
35 : : #include "theory/quantifiers/term_util.h"
36 : : #include "theory/rewriter.h"
37 : : #include "theory/strings/theory_strings_utils.h"
38 : : #include "theory/uf/theory_uf_rewriter.h"
39 : : #include "util/rational.h"
40 : :
41 : : using namespace std;
42 : : using namespace cvc5::internal::kind;
43 : : using namespace cvc5::context;
44 : :
45 : : namespace cvc5::internal {
46 : : namespace theory {
47 : : namespace quantifiers {
48 : :
49 : : /**
50 : : * Attributes used for constructing bound variables in a canonical way. These
51 : : * are attributes that map to bound variable, introduced for the following
52 : : * purposes:
53 : : * - QRewPrenexAttribute: cached on (v, body) where we are prenexing bound
54 : : * variable v in a nested quantified formula within the given body.
55 : : * - QRewMiniscopeAttribute: cached on (v, q, i) where q is being miniscoped
56 : : * for F_i in its body (and F_1 ... F_n), and v is one of the bound variables
57 : : * that q binds.
58 : : * - QRewDtExpandAttribute: cached on (F, lit, a) where lit is the tested
59 : : * literal used for expanding a quantified datatype variable in quantified
60 : : * formula with body F, and a is the rational corresponding to the argument
61 : : * position of the variable, e.g. lit is ((_ is C) x) and x is
62 : : * replaced by (C y1 ... yn), where the argument position of yi is i.
63 : : */
64 : : struct QRewPrenexAttributeId
65 : : {
66 : : };
67 : : using QRewPrenexAttribute = expr::Attribute<QRewPrenexAttributeId, Node>;
68 : : struct QRewMiniscopeAttributeId
69 : : {
70 : : };
71 : : using QRewMiniscopeAttribute = expr::Attribute<QRewMiniscopeAttributeId, Node>;
72 : : struct QRewDtExpandAttributeId
73 : : {
74 : : };
75 : : using QRewDtExpandAttribute = expr::Attribute<QRewDtExpandAttributeId, Node>;
76 : :
77 : 0 : std::ostream& operator<<(std::ostream& out, RewriteStep s)
78 : : {
79 [ - - ][ - - ]: 0 : switch (s)
[ - - ][ - - ]
[ - ]
80 : : {
81 : 0 : case COMPUTE_ELIM_SYMBOLS: out << "COMPUTE_ELIM_SYMBOLS"; break;
82 : 0 : case COMPUTE_MINISCOPING: out << "COMPUTE_MINISCOPING"; break;
83 : 0 : case COMPUTE_AGGRESSIVE_MINISCOPING:
84 : 0 : out << "COMPUTE_AGGRESSIVE_MINISCOPING";
85 : 0 : break;
86 : 0 : case COMPUTE_PROCESS_TERMS: out << "COMPUTE_PROCESS_TERMS"; break;
87 : 0 : case COMPUTE_PRENEX: out << "COMPUTE_PRENEX"; break;
88 : 0 : case COMPUTE_VAR_ELIMINATION: out << "COMPUTE_VAR_ELIMINATION"; break;
89 : 0 : case COMPUTE_COND_SPLIT: out << "COMPUTE_COND_SPLIT"; break;
90 : 0 : case COMPUTE_EXT_REWRITE: out << "COMPUTE_EXT_REWRITE"; break;
91 : 0 : default: out << "UnknownRewriteStep"; break;
92 : : }
93 : 0 : return out;
94 : : }
95 : :
96 : 131308 : QuantifiersRewriter::QuantifiersRewriter(NodeManager* nm,
97 : : Rewriter* r,
98 : 131308 : const Options& opts)
99 : 131308 : : TheoryRewriter(nm), d_rewriter(r), d_opts(opts)
100 : : {
101 : 131308 : registerProofRewriteRule(ProofRewriteRule::EXISTS_ELIM,
102 : : TheoryRewriteCtx::PRE_DSL);
103 : 131308 : registerProofRewriteRule(ProofRewriteRule::QUANT_UNUSED_VARS,
104 : : TheoryRewriteCtx::PRE_DSL);
105 : 131308 : registerProofRewriteRule(ProofRewriteRule::QUANT_MERGE_PRENEX,
106 : : TheoryRewriteCtx::PRE_DSL);
107 : 131308 : registerProofRewriteRule(ProofRewriteRule::QUANT_MINISCOPE,
108 : : TheoryRewriteCtx::PRE_DSL);
109 : 131308 : registerProofRewriteRule(ProofRewriteRule::MACRO_QUANT_PARTITION_CONNECTED_FV,
110 : : TheoryRewriteCtx::PRE_DSL);
111 : 131308 : registerProofRewriteRule(ProofRewriteRule::MACRO_QUANT_VAR_ELIM_EQ,
112 : : TheoryRewriteCtx::PRE_DSL);
113 : 131308 : registerProofRewriteRule(ProofRewriteRule::MACRO_QUANT_VAR_ELIM_INEQ,
114 : : TheoryRewriteCtx::PRE_DSL);
115 : 131308 : }
116 : :
117 : 7625 : Node QuantifiersRewriter::rewriteViaRule(ProofRewriteRule id, const Node& n)
118 : : {
119 [ + + ][ + + ]: 7625 : switch (id)
[ + + ][ + - ]
120 : : {
121 : 2020 : case ProofRewriteRule::EXISTS_ELIM:
122 : : {
123 [ + + ]: 2020 : if (n.getKind() != Kind::EXISTS)
124 : : {
125 : 1029 : return Node::null();
126 : : }
127 : 991 : std::vector<Node> fchildren;
128 : 991 : fchildren.push_back(n[0]);
129 : 991 : fchildren.push_back(n[1].notNode());
130 [ + + ]: 991 : if (n.getNumChildren() == 3)
131 : : {
132 : 5 : fchildren.push_back(n[2]);
133 : : }
134 : 991 : return d_nm->mkNode(Kind::NOT, d_nm->mkNode(Kind::FORALL, fchildren));
135 : : }
136 : 1307 : case ProofRewriteRule::QUANT_UNUSED_VARS:
137 : : {
138 [ - + ]: 1307 : if (!n.isClosure())
139 : : {
140 : 443 : return Node::null();
141 : : }
142 : 2614 : std::vector<Node> vars(n[0].begin(), n[0].end());
143 : 1307 : std::vector<Node> activeVars;
144 : 1307 : computeArgVec(vars, activeVars, n[1]);
145 [ + + ]: 1307 : if (activeVars.size() < vars.size())
146 : : {
147 [ + + ]: 443 : if (activeVars.empty())
148 : : {
149 : 320 : return n[1];
150 : : }
151 : 123 : return d_nm->mkNode(
152 : 123 : n.getKind(), d_nm->mkNode(Kind::BOUND_VAR_LIST, activeVars), n[1]);
153 : : }
154 : : }
155 : 864 : break;
156 : 1114 : case ProofRewriteRule::QUANT_MERGE_PRENEX:
157 : : {
158 [ - + ]: 1114 : if (!n.isClosure())
159 : : {
160 : 322 : return Node::null();
161 : : }
162 : : // Don't check standard here, which can't be replicated in a proof checker
163 : : // without modelling the patterns.
164 : 1114 : Node q = mergePrenex(n, false);
165 [ + + ]: 1114 : if (q != n)
166 : : {
167 : 322 : return q;
168 : : }
169 : : }
170 : 792 : break;
171 : 961 : case ProofRewriteRule::QUANT_MINISCOPE:
172 : : {
173 [ + - ][ + + ]: 961 : if (n.getKind() != Kind::FORALL || n[1].getKind() != Kind::AND)
[ + - ][ + + ]
[ - - ]
174 : : {
175 : 682 : return Node::null();
176 : : }
177 : : // note that qa is not needed; moreover external proofs should be agnostic
178 : : // to it
179 : 558 : QAttributes qa;
180 : 279 : QuantAttributes::computeQuantAttributes(n, qa);
181 : 558 : Node nret = computeMiniscoping(n, qa, true, false);
182 [ - + ][ - + ]: 279 : Assert(nret != n);
[ - - ]
183 : 279 : return nret;
184 : : }
185 : : break;
186 : 819 : case ProofRewriteRule::MACRO_QUANT_PARTITION_CONNECTED_FV:
187 : : {
188 [ + - ][ + + ]: 819 : if (n.getKind() != Kind::FORALL || n[1].getKind() != Kind::OR)
[ + - ][ + + ]
[ - - ]
189 : : {
190 : 698 : return Node::null();
191 : : }
192 : : // note that qa is not needed; moreover external proofs should be agnostic
193 : : // to it
194 : 607 : QAttributes qa;
195 : 607 : QuantAttributes::computeQuantAttributes(n, qa);
196 : 1214 : std::vector<Node> vars(n[0].begin(), n[0].end());
197 : 607 : Node body = n[1];
198 : 607 : Node nret = computeSplit(vars, body, qa);
199 [ + + ]: 607 : if (!nret.isNull())
200 : : {
201 : : // only do this rule if it is a proper split; otherwise it will be
202 : : // subsumed by QUANT_UNUSED_VARS.
203 [ + + ]: 278 : if (nret.getKind() == Kind::OR)
204 : : {
205 : 274 : return nret;
206 : : }
207 : : }
208 : : }
209 : 333 : break;
210 : 72 : case ProofRewriteRule::QUANT_MINISCOPE_FV:
211 : : {
212 [ + - ][ - + ]: 72 : if (n.getKind() != Kind::FORALL || n[1].getKind() != Kind::OR)
[ + - ][ - + ]
[ - - ]
213 : : {
214 : 0 : return Node::null();
215 : : }
216 : 72 : size_t nvars = n[0].getNumChildren();
217 : 144 : std::vector<Node> disj;
218 : 144 : std::unordered_set<Node> varsUsed;
219 : 72 : size_t varIndex = 0;
220 [ + + ]: 314 : for (const Node& d : n[1])
221 : : {
222 : : // Note that we may apply to a nested quantified formula, in which
223 : : // case some variables in fvs may not be bound by this quantified
224 : : // formula.
225 : 484 : std::unordered_set<Node> fvs;
226 : 242 : expr::getFreeVariables(d, fvs);
227 : 242 : size_t prevVarIndex = varIndex;
228 : 424 : while (varIndex < nvars && fvs.find(n[0][varIndex]) != fvs.end())
229 : : {
230 : 182 : varIndex++;
231 : : }
232 : 484 : std::vector<Node> dvs(n[0].begin() + prevVarIndex,
233 : 968 : n[0].begin() + varIndex);
234 [ + + ]: 242 : if (dvs.empty())
235 : : {
236 : 153 : disj.emplace_back(d);
237 : : }
238 : : else
239 : : {
240 : 89 : Node bvl = d_nm->mkNode(Kind::BOUND_VAR_LIST, dvs);
241 : 89 : disj.emplace_back(d_nm->mkNode(Kind::FORALL, bvl, d));
242 : : }
243 : : }
244 : : // must consume all variables
245 [ - + ]: 72 : if (varIndex != nvars)
246 : : {
247 : 0 : return Node::null();
248 : : }
249 : 144 : Node ret = d_nm->mkOr(disj);
250 : : // go back and ensure all variables are bound
251 : 144 : std::unordered_set<Node> fvs;
252 : 72 : expr::getFreeVariables(ret, fvs);
253 [ + + ]: 254 : for (const Node& v : n[0])
254 : : {
255 [ - + ]: 182 : if (fvs.find(v) != fvs.end())
256 : : {
257 : 0 : return Node::null();
258 : : }
259 : : }
260 : 72 : return ret;
261 : : }
262 : : break;
263 : 1332 : case ProofRewriteRule::MACRO_QUANT_VAR_ELIM_EQ:
264 : : case ProofRewriteRule::QUANT_VAR_ELIM_EQ:
265 : : case ProofRewriteRule::MACRO_QUANT_VAR_ELIM_INEQ:
266 : : {
267 [ + - ][ + + ]: 1332 : if (n.getKind() != Kind::FORALL || n.getNumChildren() != 2)
[ + + ]
268 : : {
269 : 909 : return Node::null();
270 : : }
271 : 2576 : std::vector<Node> args(n[0].begin(), n[0].end());
272 : 1288 : std::vector<Node> vars;
273 : 1288 : std::vector<Node> subs;
274 : 1288 : Node body = n[1];
275 [ + + ]: 1288 : if (id == ProofRewriteRule::MACRO_QUANT_VAR_ELIM_EQ)
276 : : {
277 : 774 : std::vector<Node> lits;
278 : 774 : getVarElim(body, args, vars, subs, lits);
279 : : }
280 [ + + ]: 514 : else if (id == ProofRewriteRule::QUANT_VAR_ELIM_EQ)
281 : : {
282 [ - + ]: 124 : if (args.size() != 1)
283 : : {
284 : 0 : return Node::null();
285 : : }
286 : 124 : std::vector<Node> lits;
287 [ + - ]: 124 : if (body.getKind() == Kind::OR)
288 : : {
289 : 124 : lits.insert(lits.end(), body.begin(), body.end());
290 : : }
291 : : else
292 : : {
293 : 0 : lits.push_back(body);
294 : : }
295 : 124 : if (lits[0].getKind() != Kind::NOT
296 [ + - ][ - + ]: 248 : || lits[0][0].getKind() != Kind::EQUAL)
[ + - ][ - + ]
[ - - ]
297 : : {
298 : 0 : return Node::null();
299 : : }
300 : 124 : Node eq = lits[0][0];
301 : 124 : if (eq[0] != args[0] || expr::hasSubterm(eq[1], eq[0]))
302 : : {
303 : 0 : return Node::null();
304 : : }
305 : 124 : vars.push_back(eq[0]);
306 : 124 : subs.push_back(eq[1]);
307 : 124 : args.clear();
308 : 124 : std::vector<Node> remLits(lits.begin() + 1, lits.end());
309 : 124 : body = d_nm->mkOr(remLits);
310 : : }
311 : : else
312 : : {
313 : : // assume empty attribute
314 : 390 : QAttributes qa;
315 : 390 : getVarElimIneq(n[1], args, vars, subs, qa);
316 : : }
317 : : // if we eliminated a variable, update body and reprocess
318 [ + + ]: 1288 : if (!vars.empty())
319 : : {
320 [ - + ][ - + ]: 821 : Assert(vars.size() == subs.size());
[ - - ]
321 : 1642 : std::vector<Node> qc(n.begin(), n.end());
322 : 821 : qc[1] =
323 : 1642 : body.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
324 [ + + ]: 821 : if (args.empty())
325 : : {
326 : 500 : return qc[1];
327 : : }
328 : 321 : qc[0] = d_nm->mkNode(Kind::BOUND_VAR_LIST, args);
329 : 321 : return d_nm->mkNode(Kind::FORALL, qc);
330 : : }
331 : : }
332 : 467 : break;
333 : 0 : default: break;
334 : : }
335 : 2456 : return Node::null();
336 : : }
337 : :
338 : 39055 : bool QuantifiersRewriter::isLiteral( Node n ){
339 [ - - ][ + + ]: 39055 : switch( n.getKind() ){
340 : 0 : case Kind::NOT:
341 : 0 : return n[0].getKind() != Kind::NOT && isLiteral(n[0]);
342 : : break;
343 : 0 : case Kind::OR:
344 : : case Kind::AND:
345 : : case Kind::IMPLIES:
346 : : case Kind::XOR:
347 : 0 : case Kind::ITE: return false; break;
348 : 18537 : case Kind::EQUAL:
349 : : // for boolean terms
350 : 18537 : return !n[0].getType().isBoolean();
351 : : break;
352 : 20518 : default: break;
353 : : }
354 : 20518 : return true;
355 : : }
356 : :
357 : 26759400 : void QuantifiersRewriter::computeArgs(const std::vector<Node>& args,
358 : : std::map<Node, bool>& activeMap,
359 : : Node n,
360 : : std::map<Node, bool>& visited)
361 : : {
362 [ + + ]: 26759400 : if( visited.find( n )==visited.end() ){
363 : 18032200 : visited[n] = true;
364 [ + + ]: 18032200 : if (n.getKind() == Kind::BOUND_VARIABLE)
365 : : {
366 [ + + ]: 3825970 : if( std::find( args.begin(), args.end(), n )!=args.end() ){
367 : 3155390 : activeMap[ n ] = true;
368 : : }
369 : : }
370 : : else
371 : : {
372 [ + + ]: 14206200 : if (n.hasOperator())
373 : : {
374 : 8472310 : computeArgs(args, activeMap, n.getOperator(), visited);
375 : : }
376 [ + + ]: 31136200 : for( int i=0; i<(int)n.getNumChildren(); i++ ){
377 : 16930000 : computeArgs( args, activeMap, n[i], visited );
378 : : }
379 : : }
380 : : }
381 : 26759400 : }
382 : :
383 : 760804 : void QuantifiersRewriter::computeArgVec(const std::vector<Node>& args,
384 : : std::vector<Node>& activeArgs,
385 : : Node n)
386 : : {
387 [ - + ][ - + ]: 760804 : Assert(activeArgs.empty());
[ - - ]
388 : 1521610 : std::map< Node, bool > activeMap;
389 : 1521610 : std::map< Node, bool > visited;
390 : 760804 : computeArgs( args, activeMap, n, visited );
391 [ + + ]: 760804 : if( !activeMap.empty() ){
392 [ + + ]: 73868200 : for( unsigned i=0; i<args.size(); i++ ){
393 [ + + ]: 73111900 : if( activeMap.find( args[i] )!=activeMap.end() ){
394 : 2130860 : activeArgs.push_back( args[i] );
395 : : }
396 : : }
397 : : }
398 : 760804 : }
399 : :
400 : 298464 : void QuantifiersRewriter::computeArgVec2(const std::vector<Node>& args,
401 : : std::vector<Node>& activeArgs,
402 : : Node n,
403 : : Node ipl)
404 : : {
405 [ - + ][ - + ]: 298464 : Assert(activeArgs.empty());
[ - - ]
406 : 596928 : std::map< Node, bool > activeMap;
407 : 596928 : std::map< Node, bool > visited;
408 : 298464 : computeArgs( args, activeMap, n, visited );
409 : : // Collect variables in inst pattern list only if we cannot eliminate
410 : : // quantifier, or if we have an add-to-pool annotation.
411 : 298464 : bool varComputePatList = !activeMap.empty();
412 [ + + ]: 299612 : for (const Node& ip : ipl)
413 : : {
414 : 1148 : Kind k = ip.getKind();
415 [ + - ][ - + ]: 1148 : if (k == Kind::INST_ADD_TO_POOL || k == Kind::SKOLEM_ADD_TO_POOL)
416 : : {
417 : 0 : varComputePatList = true;
418 : 0 : break;
419 : : }
420 : : }
421 [ + + ]: 298464 : if (varComputePatList)
422 : : {
423 : 297841 : computeArgs( args, activeMap, ipl, visited );
424 : : }
425 [ + + ]: 298464 : if (!activeMap.empty())
426 : : {
427 [ + + ]: 1323530 : for (const Node& a : args)
428 : : {
429 [ + + ]: 1025690 : if (activeMap.find(a) != activeMap.end())
430 : : {
431 : 1024530 : activeArgs.push_back(a);
432 : : }
433 : : }
434 : : }
435 : 298464 : }
436 : :
437 : 741682 : RewriteResponse QuantifiersRewriter::preRewrite(TNode q)
438 : : {
439 : 741682 : Kind k = q.getKind();
440 [ + + ][ + + ]: 741682 : if (k == Kind::FORALL || k == Kind::EXISTS)
441 : : {
442 : : // Do prenex merging now, since this may impact trigger selection.
443 : : // In particular consider:
444 : : // (forall ((x Int)) (forall ((y Int)) (! (P x) :pattern ((f x)))))
445 : : // If we wait until post-rewrite, we would rewrite the inner quantified
446 : : // formula, dropping the pattern, so the entire formula becomes:
447 : : // (forall ((x Int)) (P x))
448 : : // Instead, we merge to:
449 : : // (forall ((x Int) (y Int)) (! (P x) :pattern ((f x))))
450 : : // eagerly here, where after we would drop y to obtain:
451 : : // (forall ((x Int)) (! (P x) :pattern ((f x))))
452 : : // See issue #10303.
453 : 477528 : Node qm = mergePrenex(q, true);
454 [ + + ]: 477528 : if (q != qm)
455 : : {
456 : 3648 : return RewriteResponse(REWRITE_AGAIN_FULL, qm);
457 : : }
458 : : }
459 : 738034 : return RewriteResponse(REWRITE_DONE, q);
460 : : }
461 : :
462 : 661672 : RewriteResponse QuantifiersRewriter::postRewrite(TNode in)
463 : : {
464 [ + - ]: 661672 : Trace("quantifiers-rewrite-debug") << "post-rewriting " << in << std::endl;
465 : 661672 : RewriteStatus status = REWRITE_DONE;
466 : 1323340 : Node ret = in;
467 : 661672 : RewriteStep rew_op = COMPUTE_LAST;
468 : : // get the body
469 [ + + ]: 661672 : if (in.getKind() == Kind::EXISTS)
470 : : {
471 : 8885 : std::vector<Node> children;
472 : 8885 : children.push_back(in[0]);
473 : 8885 : children.push_back(in[1].notNode());
474 [ + + ]: 8885 : if (in.getNumChildren() == 3)
475 : : {
476 : 75 : children.push_back(in[2]);
477 : : }
478 : 8885 : ret = nodeManager()->mkNode(Kind::FORALL, children);
479 : 8885 : ret = ret.negate();
480 : 8885 : status = REWRITE_AGAIN_FULL;
481 : : }
482 [ + + ]: 652787 : else if (in.getKind() == Kind::FORALL)
483 : : {
484 : : // do prenex merging
485 : 388633 : ret = mergePrenex(in, true);
486 [ + + ]: 388633 : if (ret != in)
487 : : {
488 : 48 : status = REWRITE_AGAIN_FULL;
489 : : }
490 [ + + ][ + + ]: 388585 : else if (in[1].isConst() && in.getNumChildren() == 2)
[ + - ][ + + ]
[ - - ]
491 : : {
492 : 1994 : return RewriteResponse( status, in[1] );
493 : : }
494 : : else
495 : : {
496 : : //compute attributes
497 : 773182 : QAttributes qa;
498 : 386591 : QuantAttributes::computeQuantAttributes( in, qa );
499 [ + + ]: 3090300 : for (unsigned i = 0; i < COMPUTE_LAST; ++i)
500 : : {
501 : 2763420 : RewriteStep op = static_cast<RewriteStep>(i);
502 [ + + ]: 2763420 : if( doOperation( in, op, qa ) ){
503 : 1972040 : ret = computeOperation( in, op, qa );
504 [ + + ]: 1972040 : if( ret!=in ){
505 : 59711 : rew_op = op;
506 : 59711 : status = REWRITE_AGAIN_FULL;
507 : 59711 : break;
508 : : }
509 : : }
510 : : }
511 : : }
512 : : }
513 : : //print if changed
514 [ + + ]: 659678 : if( in!=ret ){
515 [ + - ]: 68644 : Trace("quantifiers-rewrite") << "*** rewrite (op=" << rew_op << ") " << in << std::endl;
516 [ + - ]: 68644 : Trace("quantifiers-rewrite") << " to " << std::endl;
517 [ + - ]: 68644 : Trace("quantifiers-rewrite") << ret << std::endl;
518 : : }
519 : 659678 : return RewriteResponse( status, ret );
520 : : }
521 : :
522 : 867275 : Node QuantifiersRewriter::mergePrenex(const Node& q, bool checkStd)
523 : : {
524 [ + + ][ - + ]: 867275 : Assert(q.getKind() == Kind::FORALL || q.getKind() == Kind::EXISTS);
[ - + ][ - - ]
525 : 867275 : Kind k = q.getKind();
526 : 1734550 : std::vector<Node> boundVars;
527 : 1734550 : Node body = q;
528 : 867275 : bool combineQuantifiers = false;
529 : 867275 : bool continueCombine = false;
530 [ + + ]: 881122 : do
531 : : {
532 [ + + ]: 4106140 : for (const Node& v : body[0])
533 : : {
534 [ + + ]: 3225020 : if (std::find(boundVars.begin(), boundVars.end(), v) == boundVars.end())
535 : : {
536 : 3225000 : boundVars.push_back(v);
537 : : }
538 : : else
539 : : {
540 : : // if duplicate variable due to shadowing, we must rewrite
541 : 21 : combineQuantifiers = true;
542 : : }
543 : : }
544 : 881122 : continueCombine = false;
545 [ + + ][ + + ]: 881122 : if (body.getNumChildren() == 2 && body[1].getKind() == k)
[ + + ][ + + ]
[ - - ]
546 : : {
547 : 13847 : bool process = true;
548 [ + + ]: 13847 : if (checkStd)
549 : : {
550 : : // Should never combine a quantified formula with a pool or
551 : : // non-standard quantified formula here.
552 : : // Note that we technically should check
553 : : // doOperation(body[1], COMPUTE_PRENEX, qa) here, although this
554 : : // is too restrictive, as sometimes nested patterns should just be
555 : : // applied to the top level, for example:
556 : : // (forall ((x Int)) (forall ((y Int)) (! P :pattern ((f x y)))))
557 : : // should be a pattern for the top-level quantifier here.
558 : 13153 : QAttributes qa;
559 : 13153 : QuantAttributes::computeQuantAttributes(body[1], qa);
560 : 13153 : process = qa.isStandard();
561 : : }
562 [ + - ]: 13847 : if (process)
563 : : {
564 : 13847 : body = body[1];
565 : 13847 : continueCombine = true;
566 : 13847 : combineQuantifiers = true;
567 : : }
568 : : }
569 : : } while (continueCombine);
570 [ + + ]: 867275 : if (combineQuantifiers)
571 : : {
572 : 4018 : NodeManager* nm = nodeManager();
573 : 8036 : std::vector<Node> children;
574 : 4018 : children.push_back(nm->mkNode(Kind::BOUND_VAR_LIST, boundVars));
575 : 4018 : children.push_back(body[1]);
576 [ + + ]: 4018 : if (body.getNumChildren() == 3)
577 : : {
578 : 158 : children.push_back(body[2]);
579 : : }
580 : 4018 : return nm->mkNode(k, children);
581 : : }
582 : 863257 : return q;
583 : : }
584 : :
585 : 0 : void QuantifiersRewriter::computeDtTesterIteSplit(
586 : : Node n,
587 : : std::map<Node, Node>& pcons,
588 : : std::map<Node, std::map<int, Node>>& ncons,
589 : : std::vector<Node>& conj) const
590 : : {
591 : 0 : if (n.getKind() == Kind::ITE && n[0].getKind() == Kind::APPLY_TESTER
592 : 0 : && n[1].getType().isBoolean())
593 : : {
594 [ - - ]: 0 : Trace("quantifiers-rewrite-ite-debug") << "Split tester condition : " << n << std::endl;
595 : 0 : Node x = n[0][0];
596 : 0 : std::map< Node, Node >::iterator itp = pcons.find( x );
597 [ - - ]: 0 : if( itp!=pcons.end() ){
598 [ - - ]: 0 : Trace("quantifiers-rewrite-ite-debug") << "...condition already set " << itp->second << std::endl;
599 [ - - ]: 0 : computeDtTesterIteSplit( n[ itp->second==n[0] ? 1 : 2 ], pcons, ncons, conj );
600 : : }else{
601 : 0 : Node tester = n[0].getOperator();
602 : 0 : int index = datatypes::utils::indexOf(tester);
603 : 0 : std::map< int, Node >::iterator itn = ncons[x].find( index );
604 [ - - ]: 0 : if( itn!=ncons[x].end() ){
605 [ - - ]: 0 : Trace("quantifiers-rewrite-ite-debug") << "...condition negated " << itn->second << std::endl;
606 : 0 : computeDtTesterIteSplit( n[ 2 ], pcons, ncons, conj );
607 : : }else{
608 [ - - ]: 0 : for( unsigned i=0; i<2; i++ ){
609 [ - - ]: 0 : if( i==0 ){
610 : 0 : pcons[x] = n[0];
611 : : }else{
612 : 0 : pcons.erase( x );
613 : 0 : ncons[x][index] = n[0].negate();
614 : : }
615 : 0 : computeDtTesterIteSplit( n[i+1], pcons, ncons, conj );
616 : : }
617 : 0 : ncons[x].erase( index );
618 : : }
619 : : }
620 : : }
621 : : else
622 : : {
623 : 0 : NodeManager* nm = nodeManager();
624 [ - - ]: 0 : Trace("quantifiers-rewrite-ite-debug") << "Return value : " << n << std::endl;
625 : 0 : std::vector< Node > children;
626 : 0 : children.push_back( n );
627 : 0 : std::vector< Node > vars;
628 : : //add all positive testers
629 [ - - ]: 0 : for( std::map< Node, Node >::iterator it = pcons.begin(); it != pcons.end(); ++it ){
630 : 0 : children.push_back( it->second.negate() );
631 : 0 : vars.push_back( it->first );
632 : : }
633 : : //add all negative testers
634 [ - - ]: 0 : for( std::map< Node, std::map< int, Node > >::iterator it = ncons.begin(); it != ncons.end(); ++it ){
635 : 0 : Node x = it->first;
636 : : //only if we haven't settled on a positive tester
637 [ - - ]: 0 : if( std::find( vars.begin(), vars.end(), x )==vars.end() ){
638 : : //check if we have exhausted all options but one
639 : 0 : const DType& dt = x.getType().getDType();
640 : 0 : std::vector< Node > nchildren;
641 : 0 : int pos_cons = -1;
642 [ - - ]: 0 : for( int i=0; i<(int)dt.getNumConstructors(); i++ ){
643 : 0 : std::map< int, Node >::iterator itt = it->second.find( i );
644 [ - - ]: 0 : if( itt==it->second.end() ){
645 [ - - ]: 0 : pos_cons = pos_cons==-1 ? i : -2;
646 : : }else{
647 : 0 : nchildren.push_back( itt->second.negate() );
648 : : }
649 : : }
650 [ - - ]: 0 : if( pos_cons>=0 ){
651 : 0 : Node tester = dt[pos_cons].getTester();
652 : 0 : children.push_back(
653 : 0 : nm->mkNode(Kind::APPLY_TESTER, tester, x).negate());
654 : : }else{
655 : 0 : children.insert( children.end(), nchildren.begin(), nchildren.end() );
656 : : }
657 : : }
658 : : }
659 : : //make condition/output pair
660 : 0 : Node c = children.size() == 1 ? children[0]
661 [ - - ]: 0 : : nodeManager()->mkNode(Kind::OR, children);
662 : 0 : conj.push_back( c );
663 : : }
664 : 0 : }
665 : :
666 : 347619 : Node QuantifiersRewriter::computeProcessTerms(const Node& q,
667 : : const std::vector<Node>& args,
668 : : Node body,
669 : : QAttributes& qa) const
670 : : {
671 : 347619 : options::IteLiftQuantMode iteLiftMode = options::IteLiftQuantMode::NONE;
672 [ + + ]: 347619 : if (qa.isStandard())
673 : : {
674 : 333073 : iteLiftMode = d_opts.quantifiers.iteLiftQuant;
675 : : }
676 : 695238 : std::vector<Node> new_conds;
677 : 695238 : std::map<Node, Node> cache;
678 : 347619 : Node n = computeProcessTerms2(q, args, body, cache, new_conds, iteLiftMode);
679 [ - + ]: 347619 : if (!new_conds.empty())
680 : : {
681 : 0 : new_conds.push_back(n);
682 : 0 : n = nodeManager()->mkNode(Kind::OR, new_conds);
683 : : }
684 : 695238 : return n;
685 : : }
686 : :
687 : 10776000 : Node QuantifiersRewriter::computeProcessTerms2(
688 : : const Node& q,
689 : : const std::vector<Node>& args,
690 : : Node body,
691 : : std::map<Node, Node>& cache,
692 : : std::vector<Node>& new_conds,
693 : : options::IteLiftQuantMode iteLiftMode) const
694 : : {
695 : 10776000 : NodeManager* nm = nodeManager();
696 [ + - ]: 21552000 : Trace("quantifiers-rewrite-term-debug2")
697 : 10776000 : << "computeProcessTerms " << body << std::endl;
698 : 10776000 : std::map< Node, Node >::iterator iti = cache.find( body );
699 [ + + ]: 10776000 : if( iti!=cache.end() ){
700 : 3335430 : return iti->second;
701 : : }
702 [ + + ]: 7440580 : if (body.isClosure())
703 : : {
704 : : // Ensure no shadowing. If this term is a closure quantifying a variable
705 : : // in args, then we introduce fresh variable(s) and replace this closure
706 : : // to be over the fresh variables instead.
707 : 87880 : std::vector<Node> oldVars;
708 : 87880 : std::vector<Node> newVars;
709 [ + + ]: 212527 : for (size_t i = 0, nvars = body[0].getNumChildren(); i < nvars; i++)
710 : : {
711 : 249294 : const Node& v = body[0][i];
712 [ + + ]: 124647 : if (std::find(args.begin(), args.end(), v) != args.end())
713 : : {
714 [ + - ]: 164 : Trace("quantifiers-rewrite-unshadow")
715 : 82 : << "Found shadowed variable " << v << " in " << q << std::endl;
716 : 82 : oldVars.push_back(v);
717 : 164 : Node nv = ElimShadowNodeConverter::getElimShadowVar(q, body, i);
718 : 82 : newVars.push_back(nv);
719 : : }
720 : : }
721 [ + + ]: 87880 : if (!oldVars.empty())
722 : : {
723 [ - + ][ - + ]: 82 : Assert(oldVars.size() == newVars.size());
[ - - ]
724 : : Node sbody = body.substitute(
725 : 164 : oldVars.begin(), oldVars.end(), newVars.begin(), newVars.end());
726 : 82 : cache[body] = sbody;
727 : 82 : return sbody;
728 : : }
729 : : }
730 : 7440500 : bool changed = false;
731 : 14881000 : std::vector<Node> children;
732 [ + + ]: 17868900 : for (const Node& bc : body)
733 : : {
734 : : // do the recursive call on children
735 : 10428400 : Node nn = computeProcessTerms2(q, args, bc, cache, new_conds, iteLiftMode);
736 : 10428400 : children.push_back(nn);
737 [ + + ][ + + ]: 10428400 : changed = changed || nn != bc;
738 : : }
739 : :
740 : : // make return value
741 : 14881000 : Node ret;
742 [ + + ]: 7440500 : if (changed)
743 : : {
744 [ + + ]: 31334 : if (body.getMetaKind() == kind::metakind::PARAMETERIZED)
745 : : {
746 : 942 : children.insert(children.begin(), body.getOperator());
747 : : }
748 : 31334 : ret = nm->mkNode(body.getKind(), children);
749 : : }
750 : : else
751 : : {
752 : 7409160 : ret = body;
753 : : }
754 : :
755 [ + - ]: 14881000 : Trace("quantifiers-rewrite-term-debug2")
756 : 7440500 : << "Returning " << ret << " for " << body << std::endl;
757 : : // do context-independent rewriting
758 : 7440500 : if (ret.getKind() == Kind::EQUAL
759 [ + + ][ + + ]: 7440500 : && iteLiftMode != options::IteLiftQuantMode::NONE)
[ + + ]
760 : : {
761 [ + + ]: 3462840 : for (size_t i = 0; i < 2; i++)
762 : : {
763 [ + + ]: 2309110 : if (ret[i].getKind() == Kind::ITE)
764 : : {
765 [ + + ]: 73549 : Node no = i == 0 ? ret[1] : ret[0];
766 [ + + ]: 73549 : if (no.getKind() != Kind::ITE)
767 : : {
768 : 67291 : bool doRewrite = (iteLiftMode == options::IteLiftQuantMode::ALL);
769 : 67291 : std::vector<Node> childrenIte;
770 : 67291 : childrenIte.push_back(ret[i][0]);
771 [ + + ]: 201873 : for (size_t j = 1; j <= 2; j++)
772 : : {
773 : : // check if it rewrites to a constant
774 : 403746 : Node nn = nm->mkNode(Kind::EQUAL, no, ret[i][j]);
775 : 134582 : childrenIte.push_back(nn);
776 : : // check if it will rewrite to a constant
777 : 134582 : if (no == ret[i][j] || (no.isConst() && ret[i][j].isConst()))
778 : : {
779 : 1479 : doRewrite = true;
780 : : }
781 : : }
782 [ + + ]: 67291 : if (doRewrite)
783 : : {
784 : 1018 : ret = nm->mkNode(Kind::ITE, childrenIte);
785 : 1018 : break;
786 : : }
787 : : }
788 : : }
789 : : }
790 : : }
791 [ + + ][ + + ]: 6285750 : else if (ret.getKind() == Kind::SELECT && ret[0].getKind() == Kind::STORE)
[ + + ][ + + ]
[ - - ]
792 : : {
793 : 376 : Node st = ret[0];
794 : 376 : Node index = ret[1];
795 : 376 : std::vector<Node> iconds;
796 : 376 : std::vector<Node> elements;
797 [ + + ]: 784 : while (st.getKind() == Kind::STORE)
798 : : {
799 : 596 : iconds.push_back(index.eqNode(st[1]));
800 : 596 : elements.push_back(st[2]);
801 : 596 : st = st[0];
802 : : }
803 : 188 : ret = nm->mkNode(Kind::SELECT, st, index);
804 : : // conditions
805 [ + + ]: 784 : for (int i = (iconds.size() - 1); i >= 0; i--)
806 : : {
807 : 596 : ret = nm->mkNode(Kind::ITE, iconds[i], elements[i], ret);
808 : : }
809 : : }
810 [ + + ][ + + ]: 6285560 : else if (ret.getKind() == Kind::HO_APPLY && !ret.getType().isFunction())
[ + + ][ + + ]
[ - - ]
811 : : {
812 : : // fully applied functions are converted to APPLY_UF here.
813 : 40528 : Node fullApp = uf::TheoryUfRewriter::getApplyUfForHoApply(ret);
814 : : // it may not be possible to convert e.g. if the head is not a variable
815 [ + - ]: 20264 : if (!fullApp.isNull())
816 : : {
817 : 20264 : ret = fullApp;
818 : : }
819 : : }
820 : 7440500 : cache[body] = ret;
821 : 7440500 : return ret;
822 : : }
823 : :
824 : 28 : Node QuantifiersRewriter::computeExtendedRewrite(TNode q,
825 : : const QAttributes& qa) const
826 : : {
827 : : // do not apply to recursive functions
828 [ + + ]: 28 : if (qa.isFunDef())
829 : : {
830 : 8 : return q;
831 : : }
832 : 40 : Node body = q[1];
833 : : // apply extended rewriter
834 : 40 : Node bodyr = d_rewriter->extendedRewrite(body);
835 [ + + ]: 20 : if (body != bodyr)
836 : : {
837 : 12 : std::vector<Node> children;
838 : 6 : children.push_back(q[0]);
839 : 6 : children.push_back(bodyr);
840 [ - + ]: 6 : if (q.getNumChildren() == 3)
841 : : {
842 : 0 : children.push_back(q[2]);
843 : : }
844 : 6 : return nodeManager()->mkNode(Kind::FORALL, children);
845 : : }
846 : 14 : return q;
847 : : }
848 : :
849 : 327277 : Node QuantifiersRewriter::computeCondSplit(Node body,
850 : : const std::vector<Node>& args,
851 : : QAttributes& qa) const
852 : : {
853 : 327277 : NodeManager* nm = nodeManager();
854 : 327277 : Kind bk = body.getKind();
855 [ + + ]: 696 : if (d_opts.quantifiers.iteDtTesterSplitQuant && bk == Kind::ITE
856 [ + + ][ - + ]: 327973 : && body[0].getKind() == Kind::APPLY_TESTER)
[ + + ][ - + ]
[ - - ]
857 : : {
858 [ - - ]: 0 : Trace("quantifiers-rewrite-ite-debug") << "DTT split : " << body << std::endl;
859 : 0 : std::map< Node, Node > pcons;
860 : 0 : std::map< Node, std::map< int, Node > > ncons;
861 : 0 : std::vector< Node > conj;
862 : 0 : computeDtTesterIteSplit( body, pcons, ncons, conj );
863 : 0 : Assert(!conj.empty());
864 [ - - ]: 0 : if( conj.size()>1 ){
865 [ - - ]: 0 : Trace("quantifiers-rewrite-ite") << "*** Split ITE (datatype tester) " << body << " into : " << std::endl;
866 [ - - ]: 0 : for( unsigned i=0; i<conj.size(); i++ ){
867 [ - - ]: 0 : Trace("quantifiers-rewrite-ite") << " " << conj[i] << std::endl;
868 : : }
869 : 0 : return nm->mkNode(Kind::AND, conj);
870 : : }
871 : : }
872 [ - + ]: 327277 : if (d_opts.quantifiers.condVarSplitQuant
873 : : == options::CondVarSplitQuantMode::OFF)
874 : : {
875 : 0 : return body;
876 : : }
877 [ + - ]: 654554 : Trace("cond-var-split-debug")
878 : 327277 : << "Conditional var elim split " << body << "?" << std::endl;
879 : : // we only do this splitting if miniscoping is enabled, as this is
880 : : // required to eliminate variables in conjuncts below. We also never
881 : : // miniscope non-standard quantifiers, so this is also guarded here.
882 [ + + ][ + + ]: 327277 : if (!doMiniscopeConj(d_opts) || !qa.isStandard())
[ + + ]
883 : : {
884 : 23848 : return body;
885 : : }
886 : :
887 : 303429 : bool aggCondSplit = (d_opts.quantifiers.condVarSplitQuant
888 : : == options::CondVarSplitQuantMode::AGG);
889 : 303429 : if (bk == Kind::ITE
890 : 303429 : || (bk == Kind::EQUAL && body[0].getType().isBoolean() && aggCondSplit))
891 : : {
892 [ - + ][ - + ]: 344 : Assert(!qa.isFunDef());
[ - - ]
893 : 344 : bool do_split = false;
894 : 344 : unsigned index_max = bk == Kind::ITE ? 0 : 1;
895 : 344 : std::vector<Node> tmpArgs = args;
896 [ + + ]: 614 : for (unsigned index = 0; index <= index_max; index++)
897 : : {
898 [ + + ][ - - ]: 344 : if (hasVarElim(body[index], true, tmpArgs)
899 [ + + ][ - + ]: 344 : || hasVarElim(body[index], false, tmpArgs))
[ + + ][ + - ]
[ - - ]
900 : : {
901 : 74 : do_split = true;
902 : 74 : break;
903 : : }
904 : : }
905 [ + + ]: 344 : if (do_split)
906 : : {
907 : 148 : Node pos;
908 : 74 : Node neg;
909 [ + - ]: 74 : if (bk == Kind::ITE)
910 : : {
911 : 74 : pos = nm->mkNode(Kind::OR, body[0].negate(), body[1]);
912 : 74 : neg = nm->mkNode(Kind::OR, body[0], body[2]);
913 : : }
914 : : else
915 : : {
916 : 0 : pos = nm->mkNode(Kind::OR, body[0].negate(), body[1]);
917 : 0 : neg = nm->mkNode(Kind::OR, body[0], body[1].negate());
918 : : }
919 [ + - ]: 148 : Trace("cond-var-split-debug") << "*** Split (conditional variable eq) "
920 : 74 : << body << " into : " << std::endl;
921 [ + - ]: 74 : Trace("cond-var-split-debug") << " " << pos << std::endl;
922 [ + - ]: 74 : Trace("cond-var-split-debug") << " " << neg << std::endl;
923 : 74 : return nm->mkNode(Kind::AND, pos, neg);
924 : : }
925 : : }
926 : :
927 [ + + ]: 303355 : if (bk == Kind::OR)
928 : : {
929 : 127805 : unsigned size = body.getNumChildren();
930 : 127805 : bool do_split = false;
931 : 127805 : unsigned split_index = 0;
932 [ + + ]: 499963 : for (unsigned i = 0; i < size; i++)
933 : : {
934 : : // check if this child is a (conditional) variable elimination
935 : 372519 : Node b = body[i];
936 [ + + ]: 372519 : if (b.getKind() == Kind::AND)
937 : : {
938 : 41366 : std::vector<Node> vars;
939 : 41366 : std::vector<Node> subs;
940 : 41366 : std::vector<Node> tmpArgs = args;
941 [ + + ]: 76608 : for (unsigned j = 0, bsize = b.getNumChildren(); j < bsize; j++)
942 : : {
943 [ + + ]: 56286 : if (getVarElimLit(body, b[j], false, tmpArgs, vars, subs))
944 : : {
945 [ + - ]: 9302 : Trace("cond-var-split-debug") << "Variable elimination in child #"
946 : 4651 : << j << " under " << i << std::endl;
947 : : // Figure out if we should split
948 : : // Currently we split if the aggressive option is set, or
949 : : // if the top-level OR is binary.
950 [ + - ][ + + ]: 4651 : if (aggCondSplit || size == 2)
951 : : {
952 : 361 : do_split = true;
953 : : }
954 : : // other splitting criteria go here
955 : :
956 [ + + ]: 4651 : if (do_split)
957 : : {
958 : 361 : split_index = i;
959 : 361 : break;
960 : : }
961 : 4290 : vars.clear();
962 : 4290 : subs.clear();
963 : 4290 : tmpArgs = args;
964 : : }
965 : : }
966 : : }
967 [ + + ]: 372519 : if (do_split)
968 : : {
969 : 361 : break;
970 : : }
971 : : }
972 [ + + ]: 127805 : if (do_split)
973 : : {
974 : 722 : std::vector<Node> children;
975 [ + + ]: 1083 : for (TNode bc : body)
976 : : {
977 : 722 : children.push_back(bc);
978 : : }
979 : 722 : std::vector<Node> split_children;
980 [ + + ]: 1454 : for (TNode bci : body[split_index])
981 : : {
982 : 1093 : children[split_index] = bci;
983 : 1093 : split_children.push_back(nm->mkNode(Kind::OR, children));
984 : : }
985 : : // split the AND child, for example:
986 : : // ( x!=a ^ P(x) ) V Q(x) ---> ( x!=a V Q(x) ) ^ ( P(x) V Q(x) )
987 : 361 : return nm->mkNode(Kind::AND, split_children);
988 : : }
989 : : }
990 : :
991 : 302994 : return body;
992 : : }
993 : :
994 : 12392 : bool QuantifiersRewriter::isVarElim(Node v, Node s)
995 : : {
996 [ - + ][ - + ]: 12392 : Assert(v.getKind() == Kind::BOUND_VARIABLE);
[ - - ]
997 : 12392 : return !expr::hasSubterm(s, v) && s.getType() == v.getType();
998 : : }
999 : :
1000 : 95225 : Node QuantifiersRewriter::getVarElimEq(Node lit,
1001 : : const std::vector<Node>& args,
1002 : : Node& var) const
1003 : : {
1004 [ - + ][ - + ]: 95225 : Assert(lit.getKind() == Kind::EQUAL);
[ - - ]
1005 : 95225 : Node slv;
1006 : 190450 : TypeNode tt = lit[0].getType();
1007 [ + + ]: 95225 : if (tt.isRealOrInt())
1008 : : {
1009 : 47654 : slv = getVarElimEqReal(lit, args, var);
1010 : : }
1011 [ + + ]: 47571 : else if (tt.isBitVector())
1012 : : {
1013 : 1331 : slv = getVarElimEqBv(lit, args, var);
1014 : : }
1015 [ + + ]: 46240 : else if (tt.isStringLike())
1016 : : {
1017 : 206 : slv = getVarElimEqString(lit, args, var);
1018 : : }
1019 : 190450 : return slv;
1020 : : }
1021 : :
1022 : 47654 : Node QuantifiersRewriter::getVarElimEqReal(Node lit,
1023 : : const std::vector<Node>& args,
1024 : : Node& var) const
1025 : : {
1026 : : // for arithmetic, solve the equality
1027 : 95308 : std::map<Node, Node> msum;
1028 [ - + ]: 47654 : if (!ArithMSum::getMonomialSumLit(lit, msum))
1029 : : {
1030 : 0 : return Node::null();
1031 : : }
1032 : 47654 : std::vector<Node>::const_iterator ita;
1033 [ + + ]: 143633 : for (std::map<Node, Node>::iterator itm = msum.begin(); itm != msum.end();
1034 : 95979 : ++itm)
1035 : : {
1036 [ + + ]: 96658 : if (itm->first.isNull())
1037 : : {
1038 : 9345 : continue;
1039 : : }
1040 : 87313 : ita = std::find(args.begin(), args.end(), itm->first);
1041 [ + + ]: 87313 : if (ita != args.end())
1042 : : {
1043 : 1551 : Node veq_c;
1044 : 1551 : Node val;
1045 : 1551 : int ires = ArithMSum::isolate(itm->first, msum, veq_c, val, Kind::EQUAL);
1046 : 1551 : if (ires != 0 && veq_c.isNull() && isVarElim(itm->first, val))
1047 : : {
1048 : 679 : var = itm->first;
1049 : 679 : return val;
1050 : : }
1051 : : }
1052 : : }
1053 : 46975 : return Node::null();
1054 : : }
1055 : :
1056 : 1331 : Node QuantifiersRewriter::getVarElimEqBv(Node lit,
1057 : : const std::vector<Node>& args,
1058 : : Node& var) const
1059 : : {
1060 [ - + ]: 1331 : if (TraceIsOn("quant-velim-bv"))
1061 : : {
1062 [ - - ]: 0 : Trace("quant-velim-bv") << "Bv-Elim : " << lit << " varList = { ";
1063 [ - - ]: 0 : for (const Node& v : args)
1064 : : {
1065 [ - - ]: 0 : Trace("quant-velim-bv") << v << " ";
1066 : : }
1067 [ - - ]: 0 : Trace("quant-velim-bv") << "} ?" << std::endl;
1068 : : }
1069 [ - + ][ - + ]: 1331 : Assert(lit.getKind() == Kind::EQUAL);
[ - - ]
1070 : : // TODO (#1494) : linearize the literal using utility
1071 : :
1072 : : // compute a subset active_args of the bound variables args that occur in lit
1073 : 2662 : std::vector<Node> active_args;
1074 : 1331 : computeArgVec(args, active_args, lit);
1075 : :
1076 : 2662 : BvInverter binv(d_opts);
1077 [ + + ]: 2763 : for (const Node& cvar : active_args)
1078 : : {
1079 : : // solve for the variable on this path using the inverter
1080 : 1551 : std::vector<unsigned> path;
1081 : 3102 : Node slit = binv.getPathToPv(lit, cvar, path);
1082 [ + + ]: 1551 : if (!slit.isNull())
1083 : : {
1084 : 1878 : Node slv = binv.solveBvLit(cvar, lit, path, nullptr);
1085 [ + - ]: 939 : Trace("quant-velim-bv") << "...solution : " << slv << std::endl;
1086 [ + + ]: 939 : if (!slv.isNull())
1087 : : {
1088 : 369 : var = cvar;
1089 : : // if this is a proper variable elimination, that is, var = slv where
1090 : : // var is not in the free variables of slv, then we can return this
1091 : : // as the variable elimination for lit.
1092 [ + + ]: 369 : if (isVarElim(var, slv))
1093 : : {
1094 : 119 : return slv;
1095 : : }
1096 : : }
1097 : : }
1098 : : else
1099 : : {
1100 [ + - ]: 612 : Trace("quant-velim-bv") << "...non-invertible path." << std::endl;
1101 : : }
1102 : : }
1103 : :
1104 : 1212 : return Node::null();
1105 : : }
1106 : :
1107 : 206 : Node QuantifiersRewriter::getVarElimEqString(Node lit,
1108 : : const std::vector<Node>& args,
1109 : : Node& var) const
1110 : : {
1111 [ - + ][ - + ]: 206 : Assert(lit.getKind() == Kind::EQUAL);
[ - - ]
1112 : 206 : NodeManager* nm = nodeManager();
1113 [ + + ]: 600 : for (unsigned i = 0; i < 2; i++)
1114 : : {
1115 [ + + ]: 412 : if (lit[i].getKind() == Kind::STRING_CONCAT)
1116 : : {
1117 : 46 : TypeNode stype = lit[i].getType();
1118 [ + + ]: 120 : for (unsigned j = 0, nchildren = lit[i].getNumChildren(); j < nchildren;
1119 : : j++)
1120 : : {
1121 [ + + ]: 92 : if (std::find(args.begin(), args.end(), lit[i][j]) != args.end())
1122 : : {
1123 : 58 : var = lit[i][j];
1124 : 58 : Node slv = lit[1 - i];
1125 : 116 : std::vector<Node> preL(lit[i].begin(), lit[i].begin() + j);
1126 : 58 : std::vector<Node> postL(lit[i].begin() + j + 1, lit[i].end());
1127 : 58 : Node tpre = strings::utils::mkConcat(preL, stype);
1128 : 58 : Node tpost = strings::utils::mkConcat(postL, stype);
1129 : 58 : Node slvL = nm->mkNode(Kind::STRING_LENGTH, slv);
1130 : 58 : Node tpreL = nm->mkNode(Kind::STRING_LENGTH, tpre);
1131 : 58 : Node tpostL = nm->mkNode(Kind::STRING_LENGTH, tpost);
1132 : 116 : slv = nm->mkNode(
1133 : : Kind::STRING_SUBSTR,
1134 : : slv,
1135 : : tpreL,
1136 : 116 : nm->mkNode(
1137 : 174 : Kind::SUB, slvL, nm->mkNode(Kind::ADD, tpreL, tpostL)));
1138 : : // forall x. r ++ x ++ t = s => P( x )
1139 : : // is equivalent to
1140 : : // r ++ s' ++ t = s => P( s' ) where
1141 : : // s' = substr( s, |r|, |s|-(|t|+|r|) ).
1142 : : // We apply this only if r,t,s do not contain free variables.
1143 [ + + ]: 58 : if (!expr::hasFreeVar(slv))
1144 : : {
1145 : 18 : return slv;
1146 : : }
1147 : : }
1148 : : }
1149 : : }
1150 : : }
1151 : :
1152 : 188 : return Node::null();
1153 : : }
1154 : :
1155 : 644757 : bool QuantifiersRewriter::getVarElimLit(Node body,
1156 : : Node lit,
1157 : : bool pol,
1158 : : std::vector<Node>& args,
1159 : : std::vector<Node>& vars,
1160 : : std::vector<Node>& subs) const
1161 : : {
1162 [ + + ]: 644757 : if (lit.getKind() == Kind::NOT)
1163 : : {
1164 : 15739 : lit = lit[0];
1165 : 15739 : pol = !pol;
1166 [ - + ][ - + ]: 15739 : Assert(lit.getKind() != Kind::NOT);
[ - - ]
1167 : : }
1168 : 644757 : NodeManager* nm = nodeManager();
1169 [ + - ]: 1289510 : Trace("var-elim-quant-debug")
1170 : 644757 : << "Eliminate : " << lit << ", pol = " << pol << "?" << std::endl;
1171 [ + + ]: 1277 : if (lit.getKind() == Kind::APPLY_TESTER && pol
1172 [ + + ][ + + ]: 645460 : && lit[0].getKind() == Kind::BOUND_VARIABLE
[ - - ]
1173 [ + + ][ + - ]: 646034 : && d_opts.quantifiers.dtVarExpandQuant)
[ + + ]
1174 : : {
1175 [ + - ]: 186 : Trace("var-elim-dt") << "Expand datatype variable based on : " << lit
1176 : 93 : << std::endl;
1177 : : std::vector<Node>::iterator ita =
1178 : 93 : std::find(args.begin(), args.end(), lit[0]);
1179 [ + - ]: 93 : if (ita != args.end())
1180 : : {
1181 : 93 : vars.push_back(lit[0]);
1182 : 186 : Node tester = lit.getOperator();
1183 : 93 : int index = datatypes::utils::indexOf(tester);
1184 : 93 : const DType& dt = datatypes::utils::datatypeOf(tester);
1185 : 93 : const DTypeConstructor& c = dt[index];
1186 : 186 : std::vector<Node> newChildren;
1187 : 186 : Node cons = c.getConstructor();
1188 : 186 : TypeNode tspec;
1189 : : // take into account if parametric
1190 [ + + ]: 93 : if (dt.isParametric())
1191 : : {
1192 : 2 : TypeNode ltn = lit[0].getType();
1193 : 2 : tspec = c.getInstantiatedConstructorType(ltn);
1194 : 2 : cons = c.getInstantiatedConstructor(ltn);
1195 : : }
1196 : : else
1197 : : {
1198 : 91 : tspec = cons.getType();
1199 : : }
1200 : 93 : newChildren.push_back(cons);
1201 : 93 : std::vector<Node> newVars;
1202 : 93 : BoundVarManager* bvm = nm->getBoundVarManager();
1203 [ + + ]: 292 : for (size_t j = 0, nargs = c.getNumArgs(); j < nargs; j++)
1204 : : {
1205 : 398 : TypeNode tn = tspec[j];
1206 : 398 : Node rn = nm->mkConstInt(Rational(j));
1207 : 597 : Node cacheVal = BoundVarManager::getCacheValue(body, lit, rn);
1208 : 597 : Node v = bvm->mkBoundVar<QRewDtExpandAttribute>(cacheVal, tn);
1209 : 199 : newChildren.push_back(v);
1210 : 199 : newVars.push_back(v);
1211 : : }
1212 : 93 : subs.push_back(nm->mkNode(Kind::APPLY_CONSTRUCTOR, newChildren));
1213 [ + - ]: 186 : Trace("var-elim-dt") << "...apply substitution " << subs[0] << "/"
1214 : 93 : << vars[0] << std::endl;
1215 : 93 : args.erase(ita);
1216 : 93 : args.insert(args.end(), newVars.begin(), newVars.end());
1217 : 93 : return true;
1218 : : }
1219 : : }
1220 : : // all eliminations below guarded by varElimQuant()
1221 [ + + ]: 644664 : if (!d_opts.quantifiers.varElimQuant)
1222 : : {
1223 : 8 : return false;
1224 : : }
1225 : :
1226 [ + + ]: 644656 : if (lit.getKind() == Kind::EQUAL)
1227 : : {
1228 : 347351 : if (pol || lit[0].getType().isBoolean())
1229 : : {
1230 [ + + ]: 507267 : for (unsigned i = 0; i < 2; i++)
1231 : : {
1232 : 342168 : bool tpol = pol;
1233 : 342168 : Node v_slv = lit[i];
1234 [ + + ]: 342168 : if (v_slv.getKind() == Kind::NOT)
1235 : : {
1236 : 13252 : v_slv = v_slv[0];
1237 : 13252 : tpol = !tpol;
1238 : : }
1239 : : std::vector<Node>::iterator ita =
1240 : 342168 : std::find(args.begin(), args.end(), v_slv);
1241 [ + + ]: 342168 : if (ita != args.end())
1242 : : {
1243 [ + + ]: 10924 : if (isVarElim(v_slv, lit[1 - i]))
1244 : : {
1245 : 9546 : Node slv = lit[1 - i];
1246 [ + + ]: 9546 : if (!tpol)
1247 : : {
1248 [ - + ][ - + ]: 956 : Assert(slv.getType().isBoolean());
[ - - ]
1249 : 956 : slv = slv.negate();
1250 : : }
1251 [ + - ]: 19092 : Trace("var-elim-quant")
1252 : 0 : << "Variable eliminate based on equality : " << v_slv << " -> "
1253 : 9546 : << slv << std::endl;
1254 : 9546 : vars.push_back(v_slv);
1255 : 9546 : subs.push_back(slv);
1256 : 9546 : args.erase(ita);
1257 : 9546 : return true;
1258 : : }
1259 : : }
1260 : : }
1261 : : }
1262 : : }
1263 [ + + ]: 635110 : if (lit.getKind() == Kind::BOUND_VARIABLE)
1264 : : {
1265 : 2760 : std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), lit );
1266 [ + + ]: 2760 : if( ita!=args.end() ){
1267 [ + - ]: 2747 : Trace("var-elim-bool") << "Variable eliminate : " << lit << std::endl;
1268 : 2747 : vars.push_back( lit );
1269 : 2747 : subs.push_back(nodeManager()->mkConst(pol));
1270 : 2747 : args.erase( ita );
1271 : 2747 : return true;
1272 : : }
1273 : : }
1274 [ + + ][ + + ]: 632363 : if (lit.getKind() == Kind::EQUAL && pol)
[ + + ]
1275 : : {
1276 : 95225 : Node var;
1277 : 95225 : Node slv = getVarElimEq(lit, args, var);
1278 [ + + ]: 95225 : if (!slv.isNull())
1279 : : {
1280 [ - + ][ - + ]: 816 : Assert(!var.isNull());
[ - - ]
1281 : : std::vector<Node>::iterator ita =
1282 : 816 : std::find(args.begin(), args.end(), var);
1283 [ - + ][ - + ]: 816 : Assert(ita != args.end());
[ - - ]
1284 [ + - ]: 1632 : Trace("var-elim-quant")
1285 : 0 : << "Variable eliminate based on theory-specific solving : " << var
1286 : 816 : << " -> " << slv << std::endl;
1287 [ - + ][ - + ]: 816 : Assert(!expr::hasSubterm(slv, var));
[ - - ]
1288 [ - + ][ - + ]: 816 : Assert(slv.getType() == var.getType());
[ - - ]
1289 : 816 : vars.push_back(var);
1290 : 816 : subs.push_back(slv);
1291 : 816 : args.erase(ita);
1292 : 816 : return true;
1293 : : }
1294 : : }
1295 : 631547 : return false;
1296 : : }
1297 : :
1298 : 323027 : bool QuantifiersRewriter::getVarElim(Node body,
1299 : : std::vector<Node>& args,
1300 : : std::vector<Node>& vars,
1301 : : std::vector<Node>& subs,
1302 : : std::vector<Node>& lits) const
1303 : : {
1304 : 323027 : return getVarElimInternal(body, body, false, args, vars, subs, lits);
1305 : : }
1306 : :
1307 : 729398 : bool QuantifiersRewriter::getVarElimInternal(Node body,
1308 : : Node n,
1309 : : bool pol,
1310 : : std::vector<Node>& args,
1311 : : std::vector<Node>& vars,
1312 : : std::vector<Node>& subs,
1313 : : std::vector<Node>& lits) const
1314 : : {
1315 : 729398 : Kind nk = n.getKind();
1316 [ + + ]: 988113 : while (nk == Kind::NOT)
1317 : : {
1318 : 258715 : n = n[0];
1319 : 258715 : pol = !pol;
1320 : 258715 : nk = n.getKind();
1321 : : }
1322 [ + + ][ + + ]: 729398 : if ((nk == Kind::AND && pol) || (nk == Kind::OR && !pol))
[ + + ][ + - ]
1323 : : {
1324 [ + + ]: 539111 : for (const Node& cn : n)
1325 : : {
1326 [ + + ]: 405757 : if (getVarElimInternal(body, cn, pol, args, vars, subs, lits))
1327 : : {
1328 : 7573 : return true;
1329 : : }
1330 : : }
1331 : 133354 : return false;
1332 : : }
1333 [ + + ]: 588471 : if (getVarElimLit(body, n, pol, args, vars, subs))
1334 : : {
1335 [ + + ]: 8551 : lits.emplace_back(pol ? n : n.notNode());
1336 : 8551 : return true;
1337 : : }
1338 : 579920 : return false;
1339 : : }
1340 : :
1341 : 614 : bool QuantifiersRewriter::hasVarElim(Node n,
1342 : : bool pol,
1343 : : std::vector<Node>& args) const
1344 : : {
1345 : 1228 : std::vector< Node > vars;
1346 : 1228 : std::vector< Node > subs;
1347 : 614 : std::vector<Node> lits;
1348 : 1228 : return getVarElimInternal(n, n, pol, args, vars, subs, lits);
1349 : : }
1350 : :
1351 : 314797 : bool QuantifiersRewriter::getVarElimIneq(Node body,
1352 : : std::vector<Node>& args,
1353 : : std::vector<Node>& bounds,
1354 : : std::vector<Node>& subs,
1355 : : QAttributes& qa) const
1356 : : {
1357 [ + - ]: 314797 : Trace("var-elim-quant-debug") << "getVarElimIneq " << body << std::endl;
1358 : : // For each variable v, we compute a set of implied bounds in the body
1359 : : // of the quantified formula.
1360 : : // num_bounds[x][-1] stores the entailed lower bounds for x
1361 : : // num_bounds[x][1] stores the entailed upper bounds for x
1362 : : // num_bounds[x][0] stores the entailed disequalities for x
1363 : : // These bounds are stored in a map that maps the literal for the bound to
1364 : : // its required polarity. For example, for quantified formula
1365 : : // (forall ((x Int)) (or (= x 0) (>= x a)))
1366 : : // we have:
1367 : : // num_bounds[x][0] contains { x -> { (= x 0) -> false } }
1368 : : // num_bounds[x][-1] contains { x -> { (>= x a) -> false } }
1369 : : // This method succeeds in eliminating x if its only occurrences are in
1370 : : // entailed disequalities, and one kind of bound. This is the case for the
1371 : : // above quantified formula, which can be rewritten to false. The reason
1372 : : // is that we can always chose a value for x that is arbitrarily large (resp.
1373 : : // small) to satisfy all disequalities and inequalities for x.
1374 : 629594 : std::map<Node, std::map<int, std::map<Node, bool>>> num_bounds;
1375 : : // The set of variables that we know we can not eliminate
1376 : 629594 : std::unordered_set<Node> ineligVars;
1377 : : // compute the entailed literals
1378 : 629594 : QuantPhaseReq qpr(body);
1379 : : // map to track which literals we have already processed, and hence can be
1380 : : // excluded from the free variables check in the latter half of this method.
1381 : 629594 : std::map<Node, int> processed;
1382 [ + + ]: 862410 : for (const std::pair<const Node, bool>& pr : qpr.d_phase_reqs)
1383 : : {
1384 : : // an inequality that is entailed with a given polarity
1385 : 547613 : Node lit = pr.first;
1386 : 547613 : bool pol = pr.second;
1387 [ + - ]: 1095230 : Trace("var-elim-quant-debug") << "Process inequality bounds : " << lit
1388 : 547613 : << ", pol = " << pol << "..." << std::endl;
1389 : 1095230 : bool canSolve = lit.getKind() == Kind::GEQ
1390 [ + + ][ + + ]: 863690 : || (lit.getKind() == Kind::EQUAL
1391 : 863690 : && lit[0].getType().isRealOrInt() && !pol);
1392 [ + + ]: 547613 : if (!canSolve)
1393 : : {
1394 : 434389 : continue;
1395 : : }
1396 : : // solve the inequality
1397 : 113224 : std::map<Node, Node> msum;
1398 [ - + ]: 113224 : if (!ArithMSum::getMonomialSumLit(lit, msum))
1399 : : {
1400 : : // not an inequality, cannot use
1401 : 0 : continue;
1402 : : }
1403 [ + + ]: 113224 : processed[lit] = pol ? -1 : 1;
1404 [ + + ]: 350096 : for (const std::pair<const Node, Node>& m : msum)
1405 : : {
1406 [ + + ][ + + ]: 236872 : if (!m.first.isNull() && ineligVars.find(m.first) == ineligVars.end())
[ + + ]
1407 : : {
1408 : : std::vector<Node>::iterator ita =
1409 : 190715 : std::find(args.begin(), args.end(), m.first);
1410 [ + + ]: 190715 : if (ita != args.end())
1411 : : {
1412 : : // store that this literal is upper/lower bound for itm->first
1413 : 175010 : Node veq_c;
1414 : 175010 : Node val;
1415 : : int ires =
1416 : 87505 : ArithMSum::isolate(m.first, msum, veq_c, val, lit.getKind());
1417 [ + - ][ + + ]: 87505 : if (ires != 0 && veq_c.isNull())
[ + + ]
1418 : : {
1419 [ + + ]: 86785 : if (lit.getKind() == Kind::GEQ)
1420 : : {
1421 : 54164 : bool is_upper = pol != (ires == 1);
1422 [ + - ]: 108328 : Trace("var-elim-ineq-debug")
1423 [ - - ]: 0 : << lit << " is a " << (is_upper ? "upper" : "lower")
1424 : 54164 : << " bound for " << m.first << std::endl;
1425 [ + - ]: 108328 : Trace("var-elim-ineq-debug")
1426 : 54164 : << " pol/ires = " << pol << " " << ires << std::endl;
1427 [ + + ]: 54164 : num_bounds[m.first][is_upper ? 1 : -1][lit] = pol;
1428 : : }
1429 : : else
1430 : : {
1431 [ + - ]: 65242 : Trace("var-elim-ineq-debug")
1432 : 32621 : << lit << " is a disequality for " << m.first << std::endl;
1433 : 32621 : num_bounds[m.first][0][lit] = pol;
1434 : : }
1435 : : }
1436 : : else
1437 : : {
1438 [ + - ]: 1440 : Trace("var-elim-ineq-debug")
1439 : 0 : << "...ineligible " << m.first
1440 : 0 : << " since it cannot be solved for (" << ires << ", " << veq_c
1441 : 720 : << ")." << std::endl;
1442 : 720 : num_bounds.erase(m.first);
1443 : 720 : ineligVars.insert(m.first);
1444 : : }
1445 : : }
1446 : : else
1447 : : {
1448 : : // compute variables in itm->first, these are not eligible for
1449 : : // elimination
1450 : 206420 : std::unordered_set<Node> fvs;
1451 : 103210 : expr::getFreeVariables(m.first, fvs);
1452 [ + + ]: 214499 : for (const Node& v : fvs)
1453 : : {
1454 [ + - ]: 222578 : Trace("var-elim-ineq-debug")
1455 : 0 : << "...ineligible " << v
1456 : 111289 : << " since it is contained in monomial." << std::endl;
1457 : 111289 : num_bounds.erase(v);
1458 : 111289 : ineligVars.insert(v);
1459 : : }
1460 : : }
1461 : : }
1462 : : }
1463 : : }
1464 : :
1465 : : // collect all variables that have only upper/lower bounds
1466 : 629594 : std::map<Node, bool> elig_vars;
1467 : 46841 : for (const std::pair<const Node, std::map<int, std::map<Node, bool>>>& nb :
1468 [ + + ]: 408479 : num_bounds)
1469 : : {
1470 [ + + ]: 46841 : if (nb.second.find(1) == nb.second.end())
1471 : : {
1472 [ + - ]: 58844 : Trace("var-elim-ineq-debug")
1473 : 29422 : << "Variable " << nb.first << " has only lower bounds." << std::endl;
1474 : 29422 : elig_vars[nb.first] = false;
1475 : : }
1476 [ + + ]: 17419 : else if (nb.second.find(-1) == nb.second.end())
1477 : : {
1478 [ + - ]: 13736 : Trace("var-elim-ineq-debug")
1479 : 6868 : << "Variable " << nb.first << " has only upper bounds." << std::endl;
1480 : 6868 : elig_vars[nb.first] = true;
1481 : : }
1482 : : }
1483 [ + + ]: 314797 : if (elig_vars.empty())
1484 : : {
1485 : 285105 : return false;
1486 : : }
1487 : 59384 : std::vector<Node> inactive_vars;
1488 : 59384 : std::map<Node, std::map<int, bool> > visited;
1489 : : // traverse the body, invalidate variables if they occur in places other than
1490 : : // the bounds they occur in
1491 : 59384 : std::unordered_map<TNode, std::unordered_set<int>> evisited;
1492 : 59384 : std::vector<TNode> evisit;
1493 : 59384 : std::vector<int> evisit_pol;
1494 : 29692 : TNode ecur;
1495 : : int ecur_pol;
1496 : 29692 : evisit.push_back(body);
1497 : 29692 : evisit_pol.push_back(1);
1498 [ + + ]: 29692 : if (!qa.d_ipl.isNull())
1499 : : {
1500 : : // do not eliminate variables that occur in the annotation
1501 : 4154 : evisit.push_back(qa.d_ipl);
1502 : 4154 : evisit_pol.push_back(0);
1503 : : }
1504 : 184758 : do
1505 : : {
1506 : 214450 : ecur = evisit.back();
1507 : 214450 : evisit.pop_back();
1508 : 214450 : ecur_pol = evisit_pol.back();
1509 : 214450 : evisit_pol.pop_back();
1510 : 214450 : std::unordered_set<int>& epp = evisited[ecur];
1511 [ + + ]: 214450 : if (epp.find(ecur_pol) == epp.end())
1512 : : {
1513 : 210971 : epp.insert(ecur_pol);
1514 [ + + ]: 210971 : if (elig_vars.find(ecur) != elig_vars.end())
1515 : : {
1516 : : // variable contained in a place apart from bounds, no longer eligible
1517 : : // for elimination
1518 : 34013 : elig_vars.erase(ecur);
1519 [ + - ]: 68026 : Trace("var-elim-ineq-debug") << "...found occurrence of " << ecur
1520 : 34013 : << ", mark ineligible" << std::endl;
1521 : : }
1522 : : else
1523 : : {
1524 : 176958 : bool rec = true;
1525 : 176958 : bool pol = ecur_pol >= 0;
1526 : 176958 : bool hasPol = ecur_pol != 0;
1527 [ + + ]: 176958 : if (hasPol)
1528 : : {
1529 : 100059 : std::map<Node, int>::iterator itx = processed.find(ecur);
1530 [ + + ][ + + ]: 100059 : if (itx != processed.end() && itx->second == ecur_pol)
[ + + ]
1531 : : {
1532 : : // already processed this literal as a bound
1533 : 16885 : rec = false;
1534 : : }
1535 : : }
1536 [ + + ]: 176958 : if (rec)
1537 : : {
1538 [ + + ]: 418301 : for (unsigned j = 0, size = ecur.getNumChildren(); j < size; j++)
1539 : : {
1540 : : bool newHasPol;
1541 : : bool newPol;
1542 : 258228 : QuantPhaseReq::getPolarity(ecur, j, hasPol, pol, newHasPol, newPol);
1543 : 258228 : evisit.push_back(ecur[j]);
1544 [ + + ][ + + ]: 258228 : evisit_pol.push_back(newHasPol ? (newPol ? 1 : -1) : 0);
1545 : : }
1546 : : }
1547 : : }
1548 : : }
1549 [ + + ][ + + ]: 214450 : } while (!evisit.empty() && !elig_vars.empty());
[ + + ]
1550 : :
1551 : 29692 : bool ret = false;
1552 : 29692 : NodeManager* nm = nodeManager();
1553 [ + + ]: 31969 : for (const std::pair<const Node, bool>& ev : elig_vars)
1554 : : {
1555 : 2277 : Node v = ev.first;
1556 [ + - ]: 4554 : Trace("var-elim-ineq-debug")
1557 : 2277 : << v << " is eligible for elimination." << std::endl;
1558 : : // do substitution corresponding to infinite projection, all literals
1559 : : // involving unbounded variable go to true/false
1560 : : // disequalities of eligible variables are also eliminated
1561 : 2277 : std::map<int, std::map<Node, bool>>& nbv = num_bounds[v];
1562 [ + + ]: 6831 : for (size_t i = 0; i < 2; i++)
1563 : : {
1564 [ + + ][ + + ]: 4554 : size_t nindex = i == 0 ? (elig_vars[v] ? 1 : -1) : 0;
1565 [ + + ]: 7167 : for (const std::pair<const Node, bool>& nb : nbv[nindex])
1566 : : {
1567 [ + - ]: 5226 : Trace("var-elim-ineq-debug")
1568 : 2613 : << " subs : " << nb.first << " -> " << nb.second << std::endl;
1569 : 2613 : bounds.push_back(nb.first);
1570 : 2613 : subs.push_back(nm->mkConst(nb.second));
1571 : : }
1572 : : }
1573 : : // eliminate from args
1574 : 2277 : std::vector<Node>::iterator ita = std::find(args.begin(), args.end(), v);
1575 [ - + ][ - + ]: 2277 : Assert(ita != args.end());
[ - - ]
1576 : 2277 : args.erase(ita);
1577 : 2277 : ret = true;
1578 : : }
1579 : 29692 : return ret;
1580 : : }
1581 : :
1582 : 322086 : Node QuantifiersRewriter::computeVarElimination(Node body,
1583 : : std::vector<Node>& args,
1584 : : QAttributes& qa) const
1585 : : {
1586 [ + + ][ - + ]: 322086 : if (!d_opts.quantifiers.varElimQuant && !d_opts.quantifiers.dtVarExpandQuant
1587 [ - - ]: 0 : && !d_opts.quantifiers.varIneqElimQuant)
1588 : : {
1589 : 0 : return body;
1590 : : }
1591 [ + - ]: 644172 : Trace("var-elim-quant-debug")
1592 : 322086 : << "computeVarElimination " << body << std::endl;
1593 : 644172 : std::vector<Node> vars;
1594 : 644172 : std::vector<Node> subs;
1595 : : // standard variable elimination
1596 [ + + ]: 322086 : if (d_opts.quantifiers.varElimQuant)
1597 : : {
1598 : 321816 : std::vector<Node> lits;
1599 : 321816 : getVarElim(body, args, vars, subs, lits);
1600 : : }
1601 : : // variable elimination based on one-direction inequalities
1602 [ + + ][ + + ]: 322086 : if (vars.empty() && d_opts.quantifiers.varIneqElimQuant)
[ + + ]
1603 : : {
1604 : 314407 : getVarElimIneq(body, args, vars, subs, qa);
1605 : : }
1606 : : // if we eliminated a variable, update body and reprocess
1607 [ + + ]: 322086 : if (!vars.empty())
1608 : : {
1609 [ + - ]: 18618 : Trace("var-elim-quant-debug")
1610 : 9309 : << "VE " << vars.size() << "/" << args.size() << std::endl;
1611 [ - + ][ - + ]: 9309 : Assert(vars.size() == subs.size());
[ - - ]
1612 : : // remake with eliminated nodes
1613 : 9309 : body = body.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
1614 [ + + ]: 9309 : if (!qa.d_ipl.isNull())
1615 : : {
1616 : 138 : qa.d_ipl = qa.d_ipl.substitute(
1617 : 69 : vars.begin(), vars.end(), subs.begin(), subs.end());
1618 : : }
1619 [ + - ]: 9309 : Trace("var-elim-quant") << "Return " << body << std::endl;
1620 : : }
1621 : 322086 : return body;
1622 : : }
1623 : :
1624 : 2207600 : Node QuantifiersRewriter::computePrenex(Node q,
1625 : : Node body,
1626 : : std::unordered_set<Node>& args,
1627 : : std::unordered_set<Node>& nargs,
1628 : : bool pol,
1629 : : bool prenexAgg) const
1630 : : {
1631 : 2207600 : NodeManager* nm = nodeManager();
1632 : 2207600 : Kind k = body.getKind();
1633 [ + + ]: 2207600 : if (k == Kind::FORALL)
1634 : : {
1635 [ - + ]: 44366 : if ((pol || prenexAgg)
1636 [ + + ][ + - ]: 94100 : && (d_opts.quantifiers.prenexQuantUser
1637 [ + + ][ + + ]: 49734 : || !QuantAttributes::hasPattern(body)))
[ + + ][ - - ]
1638 : : {
1639 : 5288 : std::vector< Node > terms;
1640 : 5288 : std::vector< Node > subs;
1641 : 2644 : BoundVarManager* bvm = nm->getBoundVarManager();
1642 : : //for doing prenexing of same-signed quantifiers
1643 : : //must rename each variable that already exists
1644 [ + + ]: 6401 : for (const Node& v : body[0])
1645 : : {
1646 : 3757 : terms.push_back(v);
1647 : 7514 : TypeNode vt = v.getType();
1648 : 7514 : Node vv;
1649 [ + + ]: 3757 : if (!q.isNull())
1650 : : {
1651 : : // We cache based on the original quantified formula, the subformula
1652 : : // that we are pulling variables from (body), and the variable v.
1653 : : // The argument body is required since in rare cases, two subformulas
1654 : : // may share the same variables. This is the case for define-fun
1655 : : // or inferred substitutions that contain quantified formulas.
1656 : 7512 : Node cacheVal = BoundVarManager::getCacheValue(q, body, v);
1657 : 3756 : vv = bvm->mkBoundVar<QRewPrenexAttribute>(cacheVal, vt);
1658 : : }
1659 : : else
1660 : : {
1661 : : // not specific to a quantified formula, use normal
1662 : 1 : vv = nm->mkBoundVar(vt);
1663 : : }
1664 : 3757 : subs.push_back(vv);
1665 : : }
1666 [ + - ]: 2644 : if (pol)
1667 : : {
1668 : 2644 : args.insert(subs.begin(), subs.end());
1669 : : }
1670 : : else
1671 : : {
1672 : 0 : nargs.insert(subs.begin(), subs.end());
1673 : : }
1674 : 5288 : Node newBody = body[1];
1675 : 2644 : newBody = newBody.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
1676 : 2644 : return newBody;
1677 : : }
1678 : : //must remove structure
1679 : : }
1680 [ + + ][ - + ]: 2160550 : else if (prenexAgg && k == Kind::ITE && body.getType().isBoolean())
[ - - ][ - + ]
[ - + ][ - - ]
1681 : : {
1682 : : Node nn = nm->mkNode(Kind::AND,
1683 : 0 : nm->mkNode(Kind::OR, body[0].notNode(), body[1]),
1684 : 0 : nm->mkNode(Kind::OR, body[0], body[2]));
1685 : 0 : return computePrenex(q, nn, args, nargs, pol, prenexAgg);
1686 : : }
1687 : 2160550 : else if (prenexAgg && k == Kind::EQUAL && body[0].getType().isBoolean())
1688 : : {
1689 : : Node nn = nm->mkNode(Kind::AND,
1690 : 0 : nm->mkNode(Kind::OR, body[0].notNode(), body[1]),
1691 : 0 : nm->mkNode(Kind::OR, body[0], body[1].notNode()));
1692 : 0 : return computePrenex(q, nn, args, nargs, pol, prenexAgg);
1693 [ + - ]: 2160550 : }else if( body.getType().isBoolean() ){
1694 [ - + ][ - + ]: 2160550 : Assert(k != Kind::EXISTS);
[ - - ]
1695 : 2160550 : bool childrenChanged = false;
1696 : 2160550 : std::vector< Node > newChildren;
1697 [ + + ]: 6319330 : for (size_t i = 0, nchild = body.getNumChildren(); i < nchild; i++)
1698 : : {
1699 : : bool newHasPol;
1700 : : bool newPol;
1701 : 4158780 : QuantPhaseReq::getPolarity( body, i, true, pol, newHasPol, newPol );
1702 [ + + ]: 4158780 : if (!newHasPol)
1703 : : {
1704 : 2237760 : newChildren.push_back( body[i] );
1705 : 2237760 : continue;
1706 : : }
1707 : 3842040 : Node n = computePrenex(q, body[i], args, nargs, newPol, prenexAgg);
1708 : 1921020 : newChildren.push_back(n);
1709 [ + + ][ + + ]: 1921020 : childrenChanged = n != body[i] || childrenChanged;
[ + - ][ - - ]
1710 : : }
1711 [ + + ]: 2160550 : if( childrenChanged ){
1712 [ - + ][ - - ]: 2560 : if (k == Kind::NOT && newChildren[0].getKind() == Kind::NOT)
[ - + ]
1713 : : {
1714 : 0 : return newChildren[0][0];
1715 : : }
1716 : 2560 : return nm->mkNode(k, newChildren);
1717 : : }
1718 : : }
1719 : 2202400 : return body;
1720 : : }
1721 : :
1722 : 129064 : Node QuantifiersRewriter::computeSplit(std::vector<Node>& args,
1723 : : Node body,
1724 : : QAttributes& qa) const
1725 : : {
1726 [ - + ][ - + ]: 129064 : Assert(body.getKind() == Kind::OR);
[ - - ]
1727 : 129064 : size_t eqc_count = 0;
1728 : 129064 : size_t eqc_active = 0;
1729 : 258128 : std::map< Node, int > var_to_eqc;
1730 : 258128 : std::map< int, std::vector< Node > > eqc_to_var;
1731 : 258128 : std::map< int, std::vector< Node > > eqc_to_lit;
1732 : :
1733 : 258128 : std::vector<Node> lits;
1734 : :
1735 [ + + ]: 887018 : for( unsigned i=0; i<body.getNumChildren(); i++ ){
1736 : : //get variables contained in the literal
1737 : 1515910 : Node n = body[i];
1738 : 1515910 : std::vector< Node > lit_args;
1739 : 757954 : computeArgVec( args, lit_args, n );
1740 [ + + ]: 757954 : if( lit_args.empty() ){
1741 : 4206 : lits.push_back( n );
1742 : : }else {
1743 : : //collect the equivalence classes this literal belongs to, and the new variables it contributes
1744 : 1507500 : std::vector< int > eqcs;
1745 : 1507500 : std::vector< Node > lit_new_args;
1746 : : //for each variable in literal
1747 [ + + ]: 2878740 : for( unsigned j=0; j<lit_args.size(); j++) {
1748 : : //see if the variable has already been found
1749 [ + + ]: 2124990 : if (var_to_eqc.find(lit_args[j])!=var_to_eqc.end()) {
1750 : 1400750 : int eqc = var_to_eqc[lit_args[j]];
1751 [ + + ]: 1400750 : if (std::find(eqcs.begin(), eqcs.end(), eqc)==eqcs.end()) {
1752 : 624086 : eqcs.push_back(eqc);
1753 : : }
1754 : : }else{
1755 : 724235 : lit_new_args.push_back(lit_args[j]);
1756 : : }
1757 : : }
1758 [ + + ]: 753748 : if (eqcs.empty()) {
1759 : 250677 : eqcs.push_back(eqc_count);
1760 : 250677 : eqc_count++;
1761 : 250677 : eqc_active++;
1762 : : }
1763 : :
1764 : 753748 : int eqcz = eqcs[0];
1765 : : //merge equivalence classes with eqcz
1766 [ + + ]: 874763 : for (unsigned j=1; j<eqcs.size(); j++) {
1767 : 121015 : int eqc = eqcs[j];
1768 : : //move all variables from equivalence class
1769 [ + + ]: 575863 : for (unsigned k=0; k<eqc_to_var[eqc].size(); k++) {
1770 : 909696 : Node v = eqc_to_var[eqc][k];
1771 : 454848 : var_to_eqc[v] = eqcz;
1772 : 454848 : eqc_to_var[eqcz].push_back(v);
1773 : : }
1774 : 121015 : eqc_to_var.erase(eqc);
1775 : : //move all literals from equivalence class
1776 [ + + ]: 510472 : for (unsigned k=0; k<eqc_to_lit[eqc].size(); k++) {
1777 : 778914 : Node l = eqc_to_lit[eqc][k];
1778 : 389457 : eqc_to_lit[eqcz].push_back(l);
1779 : : }
1780 : 121015 : eqc_to_lit.erase(eqc);
1781 : 121015 : eqc_active--;
1782 : : }
1783 : : //add variables to equivalence class
1784 [ + + ]: 1477980 : for (unsigned j=0; j<lit_new_args.size(); j++) {
1785 : 724235 : var_to_eqc[lit_new_args[j]] = eqcz;
1786 : 724235 : eqc_to_var[eqcz].push_back(lit_new_args[j]);
1787 : : }
1788 : : //add literal to equivalence class
1789 : 753748 : eqc_to_lit[eqcz].push_back(n);
1790 : : }
1791 : : }
1792 [ + + ][ + + ]: 129064 : if ( eqc_active>1 || !lits.empty() || var_to_eqc.size()!=args.size() ){
[ + + ][ + + ]
1793 : 1923 : NodeManager* nm = nodeManager();
1794 [ - + ]: 1923 : if (TraceIsOn("clause-split-debug"))
1795 : : {
1796 [ - - ]: 0 : Trace("clause-split-debug")
1797 : 0 : << "Split quantified formula with body " << body << std::endl;
1798 [ - - ]: 0 : Trace("clause-split-debug") << " Ground literals: " << std::endl;
1799 [ - - ]: 0 : for (size_t i = 0; i < lits.size(); i++)
1800 : : {
1801 [ - - ]: 0 : Trace("clause-split-debug") << " " << lits[i] << std::endl;
1802 : : }
1803 [ - - ]: 0 : Trace("clause-split-debug") << std::endl;
1804 [ - - ]: 0 : Trace("clause-split-debug") << "Equivalence classes: " << std::endl;
1805 : : }
1806 [ + + ]: 4444 : for (std::map< int, std::vector< Node > >::iterator it = eqc_to_lit.begin(); it != eqc_to_lit.end(); ++it ){
1807 : 2521 : int eqc = it->first;
1808 [ - + ]: 2521 : if (TraceIsOn("clause-split-debug"))
1809 : : {
1810 [ - - ]: 0 : Trace("clause-split-debug") << " Literals: " << std::endl;
1811 [ - - ]: 0 : for (size_t i = 0; i < it->second.size(); i++)
1812 : : {
1813 [ - - ]: 0 : Trace("clause-split-debug") << " " << it->second[i] << std::endl;
1814 : : }
1815 [ - - ]: 0 : Trace("clause-split-debug") << " Variables: " << std::endl;
1816 [ - - ]: 0 : for (size_t i = 0; i < eqc_to_var[eqc].size(); i++)
1817 : : {
1818 [ - - ]: 0 : Trace("clause-split-debug")
1819 : 0 : << " " << eqc_to_var[eqc][i] << std::endl;
1820 : : }
1821 [ - - ]: 0 : Trace("clause-split-debug") << std::endl;
1822 : : }
1823 : 2521 : std::vector<Node>& evars = eqc_to_var[eqc];
1824 : : // for the sake of proofs, we provide the variables in the order
1825 : : // they appear in the original quantified formula
1826 : 5042 : std::vector<Node> ovars;
1827 [ + + ]: 68571 : for (const Node& v : args)
1828 : : {
1829 [ + + ]: 66050 : if (std::find(evars.begin(), evars.end(), v) != evars.end())
1830 : : {
1831 : 28292 : ovars.emplace_back(v);
1832 : : }
1833 : : }
1834 : 5042 : Node bvl = nodeManager()->mkNode(Kind::BOUND_VAR_LIST, ovars);
1835 : 3485 : Node bd = it->second.size() == 1 ? it->second[0]
1836 [ + + ]: 6006 : : nm->mkNode(Kind::OR, it->second);
1837 : 7563 : Node fa = nm->mkNode(Kind::FORALL, bvl, bd);
1838 : 2521 : lits.push_back(fa);
1839 : : }
1840 [ - + ][ - + ]: 1923 : Assert(!lits.empty());
[ - - ]
1841 : 3846 : Node nf = nodeManager()->mkOr(lits);
1842 [ + - ]: 1923 : Trace("clause-split-debug") << "Made node : " << nf << std::endl;
1843 : 1923 : return nf;
1844 : : }
1845 : 127141 : return Node::null();
1846 : : }
1847 : :
1848 : 298782 : Node QuantifiersRewriter::mkForAll(const std::vector<Node>& args,
1849 : : Node body,
1850 : : QAttributes& qa) const
1851 : : {
1852 [ + + ]: 298782 : if (args.empty())
1853 : : {
1854 : 623 : return body;
1855 : : }
1856 : 298159 : NodeManager* nm = nodeManager();
1857 : 596318 : std::vector<Node> children;
1858 : 298159 : children.push_back(nm->mkNode(Kind::BOUND_VAR_LIST, args));
1859 : 298159 : children.push_back(body);
1860 [ + + ]: 298159 : if (!qa.d_ipl.isNull())
1861 : : {
1862 : 845 : children.push_back(qa.d_ipl);
1863 : : }
1864 : 298159 : return nm->mkNode(Kind::FORALL, children);
1865 : : }
1866 : :
1867 : 1 : Node QuantifiersRewriter::mkForall(const std::vector<Node>& args,
1868 : : Node body,
1869 : : bool marked) const
1870 : : {
1871 : 1 : std::vector< Node > iplc;
1872 : 2 : return mkForall( args, body, iplc, marked );
1873 : : }
1874 : :
1875 : 2 : Node QuantifiersRewriter::mkForall(const std::vector<Node>& args,
1876 : : Node body,
1877 : : std::vector<Node>& iplc,
1878 : : bool marked) const
1879 : : {
1880 [ - + ]: 2 : if (args.empty())
1881 : : {
1882 : 0 : return body;
1883 : : }
1884 : 2 : NodeManager* nm = nodeManager();
1885 : 4 : std::vector<Node> children;
1886 : 2 : children.push_back(nm->mkNode(Kind::BOUND_VAR_LIST, args));
1887 : 2 : children.push_back(body);
1888 [ + - ]: 2 : if (marked)
1889 : : {
1890 : 2 : SkolemManager* sm = nm->getSkolemManager();
1891 : 4 : Node avar = sm->mkDummySkolem("id", nm->booleanType());
1892 : : QuantIdNumAttribute ida;
1893 : 2 : avar.setAttribute(ida, 0);
1894 : 2 : iplc.push_back(nm->mkNode(Kind::INST_ATTRIBUTE, avar));
1895 : : }
1896 [ + - ]: 2 : if (!iplc.empty())
1897 : : {
1898 : 2 : children.push_back(nm->mkNode(Kind::INST_PATTERN_LIST, iplc));
1899 : : }
1900 : 2 : return nm->mkNode(Kind::FORALL, children);
1901 : : }
1902 : :
1903 : : //computes miniscoping, also eliminates variables that do not occur free in body
1904 : 301815 : Node QuantifiersRewriter::computeMiniscoping(Node q,
1905 : : QAttributes& qa,
1906 : : bool miniscopeConj,
1907 : : bool miniscopeFv) const
1908 : : {
1909 : 301815 : NodeManager* nm = nodeManager();
1910 : 905445 : std::vector<Node> args(q[0].begin(), q[0].end());
1911 : 603630 : Node body = q[1];
1912 [ + + ]: 301815 : if (body.getKind() == Kind::AND)
1913 : : {
1914 : : // aggressive miniscoping implies that structural miniscoping should
1915 : : // be applied first
1916 [ + + ]: 4446 : if (miniscopeConj)
1917 : : {
1918 : 1706 : BoundVarManager* bvm = nm->getBoundVarManager();
1919 : : // Break apart the quantifed formula
1920 : : // forall x. P1 ^ ... ^ Pn ---> forall x. P1 ^ ... ^ forall x. Pn
1921 : 3412 : NodeBuilder t(Kind::AND);
1922 : 3412 : std::vector<Node> argsc;
1923 [ + + ]: 9061 : for (size_t i = 0, nchild = body.getNumChildren(); i < nchild; i++)
1924 : : {
1925 [ + + ]: 7355 : if (argsc.empty())
1926 : : {
1927 : : // If not done so, we must create fresh copy of args. This is to
1928 : : // ensure that quantified formulas do not reuse variables.
1929 [ + + ]: 14323 : for (const Node& v : q[0])
1930 : : {
1931 : 19762 : TypeNode vt = v.getType();
1932 : 29643 : Node cacheVal = BoundVarManager::getCacheValue(q, v, i);
1933 : 29643 : Node vv = bvm->mkBoundVar<QRewMiniscopeAttribute>(cacheVal, vt);
1934 : 9881 : argsc.push_back(vv);
1935 : : }
1936 : : }
1937 : 14710 : Node b = body[i];
1938 : : Node bodyc =
1939 : 14710 : b.substitute(args.begin(), args.end(), argsc.begin(), argsc.end());
1940 [ + + ]: 7355 : if (b == bodyc)
1941 : : {
1942 : : // Did not contain variables in args, thus it is ground. Since we did
1943 : : // not use them, we keep the variables argsc for the next child.
1944 : 3055 : t << b;
1945 : : }
1946 : : else
1947 : : {
1948 : : // make the miniscoped quantified formula
1949 : 8600 : Node cbvl = nm->mkNode(Kind::BOUND_VAR_LIST, argsc);
1950 : 12900 : Node qq = nm->mkNode(Kind::FORALL, cbvl, bodyc);
1951 : 4300 : t << qq;
1952 : : // We used argsc, clear so we will construct a fresh copy above.
1953 : 4300 : argsc.clear();
1954 : : }
1955 : : }
1956 : 3412 : Node retVal = t;
1957 : 1706 : return retVal;
1958 : : }
1959 : : }
1960 [ + + ]: 297369 : else if (body.getKind() == Kind::OR)
1961 : : {
1962 [ + + ]: 134606 : if (miniscopeFv)
1963 : : {
1964 : : //splitting subsumes free variable miniscoping, apply it with higher priority
1965 : 128457 : Node ret = computeSplit(args, body, qa);
1966 [ + + ]: 128457 : if (!ret.isNull())
1967 : : {
1968 : 1645 : return ret;
1969 : : }
1970 : : }
1971 : : }
1972 [ + + ]: 162763 : else if (body.getKind() == Kind::NOT)
1973 : : {
1974 [ - + ][ - + ]: 39055 : Assert(isLiteral(body[0]));
[ - - ]
1975 : : }
1976 : : //remove variables that don't occur
1977 : 298464 : std::vector< Node > activeArgs;
1978 : 298464 : computeArgVec2( args, activeArgs, body, qa.d_ipl );
1979 : 298464 : return mkForAll( activeArgs, body, qa );
1980 : : }
1981 : :
1982 : 344 : Node QuantifiersRewriter::computeAggressiveMiniscoping(std::vector<Node>& args,
1983 : : Node body) const
1984 : : {
1985 : 688 : std::map<Node, std::vector<Node> > varLits;
1986 : 688 : std::map<Node, std::vector<Node> > litVars;
1987 [ + + ]: 344 : if (body.getKind() == Kind::OR)
1988 : : {
1989 [ + - ]: 100 : Trace("ag-miniscope") << "compute aggressive miniscoping on " << body << std::endl;
1990 [ + + ]: 312 : for (size_t i = 0; i < body.getNumChildren(); i++) {
1991 : 212 : std::vector<Node> activeArgs;
1992 : 212 : computeArgVec(args, activeArgs, body[i]);
1993 [ + + ]: 476 : for (unsigned j = 0; j < activeArgs.size(); j++) {
1994 : 264 : varLits[activeArgs[j]].push_back(body[i]);
1995 : : }
1996 : 212 : std::vector<Node>& lit_body_i = litVars[body[i]];
1997 : 212 : std::vector<Node>::iterator lit_body_i_begin = lit_body_i.begin();
1998 : 212 : std::vector<Node>::const_iterator active_begin = activeArgs.begin();
1999 : 212 : std::vector<Node>::const_iterator active_end = activeArgs.end();
2000 : 212 : lit_body_i.insert(lit_body_i_begin, active_begin, active_end);
2001 : : }
2002 : : //find the variable in the least number of literals
2003 : 100 : Node bestVar;
2004 [ + + ]: 252 : for( std::map< Node, std::vector<Node> >::iterator it = varLits.begin(); it != varLits.end(); ++it ){
2005 [ + + ][ + + ]: 152 : if( bestVar.isNull() || varLits[bestVar].size()>it->second.size() ){
[ + + ]
2006 : 124 : bestVar = it->first;
2007 : : }
2008 : : }
2009 [ + - ]: 100 : Trace("ag-miniscope-debug") << "Best variable " << bestVar << " occurs in " << varLits[bestVar].size() << "/ " << body.getNumChildren() << " literals." << std::endl;
2010 [ + - ][ + + ]: 100 : if( !bestVar.isNull() && varLits[bestVar].size()<body.getNumChildren() ){
[ + + ]
2011 : : //we can miniscope
2012 [ + - ]: 26 : Trace("ag-miniscope") << "Miniscope on " << bestVar << std::endl;
2013 : : //make the bodies
2014 : 52 : std::vector<Node> qlit1;
2015 : 26 : qlit1.insert( qlit1.begin(), varLits[bestVar].begin(), varLits[bestVar].end() );
2016 : 52 : std::vector<Node> qlitt;
2017 : : //for all literals not containing bestVar
2018 [ + + ]: 90 : for( size_t i=0; i<body.getNumChildren(); i++ ){
2019 [ + + ]: 64 : if( std::find( qlit1.begin(), qlit1.end(), body[i] )==qlit1.end() ){
2020 : 38 : qlitt.push_back( body[i] );
2021 : : }
2022 : : }
2023 : : //make the variable lists
2024 : 52 : std::vector<Node> qvl1;
2025 : 52 : std::vector<Node> qvl2;
2026 : 52 : std::vector<Node> qvsh;
2027 [ + + ]: 104 : for( unsigned i=0; i<args.size(); i++ ){
2028 : 78 : bool found1 = false;
2029 : 78 : bool found2 = false;
2030 [ + + ]: 168 : for( size_t j=0; j<varLits[args[i]].size(); j++ ){
2031 [ + + ][ + + ]: 116 : if( !found1 && std::find( qlit1.begin(), qlit1.end(), varLits[args[i]][j] )!=qlit1.end() ){
[ + + ]
2032 : 52 : found1 = true;
2033 [ + + ][ + - ]: 64 : }else if( !found2 && std::find( qlitt.begin(), qlitt.end(), varLits[args[i]][j] )!=qlitt.end() ){
[ + + ]
2034 : 52 : found2 = true;
2035 : : }
2036 [ + + ][ + + ]: 116 : if( found1 && found2 ){
2037 : 26 : break;
2038 : : }
2039 : : }
2040 [ + + ]: 78 : if( found1 ){
2041 [ + + ]: 52 : if( found2 ){
2042 : 26 : qvsh.push_back( args[i] );
2043 : : }else{
2044 : 26 : qvl1.push_back( args[i] );
2045 : : }
2046 : : }else{
2047 [ - + ][ - + ]: 26 : Assert(found2);
[ - - ]
2048 : 26 : qvl2.push_back( args[i] );
2049 : : }
2050 : : }
2051 [ - + ][ - + ]: 26 : Assert(!qvl1.empty());
[ - - ]
2052 : : //check for literals that only contain shared variables
2053 : 52 : std::vector<Node> qlitsh;
2054 : 52 : std::vector<Node> qlit2;
2055 [ + + ]: 64 : for( size_t i=0; i<qlitt.size(); i++ ){
2056 : 38 : bool hasVar2 = false;
2057 [ + + ]: 52 : for( size_t j=0; j<litVars[qlitt[i]].size(); j++ ){
2058 [ + + ]: 40 : if( std::find( qvl2.begin(), qvl2.end(), litVars[qlitt[i]][j] )!=qvl2.end() ){
2059 : 26 : hasVar2 = true;
2060 : 26 : break;
2061 : : }
2062 : : }
2063 [ + + ]: 38 : if( hasVar2 ){
2064 : 26 : qlit2.push_back( qlitt[i] );
2065 : : }else{
2066 : 12 : qlitsh.push_back( qlitt[i] );
2067 : : }
2068 : : }
2069 : 26 : varLits.clear();
2070 : 26 : litVars.clear();
2071 [ + - ]: 26 : Trace("ag-miniscope-debug") << "Split into literals : " << qlit1.size() << " / " << qlit2.size() << " / " << qlitsh.size();
2072 [ + - ]: 26 : Trace("ag-miniscope-debug") << ", variables : " << qvl1.size() << " / " << qvl2.size() << " / " << qvsh.size() << std::endl;
2073 : : Node n1 =
2074 [ + - ]: 52 : qlit1.size() == 1 ? qlit1[0] : nodeManager()->mkNode(Kind::OR, qlit1);
2075 : 26 : n1 = computeAggressiveMiniscoping( qvl1, n1 );
2076 : 26 : qlitsh.push_back( n1 );
2077 [ + + ]: 26 : if( !qlit2.empty() ){
2078 : 16 : Node n2 = qlit2.size() == 1 ? qlit2[0]
2079 [ + + ]: 30 : : nodeManager()->mkNode(Kind::OR, qlit2);
2080 : 14 : n2 = computeAggressiveMiniscoping( qvl2, n2 );
2081 : 14 : qlitsh.push_back( n2 );
2082 : : }
2083 : 52 : Node n = nodeManager()->mkNode(Kind::OR, qlitsh);
2084 [ + - ]: 26 : if( !qvsh.empty() ){
2085 : 26 : Node bvl = nodeManager()->mkNode(Kind::BOUND_VAR_LIST, qvsh);
2086 : 26 : n = nodeManager()->mkNode(Kind::FORALL, bvl, n);
2087 : : }
2088 [ + - ]: 26 : Trace("ag-miniscope") << "Return " << n << " for " << body << std::endl;
2089 : 26 : return n;
2090 : : }
2091 : : }
2092 : 318 : QAttributes qa;
2093 : 318 : return mkForAll( args, body, qa );
2094 : : }
2095 : :
2096 : 1 : bool QuantifiersRewriter::isStandard(const Node& q, const Options& opts)
2097 : : {
2098 : 2 : QAttributes qa;
2099 : 1 : QuantAttributes::computeQuantAttributes(q, qa);
2100 : 2 : return isStandard(qa, opts);
2101 : : }
2102 : :
2103 : 2763420 : bool QuantifiersRewriter::isStandard(QAttributes& qa, const Options& opts)
2104 : : {
2105 : 2763420 : bool is_strict_trigger =
2106 : 2763420 : qa.d_hasPattern
2107 [ + + ][ + + ]: 2763420 : && opts.quantifiers.userPatternsQuant == options::UserPatMode::STRICT;
2108 [ + + ][ + - ]: 2763420 : return qa.isStandard() && !is_strict_trigger;
2109 : : }
2110 : :
2111 : 2763420 : bool QuantifiersRewriter::doOperation(Node q,
2112 : : RewriteStep computeOption,
2113 : : QAttributes& qa) const
2114 : : {
2115 : 2763420 : bool is_strict_trigger =
2116 : 2763420 : qa.d_hasPattern
2117 [ + + ][ + + ]: 2763420 : && d_opts.quantifiers.userPatternsQuant == options::UserPatMode::STRICT;
2118 : 2763420 : bool is_std = isStandard(qa, d_opts);
2119 [ + + ]: 2763420 : if (computeOption == COMPUTE_ELIM_SYMBOLS)
2120 : : {
2121 : 386591 : return true;
2122 : : }
2123 [ + + ]: 2376830 : else if (computeOption == COMPUTE_MINISCOPING
2124 [ + + ]: 2024880 : || computeOption == COMPUTE_AGGRESSIVE_MINISCOPING)
2125 : : {
2126 : : // in the rare case the body is ground, we always eliminate unless it
2127 : : // is truly a non-standard quantified formula (e.g. one for QE).
2128 [ + + ]: 699589 : if (!expr::hasBoundVar(q[1]))
2129 : : {
2130 : : // This returns true if q is a non-standard quantified formula. Note that
2131 : : // is_std is additionally true if user-pat is strict and q has user
2132 : : // patterns.
2133 : 3142 : return qa.isStandard();
2134 : : }
2135 [ + + ]: 696447 : if (!is_std)
2136 : : {
2137 : 26456 : return false;
2138 : : }
2139 : : // do not miniscope if we have user patterns unless option is set
2140 [ + - ][ + + ]: 669991 : if (!d_opts.quantifiers.miniscopeQuantUser && qa.d_hasPattern)
2141 : : {
2142 : 71734 : return false;
2143 : : }
2144 [ + + ]: 598257 : if (computeOption == COMPUTE_AGGRESSIVE_MINISCOPING)
2145 : : {
2146 : 297220 : return d_opts.quantifiers.miniscopeQuant
2147 : 297220 : == options::MiniscopeQuantMode::AGG;
2148 : : }
2149 : 301037 : return true;
2150 : : }
2151 [ + + ]: 1677240 : else if (computeOption == COMPUTE_EXT_REWRITE)
2152 : : {
2153 : 326886 : return d_opts.quantifiers.extRewriteQuant;
2154 : : }
2155 [ + + ]: 1350360 : else if (computeOption == COMPUTE_PROCESS_TERMS)
2156 : : {
2157 : 347619 : return true;
2158 : : }
2159 [ + + ]: 1002740 : else if (computeOption == COMPUTE_COND_SPLIT)
2160 : : {
2161 : 327321 : return (d_opts.quantifiers.iteDtTesterSplitQuant
2162 [ + - ]: 326625 : || d_opts.quantifiers.condVarSplitQuant
2163 : : != options::CondVarSplitQuantMode::OFF)
2164 [ + + ][ + + ]: 653946 : && !is_strict_trigger;
2165 : : }
2166 [ + + ]: 675418 : else if (computeOption == COMPUTE_PRENEX)
2167 : : {
2168 : : // do not prenex to pull variables into those with user patterns
2169 [ + + ][ + + ]: 338788 : if (!d_opts.quantifiers.prenexQuantUser && qa.d_hasPattern)
2170 : : {
2171 : 35871 : return false;
2172 : : }
2173 [ + + ]: 302917 : if (qa.d_hasPool)
2174 : : {
2175 : 314 : return false;
2176 : : }
2177 : 302603 : return d_opts.quantifiers.prenexQuant != options::PrenexQuantMode::NONE
2178 [ + + ]: 300920 : && d_opts.quantifiers.miniscopeQuant
2179 : : != options::MiniscopeQuantMode::AGG
2180 [ + + ][ + + ]: 603523 : && is_std;
2181 : : }
2182 [ + - ]: 336630 : else if (computeOption == COMPUTE_VAR_ELIMINATION)
2183 : : {
2184 : 336630 : return (d_opts.quantifiers.varElimQuant
2185 [ + - ]: 270 : || d_opts.quantifiers.dtVarExpandQuant)
2186 [ + + ][ + + ]: 336900 : && is_std && !is_strict_trigger;
[ + - ]
2187 : : }
2188 : : else
2189 : : {
2190 : 0 : return false;
2191 : : }
2192 : : }
2193 : :
2194 : : //general method for computing various rewrites
2195 : 1972040 : Node QuantifiersRewriter::computeOperation(Node f,
2196 : : RewriteStep computeOption,
2197 : : QAttributes& qa) const
2198 : : {
2199 [ + - ]: 1972040 : Trace("quantifiers-rewrite-debug") << "Compute operation " << computeOption << " on " << f << " " << qa.d_qid_num << std::endl;
2200 [ + + ]: 1972040 : if (computeOption == COMPUTE_MINISCOPING)
2201 : : {
2202 [ + + ]: 301543 : if (d_opts.quantifiers.prenexQuant == options::PrenexQuantMode::NORMAL)
2203 : : {
2204 [ + + ]: 9 : if( !qa.d_qid_num.isNull() ){
2205 : : //already processed this, return self
2206 : 7 : return f;
2207 : : }
2208 : : }
2209 : 301536 : bool miniscopeConj = doMiniscopeConj(d_opts);
2210 : 301536 : bool miniscopeFv = doMiniscopeFv(d_opts);
2211 : : //return directly
2212 : 301536 : return computeMiniscoping(f, qa, miniscopeConj, miniscopeFv);
2213 : : }
2214 : 5011490 : std::vector<Node> args(f[0].begin(), f[0].end());
2215 : 3340990 : Node n = f[1];
2216 [ + + ]: 1670500 : if (computeOption == COMPUTE_ELIM_SYMBOLS)
2217 : : {
2218 : : // relies on external utility
2219 : 386591 : n = booleans::TheoryBoolRewriter::computeNnfNorm(nodeManager(), n);
2220 : : }
2221 [ + + ]: 1283910 : else if (computeOption == COMPUTE_AGGRESSIVE_MINISCOPING)
2222 : : {
2223 : 304 : return computeAggressiveMiniscoping( args, n );
2224 : : }
2225 [ + + ]: 1283600 : else if (computeOption == COMPUTE_EXT_REWRITE)
2226 : : {
2227 : 28 : return computeExtendedRewrite(f, qa);
2228 : : }
2229 [ + + ]: 1283570 : else if (computeOption == COMPUTE_PROCESS_TERMS)
2230 : : {
2231 : 347619 : n = computeProcessTerms(f, args, n, qa);
2232 : : }
2233 [ + + ]: 935955 : else if (computeOption == COMPUTE_COND_SPLIT)
2234 : : {
2235 : 327277 : n = computeCondSplit(n, args, qa);
2236 : : }
2237 [ + + ]: 608678 : else if (computeOption == COMPUTE_PRENEX)
2238 : : {
2239 [ + + ]: 286592 : if (d_opts.quantifiers.prenexQuant == options::PrenexQuantMode::NORMAL)
2240 : : {
2241 : : //will rewrite at preprocess time
2242 : 9 : return f;
2243 : : }
2244 : : else
2245 : : {
2246 : 573166 : std::unordered_set<Node> argsSet, nargsSet;
2247 : 286583 : n = computePrenex(f, n, argsSet, nargsSet, true, false);
2248 [ - + ][ - + ]: 286583 : Assert(nargsSet.empty());
[ - - ]
2249 : 286583 : args.insert(args.end(), argsSet.begin(), argsSet.end());
2250 : : }
2251 : : }
2252 [ + - ]: 322086 : else if (computeOption == COMPUTE_VAR_ELIMINATION)
2253 : : {
2254 : 322086 : n = computeVarElimination( n, args, qa );
2255 : : }
2256 [ + - ]: 1670160 : Trace("quantifiers-rewrite-debug") << "Compute Operation: return " << n << ", " << args.size() << std::endl;
2257 : 1670160 : if( f[1]==n && args.size()==f[0].getNumChildren() ){
2258 : 1614790 : return f;
2259 : : }else{
2260 [ + + ]: 55368 : if( args.empty() ){
2261 : 2538 : return n;
2262 : : }else{
2263 : 105660 : std::vector< Node > children;
2264 : 52830 : children.push_back(nodeManager()->mkNode(Kind::BOUND_VAR_LIST, args));
2265 : 52830 : children.push_back( n );
2266 [ + + ][ + + ]: 52830 : if( !qa.d_ipl.isNull() && args.size()==f[0].getNumChildren() ){
[ + + ][ + + ]
[ - - ]
2267 : 5909 : children.push_back( qa.d_ipl );
2268 : : }
2269 : 52830 : return nodeManager()->mkNode(Kind::FORALL, children);
2270 : : }
2271 : : }
2272 : : }
2273 : 628813 : bool QuantifiersRewriter::doMiniscopeConj(const Options& opts)
2274 : : {
2275 : 628813 : options::MiniscopeQuantMode mqm = opts.quantifiers.miniscopeQuant;
2276 : : return mqm == options::MiniscopeQuantMode::CONJ_AND_FV
2277 [ + - ]: 28218 : || mqm == options::MiniscopeQuantMode::CONJ
2278 [ + + ][ + + ]: 657031 : || mqm == options::MiniscopeQuantMode::AGG;
2279 : : }
2280 : :
2281 : 301536 : bool QuantifiersRewriter::doMiniscopeFv(const Options& opts)
2282 : : {
2283 : 301536 : options::MiniscopeQuantMode mqm = opts.quantifiers.miniscopeQuant;
2284 : : return mqm == options::MiniscopeQuantMode::CONJ_AND_FV
2285 [ + + ]: 12084 : || mqm == options::MiniscopeQuantMode::FV
2286 [ + + ][ + + ]: 313620 : || mqm == options::MiniscopeQuantMode::AGG;
2287 : : }
2288 : :
2289 : 0 : bool QuantifiersRewriter::isPrenexNormalForm( Node n ) {
2290 [ - - ]: 0 : if (n.getKind() == Kind::FORALL)
2291 : : {
2292 : 0 : return n[1].getKind() != Kind::FORALL && isPrenexNormalForm(n[1]);
2293 : : }
2294 [ - - ]: 0 : else if (n.getKind() == Kind::NOT)
2295 : : {
2296 : 0 : return n[0].getKind() != Kind::NOT && isPrenexNormalForm(n[0]);
2297 : : }
2298 : : else
2299 : : {
2300 : 0 : return !expr::hasClosure(n);
2301 : : }
2302 : : }
2303 : :
2304 : : } // namespace quantifiers
2305 : : } // namespace theory
2306 : : } // namespace cvc5::internal
|