Skip to content

Commit 829124d

Browse files
committed
value_set_abstract_object::compact combines overlapping intervals
1 parent 9ca9e63 commit 829124d

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
@@ -397,8 +397,13 @@ static abstract_object_sett compact_values(const abstract_object_sett &values)
397397
return compacted;
398398
}
399399

400-
static abstract_object_sett
401-
non_destructive_compact(const abstract_object_sett &values)
400+
static exprt eval_expr(const exprt &e);
401+
static bool is_le(const exprt &lhs, const exprt &rhs);
402+
static void
403+
collapse_overlapping_intervals(std::vector<constant_interval_exprt> &intervals);
404+
405+
static std::vector<constant_interval_exprt>
406+
collect_intervals(const abstract_object_sett &values)
402407
{
403408
auto intervals = std::vector<constant_interval_exprt>{};
404409
for(auto const &object : values)
@@ -410,6 +415,45 @@ non_destructive_compact(const abstract_object_sett &values)
410415
intervals.push_back(as_expr);
411416
}
412417

418+
collapse_overlapping_intervals(intervals);
419+
420+
return intervals;
421+
}
422+
423+
void collapse_overlapping_intervals(
424+
std::vector<constant_interval_exprt> &intervals)
425+
{
426+
std::sort(
427+
intervals.begin(),
428+
intervals.end(),
429+
[](constant_interval_exprt const &lhs, constant_interval_exprt const &rhs) {
430+
return is_le(lhs.get_lower(), rhs.get_lower());
431+
});
432+
433+
size_t index = 1;
434+
while(index < intervals.size())
435+
{
436+
auto &lhs = intervals[index - 1];
437+
auto &rhs = intervals[index];
438+
439+
bool overlap = is_le(rhs.get_lower(), lhs.get_upper());
440+
if(overlap)
441+
{
442+
auto upper = is_le(lhs.get_upper(), rhs.get_upper()) ? rhs.get_upper()
443+
: lhs.get_upper();
444+
auto expanded = constant_interval_exprt(lhs.get_lower(), upper);
445+
lhs = expanded;
446+
intervals.erase(intervals.begin() + index);
447+
}
448+
else
449+
++index;
450+
}
451+
}
452+
453+
static abstract_object_sett
454+
non_destructive_compact(const abstract_object_sett &values)
455+
{
456+
auto intervals = collect_intervals(values);
413457
if(intervals.empty())
414458
return values;
415459

@@ -423,18 +467,16 @@ non_destructive_compact(const abstract_object_sett &values)
423467
[&intervals](const abstract_object_pointert &object) {
424468
return value_is_not_contained_in(object, intervals);
425469
});
426-
470+
std::transform(
471+
intervals.begin(),
472+
intervals.end(),
473+
std::back_inserter(compacted),
474+
[](const constant_interval_exprt &interval) {
475+
return interval_abstract_valuet::make_interval(interval);
476+
});
427477
return compacted;
428478
}
429479

430-
exprt eval_expr(exprt e)
431-
{
432-
auto dummy_symbol_table = symbol_tablet{};
433-
auto dummy_namespace = namespacet{dummy_symbol_table};
434-
435-
return simplify_expr(e, dummy_namespace);
436-
}
437-
438480
static abstract_object_sett
439481
destructive_compact(abstract_object_sett values, int slice)
440482
{
@@ -444,10 +486,16 @@ destructive_compact(abstract_object_sett values, int slice)
444486
minus_exprt(width.get_upper(), width.get_lower()),
445487
from_integer(slice, width.type())));
446488

447-
auto lower_slice = constant_interval_exprt(
448-
width.get_lower(), eval_expr(plus_exprt(width.get_lower(), slice_width)));
449-
auto upper_slice = constant_interval_exprt(
450-
eval_expr(minus_exprt(width.get_upper(), slice_width)), width.get_upper());
489+
auto lower_boundary = eval_expr(plus_exprt(width.get_lower(), slice_width));
490+
auto upper_start = eval_expr(minus_exprt(width.get_upper(), slice_width));
491+
if(
492+
lower_boundary ==
493+
upper_start) // adjust so the intervals are not immediately combined
494+
upper_start = eval_expr(
495+
plus_exprt(upper_start, from_integer(1, lower_boundary.type())));
496+
497+
auto lower_slice = constant_interval_exprt(width.get_lower(), lower_boundary);
498+
auto upper_slice = constant_interval_exprt(upper_start, width.get_upper());
451499

452500
values.insert(interval_abstract_valuet::make_interval(lower_slice));
453501
values.insert(interval_abstract_valuet::make_interval(upper_slice));
@@ -470,8 +518,20 @@ static bool value_is_not_contained_in(
470518
intervals.begin(),
471519
intervals.end(),
472520
[&as_expr](const constant_interval_exprt &interval) {
473-
if(interval == as_expr)
474-
return false;
475521
return interval.contains(as_expr);
476522
});
477523
}
524+
525+
static exprt eval_expr(const exprt &e)
526+
{
527+
auto symbol_table = symbol_tablet{};
528+
auto ns = namespacet{symbol_table};
529+
530+
return simplify_expr(e, ns);
531+
}
532+
533+
static bool is_le(const exprt &lhs, const exprt &rhs)
534+
{
535+
auto is_le_expr = binary_relation_exprt(lhs, ID_le, rhs);
536+
return eval_expr(is_le_expr).is_true();
537+
}

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)