Skip to content

Commit f9be0eb

Browse files
authored
Merge pull request diffblue#6192 from diffblue/binding_instantiate
Introduce binding_exprt::instantiate
2 parents 3509cc3 + e3d8334 commit f9be0eb

File tree

5 files changed

+170
-75
lines changed

5 files changed

+170
-75
lines changed

src/solvers/flattening/boolbv_quantifier.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Author: Daniel Kroening, [email protected]
1414
#include <util/optional.h>
1515
#include <util/range.h>
1616
#include <util/replace_expr.h>
17-
#include <util/replace_symbol.h>
1817
#include <util/simplify_expr.h>
1918

2019
/// A method to detect equivalence between experts that can contain typecast
@@ -212,17 +211,11 @@ literalt boolbvt::convert_quantifier(const quantifier_exprt &src)
212211
auto fresh_symbols = fresh_binding(src);
213212

214213
// replace in where()
215-
replace_symbolt replace_symbol;
216-
217-
for(const auto &pair : make_range(src.variables()).zip(fresh_symbols))
218-
replace_symbol.insert(pair.first, pair.second);
219-
220-
exprt renamed_where = src.where();
221-
replace_symbol(renamed_where);
214+
auto where_replaced = src.instantiate(fresh_symbols);
222215

223216
// produce new quantifier expression
224217
auto new_src =
225-
quantifier_exprt(src.id(), std::move(fresh_symbols), renamed_where);
218+
quantifier_exprt(src.id(), std::move(fresh_symbols), where_replaced);
226219

227220
const auto res = instantiate_quantifier(src, ns);
228221

src/util/mathematical_expr.cpp

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -51,68 +51,3 @@ lambda_exprt::lambda_exprt(const variablest &_variables, const exprt &_where)
5151
lambda_type(_variables, _where))
5252
{
5353
}
54-
55-
static optionalt<exprt> substitute_symbols_rec(
56-
const std::map<irep_idt, exprt> &substitutions,
57-
exprt src)
58-
{
59-
if(src.id() == ID_symbol)
60-
{
61-
auto s_it = substitutions.find(to_symbol_expr(src).get_identifier());
62-
if(s_it == substitutions.end())
63-
return {};
64-
else
65-
return s_it->second;
66-
}
67-
68-
if(!src.has_operands())
69-
return {};
70-
71-
bool op_changed = false;
72-
73-
for(auto &op : src.operands())
74-
{
75-
auto op_result = substitute_symbols_rec(substitutions, op);
76-
77-
if(op_result.has_value())
78-
{
79-
op = op_result.value();
80-
op_changed = true;
81-
}
82-
}
83-
84-
if(op_changed)
85-
return src;
86-
else
87-
return {};
88-
}
89-
90-
exprt lambda_exprt::application(const operandst &arguments) const
91-
{
92-
// number of arguments must match function signature
93-
auto &variables = this->variables();
94-
PRECONDITION(variables.size() == arguments.size());
95-
96-
std::map<symbol_exprt, exprt> value_map;
97-
98-
for(std::size_t i = 0; i < variables.size(); i++)
99-
{
100-
// types must match
101-
PRECONDITION(variables[i].type() == arguments[i].type());
102-
value_map[variables[i]] = arguments[i];
103-
}
104-
105-
// build a subsitution map
106-
std::map<irep_idt, exprt> substitutions;
107-
108-
for(std::size_t i = 0; i < variables.size(); i++)
109-
substitutions[variables[i].get_identifier()] = arguments[i];
110-
111-
// now recurse downwards and substitute in 'where'
112-
auto substitute_result = substitute_symbols_rec(substitutions, where());
113-
114-
if(substitute_result.has_value())
115-
return substitute_result.value();
116-
else
117-
return where(); // trivial case, variables not used
118-
}

src/util/mathematical_expr.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,10 @@ class lambda_exprt : public binding_exprt
398398
}
399399

400400
// apply the function to the given arguments
401-
exprt application(const operandst &) const;
401+
exprt application(const operandst &arguments) const
402+
{
403+
return instantiate(arguments);
404+
}
402405
};
403406

404407
template <>

src/util/std_expr.cpp

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Author: Daniel Kroening, [email protected]
1111
#include "namespace.h"
1212
#include "range.h"
1313

