CBMC
Loading...
Searching...
No Matches
refine_arithmetic.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
9#include "bv_refinement.h"
10
11#include <util/arith_tools.h>
13#include <util/bv_arithmetic.h>
14#include <util/expr_util.h>
15#include <util/floatbv_expr.h>
16#include <util/ieee_float.h>
17
20
21// Parameters
22#define MAX_INTEGER_UNDERAPPROX 3
23#define MAX_FLOAT_UNDERAPPROX 10
24
26{
27 // if it's a constant already, give up
28 if(!l.is_constant())
29 over_assumptions.push_back(literal_exprt(l));
30}
31
33{
34 // if it's a constant already, give up
35 if(!l.is_constant())
36 under_assumptions.push_back(literal_exprt(l));
37}
38
40{
42 return SUB::convert_floatbv_op(expr);
43
44 if(expr.type().id() != ID_floatbv)
45 return SUB::convert_floatbv_op(expr);
46
47 bvt bv;
48 add_approximation(expr, bv);
49 return bv;
50}
51
53{
55 return SUB::convert_mult(expr);
56
57 // we catch any multiplication
58 // unless it involves a constant
59
60 const exprt::operandst &operands=expr.operands();
61
62 const typet &type = expr.type();
63
64 PRECONDITION(operands.size()>=2);
65
66 if(operands.size()>2)
67 return convert_mult(to_mult_expr(make_binary(expr))); // make binary
68
69 // we keep multiplication by a constant for integers
70 if(type.id()!=ID_floatbv)
71 if(operands[0].is_constant() || operands[1].is_constant())
72 return SUB::convert_mult(expr);
73
74 bvt bv;
76
77 // initially, we have a partial interpretation for integers
78 if(type.id()==ID_signedbv ||
79 type.id()==ID_unsignedbv)
80 {
81 // x*0==0 and 0*x==0
87
88 // x*1==x and 1*x==x
91 literalt res_op0=bv_utils.equal(a.op0_bv, a.result_bv);
92 literalt res_op1=bv_utils.equal(a.op1_bv, a.result_bv);
95 }
96
97 return bv;
98}
99
101{
102 if(!config_.refine_arithmetic || expr.type().id()==ID_fixedbv)
103 return SUB::convert_div(expr);
104
105 // we catch any division
106 // unless it's integer division by a constant
107
108 PRECONDITION(expr.operands().size()==2);
109
110 if(expr.op1().is_constant())
111 return SUB::convert_div(expr);
112
113 bvt bv;
114 add_approximation(expr, bv);
115 return bv;
116}
117
119{
120 if(!config_.refine_arithmetic || expr.type().id()==ID_fixedbv)
121 return SUB::convert_mod(expr);
122
123 // we catch any mod
124 // unless it's integer + constant
125
126 PRECONDITION(expr.operands().size()==2);
127
128 if(expr.op1().is_constant())
129 return SUB::convert_mod(expr);
130
131 bvt bv;
132 add_approximation(expr, bv);
133 return bv;
134}
135
137{
138 std::size_t o=a.expr.operands().size();
139
140 if(o==1)
141 a.op0_value=get_value(a.op0_bv);
142 else if(o==2)
143 {
144 a.op0_value=get_value(a.op0_bv);
145 a.op1_value=get_value(a.op1_bv);
146 }
147 else if(o==3)
148 {
149 a.op0_value=get_value(a.op0_bv);
150 a.op1_value=get_value(a.op1_bv);
151 a.op2_value=get_value(a.op2_bv);
152 }
153 else
155
156 a.result_value=get_value(a.result_bv);
157}
158
162{
163 // see if the satisfying assignment is spurious in any way
164
165 const typet &type = a.expr.type();
166
167 if(type.id()==ID_floatbv)
168 {
169 const auto &float_op = to_ieee_float_op_expr(a.expr);
170
171 if(a.over_state==MAX_STATE)
172 return;
173
174 // get actual rounding mode
175 constant_exprt rounding_mode_expr =
176 to_constant_expr(get(float_op.rounding_mode()));
177 const std::size_t rounding_mode_int =
178 numeric_cast_v<std::size_t>(rounding_mode_expr);
179 ieee_floatt::rounding_modet rounding_mode =
181
183 ieee_floatt o0(spec, rounding_mode), o1(spec, rounding_mode);
184
185 o0.unpack(a.op0_value);
186 o1.unpack(a.op1_value);
187
188 ieee_floatt result = o0;
189
190 if(a.expr.id()==ID_floatbv_plus)
191 result+=o1;
192 else if(a.expr.id()==ID_floatbv_minus)
193 result-=o1;
194 else if(a.expr.id()==ID_floatbv_mult)
195 result*=o1;
196 else if(a.expr.id()==ID_floatbv_div)
197 result/=o1;
198 else
200
201 if(result.pack()==a.result_value) // ok
202 return;
203
204#ifdef DEBUG
205 ieee_floatt rr(spec);
206 rr.unpack(a.result_value);
207
208 log.debug() << "S1: " << o0 << " " << a.expr.id() << " " << o1
209 << " != " << rr << messaget::eom;
210 log.debug() << "S2: " << integer2binary(a.op0_value, spec.width()) << " "
211 << a.expr.id() << " "
212 << integer2binary(a.op1_value, spec.width())
213 << "!=" << integer2binary(a.result_value, spec.width())
214 << messaget::eom;
215 log.debug() << "S3: " << integer2binary(a.op0_value, spec.width()) << " "
216 << a.expr.id() << " "
217 << integer2binary(a.op1_value, spec.width())
218 << "==" << integer2binary(result.pack(), spec.width())
219 << messaget::eom;
220#endif
221
222 if(a.over_state<config_.max_node_refinement)
223 {
224 bvt r;
226 float_utils.spec=spec;
227 float_utils.rounding_mode_bits.set(rounding_mode);
228
230 bv_utils.equal(a.op0_bv, float_utils.build_constant(o0));
231
233 bv_utils.equal(a.op1_bv, float_utils.build_constant(o1));
234
236 bv_utils.equal(a.result_bv, float_utils.build_constant(result));
237
240
243 }
244 else
245 {
246 // give up
247 // remove any previous over-approximation
248 a.over_assumptions.clear();
249 a.over_state=MAX_STATE;
250
251 bvt r;
253 float_utils.spec=spec;
254 float_utils.rounding_mode_bits.set(rounding_mode);
255
256 bvt op0=a.op0_bv, op1=a.op1_bv, res=a.result_bv;
257
258 if(a.expr.id()==ID_floatbv_plus)
259 r=float_utils.add(op0, op1);
260 else if(a.expr.id()==ID_floatbv_minus)
261 r=float_utils.sub(op0, op1);
262 else if(a.expr.id()==ID_floatbv_mult)
263 r=float_utils.mul(op0, op1);
264 else if(a.expr.id()==ID_floatbv_div)
265 r=float_utils.div(op0, op1);
266 else
268
269 CHECK_RETURN(r.size()==res.size());
271 }
272 }
273 else if(type.id()==ID_signedbv ||
274 type.id()==ID_unsignedbv)
275 {
276 // these are all binary
277 INVARIANT(
278 a.expr.operands().size() == 2, "all (un)signedbv typed exprs are binary");
279
280 // already full interpretation?
281 if(a.over_state>0)
282 return;
283
284 bv_spect spec(type);
285 bv_arithmetict o0(spec), o1(spec);
286 o0.unpack(a.op0_value);
287 o1.unpack(a.op1_value);
288
289 // division by zero is never spurious
290
291 if((a.expr.id()==ID_div || a.expr.id()==ID_mod) &&
292 o1==0)
293 return;
294
295 if(a.expr.id()==ID_mult)
296 o0*=o1;
297 else if(a.expr.id()==ID_div)
298 o0/=o1;
299 else if(a.expr.id()==ID_mod)
300 o0%=o1;
301 else
303
304 if(o0.pack()==a.result_value) // ok
305 return;
306
307 if(a.over_state==0)
308 {
309 // we give up right away and add the full interpretation
310 bvt r;
311 if(a.expr.id()==ID_mult)
312 {
314 a.op0_bv, a.op1_bv,
315 a.expr.type().id()==ID_signedbv?
318 }
319 else if(a.expr.id()==ID_div)
320 {
322 a.op0_bv, a.op1_bv,
323 a.expr.type().id()==ID_signedbv?
326 }
327 else if(a.expr.id()==ID_mod)
328 {
330 a.op0_bv, a.op1_bv,
331 a.expr.type().id()==ID_signedbv?
334 }
335 else
337
338 bv_utils.set_equal(r, a.result_bv);
339 }
340 else
342 }
343 else if(type.id()==ID_fixedbv)
344 {
345 // TODO: not implemented
346 TODO;
347 }
348 else
349 {
351 }
352
353 log.status() << "Found spurious '" << a.as_string() << "' (state "
354 << a.over_state << ")" << messaget::eom;
355
356 progress=true;
357 if(a.over_state<MAX_STATE)
358 a.over_state++;
359}
360
364{
365 // part of the conflict?
366 if(!this->conflicts_with(a))
367 return;
368
369 log.status() << "Found assumption for '" << a.as_string()
370 << "' in proof (state " << a.under_state << ")" << messaget::eom;
371
372 PRECONDITION(!a.under_assumptions.empty());
373
374 a.under_assumptions.clear();
375
376 if(a.expr.type().id()==ID_floatbv)
377 {
378 const floatbv_typet &floatbv_type=to_floatbv_type(a.expr.type());
380
381 a.under_assumptions.reserve(a.op0_bv.size()+a.op1_bv.size());
382
384 float_utils.spec=spec;
385
386 // the fraction without hidden bit
387 const bvt fraction0=float_utils.get_fraction(a.op0_bv);
388 const bvt fraction1=float_utils.get_fraction(a.op1_bv);
389
390 if(a.under_state==0)
391 {
392 // we first set sign and exponent free,
393 // but keep the fraction zero
394
395 for(std::size_t i=0; i<fraction0.size(); i++)
396 a.add_under_assumption(!fraction0[i]);
397
398 for(std::size_t i=0; i<fraction1.size(); i++)
399 a.add_under_assumption(!fraction1[i]);
400 }
401 else
402 {
403 // now fraction: make this grow quadratically
404 unsigned x=a.under_state*a.under_state;
405
406 if(x>=MAX_FLOAT_UNDERAPPROX && x>=a.result_bv.size())
407 {
408 // make it free altogether, this guarantees progress
409 }
410 else
411 {
412 // set x bits of both exponent and mantissa free
413 // need to start with most-significant bits
414
415 #if 0
416 for(std::size_t i=x; i<fraction0.size(); i++)
417 a.add_under_assumption(!fraction0[fraction0.size()-i-1]);
418
419 for(std::size_t i=x; i<fraction1.size(); i++)
420 a.add_under_assumption(!fraction1[fraction1.size()-i-1]);
421 #endif
422 }
423 }
424 }
425 else
426 {
427 unsigned x=a.under_state+1;
428
429 if(x>=MAX_INTEGER_UNDERAPPROX && x>=a.result_bv.size())
430 {
431 // make it free altogether, this guarantees progress
432 }
433 else
434 {
435 // set x least-significant bits free
436 a.under_assumptions.reserve(a.op0_bv.size()+a.op1_bv.size());
437
438 for(std::size_t i=x; i<a.op0_bv.size(); i++)
439 a.add_under_assumption(!a.op0_bv[i]);
440
441 for(std::size_t i=x; i<a.op1_bv.size(); i++)
442 a.add_under_assumption(!a.op1_bv[i]);
443 }
444 }
445
446 a.under_state++;
447 progress=true;
448}
449
452{
453 for(std::size_t i=0; i<a.under_assumptions.size(); i++)
454 {
456 to_literal_expr(a.under_assumptions[i]).get_literal()))
457 {
458 return true;
459 }
460 }
461
462 return false;
463}
464
466{
467 a.over_state=a.under_state=0;
468
469 a.under_assumptions.reserve(a.op0_bv.size()+a.op1_bv.size());
470
471 // initially, we force the operands to be all zero
472
473 for(std::size_t i=0; i<a.op0_bv.size(); i++)
474 a.add_under_assumption(!a.op0_bv[i]);
475
476 for(std::size_t i=0; i<a.op1_bv.size(); i++)
477 a.add_under_assumption(!a.op1_bv[i]);
478}
479
482 const exprt &expr, bvt &bv)
483{
486
487 std::size_t width=boolbv_width(expr.type());
488 PRECONDITION(width!=0);
489
490 a.expr=expr;
491 a.result_bv=prop.new_variables(width);
492 a.no_operands=expr.operands().size();
493 set_frozen(a.result_bv);
494
495 if(a.no_operands==1)
496 {
497 a.op0_bv = convert_bv(to_unary_expr(expr).op());
498 set_frozen(a.op0_bv);
499 }
500 else if(a.no_operands==2)
501 {
502 a.op0_bv = convert_bv(to_binary_expr(expr).op0());
503 a.op1_bv = convert_bv(to_binary_expr(expr).op1());
504 set_frozen(a.op0_bv);
505 set_frozen(a.op1_bv);
506 }
507 else if(a.no_operands==3)
508 {
509 a.op0_bv = convert_bv(to_multi_ary_expr(expr).op0());
510 a.op1_bv = convert_bv(to_multi_ary_expr(expr).op1());
511 a.op2_bv = convert_bv(to_multi_ary_expr(expr).op2());
512 set_frozen(a.op0_bv);
513 set_frozen(a.op1_bv);
514 set_frozen(a.op2_bv);
515 }
516 else
518
519 bv=a.result_bv;
520
521 initialize(a);
522
523 return a;
524}
525
527{
528 return std::to_string(id_nr)+"/"+id2string(expr.id());
529}
Pre-defined bitvector types.
const floatbv_typet & to_floatbv_type(const typet &type)
Cast a typet to a floatbv_typet.
Abstraction Refinement Loop.
#define MAX_STATE
virtual void clear()
Reset the abstract state.
Definition ai.h:265
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
messaget log
Definition arrays.h:57
exprt & op1()
Definition expr.h:136
virtual const bvt & convert_bv(const exprt &expr, const std::optional< std::size_t > expected_width={})
Convert expression to vector of literalts, using an internal cache to speed up conversion if availabl...
Definition boolbv.cpp:39
virtual bvt convert_mod(const mod_exprt &expr)
virtual bvt convert_mult(const mult_exprt &expr)
exprt get(const exprt &expr) const override
Return expr with variables replaced by values from satisfying assignment if available.
virtual bvt convert_floatbv_op(const ieee_float_op_exprt &)
virtual bvt convert_div(const div_exprt &expr)
bv_utilst bv_utils
Definition boolbv.h:118
virtual std::size_t boolbv_width(const typet &type) const
Definition boolbv.h:103
mp_integer get_value(const bvt &bv)
Definition boolbv.h:91
bvt convert_mult(const mult_exprt &expr) override
bvt convert_div(const div_exprt &expr) override
bool conflicts_with(approximationt &approximation)
check if an under-approximation is part of the conflict
approximationt & add_approximation(const exprt &expr, bvt &bv)
void get_values(approximationt &approximation)
bvt convert_mod(const mod_exprt &expr) override
bvt convert_floatbv_op(const ieee_float_op_exprt &) override
void initialize(approximationt &approximation)
std::list< approximationt > approximations
void set_equal(const bvt &a, const bvt &b)
Definition bv_utils.cpp:34
literalt is_zero(const bvt &op)
Definition bv_utils.h:143
literalt equal(const bvt &op0, const bvt &op1)
Bit-blasting ID_equal and use in other encodings.
literalt is_one(const bvt &op)
Definition bv_utils.cpp:25
bvt remainder(const bvt &op0, const bvt &op1, representationt rep)
Definition bv_utils.h:96
bvt divider(const bvt &op0, const bvt &op1, representationt rep)
Definition bv_utils.h:89
bvt multiplier(const bvt &op0, const bvt &op1, representationt rep)
A constant literal expression.
Definition std_expr.h:3117
Division.
Definition std_expr.h:1157
Base class for all expressions.
Definition expr.h:56
std::vector< exprt > operandst
Definition expr.h:58
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:212
typet & type()
Return the type of the expression.
Definition expr.h:84
operandst & operands()
Definition expr.h:94
Fixed-width bit-vector with IEEE floating-point interpretation.
IEEE floating-point operations These have two data operands (op0 and op1) and one rounding mode (op2)...
std::size_t width() const
Definition ieee_float.h:50
mp_integer pack() const
An IEEE 754 value plus a rounding mode, enabling operations with rounding on values.
Definition ieee_float.h:338
const irep_idt & id() const
Definition irep.h:388
bool is_constant() const
Definition literal.h:166
mstreamt & debug() const
Definition message.h:421
static eomt eom
Definition message.h:289
mstreamt & status() const
Definition message.h:406
Modulo defined as lhs-(rhs * truncate(lhs/rhs)).
Definition std_expr.h:1228
Binary multiplication Associativity is not specified.
Definition std_expr.h:1107
void set_frozen(literalt)
void l_set_to_true(literalt a)
Definition prop.h:52
virtual literalt land(literalt a, literalt b)=0
virtual literalt limplies(literalt a, literalt b)=0
virtual bvt new_variables(std::size_t width)
generates a bitvector of given width with new variables
Definition prop.cpp:30
virtual literalt lor(literalt a, literalt b)=0
virtual bool is_in_conflict(literalt l) const =0
Returns true if an assumption is in the final conflict.
The type of an expression, extends irept.
Definition type.h:29
exprt make_binary(const exprt &expr)
splits an expression with >=3 operands into nested binary expressions
Definition expr_util.cpp:38
Deprecated expression utility functions.
API to expression classes for floating-point arithmetic.
const ieee_float_op_exprt & to_ieee_float_op_expr(const exprt &expr)
Cast an exprt to an ieee_float_op_exprt.
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
static int8_t r
Definition irep_hash.h:60
std::vector< literalt > bvt
Definition literal.h:201
const literal_exprt & to_literal_expr(const exprt &expr)
Cast a generic exprt to a literal_exprt.
const std::string integer2binary(const mp_integer &n, std::size_t width)
Definition mp_arith.cpp:64
#define MAX_INTEGER_UNDERAPPROX
#define MAX_FLOAT_UNDERAPPROX
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition invariant.h:525
#define PRECONDITION(CONDITION)
Definition invariant.h:463
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
#define TODO
Definition invariant.h:557
const mult_exprt & to_mult_expr(const exprt &expr)
Cast an exprt to a mult_exprt.
Definition std_expr.h:1137
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition std_expr.h:715
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition std_expr.h:426
const multi_ary_exprt & to_multi_ary_expr(const exprt &expr)
Cast an exprt to a multi_ary_exprt.
Definition std_expr.h:987
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3172
bool is_constant(const typet &type)
This method tests, if the given typet is a constant.
Definition std_types.h:29
std::vector< exprt > over_assumptions
unsigned max_node_refinement
Max number of times we refine a formula node.
bool refine_arithmetic
Enable arithmetic refinement.