summaryrefslogtreecommitdiff
path: root/src/smt/smt_engine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/smt/smt_engine.cpp')
-rw-r--r--src/smt/smt_engine.cpp804
1 files changed, 530 insertions, 274 deletions
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index d035f88c1..305c36d13 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -31,6 +31,7 @@
#include "base/configuration.h"
#include "base/configuration_private.h"
+#include "base/cvc4_check.h"
#include "base/exception.h"
#include "base/listener.h"
#include "base/modal_exception.h"
@@ -67,8 +68,8 @@
#include "options/sep_options.h"
#include "options/set_language.h"
#include "options/smt_options.h"
+#include "options/strings_modes.h"
#include "options/strings_options.h"
-#include "options/strings_process_loop_mode.h"
#include "options/theory_options.h"
#include "options/uf_options.h"
#include "preprocessing/preprocessing_pass.h"
@@ -84,6 +85,7 @@
#include "smt/command_list.h"
#include "smt/logic_request.h"
#include "smt/managed_ostreams.h"
+#include "smt/model_blocker.h"
#include "smt/model_core_builder.h"
#include "smt/smt_engine_scope.h"
#include "smt/term_formula_removal.h"
@@ -97,8 +99,10 @@
#include "theory/quantifiers/fun_def_process.h"
#include "theory/quantifiers/quantifiers_rewriter.h"
#include "theory/quantifiers/single_inv_partition.h"
+#include "theory/quantifiers/sygus/sygus_abduct.h"
#include "theory/quantifiers/sygus/synth_engine.h"
#include "theory/quantifiers/term_util.h"
+#include "theory/quantifiers_engine.h"
#include "theory/rewriter.h"
#include "theory/sort_inference.h"
#include "theory/strings/theory_strings.h"
@@ -284,18 +288,6 @@ class HardResourceOutListener : public Listener {
SmtEngine* d_smt;
}; /* class HardResourceOutListener */
-class SetLogicListener : public Listener {
- public:
- SetLogicListener(SmtEngine& smt) : d_smt(&smt) {}
- void notify() override
- {
- LogicInfo inOptions(options::forceLogicString());
- d_smt->setLogic(inOptions);
- }
- private:
- SmtEngine* d_smt;
-}; /* class SetLogicListener */
-
class BeforeSearchListener : public Listener {
public:
BeforeSearchListener(SmtEngine& smt) : d_smt(&smt) {}
@@ -451,7 +443,6 @@ class SmtEnginePrivate : public NodeManagerListener {
* This list contains:
* softResourceOut
* hardResourceOut
- * setForceLogic
* beforeSearchListener
* UseTheoryListListener
*
@@ -526,15 +517,10 @@ class SmtEnginePrivate : public NodeManagerListener {
std::vector<Node> d_sygusConstraints;
/** functions-to-synthesize */
std::vector<Node> d_sygusFunSymbols;
- /** maps functions-to-synthesize to their respective input variables lists */
- std::map<Node, std::vector<Node>> d_sygusFunVars;
- /** maps functions-to-synthesize to their respective syntactic restrictions
- *
- * If function has syntactic restrictions, these are encoded as a SyGuS
- * datatype type
+ /**
+ * Whether we need to reconstruct the sygus conjecture.
*/
- std::map<Node, TypeNode> d_sygusFunSyntax;
-
+ CDO<bool> d_sygusConjectureStale;
/*------------------- end of sygus utils ------------------*/
private:
@@ -584,7 +570,8 @@ class SmtEnginePrivate : public NodeManagerListener {
d_simplifyAssertionsDepth(0),
// d_needsExpandDefs(true), //TODO?
d_exprNames(smt.d_userContext),
- d_iteRemover(smt.d_userContext)
+ d_iteRemover(smt.d_userContext),
+ d_sygusConjectureStale(smt.d_userContext, true)
{
d_smt.d_nodeManager->subscribeEvents(this);
d_true = NodeManager::currentNM()->mkConst(true);
@@ -599,9 +586,6 @@ class SmtEnginePrivate : public NodeManagerListener {
try
{
Options& nodeManagerOptions = NodeManager::currentNM()->getOptions();
- d_listenerRegistrations->add(
- nodeManagerOptions.registerForceLogicListener(
- new SetLogicListener(d_smt), true));
// Multiple options reuse BeforeSearchListener so registration requires an
// extra bit of care.
@@ -861,8 +845,8 @@ class SmtEnginePrivate : public NodeManagerListener {
SmtEngine::SmtEngine(ExprManager* em)
: d_context(new Context()),
- d_userLevels(),
d_userContext(new UserContext()),
+ d_userLevels(),
d_exprManager(em),
d_nodeManager(d_exprManager->getNodeManager()),
d_decisionEngine(NULL),
@@ -882,12 +866,13 @@ SmtEngine::SmtEngine(ExprManager* em)
d_isInternalSubsolver(false),
d_pendingPops(0),
d_fullyInited(false),
- d_problemExtended(false),
d_queryMade(false),
d_needPostsolve(false),
d_earlyTheoryPP(true),
d_globalNegation(false),
d_status(),
+ d_expectedStatus(),
+ d_smtMode(SMT_MODE_START),
d_replayStream(NULL),
d_private(NULL),
d_statisticsRegistry(NULL),
@@ -1172,10 +1157,12 @@ void SmtEngine::setDefaults() {
// option if we are sygus, since we assume SMT LIB 2.6 semantics for sygus.
options::bitvectorDivByZeroConst.set(
language::isInputLang_smt2_6(options::inputLanguage())
- || options::inputLanguage() == language::input::LANG_SYGUS);
+ || options::inputLanguage() == language::input::LANG_SYGUS
+ || options::inputLanguage() == language::input::LANG_SYGUS_V2);
}
bool is_sygus = false;
- if (options::inputLanguage() == language::input::LANG_SYGUS)
+ if (options::inputLanguage() == language::input::LANG_SYGUS
+ || options::inputLanguage() == language::input::LANG_SYGUS_V2)
{
is_sygus = true;
}
@@ -1207,9 +1194,8 @@ void SmtEngine::setDefaults() {
}
}
- if(options::forceLogicString.wasSetByUser()) {
- d_logic = LogicInfo(options::forceLogicString());
- }else if (options::solveIntAsBV() > 0) {
+ if (options::solveIntAsBV() > 0)
+ {
if (!(d_logic <= LogicInfo("QF_NIA")))
{
throw OptionException(
@@ -1217,76 +1203,76 @@ void SmtEngine::setDefaults() {
"QF_LIA, QF_IDL)");
}
d_logic = LogicInfo("QF_BV");
- }else if (d_logic.getLogicString() == "QF_NRA" && options::solveRealAsInt()) {
+ }
+ else if (d_logic.getLogicString() == "QF_NRA" && options::solveRealAsInt())
+ {
d_logic = LogicInfo("QF_NIA");
- } else if ((d_logic.getLogicString() == "QF_UFBV" ||
- d_logic.getLogicString() == "QF_ABV") &&
- options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
+ }
+ else if ((d_logic.getLogicString() == "QF_UFBV"
+ || d_logic.getLogicString() == "QF_ABV")
+ && options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER)
+ {
d_logic = LogicInfo("QF_BV");
}
- // set strings-exp
- /* - disabled for 1.4 release [MGD 2014.06.25]
- if(!d_logic.hasEverything() && d_logic.isTheoryEnabled(THEORY_STRINGS) ) {
- if(! options::stringExp.wasSetByUser()) {
- options::stringExp.set( true );
- Trace("smt") << "turning on strings-exp, for the theory of strings" << std::endl;
- }
- }
- */
- // for strings
- if(options::stringExp()) {
- if( !d_logic.isQuantified() ) {
+ // set default options associated with strings-exp
+ if (options::stringExp())
+ {
+ // We require quantifiers since extended functions reduce using them
+ if (!d_logic.isQuantified())
+ {
d_logic = d_logic.getUnlockedCopy();
d_logic.enableQuantifiers();
d_logic.lock();
Trace("smt") << "turning on quantifier logic, for strings-exp"
<< std::endl;
}
- if(! options::fmfBound.wasSetByUser()) {
+ // We require bounded quantifier handling.
+ if (!options::fmfBound.wasSetByUser())
+ {
options::fmfBound.set( true );
Trace("smt") << "turning on fmf-bound-int, for strings-exp" << std::endl;
}
- if(! options::fmfInstEngine.wasSetByUser()) {
- options::fmfInstEngine.set( true );
- Trace("smt") << "turning on fmf-inst-engine, for strings-exp" << std::endl;
+ // Turn off E-matching, since some bounded quantifiers introduced by strings
+ // (e.g. for replaceall) admit matching loops.
+ if (!options::eMatching.wasSetByUser())
+ {
+ options::eMatching.set(false);
+ Trace("smt") << "turning off E-matching, for strings-exp" << std::endl;
}
- /*
- if(! options::rewriteDivk.wasSetByUser()) {
- options::rewriteDivk.set( true );
- Trace("smt") << "turning on rewrite-divk, for strings-exp" << std::endl;
- }*/
- /*
- if(! options::stringFMF.wasSetByUser()) {
- options::stringFMF.set( true );
- Trace("smt") << "turning on strings-fmf, for strings-exp" << std::endl;
+ // Do not eliminate extended arithmetic symbols from quantified formulas,
+ // since some strategies, e.g. --re-elim-agg, introduce them.
+ if (!options::elimExtArithQuant.wasSetByUser())
+ {
+ options::elimExtArithQuant.set(false);
+ Trace("smt") << "turning off elim-ext-arith-quant, for strings-exp"
+ << std::endl;
}
- */
}
// sygus inference may require datatypes
if (!d_isInternalSubsolver)
{
- if (options::sygusInference() || options::sygusRewSynthInput()
- || options::sygusAbduct())
+ if (options::produceAbducts() || options::sygusInference()
+ || options::sygusRewSynthInput())
{
- d_logic = d_logic.getUnlockedCopy();
- // sygus requires arithmetic, datatypes and quantifiers
- d_logic.enableTheory(THEORY_ARITH);
- d_logic.enableTheory(THEORY_DATATYPES);
- d_logic.enableTheory(THEORY_QUANTIFIERS);
- d_logic.lock();
// since we are trying to recast as sygus, we assume the input is sygus
is_sygus = true;
+ // we change the logic to incorporate sygus immediately
+ d_logic = d_logic.getUnlockedCopy();
+ d_logic.enableSygus();
+ d_logic.lock();
}
}
if ((options::checkModels() || options::checkSynthSol()
- || options::modelCoresMode() != MODEL_CORES_NONE)
+ || options::produceAbducts()
+ || options::modelCoresMode() != MODEL_CORES_NONE
+ || options::blockModelsMode() != BLOCK_MODELS_NONE)
&& !options::produceAssertions())
{
Notice() << "SmtEngine: turning on produce-assertions to support "
- << "check-models, check-synth-sol or produce-model-cores." << endl;
+ << "option requiring assertions." << endl;
setOption("produce-assertions", SExpr("true"));
}
@@ -1327,14 +1313,6 @@ void SmtEngine::setDefaults() {
options::unconstrainedSimp.set(uncSimp);
}
}
- if (!options::proof())
- {
- // minimizing solutions from single invocation requires proofs
- if (options::cegqiSolMinCore() && options::cegqiSolMinCore.wasSetByUser())
- {
- throw OptionException("cegqi-si-sol-min-core requires --proof");
- }
- }
// Disable options incompatible with unsat cores and proofs or output an
// error if enabled explicitly
@@ -1810,8 +1788,12 @@ void SmtEngine::setDefaults() {
Notice() << "SmtEngine: turning off cbqi to support instMaxLevel" << endl;
options::cbqi.set(false);
}
- //track instantiations?
- if( options::cbqiNestedQE() || ( options::proof() && !options::trackInstLemmas.wasSetByUser() ) ){
+ // Do we need to track instantiations?
+ // Needed for sygus due to single invocation techniques.
+ if (options::cbqiNestedQE()
+ || (options::proof() && !options::trackInstLemmas.wasSetByUser())
+ || is_sygus)
+ {
options::trackInstLemmas.set( true );
}
@@ -1822,8 +1804,6 @@ void SmtEngine::setDefaults() {
//now have determined whether fmfBoundInt is on/off
//apply fmfBoundInt options
if( options::fmfBound() ){
- //must have finite model finding on
- options::finiteModelFind.set( true );
if (!options::mbqiMode.wasSetByUser()
|| (options::mbqiMode() != quantifiers::MBQI_NONE
&& options::mbqiMode() != quantifiers::MBQI_FMC))
@@ -1840,6 +1820,11 @@ void SmtEngine::setDefaults() {
if( options::mbqiMode()!=quantifiers::MBQI_NONE ){
options::mbqiMode.set( quantifiers::MBQI_NONE );
}
+ if (!options::hoElimStoreAx.wasSetByUser())
+ {
+ // by default, use store axioms only if --ho-elim is set
+ options::hoElimStoreAx.set(options::hoElim());
+ }
}
if( options::fmfFunWellDefinedRelevant() ){
if( !options::fmfFunWellDefined.wasSetByUser() ){
@@ -1963,26 +1948,37 @@ void SmtEngine::setDefaults() {
options::sygusExtRew.set(false);
}
}
- if (options::sygusAbduct())
+ // Whether we must use "basic" sygus algorithms. A non-basic sygus algorithm
+ // is one that is specialized for returning a single solution. Non-basic
+ // sygus algorithms currently include the PBE solver, static template
+ // inference for invariant synthesis, and single invocation techniques.
+ bool reqBasicSygus = false;
+ if (options::produceAbducts())
{
// if doing abduction, we should filter strong solutions
if (!options::sygusFilterSolMode.wasSetByUser())
{
options::sygusFilterSolMode.set(quantifiers::SYGUS_FILTER_SOL_STRONG);
}
+ // we must use basic sygus algorithms, since e.g. we require checking
+ // a sygus side condition for consistency with axioms.
+ reqBasicSygus = true;
}
if (options::sygusRewSynth() || options::sygusRewVerify()
- || options::sygusQueryGen() || options::sygusAbduct())
+ || options::sygusQueryGen())
{
// rewrite rule synthesis implies that sygus stream must be true
options::sygusStream.set(true);
}
- if (options::sygusStream())
+ if (options::sygusStream() || options::incrementalSolving())
+ {
+ // Streaming and incremental mode are incompatible with techniques that
+ // focus the search towards finding a single solution.
+ reqBasicSygus = true;
+ }
+ // Now, disable options for non-basic sygus algorithms, if necessary.
+ if (reqBasicSygus)
{
- // Streaming is incompatible with techniques that focus the search towards
- // finding a single solution. This currently includes the PBE solver,
- // static template inference for invariant synthesis, and single
- // invocation techniques.
if (!options::sygusUnifPbe.wasSetByUser())
{
options::sygusUnifPbe.set(false);
@@ -2300,11 +2296,11 @@ void SmtEngine::setDefaults() {
"--sygus-expr-miner-check-timeout=N requires "
"--sygus-expr-miner-check-use-export");
}
- if (options::sygusRewSynthInput() || options::sygusAbduct())
+ if (options::sygusRewSynthInput() || options::produceAbducts())
{
std::stringstream ss;
ss << (options::sygusRewSynthInput() ? "--sygus-rr-synth-input"
- : "--sygus-abduct");
+ : "--produce-abducts");
ss << "requires --sygus-expr-miner-check-use-export";
throw OptionException(ss.str());
}
@@ -2320,10 +2316,10 @@ void SmtEngine::setDefaults() {
}
}
-void SmtEngine::setProblemExtended(bool value)
+void SmtEngine::setProblemExtended()
{
- d_problemExtended = value;
- if (value) { d_assumptions.clear(); }
+ d_smtMode = SMT_MODE_ASSERT;
+ d_assumptions.clear();
}
void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
@@ -2344,25 +2340,6 @@ void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
}
}
- // Check for CVC4-specific info keys (prefixed with "cvc4-" or "cvc4_")
- if(key.length() > 5) {
- string prefix = key.substr(0, 5);
- if(prefix == "cvc4-" || prefix == "cvc4_") {
- string cvc4key = key.substr(5);
- if(cvc4key == "logic") {
- if(! value.isAtom()) {
- throw OptionException("argument to (set-info :cvc4-logic ..) must be a string");
- }
- SmtScope smts(this);
- d_logic = value.getValue();
- setLogicInternal();
- return;
- } else {
- throw UnrecognizedOptionException();
- }
- }
- }
-
// Check for standard info keys (SMT-LIB v1, SMT-LIB v2, ...)
if (key == "source" || key == "category" || key == "difficulty"
|| key == "notes" || key == "name" || key == "license")
@@ -2420,7 +2397,7 @@ void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
throw OptionException("argument to (set-info :status ..) must be "
"`sat' or `unsat' or `unknown'");
}
- d_status = Result(s, d_filename);
+ d_expectedStatus = Result(s, d_filename);
return;
}
throw UnrecognizedOptionException();
@@ -2451,12 +2428,7 @@ CVC4::SExpr SmtEngine::getInfo(const std::string& key) const {
}
return SExpr(stats);
} else if(key == "error-behavior") {
- // immediate-exit | continued-execution
- if( options::continuedExecution() || options::interactive() ) {
- return SExpr(SExpr::Keyword("continued-execution"));
- } else {
- return SExpr(SExpr::Keyword("immediate-exit"));
- }
+ return SExpr(SExpr::Keyword("immediate-exit"));
} else if(key == "name") {
return SExpr(Configuration::getName());
} else if(key == "version") {
@@ -2734,13 +2706,20 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, unordered_map<Node, Node, Node
if(n.isVar()) {
SmtEngine::DefinedFunctionMap::const_iterator i = d_smt.d_definedFunctions->find(n);
if(i != d_smt.d_definedFunctions->end()) {
+ Node f = (*i).second.getFormula();
+ // must expand its definition
+ Node fe = expandDefinitions(f, cache, expandOnly);
// replacement must be closed
if((*i).second.getFormals().size() > 0) {
- result.push(d_smt.d_nodeManager->mkNode(kind::LAMBDA, d_smt.d_nodeManager->mkNode(kind::BOUND_VAR_LIST, (*i).second.getFormals()), (*i).second.getFormula()));
+ result.push(d_smt.d_nodeManager->mkNode(
+ kind::LAMBDA,
+ d_smt.d_nodeManager->mkNode(kind::BOUND_VAR_LIST,
+ (*i).second.getFormals()),
+ fe));
continue;
}
// don't bother putting in the cache
- result.push((*i).second.getFormula());
+ result.push(fe);
continue;
}
// don't bother putting in the cache
@@ -2758,11 +2737,7 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, unordered_map<Node, Node, Node
// otherwise expand it
bool doExpand = false;
- if (k == kind::APPLY)
- {
- doExpand = true;
- }
- else if (k == kind::APPLY_UF)
+ if (k == kind::APPLY_UF)
{
// Always do beta-reduction here. The reason is that there may be
// operators such as INTS_MODULUS in the body of the lambda that would
@@ -2775,10 +2750,9 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, unordered_map<Node, Node, Node
{
doExpand = true;
}
- else if (options::macrosQuant() || options::sygusInference())
+ else
{
- // The above options assign substitutions to APPLY_UF, thus we check
- // here and expand if this operator corresponds to a defined function.
+ // We always check if this operator corresponds to a defined function.
doExpand = d_smt.isDefinedFunction(n.getOperator().toExpr());
}
}
@@ -3065,6 +3039,43 @@ Result SmtEngine::quickCheck() {
return Result(Result::VALIDITY_UNKNOWN, Result::REQUIRES_FULL_CHECK, d_filename);
}
+theory::TheoryModel* SmtEngine::getAvailableModel(const char* c) const
+{
+ if (!options::assignFunctionValues())
+ {
+ std::stringstream ss;
+ ss << "Cannot " << c << " when --assign-function-values is false.";
+ throw RecoverableModalException(ss.str().c_str());
+ }
+
+ if (d_smtMode != SMT_MODE_SAT)
+ {
+ std::stringstream ss;
+ ss << "Cannot " << c
+ << " unless immediately preceded by SAT/INVALID or UNKNOWN response.";
+ throw RecoverableModalException(ss.str().c_str());
+ }
+
+ if (!options::produceModels())
+ {
+ std::stringstream ss;
+ ss << "Cannot " << c << " when produce-models options is off.";
+ throw ModalException(ss.str().c_str());
+ }
+
+ TheoryModel* m = d_theoryEngine->getBuiltModel();
+
+ if (m == nullptr)
+ {
+ std::stringstream ss;
+ ss << "Cannot " << c
+ << " since model is not available. Perhaps the most recent call to "
+ "check-sat was interupted?";
+ throw RecoverableModalException(ss.str().c_str());
+ }
+
+ return m;
+}
void SmtEnginePrivate::collectSkolems(TNode n, set<TNode>& skolemSet, unordered_map<Node, bool, NodeHashFunction>& cache)
{
@@ -3206,15 +3217,6 @@ void SmtEnginePrivate::processAssertions() {
d_passes["nl-ext-purify"]->apply(&d_assertions);
}
- if( options::ceGuidedInst() ){
- //register sygus conjecture pre-rewrite (motivated by solution reconstruction)
- for (unsigned i = 0; i < d_assertions.size(); ++ i) {
- d_smt.d_theoryEngine->getQuantifiersEngine()
- ->getSynthEngine()
- ->preregisterAssertion(d_assertions[i]);
- }
- }
-
if (options::solveRealAsInt()) {
d_passes["real-to-int"]->apply(&d_assertions);
}
@@ -3351,10 +3353,6 @@ void SmtEnginePrivate::processAssertions() {
{
d_passes["sygus-infer"]->apply(&d_assertions);
}
- else if (options::sygusAbduct())
- {
- d_passes["sygus-abduct"]->apply(&d_assertions);
- }
else if (options::sygusRewSynthInput())
{
// do candidate rewrite rule synthesis
@@ -3472,6 +3470,11 @@ void SmtEnginePrivate::processAssertions() {
d_passes["apply-to-const"]->apply(&d_assertions);
}
+ if (options::ufHo())
+ {
+ d_passes["ho-elim"]->apply(&d_assertions);
+ }
+
// begin: INVARIANT to maintain: no reordering of assertions or
// introducing new ones
#ifdef CVC4_ASSERTIONS
@@ -3640,7 +3643,7 @@ Result SmtEngine::checkSatisfiability(const vector<Expr>& assumptions,
bool didInternalPush = false;
- setProblemExtended(true);
+ setProblemExtended();
if (isQuery)
{
@@ -3745,15 +3748,31 @@ Result SmtEngine::checkSatisfiability(const vector<Expr>& assumptions,
// Remember the status
d_status = r;
-
- setProblemExtended(false);
+ // Check against expected status
+ if (!d_expectedStatus.isUnknown() && !d_status.isUnknown()
+ && d_status != d_expectedStatus)
+ {
+ CVC4_FATAL() << "Expected result " << d_expectedStatus << " but got "
+ << d_status;
+ }
+ d_expectedStatus = Result();
+ // Update the SMT mode
+ if (d_status.asSatisfiabilityResult().isSat() == Result::UNSAT)
+ {
+ d_smtMode = SMT_MODE_UNSAT;
+ }
+ else
+ {
+ // Notice that unknown response moves to sat mode, since the same set
+ // of commands (get-model, get-value) are applicable to this case.
+ d_smtMode = SMT_MODE_SAT;
+ }
Trace("smt") << "SmtEngine::" << (isQuery ? "query" : "checkSat") << "("
<< assumptions << ") => " << r << endl;
// Check that SAT results generate a model correctly.
if(options::checkModels()) {
- // TODO (#1693) check model when unknown result?
if (r.asSatisfiabilityResult().isSat() == Result::SAT)
{
checkModel();
@@ -3798,9 +3817,7 @@ vector<Expr> SmtEngine::getUnsatAssumptions(void)
"Cannot get unsat assumptions when produce-unsat-assumptions option "
"is off.");
}
- if (d_status.isNull()
- || d_status.asSatisfiabilityResult() != Result::UNSAT
- || d_problemExtended)
+ if (d_smtMode != SMT_MODE_UNSAT)
{
throw RecoverableModalException(
"Cannot get unsat assumptions unless immediately preceded by "
@@ -3854,6 +3871,7 @@ void SmtEngine::declareSygusVar(const std::string& id, Expr var, Type type)
{
d_private->d_sygusVars.push_back(Node::fromExpr(var));
Trace("smt") << "SmtEngine::declareSygusVar: " << var << "\n";
+ // don't need to set that the conjecture is stale
}
void SmtEngine::declareSygusPrimedVar(const std::string& id, Type type)
@@ -3862,6 +3880,7 @@ void SmtEngine::declareSygusPrimedVar(const std::string& id, Type type)
d_private->d_sygusPrimedVarTypes.push_back(type);
#endif
Trace("smt") << "SmtEngine::declareSygusPrimedVar: " << id << "\n";
+ // don't need to set that the conjecture is stale
}
void SmtEngine::declareSygusFunctionVar(const std::string& id,
@@ -3870,6 +3889,7 @@ void SmtEngine::declareSygusFunctionVar(const std::string& id,
{
d_private->d_sygusVars.push_back(Node::fromExpr(var));
Trace("smt") << "SmtEngine::declareSygusFunctionVar: " << var << "\n";
+ // don't need to set that the conjecture is stale
}
void SmtEngine::declareSynthFun(const std::string& id,
@@ -3878,28 +3898,41 @@ void SmtEngine::declareSynthFun(const std::string& id,
bool isInv,
const std::vector<Expr>& vars)
{
+ SmtScope smts(this);
+ finalOptionsAreSet();
+ doPendingPops();
Node fn = Node::fromExpr(func);
d_private->d_sygusFunSymbols.push_back(fn);
- std::vector<Node> var_nodes;
- for (const Expr& v : vars)
+ if (!vars.empty())
{
- var_nodes.push_back(Node::fromExpr(v));
+ Expr bvl = d_exprManager->mkExpr(kind::BOUND_VAR_LIST, vars);
+ std::vector<Expr> attr_val_bvl;
+ attr_val_bvl.push_back(bvl);
+ setUserAttribute("sygus-synth-fun-var-list", func, attr_val_bvl, "");
}
- d_private->d_sygusFunVars[fn] = var_nodes;
// whether sygus type encodes syntax restrictions
if (sygusType.isDatatype()
&& static_cast<DatatypeType>(sygusType).getDatatype().isSygus())
{
- d_private->d_sygusFunSyntax[fn] = TypeNode::fromType(sygusType);
+ TypeNode stn = TypeNode::fromType(sygusType);
+ Node sym = d_nodeManager->mkBoundVar("sfproxy", stn);
+ std::vector<Expr> attr_value;
+ attr_value.push_back(sym.toExpr());
+ setUserAttribute("sygus-synth-grammar", func, attr_value, "");
}
Trace("smt") << "SmtEngine::declareSynthFun: " << func << "\n";
+ // sygus conjecture is now stale
+ setSygusConjectureStale();
}
void SmtEngine::assertSygusConstraint(Expr constraint)
{
+ SmtScope smts(this);
d_private->d_sygusConstraints.push_back(constraint);
Trace("smt") << "SmtEngine::assertSygusConstrant: " << constraint << "\n";
+ // sygus conjecture is now stale
+ setSygusConjectureStale();
}
void SmtEngine::assertSygusInvConstraint(const Expr& inv,
@@ -3969,8 +4002,7 @@ void SmtEngine::assertSygusInvConstraint(const Expr& inv,
{
children.insert(children.end(), vars.begin(), vars.end());
}
- terms[i] =
- d_nodeManager->mkNode(i == 0 ? kind::APPLY_UF : kind::APPLY, children);
+ terms[i] = d_nodeManager->mkNode(kind::APPLY_UF, children);
// make application of Inv on primed variables
if (i == 0)
{
@@ -3991,11 +4023,27 @@ void SmtEngine::assertSygusInvConstraint(const Expr& inv,
d_private->d_sygusConstraints.push_back(constraint);
Trace("smt") << "SmtEngine::assertSygusInvConstrant: " << constraint << "\n";
+ // sygus conjecture is now stale
+ setSygusConjectureStale();
}
Result SmtEngine::checkSynth()
{
SmtScope smts(this);
+
+ if (options::incrementalSolving())
+ {
+ // TODO (project #7)
+ throw ModalException(
+ "Cannot make check-synth commands when incremental solving is enabled");
+ }
+
+ if (!d_private->d_sygusConjectureStale)
+ {
+ // do not need to reconstruct, we're done
+ return checkSatisfiability(Expr(), true, false);
+ }
+
// build synthesis conjecture from asserted constraints and declared
// variables/functions
Node sygusVar =
@@ -4031,39 +4079,19 @@ Result SmtEngine::checkSynth()
// set attribute for synthesis conjecture
setUserAttribute("sygus", sygusVar.toExpr(), {}, "");
- // set attributes for functions-to-synthesize
- for (const Node& synth_fun : d_private->d_sygusFunSymbols)
+ Trace("smt") << "Check synthesis conjecture: " << body << std::endl;
+
+ d_private->d_sygusConjectureStale = false;
+
+ if (options::incrementalSolving())
{
- // associate var list with function-to-synthesize
- Assert(d_private->d_sygusFunVars.find(synth_fun)
- != d_private->d_sygusFunVars.end());
- const std::vector<Node>& vars = d_private->d_sygusFunVars[synth_fun];
- Node bvl;
- if (!vars.empty())
- {
- bvl = d_nodeManager->mkNode(kind::BOUND_VAR_LIST, vars);
- }
- std::vector<Expr> attr_val_bvl;
- attr_val_bvl.push_back(bvl.toExpr());
- setUserAttribute(
- "sygus-synth-fun-var-list", synth_fun.toExpr(), attr_val_bvl, "");
- // If the function has syntax restrition, bulid a variable "sfproxy" which
- // carries the type, a SyGuS datatype that corresponding to the syntactic
- // restrictions.
- std::map<Node, TypeNode>::const_iterator it =
- d_private->d_sygusFunSyntax.find(synth_fun);
- if (it != d_private->d_sygusFunSyntax.end())
- {
- Node sym = d_nodeManager->mkBoundVar("sfproxy", it->second);
- std::vector<Expr> attr_value;
- attr_value.push_back(sym.toExpr());
- setUserAttribute(
- "sygus-synth-grammar", synth_fun.toExpr(), attr_value, "");
- }
+ // we push a context so that this conjecture is removed if we modify it
+ // later
+ internalPush();
+ assertFormula(body.toExpr(), true);
+ return checkSatisfiability(body.toExpr(), true, false);
}
- Trace("smt") << "Check synthesis conjecture: " << body << std::endl;
-
return checkSatisfiability(body.toExpr(), true, false);
}
@@ -4138,19 +4166,6 @@ Expr SmtEngine::getValue(const Expr& ex) const
Dump("benchmark") << GetValueCommand(ex);
}
- if(!options::produceModels()) {
- const char* msg =
- "Cannot get value when produce-models options is off.";
- throw ModalException(msg);
- }
- if(d_status.isNull() ||
- d_status.asSatisfiabilityResult() == Result::UNSAT ||
- d_problemExtended) {
- const char* msg =
- "Cannot get value unless immediately preceded by SAT/INVALID or UNKNOWN response.";
- throw RecoverableModalException(msg);
- }
-
// Substitute out any abstract values in ex.
Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
@@ -4179,7 +4194,7 @@ Expr SmtEngine::getValue(const Expr& ex) const
}
Trace("smt") << "--- getting value of " << n << endl;
- TheoryModel* m = d_theoryEngine->getBuiltModel();
+ TheoryModel* m = getAvailableModel("get-value");
Node resultNode;
if(m != NULL) {
resultNode = m->getValue(n);
@@ -4191,11 +4206,16 @@ Expr SmtEngine::getValue(const Expr& ex) const
Trace("smt") << "--- model-post expected " << expectedType << endl;
// type-check the result we got
- Assert(resultNode.isNull() || resultNode.getType().isSubtypeOf(expectedType),
+ // Notice that lambdas have function type, which does not respect the subtype
+ // relation, so we ignore them here.
+ Assert(resultNode.isNull() || resultNode.getKind() == kind::LAMBDA
+ || resultNode.getType().isSubtypeOf(expectedType),
"Run with -t smt for details.");
- // ensure it's a constant
- Assert(resultNode.getKind() == kind::LAMBDA || resultNode.isConst());
+ // Ensure it's a constant, or a lambda (for uninterpreted functions), or
+ // a choice (for approximate values).
+ Assert(resultNode.getKind() == kind::LAMBDA
+ || resultNode.getKind() == kind::CHOICE || resultNode.isConst());
if(options::abstractValues() && resultNode.getType().isArray()) {
resultNode = d_private->mkAbstractValue(resultNode);
@@ -4205,6 +4225,16 @@ Expr SmtEngine::getValue(const Expr& ex) const
return resultNode.toExpr();
}
+vector<Expr> SmtEngine::getValues(const vector<Expr>& exprs)
+{
+ vector<Expr> result;
+ for (const Expr& e : exprs)
+ {
+ result.push_back(getValue(e));
+ }
+ return result;
+}
+
bool SmtEngine::addToAssignment(const Expr& ex) {
SmtScope smts(this);
finalOptionsAreSet();
@@ -4218,15 +4248,15 @@ bool SmtEngine::addToAssignment(const Expr& ex) {
"expected Boolean-typed variable or function application "
"in addToAssignment()" );
Node n = e.getNode();
- // must be an APPLY of a zero-ary defined function, or a variable
+ // must be a defined constant, or a variable
PrettyCheckArgument(
- ( ( n.getKind() == kind::APPLY &&
- ( d_definedFunctions->find(n.getOperator()) !=
- d_definedFunctions->end() ) &&
- n.getNumChildren() == 0 ) ||
- n.isVar() ), e,
+ (((d_definedFunctions->find(n) != d_definedFunctions->end())
+ && n.getNumChildren() == 0)
+ || n.isVar()),
+ e,
"expected variable or defined-function application "
- "in addToAssignment(),\ngot %s", e.toString().c_str() );
+ "in addToAssignment(),\ngot %s",
+ e.toString().c_str());
if(!options::produceAssignments()) {
return false;
}
@@ -4253,20 +4283,16 @@ vector<pair<Expr, Expr>> SmtEngine::getAssignment()
"produce-assignments option is off.";
throw ModalException(msg);
}
- if(d_status.isNull() ||
- d_status.asSatisfiabilityResult() == Result::UNSAT ||
- d_problemExtended) {
- const char* msg =
- "Cannot get the current assignment unless immediately "
- "preceded by SAT/INVALID or UNKNOWN response.";
- throw RecoverableModalException(msg);
- }
+
+ // Get the model here, regardless of whether d_assignments is null, since
+ // we should throw errors related to model availability whether or not
+ // assignments is null.
+ TheoryModel* m = getAvailableModel("get assignment");
vector<pair<Expr,Expr>> res;
if (d_assignments != nullptr)
{
TypeNode boolType = d_nodeManager->booleanType();
- TheoryModel* m = d_theoryEngine->getBuiltModel();
for (AssignmentSet::key_iterator i = d_assignments->key_begin(),
iend = d_assignments->key_end();
i != iend;
@@ -4295,8 +4321,7 @@ vector<pair<Expr, Expr>> SmtEngine::getAssignment()
// ensure it's a constant
Assert(resultNode.isConst());
- Assert(as.getKind() == kind::APPLY || as.isVar());
- Assert(as.getKind() != kind::APPLY || as.getNumChildren() == 0);
+ Assert(as.isVar());
res.emplace_back(as.toExpr(), resultNode.toExpr());
}
}
@@ -4343,27 +4368,7 @@ Model* SmtEngine::getModel() {
Dump("benchmark") << GetModelCommand();
}
- if (!options::assignFunctionValues())
- {
- const char* msg =
- "Cannot get the model when --assign-function-values is false.";
- throw RecoverableModalException(msg);
- }
-
- if(d_status.isNull() ||
- d_status.asSatisfiabilityResult() == Result::UNSAT ||
- d_problemExtended) {
- const char* msg =
- "Cannot get the current model unless immediately "
- "preceded by SAT/INVALID or UNKNOWN response.";
- throw RecoverableModalException(msg);
- }
- if(!options::produceModels()) {
- const char* msg =
- "Cannot get model when produce-models options is off.";
- throw ModalException(msg);
- }
- TheoryModel* m = d_theoryEngine->getBuiltModel();
+ TheoryModel* m = getAvailableModel("get model");
// Since model m is being returned to the user, we must ensure that this
// model object remains valid with future check-sat calls. Hence, we set
@@ -4373,23 +4378,67 @@ Model* SmtEngine::getModel() {
if (options::modelCoresMode() != MODEL_CORES_NONE)
{
// If we enabled model cores, we compute a model core for m based on our
- // assertions using the model core builder utility
- std::vector<Expr> easserts = getAssertions();
- // must expand definitions
- std::vector<Expr> eassertsProc;
- std::unordered_map<Node, Node, NodeHashFunction> cache;
- for (unsigned i = 0, nasserts = easserts.size(); i < nasserts; i++)
- {
- Node ea = Node::fromExpr(easserts[i]);
- Node eae = d_private->expandDefinitions(ea, cache);
- eassertsProc.push_back(eae.toExpr());
- }
+ // (expanded) assertions using the model core builder utility
+ std::vector<Expr> eassertsProc = getExpandedAssertions();
ModelCoreBuilder::setModelCore(eassertsProc, m, options::modelCoresMode());
}
m->d_inputName = d_filename;
return m;
}
+Result SmtEngine::blockModel()
+{
+ Trace("smt") << "SMT blockModel()" << endl;
+ SmtScope smts(this);
+
+ finalOptionsAreSet();
+
+ if (Dump.isOn("benchmark"))
+ {
+ Dump("benchmark") << BlockModelCommand();
+ }
+
+ TheoryModel* m = getAvailableModel("block model");
+
+ if (options::blockModelsMode() == BLOCK_MODELS_NONE)
+ {
+ std::stringstream ss;
+ ss << "Cannot block model when block-models is set to none.";
+ throw ModalException(ss.str().c_str());
+ }
+
+ // get expanded assertions
+ std::vector<Expr> eassertsProc = getExpandedAssertions();
+ Expr eblocker = ModelBlocker::getModelBlocker(
+ eassertsProc, m, options::blockModelsMode());
+ return assertFormula(eblocker);
+}
+
+Result SmtEngine::blockModelValues(const std::vector<Expr>& exprs)
+{
+ Trace("smt") << "SMT blockModelValues()" << endl;
+ SmtScope smts(this);
+
+ finalOptionsAreSet();
+
+ PrettyCheckArgument(
+ !exprs.empty(),
+ "block model values must be called on non-empty set of terms");
+ if (Dump.isOn("benchmark"))
+ {
+ Dump("benchmark") << BlockModelValuesCommand(exprs);
+ }
+
+ TheoryModel* m = getAvailableModel("block model values");
+
+ // get expanded assertions
+ std::vector<Expr> eassertsProc = getExpandedAssertions();
+ // we always do block model values mode here
+ Expr eblocker = ModelBlocker::getModelBlocker(
+ eassertsProc, m, BLOCK_MODELS_VALUES, exprs);
+ return assertFormula(eblocker);
+}
+
std::pair<Expr, Expr> SmtEngine::getSepHeapAndNilExpr(void)
{
if (!d_logic.isTheoryEnabled(THEORY_SEP))
@@ -4402,7 +4451,7 @@ std::pair<Expr, Expr> SmtEngine::getSepHeapAndNilExpr(void)
NodeManagerScope nms(d_nodeManager);
Expr heap;
Expr nil;
- Model* m = d_theoryEngine->getBuiltModel();
+ Model* m = getAvailableModel("get separation logic heap and nil");
if (m->getHeapModel(heap, nil))
{
return std::make_pair(heap, nil);
@@ -4412,6 +4461,21 @@ std::pair<Expr, Expr> SmtEngine::getSepHeapAndNilExpr(void)
"expressions from theory model.");
}
+std::vector<Expr> SmtEngine::getExpandedAssertions()
+{
+ std::vector<Expr> easserts = getAssertions();
+ // must expand definitions
+ std::vector<Expr> eassertsProc;
+ std::unordered_map<Node, Node, NodeHashFunction> cache;
+ for (const Expr& e : easserts)
+ {
+ Node ea = Node::fromExpr(e);
+ Node eae = d_private->expandDefinitions(ea, cache);
+ eassertsProc.push_back(eae.toExpr());
+ }
+ return eassertsProc;
+}
+
Expr SmtEngine::getSepHeapExpr() { return getSepHeapAndNilExpr().first; }
Expr SmtEngine::getSepNilExpr() { return getSepHeapAndNilExpr().second; }
@@ -4428,13 +4492,7 @@ void SmtEngine::checkProof()
std::string logicString = d_logic.getLogicString();
- if (!(
- // Pure logics
- logicString == "QF_UF" || logicString == "QF_AX"
- || logicString == "QF_BV" ||
- // Non-pure logics
- logicString == "QF_AUF" || logicString == "QF_UFBV"
- || logicString == "QF_ABV" || logicString == "QF_AUFBV"))
+ if (!(d_logic <= LogicInfo("QF_AUFBVLRA")))
{
// This logic is not yet supported
Notice() << "Notice: no proof-checking for " << logicString << " proofs yet"
@@ -4475,8 +4533,7 @@ UnsatCore SmtEngine::getUnsatCoreInternal()
throw ModalException(
"Cannot get an unsat core when produce-unsat-cores option is off.");
}
- if (d_status.isNull() || d_status.asSatisfiabilityResult() != Result::UNSAT
- || d_problemExtended)
+ if (d_smtMode != SMT_MODE_UNSAT)
{
throw RecoverableModalException(
"Cannot get an unsat core unless immediately preceded by UNSAT/VALID "
@@ -4546,7 +4603,7 @@ void SmtEngine::checkModel(bool hardFailure) {
// and if Notice() is on, the user gave --verbose (or equivalent).
Notice() << "SmtEngine::checkModel(): generating model" << endl;
- TheoryModel* m = d_theoryEngine->getBuiltModel();
+ TheoryModel* m = getAvailableModel("check model");
// check-model is not guaranteed to succeed if approximate values were used
if (m->hasApproximations())
@@ -4842,6 +4899,70 @@ void SmtEngine::checkSynthSolution()
}
}
+void SmtEngine::checkAbduct(Expr a)
+{
+ Assert(a.getType().isBoolean());
+ Trace("check-abduct") << "SmtEngine::checkAbduct: get expanded assertions"
+ << std::endl;
+
+ std::vector<Expr> asserts = getExpandedAssertions();
+ asserts.push_back(a);
+
+ // two checks: first, consistent with assertions, second, implies negated goal
+ // is unsatisfiable.
+ for (unsigned j = 0; j < 2; j++)
+ {
+ Trace("check-abduct") << "SmtEngine::checkAbduct: phase " << j
+ << ": make new SMT engine" << std::endl;
+ // Start new SMT engine to check solution
+ SmtEngine abdChecker(d_exprManager);
+ abdChecker.setLogic(getLogicInfo());
+ Trace("check-abduct") << "SmtEngine::checkAbduct: phase " << j
+ << ": asserting formulas" << std::endl;
+ for (const Expr& e : asserts)
+ {
+ abdChecker.assertFormula(e);
+ }
+ Trace("check-abduct") << "SmtEngine::checkAbduct: phase " << j
+ << ": check the assertions" << std::endl;
+ Result r = abdChecker.checkSat();
+ Trace("check-abduct") << "SmtEngine::checkAbduct: phase " << j
+ << ": result is " << r << endl;
+ std::stringstream serr;
+ bool isError = false;
+ if (j == 0)
+ {
+ if (r.asSatisfiabilityResult().isSat() != Result::SAT)
+ {
+ isError = true;
+ serr << "SmtEngine::checkAbduct(): produced solution cannot be shown "
+ "to be consisconsistenttent with assertions, result was "
+ << r;
+ }
+ Trace("check-abduct")
+ << "SmtEngine::checkAbduct: goal is " << d_abdConj << std::endl;
+ // add the goal to the set of assertions
+ Assert(!d_abdConj.isNull());
+ asserts.push_back(d_abdConj);
+ }
+ else
+ {
+ if (r.asSatisfiabilityResult().isSat() != Result::UNSAT)
+ {
+ isError = true;
+ serr << "SmtEngine::checkAbduct(): negated goal cannot be shown "
+ "unsatisfiable with produced solution, result was "
+ << r;
+ }
+ }
+ // did we get an unexpected result?
+ if (isError)
+ {
+ InternalError(serr.str().c_str());
+ }
+ }
+}
+
// TODO(#1108): Simplify the error reporting of this method.
UnsatCore SmtEngine::getUnsatCore() {
Trace("smt") << "SMT getUnsatCore()" << endl;
@@ -4866,9 +4987,8 @@ const Proof& SmtEngine::getProof()
if(!options::proof()) {
throw ModalException("Cannot get a proof when produce-proofs option is off.");
}
- if(d_status.isNull() ||
- d_status.asSatisfiabilityResult() != Result::UNSAT ||
- d_problemExtended) {
+ if (d_smtMode != SMT_MODE_UNSAT)
+ {
throw RecoverableModalException(
"Cannot get a proof unless immediately preceded by UNSAT/VALID "
"response.");
@@ -4985,6 +5105,128 @@ Expr SmtEngine::doQuantifierElimination(const Expr& e, bool doFull, bool strict)
}
}
+bool SmtEngine::getAbduct(const Expr& conj, const Type& grammarType, Expr& abd)
+{
+ SmtScope smts(this);
+
+ if (!options::produceAbducts())
+ {
+ const char* msg = "Cannot get abduct when produce-abducts options is off.";
+ throw ModalException(msg);
+ }
+ Trace("sygus-abduct") << "SmtEngine::getAbduct: conjecture " << conj
+ << std::endl;
+ std::vector<Expr> easserts = getExpandedAssertions();
+ std::vector<Node> axioms;
+ for (unsigned i = 0, size = easserts.size(); i < size; i++)
+ {
+ axioms.push_back(Node::fromExpr(easserts[i]));
+ }
+ std::vector<Node> asserts(axioms.begin(), axioms.end());
+ // negate the conjecture
+ Node conjn = Node::fromExpr(conj);
+ // must expand definitions
+ std::unordered_map<Node, Node, NodeHashFunction> cache;
+ conjn = d_private->expandDefinitions(conjn, cache);
+ // now negate
+ conjn = conjn.negate();
+ d_abdConj = conjn.toExpr();
+ asserts.push_back(conjn);
+ std::string name("A");
+ Node aconj = theory::quantifiers::SygusAbduct::mkAbductionConjecture(
+ name, asserts, axioms, TypeNode::fromType(grammarType));
+ // should be a quantified conjecture with one function-to-synthesize
+ Assert(aconj.getKind() == kind::FORALL && aconj[0].getNumChildren() == 1);
+ // remember the abduct-to-synthesize
+ d_sssf = aconj[0][0].toExpr();
+ Trace("sygus-abduct") << "SmtEngine::getAbduct: made conjecture : " << aconj
+ << ", solving for " << d_sssf << std::endl;
+ // we generate a new smt engine to do the abduction query
+ d_subsolver.reset(new SmtEngine(NodeManager::currentNM()->toExprManager()));
+ d_subsolver->setIsInternalSubsolver();
+ // get the logic
+ LogicInfo l = d_logic.getUnlockedCopy();
+ // enable everything needed for sygus
+ l.enableSygus();
+ d_subsolver->setLogic(l);
+ // assert the abduction query
+ d_subsolver->assertFormula(aconj.toExpr());
+ if (getAbductInternal(abd))
+ {
+ // successfully generated an abduct, update to abduct state
+ d_smtMode = SMT_MODE_ABDUCT;
+ return true;
+ }
+ // failed, we revert to the assert state
+ d_smtMode = SMT_MODE_ASSERT;
+ return false;
+}
+
+bool SmtEngine::getAbductInternal(Expr& abd)
+{
+ // should have initialized the subsolver by now
+ Assert(d_subsolver != nullptr);
+ Trace("sygus-abduct") << " SmtEngine::getAbduct check sat..." << std::endl;
+ Result r = d_subsolver->checkSat();
+ Trace("sygus-abduct") << " SmtEngine::getAbduct result: " << r << std::endl;
+ if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
+ {
+ // get the synthesis solution
+ std::map<Expr, Expr> sols;
+ d_subsolver->getSynthSolutions(sols);
+ Assert(sols.size() == 1);
+ std::map<Expr, Expr>::iterator its = sols.find(d_sssf);
+ if (its != sols.end())
+ {
+ Trace("sygus-abduct")
+ << "SmtEngine::getAbduct: solution is " << its->second << std::endl;
+ Node abdn = Node::fromExpr(its->second);
+ if (abdn.getKind() == kind::LAMBDA)
+ {
+ abdn = abdn[1];
+ }
+ // get the grammar type for the abduct
+ Node af = Node::fromExpr(d_sssf);
+ Node agdtbv = af.getAttribute(theory::SygusSynthFunVarListAttribute());
+ Assert(!agdtbv.isNull());
+ Assert(agdtbv.getKind() == kind::BOUND_VAR_LIST);
+ // convert back to original
+ // must replace formal arguments of abd with the free variables in the
+ // input problem that they correspond to.
+ std::vector<Node> vars;
+ std::vector<Node> syms;
+ SygusVarToTermAttribute sta;
+ for (const Node& bv : agdtbv)
+ {
+ vars.push_back(bv);
+ syms.push_back(bv.hasAttribute(sta) ? bv.getAttribute(sta) : bv);
+ }
+ abdn =
+ abdn.substitute(vars.begin(), vars.end(), syms.begin(), syms.end());
+
+ // convert to expression
+ abd = abdn.toExpr();
+
+ // if check abducts option is set, we check the correctness
+ if (options::checkAbducts())
+ {
+ checkAbduct(abd);
+ }
+ return true;
+ }
+ Trace("sygus-abduct") << "SmtEngine::getAbduct: could not find solution!"
+ << std::endl;
+ throw RecoverableModalException("Could not find solution for get-abduct.");
+ }
+ return false;
+}
+
+bool SmtEngine::getAbduct(const Expr& conj, Expr& abd)
+{
+ Type grammarType;
+ return getAbduct(conj, grammarType, abd);
+}
+
void SmtEngine::getInstantiatedQuantifiedFormulas( std::vector< Expr >& qs ) {
SmtScope smts(this);
if( d_theoryEngine ){
@@ -5065,8 +5307,8 @@ void SmtEngine::push()
// The problem isn't really "extended" yet, but this disallows
// get-model after a push, simplifying our lives somewhat and
- // staying symmtric with pop.
- setProblemExtended(true);
+ // staying symmetric with pop.
+ setProblemExtended();
d_userLevels.push_back(d_userContext->getLevel());
internalPush();
@@ -5094,7 +5336,7 @@ void SmtEngine::pop() {
// but also it would be weird to have a legally-executed (get-model)
// that only returns a subset of the assignment (because the rest
// is no longer in scope!).
- setProblemExtended(true);
+ setProblemExtended();
AlwaysAssert(d_userContext->getLevel() > 0);
AlwaysAssert(d_userLevels.back() < d_userContext->getLevel());
@@ -5397,4 +5639,18 @@ void SmtEngine::setExpressionName(Expr e, const std::string& name) {
d_private->setExpressionName(e,name);
}
+void SmtEngine::setSygusConjectureStale()
+{
+ if (d_private->d_sygusConjectureStale)
+ {
+ // already stale
+ return;
+ }
+ d_private->d_sygusConjectureStale = true;
+ if (options::incrementalSolving())
+ {
+ internalPop();
+ }
+}
+
}/* CVC4 namespace */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback