|
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