CBMC
Loading...
Searching...
No Matches
cegis_evaluator.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Evaluate if an expression is consistent with examples
4
5Author: Qinheping Hu
6
7\*******************************************************************/
8
11
12#include "cegis_evaluator.h"
13
14#include <util/arith_tools.h>
15#include <util/format_expr.h>
16
18{
19 auto is_inconsistent = false;
20 // Check if checked_expr is consistent with all examples.
21 for(const auto &cex : cexs)
22 {
23 // checked_expr is inconsistent with a positive example if its evaluation
24 // false.
27 // checked_expr is inconsistent with a negative example if its evaluation
28 // false.
31 }
32 return !is_inconsistent;
33}
34
36 const exprt &expr,
37 const cext &cex,
38 const bool is_positive)
39{
40 const auto id = expr.id();
41 // eval(AND op1 op2) :=
42 // eval(op1) && eval(op2)
43 if(id == ID_and)
44 {
45 bool result = true;
46 for(auto &op : expr.operands())
47 {
48 result = result && evaluate_rec_bool(op, cex, is_positive);
49 }
50 return result;
51 }
52
53 // eval(OR op1 op2) :=
54 // eval(op1) || eval(op2)
55 if(id == ID_or)
56 {
57 bool result = false;
58 for(auto &op : expr.operands())
59 {
60 result = result || evaluate_rec_bool(op, cex, is_positive);
61 }
62 return result;
63 }
64
65 // eval(IMPLIES op1 op2) :=
66 // eval(op1) => eval(op2)
67 if(id == ID_implies)
68 {
69 return !evaluate_rec_bool(expr.operands()[0], cex, is_positive) ||
71 }
72
73 // eval(NOT op) :=
74 // !eval(op)
75 if(id == ID_not)
76 {
77 return !evaluate_rec_bool(expr.operands()[0], cex, is_positive);
78 }
79
80 // eval(EQUAL op1 op2) :=
81 // eval(op1) == eval(op2)
82 if(id == ID_equal)
83 {
84 return evaluate_rec_int(expr.operands()[0], cex, is_positive) ==
86 }
87
88 // eval(NOTEQUAL op1 op2) :=
89 // eval(op1) != eval(op2)
90 if(id == ID_notequal)
91 {
92 return evaluate_rec_int(expr.operands()[0], cex, is_positive) !=
94 }
95
96 // eval(LE op1 op2) :=
97 // eval(op1) <= eval(op2)
98 if(id == ID_le)
99 {
100 return evaluate_rec_int(expr.operands()[0], cex, is_positive) <=
102 }
103
104 // eval(LT op1 op2) :=
105 // eval(op1) < eval(op2)
106 if(id == ID_lt)
107 {
108 return evaluate_rec_int(expr.operands()[0], cex, is_positive) <
110 }
111
112 // eval(GE op1 op2) :=
113 // eval(op1) >= eval(op2)
114 if(id == ID_ge)
115 {
116 return evaluate_rec_int(expr.operands()[0], cex, is_positive) >=
118 }
119
120 // eval(GT op1 op2) :=
121 // eval(op1) > eval(op2)
122 if(id == ID_gt)
123 {
124 return evaluate_rec_int(expr.operands()[0], cex, is_positive) >
126 }
127
128 // eval(CONST op) :=
129 // op
130 if(id == ID_constant)
131 {
132 if(expr == true_exprt())
133 {
134 return true;
135 }
136 else if(expr == false_exprt())
137 {
138 return false;
139 }
141 "Boolean constant must be either true or false: " + expr.pretty());
142 }
143
145 "Found a unsupported boolean operator during quick filtering: " +
146 expr.id_string());
147}
148
150 const exprt &expr,
151 const cext &cex,
152 const bool is_positive)
153{
154 const auto id = expr.id();
155 mp_integer result;
156
157 // For symbol expression, we look up their values from the example.
158 // There are three cases:
159 // 1. is_positive == true
160 // We evaluate the expression on the positive examples, which is the
161 // valuation of loop_entry(v). Note that the loop invariants must hold
162 // for loop_entry valuations as the base case. So we look up the values
163 // in the loop_entry set
164 // 2. is_positive == false, expr in the havoced set
165 // We evaluate the expression on the negative examples---the havoced set.
166 // 3. is_positive == false, expr not in havoced set
167 // The valuations of expr in the havoced iteration is the same as
168 // in the loop entry. So we look up the values from loop_entry set.
169 if(id == ID_symbol)
170 {
171 if(
172 cex.havoced_values.find(expr) != cex.havoced_values.end() && !is_positive)
173 {
174 // Use havoc values if they exists and we are evaluating on
175 // the negative example---is_positive is false.
176 result = cex.havoced_values.at(expr);
177 }
178 else if(cex.loop_entry_values.find(expr) != cex.loop_entry_values.end())
179 {
180 result = cex.loop_entry_values.at(expr);
181 }
182 else
183 {
185 "Variable not found in the havoced set or the un-havoced set: " +
186 expr.pretty());
187 }
188
189 // Typecast `result` to the type of `expr`.
190 auto tmp_expr = from_integer(result, expr.type());
191 to_integer(tmp_expr, result);
192 return result;
193 }
194
195 // For loop_entry expression, we look up their values from loop_entry set.
196 if(id == ID_loop_entry)
197 {
198 if(
199 cex.loop_entry_values.find(expr.operands()[0]) !=
200 cex.loop_entry_values.end())
201 {
202 result = cex.loop_entry_values.at(expr.operands()[0]);
203 }
204 else
205 {
207 "Variable not found in the havoced set or the un-havoced set: " +
208 expr.pretty());
209 }
210
211 // Typecast `result` to the type of `expr`.
212 auto tmp_expr = from_integer(result, expr.type());
213 to_integer(tmp_expr, result);
214 return result;
215 }
216
217 // Evaluate the underlying expression and then typecast the result.
218 if(id == ID_typecast)
219 {
220 // Typecast `result` to the type of `expr`.
221 result = evaluate_rec_int(expr.operands()[0], cex, is_positive);
222 auto tmp_expr = from_integer(result, expr.type());
223 to_integer(tmp_expr, result);
224 return result;
225 }
226
227 // For object_size expression, look up the size of the underlying pointer in
228 // the example `cex`.
229 if(id == ID_object_size)
230 {
231 if(cex.object_sizes.find(expr.operands()[0]) != cex.object_sizes.end())
232 {
233 result = cex.object_sizes.at(expr.operands()[0]);
234 }
235 else
236 {
238 "Variable not found in the object size set: " + expr.pretty());
239 }
240
241 // Typecast `result` to the type of `expr`.
242 auto tmp_expr = from_integer(result, expr.type());
243 to_integer(tmp_expr, result);
244 return result;
245 }
246
247 // For pointer_offset expression, look up the offset of the underlying
248 // pointer in the example `cex`.
249 // A pointer offset expression can be of form
250 // pointer_offset(p)
251 // or
252 // pointer_offset(loop_entry(p))
253 // for some pointer p.
254 // For the first case, we look up the offset in havoced
255 // offset set. Note that if the pointer is not in the havoced set or
256 // is_positive is set, we look up in loop_entry_offset set instead.
257 // For the second case, we look up the offset in the loop_entry_offset set.
258 if(id == ID_pointer_offset)
259 {
260 if(expr.operands()[0].id() != ID_loop_entry)
261 {
262 // If the expression is pointer_offset(p), look up the offset in the
263 // havoced offset set.
264 if(
265 cex.havoced_pointer_offsets.find(expr.operands()[0]) !=
266 cex.havoced_pointer_offsets.end() &&
268 {
269 // Use havoc values only if we are evaluating the expression against
270 // the negative example---is_positive is false.
271 result = cex.havoced_pointer_offsets.at(expr.operands()[0]);
272 }
273 else if(
274 cex.loop_entry_offsets.find(expr.operands()[0]) !=
275 cex.loop_entry_offsets.end())
276 {
277 // The pointer is not havoced. So look up the offset in the loop-entry
278 // set instead.
279 result = cex.loop_entry_offsets.at(expr.operands()[0]);
280 }
281 else
282 {
284 "Variable not found in the offset set: " + expr.pretty());
285 }
286 }
287 else
288 {
289 // If the expression is pointer_offset(loop_entry(p)), look up the
290 // offset in the offset-of-loop-entry-set.
291 if(
292 cex.loop_entry_offsets.find(expr.operands()[0].operands()[0]) !=
293 cex.loop_entry_offsets.end())
294 {
295 result = cex.loop_entry_offsets.at(expr.operands()[0].operands()[0]);
296 }
297 else
298 {
300 "Variable not found in the offset set: " + expr.pretty());
301 }
302 }
303
304 // Typecast `result` to the type of `expr`.
305 auto tmp_expr = from_integer(result, expr.type());
306 to_integer(tmp_expr, result);
307 return result;
308 }
309
310 // For a constant expression, return its evaluation.
311 if(id == ID_constant)
312 {
313 to_integer(to_constant_expr(expr), result);
314 return result;
315 }
316
317 // For a plus expression, return the sum of the evaluations of two operands.
318 if(id == ID_plus)
319 {
320 result = evaluate_rec_int(expr.operands()[0], cex, is_positive) +
322
323 // Typecast `result` to the type of `expr`.
324 auto tmp_expr = from_integer(result, expr.type());
325 to_integer(tmp_expr, result);
326 return result;
327 }
328
329 // For a minus expression, return difference of evaluations of two operands.
330 if(id == ID_minus)
331 {
332 result = evaluate_rec_int(expr.operands()[0], cex, is_positive) -
334
335 // Typecast `result` to the type of `expr`.
336 auto tmp_expr = from_integer(result, expr.type());
337 to_integer(tmp_expr, result);
338 return result;
339 }
340
342 "Found a unsupported operator during quick filtering: " + expr.id_string());
343}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
bool to_integer(const constant_exprt &expr, mp_integer &int_value)
Convert a constant expression expr to an arbitrary-precision integer.
Evaluate if an expression is consistent with examples.
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
const std::vector< cext > & cexs
The set of examples evaluated against.
const exprt & checked_expr
The expression being evaluated.
bool evaluate_rec_bool(const exprt &expr, const cext &cex, const bool is_positive)
mp_integer evaluate_rec_int(const exprt &expr, const cext &cex, const bool is_positive)
Formatted counterexample.
Base class for all expressions.
Definition expr.h:56
typet & type()
Return the type of the expression.
Definition expr.h:84
operandst & operands()
Definition expr.h:94
The Boolean constant false.
Definition std_expr.h:3199
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition irep.cpp:482
const std::string & id_string() const
Definition irep.h:391
const irep_idt & id() const
Definition irep.h:388
The Boolean constant true.
Definition std_expr.h:3190
#define UNREACHABLE_BECAUSE(REASON)
Definition invariant.h:526
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3172
exprt is_positive(const exprt &x)