1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Andres Noetzli, Aina Niemetz |
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 |
|
* Implementation of extended rewriting techniques. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/extended_rewrite.h" |
17 |
|
|
18 |
|
#include <sstream> |
19 |
|
|
20 |
|
#include "theory/arith/arith_msum.h" |
21 |
|
#include "theory/bv/theory_bv_utils.h" |
22 |
|
#include "theory/datatypes/datatypes_rewriter.h" |
23 |
|
#include "theory/quantifiers/term_util.h" |
24 |
|
#include "theory/rewriter.h" |
25 |
|
#include "theory/strings/sequences_rewriter.h" |
26 |
|
#include "theory/theory.h" |
27 |
|
|
28 |
|
using namespace cvc5::kind; |
29 |
|
using namespace std; |
30 |
|
|
31 |
|
namespace cvc5 { |
32 |
|
namespace theory { |
33 |
|
namespace quantifiers { |
34 |
|
|
35 |
|
struct ExtRewriteAttributeId |
36 |
|
{ |
37 |
|
}; |
38 |
|
typedef expr::Attribute<ExtRewriteAttributeId, Node> ExtRewriteAttribute; |
39 |
|
|
40 |
|
struct ExtRewriteAggAttributeId |
41 |
|
{ |
42 |
|
}; |
43 |
|
typedef expr::Attribute<ExtRewriteAggAttributeId, Node> ExtRewriteAggAttribute; |
44 |
|
|
45 |
12127 |
ExtendedRewriter::ExtendedRewriter(bool aggr) : d_aggr(aggr) |
46 |
|
{ |
47 |
12127 |
d_true = NodeManager::currentNM()->mkConst(true); |
48 |
12127 |
d_false = NodeManager::currentNM()->mkConst(false); |
49 |
12127 |
} |
50 |
|
|
51 |
371380 |
void ExtendedRewriter::setCache(Node n, Node ret) const |
52 |
|
{ |
53 |
371380 |
if (d_aggr) |
54 |
|
{ |
55 |
|
ExtRewriteAggAttribute erga; |
56 |
370732 |
n.setAttribute(erga, ret); |
57 |
|
} |
58 |
|
else |
59 |
|
{ |
60 |
|
ExtRewriteAttribute era; |
61 |
648 |
n.setAttribute(era, ret); |
62 |
|
} |
63 |
371380 |
} |
64 |
|
|
65 |
825508 |
Node ExtendedRewriter::getCache(Node n) const |
66 |
|
{ |
67 |
825508 |
if (d_aggr) |
68 |
|
{ |
69 |
824996 |
if (n.hasAttribute(ExtRewriteAggAttribute())) |
70 |
|
{ |
71 |
638122 |
return n.getAttribute(ExtRewriteAggAttribute()); |
72 |
|
} |
73 |
|
} |
74 |
|
else |
75 |
|
{ |
76 |
512 |
if (n.hasAttribute(ExtRewriteAttribute())) |
77 |
|
{ |
78 |
188 |
return n.getAttribute(ExtRewriteAttribute()); |
79 |
|
} |
80 |
|
} |
81 |
187198 |
return Node::null(); |
82 |
|
} |
83 |
|
|
84 |
518690 |
bool ExtendedRewriter::addToChildren(Node nc, |
85 |
|
std::vector<Node>& children, |
86 |
|
bool dropDup) const |
87 |
|
{ |
88 |
|
// If the operator is non-additive, do not consider duplicates |
89 |
518690 |
if (dropDup |
90 |
518690 |
&& std::find(children.begin(), children.end(), nc) != children.end()) |
91 |
|
{ |
92 |
773 |
return false; |
93 |
|
} |
94 |
517917 |
children.push_back(nc); |
95 |
517917 |
return true; |
96 |
|
} |
97 |
|
|
98 |
825508 |
Node ExtendedRewriter::extendedRewrite(Node n) const |
99 |
|
{ |
100 |
825508 |
n = Rewriter::rewrite(n); |
101 |
|
|
102 |
|
// has it already been computed? |
103 |
1651016 |
Node ncache = getCache(n); |
104 |
825508 |
if (!ncache.isNull()) |
105 |
|
{ |
106 |
638310 |
return ncache; |
107 |
|
} |
108 |
|
|
109 |
374396 |
Node ret = n; |
110 |
187198 |
NodeManager* nm = NodeManager::currentNM(); |
111 |
|
|
112 |
|
//--------------------pre-rewrite |
113 |
187198 |
if (d_aggr) |
114 |
|
{ |
115 |
370732 |
Node pre_new_ret; |
116 |
186874 |
if (ret.getKind() == IMPLIES) |
117 |
|
{ |
118 |
159 |
pre_new_ret = nm->mkNode(OR, ret[0].negate(), ret[1]); |
119 |
159 |
debugExtendedRewrite(ret, pre_new_ret, "IMPLIES elim"); |
120 |
|
} |
121 |
186715 |
else if (ret.getKind() == XOR) |
122 |
|
{ |
123 |
178 |
pre_new_ret = nm->mkNode(EQUAL, ret[0].negate(), ret[1]); |
124 |
178 |
debugExtendedRewrite(ret, pre_new_ret, "XOR elim"); |
125 |
|
} |
126 |
186537 |
else if (ret.getKind() == NOT) |
127 |
|
{ |
128 |
16155 |
pre_new_ret = extendedRewriteNnf(ret); |
129 |
16155 |
debugExtendedRewrite(ret, pre_new_ret, "NNF"); |
130 |
|
} |
131 |
186874 |
if (!pre_new_ret.isNull()) |
132 |
|
{ |
133 |
3016 |
ret = extendedRewrite(pre_new_ret); |
134 |
|
|
135 |
6032 |
Trace("q-ext-rewrite-debug") |
136 |
3016 |
<< "...ext-pre-rewrite : " << n << " -> " << pre_new_ret << std::endl; |
137 |
3016 |
setCache(n, ret); |
138 |
3016 |
return ret; |
139 |
|
} |
140 |
|
} |
141 |
|
//--------------------end pre-rewrite |
142 |
|
|
143 |
|
//--------------------rewrite children |
144 |
184182 |
if (n.getNumChildren() > 0) |
145 |
|
{ |
146 |
347392 |
std::vector<Node> children; |
147 |
173696 |
if (n.getMetaKind() == metakind::PARAMETERIZED) |
148 |
|
{ |
149 |
4907 |
children.push_back(n.getOperator()); |
150 |
|
} |
151 |
173696 |
Kind k = n.getKind(); |
152 |
173696 |
bool childChanged = false; |
153 |
173696 |
bool isNonAdditive = TermUtil::isNonAdditive(k); |
154 |
|
// We flatten associative operators below, which requires k to be n-ary. |
155 |
173696 |
bool isAssoc = TermUtil::isAssoc(k, true); |
156 |
685419 |
for (unsigned i = 0; i < n.getNumChildren(); i++) |
157 |
|
{ |
158 |
1023446 |
Node nc = extendedRewrite(n[i]); |
159 |
511723 |
childChanged = nc != n[i] || childChanged; |
160 |
511723 |
if (isAssoc && nc.getKind() == n.getKind()) |
161 |
|
{ |
162 |
12033 |
for (const Node& ncc : nc) |
163 |
|
{ |
164 |
9500 |
if (!addToChildren(ncc, children, isNonAdditive)) |
165 |
|
{ |
166 |
9 |
childChanged = true; |
167 |
|
} |
168 |
|
} |
169 |
|
} |
170 |
509190 |
else if (!addToChildren(nc, children, isNonAdditive)) |
171 |
|
{ |
172 |
764 |
childChanged = true; |
173 |
|
} |
174 |
|
} |
175 |
173696 |
Assert(!children.empty()); |
176 |
|
// Some commutative operators have rewriters that are agnostic to order, |
177 |
|
// thus, we sort here. |
178 |
173696 |
if (TermUtil::isComm(k) && (d_aggr || children.size() <= 5)) |
179 |
|
{ |
180 |
111702 |
childChanged = true; |
181 |
111702 |
std::sort(children.begin(), children.end()); |
182 |
|
} |
183 |
173696 |
if (childChanged) |
184 |
|
{ |
185 |
122362 |
if (isNonAdditive && children.size() == 1) |
186 |
|
{ |
187 |
|
// we may have subsumed children down to one |
188 |
26 |
ret = children[0]; |
189 |
|
} |
190 |
122336 |
else if (isAssoc |
191 |
122336 |
&& children.size() > kind::metakind::getMaxArityForKind(k)) |
192 |
|
{ |
193 |
2 |
Assert(kind::metakind::getMaxArityForKind(k) >= 2); |
194 |
|
// kind may require binary construction |
195 |
2 |
ret = children[0]; |
196 |
6 |
for (unsigned i = 1, nchild = children.size(); i < nchild; i++) |
197 |
|
{ |
198 |
4 |
ret = nm->mkNode(k, ret, children[i]); |
199 |
|
} |
200 |
|
} |
201 |
|
else |
202 |
|
{ |
203 |
122334 |
ret = nm->mkNode(k, children); |
204 |
|
} |
205 |
|
} |
206 |
|
} |
207 |
184182 |
ret = Rewriter::rewrite(ret); |
208 |
|
//--------------------end rewrite children |
209 |
|
|
210 |
|
// now, do extended rewrite |
211 |
368364 |
Trace("q-ext-rewrite-debug") << "Do extended rewrite on : " << ret |
212 |
184182 |
<< " (from " << n << ")" << std::endl; |
213 |
368364 |
Node new_ret; |
214 |
|
|
215 |
|
//---------------------- theory-independent post-rewriting |
216 |
184182 |
if (ret.getKind() == ITE) |
217 |
|
{ |
218 |
14646 |
new_ret = extendedRewriteIte(ITE, ret); |
219 |
|
} |
220 |
169536 |
else if (ret.getKind() == AND || ret.getKind() == OR) |
221 |
|
{ |
222 |
50593 |
new_ret = extendedRewriteAndOr(ret); |
223 |
|
} |
224 |
118943 |
else if (ret.getKind() == EQUAL) |
225 |
|
{ |
226 |
25494 |
new_ret = extendedRewriteEqChain(EQUAL, AND, OR, NOT, ret); |
227 |
25494 |
debugExtendedRewrite(ret, new_ret, "Bool eq-chain simplify"); |
228 |
|
} |
229 |
184182 |
Assert(new_ret.isNull() || new_ret != ret); |
230 |
184182 |
if (new_ret.isNull() && ret.getKind() != ITE) |
231 |
|
{ |
232 |
|
// simple ITE pulling |
233 |
160627 |
new_ret = extendedRewritePullIte(ITE, ret); |
234 |
|
} |
235 |
|
//----------------------end theory-independent post-rewriting |
236 |
|
|
237 |
|
//----------------------theory-specific post-rewriting |
238 |
184182 |
if (new_ret.isNull()) |
239 |
|
{ |
240 |
|
TheoryId tid; |
241 |
161646 |
if (ret.getKind() == ITE) |
242 |
|
{ |
243 |
13457 |
tid = Theory::theoryOf(ret.getType()); |
244 |
|
} |
245 |
|
else |
246 |
|
{ |
247 |
148189 |
tid = Theory::theoryOf(ret); |
248 |
|
} |
249 |
323292 |
Trace("q-ext-rewrite-debug") << "theoryOf( " << ret << " )= " << tid |
250 |
161646 |
<< std::endl; |
251 |
161646 |
if (tid == THEORY_STRINGS) |
252 |
|
{ |
253 |
1660 |
new_ret = extendedRewriteStrings(ret); |
254 |
|
} |
255 |
|
} |
256 |
|
//----------------------end theory-specific post-rewriting |
257 |
|
|
258 |
|
//----------------------aggressive rewrites |
259 |
184182 |
if (new_ret.isNull() && d_aggr) |
260 |
|
{ |
261 |
161035 |
new_ret = extendedRewriteAggr(ret); |
262 |
|
} |
263 |
|
//----------------------end aggressive rewrites |
264 |
|
|
265 |
184182 |
setCache(n, ret); |
266 |
184182 |
if (!new_ret.isNull()) |
267 |
|
{ |
268 |
23910 |
ret = extendedRewrite(new_ret); |
269 |
|
} |
270 |
368364 |
Trace("q-ext-rewrite-debug") << "...ext-rewrite : " << n << " -> " << ret |
271 |
184182 |
<< std::endl; |
272 |
184182 |
if (Trace.isOn("q-ext-rewrite-nf")) |
273 |
|
{ |
274 |
|
if (n == ret) |
275 |
|
{ |
276 |
|
Trace("q-ext-rewrite-nf") << "ext-rew normal form : " << n << std::endl; |
277 |
|
} |
278 |
|
} |
279 |
184182 |
setCache(n, ret); |
280 |
184182 |
return ret; |
281 |
|
} |
282 |
|
|
283 |
161035 |
Node ExtendedRewriter::extendedRewriteAggr(Node n) const |
284 |
|
{ |
285 |
161035 |
Node new_ret; |
286 |
322070 |
Trace("q-ext-rewrite-debug2") |
287 |
161035 |
<< "Do aggressive rewrites on " << n << std::endl; |
288 |
161035 |
bool polarity = n.getKind() != NOT; |
289 |
322070 |
Node ret_atom = n.getKind() == NOT ? n[0] : n; |
290 |
342900 |
if ((ret_atom.getKind() == EQUAL && ret_atom[0].getType().isReal()) |
291 |
470889 |
|| ret_atom.getKind() == GEQ) |
292 |
|
{ |
293 |
|
// ITE term removal in polynomials |
294 |
|
// e.g. ite( x=0, x, y ) = x+1 ---> ( x=0 ^ y = x+1 ) |
295 |
64964 |
Trace("q-ext-rewrite-debug2") |
296 |
32482 |
<< "Compute monomial sum " << ret_atom << std::endl; |
297 |
|
// compute monomial sum |
298 |
64964 |
std::map<Node, Node> msum; |
299 |
32482 |
if (ArithMSum::getMonomialSumLit(ret_atom, msum)) |
300 |
|
{ |
301 |
108557 |
for (std::map<Node, Node>::iterator itm = msum.begin(); itm != msum.end(); |
302 |
|
++itm) |
303 |
|
{ |
304 |
153231 |
Node v = itm->first; |
305 |
154312 |
Trace("q-ext-rewrite-debug2") |
306 |
77156 |
<< itm->first << " * " << itm->second << std::endl; |
307 |
77156 |
if (v.getKind() == ITE) |
308 |
|
{ |
309 |
14401 |
Node veq; |
310 |
7741 |
int res = ArithMSum::isolate(v, msum, veq, ret_atom.getKind()); |
311 |
7741 |
if (res != 0) |
312 |
|
{ |
313 |
15476 |
Trace("q-ext-rewrite-debug") |
314 |
7738 |
<< " have ITE relation, solved form : " << veq << std::endl; |
315 |
|
// try pulling ITE |
316 |
7738 |
new_ret = extendedRewritePullIte(ITE, veq); |
317 |
7738 |
if (!new_ret.isNull()) |
318 |
|
{ |
319 |
1081 |
if (!polarity) |
320 |
|
{ |
321 |
|
new_ret = new_ret.negate(); |
322 |
|
} |
323 |
1081 |
break; |
324 |
|
} |
325 |
|
} |
326 |
|
else |
327 |
|
{ |
328 |
6 |
Trace("q-ext-rewrite-debug") |
329 |
3 |
<< " failed to isolate " << v << " in " << n << std::endl; |
330 |
|
} |
331 |
|
} |
332 |
|
} |
333 |
|
} |
334 |
|
else |
335 |
|
{ |
336 |
|
Trace("q-ext-rewrite-debug") |
337 |
|
<< " failed to get monomial sum of " << n << std::endl; |
338 |
|
} |
339 |
|
} |
340 |
|
// TODO (#1706) : conditional rewriting, condition merging |
341 |
322070 |
return new_ret; |
342 |
|
} |
343 |
|
|
344 |
30615 |
Node ExtendedRewriter::extendedRewriteIte(Kind itek, Node n, bool full) const |
345 |
|
{ |
346 |
30615 |
Assert(n.getKind() == itek); |
347 |
30615 |
Assert(n[1] != n[2]); |
348 |
|
|
349 |
30615 |
NodeManager* nm = NodeManager::currentNM(); |
350 |
|
|
351 |
30615 |
Trace("ext-rew-ite") << "Rewrite ITE : " << n << std::endl; |
352 |
|
|
353 |
61230 |
Node flip_cond; |
354 |
30615 |
if (n[0].getKind() == NOT) |
355 |
|
{ |
356 |
|
flip_cond = n[0][0]; |
357 |
|
} |
358 |
30615 |
else if (n[0].getKind() == OR) |
359 |
|
{ |
360 |
|
// a | b ---> ~( ~a & ~b ) |
361 |
106 |
flip_cond = TermUtil::simpleNegate(n[0]); |
362 |
|
} |
363 |
30615 |
if (!flip_cond.isNull()) |
364 |
|
{ |
365 |
212 |
Node new_ret = nm->mkNode(ITE, flip_cond, n[2], n[1]); |
366 |
|
// only print debug trace if full=true |
367 |
106 |
if (full) |
368 |
|
{ |
369 |
106 |
debugExtendedRewrite(n, new_ret, "ITE flip"); |
370 |
|
} |
371 |
106 |
return new_ret; |
372 |
|
} |
373 |
|
// Boolean true/false return |
374 |
61018 |
TypeNode tn = n.getType(); |
375 |
30509 |
if (tn.isBoolean()) |
376 |
|
{ |
377 |
52773 |
for (unsigned i = 1; i <= 2; i++) |
378 |
|
{ |
379 |
35182 |
if (n[i].isConst()) |
380 |
|
{ |
381 |
|
Node cond = i == 1 ? n[0] : n[0].negate(); |
382 |
|
Node other = n[i == 1 ? 2 : 1]; |
383 |
|
Kind retk = AND; |
384 |
|
if (n[i].getConst<bool>()) |
385 |
|
{ |
386 |
|
retk = OR; |
387 |
|
} |
388 |
|
else |
389 |
|
{ |
390 |
|
cond = cond.negate(); |
391 |
|
} |
392 |
|
Node new_ret = nm->mkNode(retk, cond, other); |
393 |
|
if (full) |
394 |
|
{ |
395 |
|
// ite( A, true, B ) ---> A V B |
396 |
|
// ite( A, false, B ) ---> ~A /\ B |
397 |
|
// ite( A, B, true ) ---> ~A V B |
398 |
|
// ite( A, B, false ) ---> A /\ B |
399 |
|
debugExtendedRewrite(n, new_ret, "ITE const return"); |
400 |
|
} |
401 |
|
return new_ret; |
402 |
|
} |
403 |
|
} |
404 |
|
} |
405 |
|
|
406 |
|
// get entailed equalities in the condition |
407 |
61018 |
std::vector<Node> eq_conds; |
408 |
30509 |
Kind ck = n[0].getKind(); |
409 |
30509 |
if (ck == EQUAL) |
410 |
|
{ |
411 |
10859 |
eq_conds.push_back(n[0]); |
412 |
|
} |
413 |
19650 |
else if (ck == AND) |
414 |
|
{ |
415 |
22289 |
for (const Node& cn : n[0]) |
416 |
|
{ |
417 |
18497 |
if (cn.getKind() == EQUAL) |
418 |
|
{ |
419 |
412 |
eq_conds.push_back(cn); |
420 |
|
} |
421 |
|
} |
422 |
|
} |
423 |
|
|
424 |
61018 |
Node new_ret; |
425 |
61018 |
Node b; |
426 |
61018 |
Node e; |
427 |
61018 |
Node t1 = n[1]; |
428 |
61018 |
Node t2 = n[2]; |
429 |
61018 |
std::stringstream ss_reason; |
430 |
|
|
431 |
41709 |
for (const Node& eq : eq_conds) |
432 |
|
{ |
433 |
|
// simple invariant ITE |
434 |
33701 |
for (unsigned i = 0; i <= 1; i++) |
435 |
|
{ |
436 |
|
// ite( x = y ^ C, y, x ) ---> x |
437 |
|
// this is subsumed by the rewrites below |
438 |
22501 |
if (t2 == eq[i] && t1 == eq[1 - i]) |
439 |
|
{ |
440 |
69 |
new_ret = t2; |
441 |
69 |
ss_reason << "ITE simple rev subs"; |
442 |
69 |
break; |
443 |
|
} |
444 |
|
} |
445 |
11269 |
if (!new_ret.isNull()) |
446 |
|
{ |
447 |
69 |
break; |
448 |
|
} |
449 |
|
} |
450 |
30509 |
if (new_ret.isNull()) |
451 |
|
{ |
452 |
|
// merging branches |
453 |
91020 |
for (unsigned i = 1; i <= 2; i++) |
454 |
|
{ |
455 |
60792 |
if (n[i].getKind() == ITE) |
456 |
|
{ |
457 |
4804 |
Node no = n[3 - i]; |
458 |
6902 |
for (unsigned j = 1; j <= 2; j++) |
459 |
|
{ |
460 |
4712 |
if (n[i][j] == no) |
461 |
|
{ |
462 |
|
// e.g. |
463 |
|
// ite( C1, ite( C2, t1, t2 ), t1 ) ----> ite( C1 ^ ~C2, t2, t1 ) |
464 |
424 |
Node nc1 = i == 2 ? n[0].negate() : n[0]; |
465 |
424 |
Node nc2 = j == 1 ? n[i][0].negate() : n[i][0]; |
466 |
424 |
Node new_cond = nm->mkNode(AND, nc1, nc2); |
467 |
212 |
new_ret = nm->mkNode(ITE, new_cond, n[i][3 - j], no); |
468 |
212 |
ss_reason << "ITE merge branch"; |
469 |
212 |
break; |
470 |
|
} |
471 |
|
} |
472 |
|
} |
473 |
60792 |
if (!new_ret.isNull()) |
474 |
|
{ |
475 |
212 |
break; |
476 |
|
} |
477 |
|
} |
478 |
|
} |
479 |
|
|
480 |
30509 |
if (new_ret.isNull() && d_aggr) |
481 |
|
{ |
482 |
|
// If x is less than t based on an ordering, then we use { x -> t } as a |
483 |
|
// substitution to the children of ite( x = t ^ C, s, t ) below. |
484 |
60448 |
std::vector<Node> vars; |
485 |
60448 |
std::vector<Node> subs; |
486 |
30224 |
inferSubstitution(n[0], vars, subs, true); |
487 |
|
|
488 |
30224 |
if (!vars.empty()) |
489 |
|
{ |
490 |
|
// reverse substitution to opposite child |
491 |
|
// r{ x -> t } = s implies ite( x=t ^ C, s, r ) ---> r |
492 |
|
// We can use ordinary substitute since the result of the substitution |
493 |
|
// is not being returned. In other words, nn is only being used to query |
494 |
|
// whether the second branch is a generalization of the first. |
495 |
|
Node nn = |
496 |
60448 |
t2.substitute(vars.begin(), vars.end(), subs.begin(), subs.end()); |
497 |
30224 |
if (nn != t2) |
498 |
|
{ |
499 |
7790 |
nn = Rewriter::rewrite(nn); |
500 |
7790 |
if (nn == t1) |
501 |
|
{ |
502 |
8 |
new_ret = t2; |
503 |
8 |
ss_reason << "ITE rev subs"; |
504 |
|
} |
505 |
|
} |
506 |
|
|
507 |
|
// ite( x=t ^ C, s, r ) ---> ite( x=t ^ C, s{ x -> t }, r ) |
508 |
|
// must use partial substitute here, to avoid substitution into witness |
509 |
60448 |
std::map<Kind, bool> rkinds; |
510 |
30224 |
nn = partialSubstitute(t1, vars, subs, rkinds); |
511 |
30224 |
nn = Rewriter::rewrite(nn); |
512 |
30224 |
if (nn != t1) |
513 |
|
{ |
514 |
|
// If full=false, then we've duplicated a term u in the children of n. |
515 |
|
// For example, when ITE pulling, we have n is of the form: |
516 |
|
// ite( C, f( u, t1 ), f( u, t2 ) ) |
517 |
|
// We must show that at least one copy of u dissappears in this case. |
518 |
5162 |
if (nn == t2) |
519 |
|
{ |
520 |
19 |
new_ret = nn; |
521 |
19 |
ss_reason << "ITE subs invariant"; |
522 |
|
} |
523 |
5143 |
else if (full || nn.isConst()) |
524 |
|
{ |
525 |
749 |
new_ret = nm->mkNode(itek, n[0], nn, t2); |
526 |
749 |
ss_reason << "ITE subs"; |
527 |
|
} |
528 |
|
} |
529 |
|
} |
530 |
30224 |
if (new_ret.isNull()) |
531 |
|
{ |
532 |
|
// ite( C, t, s ) ----> ite( C, t, s { C -> false } ) |
533 |
|
// use partial substitute to avoid substitution into witness |
534 |
58896 |
std::map<Node, Node> assign; |
535 |
29448 |
assign[n[0]] = d_false; |
536 |
58896 |
std::map<Kind, bool> rkinds; |
537 |
58896 |
Node nn = partialSubstitute(t2, assign, rkinds); |
538 |
29448 |
if (nn != t2) |
539 |
|
{ |
540 |
3791 |
nn = Rewriter::rewrite(nn); |
541 |
3791 |
if (nn == t1) |
542 |
|
{ |
543 |
2 |
new_ret = nn; |
544 |
2 |
ss_reason << "ITE subs invariant false"; |
545 |
|
} |
546 |
3789 |
else if (full || nn.isConst()) |
547 |
|
{ |
548 |
186 |
new_ret = nm->mkNode(itek, n[0], t1, nn); |
549 |
186 |
ss_reason << "ITE subs false"; |
550 |
|
} |
551 |
|
} |
552 |
|
} |
553 |
|
} |
554 |
|
|
555 |
|
// only print debug trace if full=true |
556 |
30509 |
if (!new_ret.isNull() && full) |
557 |
|
{ |
558 |
1083 |
debugExtendedRewrite(n, new_ret, ss_reason.str().c_str()); |
559 |
|
} |
560 |
|
|
561 |
30509 |
return new_ret; |
562 |
|
} |
563 |
|
|
564 |
50593 |
Node ExtendedRewriter::extendedRewriteAndOr(Node n) const |
565 |
|
{ |
566 |
|
// all the below rewrites are aggressive |
567 |
50593 |
if (!d_aggr) |
568 |
|
{ |
569 |
18 |
return Node::null(); |
570 |
|
} |
571 |
101150 |
Node new_ret; |
572 |
|
// we allow substitutions to recurse over any kind, except WITNESS which is |
573 |
|
// managed by partialSubstitute. |
574 |
101150 |
std::map<Kind, bool> bcp_kinds; |
575 |
50575 |
new_ret = extendedRewriteBcp(AND, OR, NOT, bcp_kinds, n); |
576 |
50575 |
if (!new_ret.isNull()) |
577 |
|
{ |
578 |
1944 |
debugExtendedRewrite(n, new_ret, "Bool bcp"); |
579 |
1944 |
return new_ret; |
580 |
|
} |
581 |
|
// factoring |
582 |
48631 |
new_ret = extendedRewriteFactoring(AND, OR, NOT, n); |
583 |
48631 |
if (!new_ret.isNull()) |
584 |
|
{ |
585 |
3511 |
debugExtendedRewrite(n, new_ret, "Bool factoring"); |
586 |
3511 |
return new_ret; |
587 |
|
} |
588 |
|
|
589 |
|
// equality resolution |
590 |
45120 |
new_ret = extendedRewriteEqRes(AND, OR, EQUAL, NOT, bcp_kinds, n, false); |
591 |
45120 |
debugExtendedRewrite(n, new_ret, "Bool eq res"); |
592 |
45120 |
return new_ret; |
593 |
|
} |
594 |
|
|
595 |
168365 |
Node ExtendedRewriter::extendedRewritePullIte(Kind itek, Node n) const |
596 |
|
{ |
597 |
168365 |
Assert(n.getKind() != ITE); |
598 |
168365 |
if (n.isClosure()) |
599 |
|
{ |
600 |
|
// don't pull ITE out of quantifiers |
601 |
164 |
return n; |
602 |
|
} |
603 |
168201 |
NodeManager* nm = NodeManager::currentNM(); |
604 |
336402 |
TypeNode tn = n.getType(); |
605 |
336402 |
std::vector<Node> children; |
606 |
168201 |
bool hasOp = (n.getMetaKind() == metakind::PARAMETERIZED); |
607 |
168201 |
if (hasOp) |
608 |
|
{ |
609 |
4936 |
children.push_back(n.getOperator()); |
610 |
|
} |
611 |
168201 |
unsigned nchildren = n.getNumChildren(); |
612 |
578817 |
for (unsigned i = 0; i < nchildren; i++) |
613 |
|
{ |
614 |
410616 |
children.push_back(n[i]); |
615 |
|
} |
616 |
336402 |
std::map<unsigned, std::map<unsigned, Node> > ite_c; |
617 |
560502 |
for (unsigned i = 0; i < nchildren; i++) |
618 |
|
{ |
619 |
|
// only pull ITEs apart if we are aggressive |
620 |
1215978 |
if (n[i].getKind() == itek |
621 |
1215978 |
&& (d_aggr || (n[i][1].getKind() != ITE && n[i][2].getKind() != ITE))) |
622 |
|
{ |
623 |
29174 |
unsigned ii = hasOp ? i + 1 : i; |
624 |
87522 |
for (unsigned j = 0; j < 2; j++) |
625 |
|
{ |
626 |
58348 |
children[ii] = n[i][j + 1]; |
627 |
116696 |
Node pull = nm->mkNode(n.getKind(), children); |
628 |
116696 |
Node pullr = Rewriter::rewrite(pull); |
629 |
58348 |
children[ii] = n[i]; |
630 |
58348 |
ite_c[i][j] = pullr; |
631 |
|
} |
632 |
29174 |
if (ite_c[i][0] == ite_c[i][1]) |
633 |
|
{ |
634 |
|
// ITE dual invariance |
635 |
|
// f( t1..s1..tn ) ---> t and f( t1..s2..tn ) ---> t implies |
636 |
|
// f( t1..ite( A, s1, s2 )..tn ) ---> t |
637 |
762 |
debugExtendedRewrite(n, ite_c[i][0], "ITE dual invariant"); |
638 |
762 |
return ite_c[i][0]; |
639 |
|
} |
640 |
28412 |
if (d_aggr) |
641 |
|
{ |
642 |
51857 |
if (nchildren == 2 && (n[1 - i].isVar() || n[1 - i].isConst()) |
643 |
42821 |
&& !n[1 - i].getType().isBoolean() && tn.isBoolean()) |
644 |
|
{ |
645 |
|
// always pull variable or constant with binary (theory) predicate |
646 |
|
// e.g. P( x, ite( A, t1, t2 ) ) ---> ite( A, P( x, t1 ), P( x, t2 ) ) |
647 |
18460 |
Node new_ret = nm->mkNode(ITE, n[i][0], ite_c[i][0], ite_c[i][1]); |
648 |
9230 |
debugExtendedRewrite(n, new_ret, "ITE pull var predicate"); |
649 |
9230 |
return new_ret; |
650 |
|
} |
651 |
52910 |
for (unsigned j = 0; j < 2; j++) |
652 |
|
{ |
653 |
70493 |
Node pullr = ite_c[i][j]; |
654 |
36763 |
if (pullr.isConst() || pullr == n[i][j + 1]) |
655 |
|
{ |
656 |
|
// ITE single child elimination |
657 |
|
// f( t1..s1..tn ) ---> t where t is a constant or s1 itself |
658 |
|
// implies |
659 |
|
// f( t1..ite( A, s1, s2 )..tn ) ---> ite( A, t, f( t1..s2..tn ) ) |
660 |
6066 |
Node new_ret; |
661 |
3033 |
if (tn.isBoolean() && pullr.isConst()) |
662 |
|
{ |
663 |
|
// remove false/true child immediately |
664 |
830 |
bool pol = pullr.getConst<bool>(); |
665 |
1660 |
std::vector<Node> new_children; |
666 |
830 |
new_children.push_back((j == 0) == pol ? n[i][0] |
667 |
|
: n[i][0].negate()); |
668 |
830 |
new_children.push_back(ite_c[i][1 - j]); |
669 |
830 |
new_ret = nm->mkNode(pol ? OR : AND, new_children); |
670 |
830 |
debugExtendedRewrite(n, new_ret, "ITE Bool single elim"); |
671 |
|
} |
672 |
|
else |
673 |
|
{ |
674 |
2203 |
new_ret = nm->mkNode(itek, n[i][0], ite_c[i][0], ite_c[i][1]); |
675 |
2203 |
debugExtendedRewrite(n, new_ret, "ITE single elim"); |
676 |
|
} |
677 |
3033 |
return new_ret; |
678 |
|
} |
679 |
|
} |
680 |
|
} |
681 |
|
} |
682 |
|
} |
683 |
155176 |
if (d_aggr) |
684 |
|
{ |
685 |
170667 |
for (std::pair<const unsigned, std::map<unsigned, Node> >& ip : ite_c) |
686 |
|
{ |
687 |
31944 |
Node nite = n[ip.first]; |
688 |
16137 |
Assert(nite.getKind() == itek); |
689 |
|
// now, simply pull the ITE and try ITE rewrites |
690 |
31944 |
Node pull_ite = nm->mkNode(itek, nite[0], ip.second[0], ip.second[1]); |
691 |
16137 |
pull_ite = Rewriter::rewrite(pull_ite); |
692 |
16137 |
if (pull_ite.getKind() == ITE) |
693 |
|
{ |
694 |
31776 |
Node new_pull_ite = extendedRewriteIte(itek, pull_ite, false); |
695 |
15969 |
if (!new_pull_ite.isNull()) |
696 |
|
{ |
697 |
162 |
debugExtendedRewrite(n, new_pull_ite, "ITE pull rewrite"); |
698 |
162 |
return new_pull_ite; |
699 |
|
} |
700 |
|
} |
701 |
|
else |
702 |
|
{ |
703 |
|
// A general rewrite could eliminate the ITE by pulling. |
704 |
|
// An example is: |
705 |
|
// ~( ite( C, ~x, ~ite( C, y, x ) ) ) ---> |
706 |
|
// ite( C, ~~x, ite( C, y, x ) ) ---> |
707 |
|
// x |
708 |
|
// where ~ is bitvector negation. |
709 |
168 |
debugExtendedRewrite(n, pull_ite, "ITE pull basic elim"); |
710 |
168 |
return pull_ite; |
711 |
|
} |
712 |
|
} |
713 |
|
} |
714 |
|
|
715 |
154846 |
return Node::null(); |
716 |
|
} |
717 |
|
|
718 |
16155 |
Node ExtendedRewriter::extendedRewriteNnf(Node ret) const |
719 |
|
{ |
720 |
16155 |
Assert(ret.getKind() == NOT); |
721 |
|
|
722 |
16155 |
Kind nk = ret[0].getKind(); |
723 |
16155 |
bool neg_ch = false; |
724 |
16155 |
bool neg_ch_1 = false; |
725 |
16155 |
if (nk == AND || nk == OR) |
726 |
|
{ |
727 |
2427 |
neg_ch = true; |
728 |
2427 |
nk = nk == AND ? OR : AND; |
729 |
|
} |
730 |
13728 |
else if (nk == IMPLIES) |
731 |
|
{ |
732 |
30 |
neg_ch = true; |
733 |
30 |
neg_ch_1 = true; |
734 |
30 |
nk = AND; |
735 |
|
} |
736 |
13698 |
else if (nk == ITE) |
737 |
|
{ |
738 |
157 |
neg_ch = true; |
739 |
157 |
neg_ch_1 = true; |
740 |
|
} |
741 |
13541 |
else if (nk == XOR) |
742 |
|
{ |
743 |
35 |
nk = EQUAL; |
744 |
|
} |
745 |
13506 |
else if (nk == EQUAL && ret[0][0].getType().isBoolean()) |
746 |
|
{ |
747 |
30 |
neg_ch_1 = true; |
748 |
|
} |
749 |
|
else |
750 |
|
{ |
751 |
13476 |
return Node::null(); |
752 |
|
} |
753 |
|
|
754 |
5358 |
std::vector<Node> new_children; |
755 |
9223 |
for (unsigned i = 0, nchild = ret[0].getNumChildren(); i < nchild; i++) |
756 |
|
{ |
757 |
13088 |
Node c = ret[0][i]; |
758 |
6544 |
c = (i == 0 ? neg_ch_1 : false) != neg_ch ? c.negate() : c; |
759 |
6544 |
new_children.push_back(c); |
760 |
|
} |
761 |
2679 |
return NodeManager::currentNM()->mkNode(nk, new_children); |
762 |
|
} |
763 |
|
|
764 |
50575 |
Node ExtendedRewriter::extendedRewriteBcp(Kind andk, |
765 |
|
Kind ork, |
766 |
|
Kind notk, |
767 |
|
std::map<Kind, bool>& bcp_kinds, |
768 |
|
Node ret) const |
769 |
|
{ |
770 |
50575 |
Kind k = ret.getKind(); |
771 |
50575 |
Assert(k == andk || k == ork); |
772 |
50575 |
Trace("ext-rew-bcp") << "BCP: **** INPUT: " << ret << std::endl; |
773 |
|
|
774 |
50575 |
NodeManager* nm = NodeManager::currentNM(); |
775 |
|
|
776 |
101150 |
TypeNode tn = ret.getType(); |
777 |
101150 |
Node truen = TermUtil::mkTypeMaxValue(tn); |
778 |
101150 |
Node falsen = TermUtil::mkTypeValue(tn, 0); |
779 |
|
|
780 |
|
// terms to process |
781 |
101150 |
std::vector<Node> to_process; |
782 |
313867 |
for (const Node& cn : ret) |
783 |
|
{ |
784 |
263292 |
to_process.push_back(cn); |
785 |
|
} |
786 |
|
// the processing terms |
787 |
101150 |
std::vector<Node> clauses; |
788 |
|
// the terms we have propagated information to |
789 |
101150 |
std::unordered_set<Node> prop_clauses; |
790 |
|
// the assignment |
791 |
101150 |
std::map<Node, Node> assign; |
792 |
101150 |
std::vector<Node> avars; |
793 |
101150 |
std::vector<Node> asubs; |
794 |
|
|
795 |
50575 |
Kind ok = k == andk ? ork : andk; |
796 |
|
// global polarity : when k=ork, everything is negated |
797 |
50575 |
bool gpol = k == andk; |
798 |
|
|
799 |
1694 |
do |
800 |
|
{ |
801 |
|
// process the current nodes |
802 |
156419 |
while (!to_process.empty()) |
803 |
|
{ |
804 |
104474 |
std::vector<Node> new_to_process; |
805 |
317709 |
for (const Node& cn : to_process) |
806 |
|
{ |
807 |
265634 |
Trace("ext-rew-bcp-debug") << "process " << cn << std::endl; |
808 |
265634 |
Kind cnk = cn.getKind(); |
809 |
265634 |
bool pol = cnk != notk; |
810 |
530944 |
Node cln = cnk == notk ? cn[0] : cn; |
811 |
265634 |
Assert(cln.getKind() != notk); |
812 |
265634 |
if ((pol && cln.getKind() == k) || (!pol && cln.getKind() == ok)) |
813 |
|
{ |
814 |
|
// flatten |
815 |
449 |
for (const Node& ccln : cln) |
816 |
|
{ |
817 |
638 |
Node lccln = pol ? ccln : TermUtil::mkNegate(notk, ccln); |
818 |
319 |
new_to_process.push_back(lccln); |
819 |
|
} |
820 |
|
} |
821 |
|
else |
822 |
|
{ |
823 |
|
// add it to the assignment |
824 |
530684 |
Node val = gpol == pol ? truen : falsen; |
825 |
265504 |
std::map<Node, Node>::iterator it = assign.find(cln); |
826 |
531008 |
Trace("ext-rew-bcp") << "BCP: assign " << cln << " -> " << val |
827 |
265504 |
<< std::endl; |
828 |
265504 |
if (it != assign.end()) |
829 |
|
{ |
830 |
362 |
if (val != it->second) |
831 |
|
{ |
832 |
324 |
Trace("ext-rew-bcp") << "BCP: conflict!" << std::endl; |
833 |
|
// a conflicting assignment: we are done |
834 |
324 |
return gpol ? falsen : truen; |
835 |
|
} |
836 |
|
} |
837 |
|
else |
838 |
|
{ |
839 |
265142 |
assign[cln] = val; |
840 |
265142 |
avars.push_back(cln); |
841 |
265142 |
asubs.push_back(val); |
842 |
|
} |
843 |
|
|
844 |
|
// also, treat it as clause if possible |
845 |
530360 |
if (cln.getNumChildren() > 0 |
846 |
489615 |
&& (bcp_kinds.empty() |
847 |
265180 |
|| bcp_kinds.find(cln.getKind()) != bcp_kinds.end())) |
848 |
|
{ |
849 |
448870 |
if (std::find(clauses.begin(), clauses.end(), cn) == clauses.end() |
850 |
224435 |
&& prop_clauses.find(cn) == prop_clauses.end()) |
851 |
|
{ |
852 |
224435 |
Trace("ext-rew-bcp") << "BCP: new clause: " << cn << std::endl; |
853 |
224435 |
clauses.push_back(cn); |
854 |
|
} |
855 |
|
} |
856 |
|
} |
857 |
|
} |
858 |
52075 |
to_process.clear(); |
859 |
52075 |
to_process.insert( |
860 |
104150 |
to_process.end(), new_to_process.begin(), new_to_process.end()); |
861 |
|
} |
862 |
|
|
863 |
|
// apply substitution to all subterms of clauses |
864 |
103890 |
std::vector<Node> new_clauses; |
865 |
284855 |
for (const Node& c : clauses) |
866 |
|
{ |
867 |
232910 |
bool cpol = c.getKind() != notk; |
868 |
465820 |
Node ca = c.getKind() == notk ? c[0] : c; |
869 |
232910 |
bool childChanged = false; |
870 |
465820 |
std::vector<Node> ccs_children; |
871 |
819033 |
for (const Node& cc : ca) |
872 |
|
{ |
873 |
|
// always use partial substitute, to avoid substitution in witness |
874 |
586123 |
Trace("ext-rew-bcp-debug") << "...do partial substitute" << std::endl; |
875 |
|
// substitution is only applicable to compatible kinds in bcp_kinds |
876 |
1172246 |
Node ccs = partialSubstitute(cc, assign, bcp_kinds); |
877 |
586123 |
childChanged = childChanged || ccs != cc; |
878 |
586123 |
ccs_children.push_back(ccs); |
879 |
|
} |
880 |
232910 |
if (childChanged) |
881 |
|
{ |
882 |
2335 |
if (ca.getMetaKind() == metakind::PARAMETERIZED) |
883 |
|
{ |
884 |
4 |
ccs_children.insert(ccs_children.begin(), ca.getOperator()); |
885 |
|
} |
886 |
4670 |
Node ccs = nm->mkNode(ca.getKind(), ccs_children); |
887 |
2335 |
ccs = cpol ? ccs : TermUtil::mkNegate(notk, ccs); |
888 |
4670 |
Trace("ext-rew-bcp") << "BCP: propagated " << c << " -> " << ccs |
889 |
2335 |
<< std::endl; |
890 |
2335 |
ccs = Rewriter::rewrite(ccs); |
891 |
2335 |
Trace("ext-rew-bcp") << "BCP: rewritten to " << ccs << std::endl; |
892 |
2335 |
to_process.push_back(ccs); |
893 |
|
// store this as a node that propagation touched. This marks c so that |
894 |
|
// it will not be included in the final construction. |
895 |
2335 |
prop_clauses.insert(ca); |
896 |
|
} |
897 |
|
else |
898 |
|
{ |
899 |
230575 |
new_clauses.push_back(c); |
900 |
|
} |
901 |
|
} |
902 |
51945 |
clauses.clear(); |
903 |
51945 |
clauses.insert(clauses.end(), new_clauses.begin(), new_clauses.end()); |
904 |
51945 |
} while (!to_process.empty()); |
905 |
|
|
906 |
|
// remake the node |
907 |
50251 |
if (!prop_clauses.empty()) |
908 |
|
{ |
909 |
3240 |
std::vector<Node> children; |
910 |
16281 |
for (std::pair<const Node, Node>& l : assign) |
911 |
|
{ |
912 |
29322 |
Node a = l.first; |
913 |
|
// if propagation did not touch a |
914 |
14661 |
if (prop_clauses.find(a) == prop_clauses.end()) |
915 |
|
{ |
916 |
12328 |
Assert(l.second == truen || l.second == falsen); |
917 |
24656 |
Node ln = (l.second == truen) == gpol ? a : TermUtil::mkNegate(notk, a); |
918 |
12328 |
children.push_back(ln); |
919 |
|
} |
920 |
|
} |
921 |
3240 |
Node new_ret = children.size() == 1 ? children[0] : nm->mkNode(k, children); |
922 |
1620 |
Trace("ext-rew-bcp") << "BCP: **** OUTPUT: " << new_ret << std::endl; |
923 |
1620 |
return new_ret; |
924 |
|
} |
925 |
|
|
926 |
48631 |
return Node::null(); |
927 |
|
} |
928 |
|
|
929 |
48631 |
Node ExtendedRewriter::extendedRewriteFactoring(Kind andk, |
930 |
|
Kind ork, |
931 |
|
Kind notk, |
932 |
|
Node n) const |
933 |
|
{ |
934 |
48631 |
Trace("ext-rew-factoring") << "Factoring: *** INPUT: " << n << std::endl; |
935 |
48631 |
NodeManager* nm = NodeManager::currentNM(); |
936 |
|
|
937 |
48631 |
Kind nk = n.getKind(); |
938 |
48631 |
Assert(nk == andk || nk == ork); |
939 |
48631 |
Kind onk = nk == andk ? ork : andk; |
940 |
|
// count the number of times atoms occur |
941 |
97262 |
std::map<Node, std::vector<Node> > lit_to_cl; |
942 |
97262 |
std::map<Node, std::vector<Node> > cl_to_lits; |
943 |
298215 |
for (const Node& nc : n) |
944 |
|
{ |
945 |
249584 |
Kind nck = nc.getKind(); |
946 |
249584 |
if (nck == onk) |
947 |
|
{ |
948 |
254935 |
for (const Node& ncl : nc) |
949 |
|
{ |
950 |
616437 |
if (std::find(lit_to_cl[ncl].begin(), lit_to_cl[ncl].end(), nc) |
951 |
616437 |
== lit_to_cl[ncl].end()) |
952 |
|
{ |
953 |
205479 |
lit_to_cl[ncl].push_back(nc); |
954 |
205479 |
cl_to_lits[nc].push_back(ncl); |
955 |
|
} |
956 |
|
} |
957 |
|
} |
958 |
|
else |
959 |
|
{ |
960 |
200128 |
lit_to_cl[nc].push_back(nc); |
961 |
200128 |
cl_to_lits[nc].push_back(nc); |
962 |
|
} |
963 |
|
} |
964 |
|
// get the maximum shared literal to factor |
965 |
48631 |
unsigned max_size = 0; |
966 |
97262 |
Node flit; |
967 |
410653 |
for (const std::pair<const Node, std::vector<Node> >& ltc : lit_to_cl) |
968 |
|
{ |
969 |
362022 |
if (ltc.second.size() > max_size) |
970 |
|
{ |
971 |
52322 |
max_size = ltc.second.size(); |
972 |
52322 |
flit = ltc.first; |
973 |
|
} |
974 |
|
} |
975 |
48631 |
if (max_size > 1) |
976 |
|
{ |
977 |
|
// do the factoring |
978 |
7022 |
std::vector<Node> children; |
979 |
7022 |
std::vector<Node> fchildren; |
980 |
3511 |
std::map<Node, std::vector<Node> >::iterator itl = lit_to_cl.find(flit); |
981 |
3511 |
std::vector<Node>& cls = itl->second; |
982 |
21964 |
for (const Node& nc : n) |
983 |
|
{ |
984 |
18453 |
if (std::find(cls.begin(), cls.end(), nc) == cls.end()) |
985 |
|
{ |
986 |
8303 |
children.push_back(nc); |
987 |
|
} |
988 |
|
else |
989 |
|
{ |
990 |
|
// rebuild |
991 |
10150 |
std::vector<Node>& lits = cl_to_lits[nc]; |
992 |
|
std::vector<Node>::iterator itlfl = |
993 |
10150 |
std::find(lits.begin(), lits.end(), flit); |
994 |
10150 |
Assert(itlfl != lits.end()); |
995 |
10150 |
lits.erase(itlfl); |
996 |
|
// rebuild |
997 |
10150 |
if (!lits.empty()) |
998 |
|
{ |
999 |
20300 |
Node new_cl = lits.size() == 1 ? lits[0] : nm->mkNode(onk, lits); |
1000 |
10150 |
fchildren.push_back(new_cl); |
1001 |
|
} |
1002 |
|
} |
1003 |
|
} |
1004 |
|
// rebuild the factored children |
1005 |
3511 |
Assert(!fchildren.empty()); |
1006 |
7022 |
Node fcn = fchildren.size() == 1 ? fchildren[0] : nm->mkNode(nk, fchildren); |
1007 |
3511 |
children.push_back(nm->mkNode(onk, flit, fcn)); |
1008 |
7022 |
Node ret = children.size() == 1 ? children[0] : nm->mkNode(nk, children); |
1009 |
3511 |
Trace("ext-rew-factoring") << "Factoring: *** OUTPUT: " << ret << std::endl; |
1010 |
3511 |
return ret; |
1011 |
|
} |
1012 |
|
else |
1013 |
|
{ |
1014 |
45120 |
Trace("ext-rew-factoring") << "Factoring: no change" << std::endl; |
1015 |
|
} |
1016 |
45120 |
return Node::null(); |
1017 |
|
} |
1018 |
|
|
1019 |
45120 |
Node ExtendedRewriter::extendedRewriteEqRes(Kind andk, |
1020 |
|
Kind ork, |
1021 |
|
Kind eqk, |
1022 |
|
Kind notk, |
1023 |
|
std::map<Kind, bool>& bcp_kinds, |
1024 |
|
Node n, |
1025 |
|
bool isXor) const |
1026 |
|
{ |
1027 |
45120 |
Assert(n.getKind() == andk || n.getKind() == ork); |
1028 |
45120 |
Trace("ext-rew-eqres") << "Eq res: **** INPUT: " << n << std::endl; |
1029 |
|
|
1030 |
45120 |
NodeManager* nm = NodeManager::currentNM(); |
1031 |
45120 |
Kind nk = n.getKind(); |
1032 |
45120 |
bool gpol = (nk == andk); |
1033 |
245677 |
for (unsigned i = 0, nchild = n.getNumChildren(); i < nchild; i++) |
1034 |
|
{ |
1035 |
404380 |
Node lit = n[i]; |
1036 |
203823 |
if (lit.getKind() == eqk) |
1037 |
|
{ |
1038 |
|
// eq is the equality we are basing a substitution on |
1039 |
182456 |
Node eq; |
1040 |
92861 |
if (gpol == isXor) |
1041 |
|
{ |
1042 |
|
// can only turn disequality into equality if types are the same |
1043 |
7991 |
if (lit[1].getType() == lit.getType()) |
1044 |
|
{ |
1045 |
|
// t != s ---> ~t = s |
1046 |
215 |
if (lit[1].getKind() == notk && lit[0].getKind() != notk) |
1047 |
|
{ |
1048 |
40 |
eq = nm->mkNode(EQUAL, lit[0], TermUtil::mkNegate(notk, lit[1])); |
1049 |
|
} |
1050 |
|
else |
1051 |
|
{ |
1052 |
175 |
eq = nm->mkNode(EQUAL, TermUtil::mkNegate(notk, lit[0]), lit[1]); |
1053 |
|
} |
1054 |
|
} |
1055 |
|
} |
1056 |
|
else |
1057 |
|
{ |
1058 |
84870 |
eq = eqk == EQUAL ? lit : nm->mkNode(EQUAL, lit[0], lit[1]); |
1059 |
|
} |
1060 |
92861 |
if (!eq.isNull()) |
1061 |
|
{ |
1062 |
|
// see if it corresponds to a substitution |
1063 |
166904 |
std::vector<Node> vars; |
1064 |
166904 |
std::vector<Node> subs; |
1065 |
85085 |
if (inferSubstitution(eq, vars, subs)) |
1066 |
|
{ |
1067 |
78207 |
Assert(vars.size() == 1); |
1068 |
153148 |
std::vector<Node> children; |
1069 |
78207 |
bool childrenChanged = false; |
1070 |
|
// apply to all other children |
1071 |
1393863 |
for (unsigned j = 0; j < nchild; j++) |
1072 |
|
{ |
1073 |
2631312 |
Node ccs = n[j]; |
1074 |
1315656 |
if (i != j) |
1075 |
|
{ |
1076 |
|
// Substitution is only applicable to compatible kinds. We always |
1077 |
|
// use the partialSubstitute method to avoid substitution into |
1078 |
|
// witness terms. |
1079 |
1237449 |
ccs = partialSubstitute(ccs, vars, subs, bcp_kinds); |
1080 |
1237449 |
childrenChanged = childrenChanged || n[j] != ccs; |
1081 |
|
} |
1082 |
1315656 |
children.push_back(ccs); |
1083 |
|
} |
1084 |
78207 |
if (childrenChanged) |
1085 |
|
{ |
1086 |
3266 |
return nm->mkNode(nk, children); |
1087 |
|
} |
1088 |
|
} |
1089 |
|
} |
1090 |
|
} |
1091 |
|
} |
1092 |
|
|
1093 |
41854 |
return Node::null(); |
1094 |
|
} |
1095 |
|
|
1096 |
|
/** sort pairs by their second (unsigned) argument */ |
1097 |
51607 |
static bool sortPairSecond(const std::pair<Node, unsigned>& a, |
1098 |
|
const std::pair<Node, unsigned>& b) |
1099 |
|
{ |
1100 |
51607 |
return (a.second < b.second); |
1101 |
|
} |
1102 |
|
|
1103 |
|
/** A simple subsumption trie used to compute pairwise list subsets */ |
1104 |
155764 |
class SimpSubsumeTrie |
1105 |
|
{ |
1106 |
|
public: |
1107 |
|
/** the children of this node */ |
1108 |
|
std::map<Node, SimpSubsumeTrie> d_children; |
1109 |
|
/** the term at this node */ |
1110 |
|
Node d_data; |
1111 |
|
/** add term to the trie |
1112 |
|
* |
1113 |
|
* This adds term c to this trie, whose atom list is alist. This adds terms |
1114 |
|
* s to subsumes such that the atom list of s is a subset of the atom list |
1115 |
|
* of c. For example, say: |
1116 |
|
* c1.alist = { A } |
1117 |
|
* c2.alist = { C } |
1118 |
|
* c3.alist = { B, C } |
1119 |
|
* c4.alist = { A, B, D } |
1120 |
|
* c5.alist = { A, B, C } |
1121 |
|
* If these terms are added in the order c1, c2, c3, c4, c5, then: |
1122 |
|
* addTerm c1 results in subsumes = {} |
1123 |
|
* addTerm c2 results in subsumes = {} |
1124 |
|
* addTerm c3 results in subsumes = { c2 } |
1125 |
|
* addTerm c4 results in subsumes = { c1 } |
1126 |
|
* addTerm c5 results in subsumes = { c1, c2, c3 } |
1127 |
|
* Notice that the intended use case of this trie is to add term t before t' |
1128 |
|
* only when size( t.alist ) <= size( t'.alist ). |
1129 |
|
* |
1130 |
|
* The last two arguments describe the state of the path [t0...tn] we |
1131 |
|
* have followed in the trie during the recursive call. |
1132 |
|
* If doAdd = true, |
1133 |
|
* then n+1 = index and alist[1]...alist[n] = t1...tn. If index=alist.size() |
1134 |
|
* we add c as the current node of this trie. |
1135 |
|
* If doAdd = false, |
1136 |
|
* then t1...tn occur in alist. |
1137 |
|
*/ |
1138 |
103632 |
void addTerm(Node c, |
1139 |
|
std::vector<Node>& alist, |
1140 |
|
std::vector<Node>& subsumes, |
1141 |
|
unsigned index = 0, |
1142 |
|
bool doAdd = true) |
1143 |
|
{ |
1144 |
103632 |
if (!d_data.isNull()) |
1145 |
|
{ |
1146 |
|
subsumes.push_back(d_data); |
1147 |
|
} |
1148 |
103632 |
if (doAdd) |
1149 |
|
{ |
1150 |
103626 |
if (index == alist.size()) |
1151 |
|
{ |
1152 |
51134 |
d_data = c; |
1153 |
51134 |
return; |
1154 |
|
} |
1155 |
|
} |
1156 |
|
// try all children where we have this atom |
1157 |
78942 |
for (std::pair<const Node, SimpSubsumeTrie>& cp : d_children) |
1158 |
|
{ |
1159 |
26444 |
if (std::find(alist.begin(), alist.end(), cp.first) != alist.end()) |
1160 |
|
{ |
1161 |
6 |
cp.second.addTerm(c, alist, subsumes, 0, false); |
1162 |
|
} |
1163 |
|
} |
1164 |
52498 |
if (doAdd) |
1165 |
|
{ |
1166 |
52492 |
d_children[alist[index]].addTerm(c, alist, subsumes, index + 1, doAdd); |
1167 |
|
} |
1168 |
|
} |
1169 |
|
}; |
1170 |
|
|
1171 |
25494 |
Node ExtendedRewriter::extendedRewriteEqChain( |
1172 |
|
Kind eqk, Kind andk, Kind ork, Kind notk, Node ret, bool isXor) const |
1173 |
|
{ |
1174 |
25494 |
Assert(ret.getKind() == eqk); |
1175 |
|
|
1176 |
|
// this rewrite is aggressive; it in fact has the precondition that other |
1177 |
|
// aggressive rewrites (including BCP) have been applied. |
1178 |
25494 |
if (!d_aggr) |
1179 |
|
{ |
1180 |
96 |
return Node::null(); |
1181 |
|
} |
1182 |
|
|
1183 |
25398 |
NodeManager* nm = NodeManager::currentNM(); |
1184 |
|
|
1185 |
50796 |
TypeNode tn = ret[0].getType(); |
1186 |
|
|
1187 |
|
// sort/cancelling for Boolean EQUAL/XOR-chains |
1188 |
25398 |
Trace("ext-rew-eqchain") << "Eq-Chain : " << ret << std::endl; |
1189 |
|
|
1190 |
|
// get the children on either side |
1191 |
25398 |
bool gpol = true; |
1192 |
50796 |
std::vector<Node> children; |
1193 |
76194 |
for (unsigned r = 0, size = ret.getNumChildren(); r < size; r++) |
1194 |
|
{ |
1195 |
101592 |
Node curr = ret[r]; |
1196 |
|
// assume, if necessary, right associative |
1197 |
51620 |
while (curr.getKind() == eqk && curr[0].getType() == tn) |
1198 |
|
{ |
1199 |
412 |
children.push_back(curr[0]); |
1200 |
412 |
curr = curr[1]; |
1201 |
|
} |
1202 |
50796 |
children.push_back(curr); |
1203 |
|
} |
1204 |
|
|
1205 |
50796 |
std::map<Node, bool> cstatus; |
1206 |
|
// add children to status |
1207 |
76606 |
for (const Node& c : children) |
1208 |
|
{ |
1209 |
102416 |
Node a = c; |
1210 |
51208 |
if (a.getKind() == notk) |
1211 |
|
{ |
1212 |
355 |
gpol = !gpol; |
1213 |
355 |
a = a[0]; |
1214 |
|
} |
1215 |
51208 |
Trace("ext-rew-eqchain") << "...child : " << a << std::endl; |
1216 |
51208 |
std::map<Node, bool>::iterator itc = cstatus.find(a); |
1217 |
51208 |
if (itc == cstatus.end()) |
1218 |
|
{ |
1219 |
51179 |
cstatus[a] = true; |
1220 |
|
} |
1221 |
|
else |
1222 |
|
{ |
1223 |
|
// cancels |
1224 |
29 |
cstatus.erase(a); |
1225 |
29 |
if (isXor) |
1226 |
|
{ |
1227 |
|
gpol = !gpol; |
1228 |
|
} |
1229 |
|
} |
1230 |
|
} |
1231 |
25398 |
Trace("ext-rew-eqchain") << "Global polarity : " << gpol << std::endl; |
1232 |
|
|
1233 |
25398 |
if (cstatus.empty()) |
1234 |
|
{ |
1235 |
2 |
return TermUtil::mkTypeConst(tn, gpol); |
1236 |
|
} |
1237 |
|
|
1238 |
25396 |
children.clear(); |
1239 |
|
|
1240 |
|
// compute the atoms of each child |
1241 |
25396 |
Trace("ext-rew-eqchain") << "eqchain-simplify: begin\n"; |
1242 |
25396 |
Trace("ext-rew-eqchain") << " eqchain-simplify: get atoms...\n"; |
1243 |
50792 |
std::map<Node, std::map<Node, bool> > atoms; |
1244 |
50792 |
std::map<Node, std::vector<Node> > alist; |
1245 |
50792 |
std::vector<std::pair<Node, unsigned> > atom_count; |
1246 |
76546 |
for (std::pair<const Node, bool>& cp : cstatus) |
1247 |
|
{ |
1248 |
51150 |
if (!cp.second) |
1249 |
|
{ |
1250 |
|
// already eliminated |
1251 |
|
continue; |
1252 |
|
} |
1253 |
102300 |
Node c = cp.first; |
1254 |
51150 |
Kind ck = c.getKind(); |
1255 |
51150 |
Trace("ext-rew-eqchain") << " process c = " << c << std::endl; |
1256 |
51150 |
if (ck == andk || ck == ork) |
1257 |
|
{ |
1258 |
2591 |
for (unsigned j = 0, nchild = c.getNumChildren(); j < nchild; j++) |
1259 |
|
{ |
1260 |
3956 |
Node cl = c[j]; |
1261 |
1982 |
bool pol = cl.getKind() != notk; |
1262 |
3956 |
Node ca = pol ? cl : cl[0]; |
1263 |
1982 |
bool newVal = (ck == andk ? !pol : pol); |
1264 |
3964 |
Trace("ext-rew-eqchain") |
1265 |
1982 |
<< " atoms(" << c << ", " << ca << ") = " << newVal << std::endl; |
1266 |
1982 |
Assert(atoms[c].find(ca) == atoms[c].end()); |
1267 |
|
// polarity is flipped when we are AND |
1268 |
1982 |
atoms[c][ca] = newVal; |
1269 |
1982 |
alist[c].push_back(ca); |
1270 |
|
|
1271 |
|
// if this already exists as a child of the equality chain, eliminate. |
1272 |
|
// this catches cases like ( x & y ) = ( ( x & y ) | z ), where we |
1273 |
|
// consider ( x & y ) a unit, whereas below it is expanded to |
1274 |
|
// ~( ~x | ~y ). |
1275 |
1982 |
std::map<Node, bool>::iterator itc = cstatus.find(ca); |
1276 |
1982 |
if (itc != cstatus.end() && itc->second) |
1277 |
|
{ |
1278 |
|
// cancel it |
1279 |
8 |
cstatus[ca] = false; |
1280 |
8 |
cstatus[c] = false; |
1281 |
|
// make new child |
1282 |
|
// x = ( y | ~x ) ---> y & x |
1283 |
|
// x = ( y | x ) ---> ~y | x |
1284 |
|
// x = ( y & x ) ---> y | ~x |
1285 |
|
// x = ( y & ~x ) ---> ~y & ~x |
1286 |
16 |
std::vector<Node> new_children; |
1287 |
24 |
for (unsigned k = 0, nchildc = c.getNumChildren(); k < nchildc; k++) |
1288 |
|
{ |
1289 |
16 |
if (j != k) |
1290 |
|
{ |
1291 |
8 |
new_children.push_back(c[k]); |
1292 |
|
} |
1293 |
|
} |
1294 |
16 |
Node nc[2]; |
1295 |
8 |
nc[0] = c[j]; |
1296 |
8 |
nc[1] = new_children.size() == 1 ? new_children[0] |
1297 |
|
: nm->mkNode(ck, new_children); |
1298 |
|
// negate the proper child |
1299 |
8 |
unsigned nindex = (ck == andk) == pol ? 0 : 1; |
1300 |
8 |
nc[nindex] = TermUtil::mkNegate(notk, nc[nindex]); |
1301 |
8 |
Kind nk = pol ? ork : andk; |
1302 |
|
// store as new child |
1303 |
8 |
children.push_back(nm->mkNode(nk, nc[0], nc[1])); |
1304 |
8 |
if (isXor) |
1305 |
|
{ |
1306 |
|
gpol = !gpol; |
1307 |
|
} |
1308 |
8 |
break; |
1309 |
|
} |
1310 |
617 |
} |
1311 |
|
} |
1312 |
|
else |
1313 |
|
{ |
1314 |
50533 |
bool pol = ck != notk; |
1315 |
101066 |
Node ca = pol ? c : c[0]; |
1316 |
50533 |
atoms[c][ca] = pol; |
1317 |
101066 |
Trace("ext-rew-eqchain") |
1318 |
50533 |
<< " atoms(" << c << ", " << ca << ") = " << pol << std::endl; |
1319 |
50533 |
alist[c].push_back(ca); |
1320 |
|
} |
1321 |
51150 |
atom_count.push_back(std::pair<Node, unsigned>(c, alist[c].size())); |
1322 |
|
} |
1323 |
|
// sort the atoms in each atom list |
1324 |
76546 |
for (std::map<Node, std::vector<Node> >::iterator it = alist.begin(); |
1325 |
76546 |
it != alist.end(); |
1326 |
|
++it) |
1327 |
|
{ |
1328 |
51150 |
std::sort(it->second.begin(), it->second.end()); |
1329 |
|
} |
1330 |
|
// check subsumptions |
1331 |
|
// sort by #atoms |
1332 |
25396 |
std::sort(atom_count.begin(), atom_count.end(), sortPairSecond); |
1333 |
25396 |
if (Trace.isOn("ext-rew-eqchain")) |
1334 |
|
{ |
1335 |
|
for (const std::pair<Node, unsigned>& ac : atom_count) |
1336 |
|
{ |
1337 |
|
Trace("ext-rew-eqchain") << " eqchain-simplify: " << ac.first << " has " |
1338 |
|
<< ac.second << " atoms." << std::endl; |
1339 |
|
} |
1340 |
|
Trace("ext-rew-eqchain") << " eqchain-simplify: compute subsumptions...\n"; |
1341 |
|
} |
1342 |
50792 |
SimpSubsumeTrie sst; |
1343 |
76546 |
for (std::pair<const Node, bool>& cp : cstatus) |
1344 |
|
{ |
1345 |
51150 |
if (!cp.second) |
1346 |
|
{ |
1347 |
|
// already eliminated |
1348 |
16 |
continue; |
1349 |
|
} |
1350 |
102268 |
Node c = cp.first; |
1351 |
51134 |
std::map<Node, std::map<Node, bool> >::iterator itc = atoms.find(c); |
1352 |
51134 |
Assert(itc != atoms.end()); |
1353 |
102268 |
Trace("ext-rew-eqchain") << " - add term " << c << " with atom list " |
1354 |
51134 |
<< alist[c] << "...\n"; |
1355 |
102268 |
std::vector<Node> subsumes; |
1356 |
51134 |
sst.addTerm(c, alist[c], subsumes); |
1357 |
51134 |
for (const Node& cc : subsumes) |
1358 |
|
{ |
1359 |
|
if (!cstatus[cc]) |
1360 |
|
{ |
1361 |
|
// subsumes a child that was already eliminated |
1362 |
|
continue; |
1363 |
|
} |
1364 |
|
Trace("ext-rew-eqchain") << " eqchain-simplify: " << c << " subsumes " |
1365 |
|
<< cc << std::endl; |
1366 |
|
// for each of the atoms in cc |
1367 |
|
std::map<Node, std::map<Node, bool> >::iterator itcc = atoms.find(cc); |
1368 |
|
Assert(itcc != atoms.end()); |
1369 |
|
std::vector<Node> common_children; |
1370 |
|
std::vector<Node> diff_children; |
1371 |
|
for (const std::pair<const Node, bool>& ap : itcc->second) |
1372 |
|
{ |
1373 |
|
// compare the polarity |
1374 |
|
Node a = ap.first; |
1375 |
|
bool polcc = ap.second; |
1376 |
|
Assert(itc->second.find(a) != itc->second.end()); |
1377 |
|
bool polc = itc->second[a]; |
1378 |
|
Trace("ext-rew-eqchain") << " eqchain-simplify: atom " << a |
1379 |
|
<< " has polarities : " << polc << " " << polcc |
1380 |
|
<< "\n"; |
1381 |
|
Node lit = polc ? a : TermUtil::mkNegate(notk, a); |
1382 |
|
if (polc != polcc) |
1383 |
|
{ |
1384 |
|
diff_children.push_back(lit); |
1385 |
|
} |
1386 |
|
else |
1387 |
|
{ |
1388 |
|
common_children.push_back(lit); |
1389 |
|
} |
1390 |
|
} |
1391 |
|
std::vector<Node> rem_children; |
1392 |
|
for (const std::pair<const Node, bool>& ap : itc->second) |
1393 |
|
{ |
1394 |
|
Node a = ap.first; |
1395 |
|
if (atoms[cc].find(a) == atoms[cc].end()) |
1396 |
|
{ |
1397 |
|
bool polc = ap.second; |
1398 |
|
rem_children.push_back(polc ? a : TermUtil::mkNegate(notk, a)); |
1399 |
|
} |
1400 |
|
} |
1401 |
|
Trace("ext-rew-eqchain") |
1402 |
|
<< " #common/diff/rem: " << common_children.size() << "/" |
1403 |
|
<< diff_children.size() << "/" << rem_children.size() << "\n"; |
1404 |
|
bool do_rewrite = false; |
1405 |
|
if (common_children.empty() && itc->second.size() == itcc->second.size() |
1406 |
|
&& itcc->second.size() == 2) |
1407 |
|
{ |
1408 |
|
// x | y = ~x | ~y ---> ~( x = y ) |
1409 |
|
do_rewrite = true; |
1410 |
|
children.push_back(diff_children[0]); |
1411 |
|
children.push_back(diff_children[1]); |
1412 |
|
gpol = !gpol; |
1413 |
|
Trace("ext-rew-eqchain") << " apply 2-child all-diff\n"; |
1414 |
|
} |
1415 |
|
else if (common_children.empty() && diff_children.size() == 1) |
1416 |
|
{ |
1417 |
|
do_rewrite = true; |
1418 |
|
// x = ( ~x | y ) ---> ~( ~x | ~y ) |
1419 |
|
Node remn = rem_children.size() == 1 ? rem_children[0] |
1420 |
|
: nm->mkNode(ork, rem_children); |
1421 |
|
remn = TermUtil::mkNegate(notk, remn); |
1422 |
|
children.push_back(nm->mkNode(ork, diff_children[0], remn)); |
1423 |
|
if (!isXor) |
1424 |
|
{ |
1425 |
|
gpol = !gpol; |
1426 |
|
} |
1427 |
|
Trace("ext-rew-eqchain") << " apply unit resolution\n"; |
1428 |
|
} |
1429 |
|
else if (diff_children.size() == 1 |
1430 |
|
&& itc->second.size() == itcc->second.size()) |
1431 |
|
{ |
1432 |
|
// ( x | y | z ) = ( x | ~y | z ) ---> ( x | z ) |
1433 |
|
do_rewrite = true; |
1434 |
|
Assert(!common_children.empty()); |
1435 |
|
Node comn = common_children.size() == 1 |
1436 |
|
? common_children[0] |
1437 |
|
: nm->mkNode(ork, common_children); |
1438 |
|
children.push_back(comn); |
1439 |
|
if (isXor) |
1440 |
|
{ |
1441 |
|
gpol = !gpol; |
1442 |
|
} |
1443 |
|
Trace("ext-rew-eqchain") << " apply resolution\n"; |
1444 |
|
} |
1445 |
|
else if (diff_children.empty()) |
1446 |
|
{ |
1447 |
|
do_rewrite = true; |
1448 |
|
if (rem_children.empty()) |
1449 |
|
{ |
1450 |
|
// x | y = x | y ---> true |
1451 |
|
// this can happen if we have ( ~x & ~y ) = ( x | y ) |
1452 |
|
children.push_back(TermUtil::mkTypeMaxValue(tn)); |
1453 |
|
if (isXor) |
1454 |
|
{ |
1455 |
|
gpol = !gpol; |
1456 |
|
} |
1457 |
|
Trace("ext-rew-eqchain") << " apply cancel\n"; |
1458 |
|
} |
1459 |
|
else |
1460 |
|
{ |
1461 |
|
// x | y = ( x | y | z ) ---> ( x | y | ~z ) |
1462 |
|
Node remn = rem_children.size() == 1 ? rem_children[0] |
1463 |
|
: nm->mkNode(ork, rem_children); |
1464 |
|
remn = TermUtil::mkNegate(notk, remn); |
1465 |
|
Node comn = common_children.size() == 1 |
1466 |
|
? common_children[0] |
1467 |
|
: nm->mkNode(ork, common_children); |
1468 |
|
children.push_back(nm->mkNode(ork, comn, remn)); |
1469 |
|
if (isXor) |
1470 |
|
{ |
1471 |
|
gpol = !gpol; |
1472 |
|
} |
1473 |
|
Trace("ext-rew-eqchain") << " apply subsume\n"; |
1474 |
|
} |
1475 |
|
} |
1476 |
|
if (do_rewrite) |
1477 |
|
{ |
1478 |
|
// eliminate the children, reverse polarity as needed |
1479 |
|
for (unsigned r = 0; r < 2; r++) |
1480 |
|
{ |
1481 |
|
Node c_rem = r == 0 ? c : cc; |
1482 |
|
cstatus[c_rem] = false; |
1483 |
|
if (c_rem.getKind() == andk) |
1484 |
|
{ |
1485 |
|
gpol = !gpol; |
1486 |
|
} |
1487 |
|
} |
1488 |
|
break; |
1489 |
|
} |
1490 |
|
} |
1491 |
|
} |
1492 |
25396 |
Trace("ext-rew-eqchain") << "eqchain-simplify: finish" << std::endl; |
1493 |
|
|
1494 |
|
// sorted right associative chain |
1495 |
25396 |
bool has_nvar = false; |
1496 |
25396 |
unsigned nvar_index = 0; |
1497 |
76546 |
for (std::pair<const Node, bool>& cp : cstatus) |
1498 |
|
{ |
1499 |
51150 |
if (cp.second) |
1500 |
|
{ |
1501 |
51134 |
if (!cp.first.isVar()) |
1502 |
|
{ |
1503 |
26669 |
has_nvar = true; |
1504 |
26669 |
nvar_index = children.size(); |
1505 |
|
} |
1506 |
51134 |
children.push_back(cp.first); |
1507 |
|
} |
1508 |
|
} |
1509 |
25396 |
std::sort(children.begin(), children.end()); |
1510 |
|
|
1511 |
50792 |
Node new_ret; |
1512 |
25396 |
if (!gpol) |
1513 |
|
{ |
1514 |
|
// negate the constant child if it exists |
1515 |
293 |
unsigned nindex = has_nvar ? nvar_index : 0; |
1516 |
293 |
children[nindex] = TermUtil::mkNegate(notk, children[nindex]); |
1517 |
|
} |
1518 |
25396 |
new_ret = children.back(); |
1519 |
25396 |
unsigned index = children.size() - 1; |
1520 |
76888 |
while (index > 0) |
1521 |
|
{ |
1522 |
25746 |
index--; |
1523 |
25746 |
new_ret = nm->mkNode(eqk, children[index], new_ret); |
1524 |
|
} |
1525 |
25396 |
new_ret = Rewriter::rewrite(new_ret); |
1526 |
25396 |
if (new_ret != ret) |
1527 |
|
{ |
1528 |
186 |
return new_ret; |
1529 |
|
} |
1530 |
25210 |
return Node::null(); |
1531 |
|
} |
1532 |
|
|
1533 |
1883244 |
Node ExtendedRewriter::partialSubstitute( |
1534 |
|
Node n, |
1535 |
|
const std::map<Node, Node>& assign, |
1536 |
|
const std::map<Kind, bool>& rkinds) const |
1537 |
|
{ |
1538 |
3766488 |
std::unordered_map<TNode, Node> visited; |
1539 |
1883244 |
std::unordered_map<TNode, Node>::iterator it; |
1540 |
1883244 |
std::map<Node, Node>::const_iterator ita; |
1541 |
3766488 |
std::vector<TNode> visit; |
1542 |
3766488 |
TNode cur; |
1543 |
1883244 |
visit.push_back(n); |
1544 |
24605245 |
do |
1545 |
|
{ |
1546 |
26488489 |
cur = visit.back(); |
1547 |
26488489 |
visit.pop_back(); |
1548 |
26488489 |
it = visited.find(cur); |
1549 |
|
|
1550 |
26488489 |
if (it == visited.end()) |
1551 |
|
{ |
1552 |
11217074 |
ita = assign.find(cur); |
1553 |
11217074 |
if (ita != assign.end()) |
1554 |
|
{ |
1555 |
27010 |
visited[cur] = ita->second; |
1556 |
|
} |
1557 |
|
else |
1558 |
|
{ |
1559 |
|
// If rkinds is non-empty, then can only recurse on its kinds. |
1560 |
|
// We also always disallow substitution into witness. Notice that |
1561 |
|
// we disallow witness here, due to unsoundness when applying contextual |
1562 |
|
// substitutions over witness terms (see #4620). |
1563 |
11190064 |
Kind k = cur.getKind(); |
1564 |
11190064 |
if (k != WITNESS && (rkinds.empty() || rkinds.find(k) != rkinds.end())) |
1565 |
|
{ |
1566 |
11190064 |
visited[cur] = Node::null(); |
1567 |
11190064 |
visit.push_back(cur); |
1568 |
24605245 |
for (const Node& cn : cur) |
1569 |
|
{ |
1570 |
13415181 |
visit.push_back(cn); |
1571 |
|
} |
1572 |
|
} |
1573 |
|
else |
1574 |
|
{ |
1575 |
|
visited[cur] = cur; |
1576 |
|
} |
1577 |
|
} |
1578 |
|
} |
1579 |
15271415 |
else if (it->second.isNull()) |
1580 |
|
{ |
1581 |
22380128 |
Node ret = cur; |
1582 |
11190064 |
bool childChanged = false; |
1583 |
22380128 |
std::vector<Node> children; |
1584 |
11190064 |
if (cur.getMetaKind() == metakind::PARAMETERIZED) |
1585 |
|
{ |
1586 |
52129 |
children.push_back(cur.getOperator()); |
1587 |
|
} |
1588 |
24605245 |
for (const Node& cn : cur) |
1589 |
|
{ |
1590 |
13415181 |
it = visited.find(cn); |
1591 |
13415181 |
Assert(it != visited.end()); |
1592 |
13415181 |
Assert(!it->second.isNull()); |
1593 |
13415181 |
childChanged = childChanged || cn != it->second; |
1594 |
13415181 |
children.push_back(it->second); |
1595 |
|
} |
1596 |
11190064 |
if (childChanged) |
1597 |
|
{ |
1598 |
90798 |
ret = NodeManager::currentNM()->mkNode(cur.getKind(), children); |
1599 |
|
} |
1600 |
11190064 |
visited[cur] = ret; |
1601 |
|
} |
1602 |
26488489 |
} while (!visit.empty()); |
1603 |
1883244 |
Assert(visited.find(n) != visited.end()); |
1604 |
1883244 |
Assert(!visited.find(n)->second.isNull()); |
1605 |
3766488 |
return visited[n]; |
1606 |
|
} |
1607 |
|
|
1608 |
1267673 |
Node ExtendedRewriter::partialSubstitute( |
1609 |
|
Node n, |
1610 |
|
const std::vector<Node>& vars, |
1611 |
|
const std::vector<Node>& subs, |
1612 |
|
const std::map<Kind, bool>& rkinds) const |
1613 |
|
{ |
1614 |
1267673 |
Assert(vars.size() == subs.size()); |
1615 |
2535346 |
std::map<Node, Node> assign; |
1616 |
2549992 |
for (size_t i = 0, nvars = vars.size(); i < nvars; i++) |
1617 |
|
{ |
1618 |
1282319 |
assign[vars[i]] = subs[i]; |
1619 |
|
} |
1620 |
2535346 |
return partialSubstitute(n, assign, rkinds); |
1621 |
|
} |
1622 |
|
|
1623 |
96214 |
Node ExtendedRewriter::solveEquality(Node n) const |
1624 |
|
{ |
1625 |
|
// TODO (#1706) : implement |
1626 |
96214 |
Assert(n.getKind() == EQUAL); |
1627 |
|
|
1628 |
96214 |
return Node::null(); |
1629 |
|
} |
1630 |
|
|
1631 |
133719 |
bool ExtendedRewriter::inferSubstitution(Node n, |
1632 |
|
std::vector<Node>& vars, |
1633 |
|
std::vector<Node>& subs, |
1634 |
|
bool usePred) const |
1635 |
|
{ |
1636 |
133719 |
if (n.getKind() == AND) |
1637 |
|
{ |
1638 |
3764 |
bool ret = false; |
1639 |
22174 |
for (const Node& nc : n) |
1640 |
|
{ |
1641 |
18410 |
bool cret = inferSubstitution(nc, vars, subs, usePred); |
1642 |
18410 |
ret = ret || cret; |
1643 |
|
} |
1644 |
3764 |
return ret; |
1645 |
|
} |
1646 |
129955 |
if (n.getKind() == EQUAL) |
1647 |
|
{ |
1648 |
|
// see if it can be put into form x = y |
1649 |
103717 |
Node slv_eq = solveEquality(n); |
1650 |
96214 |
if (!slv_eq.isNull()) |
1651 |
|
{ |
1652 |
|
n = slv_eq; |
1653 |
|
} |
1654 |
288642 |
Node v[2]; |
1655 |
247037 |
for (unsigned i = 0; i < 2; i++) |
1656 |
|
{ |
1657 |
192287 |
if (n[i].isConst()) |
1658 |
|
{ |
1659 |
41464 |
vars.push_back(n[1 - i]); |
1660 |
41464 |
subs.push_back(n[i]); |
1661 |
41464 |
return true; |
1662 |
|
} |
1663 |
150823 |
if (n[i].isVar()) |
1664 |
|
{ |
1665 |
140070 |
v[i] = n[i]; |
1666 |
|
} |
1667 |
10753 |
else if (TermUtil::isNegate(n[i].getKind()) && n[i][0].isVar()) |
1668 |
|
{ |
1669 |
263 |
v[i] = n[i][0]; |
1670 |
|
} |
1671 |
|
} |
1672 |
73093 |
for (unsigned i = 0; i < 2; i++) |
1673 |
|
{ |
1674 |
83933 |
TNode r1 = v[i]; |
1675 |
83933 |
Node r2 = v[1 - i]; |
1676 |
65590 |
if (r1.isVar() && ((r2.isVar() && r1 < r2) || r2.isConst())) |
1677 |
|
{ |
1678 |
47247 |
r2 = n[1 - i]; |
1679 |
47247 |
if (v[i] != n[i]) |
1680 |
|
{ |
1681 |
257 |
Assert(TermUtil::isNegate(n[i].getKind())); |
1682 |
257 |
r2 = TermUtil::mkNegate(n[i].getKind(), r2); |
1683 |
|
} |
1684 |
|
// TODO (#1706) : union find |
1685 |
47247 |
if (std::find(vars.begin(), vars.end(), r1) == vars.end()) |
1686 |
|
{ |
1687 |
47247 |
vars.push_back(r1); |
1688 |
47247 |
subs.push_back(r2); |
1689 |
47247 |
return true; |
1690 |
|
} |
1691 |
|
} |
1692 |
|
} |
1693 |
|
} |
1694 |
41244 |
if (usePred) |
1695 |
|
{ |
1696 |
34366 |
bool negated = n.getKind() == NOT; |
1697 |
34366 |
vars.push_back(negated ? n[0] : n); |
1698 |
34366 |
subs.push_back(negated ? d_false : d_true); |
1699 |
34366 |
return true; |
1700 |
|
} |
1701 |
6878 |
return false; |
1702 |
|
} |
1703 |
|
|
1704 |
1660 |
Node ExtendedRewriter::extendedRewriteStrings(Node ret) const |
1705 |
|
{ |
1706 |
1660 |
Node new_ret; |
1707 |
3320 |
Trace("q-ext-rewrite-debug") |
1708 |
1660 |
<< "Extended rewrite strings : " << ret << std::endl; |
1709 |
|
|
1710 |
1660 |
if (ret.getKind() == EQUAL) |
1711 |
|
{ |
1712 |
293 |
new_ret = strings::SequencesRewriter(nullptr).rewriteEqualityExt(ret); |
1713 |
|
} |
1714 |
|
|
1715 |
1660 |
return new_ret; |
1716 |
|
} |
1717 |
|
|
1718 |
107105 |
void ExtendedRewriter::debugExtendedRewrite(Node n, |
1719 |
|
Node ret, |
1720 |
|
const char* c) const |
1721 |
|
{ |
1722 |
107105 |
if (Trace.isOn("q-ext-rewrite")) |
1723 |
|
{ |
1724 |
|
if (!ret.isNull()) |
1725 |
|
{ |
1726 |
|
Trace("q-ext-rewrite-apply") << "sygus-extr : apply " << c << std::endl; |
1727 |
|
Trace("q-ext-rewrite") << "sygus-extr : " << c << " : " << n |
1728 |
|
<< " rewrites to " << ret << std::endl; |
1729 |
|
} |
1730 |
|
} |
1731 |
107105 |
} |
1732 |
|
|
1733 |
|
} // namespace quantifiers |
1734 |
|
} // namespace theory |
1735 |
29508 |
} // namespace cvc5 |