CBMC
smt_terms.cpp
Go to the documentation of this file.
1 // Author: Diffblue Ltd.
2 
4 
6 
7 #include <util/arith_tools.h>
8 #include <util/mp_arith.h>
9 #include <util/range.h>
10 
11 #include <algorithm>
12 #include <regex>
13 
14 // Define the irep_idts for terms.
15 #define TERM_ID(the_id) \
16  const irep_idt ID_smt_##the_id##_term{"smt_" #the_id "_term"};
17 #include <solvers/smt2_incremental/smt_terms.def>
18 #undef TERM_ID
19 
21  : irept{id, {{ID_type, upcast(std::move(sort))}}, {}}
22 {
23 }
24 
25 bool smt_termt::operator==(const smt_termt &other) const
26 {
27  return irept::operator==(other);
28 }
29 
30 bool smt_termt::operator!=(const smt_termt &other) const
31 {
32  return !(*this == other);
33 }
34 
36 {
37  return downcast(find(ID_type));
38 }
39 
41  : smt_termt{ID_smt_bool_literal_term, smt_bool_sortt{}}
42 {
43  set(ID_value, value);
44 }
45 
47 {
48  return get_bool(ID_value);
49 }
50 
51 static bool is_valid_smt_identifier(irep_idt identifier)
52 {
53  // The below regex matches a complete string which does not contain the `|`
54  // character. So it would match the string `foo bar`, but not `|foo bar|`.
55  static const std::regex valid{"[^\\|]*"};
56  return std::regex_match(id2string(identifier), valid);
57 }
58 
60  irep_idt identifier,
61  smt_sortt sort,
62  std::vector<smt_indext> indices)
63  : smt_termt(ID_smt_identifier_term, std::move(sort))
64 {
65  // The below invariant exists as a sanity check that the string being used for
66  // the identifier is in unescaped form. This is because the escaping and
67  // unescaping are implementation details of the printing to string and
68  // response parsing respectively, not part of the underlying data.
69  INVARIANT(
71  R"(Identifiers may not contain | characters.)");
72  set(ID_identifier, identifier);
73  for(auto &index : indices)
74  {
75  get_sub().push_back(
77  }
78 }
79 
81 {
82  return get(ID_identifier);
83 }
84 
85 std::vector<std::reference_wrapper<const smt_indext>>
87 {
88  return make_range(get_sub()).map([](const irept &index) {
89  return std::cref(
91  });
92 }
93 
95  const mp_integer &value,
97  : smt_termt{ID_smt_bit_vector_constant_term, std::move(sort)}
98 {
99  INVARIANT(
100  value < power(mp_integer{2}, get_sort().bit_width()),
101  "value must fit in number of bits available.");
102  INVARIANT(
103  !value.is_negative(),
104  "Negative numbers are not supported by bit vector constants.");
105  set(ID_value, integer2bvrep(value, get_sort().bit_width()));
106 }
107 
109  const mp_integer &value,
110  std::size_t bit_width)
112 {
113 }
114 
116 {
117  return bvrep2integer(get(ID_value), get_sort().bit_width(), false);
118 }
119 
121 {
122  // The below cast is sound because the constructor only allows bit_vector
123  // sorts to be set.
124  return static_cast<const smt_bit_vector_sortt &>(smt_termt::get_sort());
125 }
126 
128  smt_identifier_termt function_identifier,
129  std::vector<smt_termt> arguments)
130  : smt_termt(ID_smt_function_application_term, function_identifier.get_sort())
131 {
132  set(ID_identifier, std::move(function_identifier));
134  std::make_move_iterator(arguments.begin()),
135  std::make_move_iterator(arguments.end()),
136  std::back_inserter(get_sub()),
137  [](smt_termt &&argument) { return static_cast<irept &&>(argument); });
138 }
139 
140 const smt_identifier_termt &
142 {
143  return static_cast<const smt_identifier_termt &>(find(ID_identifier));
144 }
145 
146 std::vector<std::reference_wrapper<const smt_termt>>
148 {
149  return make_range(get_sub()).map([](const irept &argument) {
150  return std::cref(static_cast<const smt_termt &>(argument));
151  });
152 }
153 
155  std::vector<smt_identifier_termt> bound_variables,
156  smt_termt predicate)
157  : smt_termt{ID_smt_forall_term, smt_bool_sortt{}}
158 {
159  INVARIANT(
160  !bound_variables.empty(),
161  "A forall term should bind at least one variable.");
163  std::make_move_iterator(bound_variables.begin()),
164  std::make_move_iterator(bound_variables.end()),
165  std::back_inserter(get_sub()),
166  [](smt_identifier_termt &&bound_variable) {
167  return irept{std::move(bound_variable)};
168  });
169  INVARIANT(
170  predicate.get_sort().cast<smt_bool_sortt>(),
171  "Predicate of forall quantifier is expected to have bool sort.");
172  set(ID_body, std::move(predicate));
173 }
174 
176 {
177  return static_cast<const smt_termt &>(find(ID_body));
178 }
179 
180 std::vector<std::reference_wrapper<const smt_identifier_termt>>
182 {
183  return make_range(get_sub()).map([](const irept &variable) {
184  return std::cref(static_cast<const smt_identifier_termt &>(variable));
185  });
186 }
187 
189  std::vector<smt_identifier_termt> bound_variables,
190  smt_termt predicate)
191  : smt_termt{ID_smt_exists_term, smt_bool_sortt{}}
192 {
193  INVARIANT(
194  !bound_variables.empty(),
195  "A exists term should bind at least one variable.");
197  std::make_move_iterator(bound_variables.begin()),
198  std::make_move_iterator(bound_variables.end()),
199  std::back_inserter(get_sub()),
200  [](smt_identifier_termt &&bound_variable) {
201  return irept{std::move(bound_variable)};
202  });
203  INVARIANT(
204  predicate.get_sort().cast<smt_bool_sortt>(),
205  "Predicate of exists quantifier is expected to have bool sort.");
206  set(ID_body, std::move(predicate));
207 }
208 
210 {
211  return static_cast<const smt_termt &>(find(ID_body));
212 }
213 
214 std::vector<std::reference_wrapper<const smt_identifier_termt>>
216 {
217  return make_range(get_sub()).map([](const irept &variable) {
218  return std::cref(static_cast<const smt_identifier_termt &>(variable));
219  });
220 }
221 
222 template <typename visitort>
223 void accept(const smt_termt &term, const irep_idt &id, visitort &&visitor)
224 {
225 #define TERM_ID(the_id) \
226  if(id == ID_smt_##the_id##_term) \
227  return visitor.visit(static_cast<const smt_##the_id##_termt &>(term));
228 // The include below is marked as nolint because including the same file
229 // multiple times is required as part of the x macro pattern.
230 #include <solvers/smt2_incremental/smt_terms.def> // NOLINT(build/include)
231 #undef TERM_ID
232  UNREACHABLE;
233 }
234 
236 {
237  ::accept(*this, id(), visitor);
238 }
239 
241 {
242  ::accept(*this, id(), std::move(visitor));
243 }
UNREACHABLE
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:503
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
mp_integer
BigInt mp_integer
Definition: smt_terms.h:17
smt_function_application_termt::function_identifier
const smt_identifier_termt & function_identifier() const
Definition: smt_terms.cpp:141
smt_identifier_termt
Stores identifiers in unescaped and unquoted form.
Definition: smt_terms.h:91
arith_tools.h
mp_arith.h
smt_identifier_termt::smt_identifier_termt
smt_identifier_termt(irep_idt identifier, smt_sortt sort, std::vector< smt_indext > indices={})
Constructs an identifier term with the given identifier and sort.
Definition: smt_terms.cpp:59
smt_function_application_termt::smt_function_application_termt
smt_function_application_termt(smt_identifier_termt function_identifier, std::vector< smt_termt > arguments)
Unchecked construction of function application terms.
Definition: smt_terms.cpp:127
accept
void accept(const smt_termt &term, const irep_idt &id, visitort &&visitor)
Definition: smt_terms.cpp:223
transform
static abstract_object_pointert transform(const exprt &expr, const std::vector< abstract_object_pointert > &operands, const abstract_environmentt &environment, const namespacet &ns)
Definition: abstract_value_object.cpp:159
irept::find
const irept & find(const irep_idt &name) const
Definition: irep.cpp:106
smt_termt
Definition: smt_terms.h:20
is_valid_smt_identifier
static bool is_valid_smt_identifier(irep_idt identifier)
Definition: smt_terms.cpp:51
smt_bit_vector_sortt
Definition: smt_sorts.h:83
smt_forall_termt::smt_forall_termt
smt_forall_termt(std::vector< smt_identifier_termt > bound_variables, smt_termt predicate)
Definition: smt_terms.cpp:154
smt_termt::operator==
bool operator==(const smt_termt &) const
Definition: smt_terms.cpp:25
smt_bit_vector_constant_termt::value
mp_integer value() const
Definition: smt_terms.cpp:115
smt_bit_vector_constant_termt::smt_bit_vector_constant_termt
smt_bit_vector_constant_termt(const mp_integer &value, smt_bit_vector_sortt)
Definition: smt_terms.cpp:94
smt_forall_termt::predicate
const smt_termt & predicate() const
Definition: smt_terms.cpp:175
smt_bool_literal_termt::value
bool value() const
Definition: smt_terms.cpp:46
irept::get
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:45
smt_sortt::storert< smt_termt >::upcast
static irept upcast(smt_sortt sort)
Definition: smt_sorts.h:66
smt_termt::operator!=
bool operator!=(const smt_termt &) const
Definition: smt_terms.cpp:30
smt_sorts.h
smt_identifier_termt::indices
std::vector< std::reference_wrapper< const smt_indext > > indices() const
Definition: smt_terms.cpp:86
integer2bvrep
irep_idt integer2bvrep(const mp_integer &src, std::size_t width)
convert an integer to bit-vector representation with given width This uses two's complement for negat...
Definition: arith_tools.cpp:380
smt_termt::smt_termt
smt_termt()=delete
id2string
const std::string & id2string(const irep_idt &d)
Definition: irep.h:47
smt_termt::accept
void accept(smt_term_const_downcast_visitort &) const
Definition: smt_terms.cpp:235
irept::set
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:420
smt_sortt
Definition: smt_sorts.h:17
smt_bool_sortt
Definition: smt_sorts.h:77
smt_identifier_termt::identifier
irep_idt identifier() const
Definition: smt_terms.cpp:80
smt_termt::get_sort
const smt_sortt & get_sort() const
Definition: smt_terms.cpp:35
irept::id
const irep_idt & id() const
Definition: irep.h:396
range.h
smt_forall_termt::bound_variables
std::vector< std::reference_wrapper< const smt_identifier_termt > > bound_variables() const
Definition: smt_terms.cpp:181
smt_exists_termt::smt_exists_termt
smt_exists_termt(std::vector< smt_identifier_termt > bound_variables, smt_termt predicate)
Definition: smt_terms.cpp:188
smt_exists_termt::predicate
const smt_termt & predicate() const
Definition: smt_terms.cpp:209
smt_indext::storert
Class for adding the ability to up and down cast smt_indext to and from irept.
Definition: smt_index.h:36
smt_bool_literal_termt::smt_bool_literal_termt
smt_bool_literal_termt(bool value)
Definition: smt_terms.cpp:40
irept::operator==
bool operator==(const irept &other) const
Definition: irep.cpp:146
bvrep2integer
mp_integer bvrep2integer(const irep_idt &src, std::size_t width, bool is_signed)
convert a bit-vector representation (possibly signed) to integer
Definition: arith_tools.cpp:402
irept::get_sub
subt & get_sub()
Definition: irep.h:456
smt_bit_vector_constant_termt::get_sort
const smt_bit_vector_sortt & get_sort() const
Definition: smt_terms.cpp:120
power
mp_integer power(const mp_integer &base, const mp_integer &exponent)
A multi-precision implementation of the power operator.
Definition: arith_tools.cpp:195
irept
There are a large number of kinds of tree structured or tree-like data in CPROVER.
Definition: irep.h:359
smt_function_application_termt::arguments
std::vector< std::reference_wrapper< const smt_termt > > arguments() const
Definition: smt_terms.cpp:147
INVARIANT
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition: invariant.h:423
smt_term_const_downcast_visitort
Definition: smt_terms.h:247
smt_bit_vector_constant_termt
Definition: smt_terms.h:116
smt_terms.h
make_range
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition: range.h:524
irept::get_bool
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:58
validation_modet::INVARIANT
@ INVARIANT
smt_sortt::storert< smt_termt >::downcast
static const smt_sortt & downcast(const irept &)
Definition: smt_sorts.h:72
smt_exists_termt::bound_variables
std::vector< std::reference_wrapper< const smt_identifier_termt > > bound_variables() const
Definition: smt_terms.cpp:215