|
11 | 11 | #include <util/arith_tools.h>
|
12 | 12 | #include <util/format_expr.h>
|
13 | 13 | #include <util/namespace.h>
|
| 14 | +#include <util/replace_expr.h> |
14 | 15 | #include <util/std_expr.h>
|
15 | 16 | #include <util/std_types.h>
|
16 | 17 |
|
@@ -38,8 +39,8 @@ void arrayst::record_array_index(const index_exprt &index)
|
38 | 39 | // entry for the root of the equivalence class
|
39 | 40 | // because this map is accessed during building the error trace
|
40 | 41 | std::size_t number=arrays.number(index.array());
|
41 |
| - index_map[number].insert(index.index()); |
42 |
| - update_indices.insert(number); |
| 42 | + if(index_map[number].insert(index.index()).second) |
| 43 | + update_indices.insert(number); |
43 | 44 | }
|
44 | 45 |
|
45 | 46 | literalt arrayst::record_array_equality(
|
@@ -82,11 +83,24 @@ void arrayst::collect_indices(const exprt &expr)
|
82 | 83 | {
|
83 | 84 | if(expr.id()!=ID_index)
|
84 | 85 | {
|
| 86 | + if(expr.id() == ID_lambda) |
| 87 | + array_comprehension_args.insert( |
| 88 | + to_array_comprehension_expr(expr).arg().get_identifier()); |
| 89 | + |
85 | 90 | forall_operands(op, expr) collect_indices(*op);
|
86 | 91 | }
|
87 | 92 | else
|
88 | 93 | {
|
89 | 94 | const index_exprt &e = to_index_expr(expr);
|
| 95 | + |
| 96 | + if( |
| 97 | + e.index().id() == ID_symbol && |
| 98 | + array_comprehension_args.count( |
| 99 | + to_symbol_expr(e.index()).get_identifier()) != 0) |
| 100 | + { |
| 101 | + return; |
| 102 | + } |
| 103 | + |
90 | 104 | collect_indices(e.index()); // necessary?
|
91 | 105 |
|
92 | 106 | const typet &array_op_type = e.array().type();
|
@@ -214,6 +228,9 @@ void arrayst::collect_arrays(const exprt &a)
|
214 | 228 | arrays.make_union(a, a.op0());
|
215 | 229 | collect_arrays(a.op0());
|
216 | 230 | }
|
| 231 | + else if(a.id() == ID_lambda) |
| 232 | + { |
| 233 | + } |
217 | 234 | else
|
218 | 235 | {
|
219 | 236 | DATA_INVARIANT(
|
@@ -257,17 +274,32 @@ void arrayst::add_array_constraints()
|
257 | 274 | // reduce initial index map
|
258 | 275 | update_index_map(true);
|
259 | 276 |
|
260 |
| - // add constraints for if, with, array_of |
| 277 | + // add constraints for if, with, array_of, lambda |
| 278 | + std::set<std::size_t> roots_to_process, updated_roots; |
261 | 279 | for(std::size_t i=0; i<arrays.size(); i++)
|
| 280 | + roots_to_process.insert(arrays.find_number(i)); |
| 281 | + |
| 282 | + while(!roots_to_process.empty()) |
262 | 283 | {
|
263 |
| - // take a copy as arrays may get modified by add_array_constraints |
264 |
| - // in case of nested unbounded arrays |
265 |
| - exprt a=arrays[i]; |
| 284 | + for(std::size_t i = 0; i < arrays.size(); i++) |
| 285 | + { |
| 286 | + if(roots_to_process.count(arrays.find_number(i)) == 0) |
| 287 | + continue; |
| 288 | + |
| 289 | + // take a copy as arrays may get modified by add_array_constraints |
| 290 | + // in case of nested unbounded arrays |
| 291 | + exprt a = arrays[i]; |
266 | 292 |
|
267 |
| - add_array_constraints(index_map[arrays.find_number(i)], a); |
| 293 | + add_array_constraints(index_map[arrays.find_number(i)], a); |
268 | 294 |
|
269 |
| - // we have to update before it gets used in the next add_* call |
270 |
| - update_index_map(false); |
| 295 | + // we have to update before it gets used in the next add_* call |
| 296 | + for(const std::size_t u : update_indices) |
| 297 | + updated_roots.insert(arrays.find_number(u)); |
| 298 | + update_index_map(false); |
| 299 | + } |
| 300 | + |
| 301 | + roots_to_process = std::move(updated_roots); |
| 302 | + updated_roots.clear(); |
271 | 303 | }
|
272 | 304 |
|
273 | 305 | // add constraints for equalities
|
@@ -438,6 +470,11 @@ void arrayst::add_array_constraints(
|
438 | 470 | return add_array_constraints_array_of(index_set, to_array_of_expr(expr));
|
439 | 471 | else if(expr.id() == ID_array)
|
440 | 472 | return add_array_constraints_array_constant(index_set, to_array_expr(expr));
|
| 473 | + else if(expr.id() == ID_lambda) |
| 474 | + { |
| 475 | + return add_array_constraints_comprehension( |
| 476 | + index_set, to_array_comprehension_expr(expr)); |
| 477 | + } |
441 | 478 | else if(expr.id()==ID_symbol ||
|
442 | 479 | expr.id()==ID_nondet_symbol ||
|
443 | 480 | expr.id()==ID_constant ||
|
@@ -727,6 +764,28 @@ void arrayst::add_array_constraints_array_constant(
|
727 | 764 | }
|
728 | 765 | }
|
729 | 766 |
|
| 767 | +void arrayst::add_array_constraints_comprehension( |
| 768 | + const index_sett &index_set, |
| 769 | + const array_comprehension_exprt &expr) |
| 770 | +{ |
| 771 | + // we got x=lambda(i: e) |
| 772 | + // get all other array index applications |
| 773 | + // and add constraints x[j]=e[i/j] |
| 774 | + |
| 775 | + for(const auto &index : index_set) |
| 776 | + { |
| 777 | + index_exprt index_expr{expr, index}; |
| 778 | + exprt comprehension_body = expr.body(); |
| 779 | + replace_expr(expr.arg(), index, comprehension_body); |
| 780 | + |
| 781 | + // add constraint |
| 782 | + lazy_constraintt lazy( |
| 783 | + lazy_typet::ARRAY_COMPREHENSION, |
| 784 | + equal_exprt(index_expr, comprehension_body)); |
| 785 | + add_array_constraint(lazy, false); // added immediately |
| 786 | + } |
| 787 | +} |
| 788 | + |
730 | 789 | void arrayst::add_array_constraints_if(
|
731 | 790 | const index_sett &index_set,
|
732 | 791 | const if_exprt &expr)
|
|
0 commit comments