Skip to content

Commit dc139cd

Browse files
committed
Array theory: Add support for array_comprehension_exprt
Array comprehension expressions are very useful to construct arrays of unbounded size. To support this use case, the array theory in the bit blasting back-end needs to handle them.
1 parent 2ceb3e3 commit dc139cd

File tree

2 files changed

+75
-10
lines changed

2 files changed

+75
-10
lines changed

src/solvers/flattening/arrays.cpp

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Author: Daniel Kroening, [email protected]
1111
#include <util/arith_tools.h>
1212
#include <util/format_expr.h>
1313
#include <util/namespace.h>
14+
#include <util/replace_expr.h>
1415
#include <util/std_expr.h>
1516
#include <util/std_types.h>
1617

@@ -38,8 +39,8 @@ void arrayst::record_array_index(const index_exprt &index)
3839
// entry for the root of the equivalence class
3940
// because this map is accessed during building the error trace
4041
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);
4344
}
4445

4546
literalt arrayst::record_array_equality(
@@ -82,11 +83,24 @@ void arrayst::collect_indices(const exprt &expr)
8283
{
8384
if(expr.id()!=ID_index)
8485
{
86+
if(expr.id() == ID_lambda)
87+
array_comprehension_args.insert(
88+
to_array_comprehension_expr(expr).arg().get_identifier());
89+
8590
forall_operands(op, expr) collect_indices(*op);
8691
}
8792
else
8893
{
8994
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+
90104
collect_indices(e.index()); // necessary?
91105

92106
const typet &array_op_type = e.array().type();
@@ -214,6 +228,9 @@ void arrayst::collect_arrays(const exprt &a)
214228
arrays.make_union(a, a.op0());
215229
collect_arrays(a.op0());
216230
}
231+
else if(a.id() == ID_lambda)
232+
{
233+
}
217234
else
218235
{
219236
DATA_INVARIANT(
@@ -257,17 +274,32 @@ void arrayst::add_array_constraints()
257274
// reduce initial index map
258275
update_index_map(true);
259276

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;
261279
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())
262283
{
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];
266292

267-
add_array_constraints(index_map[arrays.find_number(i)], a);
293+
add_array_constraints(index_map[arrays.find_number(i)], a);
268294

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();
271303
}
272304

273305
// add constraints for equalities
@@ -438,6 +470,11 @@ void arrayst::add_array_constraints(
438470
return add_array_constraints_array_of(index_set, to_array_of_expr(expr));
439471
else if(expr.id() == ID_array)
440472
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+
}
441478
else if(expr.id()==ID_symbol ||
442479
expr.id()==ID_nondet_symbol ||
443480
expr.id()==ID_constant ||
@@ -727,6 +764,28 @@ void arrayst::add_array_constraints_array_constant(
727764
}
728765
}
729766

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+
730789
void arrayst::add_array_constraints_if(
731790
const index_sett &index_set,
732791
const if_exprt &expr)

src/solvers/flattening/arrays.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Author: Daniel Kroening, [email protected]
1414

1515
#include <list>
1616
#include <set>
17+
#include <unordered_set>
1718

1819
#include <util/union_find.h>
1920

@@ -84,7 +85,8 @@ class arrayst:public equalityt
8485
ARRAY_IF,
8586
ARRAY_OF,
8687
ARRAY_TYPECAST,
87-
ARRAY_CONSTANT
88+
ARRAY_CONSTANT,
89+
ARRAY_COMPREHENSION
8890
};
8991

9092
struct lazy_constraintt
@@ -123,13 +125,17 @@ class arrayst:public equalityt
123125
void add_array_constraints_array_constant(
124126
const index_sett &index_set,
125127
const array_exprt &exprt);
128+
void add_array_constraints_comprehension(
129+
const index_sett &index_set,
130+
const array_comprehension_exprt &expr);
126131

127132
void update_index_map(bool update_all);
128133
void update_index_map(std::size_t i);
129134
std::set<std::size_t> update_indices;
130135
void collect_arrays(const exprt &a);
131136
void collect_indices();
132137
void collect_indices(const exprt &a);
138+
std::unordered_set<irep_idt> array_comprehension_args;
133139

134140
virtual bool is_unbounded_array(const typet &type) const=0;
135141
// (maybe this function should be partially moved here from boolbv)

0 commit comments

Comments
 (0)