CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
interval_union.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Util
4
5Author: Diffblue Limited
6
7\*******************************************************************/
8
9#include "interval_union.h"
10#include "arith_tools.h"
11#include "range.h"
12#include "string_utils.h"
13#include <regex>
14#include <util/invariant.h>
15#include <util/std_expr.h>
16
21
23{
26 interval.make_ge_than(value);
27 interval_union.intervals.emplace_back(std::move(interval));
28 return interval_union;
29}
30
32{
35 interval.make_le_than(value);
36 interval_union.intervals.emplace_back(std::move(interval));
37 return interval_union;
38}
39
42{
43 interval_uniont result{};
44 auto it1 = intervals.begin();
45 auto it2 = other.intervals.begin();
46 while(it1 != intervals.end() && it2 != other.intervals.end())
47 {
49 intersection.intersect_with(*it2);
50 if(!intersection.empty())
51 result.intervals.emplace_back(std::move(intersection));
52 if(it1->upper < it2->upper)
53 ++it1;
54 else
55 ++it2;
56 }
57 return result;
58}
59
61{
62 if(intervals.empty())
63 return other;
64 if(other.intervals.empty())
65 return *this;
66
67 // The algorithm goes process the intervals contained in both unions in order
68 // of their lower bound. At each iteration of the loop, the \c result object
69 // contains the union of intervals from both sets that have lower bound
70 // smaller than the intervals currently pointed by \c it1 and \c it2.
71 interval_uniont result{};
72 auto it1 = intervals.begin();
73 auto it2 = other.intervals.begin();
74
75 // Initialize the first interval of \c result depending on which of the two
76 // sets are unbounded to the left.
77 if(!it1->lower_set)
78 {
79 if(!it2->lower_set)
80 {
81 result = smaller_or_equal(std::max(it1->upper, it2->upper));
82 ++it1;
83 ++it2;
84 }
85 else
86 {
87 result.intervals.push_back(*it1);
88 ++it1;
89 }
90 }
91 else
92 {
93 if(!it2->lower_set)
94 {
95 result.intervals.push_back(*it2);
96 ++it2;
97 }
98 else if(it1->lower <= it2->lower)
99 {
100 result.intervals.push_back(*it1);
101 ++it1;
102 }
103 else
104 {
105 result.intervals.push_back(*it2);
106 ++it2;
107 }
108 }
109 while(it1 != intervals.end() || it2 != other.intervals.end())
110 {
111 intervalt &back = result.intervals.back();
112 INVARIANT(
113 !back.lower_set ||
114 ((it1 == intervals.end() || it1->lower >= back.lower) &&
115 (it2 == other.intervals.end() || it2->lower >= back.lower)),
116 "intervals should be processed in order");
117 INVARIANT(
118 (it1 == intervals.end() || it1->lower_set) &&
119 (it2 == other.intervals.end() || it2->lower_set),
120 "intervals unbounded to the left should have been processed in prelude");
121 if(it1 != intervals.end() && it1->lower <= back.upper + 1)
122 {
123 back.approx_union_with(*it1);
124 ++it1;
125 }
126 else if(it2 != other.intervals.end() && it2->lower <= back.upper + 1)
127 {
128 back.approx_union_with(*it2);
129 ++it2;
130 }
131 else if(
132 it1 != intervals.end() &&
133 (it2 == other.intervals.end() || it1->lower <= it2->lower))
134 {
135 result.intervals.push_back(*it1);
136 ++it1;
137 }
138 else
139 {
140 result.intervals.push_back(*it2);
141 ++it2;
142 }
143 }
144 return result;
145}
146
148{
149 return intervals.empty();
150}
151
152std::optional<mp_integer> interval_uniont::maximum() const
153{
154 if(intervals.empty())
155 return {};
156 const intervalt &back = intervals.back();
157 if(back.upper_set)
158 return back.upper;
159 return {};
160}
161
162std::optional<mp_integer> interval_uniont::minimum() const
163{
164 if(intervals.empty())
165 return {};
166 const intervalt &front = intervals.front();
167 if(front.lower_set)
168 return front.lower;
169 return {};
170}
171
172std::string interval_uniont::to_string() const
173{
174 if(intervals.empty())
175 return "[]";
176 std::ostringstream output;
177 for(const intervalt &i : intervals)
178 {
179 output << '[';
180 if(i.lower_set)
181 output << i.lower;
182 output << ':';
183 if(i.upper_set)
184 output << i.upper;
185 output << "]";
186 }
187 return output.str();
188}
189
191{
192 return disjunction(make_range(intervals).map([&e](const intervalt &interval) {
193 std::vector<exprt> conjuncts;
194 if(interval.lower_set)
195 {
196 conjuncts.emplace_back(binary_relation_exprt{
197 e, ID_ge, from_integer(interval.lower, e.type())});
198 }
199 if(interval.upper_set)
200 {
201 conjuncts.emplace_back(binary_relation_exprt{
202 e, ID_le, from_integer(interval.upper, e.type())});
203 }
204 return conjunction(conjuncts);
205 }));
206}
207
210{
211 interval_uniont result;
212 result.intervals.emplace_back(std::move(interval));
213 return result;
214}
215
216std::optional<interval_uniont>
218{
219 const std::regex limits_regex("\\[(-\\d+|\\d*):(-\\d+|\\d*)\\]");
220 interval_uniont result;
221 for(const std::string &interval_string : split_string(to_parse, ','))
222 {
223 std::smatch base_match;
224 if(!std::regex_match(interval_string, base_match, limits_regex))
225 return {};
227 if(!base_match[1].str().empty())
228 interval.make_ge_than(string2integer(base_match[1].str()));
229 if(!base_match[2].str().empty())
230 interval.make_le_than(string2integer(base_match[2].str()));
231 if(!interval.empty())
232 result = result.make_union(of_interval(interval));
233 }
234 INVARIANT(result.validate(), "intervals should be strictly ordered");
235 return result;
236}
237
238std::optional<mp_integer> interval_uniont::as_singleton() const
239{
240 if(intervals.size() != 1)
241 return {};
242 const intervalt &interval = intervals[0];
243 if(!interval.lower_set || !interval.upper_set)
244 return {};
245 if(interval.upper != interval.lower)
246 return {};
247 return interval.lower;
248}
249
251static bool strictly_below(
254{
255 return a.upper_set && b.lower_set && a.upper < b.lower;
256}
257
259{
260 return std::is_sorted(intervals.begin(), intervals.end(), strictly_below);
261}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition std_expr.h:762
Base class for all expressions.
Definition expr.h:56
typet & type()
Return the type of the expression.
Definition expr.h:84
void approx_union_with(const interval_templatet &i)
Represents a set of integers by a union of intervals, which are stored in increasing order for effici...
interval_uniont make_union(const interval_uniont &other) const
Return a new interval_uniontt object representing the set of intergers in the union of this object an...
static interval_uniont greater_or_equal(const mp_integer &value)
Construct interval_uniont object representing the set of integers that are greater or equal to value.
std::vector< intervalt > intervals
Non-overlapping intervals stored in order of their lower bound, so that each interval is strictly bel...
static interval_uniont smaller_or_equal(const mp_integer &value)
Construct interval_uniont object representing the set of integers that are greater or equal to value.
std::optional< mp_integer > maximum() const
empty optional means either unbounded on the right or empty, is_empty has to be called to distinguish...
std::optional< mp_integer > as_singleton() const
If the set contains only one element, return the value of this element.
bool validate() const
Check that intervals are strictly ordered.
std::optional< mp_integer > minimum() const
empty optional means either unbounded on the left or empty, is_empty has to be called to distinguish ...
bool is_empty() const
static std::optional< interval_uniont > of_string(const std::string &to_parse)
Parse a string which is a comma , separated list of intervals of the form "[lower1:upper1]",...
std::string to_string() const
Convert the set to a string representing a sequence of intervals, each interval being of the form "[l...
static interval_uniont all_integers()
Set of all integers.
static interval_uniont of_interval(intervalt interval)
Construct interval union from a single interval.
interval_uniont make_intersection(const interval_uniont &other) const
Return a new interval_uniontt object representing the set of intergers in the intersection of this ob...
exprt make_contains_expr(const exprt &e) const
Expression which is true exactly when e belongs to the set.
void intersection(const typename graph_nodet< E >::edgest &a, const typename graph_nodet< E >::edgest &b, typename graph_nodet< E >::edgest &dest)
Compute intersection of two edge sets, in linear time.
Definition graph.h:115
static bool strictly_below(const interval_templatet< mp_integer > &a, const interval_templatet< mp_integer > &b)
Check that interval a is strictly below interval b.
Union of intervals.
const mp_integer string2integer(const std::string &n, unsigned base)
Definition mp_arith.cpp:54
Ranges: pair of begin and end iterators, which can be initialized from containers,...
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition range.h:522
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
exprt conjunction(const exprt::operandst &op)
1) generates a conjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition std_expr.cpp:83
exprt disjunction(const exprt::operandst &op)
1) generates a disjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition std_expr.cpp:71
API to expression classes.
void split_string(const std::string &s, char delim, std::vector< std::string > &result, bool strip, bool remove_empty)