Skip to content

Commit 2ec1f1c

Browse files
committed
value_set_abstract_object::compact combines overlapping intervals
1 parent fd01ee8 commit 2ec1f1c

File tree

2 files changed

+144
-21
lines changed

2 files changed

+144
-21
lines changed

src/analyses/variable-sensitivity/value_set_abstract_object.cpp

Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,13 @@ static abstract_object_sett compact_values(const abstract_object_sett &values)
368368
return compacted;
369369
}
370370

371-
static abstract_object_sett
372-
non_destructive_compact(const abstract_object_sett &values)
371+
static exprt eval_expr(const exprt &e);
372+
static bool is_le(const exprt &lhs, const exprt &rhs);
373+
static void
374+
collapse_overlapping_intervals(std::vector<constant_interval_exprt> &intervals);
375+
376+
static std::vector<constant_interval_exprt>
377+
collect_intervals(const abstract_object_sett &values)
373378
{
374379
auto intervals = std::vector<constant_interval_exprt>{};
375380
for(auto const &object : values)
@@ -381,6 +386,45 @@ non_destructive_compact(const abstract_object_sett &values)
381386
intervals.push_back(as_expr);
382387
}
383388

389+
collapse_overlapping_intervals(intervals);
390+
391+
return intervals;
392+
}
393+
394+
void collapse_overlapping_intervals(
395+
std::vector<constant_interval_exprt> &intervals)
396+
{
397+
std::sort(
398+
intervals.begin(),
399+
intervals.end(),
400+
[](constant_interval_exprt const &lhs, constant_interval_exprt const &rhs) {
401+
return is_le(lhs.get_lower(), rhs.get_lower());
402+
});
403+
404+
size_t index = 1;
405+
while(index < intervals.size())
406+
{
407+
auto &lhs = intervals[index - 1];
408+
auto &rhs = intervals[index];
409+
410+
bool overlap = is_le(rhs.get_lower(), lhs.get_upper());
411+
if(overlap)
412+
{
413+
auto upper = is_le(lhs.get_upper(), rhs.get_upper()) ? rhs.get_upper()
414+
: lhs.get_upper();
415+
auto expanded = constant_interval_exprt(lhs.get_lower(), upper);
416+
lhs = expanded;
417+
intervals.erase(intervals.begin() + index);
418+
}
419+
else
420+
++index;
421+
}
422+
}
423+
424+
static abstract_object_sett
425+
non_destructive_compact(const abstract_object_sett &values)
426+
{
427+
auto intervals = collect_intervals(values);
384428
if(intervals.empty())
385429
return values;
386430

@@ -394,18 +438,16 @@ non_destructive_compact(const abstract_object_sett &values)
394438
[&intervals](const abstract_object_pointert &object) {
395439
return value_is_not_contained_in(object, intervals);
396440
});
397-
441+
std::transform(
442+
intervals.begin(),
443+
intervals.end(),
444+
std::back_inserter(compacted),
445+
[](const constant_interval_exprt &interval) {
446+
return interval_abstract_valuet::make_interval(interval);
447+
});
398448
return compacted;
399449
}
400450

401-
exprt eval_expr(exprt e)
402-
{
403-
auto dummy_symbol_table = symbol_tablet{};
404-
auto dummy_namespace = namespacet{dummy_symbol_table};
405-
406-
return simplify_expr(e, dummy_namespace);
407-
}
408-
409451
static abstract_object_sett
410452
destructive_compact(abstract_object_sett values, int slice)
411453
{
@@ -415,10 +457,16 @@ destructive_compact(abstract_object_sett values, int slice)
415457
minus_exprt(width.get_upper(), width.get_lower()),
416458
from_integer(slice, width.type())));
417459

418-
auto lower_slice = constant_interval_exprt(
419-
width.get_lower(), eval_expr(plus_exprt(width.get_lower(), slice_width)));
420-
auto upper_slice = constant_interval_exprt(
421-
eval_expr(minus_exprt(width.get_upper(), slice_width)), width.get_upper());
460+
auto lower_boundary = eval_expr(plus_exprt(width.get_lower(), slice_width));
461+
auto upper_start = eval_expr(minus_exprt(width.get_upper(), slice_width));
462+
if(
463+
lower_boundary ==
464+
upper_start) // adjust so the intervals are not immediately combined
465+
upper_start = eval_expr(
466+
plus_exprt(upper_start, from_integer(1, lower_boundary.type())));
467+
468+
auto lower_slice = constant_interval_exprt(width.get_lower(), lower_boundary);
469+
auto upper_slice = constant_interval_exprt(upper_start, width.get_upper());
422470

