CBMC
simplify_expr_boolean.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
9 #include "simplify_expr_class.h"
10 
11 #include "arith_tools.h"
12 #include "c_types.h"
13 #include "expr_util.h"
14 #include "mathematical_expr.h"
15 #include "namespace.h"
16 #include "std_expr.h"
17 
18 #include <unordered_set>
19 
21 {
22  if(!expr.has_operands())
23  return unchanged(expr);
24 
25  if(expr.type().id()!=ID_bool)
26  return unchanged(expr);
27 
28  if(expr.id()==ID_implies)
29  {
30  const auto &implies_expr = to_implies_expr(expr);
31 
32  if(
33  implies_expr.op0().type().id() != ID_bool ||
34  implies_expr.op1().type().id() != ID_bool)
35  {
36  return unchanged(expr);
37  }
38 
39  // turn a => b into !a || b
40 
41  binary_exprt new_expr = implies_expr;
42  new_expr.id(ID_or);
43  new_expr.op0() = simplify_not(not_exprt(new_expr.op0()));
44  return changed(simplify_boolean(new_expr));
45  }
46  else if(expr.id()==ID_xor)
47  {
48  bool no_change = true;
49  bool negate = false;
50 
51  exprt::operandst new_operands = expr.operands();
52 
53  for(exprt::operandst::const_iterator it = new_operands.begin();
54  it != new_operands.end();)
55  {
56  if(it->type().id()!=ID_bool)
57  return unchanged(expr);
58 
59  bool erase;
60 
61  if(it->is_true())
62  {
63  erase=true;
64  negate=!negate;
65  }
66  else
67  erase=it->is_false();
68 
69  if(erase)
70  {
71  it = new_operands.erase(it);
72  no_change = false;
73  }
74  else
75  it++;
76  }
77 
78  if(new_operands.empty())
79  {
80  return make_boolean_expr(negate);
81  }
82  else if(new_operands.size() == 1)
83  {
84  if(negate)
85  return changed(simplify_not(not_exprt(new_operands.front())));
86  else
87  return std::move(new_operands.front());
88  }
89 
90  if(!no_change)
91  {
92  auto tmp = expr;
93  tmp.operands() = std::move(new_operands);
94  return std::move(tmp);
95  }
96  }
97  else if(expr.id()==ID_and || expr.id()==ID_or)
98  {
99  std::unordered_set<exprt, irep_hash> expr_set;
100 
101  bool no_change = true;
102  bool may_be_reducible_to_interval =
103  expr.id() == ID_or && expr.operands().size() > 2;
104 
105  exprt::operandst new_operands = expr.operands();
106 
107  for(exprt::operandst::const_iterator it = new_operands.begin();
108  it != new_operands.end();)
109  {
110  if(it->type().id()!=ID_bool)
111  return unchanged(expr);
112 
113  bool is_true=it->is_true();
114  bool is_false=it->is_false();
115 
116  if(expr.id()==ID_and && is_false)
117  {
118  return false_exprt();
119  }
120  else if(expr.id()==ID_or && is_true)
121  {
122  return true_exprt();
123  }
124 
125  bool erase=
126  (expr.id()==ID_and ? is_true : is_false) ||
127  !expr_set.insert(*it).second;
128 
129  if(erase)
130  {
131  it = new_operands.erase(it);
132  no_change = false;
133  }
134  else
135  {
136  if(may_be_reducible_to_interval)
137  may_be_reducible_to_interval = it->id() == ID_equal;
138  it++;
139  }
140  }
141 
142  if(may_be_reducible_to_interval)
143  {
144  optionalt<symbol_exprt> symbol_opt;
145  std::set<mp_integer> values;
146  for(const exprt &op : new_operands)
147  {
148  equal_exprt eq = to_equal_expr(op);
149  if(eq.lhs().is_constant())
150  std::swap(eq.lhs(), eq.rhs());
151  if(auto s = expr_try_dynamic_cast<symbol_exprt>(eq.lhs()))
152  {
153  if(!symbol_opt.has_value())
154  symbol_opt = *s;
155 
156  if(*s == *symbol_opt)
157  {
158  if(auto c = expr_try_dynamic_cast<constant_exprt>(eq.rhs()))
159  {
160  constant_exprt c_tmp = *c;
161  if(c_tmp.type().id() == ID_c_enum_tag)
162  c_tmp.type() = ns.follow_tag(to_c_enum_tag_type(c_tmp.type()));
163  if(auto int_opt = numeric_cast<mp_integer>(c_tmp))
164  {
165  values.insert(*int_opt);
166  continue;
167  }
168  }
169  }
170  }
171 
172  symbol_opt.reset();
173  break;
174  }
175 
176  if(symbol_opt.has_value() && values.size() >= 3)
177  {
178  mp_integer lower = *values.begin();
179  mp_integer upper = *std::prev(values.end());
180  if(upper - lower + 1 == mp_integer{values.size()})
181  {
182  typet type = symbol_opt->type();
183  if(symbol_opt->type().id() == ID_c_enum_tag)
184  {
185  type = ns.follow_tag(to_c_enum_tag_type(symbol_opt->type()))
186  .underlying_type();
187  }
188 
190  from_integer(lower, type),
191  typecast_exprt::conditional_cast(*symbol_opt, type)};
193  typecast_exprt::conditional_cast(*symbol_opt, type),
194  from_integer(upper, type)};
195 
196  return and_exprt{lb, ub};
197  }
198  }
199  }
200 
201  // search for a and !a
202  for(const exprt &op : new_operands)
203  if(
204  op.id() == ID_not && op.type().id() == ID_bool &&
205  expr_set.find(to_not_expr(op).op()) != expr_set.end())
206  {
207  return make_boolean_expr(expr.id() == ID_or);
208  }
209 
210  if(new_operands.empty())
211  {
212  return make_boolean_expr(expr.id() == ID_and);
213  }
214  else if(new_operands.size() == 1)
215  {
216  return std::move(new_operands.front());
217  }
218 
219  if(!no_change)
220  {
221  auto tmp = expr;
222  tmp.operands() = std::move(new_operands);
223  return std::move(tmp);
224  }
225  }
226 
227  return unchanged(expr);
228 }
229 
231 {
232  const exprt &op = expr.op();
233 
234  if(expr.type().id()!=ID_bool ||
235  op.type().id()!=ID_bool)
236  {
237  return unchanged(expr);
238  }
239 
240  if(op.id()==ID_not) // (not not a) == a
241  {
242  return to_not_expr(op).op();
243  }
244  else if(op.is_false())
245  {
246  return true_exprt();
247  }
248  else if(op.is_true())
249  {
250  return false_exprt();
251  }
252  else if(op.id()==ID_and ||
253  op.id()==ID_or)
254  {
255  exprt tmp = op;
256 
257  Forall_operands(it, tmp)
258  {
259  *it = simplify_not(not_exprt(*it));
260  }
261 
262  tmp.id(tmp.id() == ID_and ? ID_or : ID_and);
263 
264  return std::move(tmp);
265  }
266  else if(op.id()==ID_notequal) // !(a!=b) <-> a==b
267  {
268  exprt tmp = op;
269  tmp.id(ID_equal);
270  return std::move(tmp);
271  }
272  else if(op.id()==ID_exists) // !(exists: a) <-> forall: not a
273  {
274  auto const &op_as_exists = to_exists_expr(op);
275  return forall_exprt{op_as_exists.variables(),
276  simplify_not(not_exprt(op_as_exists.where()))};
277  }
278  else if(op.id() == ID_forall) // !(forall: a) <-> exists: not a
279  {
280  auto const &op_as_forall = to_forall_expr(op);
281  return exists_exprt{op_as_forall.variables(),
282  simplify_not(not_exprt(op_as_forall.where()))};
283  }
284 
285  return unchanged(expr);
286 }
typecast_exprt::conditional_cast
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:2025
mp_integer
BigInt mp_integer
Definition: smt_terms.h:17
binary_exprt::rhs
exprt & rhs()
Definition: std_expr.h:623
simplify_expr_class.h
Forall_operands
#define Forall_operands(it, expr)
Definition: expr.h:27
arith_tools.h
forall_exprt
A forall expression.
Definition: mathematical_expr.h:337
typet
The type of an expression, extends irept.
Definition: type.h:28
and_exprt
Boolean AND.
Definition: std_expr.h:2070
exists_exprt
An exists expression.
Definition: mathematical_expr.h:379
simplify_exprt::simplify_boolean
resultt simplify_boolean(const exprt &)
Definition: simplify_expr_boolean.cpp:20
exprt
Base class for all expressions.
Definition: expr.h:55
binary_exprt::lhs
exprt & lhs()
Definition: std_expr.h:613
binary_exprt
A base class for binary expressions.
Definition: std_expr.h:582
namespace_baset::follow_tag
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
exprt::is_true
bool is_true() const
Return whether the expression is a constant representing true.
Definition: expr.cpp:34
namespace.h
equal_exprt
Equality.
Definition: std_expr.h:1305
simplify_exprt::simplify_not
resultt simplify_not(const not_exprt &)
Definition: simplify_expr_boolean.cpp:230
simplify_exprt::unchanged
static resultt unchanged(exprt expr)
Definition: simplify_expr_class.h:136
exprt::is_false
bool is_false() const
Return whether the expression is a constant representing false.
Definition: expr.cpp:43
binding_exprt::variables
variablest & variables()
Definition: std_expr.h:3073
is_false
bool is_false(const literalt &l)
Definition: literal.h:197
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
exprt::has_operands
bool has_operands() const
Return true if there is at least one operand.
Definition: expr.h:91
to_c_enum_tag_type
const c_enum_tag_typet & to_c_enum_tag_type(const typet &type)
Cast a typet to a c_enum_tag_typet.
Definition: c_types.h:344
simplify_exprt::changed
static resultt changed(resultt<> result)
Definition: simplify_expr_class.h:141
irept::id
const irep_idt & id() const
Definition: irep.h:396
exprt::operandst
std::vector< exprt > operandst
Definition: expr.h:58
false_exprt
The Boolean constant false.
Definition: std_expr.h:3016
unary_exprt::op
const exprt & op() const
Definition: std_expr.h:326
simplify_exprt::resultt
Definition: simplify_expr_class.h:102
optionalt
nonstd::optional< T > optionalt
Definition: optional.h:35
to_exists_expr
const exists_exprt & to_exists_expr(const exprt &expr)
Definition: mathematical_expr.h:404
expr_util.h
Deprecated expression utility functions.
to_not_expr
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition: std_expr.h:2303
to_implies_expr
const implies_exprt & to_implies_expr(const exprt &expr)
Cast an exprt to a implies_exprt.
Definition: std_expr.h:2159
from_integer
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:100
exprt::is_constant
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.cpp:27
to_equal_expr
const equal_exprt & to_equal_expr(const exprt &expr)
Cast an exprt to an equal_exprt.
Definition: std_expr.h:1347
simplify_exprt::ns
const namespacet & ns
Definition: simplify_expr_class.h:266
make_boolean_expr
constant_exprt make_boolean_expr(bool value)
returns true_exprt if given true and false_exprt otherwise
Definition: expr_util.cpp:284
exprt::operands
operandst & operands()
Definition: expr.h:94
less_than_or_equal_exprt
Binary less than or equal operator expression.
Definition: std_expr.h:814
true_exprt
The Boolean constant true.
Definition: std_expr.h:3007
constant_exprt
A constant literal expression.
Definition: std_expr.h:2941
is_true
bool is_true(const literalt &l)
Definition: literal.h:198
std_expr.h
c_types.h
to_forall_expr
const forall_exprt & to_forall_expr(const exprt &expr)
Definition: mathematical_expr.h:362
binary_exprt::op0
exprt & op0()
Definition: expr.h:125
mathematical_expr.h
not_exprt
Boolean negation.
Definition: std_expr.h:2277