1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Haniel Barbosa, Morgan Deters |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* [[ Add one-line brief description here ]] |
14 |
|
* |
15 |
|
* [[ Add lengthier description here ]] |
16 |
|
* \todo document this file |
17 |
|
*/ |
18 |
|
|
19 |
|
#include "theory/builtin/theory_builtin_rewriter.h" |
20 |
|
|
21 |
|
#include "expr/array_store_all.h" |
22 |
|
#include "expr/attribute.h" |
23 |
|
#include "expr/node_algorithm.h" |
24 |
|
#include "theory/rewriter.h" |
25 |
|
|
26 |
|
using namespace std; |
27 |
|
|
28 |
|
namespace cvc5 { |
29 |
|
namespace theory { |
30 |
|
namespace builtin { |
31 |
|
|
32 |
10510 |
Node TheoryBuiltinRewriter::blastDistinct(TNode in) { |
33 |
10510 |
Assert(in.getKind() == kind::DISTINCT); |
34 |
|
|
35 |
10510 |
if(in.getNumChildren() == 2) { |
36 |
|
// if this is the case exactly 1 != pair will be generated so the |
37 |
|
// AND is not required |
38 |
20014 |
Node eq = NodeManager::currentNM()->mkNode(kind::EQUAL, in[0], in[1]); |
39 |
20014 |
Node neq = NodeManager::currentNM()->mkNode(kind::NOT, eq); |
40 |
10007 |
return neq; |
41 |
|
} |
42 |
|
|
43 |
|
// assume that in.getNumChildren() > 2 => diseqs.size() > 1 |
44 |
1006 |
vector<Node> diseqs; |
45 |
3623 |
for(TNode::iterator i = in.begin(); i != in.end(); ++i) { |
46 |
3120 |
TNode::iterator j = i; |
47 |
71316 |
while(++j != in.end()) { |
48 |
68196 |
Node eq = NodeManager::currentNM()->mkNode(kind::EQUAL, *i, *j); |
49 |
68196 |
Node neq = NodeManager::currentNM()->mkNode(kind::NOT, eq); |
50 |
34098 |
diseqs.push_back(neq); |
51 |
|
} |
52 |
|
} |
53 |
1006 |
Node out = NodeManager::currentNM()->mkNode(kind::AND, diseqs); |
54 |
503 |
return out; |
55 |
|
} |
56 |
|
|
57 |
796830 |
RewriteResponse TheoryBuiltinRewriter::postRewrite(TNode node) { |
58 |
796830 |
if( node.getKind()==kind::LAMBDA ){ |
59 |
|
// The following code ensures that if node is equivalent to a constant |
60 |
|
// lambda, then we return the canonical representation for the lambda, which |
61 |
|
// in turn ensures that two constant lambdas are equivalent if and only |
62 |
|
// if they are the same node. |
63 |
|
// We canonicalize lambdas by turning them into array constants, applying |
64 |
|
// normalization on array constants, and then converting the array constant |
65 |
|
// back to a lambda. |
66 |
5742 |
Trace("builtin-rewrite") << "Rewriting lambda " << node << "..." << std::endl; |
67 |
11484 |
Node anode = getArrayRepresentationForLambda( node ); |
68 |
|
// Only rewrite constant array nodes, since these are the only cases |
69 |
|
// where we require canonicalization of lambdas. Moreover, applying the |
70 |
|
// below code is not correct if the arguments to the lambda occur |
71 |
|
// in return values. For example, lambda x. ite( x=1, f(x), c ) would |
72 |
|
// be converted to (store (storeall ... c) 1 f(x)), and then converted |
73 |
|
// to lambda y. ite( y=1, f(x), c), losing the relation between x and y. |
74 |
5742 |
if (!anode.isNull() && anode.isConst()) |
75 |
|
{ |
76 |
2628 |
Assert(anode.getType().isArray()); |
77 |
|
//must get the standard bound variable list |
78 |
4024 |
Node varList = NodeManager::currentNM()->getBoundVarListForFunctionType( node.getType() ); |
79 |
4024 |
Node retNode = getLambdaForArrayRepresentation( anode, varList ); |
80 |
2628 |
if( !retNode.isNull() && retNode!=node ){ |
81 |
1232 |
Trace("builtin-rewrite") << "Rewrote lambda : " << std::endl; |
82 |
1232 |
Trace("builtin-rewrite") << " input : " << node << std::endl; |
83 |
1232 |
Trace("builtin-rewrite") << " output : " << retNode << ", constant = " << retNode.isConst() << std::endl; |
84 |
1232 |
Trace("builtin-rewrite") << " array rep : " << anode << ", constant = " << anode.isConst() << std::endl; |
85 |
1232 |
Assert(anode.isConst() == retNode.isConst()); |
86 |
1232 |
Assert(retNode.getType() == node.getType()); |
87 |
1232 |
Assert(expr::hasFreeVar(node) == expr::hasFreeVar(retNode)); |
88 |
1232 |
return RewriteResponse(REWRITE_DONE, retNode); |
89 |
|
} |
90 |
|
} |
91 |
|
else |
92 |
|
{ |
93 |
3114 |
Trace("builtin-rewrite-debug") << "...failed to get array representation." << std::endl; |
94 |
|
} |
95 |
4510 |
return RewriteResponse(REWRITE_DONE, node); |
96 |
|
} |
97 |
|
// otherwise, do the default call |
98 |
791088 |
return doRewrite(node); |
99 |
|
} |
100 |
|
|
101 |
1216860 |
RewriteResponse TheoryBuiltinRewriter::doRewrite(TNode node) |
102 |
|
{ |
103 |
1216860 |
switch (node.getKind()) |
104 |
|
{ |
105 |
2661 |
case kind::WITNESS: |
106 |
|
{ |
107 |
|
// it is important to run this rewriting at prerewrite and postrewrite, |
108 |
|
// since e.g. arithmetic rewrites equalities in ways that may make an |
109 |
|
// equality not in solved form syntactically, e.g. (= x (+ 1 a)) rewrites |
110 |
|
// to (= a (- x 1)), where x no longer is in solved form. |
111 |
5322 |
Node rnode = rewriteWitness(node); |
112 |
2661 |
return RewriteResponse(REWRITE_DONE, rnode); |
113 |
|
} |
114 |
10510 |
case kind::DISTINCT: |
115 |
10510 |
return RewriteResponse(REWRITE_DONE, blastDistinct(node)); |
116 |
1203689 |
default: return RewriteResponse(REWRITE_DONE, node); |
117 |
|
} |
118 |
|
} |
119 |
|
|
120 |
|
TypeNode TheoryBuiltinRewriter::getFunctionTypeForArrayType(TypeNode atn, |
121 |
|
Node bvl) |
122 |
|
{ |
123 |
|
std::vector<TypeNode> children; |
124 |
|
for (unsigned i = 0; i < bvl.getNumChildren(); i++) |
125 |
|
{ |
126 |
|
Assert(atn.isArray()); |
127 |
|
Assert(bvl[i].getType() == atn.getArrayIndexType()); |
128 |
|
children.push_back(atn.getArrayIndexType()); |
129 |
|
atn = atn.getArrayConstituentType(); |
130 |
|
} |
131 |
|
children.push_back(atn); |
132 |
|
return NodeManager::currentNM()->mkFunctionType(children); |
133 |
|
} |
134 |
|
|
135 |
|
TypeNode TheoryBuiltinRewriter::getArrayTypeForFunctionType(TypeNode ftn) |
136 |
|
{ |
137 |
|
Assert(ftn.isFunction()); |
138 |
|
// construct the curried array type |
139 |
|
unsigned nchildren = ftn.getNumChildren(); |
140 |
|
TypeNode ret = ftn[nchildren - 1]; |
141 |
|
for (int i = (static_cast<int>(nchildren) - 2); i >= 0; i--) |
142 |
|
{ |
143 |
|
ret = NodeManager::currentNM()->mkArrayType(ftn[i], ret); |
144 |
|
} |
145 |
|
return ret; |
146 |
|
} |
147 |
|
|
148 |
16518 |
Node TheoryBuiltinRewriter::getLambdaForArrayRepresentationRec( |
149 |
|
TNode a, |
150 |
|
TNode bvl, |
151 |
|
unsigned bvlIndex, |
152 |
|
std::unordered_map<TNode, Node>& visited) |
153 |
|
{ |
154 |
16518 |
std::unordered_map<TNode, Node>::iterator it = visited.find(a); |
155 |
16518 |
if( it==visited.end() ){ |
156 |
31316 |
Node ret; |
157 |
15658 |
if( bvlIndex<bvl.getNumChildren() ){ |
158 |
8466 |
Assert(a.getType().isArray()); |
159 |
8466 |
if( a.getKind()==kind::STORE ){ |
160 |
|
// convert the array recursively |
161 |
10848 |
Node body = getLambdaForArrayRepresentationRec( a[0], bvl, bvlIndex, visited ); |
162 |
5424 |
if( !body.isNull() ){ |
163 |
|
// convert the value recursively (bounded by the number of arguments in bvl) |
164 |
10848 |
Node val = getLambdaForArrayRepresentationRec( a[2], bvl, bvlIndex+1, visited ); |
165 |
5424 |
if( !val.isNull() ){ |
166 |
5424 |
Assert(!TypeNode::leastCommonTypeNode(a[1].getType(), |
167 |
|
bvl[bvlIndex].getType()) |
168 |
|
.isNull()); |
169 |
5424 |
Assert(!TypeNode::leastCommonTypeNode(val.getType(), body.getType()) |
170 |
|
.isNull()); |
171 |
10848 |
Node cond = bvl[bvlIndex].eqNode( a[1] ); |
172 |
5424 |
ret = NodeManager::currentNM()->mkNode( kind::ITE, cond, val, body ); |
173 |
|
} |
174 |
|
} |
175 |
3042 |
}else if( a.getKind()==kind::STORE_ALL ){ |
176 |
6084 |
ArrayStoreAll storeAll = a.getConst<ArrayStoreAll>(); |
177 |
6084 |
Node sa = storeAll.getValue(); |
178 |
|
// convert the default value recursively (bounded by the number of arguments in bvl) |
179 |
3042 |
ret = getLambdaForArrayRepresentationRec( sa, bvl, bvlIndex+1, visited ); |
180 |
|
} |
181 |
|
}else{ |
182 |
7192 |
ret = a; |
183 |
|
} |
184 |
15658 |
visited[a] = ret; |
185 |
15658 |
return ret; |
186 |
|
}else{ |
187 |
860 |
return it->second; |
188 |
|
} |
189 |
|
} |
190 |
|
|
191 |
2628 |
Node TheoryBuiltinRewriter::getLambdaForArrayRepresentation( TNode a, TNode bvl ){ |
192 |
2628 |
Assert(a.getType().isArray()); |
193 |
5256 |
std::unordered_map<TNode, Node> visited; |
194 |
2628 |
Trace("builtin-rewrite-debug") << "Get lambda for : " << a << ", with variables " << bvl << std::endl; |
195 |
5256 |
Node body = getLambdaForArrayRepresentationRec( a, bvl, 0, visited ); |
196 |
2628 |
if( !body.isNull() ){ |
197 |
2628 |
body = Rewriter::rewrite( body ); |
198 |
2628 |
Trace("builtin-rewrite-debug") << "...got lambda body " << body << std::endl; |
199 |
2628 |
return NodeManager::currentNM()->mkNode( kind::LAMBDA, bvl, body ); |
200 |
|
}else{ |
201 |
|
Trace("builtin-rewrite-debug") << "...failed to get lambda body" << std::endl; |
202 |
|
return Node::null(); |
203 |
|
} |
204 |
|
} |
205 |
|
|
206 |
11171 |
Node TheoryBuiltinRewriter::getArrayRepresentationForLambdaRec(TNode n, |
207 |
|
TypeNode retType) |
208 |
|
{ |
209 |
11171 |
Assert(n.getKind() == kind::LAMBDA); |
210 |
11171 |
NodeManager* nm = NodeManager::currentNM(); |
211 |
11171 |
Trace("builtin-rewrite-debug") << "Get array representation for : " << n << std::endl; |
212 |
|
|
213 |
22342 |
Node first_arg = n[0][0]; |
214 |
22342 |
Node rec_bvl; |
215 |
11171 |
unsigned size = n[0].getNumChildren(); |
216 |
11171 |
if (size > 1) |
217 |
|
{ |
218 |
6156 |
std::vector< Node > args; |
219 |
6673 |
for (unsigned i = 1; i < size; i++) |
220 |
|
{ |
221 |
3595 |
args.push_back( n[0][i] ); |
222 |
|
} |
223 |
3078 |
rec_bvl = nm->mkNode(kind::BOUND_VAR_LIST, args); |
224 |
|
} |
225 |
|
|
226 |
11171 |
Trace("builtin-rewrite-debug2") << " process body..." << std::endl; |
227 |
22342 |
std::vector< Node > conds; |
228 |
22342 |
std::vector< Node > vals; |
229 |
22342 |
Node curr = n[1]; |
230 |
11171 |
Kind ck = curr.getKind(); |
231 |
19117 |
while (ck == kind::ITE || ck == kind::OR || ck == kind::AND |
232 |
29679 |
|| ck == kind::EQUAL || ck == kind::NOT || ck == kind::BOUND_VARIABLE) |
233 |
|
{ |
234 |
17124 |
Node index_eq; |
235 |
17124 |
Node curr_val; |
236 |
17124 |
Node next; |
237 |
|
// Each iteration of this loop infers an entry in the function, e.g. it |
238 |
|
// has a value under some condition. |
239 |
|
|
240 |
|
// [1] We infer that the entry has value "curr_val" under condition |
241 |
|
// "index_eq". We set "next" to the node that is the remainder of the |
242 |
|
// function to process. |
243 |
9391 |
if (ck == kind::ITE) |
244 |
|
{ |
245 |
15040 |
Trace("builtin-rewrite-debug2") |
246 |
7520 |
<< " process condition : " << curr[0] << std::endl; |
247 |
7520 |
index_eq = curr[0]; |
248 |
7520 |
curr_val = curr[1]; |
249 |
7520 |
next = curr[2]; |
250 |
|
} |
251 |
1871 |
else if (ck == kind::OR || ck == kind::AND) |
252 |
|
{ |
253 |
1218 |
Trace("builtin-rewrite-debug2") |
254 |
609 |
<< " process base : " << curr << std::endl; |
255 |
|
// curr = Rewriter::rewrite(curr); |
256 |
|
// Trace("builtin-rewrite-debug2") |
257 |
|
// << " rewriten base : " << curr << std::endl; |
258 |
|
// Complex Boolean return cases, in which |
259 |
|
// (1) lambda x. (= x v1) v ... becomes |
260 |
|
// lambda x. (ite (= x v1) true [...]) |
261 |
|
// |
262 |
|
// (2) lambda x. (not (= x v1)) ^ ... becomes |
263 |
|
// lambda x. (ite (= x v1) false [...]) |
264 |
|
// |
265 |
|
// Note the negated cases of the lhs of the OR/AND operators above are |
266 |
|
// handled by pushing the recursion to the then-branch, with the |
267 |
|
// else-branch being the constant value. For example, the negated (1) |
268 |
|
// would be |
269 |
|
// (1') lambda x. (not (= x v1)) v ... becomes |
270 |
|
// lambda x. (ite (= x v1) [...] true) |
271 |
|
// thus requiring the rest of the disjunction to be further processed in |
272 |
|
// the then-branch as the current value. |
273 |
609 |
bool pol = curr[0].getKind() != kind::NOT; |
274 |
609 |
bool inverted = (pol && ck == kind::AND) || (!pol && ck == kind::OR); |
275 |
609 |
index_eq = pol ? curr[0] : curr[0][0]; |
276 |
|
// processed : the value that is determined by the first child of curr |
277 |
|
// remainder : the remaining children of curr |
278 |
1049 |
Node processed, remainder; |
279 |
|
// the value is the polarity of the first child or its inverse if we are |
280 |
|
// in the inverted case |
281 |
609 |
processed = nm->mkConst(!inverted? pol : !pol); |
282 |
|
// build an OR/AND with the remaining components |
283 |
609 |
if (curr.getNumChildren() == 2) |
284 |
|
{ |
285 |
593 |
remainder = curr[1]; |
286 |
|
} |
287 |
|
else |
288 |
|
{ |
289 |
32 |
std::vector<Node> remainderNodes{curr.begin() + 1, curr.end()}; |
290 |
16 |
remainder = nm->mkNode(ck, remainderNodes); |
291 |
|
} |
292 |
609 |
if (inverted) |
293 |
|
{ |
294 |
367 |
curr_val = remainder; |
295 |
367 |
next = processed; |
296 |
|
// If the lambda contains more variables than the one being currently |
297 |
|
// processed, the current value can be non-constant, since it'll be |
298 |
|
// processed recursively below. Otherwise we fail. |
299 |
367 |
if (rec_bvl.isNull() && !curr_val.isConst()) |
300 |
|
{ |
301 |
338 |
Trace("builtin-rewrite-debug2") |
302 |
169 |
<< "...non-const curr_val " << curr_val << "\n"; |
303 |
169 |
return Node::null(); |
304 |
|
} |
305 |
|
} |
306 |
|
else |
307 |
|
{ |
308 |
242 |
curr_val = processed; |
309 |
242 |
next = remainder; |
310 |
|
} |
311 |
440 |
Trace("builtin-rewrite-debug2") << " index_eq : " << index_eq << "\n"; |
312 |
440 |
Trace("builtin-rewrite-debug2") << " curr_val : " << curr_val << "\n"; |
313 |
880 |
Trace("builtin-rewrite-debug2") << " next : " << next << std::endl; |
314 |
|
} |
315 |
|
else |
316 |
|
{ |
317 |
2524 |
Trace("builtin-rewrite-debug2") |
318 |
1262 |
<< " process base : " << curr << std::endl; |
319 |
|
// Simple Boolean return cases, in which |
320 |
|
// (1) lambda x. (= x v) becomes lambda x. (ite (= x v) true false) |
321 |
|
// (2) lambda x. v becomes lambda x. (ite (= x v) true false) |
322 |
|
// Note the negateg cases of the bodies above are also handled. |
323 |
1262 |
bool pol = ck != kind::NOT; |
324 |
1262 |
index_eq = pol ? curr : curr[0]; |
325 |
1262 |
curr_val = nm->mkConst(pol); |
326 |
1262 |
next = nm->mkConst(!pol); |
327 |
|
} |
328 |
|
|
329 |
|
// [2] We ensure that "index_eq" is an equality, if possible. |
330 |
9222 |
if (index_eq.getKind() != kind::EQUAL) |
331 |
|
{ |
332 |
1649 |
bool pol = index_eq.getKind() != kind::NOT; |
333 |
2400 |
Node indexEqAtom = pol ? index_eq : index_eq[0]; |
334 |
1649 |
if (indexEqAtom.getKind() == kind::BOUND_VARIABLE) |
335 |
|
{ |
336 |
1083 |
if (!indexEqAtom.getType().isBoolean()) |
337 |
|
{ |
338 |
|
// Catches default case of non-Boolean variable, e.g. |
339 |
|
// lambda x : Int. x. In this case, it is not canonical and we fail. |
340 |
664 |
Trace("builtin-rewrite-debug2") |
341 |
332 |
<< " ...non-Boolean variable." << std::endl; |
342 |
332 |
return Node::null(); |
343 |
|
} |
344 |
|
// Boolean argument case, e.g. lambda x. ite( x, t, s ) is processed as |
345 |
|
// lambda x. (ite (= x true) t s) |
346 |
751 |
index_eq = indexEqAtom.eqNode(nm->mkConst(pol)); |
347 |
|
} |
348 |
|
else |
349 |
|
{ |
350 |
|
// non-equality condition |
351 |
1132 |
Trace("builtin-rewrite-debug2") |
352 |
566 |
<< " ...non-equality condition." << std::endl; |
353 |
566 |
return Node::null(); |
354 |
|
} |
355 |
|
} |
356 |
7573 |
else if (Rewriter::rewrite(index_eq) != index_eq) |
357 |
|
{ |
358 |
|
// equality must be oriented correctly based on rewriter |
359 |
9 |
Trace("builtin-rewrite-debug2") << " ...equality not oriented properly." << std::endl; |
360 |
9 |
return Node::null(); |
361 |
|
} |
362 |
|
|
363 |
|
// [3] We ensure that "index_eq" is an equality that is equivalent to |
364 |
|
// "first_arg" = "curr_index", where curr_index is a constant, and |
365 |
|
// "first_arg" is the current argument we are processing, if possible. |
366 |
16048 |
Node curr_index; |
367 |
10115 |
for( unsigned r=0; r<2; r++ ){ |
368 |
11732 |
Node arg = index_eq[r]; |
369 |
11732 |
Node val = index_eq[1-r]; |
370 |
9932 |
if( arg==first_arg ){ |
371 |
8132 |
if (!val.isConst()) |
372 |
|
{ |
373 |
|
// non-constant value |
374 |
400 |
Trace("builtin-rewrite-debug2") |
375 |
200 |
<< " ...non-constant value for argument\n."; |
376 |
200 |
return Node::null(); |
377 |
|
}else{ |
378 |
7932 |
curr_index = val; |
379 |
15864 |
Trace("builtin-rewrite-debug2") |
380 |
7932 |
<< " arg " << arg << " -> " << val << std::endl; |
381 |
7932 |
break; |
382 |
|
} |
383 |
|
} |
384 |
|
} |
385 |
8115 |
if (curr_index.isNull()) |
386 |
|
{ |
387 |
366 |
Trace("builtin-rewrite-debug2") |
388 |
183 |
<< " ...could not infer index value." << std::endl; |
389 |
183 |
return Node::null(); |
390 |
|
} |
391 |
|
|
392 |
|
// [4] Recurse to ensure that "curr_val" has been normalized w.r.t. the |
393 |
|
// remaining arguments (rec_bvl). |
394 |
7932 |
if (!rec_bvl.isNull()) |
395 |
|
{ |
396 |
1447 |
curr_val = nm->mkNode(kind::LAMBDA, rec_bvl, curr_val); |
397 |
1447 |
Trace("builtin-rewrite-debug") << push; |
398 |
1447 |
Trace("builtin-rewrite-debug2") << push; |
399 |
1447 |
curr_val = getArrayRepresentationForLambdaRec(curr_val, retType); |
400 |
1447 |
Trace("builtin-rewrite-debug") << pop; |
401 |
1447 |
Trace("builtin-rewrite-debug2") << pop; |
402 |
1447 |
if (curr_val.isNull()) |
403 |
|
{ |
404 |
398 |
Trace("builtin-rewrite-debug2") |
405 |
199 |
<< " ...failed to recursively find value." << std::endl; |
406 |
199 |
return Node::null(); |
407 |
|
} |
408 |
|
} |
409 |
15466 |
Trace("builtin-rewrite-debug2") |
410 |
7733 |
<< " ...condition is index " << curr_val << std::endl; |
411 |
|
|
412 |
|
// [5] Add the entry |
413 |
7733 |
conds.push_back( curr_index ); |
414 |
7733 |
vals.push_back( curr_val ); |
415 |
|
|
416 |
|
// we will now process the remainder |
417 |
7733 |
curr = next; |
418 |
7733 |
ck = curr.getKind(); |
419 |
15466 |
Trace("builtin-rewrite-debug2") |
420 |
7733 |
<< " process remainder : " << curr << std::endl; |
421 |
|
} |
422 |
9513 |
if( !rec_bvl.isNull() ){ |
423 |
2270 |
curr = nm->mkNode(kind::LAMBDA, rec_bvl, curr); |
424 |
2270 |
Trace("builtin-rewrite-debug") << push; |
425 |
2270 |
Trace("builtin-rewrite-debug2") << push; |
426 |
2270 |
curr = getArrayRepresentationForLambdaRec(curr, retType); |
427 |
2270 |
Trace("builtin-rewrite-debug") << pop; |
428 |
2270 |
Trace("builtin-rewrite-debug2") << pop; |
429 |
|
} |
430 |
9513 |
if( !curr.isNull() && curr.isConst() ){ |
431 |
|
// compute the return type |
432 |
10220 |
TypeNode array_type = retType; |
433 |
11033 |
for (unsigned i = 0; i < size; i++) |
434 |
|
{ |
435 |
5923 |
unsigned index = (size - 1) - i; |
436 |
5923 |
array_type = nm->mkArrayType(n[0][index].getType(), array_type); |
437 |
|
} |
438 |
5110 |
Trace("builtin-rewrite-debug2") << " make array store all " << curr.getType() << " annotated : " << array_type << std::endl; |
439 |
5110 |
Assert(curr.getType().isSubtypeOf(array_type.getArrayConstituentType())); |
440 |
5110 |
curr = nm->mkConst(ArrayStoreAll(array_type, curr)); |
441 |
5110 |
Trace("builtin-rewrite-debug2") << " build array..." << std::endl; |
442 |
|
// can only build if default value is constant (since array store all must be constant) |
443 |
5110 |
Trace("builtin-rewrite-debug2") << " got constant base " << curr << std::endl; |
444 |
5110 |
Trace("builtin-rewrite-debug2") << " conditions " << conds << std::endl; |
445 |
5110 |
Trace("builtin-rewrite-debug2") << " values " << vals << std::endl; |
446 |
|
// construct store chain |
447 |
12609 |
for (int i = static_cast<int>(conds.size()) - 1; i >= 0; i--) |
448 |
|
{ |
449 |
7499 |
Assert(conds[i].getType().isSubtypeOf(first_arg.getType())); |
450 |
7499 |
curr = nm->mkNode(kind::STORE, curr, conds[i], vals[i]); |
451 |
|
} |
452 |
5110 |
Trace("builtin-rewrite-debug") << "...got array " << curr << " for " << n << std::endl; |
453 |
5110 |
return curr; |
454 |
|
}else{ |
455 |
4403 |
Trace("builtin-rewrite-debug") << "...failed to get array (cannot get constant default value)" << std::endl; |
456 |
4403 |
return Node::null(); |
457 |
|
} |
458 |
|
} |
459 |
|
|
460 |
2661 |
Node TheoryBuiltinRewriter::rewriteWitness(TNode node) |
461 |
|
{ |
462 |
2661 |
Assert(node.getKind() == kind::WITNESS); |
463 |
2661 |
if (node[1].getKind() == kind::EQUAL) |
464 |
|
{ |
465 |
198 |
for (size_t i = 0; i < 2; i++) |
466 |
|
{ |
467 |
|
// (witness ((x T)) (= x t)) ---> t |
468 |
132 |
if (node[1][i] == node[0][0]) |
469 |
|
{ |
470 |
|
Trace("builtin-rewrite") << "Witness rewrite: " << node << " --> " |
471 |
|
<< node[1][1 - i] << std::endl; |
472 |
|
// also must be a legal elimination: the other side of the equality |
473 |
|
// cannot contain the variable, and it must be a subtype of the |
474 |
|
// variable |
475 |
|
if (!expr::hasSubterm(node[1][1 - i], node[0][0]) |
476 |
|
&& node[1][i].getType().isSubtypeOf(node[0][0].getType())) |
477 |
|
{ |
478 |
|
return node[1][1 - i]; |
479 |
|
} |
480 |
|
} |
481 |
|
} |
482 |
|
} |
483 |
2595 |
else if (node[1] == node[0][0]) |
484 |
|
{ |
485 |
|
// (witness ((x Bool)) x) ---> true |
486 |
|
return NodeManager::currentNM()->mkConst(true); |
487 |
|
} |
488 |
2595 |
else if (node[1].getKind() == kind::NOT && node[1][0] == node[0][0]) |
489 |
|
{ |
490 |
|
// (witness ((x Bool)) (not x)) ---> false |
491 |
|
return NodeManager::currentNM()->mkConst(false); |
492 |
|
} |
493 |
2661 |
return node; |
494 |
|
} |
495 |
|
|
496 |
7454 |
Node TheoryBuiltinRewriter::getArrayRepresentationForLambda(TNode n) |
497 |
|
{ |
498 |
7454 |
Assert(n.getKind() == kind::LAMBDA); |
499 |
|
// must carry the overall return type to deal with cases like (lambda ((x Int) |
500 |
|
// (y Int)) (ite (= x _) 0.5 0.0)), where the inner construction for the else |
501 |
|
// case above should be (arraystoreall (Array Int Real) 0.0) |
502 |
14908 |
Node anode = getArrayRepresentationForLambdaRec(n, n[1].getType()); |
503 |
7454 |
if (anode.isNull()) |
504 |
|
{ |
505 |
4320 |
return anode; |
506 |
|
} |
507 |
|
// must rewrite it to make canonical |
508 |
3134 |
return Rewriter::rewrite(anode); |
509 |
|
} |
510 |
|
|
511 |
|
} // namespace builtin |
512 |
|
} // namespace theory |
513 |
29349 |
} // namespace cvc5 |