@@ -20,6 +20,7 @@ Author: Alberto Griggio, alberto.griggio@gmail.com
20
20
#include < solvers/refinement/string_refinement.h>
21
21
22
22
#include < iomanip>
23
+ #include < numeric>
23
24
#include < stack>
24
25
#include < util/expr_iterator.h>
25
26
#include < util/arith_tools.h>
@@ -1221,62 +1222,87 @@ void debug_model(
1221
1222
stream << messaget::eom;
1222
1223
}
1223
1224
1224
- // / Create a new expression where 'with' expressions on arrays are replaced by
1225
- // / 'if' expressions. e.g. for an array access arr[index], where: `arr :=
1226
- // / array_of(12) with {0:=24} with {2:=42}` the constructed expression will be:
1227
- // / `index==0 ? 24 : index==2 ? 42 : 12`
1228
- // / If `left_propagate` is set to true, the expression will look like
1229
- // / `index<=0 ? 24 : index<=2 ? 42 : 12`
1230
- // / \param expr: A (possibly nested) 'with' expression on an `array_of`
1231
- // / expression. The function checks that the expression is of the form
1232
- // / `with_expr(with_expr(...(array_of(...)))`. This is the form in which
1233
- // / array valuations coming from the underlying solver are given.
1234
- // / \param index: An index with which to build the equality condition
1235
- // / \return An expression containing no 'with' expression
1236
- static exprt substitute_array_access (
1237
- const with_exprt &expr,
1238
- const exprt &index,
1239
- const bool left_propagate)
1225
+ sparse_arrayt::sparse_arrayt (const with_exprt &expr)
1240
1226
{
1241
- std::vector<std::pair<std::size_t , exprt>> entries;
1242
- std::reference_wrapper<const exprt> ref =
1243
- std::ref (static_cast <const exprt &>(expr));
1227
+ auto ref = std::ref (static_cast <const exprt &>(expr));
1244
1228
while (can_cast_expr<with_exprt>(ref.get ()))
1245
1229
{
1246
1230
const auto &with_expr = expr_dynamic_cast<with_exprt>(ref.get ());
1247
- auto current_index = numeric_cast_v<std::size_t >(with_expr.where ());
1248
- entries.push_back ( std::make_pair ( current_index, with_expr.new_value () ));
1231
+ const auto current_index = numeric_cast_v<std::size_t >(with_expr.where ());
1232
+ entries.emplace_back ( current_index, with_expr.new_value ());
1249
1233
ref = with_expr.old ();
1250
1234
}
1251
1235
1252
1236
// This function only handles 'with' and 'array_of' expressions
1253
1237
PRECONDITION (ref.get ().id () == ID_array_of);
1238
+ default_value = expr_dynamic_cast<array_of_exprt>(ref.get ()).what ();
1239
+ }
1254
1240
1255
- // sort entries by increasing index
1241
+ exprt sparse_arrayt::to_if_expression (const exprt &index) const
1242
+ {
1243
+ return std::accumulate (
1244
+ entries.begin (),
1245
+ entries.end (),
1246
+ default_value,
1247
+ [&](
1248
+ const exprt if_expr,
1249
+ const std::pair<std::size_t , exprt> &entry) { // NOLINT
1250
+ const exprt entry_index = from_integer (entry.first , index.type ());
1251
+ const exprt &then_expr = entry.second ;
1252
+ CHECK_RETURN (then_expr.type () == if_expr.type ());
1253
+ const equal_exprt index_equal (index, entry_index);
1254
+ return if_exprt (index_equal, then_expr, if_expr, if_expr.type ());
1255
+ });
1256
+ }
1257
+
1258
+ interval_sparse_arrayt::interval_sparse_arrayt (const with_exprt &expr)
1259
+ : sparse_arrayt(expr)
1260
+ {
1261
+ // Entries are sorted so that successive entries correspond to intervals
1256
1262
std::sort (
1257
1263
entries.begin (),
1258
1264
entries.end (),
1259
1265
[](
1260
1266
const std::pair<std::size_t , exprt> &a,
1261
1267
const std::pair<std::size_t , exprt> &b) { return a.first < b.first ; });
1268
+ }
1262
1269
1263
- exprt result = expr_dynamic_cast<array_of_exprt>(ref.get ()).what ();
1264
- for (const auto &entry : entries)
1265
- {
1266
- const exprt &then_expr = entry.second ;
1267
- const typet &type = then_expr.type ();
1268
- CHECK_RETURN (type == result.type ());
1269
- const exprt entry_index = from_integer (entry.first , index.type ());
1270
- if (left_propagate)
1271
- {
1270
+ exprt interval_sparse_arrayt::to_if_expression (const exprt &index) const
1271
+ {
1272
+ return std::accumulate (
1273
+ entries.rbegin (),
1274
+ entries.rend (),
1275
+ default_value,
1276
+ [&](
1277
+ const exprt if_expr,
1278
+ const std::pair<std::size_t , exprt> &entry) { // NOLINT
1279
+ const exprt entry_index = from_integer (entry.first , index.type ());
1280
+ const exprt &then_expr = entry.second ;
1281
+ CHECK_RETURN (then_expr.type () == if_expr.type ());
1272
1282
const binary_relation_exprt index_small_eq (index, ID_le, entry_index);
1273
- result = if_exprt (index_small_eq, then_expr, result, type);
1274
- }
1275
- else
1276
- result =
1277
- if_exprt (equal_exprt (index, entry_index), then_expr, result, type);
1278
- }
1279
- return result;
1283
+ return if_exprt (index_small_eq, then_expr, if_expr, if_expr.type ());
1284
+ });
1285
+ }
1286
+
1287
+ // / Create a new expression where 'with' expressions on arrays are replaced by
1288
+ // / 'if' expressions. e.g. for an array access arr[index], where: `arr :=
1289
+ // / array_of(12) with {0:=24} with {2:=42}` the constructed expression will be:
1290
+ // / `index==0 ? 24 : index==2 ? 42 : 12`
1291
+ // / If `left_propagate` is set to true, the expression will look like
1292
+ // / `index<=0 ? 24 : index<=2 ? 42 : 12`
1293
+ // / \param expr: A (possibly nested) 'with' expression on an `array_of`
1294
+ // / expression. The function checks that the expression is of the form
1295
+ // / `with_expr(with_expr(...(array_of(...)))`. This is the form in which
1296
+ // / array valuations coming from the underlying solver are given.
1297
+ // / \param index: An index with which to build the equality condition
1298
+ // / \return An expression containing no 'with' expression
1299
+ static exprt substitute_array_access (
1300
+ const with_exprt &expr,
1301
+ const exprt &index,
1302
+ const bool left_propagate)
1303
+ {
1304
+ return left_propagate ? interval_sparse_arrayt (expr).to_if_expression (index)
1305
+ : sparse_arrayt (expr).to_if_expression (index);
1280
1306
}
1281
1307
1282
1308
// / Fill an array represented by a list of with_expr by propagating values to
0 commit comments