1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Mathias Preiner, Aina Niemetz, Andres Noetzli |
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 ceg_bv_instantiator. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/cegqi/ceg_bv_instantiator_utils.h" |
17 |
|
|
18 |
|
#include "theory/bv/theory_bv_utils.h" |
19 |
|
#include "theory/rewriter.h" |
20 |
|
|
21 |
|
using namespace cvc5::kind; |
22 |
|
|
23 |
|
namespace cvc5 { |
24 |
|
namespace theory { |
25 |
|
namespace quantifiers { |
26 |
|
namespace utils { |
27 |
|
|
28 |
746 |
Node getPvCoeff(TNode pv, TNode n) |
29 |
|
{ |
30 |
746 |
bool neg = false; |
31 |
1492 |
Node coeff; |
32 |
|
|
33 |
746 |
if (n.getKind() == BITVECTOR_NEG) |
34 |
|
{ |
35 |
2 |
neg = true; |
36 |
2 |
n = n[0]; |
37 |
|
} |
38 |
|
|
39 |
746 |
if (n == pv) |
40 |
|
{ |
41 |
640 |
coeff = bv::utils::mkOne(bv::utils::getSize(pv)); |
42 |
|
} |
43 |
|
/* All multiplications are normalized to pv * (t1 * t2). */ |
44 |
106 |
else if (n.getKind() == BITVECTOR_MULT && n.getAttribute(BvLinearAttribute())) |
45 |
|
{ |
46 |
104 |
Assert(n.getNumChildren() == 2); |
47 |
104 |
Assert(n[0] == pv); |
48 |
104 |
coeff = n[1]; |
49 |
|
} |
50 |
|
else /* n is in no form to extract the coefficient for pv */ |
51 |
|
{ |
52 |
4 |
Trace("cegqi-bv-nl") << "Cannot extract coefficient for " << pv << " in " |
53 |
2 |
<< n << std::endl; |
54 |
2 |
return Node::null(); |
55 |
|
} |
56 |
744 |
Assert(!coeff.isNull()); |
57 |
|
|
58 |
744 |
if (neg) return NodeManager::currentNM()->mkNode(BITVECTOR_NEG, coeff); |
59 |
742 |
return coeff; |
60 |
|
} |
61 |
|
|
62 |
982 |
Node normalizePvMult(TNode pv, |
63 |
|
const std::vector<Node>& children, |
64 |
|
std::unordered_map<Node, bool>& contains_pv) |
65 |
|
{ |
66 |
982 |
bool neg, neg_coeff = false; |
67 |
982 |
bool found_pv = false; |
68 |
|
NodeManager* nm; |
69 |
1964 |
NodeBuilder nb(BITVECTOR_MULT); |
70 |
|
BvLinearAttribute is_linear; |
71 |
|
|
72 |
982 |
nm = NodeManager::currentNM(); |
73 |
2912 |
for (TNode nc : children) |
74 |
|
{ |
75 |
2950 |
if (!contains_pv[nc]) |
76 |
|
{ |
77 |
978 |
nb << nc; |
78 |
978 |
continue; |
79 |
|
} |
80 |
|
|
81 |
994 |
neg = false; |
82 |
994 |
if (nc.getKind() == BITVECTOR_NEG) |
83 |
|
{ |
84 |
8 |
neg = true; |
85 |
8 |
nc = nc[0]; |
86 |
|
} |
87 |
|
|
88 |
1942 |
if (!found_pv && nc == pv) |
89 |
|
{ |
90 |
948 |
found_pv = true; |
91 |
948 |
neg_coeff = neg; |
92 |
948 |
continue; |
93 |
|
} |
94 |
128 |
else if (!found_pv && nc.getKind() == BITVECTOR_MULT |
95 |
50 |
&& nc.getAttribute(is_linear)) |
96 |
|
{ |
97 |
4 |
Assert(nc.getNumChildren() == 2); |
98 |
4 |
Assert(nc[0] == pv); |
99 |
4 |
Assert(!contains_pv[nc[1]]); |
100 |
4 |
found_pv = true; |
101 |
4 |
neg_coeff = neg; |
102 |
4 |
nb << nc[1]; |
103 |
4 |
continue; |
104 |
|
} |
105 |
42 |
return Node::null(); /* non-linear */ |
106 |
|
} |
107 |
940 |
Assert(nb.getNumChildren() > 0); |
108 |
|
|
109 |
1880 |
Node coeff = (nb.getNumChildren() == 1) ? nb[0] : nb.constructNode(); |
110 |
940 |
if (neg_coeff) |
111 |
|
{ |
112 |
6 |
coeff = nm->mkNode(BITVECTOR_NEG, coeff); |
113 |
|
} |
114 |
940 |
coeff = Rewriter::rewrite(coeff); |
115 |
940 |
unsigned size_coeff = bv::utils::getSize(coeff); |
116 |
1880 |
Node zero = bv::utils::mkZero(size_coeff); |
117 |
940 |
if (coeff == zero) |
118 |
|
{ |
119 |
12 |
return zero; |
120 |
|
} |
121 |
1856 |
Node result; |
122 |
928 |
if (found_pv) |
123 |
|
{ |
124 |
926 |
if (coeff == bv::utils::mkOne(size_coeff)) |
125 |
|
{ |
126 |
562 |
return pv; |
127 |
|
} |
128 |
364 |
result = nm->mkNode(BITVECTOR_MULT, pv, coeff); |
129 |
364 |
contains_pv[result] = true; |
130 |
364 |
result.setAttribute(is_linear, true); |
131 |
|
} |
132 |
|
else |
133 |
|
{ |
134 |
2 |
result = coeff; |
135 |
|
} |
136 |
366 |
return result; |
137 |
|
} |
138 |
|
|
139 |
|
#ifdef CVC5_ASSERTIONS |
140 |
|
namespace { |
141 |
28 |
bool isLinearPlus(TNode n, |
142 |
|
TNode pv, |
143 |
|
std::unordered_map<Node, bool>& contains_pv) |
144 |
|
{ |
145 |
56 |
Node coeff; |
146 |
28 |
Assert(n.getAttribute(BvLinearAttribute())); |
147 |
28 |
Assert(n.getNumChildren() == 2); |
148 |
28 |
if (n[0] != pv) |
149 |
|
{ |
150 |
8 |
Assert(n[0].getKind() == BITVECTOR_MULT); |
151 |
8 |
Assert(n[0].getNumChildren() == 2); |
152 |
8 |
Assert(n[0][0] == pv); |
153 |
8 |
Assert(!contains_pv[n[0][1]]); |
154 |
|
} |
155 |
28 |
Assert(!contains_pv[n[1]]); |
156 |
28 |
coeff = utils::getPvCoeff(pv, n[0]); |
157 |
28 |
Assert(!coeff.isNull()); |
158 |
28 |
Assert(!contains_pv[coeff]); |
159 |
56 |
return true; |
160 |
|
} |
161 |
|
} // namespace |
162 |
|
#endif |
163 |
|
|
164 |
1407 |
Node normalizePvPlus(Node pv, |
165 |
|
const std::vector<Node>& children, |
166 |
|
std::unordered_map<Node, bool>& contains_pv) |
167 |
|
{ |
168 |
|
NodeManager* nm; |
169 |
2814 |
NodeBuilder nb_c(BITVECTOR_ADD); |
170 |
2814 |
NodeBuilder nb_l(BITVECTOR_ADD); |
171 |
|
BvLinearAttribute is_linear; |
172 |
|
bool neg; |
173 |
|
|
174 |
1407 |
nm = NodeManager::currentNM(); |
175 |
2793 |
for (TNode nc : children) |
176 |
|
{ |
177 |
2873 |
if (!contains_pv[nc]) |
178 |
|
{ |
179 |
730 |
nb_l << nc; |
180 |
730 |
continue; |
181 |
|
} |
182 |
|
|
183 |
1413 |
neg = false; |
184 |
1413 |
if (nc.getKind() == BITVECTOR_NEG) |
185 |
|
{ |
186 |
144 |
neg = true; |
187 |
144 |
nc = nc[0]; |
188 |
|
} |
189 |
|
|
190 |
2826 |
if (nc == pv |
191 |
1413 |
|| (nc.getKind() == BITVECTOR_MULT && nc.getAttribute(is_linear))) |
192 |
|
{ |
193 |
1288 |
Node coeff = utils::getPvCoeff(pv, nc); |
194 |
644 |
Assert(!coeff.isNull()); |
195 |
644 |
if (neg) |
196 |
|
{ |
197 |
32 |
coeff = nm->mkNode(BITVECTOR_NEG, coeff); |
198 |
|
} |
199 |
644 |
nb_c << coeff; |
200 |
644 |
continue; |
201 |
|
} |
202 |
769 |
else if (nc.getKind() == BITVECTOR_ADD && nc.getAttribute(is_linear)) |
203 |
|
{ |
204 |
12 |
Assert(isLinearPlus(nc, pv, contains_pv)); |
205 |
24 |
Node coeff = utils::getPvCoeff(pv, nc[0]); |
206 |
12 |
Assert(!coeff.isNull()); |
207 |
24 |
Node leaf = nc[1]; |
208 |
12 |
if (neg) |
209 |
|
{ |
210 |
2 |
coeff = nm->mkNode(BITVECTOR_NEG, coeff); |
211 |
2 |
leaf = nm->mkNode(BITVECTOR_NEG, leaf); |
212 |
|
} |
213 |
12 |
nb_c << coeff; |
214 |
12 |
nb_l << leaf; |
215 |
12 |
continue; |
216 |
|
} |
217 |
|
/* can't collect coefficients of 'pv' in 'cur' -> non-linear */ |
218 |
757 |
return Node::null(); |
219 |
|
} |
220 |
650 |
Assert(nb_c.getNumChildren() > 0 || nb_l.getNumChildren() > 0); |
221 |
|
|
222 |
1300 |
Node pv_mult_coeffs, result; |
223 |
650 |
if (nb_c.getNumChildren() > 0) |
224 |
|
{ |
225 |
1296 |
Node coeffs = (nb_c.getNumChildren() == 1) ? nb_c[0] : nb_c.constructNode(); |
226 |
648 |
coeffs = Rewriter::rewrite(coeffs); |
227 |
648 |
result = pv_mult_coeffs = |
228 |
1296 |
utils::normalizePvMult(pv, {pv, coeffs}, contains_pv); |
229 |
|
} |
230 |
|
|
231 |
650 |
if (nb_l.getNumChildren() > 0) |
232 |
|
{ |
233 |
1288 |
Node leafs = (nb_l.getNumChildren() == 1) ? nb_l[0] : nb_l.constructNode(); |
234 |
644 |
leafs = Rewriter::rewrite(leafs); |
235 |
1288 |
Node zero = bv::utils::mkZero(bv::utils::getSize(pv)); |
236 |
|
/* pv * 0 + t --> t */ |
237 |
644 |
if (pv_mult_coeffs.isNull() || pv_mult_coeffs == zero) |
238 |
|
{ |
239 |
4 |
result = leafs; |
240 |
|
} |
241 |
|
else |
242 |
|
{ |
243 |
640 |
result = nm->mkNode(BITVECTOR_ADD, pv_mult_coeffs, leafs); |
244 |
640 |
contains_pv[result] = true; |
245 |
640 |
result.setAttribute(is_linear, true); |
246 |
|
} |
247 |
|
} |
248 |
650 |
Assert(!result.isNull()); |
249 |
650 |
return result; |
250 |
|
} |
251 |
|
|
252 |
33 |
Node normalizePvEqual(Node pv, |
253 |
|
const std::vector<Node>& children, |
254 |
|
std::unordered_map<Node, bool>& contains_pv) |
255 |
|
{ |
256 |
33 |
Assert(children.size() == 2); |
257 |
|
|
258 |
33 |
NodeManager* nm = NodeManager::currentNM(); |
259 |
|
BvLinearAttribute is_linear; |
260 |
66 |
Node coeffs[2], leafs[2]; |
261 |
|
bool neg; |
262 |
66 |
TNode child; |
263 |
|
|
264 |
99 |
for (unsigned i = 0; i < 2; ++i) |
265 |
|
{ |
266 |
66 |
child = children[i]; |
267 |
66 |
neg = false; |
268 |
66 |
if (child.getKind() == BITVECTOR_NEG) |
269 |
|
{ |
270 |
4 |
neg = true; |
271 |
4 |
child = child[0]; |
272 |
|
} |
273 |
66 |
if (child.getAttribute(is_linear) || child == pv) |
274 |
|
{ |
275 |
52 |
if (child.getKind() == BITVECTOR_ADD) |
276 |
|
{ |
277 |
16 |
Assert(isLinearPlus(child, pv, contains_pv)); |
278 |
16 |
coeffs[i] = utils::getPvCoeff(pv, child[0]); |
279 |
16 |
leafs[i] = child[1]; |
280 |
|
} |
281 |
|
else |
282 |
|
{ |
283 |
36 |
Assert(child.getKind() == BITVECTOR_MULT || child == pv); |
284 |
36 |
coeffs[i] = utils::getPvCoeff(pv, child); |
285 |
|
} |
286 |
|
} |
287 |
66 |
if (neg) |
288 |
|
{ |
289 |
4 |
if (!coeffs[i].isNull()) |
290 |
|
{ |
291 |
4 |
coeffs[i] = nm->mkNode(BITVECTOR_NEG, coeffs[i]); |
292 |
|
} |
293 |
4 |
if (!leafs[i].isNull()) |
294 |
|
{ |
295 |
2 |
leafs[i] = nm->mkNode(BITVECTOR_NEG, leafs[i]); |
296 |
|
} |
297 |
|
} |
298 |
|
} |
299 |
|
|
300 |
33 |
if (coeffs[0].isNull() || coeffs[1].isNull()) |
301 |
|
{ |
302 |
11 |
return Node::null(); |
303 |
|
} |
304 |
|
|
305 |
44 |
Node coeff = nm->mkNode(BITVECTOR_SUB, coeffs[0], coeffs[1]); |
306 |
22 |
coeff = Rewriter::rewrite(coeff); |
307 |
44 |
std::vector<Node> mult_children = {pv, coeff}; |
308 |
44 |
Node lhs = utils::normalizePvMult(pv, mult_children, contains_pv); |
309 |
|
|
310 |
44 |
Node rhs; |
311 |
22 |
if (!leafs[0].isNull() && !leafs[1].isNull()) |
312 |
|
{ |
313 |
2 |
rhs = nm->mkNode(BITVECTOR_SUB, leafs[1], leafs[0]); |
314 |
|
} |
315 |
20 |
else if (!leafs[0].isNull()) |
316 |
|
{ |
317 |
8 |
rhs = nm->mkNode(BITVECTOR_NEG, leafs[0]); |
318 |
|
} |
319 |
12 |
else if (!leafs[1].isNull()) |
320 |
|
{ |
321 |
2 |
rhs = leafs[1]; |
322 |
|
} |
323 |
|
else |
324 |
|
{ |
325 |
10 |
rhs = bv::utils::mkZero(bv::utils::getSize(pv)); |
326 |
|
} |
327 |
22 |
rhs = Rewriter::rewrite(rhs); |
328 |
|
|
329 |
22 |
if (lhs == rhs) |
330 |
|
{ |
331 |
2 |
return bv::utils::mkTrue(); |
332 |
|
} |
333 |
|
|
334 |
40 |
Node result = lhs.eqNode(rhs); |
335 |
20 |
contains_pv[result] = true; |
336 |
20 |
return result; |
337 |
|
} |
338 |
|
|
339 |
|
} // namespace utils |
340 |
|
} // namespace quantifiers |
341 |
|
} // namespace theory |
342 |
29514 |
} // namespace cvc5 |