423471
values.insert(interval_abstract_valuet::make_interval(lower_slice));
424472
values.insert(interval_abstract_valuet::make_interval(upper_slice));
@@ -441,8 +489,20 @@ static bool value_is_not_contained_in(
441489
intervals.begin(),
442490
intervals.end(),
443491
[&as_expr](const constant_interval_exprt &interval) {
444-
if(interval == as_expr)
445-
return false;
446492
return interval.contains(as_expr);
447493
});
448494
}
495+
496+
static exprt eval_expr(const exprt &e)
497+
{
498+
auto symbol_table = symbol_tablet{};
499+
auto ns = namespacet{symbol_table};
500+
501+
return simplify_expr(e, ns);
502+
}
503+
504+
static bool is_le(const exprt &lhs, const exprt &rhs)
505+
{
506+
auto is_le_expr = binary_relation_exprt(lhs, ID_le, rhs);
507+
return eval_expr(is_le_expr).is_true();
508+
}

unit/analyses/variable-sensitivity/value_set_abstract_object/compacting.cpp

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,70 @@ SCENARIO(
167167
}
168168
}
169169

170-
GIVEN("compact values to create new intervals")
170+
GIVEN("compact overlapping interval together")
171+
{
172+
auto interval_1_2 = constant_interval_exprt(val1, val2);
173+
auto interval_2_3 = constant_interval_exprt(val2, val3);
174+
auto interval_3_4 = constant_interval_exprt(val3, val4);
175+
auto interval_4_5 = constant_interval_exprt(val4, val5);
176+
auto interval_8_10 = constant_interval_exprt(val8, val10);
177+
auto interval_9_12 = constant_interval_exprt(val9, val12);
178+
auto val13 = from_integer(13, type);
179+
auto val14 = from_integer(14, type);
180+
auto val15 = from_integer(15, type);
181+
182+
WHEN(
183+
"compacting { 0, [1, 2], [2, 3], [3, 4], [4, 5], 6, 7, [8, 10], [9, 12], "
184+
"13, 14, 15 }")
185+
{
186+
auto value_set = make_value_set(
187+
{val0,
188+
interval_1_2,
189+
interval_2_3,
190+
interval_3_4,
191+
interval_4_5,
192+
val6,
193+
val7,
194+
interval_8_10,
195+
interval_9_12,
196+
val13,
197+
val14,
198+
val15},
199+
environment,
200+
ns);
201+
THEN("{ 0, [1, 5], 6, 7, [9, 12], 13, 14, 15 }")
202+
{
203+
auto interval_1_5 = constant_interval_exprt(val1, val5);
204+
auto interval_8_12 = constant_interval_exprt(val8, val12);
205+
EXPECT(
206+
value_set,
207+
{val0, interval_1_5, val6, val7, interval_8_12, val13, val14, val15});
208+
}
209+
}
210+
WHEN(
211+
"compacting { [1, 2], [2, 3], [3, 4], [4, 5], [8, 10], [9, 12], 0, 1, 2, "
212+
"3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }")
213+
{
214+
auto value_set = make_value_set(
215+
{val0, val1, val2, val3, val4,
216+
val5, val6, val7, val8, val9,
217+
val10, val11, val12, val13, val14,
218+
val15, interval_1_2, interval_2_3, interval_3_4, interval_4_5,
219+
interval_8_10, interval_9_12},
220+
environment,
221+
ns);
222+
THEN("{ 0, [1, 5], 6, 7, [9, 12], 13, 14, 15 }")
223+
{
224+
auto interval_1_5 = constant_interval_exprt(val1, val5);
225+
auto interval_8_12 = constant_interval_exprt(val8, val12);
226+
EXPECT(
227+
value_set,
228+
{val0, interval_1_5, val6, val7, interval_8_12, val13, val14, val15});
229+
}
230+
}
231+
}
232+
233+
GIVEN("compact values into new intervals")
171234
{
172235
WHEN("compacting { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }")
173236
{
@@ -217,11 +280,11 @@ SCENARIO(
217280
val100},
218281
environment,
219282
ns);
220-
THEN("{ [-100, 0], [0, 100] }")
283+
THEN("{ [-100, 0], [1, 100] }")
221284
{
222285
auto interval_100minus_0 = constant_interval_exprt(val100minus, val0);
223-
auto interval_0_100 = constant_interval_exprt(val0, val100);
224-
EXPECT(value_set, {interval_100minus_0, interval_0_100});
286+
auto interval_1_100 = constant_interval_exprt(val1, val100);
287+
EXPECT(value_set, {interval_100minus_0, interval_1_100});
225288
}
226289
}
227290
}

0 commit comments

Comments
 (0)