Skip to content

Commit 9da388a

Browse files
committed
value_set_abstract_object::compact combines overlapping intervals
1 parent 26192d1 commit 9da388a

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
@@ -370,8 +370,13 @@ static abstract_object_sett compact_values(const abstract_object_sett &values)
370370
return compacted;
371371
}
372372

373-
static abstract_object_sett
374-
non_destructive_compact(const abstract_object_sett &values)
373+
static exprt eval_expr(const exprt &e);
374+
static bool is_le(const exprt &lhs, const exprt &rhs);
375+
static void
376+
collapse_overlapping_intervals(std::vector<constant_interval_exprt> &intervals);
377+
378+
static std::vector<constant_interval_exprt>
379+
collect_intervals(const abstract_object_sett &values)
375380
{
376381
auto intervals = std::vector<constant_interval_exprt>{};
377382
for(auto const &object : values)
@@ -383,6 +388,45 @@ non_destructive_compact(const abstract_object_sett &values)
383388
intervals.push_back(as_expr);
384389
}
385390

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

@@ -396,18 +440,16 @@ non_destructive_compact(const abstract_object_sett &values)
396440
[&intervals](const abstract_object_pointert &object) {
397441
return value_is_not_contained_in(object, intervals);
398442
});
399-
443+
std::transform(
444+
intervals.begin(),
445+
intervals.end(),
446+
std::back_inserter(compacted),
447+
[](const constant_interval_exprt &interval) {
448+
return interval_abstract_valuet::make_interval(interval);
449+
});
400450
return compacted;
401451
}
402452

403-
exprt eval_expr(exprt e)
404-
{
405-
auto dummy_symbol_table = symbol_tablet{};
406-
auto dummy_namespace = namespacet{dummy_symbol_table};
407-
408-
return simplify_expr(e, dummy_namespace);
409-
}
410-
411453
static abstract_object_sett
412454
destructive_compact(abstract_object_sett values, int slice)
413455
{
@@ -417,10 +459,16 @@ destructive_compact(abstract_object_sett values, int slice)
417459
minus_exprt(width.get_upper(), width.get_lower()),
418460
from_integer(slice, width.type())));
419461

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

425473
values.insert(interval_abstract_valuet::make_interval(lower_slice));
426474
values.insert(interval_abstract_valuet::make_interval(upper_slice));
@@ -443,8 +491,20 @@ static bool value_is_not_contained_in(
443491
intervals.begin(),
444492
intervals.end(),
445493
[&as_expr](const constant_interval_exprt &interval) {
446-
if(interval == as_expr)
447-
return false;
448494
return interval.contains(as_expr);
449495
});
450496
}
497+
498+
static exprt eval_expr(const exprt &e)
499+
{
500+
auto symbol_table = symbol_tablet{};
501+
auto ns = namespacet{symbol_table};
502+
503+
return simplify_expr(e, ns);
504+
}
505+
506+
static bool is_le(const exprt &lhs, const exprt &rhs)
507+
{
508+
auto is_le_expr = binary_relation_exprt(lhs, ID_le, rhs);
509+
return eval_expr(is_le_expr).is_true();
510+
}

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)