mCRL2
Loading...
Searching...
No Matches
solver.cpp
Go to the documentation of this file.
1// Author(s): Ruud Koolen, Thomas Neele
2// Copyright: see the accompanying file COPYING or copy at
3// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
9/// \file solver.cpp
10
11#include "mcrl2/data/list.h"
12#include "mcrl2/smt/translate_specification.h"
13#include "mcrl2/smt/solver.h"
14#include "mcrl2/smt/unfold_pattern_matching.h"
15
16namespace mcrl2
17{
18namespace smt
19{
20
21answer smt_solver::execute_and_check(const std::string& s, const std::chrono::microseconds& timeout) const
22{
23 z3.write(s);
24
25 std::string result = timeout == std::chrono::microseconds::zero() ? z3.read() : z3.read(timeout);
26 if(result.compare(0, 3, "sat") == 0)
27 {
28 return answer::SAT;
29 }
30 else if(result.compare(0, 5, "unsat") == 0)
31 {
32 return answer::UNSAT;
33 }
34 else if(result.compare(0, 7, "unknown") == 0)
35 {
36 return answer::UNKNOWN;
37 }
38 else
39 {
40 mCRL2log(log::error) << "Error when checking satisfiability of \n" << s.substr(0, 500) << "...." << std::endl;
41 throw mcrl2::runtime_error("Got unexpected response from SMT-solver:\n" + result);
42 }
43}
44
47, z3("Z3")
48{
49 std::ostringstream out;
50 translate_data_specification(dataspec, out, m_cache, m_native);
51 z3.write(out.str());
52}
53
54answer smt_solver::solve(const data::variable_list& vars, const data::data_expression& expr, const std::chrono::microseconds& timeout)
55{
56 z3.write("(push)\n");
57 std::ostringstream out;
58 translate_variable_declaration(vars, out, m_cache, m_native);
59 translate_assertion(expr, out, m_cache, m_native);
60 out << "(check-sat)\n";
61 answer result = execute_and_check(out.str(), timeout);
62 z3.write("(pop)\n");
63 return result;
64}
65
66
67namespace detail {
68
70{
72
73 fixed_string_translation(const std::string& s)
74 : translation(s)
75 {}
76
77 void operator()(const data::data_expression& /*e*/,
78 const std::function<void(std::string)>& output_func,
79 const std::function<void(data::data_expression)>& /*translate_func*/) const
80 {
81 output_func(translation);
82 }
83};
84
86 const std::function<void(std::string)>& output_func,
87 const std::function<void(data::data_expression)>& /*translate_func*/)
88{
90};
92 const std::function<void(std::string)>& output_func,
93 const std::function<void(data::data_expression)>& /*translate_func*/)
94{
97 output_func("(/ " + data::pp(a[0]) + ".0 " + data::pp(a[1]) + ".0)");
98};
100 const std::function<void(std::string)>& output_func,
102{
105#ifndef MCRL2_ENABLE_MACHINENUMBERS
109 {
111 output_func("(" + std::string(data::sort_nat::is_first_application(a2) ? "div" : "mod") + " ");
112 translate_func(a2[0]);
113 output_func(" ");
114 translate_func(a2[1]);
115 output_func(")");
116 }
117 else
118#endif
119 {
120 throw translation_error("Cannot perform native translation of " + pp(e));
121 }
122};
123
124} // namespace detail
125
127{
128 using namespace detail;
129 using namespace data;
131
132 nt.sorts[sort_bool::bool_()] = "Bool";
133 nt.sorts[sort_pos::pos()] = "Int";
134 nt.sorts[sort_nat::nat()] = "Int";
135 nt.sorts[sort_int::int_()] = "Int";
136 nt.sorts[sort_real::real_()] = "Real";
137nt.sorts[sort_machine_word::machine_word()] = "Int";
138
139 std::vector<sort_expression> number_sorts({ sort_pos::pos(), sort_nat::nat(), sort_int::int_(), sort_real::real_() });
140 std::set<sort_expression> sorts = dataspec.sorts();
141 // Add native definitions for the left-hand side of every alias
142 for(const auto& alias: dataspec.sort_alias_map())
143 {
144 sorts.insert(alias.first);
145 }
146 for(const sort_expression& sort: sorts)
147 {
148 if(is_basic_sort(sort) || is_container_sort(sort))
149 {
150 nt.set_native_definition(equal_to(sort), "=");
151 nt.set_native_definition(not_equal_to(sort), "distinct");
152 nt.set_native_definition(if_(sort), "ite");
153
154 if(std::find(number_sorts.begin(), number_sorts.end(), sort) != number_sorts.end())
155 {
156 nt.set_native_definition(less(sort));
157 nt.set_native_definition(less_equal(sort));
158 nt.set_native_definition(greater(sort));
159 nt.set_native_definition(greater_equal(sort));
160 nt.set_alternative_name(sort_real::exp(sort, sort == sort_real::real_() ? sort_int::int_() : sort_nat::nat()), "^");
161 nt.set_alternative_name(sort_real::minus(sort, sort), "-");
162 nt.set_alternative_name(sort_real::negate(sort), "-");
163 }
164 else if(sort == basic_sort("@NatPair") || sort == basic_sort("@NatNatPair") || sort == basic_sort("@word"))
165 {
166 // NatPair is not used and its equations upset Z3
167 nt.set_native_definition(less(sort));
168 nt.set_native_definition(less_equal(sort));
169 nt.set_native_definition(greater(sort));
170 nt.set_native_definition(greater_equal(sort));
171 }
172 else
173 {
174 // Functions <, <=, >, >= are already defined on Int/Real and cannot be overloaded
175 nt.set_alternative_name(less(sort), "@less");
176 nt.set_alternative_name(less_equal(sort), "@less_equal");
177 nt.set_alternative_name(greater(sort), "@greater");
178 nt.set_alternative_name(greater_equal(sort), "@greater_equal");
179 }
180
181 std::string printed_sort_name = nt.sorts.find(sort) != nt.sorts.end() ? nt.sorts.find(sort)->second : translate_identifier(pp(sort));
182 std::string list_sort_name = "(List " + printed_sort_name + ")";
183 nt.set_alternative_name(sort_list::count(sort), "@list_count");
184 nt.set_alternative_name(sort_list::snoc(sort), "@snoc");
185 nt.set_native_definition(sort_list::empty(sort), "nil");
186 nt.set_ambiguous(sort_list::empty(sort));
187 nt.set_native_definition(sort_list::cons_(sort), "insert");
188 nt.set_native_definition(sort_list::head(sort));
189 nt.set_native_definition(sort_list::tail(sort));
190 nt.sorts[sort_list::list(sort)] = list_sort_name;
191 }
192 }
193
194 std::vector<function_symbol_vector> fs_numbers(
195 {
196 sort_pos::pos_generate_functions_code(),
197 sort_nat::nat_generate_functions_code(),
198 sort_int::int_generate_functions_code(),
199 sort_real::real_generate_functions_code()
200 }
201 );
202 for(const auto& fsv: fs_numbers)
203 {
204 for(const auto& fs: fsv)
205 {
206 nt.set_native_definition(fs);
207 }
208 }
209
210 auto one = [](const sort_expression& s)
211 {
212 return s == sort_int::int_() ? sort_int::int_(1) : sort_real::real_(1);
213 };
214 for(const sort_expression& s: { sort_int::int_(), sort_real::real_() })
215 {
216 variable v1("v1", s);
217 variable v2("v2", s);
218 variable_list l1({v1});
219 variable_list l2({v1,v2});
220 nt.mappings[sort_real::minimum(s,s)] = data_equation(l2, sort_real::minimum(v1, v2), if_(less(v1,v2), v1, v2));
221 nt.mappings[sort_real::maximum(s,s)] = data_equation(l2, sort_real::maximum(v1, v2), if_(less(v1,v2), v2, v1));
222 nt.mappings[sort_real::succ(s)] = data_equation(l1, sort_real::succ(v1), sort_real::plus(v1, one(s)));
223 nt.mappings[sort_real::pred(s)] = data_equation(l1, sort_real::pred(v1), sort_real::minus(v1, one(s)));
224 nt.set_ambiguous(sort_real::minimum(s,s));
225 nt.set_ambiguous(sort_real::maximum(s,s));
226 nt.set_ambiguous(sort_real::succ(s));
227 nt.set_ambiguous(sort_real::pred(s));
228 }
229 nt.expressions[sort_nat::first()] = reconstruct_divmod;
230 nt.expressions[sort_nat::last()] = reconstruct_divmod;
231
232 // TODO come up with equations for these
233 // nt.mappings[sort_real::floor(s)]
234 // nt.mappings[sort_real::ceil(s)]
235 // nt.mappings[sort_real::round(s)]
236
237 nt.set_native_definition(sort_bool::not_(), "not");
238 nt.set_native_definition(sort_bool::and_(), "and");
239 nt.set_native_definition(sort_bool::or_(), "or");
241
242nt.set_native_definition(sort_nat::c0(), pp(sort_nat::c0()));
243 nt.set_native_definition(sort_pos::c1(), pp(sort_pos::c1()));
244#ifdef MCRL2_ENABLE_MACHINENUMBERS
245 nt.set_native_definition(sort_pos::succpos(), "+ 1");
246 nt.set_native_definition(sort_nat::succ_nat(), "+ 1");
247 variable v1("v1", sort_nat::nat());
248 nt.mappings[sort_nat::natpred()] = data_equation(variable_list({v1}), sort_nat::natpred(v1), sort_int::minus(v1, sort_nat::nat(1)));
249 nt.set_native_definition(sort_machine_word::zero_word(), "0");
250 nt.set_native_definition(sort_machine_word::one_word(), "1");
251 nt.expressions[sort_pos::most_significant_digit()] = pp_translation;
252 nt.expressions[sort_pos::concat_digit()] = pp_translation;
253 nt.expressions[sort_nat::most_significant_digit_nat()] = pp_translation;
254 nt.expressions[sort_nat::concat_digit(sort_nat::nat(), sort_machine_word::machine_word())] = pp_translation;
255 // nt.set_ambiguous(sort_nat::concat_digit())
256#else
257 nt.expressions[sort_pos::cdub()] = pp_translation;
258 nt.set_native_definition(sort_nat::cnat(), "@id");
259#endif
260 nt.set_native_definition(sort_int::cneg(), "-");
261 nt.set_native_definition(sort_int::cint(), "@id");
262 nt.expressions[sort_real::creal()] = pp_real_translation;
264
265 nt.special_recogniser[data::sort_bool::true_()] = "@id";
266 nt.special_recogniser[data::sort_bool::false_()] = "not";
267 nt.special_recogniser[data::sort_pos::c1()] = "= 1";
268nt.special_recogniser[data::sort_nat::c0()] = "= 0";
269#ifdef MCRL2_ENABLE_MACHINENUMBERS
270nt.special_recogniser[sort_pos::succpos()] = ">= 2";
271 nt.special_recogniser[sort_nat::succ_nat()] = ">= 1";
272#else
273 nt.special_recogniser[data::sort_pos::cdub()] = ">= 2";
274 nt.special_recogniser[data::sort_nat::cnat()] = ">= 1";
275#endif
276 nt.special_recogniser[data::sort_int::cneg()] = "< 0";
277 nt.special_recogniser[data::sort_int::cint()] = ">= 0";
278
279 nt.set_native_definition(sort_nat::pos2nat(), "@id");
280 nt.set_native_definition(sort_nat::nat2pos(), "@id");
281 nt.set_native_definition(sort_int::pos2int(), "@id");
282 nt.set_native_definition(sort_int::int2pos(), "@id");
283 nt.set_native_definition(sort_int::nat2int(), "@id");
284 nt.set_native_definition(sort_int::int2nat(), "@id");
285 nt.set_native_definition(sort_real::pos2real(), "to_real");
286 nt.set_native_definition(sort_real::real2pos(), "to_int");
287 nt.set_native_definition(sort_real::nat2real(), "to_real");
288 nt.set_native_definition(sort_real::real2nat(), "to_int");
289 nt.set_native_definition(sort_real::int2real(), "to_real");
290 nt.set_native_definition(sort_real::real2int(), "to_int");
291
292 function_symbol id_bool("@id", function_sort({sort_bool::bool_()}, sort_bool::bool_()));
293 function_symbol id_int("@id", function_sort({sort_int::int_()}, sort_int::int_()));
294 function_symbol id_real("@id", function_sort({sort_real::real_()}, sort_real::real_()));
296 variable vi("i", sort_int::int_());
298 nt.mappings[id_bool] = data_equation(variable_list({vb}), id_bool(vb), vb);
299 nt.mappings[id_int] = data_equation(variable_list({vi}), id_int(vi), vi);
300 nt.mappings[id_real] = data_equation(variable_list({vr}), id_real(vr), vr);
301 // necessary for translating the equations above
302 nt.set_native_definition(equal_to(sort_bool::bool_()), "=");
303 nt.set_native_definition(equal_to(sort_int::int_()), "=");
304 nt.set_native_definition(equal_to(sort_real::real_()), "=");
305
307
308 return nt;
309}
310
311
312} // namespace smt
313} // namespace mcrl2
application operator()(const data_expression &e) const
Apply a data expression to a data expression.
\brief A function symbol
\brief A sort expression
\brief A data variable
Definition variable.h:28
answer solve(const data::variable_list &vars, const data::data_expression &expr, const std::chrono::microseconds &timeout=std::chrono::microseconds::zero())
Definition solver.cpp:54
answer execute_and_check(const std::string &command, const std::chrono::microseconds &timeout) const
Definition solver.cpp:21
smt_solver(const data::data_specification &dataspec)
Definition solver.cpp:45
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:391
Namespace for system defined sort bool_.
Definition bool.h:32
const basic_sort & bool_()
Constructor for sort expression Bool.
Definition bool.h:44
const function_symbol & implies()
Constructor for function symbol =>.
Definition bool.h:363
const function_symbol & and_()
Constructor for function symbol &&.
Definition bool.h:235
const function_symbol & false_()
Constructor for function symbol false.
Definition bool.h:109
const function_symbol & or_()
Constructor for function symbol ||.
Definition bool.h:299
const function_symbol & not_()
Constructor for function symbol !.
Definition bool.h:173
const function_symbol & true_()
Constructor for function symbol true.
Definition bool.h:77
Namespace for system defined sort int_.
const function_symbol & pos2int()
Constructor for function symbol Pos2Int.
Definition int1.h:360
const function_symbol & int2nat()
Constructor for function symbol Int2Nat.
Definition int1.h:298
const function_symbol & nat2int()
Constructor for function symbol Nat2Int.
Definition int1.h:236
const function_symbol & cneg()
Constructor for function symbol @cNeg.
Definition int1.h:142
const function_symbol & int2pos()
Constructor for function symbol Int2Pos.
Definition int1.h:422
const function_symbol & cint()
Constructor for function symbol @cInt.
Definition int1.h:80
const basic_sort & int_()
Constructor for sort expression Int.
Definition int1.h:47
Namespace for system defined sort nat.
const function_symbol & c0()
Constructor for function symbol @c0.
Definition nat1.h:108
const function_symbol & cnat()
Constructor for function symbol @cNat.
Definition nat1.h:140
const basic_sort & nat()
Constructor for sort expression Nat.
Definition nat1.h:46
const function_symbol & nat2pos()
Constructor for function symbol Nat2Pos.
Definition nat1.h:362
const function_symbol & pos2nat()
Constructor for function symbol Pos2Nat.
Definition nat1.h:300
Namespace for system defined sort pos.
const function_symbol & c1()
Constructor for function symbol @c1.
Definition pos1.h:78
const function_symbol & cdub()
Constructor for function symbol @cDub.
Definition pos1.h:110
const basic_sort & pos()
Constructor for sort expression Pos.
Definition pos1.h:45
Namespace for system defined sort real_.
const function_symbol & creal()
Constructor for function symbol @cReal.
Definition real1.h:107
const function_symbol & pos2real()
Constructor for function symbol Pos2Real.
Definition real1.h:171
const function_symbol & real2nat()
Constructor for function symbol Real2Nat.
Definition real1.h:419
const function_symbol & real2int()
Constructor for function symbol Real2Int.
Definition real1.h:481
const basic_sort & real_()
Constructor for sort expression Real.
Definition real1.h:48
const function_symbol & nat2real()
Constructor for function symbol Nat2Real.
Definition real1.h:233
const function_symbol & int2real()
Constructor for function symbol Int2Real.
Definition real1.h:295
const function_symbol & real2pos()
Constructor for function symbol Real2Pos.
Definition real1.h:357
Namespace for all data library functionality.
Definition data.cpp:22
atermpp::term_list< variable > variable_list
\brief list of variables
function_symbol equal_to(const sort_expression &s)
Constructor for function symbol ==.
Definition standard.h:126
static const native_translation_t pp_real_translation
Definition solver.cpp:91
static const native_translation_t pp_translation
Definition solver.cpp:85
static const native_translation_t reconstruct_divmod
Definition solver.cpp:99
native_translations initialise_native_translation(const data::data_specification &dataspec)
Definition solver.cpp:126
void unfold_pattern_matching(const data::data_specification &dataspec, native_translations &nt)
std::function< void(data::data_expression, std::function< void(std::string)>, std::function< void(data::data_expression)>)> native_translation_t
@ UNKNOWN
Definition answer.h:24
fixed_string_translation(const std::string &s)
Definition solver.cpp:73
void operator()(const data::data_expression &, const std::function< void(std::string)> &output_func, const std::function< void(data::data_expression)> &) const
Definition solver.cpp:77
void set_native_definition(const data::function_symbol &f)
Record that the mapping and equations for f should not be translated.
std::size_t operator()(const atermpp::detail::reference_aterm< T > &t) const