Adds smt2 parsing, printing and API support for get-difficulty. Adds unit tests.
CVC5_API_TRY_CATCH_END;
}
+std::map<Term, Term> Solver::getDifficulty() const
+{
+ CVC5_API_TRY_CATCH_BEGIN;
+ NodeManagerScope scope(getNodeManager());
+ CVC5_API_RECOVERABLE_CHECK(d_smtEngine->getSmtMode() == SmtMode::UNSAT
+ || d_smtEngine->getSmtMode() == SmtMode::SAT
+ || d_smtEngine->getSmtMode()
+ == SmtMode::SAT_UNKNOWN)
+ << "Cannot get difficulty unless after a UNSAT, SAT or unknown response.";
+ //////// all checks before this line
+ std::map<Term, Term> res;
+ std::map<Node, Node> dmap;
+ d_smtEngine->getDifficultyMap(dmap);
+ for (const std::pair<const Node, Node>& d : dmap)
+ {
+ res[Term(this, d.first)] = Term(this, d.second);
+ }
+ return res;
+ ////////
+ CVC5_API_TRY_CATCH_END;
+}
+
std::string Solver::getProof(void) const
{
CVC5_API_TRY_CATCH_BEGIN;
NodeManagerScope scope(getNodeManager());
CVC5_API_CHECK(d_smtEngine->getOptions().smt.produceProofs)
- << "Cannot get proof explicitly enabled (try --prooduce-proofs)";
+ << "Cannot get proof explicitly enabled (try --produce-proofs)";
CVC5_API_RECOVERABLE_CHECK(d_smtEngine->getSmtMode() == SmtMode::UNSAT)
<< "Cannot get proof unless in unsat mode.";
return d_smtEngine->getProof();
*/
std::vector<Term> getUnsatCore() const;
+ /**
+ * Get a difficulty estimate for an asserted formula. This method is
+ * intended to be called immediately after any response to a checkSat.
+ *
+ * @return a map from (a subset of) the input assertions to a real value that
+ * is an estimate of how difficult each assertion was to solve. Unmentioned
+ * assertions can be assumed to have zero difficulty.
+ */
+ std::map<Term, Term> getDifficulty() const;
+
/**
* Get the refutation proof
* SMT-LIB:
getterCommands.emplace_back(new GetUnsatCoreCommand());
}
+ if (d_solver->getOptionInfo("dump-difficulty").boolValue()
+ && (isResultUnsat || isResultSat || res.isSatUnknown()))
+ {
+ getterCommands.emplace_back(new GetDifficultyCommand());
+ }
+
if (!getterCommands.empty()) {
// set no time limit during dumping if applicable
if (d_solver->getOptionInfo("force-no-limit-cpu-while-dump").boolValue())
default = "false"
help = "dump the full unsat core, including unlabeled assertions"
+[[option]]
+ name = "dumpDifficulty"
+ category = "regular"
+ long = "dump-difficulty"
+ type = "bool"
+ default = "false"
+ help = "dump the difficulty measure after every response to check-sat"
+
[[option]]
name = "forceNoLimitCpuWhileDump"
category = "regular"
| /* get-unsat-core */
GET_UNSAT_CORE_TOK { PARSER_STATE->checkThatLogicIsSet(); }
{ cmd->reset(new GetUnsatCoreCommand); }
+ | /* get-difficulty */
+ GET_DIFFICULTY_TOK { PARSER_STATE->checkThatLogicIsSet(); }
+ { cmd->reset(new GetDifficultyCommand); }
| /* push */
PUSH_TOK { PARSER_STATE->checkThatLogicIsSet(); }
{ if( PARSER_STATE->sygus() ){
| DEFINE_FUN_TOK | DEFINE_FUN_REC_TOK | DEFINE_FUNS_REC_TOK
| DEFINE_SORT_TOK | GET_VALUE_TOK | GET_ASSIGNMENT_TOK
| GET_ASSERTIONS_TOK | GET_PROOF_TOK | GET_UNSAT_ASSUMPTIONS_TOK
- | GET_UNSAT_CORE_TOK | EXIT_TOK
+ | GET_UNSAT_CORE_TOK | GET_DIFFICULTY_TOK | EXIT_TOK
| RESET_TOK | RESET_ASSERTIONS_TOK | SET_LOGIC_TOK | SET_INFO_TOK
| GET_INFO_TOK | SET_OPTION_TOK | GET_OPTION_TOK | PUSH_TOK | POP_TOK
| DECLARE_DATATYPES_TOK | GET_MODEL_TOK | ECHO_TOK | SIMPLIFY_TOK)
GET_PROOF_TOK : 'get-proof';
GET_UNSAT_ASSUMPTIONS_TOK : 'get-unsat-assumptions';
GET_UNSAT_CORE_TOK : 'get-unsat-core';
+GET_DIFFICULTY_TOK : 'get-difficulty';
EXIT_TOK : 'exit';
RESET_TOK : 'reset';
RESET_ASSERTIONS_TOK : 'reset-assertions';
printUnknownCommand(out, "get-unsat-core");
}
+void Printer::toStreamCmdGetDifficulty(std::ostream& out) const
+{
+ printUnknownCommand(out, "get-difficulty");
+}
+
void Printer::toStreamCmdGetAssertions(std::ostream& out) const
{
printUnknownCommand(out, "get-assertions");
/** Print get-unsat-core command */
virtual void toStreamCmdGetUnsatCore(std::ostream& out) const;
+ /** Print get-difficulty command */
+ virtual void toStreamCmdGetDifficulty(std::ostream& out) const;
+
/** Print get-assertions command */
virtual void toStreamCmdGetAssertions(std::ostream& out) const;
out << "(get-unsat-core)" << std::endl;
}
+void Smt2Printer::toStreamCmdGetDifficulty(std::ostream& out) const
+{
+ out << "(get-difficulty)" << std::endl;
+}
+
void Smt2Printer::toStreamCmdSetBenchmarkStatus(std::ostream& out,
Result::Sat status) const
{
/** Print get-unsat-core command */
void toStreamCmdGetUnsatCore(std::ostream& out) const override;
+ /** Print get-difficulty command */
+ void toStreamCmdGetDifficulty(std::ostream& out) const override;
+
/** Print get-assertions command */
void toStreamCmdGetAssertions(std::ostream& out) const override;
bool Solver::needProof() const
{
return isProofEnabled()
- && options::unsatCoresMode() != options::UnsatCoresMode::ASSUMPTIONS;
+ && options::unsatCoresMode() != options::UnsatCoresMode::ASSUMPTIONS
+ && options::unsatCoresMode() != options::UnsatCoresMode::PP_ONLY;
}
} // namespace Minisat
Printer::getPrinter(language)->toStreamCmdGetUnsatCore(out);
}
+/* -------------------------------------------------------------------------- */
+/* class GetDifficultyCommand */
+/* -------------------------------------------------------------------------- */
+
+GetDifficultyCommand::GetDifficultyCommand() : d_sm(nullptr) {}
+void GetDifficultyCommand::invoke(api::Solver* solver, SymbolManager* sm)
+{
+ try
+ {
+ d_sm = sm;
+ d_result = solver->getDifficulty();
+
+ d_commandStatus = CommandSuccess::instance();
+ }
+ catch (api::CVC5ApiRecoverableException& e)
+ {
+ d_commandStatus = new CommandRecoverableFailure(e.what());
+ }
+ catch (exception& e)
+ {
+ d_commandStatus = new CommandFailure(e.what());
+ }
+}
+
+void GetDifficultyCommand::printResult(std::ostream& out,
+ uint32_t verbosity) const
+{
+ if (!ok())
+ {
+ this->Command::printResult(out, verbosity);
+ }
+ else
+ {
+ out << "(" << std::endl;
+ for (const std::pair<const api::Term, api::Term>& d : d_result)
+ {
+ out << "(";
+ // use name if it has one
+ std::string name;
+ if (d_sm->getExpressionName(d.first, name, true))
+ {
+ out << name;
+ }
+ else
+ {
+ out << d.first;
+ }
+ out << " " << d.second << ")" << std::endl;
+ }
+ out << ")" << std::endl;
+ }
+}
+
+const std::map<api::Term, api::Term>& GetDifficultyCommand::getDifficultyMap()
+ const
+{
+ return d_result;
+}
+
+Command* GetDifficultyCommand::clone() const
+{
+ GetDifficultyCommand* c = new GetDifficultyCommand;
+ c->d_sm = d_sm;
+ c->d_result = d_result;
+ return c;
+}
+
+std::string GetDifficultyCommand::getCommandName() const
+{
+ return "get-difficulty";
+}
+
+void GetDifficultyCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ Language language) const
+{
+ Printer::getPrinter(language)->toStreamCmdGetDifficulty(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class GetAssertionsCommand */
/* -------------------------------------------------------------------------- */
std::vector<api::Term> d_result;
}; /* class GetUnsatCoreCommand */
+class CVC5_EXPORT GetDifficultyCommand : public Command
+{
+ public:
+ GetDifficultyCommand();
+ const std::map<api::Term, api::Term>& getDifficultyMap() const;
+
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
+ void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
+
+ Command* clone() const override;
+ std::string getCommandName() const override;
+ void toStream(std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ Language language = Language::LANG_AUTO) const override;
+
+ protected:
+ /** The symbol manager we were invoked with */
+ SymbolManager* d_sm;
+ /** the result of the get difficulty call */
+ std::map<api::Term, api::Term> d_result;
+};
+
class CVC5_EXPORT GetAssertionsCommand : public Command
{
protected:
{
opts.driver.dumpUnsatCores = true;
}
+ if (opts.driver.dumpDifficulty)
+ {
+ opts.smt.produceDifficulty = true;
+ }
if (opts.smt.produceDifficulty)
{
if (opts.smt.unsatCoresMode == options::UnsatCoresMode::OFF)
return getAssertionsInternal();
}
+void SmtEngine::getDifficultyMap(std::map<Node, Node>& dmap)
+{
+ Trace("smt") << "SMT getDifficultyMap()\n";
+ SmtScope smts(this);
+ finishInit();
+ if (Dump.isOn("benchmark"))
+ {
+ getPrinter().toStreamCmdGetDifficulty(d_env->getDumpOut());
+ }
+ if (!d_env->getOptions().smt.produceDifficulty)
+ {
+ throw ModalException(
+ "Cannot get difficulty when difficulty option is off.");
+ }
+ // the prop engine has the proof of false
+ Assert(d_pfManager);
+ // get difficulty map from theory engine first
+ TheoryEngine* te = getTheoryEngine();
+ te->getDifficultyMap(dmap);
+ // then ask proof manager to translate dmap in terms of the input
+ d_pfManager->translateDifficultyMap(dmap, *d_asserts);
+}
+
void SmtEngine::push()
{
SmtScope smts(this);
*/
std::vector<Node> getAssertions();
+ /**
+ * Get difficulty map, which populates dmap, mapping input assertions
+ * to a value that estimates their difficulty for solving the current problem.
+ */
+ void getDifficultyMap(std::map<Node, Node>& dmap);
+
/**
* Push a user-level context.
* throw@ ModalException, LogicException, UnsafeInterruptException
ASSERT_NO_THROW(d_solver.getProof());
}
+TEST_F(TestApiBlackSolver, getDifficulty)
+{
+ d_solver.setOption("produce-difficulty", "true");
+ // cannot ask before a check sat
+ ASSERT_THROW(d_solver.getDifficulty(), CVC5ApiException);
+ d_solver.checkSat();
+ ASSERT_NO_THROW(d_solver.getDifficulty());
+}
+
+TEST_F(TestApiBlackSolver, getDifficulty2)
+{
+ d_solver.checkSat();
+ // option is not set
+ ASSERT_THROW(d_solver.getDifficulty(), CVC5ApiException);
+}
+
+TEST_F(TestApiBlackSolver, getDifficulty3)
+{
+ d_solver.setOption("produce-difficulty", "true");
+ Sort intSort = d_solver.getIntegerSort();
+ Term x = d_solver.mkConst(intSort, "x");
+ Term zero = d_solver.mkInteger(0);
+ Term ten = d_solver.mkInteger(10);
+ Term f0 = d_solver.mkTerm(GEQ, x, ten);
+ Term f1 = d_solver.mkTerm(GEQ, zero, x);
+ d_solver.checkSat();
+ std::map<Term, Term> dmap;
+ ASSERT_NO_THROW(dmap = d_solver.getDifficulty());
+ // difficulty should map assertions to integer values
+ for (const std::pair<Term, Term>& t : dmap)
+ {
+ ASSERT_TRUE(t.first == f0 || t.first == f1);
+ ASSERT_TRUE(t.second.getKind() == CONST_RATIONAL);
+ }
+}
+
TEST_F(TestApiBlackSolver, getValue1)
{
d_solver.setOption("produce-models", "false");