Skip to content

Commit b7b8798

Browse files
Refactor map_representation_of_sum/sum_over_map
We wrap these two functions in a `linear_functiont` and rename them, to make clearer how these two functions work together and clarifies what this intermediary structure represents.
1 parent 116d4ac commit b7b8798

File tree

3 files changed

+62
-78
lines changed

3 files changed

+62
-78
lines changed

src/solvers/strings/string_constraint_instantiation.cpp

Lines changed: 44 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,24 @@ find_indexes(const exprt &expr, const exprt &str, const symbol_exprt &qvar)
5050
return result;
5151
}
5252

53-
std::map<exprt, int> map_representation_of_sum(const exprt &f)
53+
linear_functiont::linear_functiont(const exprt &f)
5454
{
55-
// number of times the leaf should be added (can be negative)
56-
std::map<exprt, int> elems;
57-
55+
type = f.type();
56+
// list of expressions to process with a boolean flag telling whether they
57+
// appear positively or negatively (true is for positive)
5858
std::list<std::pair<exprt, bool>> to_process;
5959
to_process.emplace_back(f, true);
6060

6161
while(!to_process.empty())
6262
{
63-
exprt cur = to_process.back().first;
63+
const exprt cur = to_process.back().first;
6464
bool positive = to_process.back().second;
6565
to_process.pop_back();
66-
if(cur.id() == ID_plus)
66+
if(auto integer = numeric_cast<mp_integer>(cur))
67+
{
68+
constant_coefficient += positive ? integer.value() : -integer.value();
69+
}
70+
else if(cur.id() == ID_plus)
6771
{
6872
for(const auto &op : cur.operands())
6973
to_process.emplace_back(op, positive);
@@ -80,68 +84,48 @@ std::map<exprt, int> map_representation_of_sum(const exprt &f)
8084
else
8185
{
8286
if(positive)
83-
++elems[cur];
87+
++coefficients[cur];
8488
else
85-
--elems[cur];
89+
--coefficients[cur];
8690
}
8791
}
88-
return elems;
8992
}
9093

91-
exprt sum_over_map(std::map<exprt, int> &m, const typet &type, bool negated)
94+
exprt linear_functiont::to_expr(bool negated) const
9295
{
93-
if(m.empty())
94-
return from_integer(0, type);
95-
96-
exprt sum = nil_exprt();
97-
mp_integer constants = 0;
98-
typet index_type = m.begin()->first.type();
96+
exprt sum = nil_exprt{};
97+
const exprt constant_expr = from_integer(constant_coefficient, type);
98+
if(constant_coefficient != 0)
99+
sum = negated ? (exprt)unary_minus_exprt{constant_expr} : constant_expr;
99100

100-
for(const auto &term : m)
101+
for(const auto &term : coefficients)
101102
{
102103
const exprt &t = term.first;
103-
int factor = negated ? (-term.second) : term.second;
104-
if(t.id() == ID_constant)
104+
const mp_integer factor = negated ? (-term.second) : term.second;
105+
if(factor == -1)
105106
{
106-
// Constants are accumulated in the variable \c constants
107-
const auto int_value = numeric_cast_v<mp_integer>(to_constant_expr(t));
108-
constants += int_value * factor;
107+
if(sum.is_nil())
108+
sum = unary_minus_exprt(t);
109+
else
110+
sum = minus_exprt(sum, t);
109111
}
110-
else
112+
else if(factor == 1)
111113
{
112-
switch(factor)
113-
{
114-
case -1:
115-
if(sum.is_nil())
116-
sum = unary_minus_exprt(t);
117-
else
118-
sum = minus_exprt(sum, t);
119-
break;
120-
121-
case 1:
122-
if(sum.is_nil())
123-
sum = t;
124-
else
125-
sum = plus_exprt(sum, t);
126-
break;
127-
128-
default:
129-
{
130-
const mult_exprt to_add{t, from_integer(factor, t.type())};
131-
if(sum.is_nil())
132-
sum = to_add;
133-
else
134-
sum = plus_exprt(sum, to_add);
135-
}
136-
}
114+
if(sum.is_nil())
115+
sum = t;
116+
else
117+
sum = plus_exprt(sum, t);
118+
}
119+
else if(factor != 0)
120+
{
121+
const mult_exprt to_add{t, from_integer(factor, t.type())};
122+
if(sum.is_nil())
123+
sum = to_add;
124+
else
125+
sum = plus_exprt(sum, to_add);
137126
}
138127
}
139-
140-
const exprt index_const = from_integer(constants, index_type);
141-
if(sum.is_not_nil())
142-
return plus_exprt(sum, index_const);
143-
else
144-
return index_const;
128+
return sum.is_nil() ? from_integer(0, type) : sum;
145129
}
146130

147131
/// \param qvar: a symbol representing a universally quantified variable
@@ -161,14 +145,14 @@ compute_inverse_function(const exprt &qvar, const exprt &val, const exprt &f)
161145
// qvar has to be equal to val - f(0) if it appears positively in f
162146
// (i.e. if f(qvar)=f(0) + qvar) and f(0) - val if it appears negatively
163147
// in f. So we start by computing val - f(0).
164-
std::map<exprt, int> elems = map_representation_of_sum(minus_exprt(val, f));
148+
linear_functiont linear_function{minus_exprt(val, f)};
165149

166-
// true if qvar appears negatively in f (positively in elems):
150+
// true if qvar appears negatively in f (positively in linear_function):
167151
bool neg = false;
168152

169-
auto it = elems.find(qvar);
153+
auto it = linear_function.coefficients.find(qvar);
170154
INVARIANT(
171-
it != elems.end(),
155+
it != linear_function.coefficients.end(),
172156
string_refinement_invariantt("a function must have an occurrence of qvar"));
173157
if(it->second == 1 || it->second == -1)
174158
{
@@ -184,8 +168,8 @@ compute_inverse_function(const exprt &qvar, const exprt &val, const exprt &f)
184168
" have one"));
185169
}
186170

