CBMC
external_sat.cpp
Go to the documentation of this file.
1 
6 #include "external_sat.h"
7 
8 #include "dimacs_cnf.h"
9 
10 #include <util/run.h>
11 #include <util/string_utils.h>
12 #include <util/tempfile.h>
13 
14 #include <algorithm>
15 #include <cstdlib>
16 #include <fstream>
17 #include <string>
18 
19 external_satt::external_satt(message_handlert &message_handler, std::string cmd)
20  : cnf_clause_list_assignmentt(message_handler), solver_cmd(std::move(cmd))
21 {
22 }
23 
24 std::string external_satt::solver_text() const
25 {
26  return "External SAT solver";
27 }
28 
30 {
32 }
33 
35 {
37 }
38 
39 void external_satt::write_cnf_file(std::string cnf_file, const bvt &assumptions)
40 {
41  log.status() << "Writing temporary CNF" << messaget::eom;
42  std::ofstream out(cnf_file);
43 
44  // We start counting at 1, thus there is one variable fewer.
45  out << "p cnf " << (no_variables() - 1) << ' '
46  << no_clauses() + assumptions.size() << '\n';
47 
48  // output the problem clauses
49  for(auto &c : clauses)
50  dimacs_cnft::write_dimacs_clause(c, out, false);
51 
52  // output the assumption clauses
53  for(const auto &literal : assumptions)
54  {
55  if(!literal.is_constant())
56  out << literal.dimacs() << " 0\n";
57  }
58 
59  out.close();
60 }
61 
62 std::string external_satt::execute_solver(std::string cnf_file)
63 {
64  log.status() << "Invoking SAT solver" << messaget::eom;
65  std::ostringstream response_ostream;
66  auto cmd_result = run(solver_cmd, {"", cnf_file}, "", response_ostream, "");
67 
68  log.status() << "Solver returned code: " << cmd_result << messaget::eom;
69  return response_ostream.str();
70 }
71 
73 {
74  std::istringstream response_istream(solver_output);
75  std::string line;
77  std::vector<bool> assigned_variables(no_variables(), false);
78  assignment.insert(assignment.begin(), no_variables(), tvt::unknown());
79 
80  while(getline(response_istream, line))
81  {
82  if(line[0] == 's')
83  {
84  auto parts = split_string(line, ' ');
85  if(parts.size() < 2)
86  {
87  log.error() << "external SAT solver has provided an unexpected "
88  "response in results.\nUnexpected response: "
89  << line << messaget::eom;
90  return resultt::P_ERROR;
91  }
92 
93  auto status = parts[1];
94  log.status() << "result:" << status << messaget::eom;
95  if(status == "UNSATISFIABLE")
96  {
98  }
99  if(status == "SATISFIABLE")
100  {
101  result = resultt::P_SATISFIABLE;
102  }
103  if(status == "TIMEOUT")
104  {
105  log.error() << "external SAT solver reports a timeout" << messaget::eom;
106  return resultt::P_ERROR;
107  }
108  }
109 
110  if(line[0] == 'v')
111  {
112  auto assignments = split_string(line, ' ', false, true);
113 
114  // remove the first element which should be 'v' identifying
115  // the line as the satisfying assignments
116  assignments.erase(assignments.begin());
117  auto number_of_variables = no_variables();
118  for(auto &assignment_string : assignments)
119  {
120  try
121  {
122  signed long long as_long = std::stoll(assignment_string);
123  size_t index = std::llabs(as_long);
124 
125  if(index >= number_of_variables)
126  {
127  log.error() << "SAT assignment " << as_long
128  << " out of range of CBMC largest variable of "
129  << (number_of_variables - 1) << messaget::eom;
130  return resultt::P_ERROR;
131  }
132  assignment[index] = tvt(as_long >= 0);
133  assigned_variables[index] = true;
134  }
135  catch(...)
136  {
137  log.error() << "SAT assignment " << assignment_string
138  << " caused an exception while processing"
139  << messaget::eom;
140  return resultt::P_ERROR;
141  }
142  }
143  // Assignments can span multiple lines so returning early isn't an option
144  }
145  }
146 
147  if(result == resultt::P_SATISFIABLE)
148  {
150  log.debug(), [this, &assigned_variables](messaget::mstreamt &mstream) {
151  // We don't need to check zero
152  for(size_t index = 1; index < no_variables(); index++)
153  {
154  // this may happen when a variable does not appear in any clause
155  if(!assigned_variables[index])
156  {
157  mstream << "No assignment was found for literal: " << index
158  << messaget::eom;
159  }
160  }
161  });
162  return resultt::P_SATISFIABLE;
163  }
164 
165  log.error() << "external SAT solver has provided an unexpected response"
166  << messaget::eom;
167  return resultt::P_ERROR;
168 }
169 
171 {
172  // are we assuming 'false'?
173  if(
174  std::find(assumptions.begin(), assumptions.end(), const_literal(false)) !=
175  assumptions.end())
176  {
178  }
179 
180  // create a temporary file
181  temporary_filet cnf_file("external-sat", ".cnf");
182  write_cnf_file(cnf_file(), assumptions);
183  auto output = execute_solver(cnf_file());
184  return parse_result(output);
185 }
size_t no_clauses() const override
virtual size_t no_variables() const override
Definition: cnf.h:42
static void write_dimacs_clause(const bvt &, std::ostream &, bool break_lines)
Definition: dimacs_cnf.cpp:53
resultt do_prop_solve(const bvt &assumptions) override
std::string execute_solver(std::string)
external_satt(message_handlert &message_handler, std::string cmd)
std::string solver_cmd
Definition: external_sat.h:31
std::string solver_text() const override
void set_assignment(literalt, bool) override
void write_cnf_file(std::string, const bvt &)
bool is_in_conflict(literalt) const override
Returns true if an assumption is in the final conflict.
resultt parse_result(std::string)
mstreamt & error() const
Definition: message.h:399
mstreamt & status() const
Definition: message.h:414
void conditional_output(mstreamt &mstream, const std::function< void(mstreamt &)> &output_generator) const
Generate output to message_stream using output_generator if the configured verbosity is at least as h...
Definition: message.cpp:139
mstreamt & debug() const
Definition: message.h:429
static eomt eom
Definition: message.h:297
resultt
Definition: prop.h:101
messaget log
Definition: prop.h:134
Definition: threeval.h:20
static tvt unknown()
Definition: threeval.h:33
Allows calling an external SAT solver to allow faster integration of newer SAT solvers.
std::vector< literalt > bvt
Definition: literal.h:201
literalt const_literal(bool value)
Definition: literal.h:188
double log(double x)
Definition: math.c:2776
int run(const std::string &what, const std::vector< std::string > &argv)
Definition: run.cpp:48
#define UNIMPLEMENTED
Definition: invariant.h:558
long long int llabs(long long int i)
Definition: stdlib.c:45
void split_string(const std::string &s, char delim, std::vector< std::string > &result, bool strip, bool remove_empty)