7#include <boost/algorithm/string.hpp>
27 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"functionality not (yet) implemented");
31 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"functionality not (yet) implemented");
35 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"functionality not (yet) implemented");
39 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"functionality not (yet) implemented");
43 :
SmtSolver(manager), isCommandFileOpen(false), expressionAdapter(nullptr), useCarlExpressions(useCarlExpressions) {
44 processIdOfSolver = 0;
45 this->expressionAdapter =
51 writeCommand(
"( exit )",
54 if (processIdOfSolver != 0) {
58 kill(processIdOfSolver, SIGTERM);
59 waitpid(processIdOfSolver,
nullptr, 0);
64 expressionAdapter->increaseScope();
65 writeCommand(
"( push 1 ) ",
true);
69 expressionAdapter->decreaseScope();
70 writeCommand(
"( pop 1 ) ",
true);
74 expressionAdapter->decreaseScope(n);
75 writeCommand(
"( pop " + std::to_string(n) +
" ) ",
true);
79 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"functionality not (yet) implemented");
83 STORM_LOG_THROW(!useCarlExpressions, storm::exceptions::IllegalFunctionCallException,
"This solver was initialized without allowing carl expressions");
84 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"functionality not (yet) implemented");
88 STORM_LOG_THROW(useCarlExpressions, storm::exceptions::IllegalFunctionCallException,
"This solver was initialized without allowing carl expressions");
90 std::set<storm::RationalFunctionVariable> variables;
91 leftHandSide.gatherVariables(variables);
92 rightHandSide.gatherVariables(variables);
93 std::vector<std::string>
const varDeclarations = expressionAdapter->checkForUndeclaredVariables(variables);
94 for (
auto declaration : varDeclarations) {
95 writeCommand(declaration,
true);
97 writeCommand(
"( assert " + expressionAdapter->translateExpression(leftHandSide, relation, rightHandSide) +
" )",
true);
101 STORM_LOG_THROW((variable.type() == carl::VariableType::VT_BOOL), storm::exceptions::IllegalArgumentException,
102 "Tried to add a constraint that consists of a non-boolean variable.");
103 std::set<storm::RationalFunctionVariable> variableSet;
104 variableSet.insert(variable);
105 std::vector<std::string>
const varDeclarations = expressionAdapter->checkForUndeclaredVariables(variableSet);
106 for (
auto declaration : varDeclarations) {
107 writeCommand(declaration,
true);
109 std::string varName = carl::VariablePool::getInstance().getName(variable, this->useReadableVarNames);
111 writeCommand(
"( assert " + varName +
" )",
true);
113 writeCommand(
"( assert (not " + varName +
") )",
true);
118 writeCommand(
"( check-sat )",
false);
120 if (processIdOfSolver != 0) {
121 auto solverOutput = readSolverOutput();
123 solverOutput.size() == 1, storm::exceptions::UnexpectedException,
124 "expected a single line of output after smt2 command ( check-sat ). Got " + std::to_string(solverOutput.size()) +
" lines of output instead.");
125 solverOutput[0].erase(std::remove_if(solverOutput[0].begin(), solverOutput[0].end(), ::isspace), solverOutput[0].end());
126 if (solverOutput[0] ==
"sat")
128 if (solverOutput[0] ==
"unsat")
130 if (solverOutput[0] ==
"unknown")
133 STORM_LOG_DEBUG(
"unexpected solver output: " << solverOutput[0] <<
". Returning result 'unknown'");
136 STORM_LOG_WARN(
"No SMT-LIBv2 Solver Command specified, which means that no actual SMT solving is done... Assume that the result is \"unknown\"");
142 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"functionality not (yet) implemented");
146 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"functionality not (yet) implemented");
149void SmtlibSmtSolver::init() {
150 if (storm::settings::getModule<storm::settings::modules::Smt2SmtSolverSettings>().isSolverCommandSet()) {
151 signal(SIGPIPE, SIG_IGN);
152 this->needsRestart =
false;
156 const std::string cmdString = storm::settings::getModule<storm::settings::modules::Smt2SmtSolverSettings>().getSolverCommand();
157 std::vector<std::string> solverCommandVec;
158 boost::split(solverCommandVec, cmdString, boost::is_any_of(
"\t "));
159 char** solverArgs =
new char*[solverCommandVec.size() + 1];
160 std::string solverPath = solverCommandVec[0].substr(0, cmdString.rfind(
'/') + 1);
161 solverArgs[0] =
const_cast<char*
>(solverPath.c_str());
162 for (uint_fast64_t argumentIndex = 1; argumentIndex < solverCommandVec.size(); ++argumentIndex) {
163 solverArgs[argumentIndex] =
const_cast<char*
>(solverCommandVec[argumentIndex].c_str());
165 solverArgs[solverCommandVec.size()] = NULL;
172 STORM_LOG_THROW(pipe(pipeIn) == 0 && pipe(pipeOut) == 0, storm::exceptions::UnexpectedException,
"Could not open pipe to new process");
176 STORM_LOG_THROW(pid >= 0, storm::exceptions::UnexpectedException,
"Could not start new process for the smt solver");
180 dup2(pipeIn[READ], STDIN_FILENO);
181 dup2(pipeOut[WRITE], STDOUT_FILENO);
182 dup2(pipeOut[WRITE], STDERR_FILENO);
185 close(pipeIn[WRITE]);
186 close(pipeOut[READ]);
187 close(pipeOut[WRITE]);
189 execv(solverCommandVec[0].c_str(), solverArgs);
191 STORM_LOG_THROW(
false, storm::exceptions::UnexpectedException,
"Could not execute the solver correctly");
194 toSolver = pipeIn[WRITE];
195 fromSolver = pipeOut[READ];
196 close(pipeOut[WRITE]);
198 processIdOfSolver = pid;
201 STORM_LOG_WARN(
"No SMT-LIBv2 Solver Command specified, which means that no actual SMT solving can be done");
204 if (storm::settings::getModule<storm::settings::modules::Smt2SmtSolverSettings>().isExportSmtLibScriptSet()) {
205 STORM_LOG_DEBUG(
"The SMT-LIBv2 commands are exportet to the given file");
206 storm::io::openFile(storm::settings::getModule<storm::settings::modules::Smt2SmtSolverSettings>().getExportSmtLibScriptPath(), commandFile);
207 isCommandFileOpen =
true;
212 writeCommand(
"( set-option :print-success true )",
true);
213 writeCommand(
"( set-logic QF_NRA )",
true);
218 return this->needsRestart;
221void SmtlibSmtSolver::writeCommand(std::string smt2Command,
bool expectSuccess) {
222 if (isCommandFileOpen) {
223 commandFile << smt2Command <<
'\n';
226 if (processIdOfSolver != 0) {
227 if (write(toSolver, (smt2Command +
"\n").c_str(), smt2Command.length() + 1) < 0) {
228 STORM_LOG_DEBUG(
"Was not able to write " << smt2Command <<
"to the solver.");
231 auto output = readSolverOutput();
232 STORM_LOG_THROW(output.size() == 1, storm::exceptions::UnexpectedException,
233 "expected a single success response after smt2 command " + smt2Command +
". Got " + std::to_string(output.size()) +
234 " lines of output instead.");
235 output[0].erase(std::remove_if(output[0].begin(), output[0].end(), ::isspace), output[0].end());
236 STORM_LOG_THROW(output[0] ==
"success", storm::exceptions::UnexpectedException,
237 "expected <<success>> response after smt2 command " + smt2Command +
". Got <<" + output[0] +
">> instead");
242std::vector<std::string> SmtlibSmtSolver::readSolverOutput(
bool waitForOutput) {
243 if (processIdOfSolver == 0) {
244 STORM_LOG_DEBUG(
"failed to read solver output as the solver is not running");
245 return std::vector<std::string>();
250 }
else if (ioctl(fromSolver, FIONREAD, &bytesReadable) < 0) {
252 return std::vector<std::string>();
254 std::string solverOutput =
"";
255 const ssize_t MAX_CHUNK_SIZE = 256;
256 char chunk[MAX_CHUNK_SIZE];
257 while (bytesReadable > 0) {
258 ssize_t chunkSize = read(fromSolver, chunk, MAX_CHUNK_SIZE);
259 STORM_LOG_THROW(chunkSize >= 0, storm::exceptions::UnexpectedException,
"failed to read solver output");
260 solverOutput += std::string(chunk, chunkSize);
261 if (ioctl(fromSolver, FIONREAD, &bytesReadable) < 0) {
263 return std::vector<std::string>();
265 if (bytesReadable == 0 && solverOutput.back() !=
'\n') {
269 <<
"' did not end with newline symbol (\\n). Since we assume that this should be the case, we will wait for more output from the solver");
272 if (bytesReadable > 0) {
273 pid_t w = waitpid(processIdOfSolver,
nullptr, WNOHANG);
275 STORM_LOG_WARN_COND(w > 0,
"Error when checking whether the solver is still running. Will assume that solver has terminated.");
276 STORM_LOG_WARN(
"The solver exited unexpectedly when reading output: " << solverOutput);
277 solverOutput +=
"terminated";
278 this->needsRestart =
true;
279 this->processIdOfSolver = 0;
284 checkForErrorMessage(solverOutput);
285 std::vector<std::string> solverOutputAsVector;
286 if (solverOutput.length() > 0) {
287 solverOutput = solverOutput.substr(0, solverOutput.length() - 1);
288 boost::split(solverOutputAsVector, solverOutput, boost::is_any_of(
"\n"));
291 return solverOutputAsVector;
294void SmtlibSmtSolver::checkForErrorMessage(
const std::string message) {
295 size_t errorOccurrance = message.find(
"error");
297 if (message.find(
"timeout") != std::string::npos) {
298 STORM_LOG_INFO(
"SMT solver answered: '" << message <<
"' and I am interpreting this as timeout ");
299 this->needsRestart =
true;
300 this->processIdOfSolver = 0;
301 }
else if (message.find(
"memory") != std::string::npos) {
302 STORM_LOG_INFO(
"SMT solver answered: '" << message <<
"' and I am interpreting this as out of memory ");
303 this->needsRestart =
true;
304 this->processIdOfSolver = 0;
305 }
else if (errorOccurrance != std::string::npos) {
306 this->needsRestart =
true;
307 std::string errorMsg =
"An error was detected while checking the solver output. ";
308 STORM_LOG_DEBUG(
"Detected an error message in the solver response:\n" + message);
309 size_t firstQuoteSign = message.find(
'\"', errorOccurrance);
310 if (firstQuoteSign != std::string::npos && message.find(
"\\\"", firstQuoteSign - 1) != firstQuoteSign - 1) {
311 size_t secondQuoteSign = message.find(
'\"', firstQuoteSign + 1);
312 while (secondQuoteSign != std::string::npos && message.find(
"\\\"", secondQuoteSign - 1) == secondQuoteSign - 1) {
313 secondQuoteSign = message.find(
'\"', secondQuoteSign + 1);
315 if (secondQuoteSign != std::string::npos) {
316 errorMsg +=
"The error message was: <<" + message.substr(errorOccurrance, secondQuoteSign - errorOccurrance + 1) +
">>.";
317 STORM_LOG_THROW(
false, storm::exceptions::UnexpectedException, errorMsg);
321 errorMsg +=
"The error message could not be parsed correctly. Snippet:\n" + message.substr(errorOccurrance, 200);
322 STORM_LOG_THROW(
false, storm::exceptions::UnexpectedException, errorMsg);
This class is responsible for managing a set of typed variables and all expressions using these varia...
The base class for all model references.
An interface that captures the functionality of an SMT solver.
storm::expressions::ExpressionManager const & getManager() const
Retrieves the expression manager associated with the solver.
CheckResult
possible check results
virtual bool getBooleanValue(storm::expressions::Variable const &variable) const override
SmtlibModelReference(storm::expressions::ExpressionManager const &manager)
virtual std::string toString() const override
virtual int_fast64_t getIntegerValue(storm::expressions::Variable const &variable) const override
virtual double getRationalValue(storm::expressions::Variable const &variable) const override
virtual ~SmtlibSmtSolver()
virtual CheckResult check() override
Checks whether the conjunction of assertions that are currently on the solver's stack is satisfiable.
virtual void push() override
Pushes a backtracking point on the solver's stack.
virtual void reset() override
Removes all assertions from the solver's stack.
virtual void add(storm::expressions::Expression const &assertion) override
Adds an assertion to the solver's stack.
virtual CheckResult checkWithAssumptions(std::set< storm::expressions::Expression > const &assumptions) override
Checks whether the conjunction of assertions that are currently on the solver's stack together with t...
bool isNeedsRestart() const
SmtlibSmtSolver(storm::expressions::ExpressionManager &manager, bool useCarlExpressions=false)
Creates a new solver with the given manager.
virtual void pop() override
Pops a backtracking point from the solver's stack.
#define STORM_LOG_INFO(message)
#define STORM_LOG_WARN(message)
#define STORM_LOG_DEBUG(message)
#define STORM_LOG_ERROR(message)
#define STORM_LOG_WARN_COND(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
void openFile(std::string const &filepath, std::ofstream &filestream, bool append=false, bool silent=false)
Open the given file for writing.
carl::Relation CompareRelation
carl::Variable RationalFunctionVariable