187-
elems.erase(it);
188-
return sum_over_map(elems, f.type(), neg);
171+
linear_function.coefficients.erase(it);
172+
return linear_function.to_expr(neg);
189173
}
190174

191175
/// Instantiates a string constraint by substituting the quantifiers.

src/solvers/strings/string_constraint_instantiation.h

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,22 @@ std::vector<exprt> instantiate_not_contains(
3535
const std::unordered_map<string_not_contains_constraintt, symbol_exprt>
3636
&witnesses);
3737

38-
/// \param f: an expression with only addition and subtraction
39-
/// \return a map where each leaf of the input is mapped to the number of times
40-
/// it is added. For instance, expression $x + x - y + 3 - 5$ would give the
41-
/// map x -> 2, y -> -1, 3 -> 1, 5 -> -1.
42-
std::map<exprt, int> map_representation_of_sum(const exprt &f);
43-
44-
/// \param m: a map from expressions to integers
45-
/// \param type: type for the returned expression
46-
/// \param negated: optinal Boolean asking to negates the sum
47-
/// \return a expression for the sum of each element in the map a number of
48-
/// times given by the corresponding integer in the map. For a map x -> 2, y
49-
/// -> -1 would give an expression $x + x - y$.
50-
exprt sum_over_map(
51-
std::map<exprt, int> &m,
52-
const typet &type,
53-
bool negated = false);
38+
/// Canonical representation of linear function, for instance, expression
39+
/// $x + x - y + 5 - 3$ would given by \c constant_coefficient 2 and
40+
/// \p coefficients: x -> 2, y -> -1
41+
struct linear_functiont
42+
{
43+
mp_integer constant_coefficient;
44+
std::unordered_map<exprt, mp_integer, irep_hash> coefficients;
45+
typet type;
46+
47+
/// Put an expression \p f composed of additions and subtractions into
48+
/// its cannonical representation
49+
explicit linear_functiont(const exprt &f);
50+
51+
/// \param negated: optional Boolean asking to negate the function
52+
/// \return an expression corresponding to the linear function
53+
exprt to_expr(bool negated = false) const;
54+
};
5455

5556
#endif // CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_INSTANTIATION_H

src/solvers/strings/string_refinement.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,8 +1462,7 @@ static std::pair<bool, std::vector<exprt>> check_axioms(
14621462
/// \return an equivalent expression in a canonical form
14631463
exprt simplify_sum(const exprt &f)
14641464
{
1465-
std::map<exprt, int> map = map_representation_of_sum(f);
1466-
return sum_over_map(map, f.type());
1465+
return linear_functiont{f}.to_expr();
14671466
}
14681467

14691468
/// Add to the index set all the indices that appear in the formulas and the

0 commit comments

Comments
 (0)