14+
#include <map>
15+
1416
bool constant_exprt::value_is_zero_string() const
1517
{
1618
const std::string val=id2string(get_value());
@@ -134,3 +136,136 @@ void let_exprt::validate(const exprt &expr, const validation_modet vm)
134136
"let bindings must be type consistent");
135137
}
136138
}
139+
140+
static optionalt<exprt> substitute_symbols_rec(
141+
const std::map<irep_idt, exprt> &substitutions,
142+
exprt src)
143+
{
144+
if(src.id() == ID_symbol)
145+
{
146+
auto s_it = substitutions.find(to_symbol_expr(src).get_identifier());
147+
if(s_it == substitutions.end())
148+
return {};
149+
else
150+
return s_it->second;
151+
}
152+
else if(
153+
src.id() == ID_forall || src.id() == ID_exists || src.id() == ID_lambda)
154+
{
155+
const auto &binding_expr = to_binding_expr(src);
156+
157+
// bindings may be nested,
158+
// which may hide some of our substitutions
159+
auto new_substitutions = substitutions;
160+
for(const auto &variable : binding_expr.variables())
161+
new_substitutions.erase(variable.get_identifier());
162+
163+
auto op_result =
164+
substitute_symbols_rec(new_substitutions, binding_expr.where());
165+
if(op_result.has_value())
166+
return binding_exprt(
167+
src.id(),
168+
binding_expr.variables(),
169+
op_result.value(),
170+
binding_expr.type());
171+
else
172+
return {};
173+
}
174+
else if(src.id() == ID_let)
175+
{
176+
auto new_let_expr = to_let_expr(src); // copy
177+
const auto &binding_expr = to_let_expr(src).binding();
178+
179+
// bindings may be nested,
180+
// which may hide some of our substitutions
181+
auto new_substitutions = substitutions;
182+
for(const auto &variable : binding_expr.variables())
183+
new_substitutions.erase(variable.get_identifier());
184+
185+
bool op_changed = false;
186+
187+
for(auto &op : new_let_expr.values())
188+
{
189+
auto op_result = substitute_symbols_rec(new_substitutions, op);
190+
191+
if(op_result.has_value())
192+
{
193+
op = op_result.value();
194+
op_changed = true;
195+
}
196+
}
197+
198+
auto op_result =
199+
substitute_symbols_rec(new_substitutions, binding_expr.where());
200+
if(op_result.has_value())
201+
{
202+
new_let_expr.where() = op_result.value();
203+
op_changed = true;
204+
}
205+
206+
if(op_changed)
207+
return std::move(new_let_expr);
208+
else
209+
return {};
210+
}
211+
212+
if(!src.has_operands())
213+
return {};
214+
215+
bool op_changed = false;
216+
217+
for(auto &op : src.operands())
218+
{
219+
auto op_result = substitute_symbols_rec(substitutions, op);
220+
221+
if(op_result.has_value())
222+
{
223+
op = op_result.value();
224+
op_changed = true;
225+
}
226+
}
227+
228+
if(op_changed)
229+
return src;
230+
else
231+
return {};
232+
}
233+
234+
exprt binding_exprt::instantiate(const operandst &values) const
235+
{
236+
// number of values must match the number of bound variables
237+
auto &variables = this->variables();
238+
PRECONDITION(variables.size() == values.size());
239+
240+
std::map<symbol_exprt, exprt> value_map;
241+
242+
for(std::size_t i = 0; i < variables.size(); i++)
243+
{
244+
// types must match
245+
PRECONDITION(variables[i].type() == values[i].type());
246+
value_map[variables[i]] = values[i];
247+
}
248+
249+
// build a substitution map
250+
std::map<irep_idt, exprt> substitutions;
251+
252+
for(std::size_t i = 0; i < variables.size(); i++)
253+
substitutions[variables[i].get_identifier()] = values[i];
254+
255+
// now recurse downwards and substitute in 'where'
256+
auto substitute_result = substitute_symbols_rec(substitutions, where());
257+
258+
if(substitute_result.has_value())
259+
return substitute_result.value();
260+
else
261+
return where(); // trivial case, variables not used
262+
}
263+
264+
exprt binding_exprt::instantiate(const variablest &new_variables) const
265+
{
266+
std::vector<exprt> values;
267+
values.reserve(new_variables.size());
268+
for(const auto &new_variable : new_variables)
269+
values.push_back(new_variable);
270+
return instantiate(values);
271+
}

src/util/std_expr.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2797,8 +2797,37 @@ class binding_exprt : public binary_exprt
27972797
{
27982798
return op1();
27992799
}
2800+
2801+
/// substitute free occurrences of the variables in where()
2802+
/// by the given values
2803+
exprt instantiate(const exprt::operandst &) const;
2804+
2805+
/// substitute free occurrences of the variables in where()
2806+
/// by a set of different symbols
2807+
exprt instantiate(const variablest &) const;
28002808
};
28012809

2810+
inline void validate_expr(const binding_exprt &binding_expr)
2811+
{
2812+
validate_operands(
2813+
binding_expr, 2, "Binding expressions must have two operands");
2814+
}
2815+
2816+
/// \brief Cast an exprt to a \ref binding_exprt
2817+
///
2818+
/// \a expr must be known to be \ref binding_exprt.
2819+
///
2820+
/// \param expr: Source expression
2821+
/// \return Object of type \ref binding_exprt
2822+
inline const binding_exprt &to_binding_expr(const exprt &expr)
2823+
{
2824+
PRECONDITION(
2825+
expr.id() == ID_forall || expr.id() == ID_exists || expr.id() == ID_lambda);
2826+
const binding_exprt &ret = static_cast<const binding_exprt &>(expr);
2827+
validate_expr(ret);
2828+
return ret;
2829+
}
2830+
28022831
/// \brief A let expression
28032832
class let_exprt : public binary_exprt
28042833
{

0 commit comments

Comments
 (0)