CBMC
Loading...
Searching...
No Matches
smt2_dec.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
9#include "smt2_dec.h"
10
11#include <util/invariant.h>
12#include <util/message.h>
13#include <util/run.h>
14#include <util/tempfile.h>
15
16#include "smt2irep.h"
17
18#include <fstream>
19
21{
22 // clang-format off
23 return "SMT2 " + logic + (use_FPA_theory ? " (with FPA)" : "") + " using " +
24 (solver==solvert::GENERIC?"Generic":
25 solver==solvert::BITWUZLA?"Bitwuzla":
26 solver==solvert::BOOLECTOR?"Boolector":
27 solver==solvert::CPROVER_SMT2?"CPROVER SMT2":
28 solver==solvert::CVC3?"CVC3":
29 solver==solvert::CVC4?"CVC4":
30 solver==solvert::CVC5?"CVC5":
31 solver==solvert::MATHSAT?"MathSAT":
32 solver==solvert::YICES?"Yices":
33 solver==solvert::Z3?"Z3":
34 "(unknown)");
35 // clang-format on
36}
37
39{
41
42 temporary_filet temp_file_problem("smt2_dec_problem_", ""),
43 temp_file_stdout("smt2_dec_stdout_", ""),
44 temp_file_stderr("smt2_dec_stderr_", "");
45
46 const auto write_problem_to_file = [&](std::ofstream problem_out) {
47 if(assumption.is_not_nil())
48 assumptions.push_back(convert(assumption));
49
51 stringstream.str(std::string{});
52
54
55 if(assumption.is_not_nil())
56 assumptions.pop_back();
57
58 problem_out << cached_output.str() << stringstream.str();
59 stringstream.str(std::string{});
60 };
61
62 write_problem_to_file(std::ofstream(
63 temp_file_problem(), std::ios_base::out | std::ios_base::trunc));
64
65 std::vector<std::string> argv;
66 std::string stdin_filename;
67
68 auto solver_binary_name = [this](const std::string &solver_name)
69 {
70 if(solver_binary_or_empty.empty())
71 return solver_name;
72 else
74 };
75
76 switch(solver)
77 {
79 argv = {solver_binary_name("bitwuzla"), temp_file_problem()};
80 break;
81
83 argv = {
84 solver_binary_name("boolector"), "--smt2", temp_file_problem(), "-m"};
85 break;
86
88 argv = {solver_binary_name("smt2_solver")};
90 break;
91
92 case solvert::CVC3:
93 argv = {
94 solver_binary_name("cvc3"),
95 "+model",
96 "-lang",
97 "smtlib",
98 "-output-lang",
99 "smtlib",
101 break;
102
103 case solvert::CVC4:
104 // The flags --bitblast=eager --bv-div-zero-const help but only
105 // work for pure bit-vector formulas.
106 argv = {solver_binary_name("cvc4"), "-L", "smt2", temp_file_problem()};
107 break;
108
109 case solvert::CVC5:
110 argv = {
111 solver_binary_name("cvc5"), "--lang", "smtlib", temp_file_problem()};
112 break;
113
114 case solvert::MATHSAT:
115 // The options below were recommended by Alberto Griggio
116 // on 10 July 2013
117
118 argv = {
119 solver_binary_name("mathsat"),
120 "-input=smt2",
121 "-preprocessor.toplevel_propagation=true",
122 "-preprocessor.simplification=7",
123 "-dpll.branching_random_frequency=0.01",
124 "-dpll.branching_random_invalidate_phase_cache=true",
125 "-dpll.restart_strategy=3",
126 "-dpll.glucose_var_activity=true",
127 "-dpll.glucose_learnt_minimization=true",
128 "-theory.bv.eager=true",
129 "-theory.bv.bit_blast_mode=1",
130 "-theory.bv.delay_propagated_eqs=true",
131 "-theory.fp.mode=1",
132 "-theory.fp.bit_blast_mode=2",
133 "-theory.arr.mode=1"};
134
136 break;
137
138 case solvert::YICES:
139 // command = "yices -smt -e " // Calling convention for older versions
140 // Convention for 2.2.1
141 argv = {solver_binary_name("yices-smt2"), temp_file_problem()};
142 break;
143
144 case solvert::Z3:
145 argv = {solver_binary_name("z3"), "-smt2", temp_file_problem()};
146 break;
147
148 case solvert::GENERIC:
151 break;
152 }
153
154 int res =
156
157 if(res<0)
158 {
160 log.error() << "error running SMT2 solver" << messaget::eom;
162 }
163
164 std::ifstream in(temp_file_stdout());
165 return read_result(in);
166}
167
168static std::string drop_quotes(std::string src)
169{
170 if(src.size() >= 2 && src.front() == '|' && src.back() == '|')
171 return std::string(src, 1, src.size() - 2);
172 else
173 return src;
174}
175
177{
178 std::string line;
180
183
184 typedef std::unordered_map<irep_idt, irept> valuest;
185 valuest parsed_values;
186
187 while(in)
188 {
190
191 if(!parsed_opt.has_value())
192 break;
193
194 const auto &parsed = parsed_opt.value();
195
196 if(parsed.id()=="sat")
198 else if(parsed.id()=="unsat")
200 else if(parsed.id() == "unknown")
201 {
203 log.error() << "SMT2 solver returned \"unknown\"" << messaget::eom;
205 }
206 else if(
207 parsed.id().empty() && parsed.get_sub().size() == 1 &&
208 parsed.get_sub().front().get_sub().size() == 2)
209 {
210 const irept &s0=parsed.get_sub().front().get_sub()[0];
211 const irept &s1=parsed.get_sub().front().get_sub()[1];
212
213 // Examples:
214 // ( (B0 true) )
215 // ( (|__CPROVER_pipe_count#1| (_ bv0 32)) )
216 // ( (|some_integer| 0) )
217 // ( (|some_integer| (- 10)) )
218
219 parsed_values[s0.id()] = s1;
220 }
221 else if(
222 parsed.id().empty() && parsed.get_sub().size() == 2 &&
223 parsed.get_sub().front().id() == "error")
224 {
225 // We ignore errors after UNSAT because get-value after check-sat
226 // returns unsat will give an error.
228 {
229 const auto &message = id2string(parsed.get_sub()[1].id());
231 log.error() << "SMT2 solver returned error message:\n"
232 << "\t\"" << message << "\"" << messaget::eom;
234 }
235 }
236 }
237
238 // If the result is not satisfiable don't bother updating the assignments and
239 // values (since we didn't get any), just return.
241 return res;
242
243 for(auto &assignment : identifier_map)
244 {
245 std::string conv_id = drop_quotes(convert_identifier(assignment.first));
246 const irept &value = parsed_values[conv_id];
247 assignment.second.value = parse_rec(value, assignment.second.type);
248 }
249
250 // Booleans
251 for(unsigned v=0; v<no_boolean_variables; v++)
252 {
253 const std::string boolean_identifier =
254 convert_identifier("B" + std::to_string(v));
255 const auto found_parsed_value =
258 {
259 const irept &value = found_parsed_value->second;
260
261 if(value.id() != ID_true && value.id() != ID_false)
262 {
264 log.error() << "SMT2 solver returned non-constant value for variable "
267 }
268 boolean_assignment[v] = value.id() == ID_true;
269 }
270 else
271 {
272 // Work out the value based on what set_to was called with.
274 if(found_set_value != set_values.end())
276 else
277 {
278 // Old code used the computation
279 // const irept &value=values["B"+std::to_string(v)];
280 // boolean_assignment[v]=(value.id()==ID_true);
281 const irept &value = parsed_values[boolean_identifier];
282
283 if(value.id() != ID_true && value.id() != ID_false)
284 {
286 log.error()
287 << "SMT2 solver returned non-Boolean value for variable "
290 }
291 boolean_assignment[v] = value.id() == ID_true;
292 }
293 }
294 }
295
296 return res;
297}
int8_t s1
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
resultt
Result of running the decision procedure.
Base class for all expressions.
Definition expr.h:57
There are a large number of kinds of tree structured or tree-like data in CPROVER.
Definition irep.h:364
bool is_not_nil() const
Definition irep.h:372
const irep_idt & id() const
Definition irep.h:388
Class that provides messages with a built-in verbosity 'level'.
Definition message.h:154
static eomt eom
Definition message.h:289
std::size_t number_of_solver_calls
Definition smt2_conv.h:111
void write_footer()
Writes the end of the SMT file to the smt_convt::out stream.
bool use_FPA_theory
Definition smt2_conv.h:67
std::string logic
Definition smt2_conv.h:102
static std::string convert_identifier(const irep_idt &identifier)
std::unordered_map< irep_idt, bool > set_values
The values which boolean identifiers have been smt2_convt::set_to or in other words those which are a...
Definition smt2_conv.h:285
exprt parse_rec(const irept &s, const typet &type)
std::vector< bool > boolean_assignment
Definition smt2_conv.h:294
std::vector< literalt > assumptions
Definition smt2_conv.h:108
solvert solver
Definition smt2_conv.h:103
identifier_mapt identifier_map
Definition smt2_conv.h:265
std::size_t no_boolean_variables
Definition smt2_conv.h:293
literalt convert(const exprt &expr)
message_handlert & message_handler
Definition smt2_dec.h:46
std::string decision_procedure_text() const override
Return a textual description of the decision procedure.
Definition smt2_dec.cpp:20
std::string solver_binary_or_empty
Definition smt2_dec.h:45
resultt dec_solve(const exprt &) override
Implementation of the decision procedure.
Definition smt2_dec.cpp:38
resultt read_result(std::istream &in)
Definition smt2_dec.cpp:176
std::stringstream cached_output
Everything except the footer is cached, so that output files can be rewritten with varying footers.
Definition smt2_dec.h:51
std::stringstream stringstream
Definition smt2_dec.h:20
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
return read_result
Definition java.io.c:7
double log(double x)
Definition math.c:2449
int run(const std::string &what, const std::vector< std::string > &argv)
Definition run.cpp:49
static std::string drop_quotes(std::string src)
Definition smt2_dec.cpp:168
std::optional< irept > smt2irep(std::istream &in, message_handlert &message_handler)
returns an irep for an SMT-LIB2 expression read from a given stream returns {} when EOF is encountere...
Definition smt2irep.cpp:92
#define PRECONDITION(CONDITION)
Definition invariant.h:463