summaryrefslogtreecommitdiff
path: root/src/smt
diff options
context:
space:
mode:
Diffstat (limited to 'src/smt')
-rw-r--r--src/smt/logic_request.h53
-rw-r--r--src/smt/options9
-rw-r--r--src/smt/options_handlers.h13
-rw-r--r--src/smt/smt_engine.cpp581
-rw-r--r--src/smt/smt_engine.h9
-rw-r--r--src/smt/smt_options_template.cpp8
6 files changed, 244 insertions, 429 deletions
diff --git a/src/smt/logic_request.h b/src/smt/logic_request.h
new file mode 100644
index 000000000..4985b0e65
--- /dev/null
+++ b/src/smt/logic_request.h
@@ -0,0 +1,53 @@
+/********************* */
+/*! \file logic_request.h
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief An object to request logic widening in the running SmtEngine
+ **
+ ** An object to request logic widening in the running SmtEngine. This
+ ** class exists as a proxy between theory code and the SmtEngine, allowing
+ ** a theory to enable another theory in the SmtEngine after initialization
+ ** (thus the usual, public setLogic() cannot be used). This is mainly to
+ ** support features like uninterpreted divide-by-zero (to support the
+ ** partial function DIVISION), where during theory expansion, the theory
+ ** of uninterpreted functions needs to be added to the logic to support
+ ** partial functions.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__LOGIC_REQUEST_H
+#define __CVC4__LOGIC_REQUEST_H
+
+#include "expr/kind.h"
+#include "smt/smt_engine.h"
+
+namespace CVC4 {
+
+class LogicRequest {
+ /** The SmtEngine at play. */
+ SmtEngine& d_smt;
+
+public:
+ LogicRequest(SmtEngine& smt) : d_smt(smt) { }
+
+ /** Widen the logic to include the given theory. */
+ void widenLogic(theory::TheoryId id) {
+ d_smt.d_logic.getUnlockedCopy();
+ d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
+ d_smt.d_logic.enableTheory(id);
+ d_smt.d_logic.lock();
+ }
+
+};/* class LogicRequest */
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__LOGIC_REQUEST_H */
diff --git a/src/smt/options b/src/smt/options
index b76822caf..f3429287f 100644
--- a/src/smt/options
+++ b/src/smt/options
@@ -5,11 +5,14 @@
module SMT "smt/options.h" SMT layer
-common-option - --dump=MODE argument :handler CVC4::smt::dumpMode :handler-include "smt/options_handlers.h"
+common-option - dump --dump=MODE argument :handler CVC4::smt::dumpMode :handler-include "smt/options_handlers.h"
dump preprocessed assertions, etc., see --dump=help
-common-option - --dump-to=FILE argument :handler CVC4::smt::dumpToFile :handler-include "smt/options_handlers.h"
+common-option - dump-to --dump-to=FILE argument :handler CVC4::smt::dumpToFile :handler-include "smt/options_handlers.h"
all dumping goes to FILE (instead of stdout)
+expert-option forceLogic force-logic --force-logic=LOGIC LogicInfo :include "theory/logic_info.h" :handler CVC4::smt::stringToLogicInfo :handler-include "smt/options_handlers.h" :default '""'
+ set the logic, and override all further user attempts to change it
+
option simplificationMode simplification-mode --simplification=MODE SimplificationMode :handler CVC4::smt::stringToSimplificationMode :default SIMPLIFICATION_MODE_BATCH :read-write :include "smt/simplification_mode.h" :handler-include "smt/options_handlers.h"
choose simplification mode, see --simplification=help
alias --no-simplification = --simplification=none
@@ -40,7 +43,7 @@ option produceAssignments produce-assignments --produce-assignments bool :defaul
# This could go in src/main/options, but by SMT-LIBv2 spec, "interactive"
# is a mode in which the assertion list must be kept. So it belongs here.
-common-option interactive interactive-mode --interactive bool :read-write
+common-option interactive interactive-mode --interactive bool :predicate CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h" :read-write
force interactive mode
option doITESimp --ite-simp bool :read-write
diff --git a/src/smt/options_handlers.h b/src/smt/options_handlers.h
index c9c3d6345..49f2c7943 100644
--- a/src/smt/options_handlers.h
+++ b/src/smt/options_handlers.h
@@ -257,6 +257,19 @@ inline void dumpMode(std::string option, std::string optarg, SmtEngine* smt) {
#endif /* CVC4_DUMPING */
}
+inline LogicInfo stringToLogicInfo(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+ try {
+ LogicInfo logic(optarg);
+ if(smt != NULL) {
+ smt->setLogic(logic);
+ }
+ return logic;
+ } catch(IllegalArgumentException& e) {
+ throw OptionException(std::string("invalid logic specification for --force-logic: `") +
+ optarg + "':\n" + e.what());
+ }
+}
+
inline SimplificationMode stringToSimplificationMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
if(optarg == "batch") {
return SIMPLIFICATION_MODE_BATCH;
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index 02542b640..328a20c28 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -43,6 +43,7 @@
#include "smt/smt_engine.h"
#include "smt/smt_engine_scope.h"
#include "smt/model_postprocessor.h"
+#include "smt/logic_request.h"
#include "theory/theory_engine.h"
#include "theory/bv/theory_bv_rewriter.h"
#include "proof/proof_manager.h"
@@ -80,8 +81,10 @@
#include "util/sort_inference.h"
#include "theory/quantifiers/quant_conflict_find.h"
#include "theory/quantifiers/macros.h"
-#include "theory/datatypes/options.h"
#include "theory/quantifiers/first_order_reasoning.h"
+#include "theory/quantifiers/quantifiers_rewriter.h"
+#include "theory/quantifiers/options.h"
+#include "theory/datatypes/options.h"
#include "theory/strings/theory_strings_preprocess.h"
using namespace std;
@@ -306,44 +309,6 @@ class SmtEnginePrivate : public NodeManagerListener {
*/
hash_map<Node, Node, NodeHashFunction> d_abstractValues;
- /**
- * Function symbol used to implement uninterpreted undefined string
- * semantics. Needed to deal with partial charat/substr function.
- */
- Node d_ufSubstr;
-
- /**
- * Function symbol used to implement uninterpreted undefined string
- * semantics. Needed to deal with partial str2int function.
- */
- Node d_ufS2I;
-
- /**
- * Function symbol used to implement uninterpreted division-by-zero
- * semantics. Needed to deal with partial division function ("/").
- */
- Node d_divByZero;
-
- /**
- * Maps from bit-vector width to divison-by-zero uninterpreted
- * function symbols.
- */
- hash_map<unsigned, Node> d_BVDivByZero;
- hash_map<unsigned, Node> d_BVRemByZero;
-
- /**
- * Function symbol used to implement uninterpreted
- * int-division-by-zero semantics. Needed to deal with partial
- * function "div".
- */
- Node d_intDivByZero;
-
- /**
- * Function symbol used to implement uninterpreted mod-zero
- * semantics. Needed to deal with partial function "mod".
- */
- Node d_modZero;
-
/** Number of calls of simplify assertions active.
*/
unsigned d_simplifyAssertionsDepth;
@@ -446,9 +411,6 @@ public:
d_fakeContext(),
d_abstractValueMap(&d_fakeContext),
d_abstractValues(),
- d_divByZero(),
- d_intDivByZero(),
- d_modZero(),
d_simplifyAssertionsDepth(0),
d_iteSkolemMap(),
d_iteRemover(smt.d_userContext),
@@ -552,25 +514,6 @@ public:
throw(TypeCheckingException, LogicException);
/**
- * Return the uinterpreted function symbol corresponding to division-by-zero
- * for this particular bit-width
- * @param k should be UREM or UDIV
- * @param width
- *
- * @return
- */
- Node getBVDivByZero(Kind k, unsigned width);
-
- /**
- * Returns the node modeling the division-by-zero semantics of node n.
- *
- * @param n
- *
- * @return
- */
- Node expandBVDivByZero(TNode n);
-
- /**
* Expand definitions in n.
*/
Node expandDefinitions(TNode n, hash_map<Node, Node, NodeHashFunction>& cache)
@@ -596,11 +539,6 @@ public:
}
/**
- * Pre-skolemize quantifiers.
- */
- Node preSkolemizeQuantifiers(Node n, bool polarity, std::vector<Node>& fvs);
-
- /**
* Substitute away all AbstractValues in a node.
*/
Node substituteAbstractValues(TNode n) {
@@ -736,6 +674,9 @@ SmtEngine::SmtEngine(ExprManager* em) throw() :
}
void SmtEngine::finishInit() {
+ // ensure that our heuristics are properly set up
+ setDefaults();
+
d_decisionEngine = new DecisionEngine(d_context, d_userContext);
d_decisionEngine->init(); // enable appropriate strategies
@@ -793,24 +734,7 @@ void SmtEngine::finalOptionsAreSet() {
return;
}
- if(options::bitvectorEagerBitblast()) {
- // Eager solver should use the internal decision strategy
- options::decisionMode.set(DECISION_STRATEGY_INTERNAL);
- }
-
- if(options::checkModels()) {
- if(! options::interactive()) {
- Notice() << "SmtEngine: turning on interactive-mode to support check-models" << endl;
- setOption("interactive-mode", SExpr("true"));
- }
- }
- if(options::produceAssignments() && !options::produceModels()) {
- Notice() << "SmtEngine: turning on produce-models to support produce-assignments" << endl;
- setOption("produce-models", SExpr("true"));
- }
-
if(! d_logic.isLocked()) {
- // ensure that our heuristics are properly set up
setLogicInternal();
}
@@ -925,15 +849,68 @@ LogicInfo SmtEngine::getLogicInfo() const {
return d_logic;
}
-// This function is called when d_logic has just been changed.
-// The LogicInfo isn't passed in explicitly, because that might
-// tempt people in the code to use the (potentially unlocked)
-// version that's passed in, leading to assert-fails in certain
-// uses of the CVC4 library.
void SmtEngine::setLogicInternal() throw() {
Assert(!d_fullyInited, "setting logic in SmtEngine but the engine has already finished initializing for this run");
-
d_logic.lock();
+}
+
+void SmtEngine::setDefaults() {
+ if(options::forceLogic.wasSetByUser()) {
+ d_logic = options::forceLogic();
+ }
+
+ // set strings-exp
+ 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() ) {
+ d_logic = d_logic.getUnlockedCopy();
+ d_logic.enableQuantifiers();
+ d_logic.lock();
+ Trace("smt") << "turning on quantifier logic, for strings-exp" << std::endl;
+ }
+ if(! options::finiteModelFind.wasSetByUser()) {
+ options::finiteModelFind.set( true );
+ Trace("smt") << "turning on finite-model-find, for strings-exp" << std::endl;
+ }
+ if(! options::fmfBoundInt.wasSetByUser()) {
+ options::fmfBoundInt.set( true );
+ Trace("smt") << "turning on fmf-bound-int, 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;
+ }
+ */
+ }
+
+ if(options::bitvectorEagerBitblast()) {
+ // Eager solver should use the internal decision strategy
+ options::decisionMode.set(DECISION_STRATEGY_INTERNAL);
+ }
+
+ if(options::checkModels()) {
+ if(! options::interactive()) {
+ Notice() << "SmtEngine: turning on interactive-mode to support check-models" << endl;
+ setOption("interactive-mode", SExpr("true"));
+ }
+ }
+
+ if(options::produceAssignments() && !options::produceModels()) {
+ Notice() << "SmtEngine: turning on produce-models to support produce-assignments" << endl;
+ setOption("produce-models", SExpr("true"));
+ }
// Set the options for the theoryOf
if(!options::theoryOfMode.wasSetByUser()) {
@@ -966,7 +943,7 @@ void SmtEngine::setLogicInternal() throw() {
options::fmfBoundInt.set( true );
Trace("smt") << "turning on fmf-bound-int, for strings-exp" << std::endl;
}
- /*
+ /*
if(! options::rewriteDivk.wasSetByUser()) {
options::rewriteDivk.set( true );
Trace("smt") << "turning on rewrite-divk, for strings-exp" << std::endl;
@@ -1068,7 +1045,7 @@ void SmtEngine::setLogicInternal() throw() {
if(! options::unconstrainedSimp.wasSetByUser() || options::incrementalSolving()) {
// bool qf_sat = d_logic.isPure(THEORY_BOOL) && !d_logic.isQuantified();
// bool uncSimp = false && !qf_sat && !options::incrementalSolving();
- bool uncSimp = !options::incrementalSolving() && !d_logic.isQuantified() && !options::produceModels() && !options::checkModels() &&
+ bool uncSimp = !options::incrementalSolving() && !d_logic.isQuantified() && !options::produceModels() && !options::produceAssignments() && !options::checkModels() &&
(d_logic.isTheoryEnabled(THEORY_ARRAY) && d_logic.isTheoryEnabled(THEORY_BV));
Trace("smt") << "setting unconstrained simplification to " << uncSimp << endl;
options::unconstrainedSimp.set(uncSimp);
@@ -1079,6 +1056,10 @@ void SmtEngine::setLogicInternal() throw() {
Notice() << "SmtEngine: turning off produce-models to support unconstrainedSimp" << endl;
setOption("produce-models", SExpr("false"));
}
+ if (options::produceAssignments()) {
+ Notice() << "SmtEngine: turning off produce-assignments to support unconstrainedSimp" << endl;
+ setOption("produce-assignments", SExpr("false"));
+ }
if (options::checkModels()) {
Notice() << "SmtEngine: turning off check-models to support unconstrainedSimp" << endl;
setOption("check-models", SExpr("false"));
@@ -1188,7 +1169,7 @@ void SmtEngine::setLogicInternal() throw() {
//instantiate only on last call
if( options::fmfInstEngine() ){
Trace("smt") << "setting inst when mode to LAST_CALL" << endl;
- options::instWhenMode.set( INST_WHEN_LAST_CALL );
+ options::instWhenMode.set( quantifiers::INST_WHEN_LAST_CALL );
}
}
if ( options::fmfBoundInt() ){
@@ -1214,7 +1195,7 @@ void SmtEngine::setLogicInternal() throw() {
//until bugs 371,431 are fixed
if( ! options::minisatUseElim.wasSetByUser()){
- if( d_logic.isQuantified() || options::produceModels() || options::checkModels() ){
+ if( d_logic.isQuantified() || options::produceModels() || options::produceAssignments() || options::checkModels() ){
options::minisatUseElim.set( false );
}
}
@@ -1223,6 +1204,10 @@ void SmtEngine::setLogicInternal() throw() {
Notice() << "SmtEngine: turning off produce-models to support minisatUseElim" << endl;
setOption("produce-models", SExpr("false"));
}
+ if (options::produceAssignments()) {
+ Notice() << "SmtEngine: turning off produce-assignments to support minisatUseElim" << endl;
+ setOption("produce-assignments", SExpr("false"));
+ }
if (options::checkModels()) {
Notice() << "SmtEngine: turning off check-models to support minisatUseElim" << endl;
setOption("check-models", SExpr("false"));
@@ -1230,7 +1215,7 @@ void SmtEngine::setLogicInternal() throw() {
}
// For now, these array theory optimizations do not support model-building
- if (options::produceModels() || options::checkModels()) {
+ if (options::produceModels() || options::produceAssignments() || options::checkModels()) {
options::arraysOptimizeLinear.set(false);
options::arraysLazyRIntro1.set(false);
}
@@ -1242,6 +1227,10 @@ void SmtEngine::setLogicInternal() throw() {
Warning() << "SmtEngine: turning off produce-models because unsupported for nonlinear arith" << endl;
setOption("produce-models", SExpr("false"));
}
+ if (options::produceAssignments()) {
+ Warning() << "SmtEngine: turning off produce-assignments because unsupported for nonlinear arith" << endl;
+ setOption("produce-assignments", SExpr("false"));
+ }
if (options::checkModels()) {
Warning() << "SmtEngine: turning off check-models because unsupported for nonlinear arith" << endl;
setOption("check-models", SExpr("false"));
@@ -1470,55 +1459,6 @@ void SmtEngine::defineFunction(Expr func,
}
-Node SmtEnginePrivate::getBVDivByZero(Kind k, unsigned width) {
- NodeManager* nm = d_smt.d_nodeManager;
- if (k == kind::BITVECTOR_UDIV) {
- if (d_BVDivByZero.find(width) == d_BVDivByZero.end()) {
- // lazily create the function symbols
- ostringstream os;
- os << "BVUDivByZero_" << width;
- Node divByZero = nm->mkSkolem(os.str(),
- nm->mkFunctionType(nm->mkBitVectorType(width), nm->mkBitVectorType(width)),
- "partial bvudiv", NodeManager::SKOLEM_EXACT_NAME);
- d_BVDivByZero[width] = divByZero;
- }
- return d_BVDivByZero[width];
- }
- else if (k == kind::BITVECTOR_UREM) {
- if (d_BVRemByZero.find(width) == d_BVRemByZero.end()) {
- ostringstream os;
- os << "BVURemByZero_" << width;
- Node divByZero = nm->mkSkolem(os.str(),
- nm->mkFunctionType(nm->mkBitVectorType(width), nm->mkBitVectorType(width)),
- "partial bvurem", NodeManager::SKOLEM_EXACT_NAME);
- d_BVRemByZero[width] = divByZero;
- }
- return d_BVRemByZero[width];
- }
-
- Unreachable();
-}
-
-
-Node SmtEnginePrivate::expandBVDivByZero(TNode n) {
- // we only deal wioth the unsigned division operators as the signed ones should have been
- // expanded in terms of the unsigned operators
- NodeManager* nm = d_smt.d_nodeManager;
- unsigned width = n.getType().getBitVectorSize();
- Node divByZero = getBVDivByZero(n.getKind(), width);
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(BitVector(width, Integer(0))));
- Node divByZeroNum = nm->mkNode(kind::APPLY_UF, divByZero, num);
- Node divTotalNumDen = nm->mkNode(n.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL :
- kind::BITVECTOR_UREM_TOTAL, num, den);
- Node node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
- if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
- d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
- d_smt.d_logic.enableTheory(THEORY_UF);
- d_smt.d_logic.lock();
- }
- return node;
-}
Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashFunction>& cache)
@@ -1527,31 +1467,36 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF
stack< triple<Node, Node, bool> > worklist;
stack<Node> result;
worklist.push(make_triple(Node(n), Node(n), false));
+ // The worklist is made of triples, each is input / original node then the output / rewritten node
+ // and finally a flag tracking whether the children have been explored (i.e. if this is a downward
+ // or upward pass).
do {
- n = worklist.top().first;
- Node node = worklist.top().second;
+ n = worklist.top().first; // n is the input / original
+ Node node = worklist.top().second; // node is the output / result
bool childrenPushed = worklist.top().third;
worklist.pop();
+ // Working downwards
if(!childrenPushed) {
Kind k = n.getKind();
+ // Apart from apply, we can short circuit leaves
if(k != kind::APPLY && n.getNumChildren() == 0) {
- SmtEngine::DefinedFunctionMap::const_iterator i = d_smt.d_definedFunctions->find(n);
- if(i != d_smt.d_definedFunctions->end()) {
- // 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()));
- continue;
- }
- // don't bother putting in the cache
- result.push((*i).second.getFormula());
- continue;
- }
- // don't bother putting in the cache
- result.push(n);
- continue;
+ SmtEngine::DefinedFunctionMap::const_iterator i = d_smt.d_definedFunctions->find(n);
+ if(i != d_smt.d_definedFunctions->end()) {
+ // 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()));
+ continue;
+ }
+ // don't bother putting in the cache
+ result.push((*i).second.getFormula());
+ continue;
+ }
+ // don't bother putting in the cache
+ result.push(n);
+ continue;
}
// maybe it's in the cache
@@ -1563,134 +1508,7 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF
}
// otherwise expand it
-
- NodeManager* nm = d_smt.d_nodeManager;
- // FIXME: this theory-specific code should be factored out of the
- // SmtEngine, somehow
- switch(k) {
- case kind::BITVECTOR_SDIV:
- case kind::BITVECTOR_SREM:
- case kind::BITVECTOR_SMOD:
- node = bv::TheoryBVRewriter::eliminateBVSDiv(node);
- break;
-
- case kind::BITVECTOR_UDIV:
- case kind::BITVECTOR_UREM:
- node = expandBVDivByZero(node);
- break;
-
- case kind::STRING_CHARAT: {
- if(d_ufSubstr.isNull()) {
- std::vector< TypeNode > argTypes;
- argTypes.push_back(NodeManager::currentNM()->stringType());
- argTypes.push_back(NodeManager::currentNM()->integerType());
- argTypes.push_back(NodeManager::currentNM()->integerType());
- d_ufSubstr = NodeManager::currentNM()->mkSkolem("__ufSS",
- NodeManager::currentNM()->mkFunctionType(
- argTypes, NodeManager::currentNM()->stringType()),
- "uf substr",
- NodeManager::SKOLEM_EXACT_NAME);
- }
- Node lenxgti = NodeManager::currentNM()->mkNode( kind::GT,
- NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n[0] ), n[1] );
- Node zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
- Node t1greq0 = NodeManager::currentNM()->mkNode( kind::GEQ, n[1], zero);
- Node cond = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, lenxgti, t1greq0 ));
- Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
- Node totalf = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, n[0], n[1], one);
- Node uf = NodeManager::currentNM()->mkNode(kind::APPLY_UF, d_ufSubstr, n[0], n[1], one);
- node = NodeManager::currentNM()->mkNode( kind::ITE, cond, totalf, uf );
- break;
- }
- case kind::STRING_SUBSTR: {
- if(d_ufSubstr.isNull()) {
- std::vector< TypeNode > argTypes;
- argTypes.push_back(NodeManager::currentNM()->stringType());
- argTypes.push_back(NodeManager::currentNM()->integerType());
- argTypes.push_back(NodeManager::currentNM()->integerType());
- d_ufSubstr = NodeManager::currentNM()->mkSkolem("__ufSS",
- NodeManager::currentNM()->mkFunctionType(
- argTypes, NodeManager::currentNM()->stringType()),
- "uf substr",
- NodeManager::SKOLEM_EXACT_NAME);
- }
- Node lenxgti = NodeManager::currentNM()->mkNode( kind::GEQ,
- NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n[0] ),
- NodeManager::currentNM()->mkNode( kind::PLUS, n[1], n[2] ) );
- Node zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
- Node t1geq0 = NodeManager::currentNM()->mkNode(kind::GEQ, n[1], zero);
- Node t2geq0 = NodeManager::currentNM()->mkNode(kind::GEQ, n[2], zero);
- Node cond = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, lenxgti, t1geq0, t2geq0 ));
- Node totalf = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, n[0], n[1], n[2]);
- Node uf = NodeManager::currentNM()->mkNode(kind::APPLY_UF, d_ufSubstr, n[0], n[1], n[2]);
- node = NodeManager::currentNM()->mkNode( kind::ITE, cond, totalf, uf );
- break;
- }
- case kind::DIVISION: {
- // partial function: division
- if(d_divByZero.isNull()) {
- d_divByZero = nm->mkSkolem("divByZero", nm->mkFunctionType(nm->realType(), nm->realType()),
- "partial real division", NodeManager::SKOLEM_EXACT_NAME);
- if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
- d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
- d_smt.d_logic.enableTheory(THEORY_UF);
- d_smt.d_logic.lock();
- }
- }
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
- Node divByZeroNum = nm->mkNode(kind::APPLY_UF, d_divByZero, num);
- Node divTotalNumDen = nm->mkNode(kind::DIVISION_TOTAL, num, den);
- node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
- break;
- }
-
- case kind::INTS_DIVISION: {
- // partial function: integer div
- if(d_intDivByZero.isNull()) {
- d_intDivByZero = nm->mkSkolem("intDivByZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
- "partial integer division", NodeManager::SKOLEM_EXACT_NAME);
- if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
- d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
- d_smt.d_logic.enableTheory(THEORY_UF);
- d_smt.d_logic.lock();
- }
- }
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
- Node intDivByZeroNum = nm->mkNode(kind::APPLY_UF, d_intDivByZero, num);
- Node intDivTotalNumDen = nm->mkNode(kind::INTS_DIVISION_TOTAL, num, den);
- node = nm->mkNode(kind::ITE, den_eq_0, intDivByZeroNum, intDivTotalNumDen);
- break;
- }
-
- case kind::INTS_MODULUS: {
- // partial function: mod
- if(d_modZero.isNull()) {
- d_modZero = nm->mkSkolem("modZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
- "partial modulus", NodeManager::SKOLEM_EXACT_NAME);
- if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
- d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
- d_smt.d_logic.enableTheory(THEORY_UF);
- d_smt.d_logic.lock();
- }
- }
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
- Node modZeroNum = nm->mkNode(kind::APPLY_UF, d_modZero, num);
- Node modTotalNumDen = nm->mkNode(kind::INTS_MODULUS_TOTAL, num, den);
- node = nm->mkNode(kind::ITE, den_eq_0, modZeroNum, modTotalNumDen);
- break;
- }
-
- case kind::ABS: {
- Node out = nm->mkNode(kind::ITE, nm->mkNode(kind::LT, node[0], nm->mkConst(Rational(0))), nm->mkNode(kind::UMINUS, node[0]), node[0]);
- cache[n] = out;
- result.push(out);
- continue;
- }
-
- case kind::APPLY: {
+ if (k == kind::APPLY) {
// application of a user-defined symbol
TNode func = n.getOperator();
SmtEngine::DefinedFunctionMap::const_iterator i =
@@ -1729,25 +1547,35 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF
cache[n] = (n == expanded ? Node::null() : expanded);
result.push(expanded);
continue;
- }
- default:
- // unknown kind for expansion, just iterate over the children
- node = n;
+ } else {
+ theory::Theory* t = d_smt.d_theoryEngine->theoryOf(node);
+
+ Assert(t != NULL);
+ LogicRequest req(d_smt);
+ node = t->expandDefinition(req, n);
}
// there should be children here, otherwise we short-circuited a result-push/continue, above
+ if (node.getNumChildren() == 0) {
+ Debug("expand") << "Unexpectedly no children..." << node << endl;
+ }
+ // This invariant holds at the moment but it is concievable that a new theory
+ // might introduce a kind which can have children before definition expansion but doesn't
+ // afterwards. If this happens, remove this assertion.
Assert(node.getNumChildren() > 0);
// the partial functions can fall through, in which case we still
// consider their children
- worklist.push(make_triple(Node(n), node, true));
+ worklist.push(make_triple(Node(n), node, true)); // Original and rewritten result
for(size_t i = 0; i < node.getNumChildren(); ++i) {
- worklist.push(make_triple(node[i], node[i], false));
+ worklist.push(make_triple(node[i], node[i], false)); // Rewrite the children of the result only
}
} else {
+ // Working upwards
+ // Reconstruct the node from it's (now rewritten) children on the stack
Debug("expand") << "cons : " << node << endl;
//cout << "cons : " << node << endl;
@@ -1766,7 +1594,7 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF
nb << expanded;
}
node = nb;
- cache[n] = n == node ? Node::null() : node;
+ cache[n] = n == node ? Node::null() : node; // Only cache once all subterms are expanded
result.push(node);
}
} while(!worklist.empty());
@@ -1776,120 +1604,6 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF
return result.top();
}
-
-struct ContainsQuantAttributeId {};
-typedef expr::Attribute<ContainsQuantAttributeId, uint64_t> ContainsQuantAttribute;
-
-// check if the given node contains a universal quantifier
-static bool containsQuantifiers(Node n) {
- if( n.hasAttribute(ContainsQuantAttribute()) ){
- return n.getAttribute(ContainsQuantAttribute())==1;
- } else if(n.getKind() == kind::FORALL) {
- return true;
- } else {
- bool cq = false;
- for( unsigned i = 0; i < n.getNumChildren(); ++i ){
- if( containsQuantifiers(n[i]) ){
- cq = true;
- break;
- }
- }
- ContainsQuantAttribute cqa;
- n.setAttribute(cqa, cq ? 1 : 0);
- return cq;
- }
-}
-
-Node SmtEnginePrivate::preSkolemizeQuantifiers( Node n, bool polarity, std::vector< Node >& fvs ){
- Trace("pre-sk") << "Pre-skolem " << n << " " << polarity << " " << fvs.size() << endl;
- if( n.getKind()==kind::NOT ){
- Node nn = preSkolemizeQuantifiers( n[0], !polarity, fvs );
- return nn.negate();
- }else if( n.getKind()==kind::FORALL ){
- if( polarity ){
- vector< Node > children;
- children.push_back( n[0] );
- //add children to current scope
- vector< Node > fvss;
- fvss.insert( fvss.begin(), fvs.begin(), fvs.end() );
- for( int i=0; i<(int)n[0].getNumChildren(); i++ ){
- fvss.push_back( n[0][i] );
- }
- //process body
- children.push_back( preSkolemizeQuantifiers( n[1], polarity, fvss ) );
- if( n.getNumChildren()==3 ){
- children.push_back( n[2] );
- }
- //return processed quantifier
- return NodeManager::currentNM()->mkNode( kind::FORALL, children );
- }else{
- //process body
- Node nn = preSkolemizeQuantifiers( n[1], polarity, fvs );
- //now, substitute skolems for the variables
- vector< TypeNode > argTypes;
- for( int i=0; i<(int)fvs.size(); i++ ){
- argTypes.push_back( fvs[i].getType() );
- }
- //calculate the variables and substitution
- vector< Node > vars;
- vector< Node > subs;
- for( int i=0; i<(int)n[0].getNumChildren(); i++ ){
- vars.push_back( n[0][i] );
- }
- for( int i=0; i<(int)n[0].getNumChildren(); i++ ){
- //make the new function symbol
- if( argTypes.empty() ){
- Node s = NodeManager::currentNM()->mkSkolem( "sk_$$", n[0][i].getType(), "created during pre-skolemization" );
- subs.push_back( s );
- }else{
- TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, n[0][i].getType() );
- Node op = NodeManager::currentNM()->mkSkolem( "skop_$$", typ, "op created during pre-skolemization" );
- //DOTHIS: set attribute on op, marking that it should not be selected as trigger
- vector< Node > funcArgs;
- funcArgs.push_back( op );
- funcArgs.insert( funcArgs.end(), fvs.begin(), fvs.end() );
- subs.push_back( NodeManager::currentNM()->mkNode( kind::APPLY_UF, funcArgs ) );
- }
- }
- //apply substitution
- nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
- return nn;
- }
- }else{
- //check if it contains a quantifier as a subterm
- //if so, we will write this node
- if( containsQuantifiers( n ) ){
- if( n.getType().isBoolean() ){
- if( n.getKind()==kind::ITE || n.getKind()==kind::IFF || n.getKind()==kind::XOR || n.getKind()==kind::IMPLIES ){
- Node nn;
- //must remove structure
- if( n.getKind()==kind::ITE ){
- nn = NodeManager::currentNM()->mkNode( kind::AND,
- NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n[1] ),
- NodeManager::currentNM()->mkNode( kind::OR, n[0], n[2] ) );
- }else if( n.getKind()==kind::IFF || n.getKind()==kind::XOR ){
- nn = NodeManager::currentNM()->mkNode( kind::AND,
- NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n.getKind()==kind::XOR ? n[1].notNode() : n[1] ),
- NodeManager::currentNM()->mkNode( kind::OR, n[0], n.getKind()==kind::XOR ? n[1] : n[1].notNode() ) );
- }else if( n.getKind()==kind::IMPLIES ){
- nn = NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n[1] );
- }
- return preSkolemizeQuantifiers( nn, polarity, fvs );
- }else if( n.getKind()==kind::AND || n.getKind()==kind::OR ){
- vector< Node > children;
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- children.push_back( preSkolemizeQuantifiers( n[i], polarity, fvs ) );
- }
- return NodeManager::currentNM()->mkNode( n.getKind(), children );
- }else{
- //must pull ite's
- }
- }
- }
- return n;
- }
-}
-
void SmtEnginePrivate::removeITEs() {
d_smt.finalOptionsAreSet();
@@ -3156,13 +2870,25 @@ void SmtEnginePrivate::processAssertions() {
dumpAssertions("post-strings-pp", d_assertionsToPreprocess);
}
if( d_smt.d_logic.isQuantified() ){
+ //remove rewrite rules
+ for( unsigned i=0; i < d_assertionsToPreprocess.size(); i++ ) {
+ if( d_assertionsToPreprocess[i].getKind() == kind::REWRITE_RULE ){
+ Node prev = d_assertionsToPreprocess[i];
+ Trace("quantifiers-rewrite-debug") << "Rewrite rewrite rule " << prev << "..." << std::endl;
+ d_assertionsToPreprocess[i] = Rewriter::rewrite( quantifiers::QuantifiersRewriter::rewriteRewriteRule( d_assertionsToPreprocess[i] ) );
+ Trace("quantifiers-rewrite") << "*** rr-rewrite " << prev << endl;
+ Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess[i] << endl;
+ }
+ }
+
dumpAssertions("pre-skolem-quant", d_assertionsToPreprocess);
if( options::preSkolemQuant() ){
//apply pre-skolemization to existential quantifiers
for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
Node prev = d_assertionsToPreprocess[i];
+ Trace("quantifiers-rewrite-debug") << "Pre-skolemize " << prev << "..." << std::endl;
vector< Node > fvs;
- d_assertionsToPreprocess[i] = Rewriter::rewrite( preSkolemizeQuantifiers( d_assertionsToPreprocess[i], true, fvs ) );
+ d_assertionsToPreprocess[i] = Rewriter::rewrite( quantifiers::QuantifiersRewriter::preSkolemizeQuantifiers( prev, true, fvs ) );
if( prev!=d_assertionsToPreprocess[i] ){
Trace("quantifiers-rewrite") << "*** Pre-skolemize " << prev << endl;
Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess[i] << endl;
@@ -3174,14 +2900,14 @@ void SmtEnginePrivate::processAssertions() {
//quantifiers macro expansion
bool success;
do{
- QuantifierMacros qm;
+ quantifiers::QuantifierMacros qm;
success = qm.simplify( d_assertionsToPreprocess, true );
}while( success );
}
Trace("fo-rsn-enable") << std::endl;
if( options::foPropQuant() ){
- FirstOrderPropagation fop;
+ quantifiers::FirstOrderPropagation fop;
fop.simplify( d_assertionsToPreprocess );
}
}
@@ -3677,8 +3403,15 @@ Expr SmtEngine::getValue(const Expr& ex) const throw(ModalException, TypeCheckin
// Expand, then normalize
hash_map<Node, Node, NodeHashFunction> cache;
n = d_private->expandDefinitions(n, cache);
- n = d_private->rewriteBooleanTerms(n);
- n = Rewriter::rewrite(n);
+ // There are two ways model values for terms are computed (for historical
+ // reasons). One way is that used in check-model; the other is that
+ // used by the Model classes. It's not clear to me exactly how these
+ // two are different, but they need to be unified. This ugly hack here
+ // is to fix bug 554 until we can revamp boolean-terms and models [MGD]
+ if(!n.getType().isFunction()) {
+ n = d_private->rewriteBooleanTerms(n);
+ n = Rewriter::rewrite(n);
+ }
Trace("smt") << "--- getting value of " << n << endl;
TheoryModel* m = d_theoryEngine->getModel();
@@ -3970,28 +3703,30 @@ void SmtEngine::checkModel(bool hardFailure) {
Debug("boolean-terms") << "++ got " << n << endl;
Notice() << "SmtEngine::checkModel(): -- substitutes to " << n << endl;
- if(Theory::theoryOf(n) != THEORY_REWRITERULES) {
+ //AJR : FIXME need to ignore quantifiers too?
+ if( n.getKind() != kind::REWRITE_RULE ){
// In case it's a quantifier (or contains one), look up its value before
// simplifying, or the quantifier might be irreparably altered.
n = m->getValue(n);
- }
-
- // Simplify the result.
- n = d_private->simplify(n);
- Notice() << "SmtEngine::checkModel(): -- simplifies to " << n << endl;
-
- TheoryId thy = Theory::theoryOf(n);
- if(thy == THEORY_REWRITERULES) {
+ } else {
// Note this "skip" is done here, rather than above. This is
// because (1) the quantifier could in principle simplify to false,
// which should be reported, and (2) checking for the quantifier
// above, before simplification, doesn't catch buried quantifiers
// anyway (those not at the top-level).
- Notice() << "SmtEngine::checkModel(): -- skipping rewrite-rules assertion"
+ Notice() << "SmtEngine::checkModel(): -- skipping quantifiers/rewrite-rules assertion"
<< endl;
continue;
}
+ // Simplify the result.
+ n = d_private->simplify(n);
+ Notice() << "SmtEngine::checkModel(): -- simplifies to " << n << endl;
+
+ // Replace the already-known ITEs (this is important for ground ITEs under quantifiers).
+ n = d_private->d_iteRemover.replace(n);
+ Notice() << "SmtEngine::checkModel(): -- ite replacement gives " << n << endl;
+
// As a last-ditch effort, ask model to simplify it.
// Presently, this is only an issue for quantifiers, which can have a value
// but don't show up in our substitution map above.
diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h
index c34d3ecba..2991ab21b 100644
--- a/src/smt/smt_engine.h
+++ b/src/smt/smt_engine.h
@@ -30,7 +30,6 @@
#include "util/proof.h"
#include "smt/modal_exception.h"
#include "smt/logic_exception.h"
-#include "util/hash.h"
#include "options/options.h"
#include "util/result.h"
#include "util/sexpr.h"
@@ -59,6 +58,7 @@ class TheoryEngine;
class ProofManager;
class Model;
+class LogicRequest;
class StatisticsRegistry;
namespace context {
@@ -281,6 +281,12 @@ class CVC4_PUBLIC SmtEngine {
void finalOptionsAreSet();
/**
+ * Apply heuristics settings and other defaults. Done once, at
+ * finishInit() time.
+ */
+ void setDefaults();
+
+ /**
* Create theory engine, prop engine, decision engine. Called by
* finalOptionsAreSet()
*/
@@ -331,6 +337,7 @@ class CVC4_PUBLIC SmtEngine {
friend ::CVC4::StatisticsRegistry* ::CVC4::stats::getStatisticsRegistry(SmtEngine*);
friend void ::CVC4::smt::beforeSearch(std::string, bool, SmtEngine*) throw(ModalException);
friend ProofManager* ::CVC4::smt::currentProofManager();
+ friend class ::CVC4::LogicRequest;
// to access d_modelCommands
friend class ::CVC4::Model;
friend class ::CVC4::theory::TheoryModel;
diff --git a/src/smt/smt_options_template.cpp b/src/smt/smt_options_template.cpp
index 4edd91a8d..987d2e3c7 100644
--- a/src/smt/smt_options_template.cpp
+++ b/src/smt/smt_options_template.cpp
@@ -62,11 +62,15 @@ void SmtEngine::setOption(const std::string& key, const CVC4::SExpr& value)
throw OptionException("command-verbosity value must be a tuple (command-name, integer)");
}
+ if(!value.isAtom()) {
+ throw OptionException("bad value for :" + key);
+ }
+
string optionarg = value.getValue();
${smt_setoption_handlers}
-#line 70 "${template}"
+#line 74 "${template}"
throw UnrecognizedOptionException(key);
}
@@ -126,7 +130,7 @@ CVC4::SExpr SmtEngine::getOption(const std::string& key) const
${smt_getoption_handlers}
-#line 130 "${template}"
+#line 134 "${template}"
throw UnrecognizedOptionException(key);
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback