CBMC
smt2_dec.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 "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 
19 {
20  // clang-format off
21  return "SMT2 " + logic + (use_FPA_theory ? " (with FPA)" : "") + " using " +
22  (solver==solvert::GENERIC?"Generic":
23  solver==solvert::BITWUZLA?"Bitwuzla":
24  solver==solvert::BOOLECTOR?"Boolector":
25  solver==solvert::CPROVER_SMT2?"CPROVER SMT2":
26  solver==solvert::CVC3?"CVC3":
27  solver==solvert::CVC4?"CVC4":
28  solver==solvert::CVC5?"CVC5":
29  solver==solvert::MATHSAT?"MathSAT":
30  solver==solvert::YICES?"Yices":
31  solver==solvert::Z3?"Z3":
32  "(unknown)");
33  // clang-format on
34 }
35 
37 {
39 
40  temporary_filet temp_file_problem("smt2_dec_problem_", ""),
41  temp_file_stdout("smt2_dec_stdout_", ""),
42  temp_file_stderr("smt2_dec_stderr_", "");
43 
44  const auto write_problem_to_file = [&](std::ofstream problem_out) {
45  if(assumption.is_not_nil())
46  assumptions.push_back(convert(assumption));
47 
48  cached_output << stringstream.str();
49  stringstream.str(std::string{});
50 
51  write_footer();
52 
53  if(assumption.is_not_nil())
54  assumptions.pop_back();
55 
56  problem_out << cached_output.str() << stringstream.str();
57  stringstream.str(std::string{});
58  };
59 
60  write_problem_to_file(std::ofstream(
61  temp_file_problem(), std::ios_base::out | std::ios_base::trunc));
62 
63  std::vector<std::string> argv;
64  std::string stdin_filename;
65 
66  switch(solver)
67  {
68  case solvert::BITWUZLA:
69  argv = {"bitwuzla", temp_file_problem()};
70  break;
71 
72  case solvert::BOOLECTOR:
73  argv = {"boolector", "--smt2", temp_file_problem(), "-m"};
74  break;
75 
77  argv = {"smt2_solver"};
78  stdin_filename = temp_file_problem();
79  break;
80 
81  case solvert::CVC3:
82  argv = {"cvc3",
83  "+model",
84  "-lang",
85  "smtlib",
86  "-output-lang",
87  "smtlib",
88  temp_file_problem()};
89  break;
90 
91  case solvert::CVC4:
92  // The flags --bitblast=eager --bv-div-zero-const help but only
93  // work for pure bit-vector formulas.
94  argv = {"cvc4", "-L", "smt2", temp_file_problem()};
95  break;
96 
97  case solvert::CVC5:
98  argv = {"cvc5", "--lang", "smtlib", temp_file_problem()};
99  break;
100 
101  case solvert::MATHSAT:
102  // The options below were recommended by Alberto Griggio
103  // on 10 July 2013
104 
105  argv = {"mathsat",
106  "-input=smt2",
107  "-preprocessor.toplevel_propagation=true",
108  "-preprocessor.simplification=7",
109  "-dpll.branching_random_frequency=0.01",
110  "-dpll.branching_random_invalidate_phase_cache=true",
111  "-dpll.restart_strategy=3",
112  "-dpll.glucose_var_activity=true",
113  "-dpll.glucose_learnt_minimization=true",
114  "-theory.bv.eager=true",
115  "-theory.bv.bit_blast_mode=1",
116  "-theory.bv.delay_propagated_eqs=true",
117  "-theory.fp.mode=1",
118  "-theory.fp.bit_blast_mode=2",
119  "-theory.arr.mode=1"};
120 
121  stdin_filename = temp_file_problem();
122  break;
123 
124  case solvert::YICES:
125  // command = "yices -smt -e " // Calling convention for older versions
126  // Convention for 2.2.1
127  argv = {"yices-smt2", temp_file_problem()};
128  break;
129 
130  case solvert::Z3:
131  argv = {"z3", "-smt2", temp_file_problem()};
132  break;
133 
134  case solvert::GENERIC:
135  UNREACHABLE;
136  }
137 
138  int res =
139  run(argv[0], argv, stdin_filename, temp_file_stdout(), temp_file_stderr());
140 
141  if(res<0)
142  {
144  log.error() << "error running SMT2 solver" << messaget::eom;
146  }
147 
148  std::ifstream in(temp_file_stdout());
149  return read_result(in);
150 }
151 
152 static std::string drop_quotes(std::string src)
153 {
154  if(src.size() >= 2 && src.front() == '|' && src.back() == '|')
155  return std::string(src, 1, src.size() - 2);
156  else
157  return src;
158 }
159 
161 {
162  std::string line;
164 
165  boolean_assignment.clear();
167 
168  typedef std::unordered_map<irep_idt, irept> valuest;
169  valuest parsed_values;
170 
171  while(in)
172  {
173  auto parsed_opt = smt2irep(in, message_handler);
174 
175  if(!parsed_opt.has_value())
176  break;
177 
178  const auto &parsed = parsed_opt.value();
179 
180  if(parsed.id()=="sat")
182  else if(parsed.id()=="unsat")
184  else if(parsed.id() == "unknown")
185  {
187  log.error() << "SMT2 solver returned \"unknown\"" << messaget::eom;
189  }
190  else if(
191  parsed.id().empty() && parsed.get_sub().size() == 1 &&
192  parsed.get_sub().front().get_sub().size() == 2)
193  {
194  const irept &s0=parsed.get_sub().front().get_sub()[0];
195  const irept &s1=parsed.get_sub().front().get_sub()[1];
196 
197  // Examples:
198  // ( (B0 true) )
199  // ( (|__CPROVER_pipe_count#1| (_ bv0 32)) )
200  // ( (|some_integer| 0) )
201  // ( (|some_integer| (- 10)) )
202 
203  parsed_values[s0.id()] = s1;
204  }
205  else if(
206  parsed.id().empty() && parsed.get_sub().size() == 2 &&
207  parsed.get_sub().front().id() == "error")
208  {
209  // We ignore errors after UNSAT because get-value after check-sat
210  // returns unsat will give an error.
211  if(res != resultt::D_UNSATISFIABLE)
212  {
213  const auto &message = id2string(parsed.get_sub()[1].id());
215  log.error() << "SMT2 solver returned error message:\n"
216  << "\t\"" << message << "\"" << messaget::eom;
218  }
219  }
220  }
221 
222  // If the result is not satisfiable don't bother updating the assignments and
223  // values (since we didn't get any), just return.
224  if(res != resultt::D_SATISFIABLE)
225  return res;
226 
227  for(auto &assignment : identifier_map)
228  {
229  std::string conv_id = drop_quotes(convert_identifier(assignment.first));
230  const irept &value = parsed_values[conv_id];
231  assignment.second.value = parse_rec(value, assignment.second.type);
232  }
233 
234  // Booleans
235  for(unsigned v=0; v<no_boolean_variables; v++)
236  {
237  const std::string boolean_identifier =
239  boolean_assignment[v] = [&]() {
240  const auto found_parsed_value =
241  parsed_values.find(drop_quotes(boolean_identifier));
242  if(found_parsed_value != parsed_values.end())
243  {
244  return found_parsed_value->second.id() == ID_true;
245  }
246  // Work out the value based on what set_to was called with.
247  const auto found_set_value = set_values.find(boolean_identifier);
248  if(found_set_value != set_values.end())
249  return found_set_value->second;
250  // Old code used the computation
251  // const irept &value=values["B"+std::to_string(v)];
252  // boolean_assignment[v]=(value.id()==ID_true);
253  return parsed_values[boolean_identifier].id() == ID_true;
254  }();
255  }
256 
257  return res;
258 }
int8_t s1
Definition: bytecode_info.h:59
resultt
Result of running the decision procedure.
Base class for all expressions.
Definition: expr.h:56
There are a large number of kinds of tree structured or tree-like data in CPROVER.
Definition: irep.h:360
subt & get_sub()
Definition: irep.h:444
bool is_not_nil() const
Definition: irep.h:368
const irep_idt & id() const
Definition: irep.h:384
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:155
static eomt eom
Definition: message.h:297
std::size_t number_of_solver_calls
Definition: smt2_conv.h:109
void write_footer()
Writes the end of the SMT file to the smt_convt::out stream.
Definition: smt2_conv.cpp:205
bool use_FPA_theory
Definition: smt2_conv.h:65
std::string logic
Definition: smt2_conv.h:100
static std::string convert_identifier(const irep_idt &identifier)
Definition: smt2_conv.cpp:1017
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:278
exprt parse_rec(const irept &s, const typet &type)
Definition: smt2_conv.cpp:698
std::vector< bool > boolean_assignment
Definition: smt2_conv.h:287
std::vector< literalt > assumptions
Definition: smt2_conv.h:106
solvert solver
Definition: smt2_conv.h:101
identifier_mapt identifier_map
Definition: smt2_conv.h:258
std::size_t no_boolean_variables
Definition: smt2_conv.h:286
literalt convert(const exprt &expr)
Definition: smt2_conv.cpp:893
message_handlert & message_handler
Definition: smt2_dec.h:45
std::string decision_procedure_text() const override
Return a textual description of the decision procedure.
Definition: smt2_dec.cpp:18
resultt dec_solve(const exprt &) override
Implementation of the decision procedure.
Definition: smt2_dec.cpp:36
resultt read_result(std::istream &in)
Definition: smt2_dec.cpp:160
std::stringstream cached_output
Everything except the footer is cached, so that output files can be rewritten with varying footers.
Definition: smt2_dec.h:50
std::stringstream stringstream
Definition: smt2_dec.h:22
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
double trunc(double x)
Definition: math.c:1516
double log(double x)
Definition: math.c:2776
int run(const std::string &what, const std::vector< std::string > &argv)
Definition: run.cpp:48
static std::string drop_quotes(std::string src)
Definition: smt2_dec.cpp:152
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 UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.