CBMC
solver_factory.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Solver Factory
4 
5 Author: Daniel Kroening, Peter Schrammel
6 
7 \*******************************************************************/
8 
11 
12 #include "solver_factory.h"
13 
14 #include <util/cmdline.h>
15 #include <util/exception_utils.h>
16 #include <util/make_unique.h>
17 #include <util/message.h>
18 #include <util/options.h>
19 #include <util/version.h>
20 
21 #include <iostream>
22 
23 #ifdef _MSC_VER
24 #include <util/unicode.h>
25 #endif
26 
28 
30 #include <solvers/prop/prop.h>
33 #include <solvers/sat/dimacs_cnf.h>
35 #include <solvers/sat/satcheck.h>
39 
41 
43  const optionst &_options,
44  const namespacet &_ns,
45  message_handlert &_message_handler,
46  bool _output_xml_in_refinement)
47  : options(_options),
48  ns(_ns),
49  message_handler(_message_handler),
50  output_xml_in_refinement(_output_xml_in_refinement)
51 {
52 }
53 
54 solver_factoryt::solvert::solvert(std::unique_ptr<decision_proceduret> p)
55  : decision_procedure_ptr(std::move(p))
56 {
57 }
58 
60  std::unique_ptr<decision_proceduret> p1,
61  std::unique_ptr<propt> p2)
62  : prop_ptr(std::move(p2)), decision_procedure_ptr(std::move(p1))
63 {
64 }
65 
67  std::unique_ptr<decision_proceduret> p1,
68  std::unique_ptr<std::ofstream> p2)
69  : ofstream_ptr(std::move(p2)), decision_procedure_ptr(std::move(p1))
70 {
71 }
72 
74 {
75  PRECONDITION(decision_procedure_ptr != nullptr);
76  return *decision_procedure_ptr;
77 }
78 
81 {
82  PRECONDITION(decision_procedure_ptr != nullptr);
84  dynamic_cast<stack_decision_proceduret *>(&*decision_procedure_ptr);
85  INVARIANT(solver != nullptr, "stack decision procedure required");
86  return *solver;
87 }
88 
90 {
91  PRECONDITION(prop_ptr != nullptr);
92  return *prop_ptr;
93 }
94 
96  decision_proceduret &decision_procedure)
97 {
98  const int timeout_seconds =
99  options.get_signed_int_option("solver-time-limit");
100 
101  if(timeout_seconds > 0)
102  {
104  dynamic_cast<solver_resource_limitst *>(&decision_procedure);
105  if(solver == nullptr)
106  {
108  log.warning() << "cannot set solver time limit on "
109  << decision_procedure.decision_procedure_text()
110  << messaget::eom;
111  return;
112  }
113 
114  solver->set_time_limit_seconds(timeout_seconds);
115  }
116 }
117 
119  std::unique_ptr<decision_proceduret> p)
120 {
121  decision_procedure_ptr = std::move(p);
122 }
123 
124 void solver_factoryt::solvert::set_prop(std::unique_ptr<propt> p)
125 {
126  prop_ptr = std::move(p);
127 }
128 
129 void solver_factoryt::solvert::set_ofstream(std::unique_ptr<std::ofstream> p)
130 {
131  ofstream_ptr = std::move(p);
132 }
133 
134 std::unique_ptr<solver_factoryt::solvert> solver_factoryt::get_solver()
135 {
136  if(options.get_bool_option("dimacs"))
137  return get_dimacs();
138  if(options.is_set("external-sat-solver"))
139  return get_external_sat();
140  if(
141  options.get_bool_option("refine") &&
142  !options.get_bool_option("refine-strings"))
143  {
144  return get_bv_refinement();
145  }
146  else if(options.get_bool_option("refine-strings"))
147  return get_string_refinement();
148  const auto incremental_smt2_solver =
149  options.get_option("incremental-smt2-solver");
150  if(!incremental_smt2_solver.empty())
151  return get_incremental_smt2(incremental_smt2_solver);
152  if(options.get_bool_option("smt2"))
153  return get_smt2(get_smt2_solver_type());
154  return get_default();
155 }
156 
160 {
161  // we shouldn't get here if this option isn't set
163 
165 
166  if(options.get_bool_option("boolector"))
168  else if(options.get_bool_option("cprover-smt2"))
170  else if(options.get_bool_option("mathsat"))
172  else if(options.get_bool_option("cvc3"))
174  else if(options.get_bool_option("cvc4"))
176  else if(options.get_bool_option("yices"))
178  else if(options.get_bool_option("z3"))
180  else if(options.get_bool_option("generic"))
182 
183  return s;
184 }
185 
186 template <typename SatcheckT>
187 static std::unique_ptr<SatcheckT>
189 {
190  auto satcheck = util_make_unique<SatcheckT>(message_handler);
191  if(options.is_set("write-solver-stats-to"))
192  {
193  if(
194  auto hardness_collector = dynamic_cast<hardness_collectort *>(&*satcheck))
195  {
196  std::unique_ptr<solver_hardnesst> solver_hardness =
197  util_make_unique<solver_hardnesst>();
198  solver_hardness->set_outfile(options.get_option("write-solver-stats-to"));
199  hardness_collector->solver_hardness = std::move(solver_hardness);
200  }
201  else
202  {
204  log.warning()
205  << "Configured solver does not support --write-solver-stats-to. "
206  << "Solver stats will not be written." << messaget::eom;
207  }
208  }
209  return satcheck;
210 }
211 
212 std::unique_ptr<solver_factoryt::solvert> solver_factoryt::get_default()
213 {
214  auto solver = util_make_unique<solvert>();
215  if(
216  options.get_bool_option("beautify") ||
217  !options.get_bool_option("sat-preprocessor")) // no simplifier
218  {
219  // simplifier won't work with beautification
220  solver->set_prop(
221  make_satcheck_prop<satcheck_no_simplifiert>(message_handler, options));
222  }
223  else // with simplifier
224  {
225  solver->set_prop(make_satcheck_prop<satcheckt>(message_handler, options));
226  }
227 
228  bool get_array_constraints =
229  options.get_bool_option("show-array-constraints");
230  auto bv_pointers = util_make_unique<bv_pointerst>(
231  ns, solver->prop(), message_handler, get_array_constraints);
232 
233  if(options.get_option("arrays-uf") == "never")
234  bv_pointers->unbounded_array = bv_pointerst::unbounded_arrayt::U_NONE;
235  else if(options.get_option("arrays-uf") == "always")
236  bv_pointers->unbounded_array = bv_pointerst::unbounded_arrayt::U_ALL;
237 
238  set_decision_procedure_time_limit(*bv_pointers);
239  solver->set_decision_procedure(std::move(bv_pointers));
240 
241  return solver;
242 }
243 
244 std::unique_ptr<solver_factoryt::solvert> solver_factoryt::get_dimacs()
245 {
248 
249  auto prop = util_make_unique<dimacs_cnft>(message_handler);
250 
251  std::string filename = options.get_option("outfile");
252 
253  auto bv_dimacs =
254  util_make_unique<bv_dimacst>(ns, *prop, message_handler, filename);
255 
256  return util_make_unique<solvert>(std::move(bv_dimacs), std::move(prop));
257 }
258 
259 std::unique_ptr<solver_factoryt::solvert> solver_factoryt::get_external_sat()
260 {
263 
264  std::string external_sat_solver = options.get_option("external-sat-solver");
265  auto prop =
266  util_make_unique<external_satt>(message_handler, external_sat_solver);
267 
268  auto bv_pointers = util_make_unique<bv_pointerst>(ns, *prop, message_handler);
269 
270  return util_make_unique<solvert>(std::move(bv_pointers), std::move(prop));
271 }
272 
273 std::unique_ptr<solver_factoryt::solvert> solver_factoryt::get_bv_refinement()
274 {
275  std::unique_ptr<propt> prop = [this]() -> std::unique_ptr<propt> {
276  // We offer the option to disable the SAT preprocessor
277  if(options.get_bool_option("sat-preprocessor"))
278  {
280  return make_satcheck_prop<satcheckt>(message_handler, options);
281  }
282  return make_satcheck_prop<satcheck_no_simplifiert>(
284  }();
285 
287  info.ns = &ns;
288  info.prop = prop.get();
290 
291  // we allow setting some parameters
292  if(options.get_bool_option("max-node-refinement"))
293  info.max_node_refinement =
294  options.get_unsigned_int_option("max-node-refinement");
295 
296  info.refine_arrays = options.get_bool_option("refine-arrays");
297  info.refine_arithmetic = options.get_bool_option("refine-arithmetic");
299 
300  auto decision_procedure = util_make_unique<bv_refinementt>(info);
301  set_decision_procedure_time_limit(*decision_procedure);
302  return util_make_unique<solvert>(
303  std::move(decision_procedure), std::move(prop));
304 }
305 
309 std::unique_ptr<solver_factoryt::solvert>
311 {
313  info.ns = &ns;
314  auto prop =
315  make_satcheck_prop<satcheck_no_simplifiert>(message_handler, options);
316  info.prop = prop.get();
319  if(options.get_bool_option("max-node-refinement"))
320  info.max_node_refinement =
321  options.get_unsigned_int_option("max-node-refinement");
322  info.refine_arrays = options.get_bool_option("refine-arrays");
323  info.refine_arithmetic = options.get_bool_option("refine-arithmetic");
325 
326  auto decision_procedure = util_make_unique<string_refinementt>(info);
327  set_decision_procedure_time_limit(*decision_procedure);
328  return util_make_unique<solvert>(
329  std::move(decision_procedure), std::move(prop));
330 }
331 
332 std::unique_ptr<solver_factoryt::solvert>
333 solver_factoryt::get_incremental_smt2(std::string solver_command)
334 {
336  auto solver_process = util_make_unique<smt_piped_solver_processt>(
337  std::move(solver_command), message_handler);
338 
339  return util_make_unique<solvert>(
340  util_make_unique<smt2_incremental_decision_proceduret>(
341  ns, std::move(solver_process), message_handler));
342 }
343 
344 std::unique_ptr<solver_factoryt::solvert>
346 {
348 
349  const std::string &filename = options.get_option("outfile");
350 
351  if(filename.empty())
352  {
354  {
356  "required filename not provided",
357  "--outfile",
358  "provide a filename with --outfile");
359  }
360 
361  auto smt2_dec = util_make_unique<smt2_dect>(
362  ns,
363  "cbmc",
364  std::string("Generated by CBMC ") + CBMC_VERSION,
365  "QF_AUFBV",
366  solver,
368 
369  if(options.get_bool_option("fpa"))
370  smt2_dec->use_FPA_theory = true;
371 
373  return util_make_unique<solvert>(std::move(smt2_dec));
374  }
375  else if(filename == "-")
376  {
377  auto smt2_conv = util_make_unique<smt2_convt>(
378  ns,
379  "cbmc",
380  std::string("Generated by CBMC ") + CBMC_VERSION,
381  "QF_AUFBV",
382  solver,
383  std::cout);
384 
385  if(options.get_bool_option("fpa"))
386  smt2_conv->use_FPA_theory = true;
387 
389  return util_make_unique<solvert>(std::move(smt2_conv));
390  }
391  else
392  {
393 #ifdef _MSC_VER
394  auto out = util_make_unique<std::ofstream>(widen(filename));
395 #else
396  auto out = util_make_unique<std::ofstream>(filename);
397 #endif
398 
399  if(!*out)
400  {
402  "failed to open file: " + filename, "--outfile");
403  }
404 
405  auto smt2_conv = util_make_unique<smt2_convt>(
406  ns,
407  "cbmc",
408  std::string("Generated by CBMC ") + CBMC_VERSION,
409  "QF_AUFBV",
410  solver,
411  *out);
412 
413  if(options.get_bool_option("fpa"))
414  smt2_conv->use_FPA_theory = true;
415 
417  return util_make_unique<solvert>(std::move(smt2_conv), std::move(out));
418  }
419 }
420 
422 {
423  if(options.get_bool_option("beautify"))
424  {
426  "the chosen solver does not support beautification", "--beautify");
427  }
428 }
429 
431 {
432  const bool all_properties = options.get_bool_option("all-properties");
433  const bool cover = options.is_set("cover");
434  const bool incremental_loop = options.is_set("incremental-loop");
435 
436  if(all_properties)
437  {
439  "the chosen solver does not support incremental solving",
440  "--all_properties");
441  }
442  else if(cover)
443  {
445  "the chosen solver does not support incremental solving", "--cover");
446  }
447  else if(incremental_loop)
448  {
450  "the chosen solver does not support incremental solving",
451  "--incremental-loop");
452  }
453 }
454 
455 static void parse_sat_options(const cmdlinet &cmdline, optionst &options)
456 {
457  if(cmdline.isset("external-sat-solver"))
458  {
460  "external-sat-solver", cmdline.get_value("external-sat-solver"));
461  }
462 
463  options.set_option("sat-preprocessor", !cmdline.isset("no-sat-preprocessor"));
464 
465  if(cmdline.isset("dimacs"))
466  options.set_option("dimacs", true);
467 }
468 
469 static void parse_smt2_options(const cmdlinet &cmdline, optionst &options)
470 {
471  if(cmdline.isset("smt2"))
472  options.set_option("smt2", true);
473 
474  if(cmdline.isset("fpa"))
475  options.set_option("fpa", true);
476 
477  bool solver_set = false;
478 
479  if(cmdline.isset("boolector"))
480  {
481  options.set_option("boolector", true), solver_set = true;
482  options.set_option("smt2", true);
483  }
484 
485  if(cmdline.isset("cprover-smt2"))
486  {
487  options.set_option("cprover-smt2", true), solver_set = true;
488  options.set_option("smt2", true);
489  }
490 
491  if(cmdline.isset("mathsat"))
492  {
493  options.set_option("mathsat", true), solver_set = true;
494  options.set_option("smt2", true);
495  }
496 
497  if(cmdline.isset("cvc4"))
498  {
499  options.set_option("cvc4", true), solver_set = true;
500  options.set_option("smt2", true);
501  }
502 
503  if(cmdline.isset("incremental-smt2-solver"))
504  {
506  "incremental-smt2-solver", cmdline.get_value("incremental-smt2-solver")),
507  solver_set = true;
508  }
509 
510  if(cmdline.isset("yices"))
511  {
512  options.set_option("yices", true), solver_set = true;
513  options.set_option("smt2", true);
514  }
515 
516  if(cmdline.isset("z3"))
517  {
518  options.set_option("z3", true), solver_set = true;
519  options.set_option("smt2", true);
520  }
521 
522  if(cmdline.isset("smt2") && !solver_set)
523  {
524  if(cmdline.isset("outfile"))
525  {
526  // outfile and no solver should give standard compliant SMT-LIB
527  options.set_option("generic", true);
528  }
529  else
530  {
531  // the default smt2 solver
532  options.set_option("z3", true);
533  }
534  }
535 }
536 
538 {
539  parse_sat_options(cmdline, options);
540  parse_smt2_options(cmdline, options);
541 
542  if(cmdline.isset("outfile"))
543  options.set_option("outfile", cmdline.get_value("outfile"));
544 
545  if(cmdline.isset("write-solver-stats-to"))
546  {
548  "write-solver-stats-to", cmdline.get_value("write-solver-stats-to"));
549  }
550 
551  if(cmdline.isset("beautify"))
552  options.set_option("beautify", true);
553 
554  if(cmdline.isset("refine-arrays"))
555  {
556  options.set_option("refine", true);
557  options.set_option("refine-arrays", true);
558  }
559 
560  if(cmdline.isset("refine-arithmetic"))
561  {
562  options.set_option("refine", true);
563  options.set_option("refine-arithmetic", true);
564  }
565 
566  if(cmdline.isset("refine"))
567  {
568  options.set_option("refine", true);
569  options.set_option("refine-arrays", true);
570  options.set_option("refine-arithmetic", true);
571  }
572 
573  if(cmdline.isset("max-node-refinement"))
574  {
576  "max-node-refinement", cmdline.get_value("max-node-refinement"));
577  }
578 }
messaget
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:154
smt2_convt::solvert::CVC4
@ CVC4
exception_utils.h
bv_refinementt::configt::max_node_refinement
unsigned max_node_refinement
Max number of times we refine a formula node.
Definition: bv_refinement.h:26
bv_refinementt::configt::output_xml
bool output_xml
Definition: bv_refinement.h:24
smt2_convt::solvert::CPROVER_SMT2
@ CPROVER_SMT2
solver_factoryt::solvert::set_decision_procedure
void set_decision_procedure(std::unique_ptr< decision_proceduret > p)
Definition: solver_factory.cpp:118
parse_smt2_options
static void parse_smt2_options(const cmdlinet &cmdline, optionst &options)
Definition: solver_factory.cpp:469
cmdlinet::isset
virtual bool isset(char option) const
Definition: cmdline.cpp:30
optionst
Definition: options.h:22
parse_solver_options
void parse_solver_options(const cmdlinet &cmdline, optionst &options)
Parse solver-related command-line parameters in cmdline and set corresponding values in options.
Definition: solver_factory.cpp:537
optionst::get_option
const std::string get_option(const std::string &option) const
Definition: options.cpp:67
decision_proceduret
Definition: decision_procedure.h:20
bv_refinementt::infot
Definition: bv_refinement.h:33
solver_factoryt::get_dimacs
std::unique_ptr< solvert > get_dimacs()
Definition: solver_factory.cpp:244
bv_refinement.h
string_refinementt::configt::refinement_bound
std::size_t refinement_bound
Definition: string_refinement.h:69
smt_solver_process.h
solver_hardness.h
smt2_convt::solvert::MATHSAT
@ MATHSAT
bv_refinementt::configt::refine_arithmetic
bool refine_arithmetic
Enable arithmetic refinement.
Definition: bv_refinement.h:30
solver_factoryt::set_decision_procedure_time_limit
void set_decision_procedure_time_limit(decision_proceduret &decision_procedure)
Sets the timeout of decision_procedure if the solver-time-limit option has a positive value (in secon...
Definition: solver_factory.cpp:95
solver_factoryt::no_incremental_check
void no_incremental_check()
Definition: solver_factory.cpp:430
DEFAULT_MAX_NB_REFINEMENT
#define DEFAULT_MAX_NB_REFINEMENT
Definition: string_refinement.h:62
options.h
optionst::set_option
void set_option(const std::string &option, const bool value)
Definition: options.cpp:28
messaget::eom
static eomt eom
Definition: message.h:297
solver_factoryt::solvert::prop
propt & prop() const
Definition: solver_factory.cpp:89
stack_decision_proceduret
Definition: stack_decision_procedure.h:57
version.h
smt2_convt::solvert::CVC3
@ CVC3
smt2_convt::solvert::BOOLECTOR
@ BOOLECTOR
namespacet
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:90
stack_decision_procedure.h
solver_factoryt::get_incremental_smt2
std::unique_ptr< solvert > get_incremental_smt2(std::string solver_command)
Definition: solver_factory.cpp:333
cmdlinet
Definition: cmdline.h:20
CBMC_VERSION
const char * CBMC_VERSION
make_unique.h
solver_factoryt::get_string_refinement
std::unique_ptr< solvert > get_string_refinement()
the string refinement adds to the bit vector refinement specifications for functions from the Java st...
Definition: solver_factory.cpp:310
solver_factoryt::get_bv_refinement
std::unique_ptr< solvert > get_bv_refinement()
Definition: solver_factory.cpp:273
solver_factoryt::no_beautification
void no_beautification()
Definition: solver_factory.cpp:421
smt2_convt::solvert::YICES
@ YICES
solver_factoryt::solvert::solvert
solvert()=default
external_sat.h
optionst::is_set
bool is_set(const std::string &option) const
N.B. opts.is_set("foo") does not imply opts.get_bool_option("foo")
Definition: options.cpp:62
PRECONDITION
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
bv_refinementt::infot::prop
propt * prop
Definition: bv_refinement.h:36
solver_factoryt::solvert::set_ofstream
void set_ofstream(std::unique_ptr< std::ofstream > p)
Definition: solver_factory.cpp:129
cmdlinet::get_value
std::string get_value(char option) const
Definition: cmdline.cpp:48
prop.h
bv_refinementt::infot::message_handler
message_handlert * message_handler
Definition: bv_refinement.h:37
solver_factoryt::message_handler
message_handlert & message_handler
Definition: solver_factory.h:71
optionst::get_signed_int_option
signed int get_signed_int_option(const std::string &option) const
Definition: options.cpp:50
message_handlert
Definition: message.h:27
string_refinement.h
solver_factory.h
widen
std::wstring widen(const char *s)
Definition: unicode.cpp:48
smt2_incremental_decision_procedure.h
solver_factoryt::solver_factoryt
solver_factoryt(const optionst &_options, const namespacet &_ns, message_handlert &_message_handler, bool _output_xml_in_refinement)
Note: The solver returned will hold a reference to the namespace ns.
Definition: solver_factory.cpp:42
solver_factoryt::get_default
std::unique_ptr< solvert > get_default()
Definition: solver_factory.cpp:212
optionst::get_unsigned_int_option
unsigned int get_unsigned_int_option(const std::string &option) const
Definition: options.cpp:56
boolbvt::unbounded_arrayt::U_NONE
@ U_NONE
solver_resource_limits.h
solver_factoryt::get_solver
virtual std::unique_ptr< solvert > get_solver()
Returns a solvert object.
Definition: solver_factory.cpp:134
solver_factoryt::solvert::stack_decision_procedure
stack_decision_proceduret & stack_decision_procedure() const
Definition: solver_factory.cpp:80
solver_factoryt::get_external_sat
std::unique_ptr< solvert > get_external_sat()
Definition: solver_factory.cpp:259
decision_proceduret::decision_procedure_text
virtual std::string decision_procedure_text() const =0
Return a textual description of the decision procedure.
satcheck.h
dimacs_cnf.h
propt
TO_BE_DOCUMENTED.
Definition: prop.h:22
solver_hardnesst::set_outfile
void set_outfile(const std::string &file_name)
Definition: solver_hardness.cpp:114
cmdline.h
solver_factoryt::solvert::set_prop
void set_prop(std::unique_ptr< propt > p)
Definition: solver_factory.cpp:124
solver_resource_limitst
Definition: solver_resource_limits.h:15
solver
int solver(std::istream &in)
Definition: smt2_solver.cpp:407
optionst::get_bool_option
bool get_bool_option(const std::string &option) const
Definition: options.cpp:44
boolbvt::unbounded_arrayt::U_ALL
@ U_ALL
solver_factoryt::options
const optionst & options
Definition: solver_factory.h:69
unicode.h
smt2_convt::solvert::GENERIC
@ GENERIC
make_satcheck_prop
static std::unique_ptr< SatcheckT > make_satcheck_prop(message_handlert &message_handler, const optionst &options)
Definition: solver_factory.cpp:188
smt2_convt::solvert::Z3
@ Z3
hardness_collectort
Definition: hardness_collector.h:44
string_refinementt::infot
string_refinementt constructor arguments
Definition: string_refinement.h:75
smt2_convt::solvert
solvert
Definition: smt2_conv.h:39
parse_sat_options
static void parse_sat_options(const cmdlinet &cmdline, optionst &options)
Definition: solver_factory.cpp:455
solver_factoryt::output_xml_in_refinement
const bool output_xml_in_refinement
Definition: solver_factory.h:72
bv_refinementt::infot::ns
const namespacet * ns
Definition: bv_refinement.h:35
message.h
messaget::warning
mstreamt & warning() const
Definition: message.h:404
invalid_command_line_argument_exceptiont
Thrown when users pass incorrect command line arguments, for example passing no files to analysis or ...
Definition: exception_utils.h:50
solver_factoryt::ns
const namespacet & ns
Definition: solver_factory.h:70
solver_factoryt::solvert::decision_procedure
decision_proceduret & decision_procedure() const
Definition: solver_factory.cpp:73
bv_refinementt::configt::refine_arrays
bool refine_arrays
Enable array refinement.
Definition: bv_refinement.h:28
solver_factoryt::get_smt2_solver_type
smt2_dect::solvert get_smt2_solver_type() const
Uses the options to pick an SMT 2.0 solver.
Definition: solver_factory.cpp:159
bv_dimacs.h
validation_modet::INVARIANT
@ INVARIANT
solver_factoryt::get_smt2
std::unique_ptr< solvert > get_smt2(smt2_dect::solvert solver)
Definition: solver_factory.cpp:345