From 65798541fa437278cde0c759ab70fd9fa4fe9638 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Thu, 12 Jul 2012 18:30:15 +0000 Subject: [PATCH] merged fmf-devel branch, includes support for SMT2 command get-value and (extended) SMT command get-model. added collectModelInfo and removed getValue from theory interface. merge also includes major updates to finite model finding module (from CASC), added fmf options, some updates to strong solver and quantifiers engine interface. The test recursion_breaker_black currently fails for me on production builds, Morgan is planning to look into this. --- README.fmf-devel | 1 + src/expr/command.cpp | 50 +- src/expr/command.h | 18 +- src/parser/cvc/Cvc.g | 4 +- src/parser/smt/Smt.g | 8 +- src/parser/smt2/Smt2.g | 8 +- src/parser/tptp/tptp.h | 12 +- src/printer/smt2/smt2_printer.cpp | 12 +- src/smt/smt_engine.cpp | 81 +- src/smt/smt_engine.h | 25 + src/theory/Makefile.am | 4 +- src/theory/arith/theory_arith.cpp | 83 +- src/theory/arith/theory_arith.h | 2 +- .../arith/theory_arith_instantiator.cpp | 21 +- src/theory/arith/theory_arith_instantiator.h | 6 +- src/theory/arrays/theory_arrays.cpp | 30 +- src/theory/arrays/theory_arrays.h | 8 +- .../arrays/theory_arrays_instantiator.cpp | 31 +- .../arrays/theory_arrays_instantiator.h | 8 +- src/theory/booleans/theory_bool.cpp | 100 +- src/theory/booleans/theory_bool.h | 3 +- src/theory/builtin/theory_builtin.cpp | 33 +- src/theory/builtin/theory_builtin.h | 2 +- src/theory/bv/theory_bv.cpp | 54 +- src/theory/bv/theory_bv.h | 10 +- src/theory/datatypes/theory_datatypes.cpp | 80 +- src/theory/datatypes/theory_datatypes.h | 10 +- .../theory_datatypes_instantiator.cpp | 26 +- .../datatypes/theory_datatypes_instantiator.h | 10 +- src/theory/example/theory_uf_tim.h | 5 +- src/theory/inst_match.cpp | 167 +- src/theory/inst_match.h | 35 +- src/theory/instantiator_default.cpp | 4 +- src/theory/instantiator_default.h | 2 +- src/theory/model.cpp | 436 +++++ src/theory/model.h | 165 ++ src/theory/quantifiers/Makefile.am | 10 +- src/theory/quantifiers/first_order_model.cpp | 146 ++ src/theory/quantifiers/first_order_model.h | 82 + .../quantifiers/instantiation_engine.cpp | 156 +- src/theory/quantifiers/instantiation_engine.h | 7 +- src/theory/quantifiers/model_engine.cpp | 1667 +++++------------ src/theory/quantifiers/model_engine.h | 366 +--- src/theory/quantifiers/relevant_domain.cpp | 173 ++ src/theory/quantifiers/relevant_domain.h | 54 + src/theory/quantifiers/rep_set_iterator.cpp | 523 ++++++ src/theory/quantifiers/rep_set_iterator.h | 120 ++ src/theory/quantifiers/term_database.cpp | 324 ++++ src/theory/quantifiers/term_database.h | 151 ++ src/theory/quantifiers/theory_quantifiers.cpp | 27 +- src/theory/quantifiers/theory_quantifiers.h | 3 + .../theory_quantifiers_instantiator.cpp | 2 +- .../theory_quantifiers_instantiator.h | 2 +- src/theory/quantifiers_engine.cpp | 454 ++--- src/theory/quantifiers_engine.h | 194 +- .../rewriterules/theory_rewriterules.cpp | 19 +- src/theory/rewriterules/theory_rewriterules.h | 3 + .../theory_rewriterules_rules.cpp | 4 +- src/theory/shared_terms_database.h | 20 +- src/theory/theory.cpp | 64 +- src/theory/theory.h | 64 +- src/theory/theory_engine.cpp | 149 +- src/theory/theory_engine.h | 49 +- src/theory/trigger.cpp | 4 +- src/theory/trigger.h | 2 +- src/theory/uf/Makefile.am | 4 +- src/theory/uf/inst_strategy.cpp | 51 +- src/theory/uf/inst_strategy.h | 20 +- src/theory/uf/kinds | 44 +- src/theory/uf/theory_uf.cpp | 5 + src/theory/uf/theory_uf.h | 6 +- .../uf/theory_uf_candidate_generator.cpp | 21 +- src/theory/uf/theory_uf_instantiator.cpp | 24 +- src/theory/uf/theory_uf_instantiator.h | 10 +- src/theory/uf/theory_uf_model.cpp | 554 ++++++ src/theory/uf/theory_uf_model.h | 216 +++ src/theory/uf/theory_uf_strong_solver.cpp | 427 +++-- src/theory/uf/theory_uf_strong_solver.h | 59 +- src/theory/uf/theory_uf_type_rules.h | 64 +- src/theory/valuation.cpp | 5 - src/theory/valuation.h | 2 - src/util/Makefile.am | 4 +- src/util/dump.h | 2 +- src/util/model.cpp | 15 + src/util/model.h | 42 + src/util/options.cpp | 113 +- src/util/options.h | 43 +- 87 files changed, 5218 insertions(+), 2906 deletions(-) create mode 100644 README.fmf-devel create mode 100644 src/theory/model.cpp create mode 100644 src/theory/model.h create mode 100644 src/theory/quantifiers/first_order_model.cpp create mode 100644 src/theory/quantifiers/first_order_model.h create mode 100644 src/theory/quantifiers/relevant_domain.cpp create mode 100644 src/theory/quantifiers/relevant_domain.h create mode 100644 src/theory/quantifiers/rep_set_iterator.cpp create mode 100644 src/theory/quantifiers/rep_set_iterator.h create mode 100644 src/theory/quantifiers/term_database.cpp create mode 100644 src/theory/quantifiers/term_database.h create mode 100644 src/theory/uf/theory_uf_model.cpp create mode 100644 src/theory/uf/theory_uf_model.h create mode 100644 src/util/model.cpp create mode 100644 src/util/model.h diff --git a/README.fmf-devel b/README.fmf-devel new file mode 100644 index 000000000..e35bcab5b --- /dev/null +++ b/README.fmf-devel @@ -0,0 +1 @@ +This branch is used for development of the finite model finding mode of CVC4. diff --git a/src/expr/command.cpp b/src/expr/command.cpp index 8b7f1bfa4..5b889712d 100644 --- a/src/expr/command.cpp +++ b/src/expr/command.cpp @@ -456,8 +456,9 @@ std::string DeclarationDefinitionCommand::getSymbol() const throw() { /* class DeclareFunctionCommand */ -DeclareFunctionCommand::DeclareFunctionCommand(const std::string& id, Type t) throw() : +DeclareFunctionCommand::DeclareFunctionCommand(const std::string& id, Expr func, Type t) throw() : DeclarationDefinitionCommand(id), + d_func(func), d_type(t) { } @@ -467,17 +468,18 @@ Type DeclareFunctionCommand::getType() const throw() { void DeclareFunctionCommand::invoke(SmtEngine* smtEngine) throw() { Dump("declarations") << *this; + smtEngine->addToModelFunction( d_func ); d_commandStatus = CommandSuccess::instance(); } Command* DeclareFunctionCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) { - return new DeclareFunctionCommand(d_symbol, + return new DeclareFunctionCommand(d_symbol, d_func.exportTo(exprManager, variableMap), d_type.exportTo(exprManager, variableMap)); } Command* DeclareFunctionCommand::clone() const { - return new DeclareFunctionCommand(d_symbol, d_type); + return new DeclareFunctionCommand(d_symbol, d_func, d_type); } /* class DeclareTypeCommand */ @@ -498,6 +500,7 @@ Type DeclareTypeCommand::getType() const throw() { void DeclareTypeCommand::invoke(SmtEngine* smtEngine) throw() { Dump("declarations") << *this; + smtEngine->addToModelType( d_type ); d_commandStatus = CommandSuccess::instance(); } @@ -762,6 +765,47 @@ Command* GetAssignmentCommand::clone() const { return c; } +/* class GetModelCommand */ + +GetModelCommand::GetModelCommand() throw() { +} + +void GetModelCommand::invoke(SmtEngine* smtEngine) throw() { + try { + d_result = smtEngine->getModel(); + d_smtEngine = smtEngine; + d_commandStatus = CommandSuccess::instance(); + } catch(exception& e) { + d_commandStatus = new CommandFailure(e.what()); + } +} + +Model* GetModelCommand::getResult() const throw() { + return d_result; +} + +void GetModelCommand::printResult(std::ostream& out) const throw() { + if(! ok()) { + this->Command::printResult(out); + } else { + d_smtEngine->printModel( out, d_result ); + } +} + +Command* GetModelCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) { + GetModelCommand* c = new GetModelCommand(); + c->d_result = d_result; + c->d_smtEngine = d_smtEngine; + return c; +} + +Command* GetModelCommand::clone() const { + GetModelCommand* c = new GetModelCommand(); + c->d_result = d_result; + c->d_smtEngine = d_smtEngine; + return c; +} + /* class GetProofCommand */ GetProofCommand::GetProofCommand() throw() { diff --git a/src/expr/command.h b/src/expr/command.h index 98046c242..123fe0182 100644 --- a/src/expr/command.h +++ b/src/expr/command.h @@ -37,6 +37,7 @@ #include "util/sexpr.h" #include "util/datatype.h" #include "util/proof.h" +#include "util/model.h" namespace CVC4 { @@ -316,9 +317,10 @@ public: class CVC4_PUBLIC DeclareFunctionCommand : public DeclarationDefinitionCommand { protected: + Expr d_func; Type d_type; public: - DeclareFunctionCommand(const std::string& id, Type type) throw(); + DeclareFunctionCommand(const std::string& id, Expr func, Type type) throw(); ~DeclareFunctionCommand() throw() {} Type getType() const throw(); void invoke(SmtEngine* smtEngine) throw(); @@ -462,6 +464,20 @@ public: Command* clone() const; };/* class GetAssignmentCommand */ +class CVC4_PUBLIC GetModelCommand : public Command { +protected: + Model* d_result; + SmtEngine* d_smtEngine; +public: + GetModelCommand() throw(); + ~GetModelCommand() throw() {} + void invoke(SmtEngine* smtEngine) throw(); + Model* getResult() const throw(); + void printResult(std::ostream& out) const throw(); + Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap); + Command* clone() const; +};/* class GetModelCommand */ + class CVC4_PUBLIC GetProofCommand : public Command { protected: Proof* d_result; diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g index 55e10724b..bbeee4f7f 100644 --- a/src/parser/cvc/Cvc.g +++ b/src/parser/cvc/Cvc.g @@ -922,9 +922,9 @@ declareVariables[CVC4::Command*& cmd, CVC4::Type& t, const std::vectormkVar(*i, t); + Expr func = PARSER_STATE->mkVar(*i, t); if(topLevel) { - Command* decl = new DeclareFunctionCommand(*i, t); + Command* decl = new DeclareFunctionCommand(*i, func, t); seq->addCommand(decl); } } diff --git a/src/parser/smt/Smt.g b/src/parser/smt/Smt.g index d44f7abcb..429adee0a 100644 --- a/src/parser/smt/Smt.g +++ b/src/parser/smt/Smt.g @@ -470,8 +470,8 @@ functionDeclaration[CVC4::Command*& smt_command] } else { t = EXPR_MANAGER->mkFunctionType(sorts); } - PARSER_STATE->mkVar(name, t); - smt_command = new DeclareFunctionCommand(name, t); + Expr func = PARSER_STATE->mkVar(name, t); + smt_command = new DeclareFunctionCommand(name, func, t); } ; @@ -490,8 +490,8 @@ predicateDeclaration[CVC4::Command*& smt_command] } else { t = EXPR_MANAGER->mkPredicateType(p_sorts); } - PARSER_STATE->mkVar(name, t); - smt_command = new DeclareFunctionCommand(name, t); + Expr func = PARSER_STATE->mkVar(name, t); + smt_command = new DeclareFunctionCommand(name, func, t); } ; diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g index 84d75ceac..577438d37 100644 --- a/src/parser/smt2/Smt2.g +++ b/src/parser/smt2/Smt2.g @@ -240,8 +240,8 @@ command returns [CVC4::Command* cmd = NULL] if( sorts.size() > 0 ) { t = EXPR_MANAGER->mkFunctionType(sorts, t); } - PARSER_STATE->mkVar(name, t); - $cmd = new DeclareFunctionCommand(name, t); } + Expr func = PARSER_STATE->mkVar(name, t); + $cmd = new DeclareFunctionCommand(name, func, t); } | /* function definition */ DEFINE_FUN_TOK { PARSER_STATE->checkThatLogicIsSet(); } symbol[name,CHECK_UNDECLARED,SYM_VARIABLE] @@ -383,6 +383,9 @@ extendedCommand[CVC4::Command*& cmd] LPAREN_TOK ( LPAREN_TOK datatypeDef[dts] RPAREN_TOK )+ RPAREN_TOK { PARSER_STATE->popScope(); cmd = new DatatypeDeclarationCommand(PARSER_STATE->mkMutualDatatypeTypes(dts)); } + | /* get model */ + GET_MODEL_TOK { PARSER_STATE->checkThatLogicIsSet(); } + { cmd = new GetModelCommand; } | ECHO_TOK ( simpleSymbolicExpr[sexpr] { std::stringstream ss; @@ -1063,6 +1066,7 @@ POP_TOK : 'pop'; // extended commands DECLARE_DATATYPES_TOK : 'declare-datatypes'; +GET_MODEL_TOK : 'get-model'; ECHO_TOK : 'echo'; // attributes diff --git a/src/parser/tptp/tptp.h b/src/parser/tptp/tptp.h index e6231920d..ae4ad4e7f 100644 --- a/src/parser/tptp/tptp.h +++ b/src/parser/tptp/tptp.h @@ -70,11 +70,11 @@ public: //Conversion from rational to unsorted t = em->mkFunctionType(em->realType(), d_unsorted); d_rtu_op = em->mkVar("$$rtu",t); - preemptCommand(new DeclareFunctionCommand("$$rtu", t)); + preemptCommand(new DeclareFunctionCommand("$$rtu", d_rtu_op, t)); //Conversion from unsorted to rational t = em->mkFunctionType(d_unsorted, em->realType()); d_utr_op = em->mkVar("$$utr",t); - preemptCommand(new DeclareFunctionCommand("$$utur", t)); + preemptCommand(new DeclareFunctionCommand("$$utur", d_utr_op, t)); } // Add the inverse in order to show that over the elements that // appear in the problem there is a bijection between unsorted and @@ -98,11 +98,11 @@ public: //Conversion from string to unsorted t = em->mkFunctionType(em->stringType(), d_unsorted); d_stu_op = em->mkVar("$$stu",t); - preemptCommand(new DeclareFunctionCommand("$$stu", t)); + preemptCommand(new DeclareFunctionCommand("$$stu", d_stu_op, t)); //Conversion from unsorted to string t = em->mkFunctionType(d_unsorted, em->stringType()); d_uts_op = em->mkVar("$$uts",t); - preemptCommand(new DeclareFunctionCommand("$$uts", t)); + preemptCommand(new DeclareFunctionCommand("$$uts", d_uts_op, t)); } // Add the inverse in order to show that over the elements that // appear in the problem there is a bijection between unsorted and @@ -185,7 +185,7 @@ inline void Tptp::makeApplication(Expr & expr, std::string & name, } else { Type t = term ? d_unsorted : getExprManager()->booleanType(); expr = mkVar(name,t,true); //levelZero - preemptCommand(new DeclareFunctionCommand(name, t)); + preemptCommand(new DeclareFunctionCommand(name, expr, t)); } } else { // Its an application if(isDeclared(name)){ //already appeared @@ -195,7 +195,7 @@ inline void Tptp::makeApplication(Expr & expr, std::string & name, Type t = term ? d_unsorted : getExprManager()->booleanType(); t = getExprManager()->mkFunctionType(sorts, t); expr = mkVar(name,t,true); //levelZero - preemptCommand(new DeclareFunctionCommand(name, t)); + preemptCommand(new DeclareFunctionCommand(name, expr, t)); } expr = getExprManager()->mkExpr(kind::APPLY_UF, expr, args); } diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp index e032a9426..7fa00a6e4 100644 --- a/src/printer/smt2/smt2_printer.cpp +++ b/src/printer/smt2/smt2_printer.cpp @@ -126,8 +126,8 @@ void Smt2Printer::toStream(std::ostream& out, TNode n, const Integer& x = bv.getValue(); unsigned n = bv.getSize(); out << "(_ "; - out << "bv" << x <<" " << n; - out << ")"; + out << "bv" << x <<" " << n; + out << ")"; // //out << "#b"; // while(n-- > 0) { @@ -307,6 +307,14 @@ void Smt2Printer::toStream(std::ostream& out, TNode n, // TODO user patterns break; + //function models + case kind::FUNCTION_MODEL: + break; + case kind::FUNCTION_CASE_SPLIT: + break; + case kind::FUNCTION_CASE: + out << "if "; + break; default: // fall back on however the kind prints itself; this probably // won't be SMT-LIB v2 compliant, but it will be clear from the diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp index 08e335717..4cccb8d10 100644 --- a/src/smt/smt_engine.cpp +++ b/src/smt/smt_engine.cpp @@ -59,6 +59,7 @@ #include "theory/theory_traits.h" #include "theory/logic_info.h" #include "util/ite_removal.h" +#include "theory/model.h" using namespace std; using namespace CVC4; @@ -743,7 +744,8 @@ void SmtEngine::setOption(const std::string& key, const SExpr& value) } else if(key == ":produce-unsat-cores") { throw BadOptionException(); } else if(key == ":produce-models") { - throw BadOptionException(); + //throw BadOptionException(); + const_cast( Options::s_current )->produceModels = true; } else if(key == ":produce-assignments") { throw BadOptionException(); } else { @@ -935,7 +937,7 @@ void SmtEnginePrivate::removeITEs() { for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) { d_assertionsToCheck[i] = Rewriter::rewrite(d_assertionsToCheck[i]); } - + } void SmtEnginePrivate::staticLearning() { @@ -1467,7 +1469,7 @@ void SmtEnginePrivate::processAssertions() { expandDefinitions(d_assertionsToPreprocess[i], cache); } } - + // Apply the substitutions we already have, and normalize Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): " << "applying substitutions" << endl; @@ -1766,16 +1768,15 @@ Expr SmtEngine::getValue(const Expr& e) throw ModalException(msg); } if(d_status.isNull() || - d_status.asSatisfiabilityResult() != Result::SAT || + d_status.asSatisfiabilityResult() == Result::UNSAT || d_problemExtended) { const char* msg = - "Cannot get value unless immediately preceded by SAT/INVALID response."; + "Cannot get value unless immediately preceded by SAT/INVALID or UNKNOWN response."; throw ModalException(msg); } - if(type.isFunction() || type.isPredicate() || - type.isKind() || type.isSortConstructor()) { + if(type.isKind() || type.isSortConstructor()) { const char* msg = - "Cannot get value of a function, predicate, or sort."; + "Cannot get value of a sort."; throw ModalException(msg); } @@ -1786,10 +1787,14 @@ Expr SmtEngine::getValue(const Expr& e) n = Rewriter::rewrite(n); Trace("smt") << "--- getting value of " << n << endl; - Node resultNode = d_theoryEngine->getValue(n); - + theory::TheoryModel* m = d_theoryEngine->getModel(); + Node resultNode; + if( m ){ + resultNode = m->getValue( n ); + } + Trace("smt") << "--- got value " << n << " = " << resultNode << endl; // type-check the result we got - Assert(resultNode.isNull() || resultNode.getType() == n.getType()); + Assert(resultNode.isNull() || resultNode.getType().isSubtypeOf( n.getType() )); return Expr(d_exprManager, new Node(resultNode)); } @@ -1835,11 +1840,11 @@ SExpr SmtEngine::getAssignment() throw(ModalException, AssertionException) { throw ModalException(msg); } if(d_status.isNull() || - d_status.asSatisfiabilityResult() != Result::SAT || + d_status.asSatisfiabilityResult() == Result::UNSAT || d_problemExtended) { const char* msg = "Cannot get the current assignment unless immediately " - "preceded by SAT/INVALID response."; + "preceded by SAT/INVALID or UNKNOWN response."; throw ModalException(msg); } @@ -1859,7 +1864,11 @@ SExpr SmtEngine::getAssignment() throw(ModalException, AssertionException) { Node n = Rewriter::rewrite(*i); Trace("smt") << "--- getting value of " << n << endl; - Node resultNode = d_theoryEngine->getValue(n); + theory::TheoryModel* m = d_theoryEngine->getModel(); + Node resultNode; + if( m ){ + resultNode = m->getValue( n ); + } // type-check the result we got Assert(resultNode.isNull() || resultNode.getType() == boolType); @@ -1878,6 +1887,45 @@ SExpr SmtEngine::getAssignment() throw(ModalException, AssertionException) { return SExpr(sexprs); } + +void SmtEngine::addToModelType( Type& t ){ + Trace("smt") << "SMT addToModelType(" << t << ")" << endl; + NodeManagerScope nms(d_nodeManager); + if( Options::current()->produceModels ) { + d_theoryEngine->getModel()->addDefineType( TypeNode::fromType( t ) ); + } +} + +void SmtEngine::addToModelFunction( Expr& e ){ + Trace("smt") << "SMT addToModelFunction(" << e << ")" << endl; + NodeManagerScope nms(d_nodeManager); + if( Options::current()->produceModels ) { + d_theoryEngine->getModel()->addDefineFunction( e.getNode() ); + } +} + + +Model* SmtEngine::getModel() throw(ModalException, AssertionException){ + Trace("smt") << "SMT getModel()" << endl; + NodeManagerScope nms(d_nodeManager); + + if(!Options::current()->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 the current model unless immediately " + "preceded by SAT/INVALID or UNKNOWN response."; + throw ModalException(msg); + } + + return d_theoryEngine->getModel(); +} + Proof* SmtEngine::getProof() throw(ModalException, AssertionException) { Trace("smt") << "SMT getProof()" << endl; NodeManagerScope nms(d_nodeManager); @@ -2063,4 +2111,9 @@ StatisticsRegistry* SmtEngine::getStatisticsRegistry() const { return d_exprManager->d_nodeManager->getStatisticsRegistry(); } +void SmtEngine::printModel( std::ostream& out, Model* m ){ + NodeManagerScope nms(d_nodeManager); + m->toStream(out); +} + }/* CVC4 namespace */ diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h index ae9caf0eb..aef98d75b 100644 --- a/src/smt/smt_engine.h +++ b/src/smt/smt_engine.h @@ -29,6 +29,7 @@ #include "expr/expr.h" #include "expr/expr_manager.h" #include "util/proof.h" +#include "util/model.h" #include "smt/bad_option_exception.h" #include "smt/modal_exception.h" #include "smt/no_such_function_exception.h" @@ -385,6 +386,25 @@ public: */ SExpr getAssignment() throw(ModalException, AssertionException); + /** + * Add to Model Type. This is used for recording which types should be reported + * during a get-model call. + */ + void addToModelType( Type& t ); + + /** + * Add to Model Function. This is used for recording which functions should be reported + * during a get-model call. + */ + void addToModelFunction( Expr& e ); + + /** + * Get the model (only if immediately preceded by a SAT + * or INVALID query). Only permitted if CVC4 was built with model + * support and produce-models is on. + */ + Model* getModel() throw(ModalException, AssertionException); + /** * Get the last proof (only if immediately preceded by an UNSAT * or VALID query). Only permitted if CVC4 was built with proof @@ -520,6 +540,11 @@ public: return d_status; } + /** + * print model function (need this?) + */ + void printModel( std::ostream& out, Model* m ); + };/* class SmtEngine */ }/* CVC4 namespace */ diff --git a/src/theory/Makefile.am b/src/theory/Makefile.am index 84af80035..bca96f7d7 100644 --- a/src/theory/Makefile.am +++ b/src/theory/Makefile.am @@ -43,7 +43,9 @@ libtheory_la_SOURCES = \ inst_match_impl.h \ inst_match.cpp \ trigger.h \ - trigger.cpp + trigger.cpp \ + model.h \ + model.cpp nodist_libtheory_la_SOURCES = \ rewriter_tables.h \ diff --git a/src/theory/arith/theory_arith.cpp b/src/theory/arith/theory_arith.cpp index 390ac280b..c68e9cf54 100644 --- a/src/theory/arith/theory_arith.cpp +++ b/src/theory/arith/theory_arith.cpp @@ -40,6 +40,7 @@ #include "theory/arith/constraint.h" #include "theory/arith/theory_arith.h" #include "theory/arith/normal_form.h" +#include "theory/model.h" #include @@ -1464,12 +1465,12 @@ void TheoryArith::check(Effort effortLevel){ d_qflraStatus = Result::UNSAT; if(previous == Result::SAT){ ++d_statistics.d_revertsOnConflicts; - Debug("arith::bt") << "clearing here " << " " << newFacts << " " << previous << " " << d_qflraStatus << endl; + Debug("arith::bt") << "clearing here " << " " << newFacts << " " << previous << " " << d_qflraStatus << endl; revertOutOfConflict(); d_simplex.clearQueue(); }else{ ++d_statistics.d_commitsOnConflicts; - Debug("arith::bt") << "committing here " << " " << newFacts << " " << previous << " " << d_qflraStatus << endl; + Debug("arith::bt") << "committing here " << " " << newFacts << " " << previous << " " << d_qflraStatus << endl; d_partialModel.commitAssignmentChanges(); revertOutOfConflict(); } @@ -1492,7 +1493,7 @@ void TheoryArith::check(Effort effortLevel){ ++d_statistics.d_nontrivialSatChecks; } - Debug("arith::bt") << "committing sap inConflit" << " " << newFacts << " " << previous << " " << d_qflraStatus << endl; + Debug("arith::bt") << "committing sap inConflit" << " " << newFacts << " " << previous << " " << d_qflraStatus << endl; d_partialModel.commitAssignmentChanges(); d_unknownsInARow = 0; if(Debug.isOn("arith::consistency")){ @@ -1503,7 +1504,7 @@ void TheoryArith::check(Effort effortLevel){ ++d_unknownsInARow; ++(d_statistics.d_unknownChecks); Assert(!fullEffort(effortLevel)); - Debug("arith::bt") << "committing unknown" << " " << newFacts << " " << previous << " " << d_qflraStatus << endl; + Debug("arith::bt") << "committing unknown" << " " << newFacts << " " << previous << " " << d_qflraStatus << endl; d_partialModel.commitAssignmentChanges(); d_statistics.d_maxUnknownsInARow.maxAssign(d_unknownsInARow); break; @@ -1922,80 +1923,8 @@ DeltaRational TheoryArith::getDeltaValue(TNode n) { } } -Node TheoryArith::getValue(TNode n) { - NodeManager* nodeManager = NodeManager::currentNM(); +void TheoryArith::collectModelInfo( TheoryModel* m ){ - Assert(d_qflraStatus == Result::SAT); - - switch(n.getKind()) { - case kind::VARIABLE: { - ArithVar var = d_arithvarNodeMap.asArithVar(n); - - DeltaRational drat = d_partialModel.getAssignment(var); - const Rational& delta = d_partialModel.getDelta(); - Debug("getValue") << n << " " << drat << " " << delta << endl; - return nodeManager-> - mkConst( drat.getNoninfinitesimalPart() + - drat.getInfinitesimalPart() * delta ); - } - - case kind::EQUAL: // 2 args - return nodeManager-> - mkConst( d_valuation.getValue(n[0]) == d_valuation.getValue(n[1]) ); - - case kind::PLUS: { // 2+ args - Rational value(0); - for(TNode::iterator i = n.begin(), - iend = n.end(); - i != iend; - ++i) { - value += d_valuation.getValue(*i).getConst(); - } - return nodeManager->mkConst(value); - } - - case kind::MULT: { // 2+ args - Rational value(1); - for(TNode::iterator i = n.begin(), - iend = n.end(); - i != iend; - ++i) { - value *= d_valuation.getValue(*i).getConst(); - } - return nodeManager->mkConst(value); - } - - case kind::MINUS: // 2 args - // should have been rewritten - Unreachable(); - - case kind::UMINUS: // 1 arg - // should have been rewritten - Unreachable(); - - case kind::DIVISION: // 2 args - return nodeManager->mkConst( d_valuation.getValue(n[0]).getConst() / - d_valuation.getValue(n[1]).getConst() ); - - case kind::LT: // 2 args - return nodeManager->mkConst( d_valuation.getValue(n[0]).getConst() < - d_valuation.getValue(n[1]).getConst() ); - - case kind::LEQ: // 2 args - return nodeManager->mkConst( d_valuation.getValue(n[0]).getConst() <= - d_valuation.getValue(n[1]).getConst() ); - - case kind::GT: // 2 args - return nodeManager->mkConst( d_valuation.getValue(n[0]).getConst() > - d_valuation.getValue(n[1]).getConst() ); - - case kind::GEQ: // 2 args - return nodeManager->mkConst( d_valuation.getValue(n[0]).getConst() >= - d_valuation.getValue(n[1]).getConst() ); - - default: - Unhandled(n.getKind()); - } } bool TheoryArith::safeToReset() const { diff --git a/src/theory/arith/theory_arith.h b/src/theory/arith/theory_arith.h index fd2925bf6..35fcca406 100644 --- a/src/theory/arith/theory_arith.h +++ b/src/theory/arith/theory_arith.h @@ -323,7 +323,7 @@ public: void propagate(Effort e); Node explain(TNode n); - Node getValue(TNode n); + void collectModelInfo( TheoryModel* m ); void shutdown(){ } diff --git a/src/theory/arith/theory_arith_instantiator.cpp b/src/theory/arith/theory_arith_instantiator.cpp index f1b870c52..c4cb2f493 100644 --- a/src/theory/arith/theory_arith_instantiator.cpp +++ b/src/theory/arith/theory_arith_instantiator.cpp @@ -17,6 +17,7 @@ #include "theory/arith/theory_arith_instantiator.h" #include "theory/arith/theory_arith.h" #include "theory/theory_engine.h" +#include "theory/quantifiers/term_database.h" using namespace std; using namespace CVC4; @@ -40,7 +41,7 @@ void InstStrategySimplex::processResetInstantiationRound( Theory::Effort effort d_counter++; } -int InstStrategySimplex::process( Node f, Theory::Effort effort, int e, int instLimit ){ +int InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){ if( e<2 ){ return STATUS_UNFINISHED; }else if( e==2 ){ @@ -99,7 +100,7 @@ int InstStrategySimplex::process( Node f, Theory::Effort effort, int e, int inst // //} // -//int InstStrategySimplexUfMatch::process( Node f, int effort, int instLimit ){ +//int InstStrategySimplexUfMatch::process( Node f, int effort ){ // if( effort<2 ){ // return STATUS_UNFINISHED; // }else if( effort==2 ){ @@ -120,7 +121,7 @@ int InstStrategySimplex::process( Node f, Theory::Effort effort, int e, int inst // while( d_tableaux_ce_term_trigger[x]->getNextMatch() && !addedLemma ){ // InstMatch* m = d_tableaux_ce_term_trigger[x]->getCurrent(); // if( m->isComplete( f ) ){ -// if( d_quantEngine->addInstantiation( f, m, true ) ){ +// if( d_quantEngine->addInstantiation( f, m ) ){ // ++(d_th->d_statistics.d_instantiations_match_pure); // ++(d_th->d_statistics.d_instantiations); // addedLemma = true; @@ -133,8 +134,8 @@ int InstStrategySimplex::process( Node f, Theory::Effort effort, int e, int inst // //Debug("quant-arith") << std::endl; // std::vector< Node > vars; // std::vector< Node > matches; -// for( int i=0; igetNumInstantiationConstants( f ); i++ ){ -// Node ic = d_quantEngine->getInstantiationConstant( f, i ); +// for( int i=0; igetTermDatabase()->getNumInstantiationConstants( f ); i++ ){ +// Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ); // if( m->d_map[ ic ]!=Node::null() ){ // vars.push_back( ic ); // matches.push_back( m->d_map[ ic ] ); @@ -162,7 +163,7 @@ int InstStrategySimplex::process( Node f, Theory::Effort effort, int e, int inst // ++(d_th->d_statistics.d_instantiations_match_var); // } // }else{ -// if( d_quantEngine->addInstantiation( f, m, true ) ){ +// if( d_quantEngine->addInstantiation( f, m ) ){ // addedLemma = true; // ++(d_th->d_statistics.d_instantiations_match_no_var); // ++(d_th->d_statistics.d_instantiations); @@ -242,7 +243,7 @@ void InstantiatorTheoryArith::processResetInstantiationRound( Theory::Effort eff } } -int InstantiatorTheoryArith::process( Node f, Theory::Effort effort, int e, int instLimit ){ +int InstantiatorTheoryArith::process( Node f, Theory::Effort effort, int e ){ Debug("quant-arith") << "Arith: Try to solve (" << effort << ") for " << f << "... " << std::endl; return InstStrategy::STATUS_UNKNOWN; } @@ -316,11 +317,11 @@ void InstantiatorTheoryArith::debugPrint( const char* c ){ Node f = d_quantEngine->getQuantifier( q ); Debug(c) << f << std::endl; Debug(c) << " Inst constants: "; - for( int i=0; i<(int)d_quantEngine->getNumInstantiationConstants( f ); i++ ){ + for( int i=0; i<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){ if( i>0 ){ Debug( c ) << ", "; } - Debug( c ) << d_quantEngine->getInstantiationConstant( f, i ); + Debug( c ) << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ); } Debug(c) << std::endl; Debug(c) << " Instantiation rows: "; @@ -377,7 +378,7 @@ bool InstantiatorTheoryArith::doInstantiation2( Node f, Node term, ArithVar x, I //use as instantiation value for var m.d_map[ var ] = instVal; Debug("quant-arith") << "Add instantiation " << m << std::endl; - return d_quantEngine->addInstantiation( f, m, true ); + return d_quantEngine->addInstantiation( f, m ); } Node InstantiatorTheoryArith::getTableauxValue( Node n, bool minus_delta ){ diff --git a/src/theory/arith/theory_arith_instantiator.h b/src/theory/arith/theory_arith_instantiator.h index 3880a49a7..406478a2a 100644 --- a/src/theory/arith/theory_arith_instantiator.h +++ b/src/theory/arith/theory_arith_instantiator.h @@ -41,7 +41,7 @@ private: Node d_negOne; /** process functions */ void processResetInstantiationRound( Theory::Effort effort ); - int process( Node f, Theory::Effort effort, int e, int instLimit ); + int process( Node f, Theory::Effort effort, int e ); public: InstStrategySimplex( InstantiatorTheoryArith* th, QuantifiersEngine* ie ); ~InstStrategySimplex(){} @@ -56,7 +56,7 @@ public: // /** trigger for instantiation rows */ // std::map< ArithVar, Trigger* > d_tableaux_ce_term_trigger; //public: -// InstStrategySimplexUfMatch( InstantiatorTheoryArith* th, QuantifiersEngine* ie ) : +// InstStrategySimplexUfMatch( InstantiatorTheoryArith* th, QuantifiersEngine* ie ) : // InstStrategy( ie ), d_th( th ){} // ~InstStrategySimplexUfMatch(){} // void resetInstantiationRound(); @@ -102,7 +102,7 @@ private: /** reset instantiation */ void processResetInstantiationRound( Theory::Effort effort ); /** process at effort */ - int process( Node f, Theory::Effort effort, int e, int instLimit ); + int process( Node f, Theory::Effort effort, int e ); /** add term to row */ void addTermToRow( ArithVar x, Node n, Node& f, NodeBuilder<>& t ); /** get delta for node */ diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp index 460289439..5add52d1f 100644 --- a/src/theory/arrays/theory_arrays.cpp +++ b/src/theory/arrays/theory_arrays.cpp @@ -24,6 +24,7 @@ #include "theory/rewriter.h" #include "expr/command.h" #include "theory/arrays/theory_arrays_instantiator.h" +#include "theory/model.h" using namespace std; @@ -57,7 +58,7 @@ TheoryArrays::TheoryArrays(context::Context* c, context::UserContext* u, OutputC d_checkTimer("theory::arrays::checkTime"), d_ppEqualityEngine(u, "theory::arrays::TheoryArraysPP"), d_ppFacts(u), - // d_ppCache(u), + // d_ppCache(u), d_literalsToPropagate(c), d_literalsToPropagateIndex(c, 0), d_isPreRegistered(c), @@ -211,7 +212,7 @@ Node TheoryArrays::ppRewrite(TNode term) { for (j = leftWrites - 1; j > i; --j) { index_j = write_j[1]; if (!ppDisequal(index_i, index_j)) { - Node hyp2(index_i.getType() == nm->booleanType()? + Node hyp2(index_i.getType() == nm->booleanType()? index_i.iffNode(index_j) : index_i.eqNode(index_j)); hyp << hyp2.notNode(); } @@ -623,27 +624,10 @@ void TheoryArrays::computeCareGraph() // MODEL GENERATION ///////////////////////////////////////////////////////////////////////////// - -Node TheoryArrays::getValue(TNode n) -{ - // TODO: Implement this - NodeManager* nodeManager = NodeManager::currentNM(); - - switch(n.getKind()) { - - case kind::VARIABLE: - Unhandled(kind::VARIABLE); - - case kind::EQUAL: // 2 args - return nodeManager-> - mkConst( d_valuation.getValue(n[0]) == d_valuation.getValue(n[1]) ); - - default: - Unhandled(n.getKind()); - } +void TheoryArrays::collectModelInfo( TheoryModel* m ){ + m->assertEqualityEngine( &d_equalityEngine ); } - ///////////////////////////////////////////////////////////////////////////// // NOTIFICATIONS ///////////////////////////////////////////////////////////////////////////// @@ -663,7 +647,7 @@ void TheoryArrays::presolve() void TheoryArrays::check(Effort e) { TimerStat::CodeTimer codeTimer(d_checkTimer); - while (!done() && !d_conflict) + while (!done() && !d_conflict) { // Get all the assertions Assertion assertion = get(); @@ -1306,7 +1290,7 @@ void TheoryArrays::dischargeLemmas() d_equalityEngine.assertEquality(eq2, true, d_true); continue; } - + Node lem = nm->mkNode(kind::OR, eq2_r, eq1_r); Trace("arrays-lem")<<"Arrays::addRowLemma adding "<getEqualityEngine()->hasTerm( a ); +} + +bool InstantiatorTheoryArrays::areEqual( Node a, Node b ){ + if( hasTerm( a ) && hasTerm( b ) ){ + return ((TheoryArrays*)d_th)->getEqualityEngine()->areEqual( a, b ); + }else{ + return a==b; + } +} + +bool InstantiatorTheoryArrays::areDisequal( Node a, Node b ){ + if( hasTerm( a ) && hasTerm( b ) ){ + return ((TheoryArrays*)d_th)->getEqualityEngine()->areDisequal( a, b, false ); + }else{ + return false; + } +} + +Node InstantiatorTheoryArrays::getRepresentative( Node a ){ + if( hasTerm( a ) ){ + return ((TheoryArrays*)d_th)->getEqualityEngine()->getRepresentative( a ); + }else{ + return a; + } +} + diff --git a/src/theory/arrays/theory_arrays_instantiator.h b/src/theory/arrays/theory_arrays_instantiator.h index 6a7c9c3ed..ade43fdb0 100644 --- a/src/theory/arrays/theory_arrays_instantiator.h +++ b/src/theory/arrays/theory_arrays_instantiator.h @@ -32,7 +32,7 @@ protected: /** reset instantiation round */ void processResetInstantiationRound( Theory::Effort effort ); /** process quantifier */ - int process( Node f, Theory::Effort effort, int e, int limitInst = 0 ); + int process( Node f, Theory::Effort effort, int e ); public: InstantiatorTheoryArrays(context::Context* c, QuantifiersEngine* ie, Theory* th); ~InstantiatorTheoryArrays() {} @@ -42,6 +42,12 @@ public: void assertNode( Node assertion ); /** identify */ std::string identify() const { return std::string("InstantiatorTheoryArrays"); } +public: + /** general queries about equality */ + bool hasTerm( Node a ); + bool areEqual( Node a, Node b ); + bool areDisequal( Node a, Node b ); + Node getRepresentative( Node a ); };/* class Instantiatior */ } diff --git a/src/theory/booleans/theory_bool.cpp b/src/theory/booleans/theory_bool.cpp index 520adc228..f096987db 100644 --- a/src/theory/booleans/theory_bool.cpp +++ b/src/theory/booleans/theory_bool.cpp @@ -32,106 +32,8 @@ namespace CVC4 { namespace theory { namespace booleans { -Node TheoryBool::getValue(TNode n) { - NodeManager* nodeManager = NodeManager::currentNM(); +void TheoryBool::collectModelInfo( TheoryModel* m ){ - switch(n.getKind()) { - case kind::VARIABLE: - // case for Boolean vars is implemented in TheoryEngine (since it - // appeals to the PropEngine to get the value) - Unreachable(); - - case kind::EQUAL: // 2 args - // should be handled by IFF - Unreachable(); - - case kind::NOT: { // 1 arg - Node v = d_valuation.getValue(n[0]); - return v.isNull() ? Node::null() : nodeManager->mkConst(! v.getConst()); - } - - case kind::AND: { // 2+ args - bool foundNull = false; - for(TNode::iterator i = n.begin(), - iend = n.end(); - i != iend; - ++i) { - Node v = d_valuation.getValue(*i); - if(v.isNull()) { - foundNull = true; - } else if(! v.getConst()) { - return nodeManager->mkConst(false); - } - } - return foundNull ? Node::null() : nodeManager->mkConst(true); - } - - case kind::IFF: { // 2 args - Node v0 = d_valuation.getValue(n[0]); - Node v1 = d_valuation.getValue(n[1]); - if(v0.isNull() || v1.isNull()) { - return Node::null(); - } - return nodeManager->mkConst( v0.getConst() == v1.getConst() ); - } - - case kind::IMPLIES: { // 2 args - Node v0 = d_valuation.getValue(n[0]); - Node v1 = d_valuation.getValue(n[1]); - if(v0.isNull() && v1.isNull()) { - return Node::null(); - } - bool value = false; - if(! v0.isNull()) { - value = value || (! v0.getConst()); - } - if(! v1.isNull()) { - value = value || v1.getConst(); - } - return nodeManager->mkConst(value); - } - - case kind::OR: { // 2+ args - bool foundNull = false; - for(TNode::iterator i = n.begin(), - iend = n.end(); - i != iend; - ++i) { - Node v = d_valuation.getValue(*i); - if(v.isNull()) { - foundNull = true; - } else if(v.getConst()) { - return nodeManager->mkConst(true); - } - } - return foundNull ? Node::null() : nodeManager->mkConst(false); - } - - case kind::XOR: { // 2 args - Node v0 = d_valuation.getValue(n[0]); - Node v1 = d_valuation.getValue(n[1]); - if(v0.isNull() || v1.isNull()) { - return Node::null(); - } - return nodeManager->mkConst( v0.getConst() != v1.getConst() ); - } - - case kind::ITE: { // 3 args - // all ITEs should be gone except (bool,bool,bool) ones - Assert( n[1].getType() == nodeManager->booleanType() && - n[2].getType() == nodeManager->booleanType() ); - Node v0 = d_valuation.getValue(n[0]); - Node v1 = d_valuation.getValue(n[1]); - Node v2 = d_valuation.getValue(n[2]); - if(v0.isNull()) { - return v1 == v2 ? v1 : Node::null(); - } - return nodeManager->mkConst( v0.getConst() ? v1.getConst() : v2.getConst() ); - } - - default: - Unhandled(n.getKind()); - } } Theory::PPAssertStatus TheoryBool::ppAssert(TNode in, SubstitutionMap& outSubstitutions) { diff --git a/src/theory/booleans/theory_bool.h b/src/theory/booleans/theory_bool.h index 40783a6ce..827b0ff57 100644 --- a/src/theory/booleans/theory_bool.h +++ b/src/theory/booleans/theory_bool.h @@ -23,6 +23,7 @@ #include "theory/theory.h" #include "context/context.h" +#include "theory/model.h" namespace CVC4 { namespace theory { @@ -34,7 +35,7 @@ public: Theory(THEORY_BOOL, c, u, out, valuation, logicInfo, qe) { } - Node getValue(TNode n); + void collectModelInfo( TheoryModel* m ); PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions); diff --git a/src/theory/builtin/theory_builtin.cpp b/src/theory/builtin/theory_builtin.cpp index e955539d5..fa176243c 100644 --- a/src/theory/builtin/theory_builtin.cpp +++ b/src/theory/builtin/theory_builtin.cpp @@ -19,6 +19,7 @@ #include "theory/builtin/theory_builtin.h" #include "theory/valuation.h" #include "expr/kind.h" +#include "theory/model.h" using namespace std; @@ -26,38 +27,8 @@ namespace CVC4 { namespace theory { namespace builtin { -Node TheoryBuiltin::getValue(TNode n) { - switch(n.getKind()) { +void TheoryBuiltin::collectModelInfo( TheoryModel* m ){ - case kind::VARIABLE: - // no variables that the builtin theory is responsible for - Unreachable(); - - case kind::EQUAL: { // 2 args - // has to be an EQUAL over tuples, since all others should be - // handled elsewhere - Assert(n[0].getKind() == kind::TUPLE && - n[1].getKind() == kind::TUPLE); - return NodeManager::currentNM()-> - mkConst( getValue(n[0]) == getValue(n[1]) ); - } - - case kind::TUPLE: { // 2+ args - NodeBuilder<> nb(kind::TUPLE); - for(TNode::iterator i = n.begin(), - iend = n.end(); - i != iend; - ++i) { - nb << d_valuation.getValue(*i); - } - return Node(nb); - } - - default: - // all other "builtins" should have been rewritten away or handled - // by the valuation, or handled elsewhere. - Unhandled(n.getKind()); - } } }/* CVC4::theory::builtin namespace */ diff --git a/src/theory/builtin/theory_builtin.h b/src/theory/builtin/theory_builtin.h index a13c69d9d..51bd7c756 100644 --- a/src/theory/builtin/theory_builtin.h +++ b/src/theory/builtin/theory_builtin.h @@ -31,7 +31,7 @@ class TheoryBuiltin : public Theory { public: TheoryBuiltin(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe) : Theory(THEORY_BUILTIN, c, u, out, valuation, logicInfo, qe) {} - Node getValue(TNode n); + void collectModelInfo( TheoryModel* m ); std::string identify() const { return std::string("TheoryBuiltin"); } };/* class TheoryBuiltin */ diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp index 273b406e6..da2dd77f6 100644 --- a/src/theory/bv/theory_bv.cpp +++ b/src/theory/bv/theory_bv.cpp @@ -57,13 +57,13 @@ TheoryBV::Statistics::Statistics(): { StatisticsRegistry::registerStat(&d_avgConflictSize); StatisticsRegistry::registerStat(&d_solveSubstitutions); - StatisticsRegistry::registerStat(&d_solveTimer); + StatisticsRegistry::registerStat(&d_solveTimer); } TheoryBV::Statistics::~Statistics() { StatisticsRegistry::unregisterStat(&d_avgConflictSize); StatisticsRegistry::unregisterStat(&d_solveSubstitutions); - StatisticsRegistry::unregisterStat(&d_solveTimer); + StatisticsRegistry::unregisterStat(&d_solveTimer); } void TheoryBV::preRegisterTerm(TNode node) { @@ -75,7 +75,7 @@ void TheoryBV::preRegisterTerm(TNode node) { } d_bitblastSolver.preRegister(node); - d_equalitySolver.preRegister(node); + d_equalitySolver.preRegister(node); } void TheoryBV::sendConflict() { @@ -94,54 +94,40 @@ void TheoryBV::check(Effort e) { BVDebug("bitvector") << "TheoryBV::check(" << e << ")" << std::endl; - // if we are already in conflict just return the conflict + // if we are already in conflict just return the conflict if (inConflict()) { sendConflict(); return; } - + // getting the new assertions - std::vector new_assertions; + std::vector new_assertions; while (!done()) { Assertion assertion = get(); TNode fact = assertion.assertion; new_assertions.push_back(fact); - BVDebug("bitvector-assertions") << "TheoryBV::check assertion " << fact << "\n"; + BVDebug("bitvector-assertions") << "TheoryBV::check assertion " << fact << "\n"; } if (!inConflict()) { // sending assertions to the equality solver first d_equalitySolver.addAssertions(new_assertions, e); } - + if (!inConflict()) { // sending assertions to the bitblast solver d_bitblastSolver.addAssertions(new_assertions, e); } - + if (inConflict()) { sendConflict(); } } +void TheoryBV::collectModelInfo( TheoryModel* m ){ -Node TheoryBV::getValue(TNode n) { - //NodeManager* nodeManager = NodeManager::currentNM(); - - switch(n.getKind()) { - - case kind::VARIABLE: - Unhandled(kind::VARIABLE); - - case kind::EQUAL: // 2 args - Unhandled(kind::VARIABLE); - - default: - Unhandled(n.getKind()); - } } - void TheoryBV::propagate(Effort e) { BVDebug("bitvector") << indent() << "TheoryBV::propagate()" << std::endl; @@ -166,14 +152,14 @@ void TheoryBV::propagate(Effort e) { Theory::PPAssertStatus TheoryBV::ppAssert(TNode in, SubstitutionMap& outSubstitutions) { switch(in.getKind()) { case kind::EQUAL: - + if (in[0].getMetaKind() == kind::metakind::VARIABLE && !in[1].hasSubterm(in[0])) { - ++(d_statistics.d_solveSubstitutions); + ++(d_statistics.d_solveSubstitutions); outSubstitutions.addSubstitution(in[0], in[1]); return PP_ASSERT_STATUS_SOLVED; } if (in[1].getMetaKind() == kind::metakind::VARIABLE && !in[0].hasSubterm(in[1])) { - ++(d_statistics.d_solveSubstitutions); + ++(d_statistics.d_solveSubstitutions); outSubstitutions.addSubstitution(in[1], in[0]); return PP_ASSERT_STATUS_SOLVED; } @@ -243,14 +229,14 @@ bool TheoryBV::storePropagation(TNode literal, SubTheory subtheory) void TheoryBV::explain(TNode literal, std::vector& assumptions) { - // Ask the appropriate subtheory for the explanation + // Ask the appropriate subtheory for the explanation if (propagatedBy(literal, SUB_EQUALITY)) { BVDebug("bitvector::explain") << "TheoryBV::explain(" << literal << "): EQUALITY" << std::endl; - d_equalitySolver.explain(literal, assumptions); + d_equalitySolver.explain(literal, assumptions); } else { Assert(propagatedBy(literal, SUB_BITBLAST)); - BVDebug("bitvector::explain") << "TheoryBV::explain(" << literal << ") : BITBLASTER" << std::endl; - d_bitblastSolver.explain(literal, assumptions); + BVDebug("bitvector::explain") << "TheoryBV::explain(" << literal << ") : BITBLASTER" << std::endl; + d_bitblastSolver.explain(literal, assumptions); } } @@ -263,7 +249,7 @@ Node TheoryBV::explain(TNode node) { explain(node, assumptions); // this means that it is something true at level 0 if (assumptions.size() == 0) { - return utils::mkTrue(); + return utils::mkTrue(); } // return the explanation Node explanation = mkAnd(assumptions); @@ -274,9 +260,9 @@ Node TheoryBV::explain(TNode node) { void TheoryBV::addSharedTerm(TNode t) { Debug("bitvector::sharing") << indent() << "TheoryBV::addSharedTerm(" << t << ")" << std::endl; - d_sharedTermsSet.insert(t); + d_sharedTermsSet.insert(t); if (!Options::current()->bitvectorEagerBitblast && d_useEqualityEngine) { - d_equalitySolver.addSharedTerm(t); + d_equalitySolver.addSharedTerm(t); } } diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h index 761c11e3d..611927b2b 100644 --- a/src/theory/bv/theory_bv.h +++ b/src/theory/bv/theory_bv.h @@ -57,10 +57,10 @@ public: void check(Effort e); void propagate(Effort e); - + Node explain(TNode n); - Node getValue(TNode n); + void collectModelInfo( TheoryModel* m ); std::string identify() const { return std::string("TheoryBV"); } @@ -124,7 +124,7 @@ private: } void setConflict(Node conflict = Node::null()) { - d_conflict = true; + d_conflict = true; d_conflictNode = conflict; } @@ -136,8 +136,8 @@ private: friend class Bitblaster; friend class BitblastSolver; - friend class EqualitySolver; - + friend class EqualitySolver; + };/* class TheoryBV */ }/* CVC4::theory::bv namespace */ diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp index f9ef49c6b..cb0f75c12 100644 --- a/src/theory/datatypes/theory_datatypes.cpp +++ b/src/theory/datatypes/theory_datatypes.cpp @@ -23,6 +23,7 @@ #include "util/datatype.h" #include "util/Assert.h" #include "theory/datatypes/theory_datatypes_instantiator.h" +#include "theory/model.h" #include @@ -94,6 +95,9 @@ void TheoryDatatypes::notifyCongruent(TNode lhs, TNode rhs) { void TheoryDatatypes::preRegisterTerm(TNode n) { Debug("datatypes-prereg") << "TheoryDatatypes::preRegisterTerm() " << n << endl; + if( n.getType().isDatatype() ){ + d_preRegTerms.push_back( n ); + } } @@ -616,16 +620,11 @@ void TheoryDatatypes::updateSelectors( Node a ) { } } -Node TheoryDatatypes::getValue(TNode n) { - NodeManager* nodeManager = NodeManager::currentNM(); - switch(n.getKind()) { - case kind::VARIABLE: - Unhandled(kind::VARIABLE); - case kind::EQUAL: // 2 args - return nodeManager-> - mkConst( d_valuation.getValue(n[0]) == d_valuation.getValue(n[1]) ); - default: - Unhandled(n.getKind()); +void TheoryDatatypes::collectModelInfo( TheoryModel* m ){ + //temporary + for( int i=0; i<(int)d_preRegTerms.size(); i++ ){ + Node n = find( d_preRegTerms[i] ); + m->assertEquality( n, d_preRegTerms[i], true ); } } @@ -1054,3 +1053,64 @@ bool TheoryDatatypes::searchForCycle( Node n, Node on, } return false; } + +bool TheoryDatatypes::hasTerm( Node a ){ + return false; +} + +bool TheoryDatatypes::areEqual( Node a, Node b ){ + Node ar = find( a ); + Node br = find( b ); + if( ar==br ){ + return true; + }else if( ar.getKind()==APPLY_CONSTRUCTOR && br.getKind()==APPLY_CONSTRUCTOR && + ar.getOperator()==br.getOperator() ){ + //for( int i=0; i<(int)ar.getNumChildren(); i++ ){ + // if( !areEqual( ar[0], br[0] ) ){ + // return false; + // } + //} + //return true; + return false; + }else{ + return false; + } +} + +bool TheoryDatatypes::areDisequal( Node a, Node b ){ + Node ar = find( a ); + Node br = find( b ); + if( ar==br ){ + return false; + }else if( ar.getKind()==APPLY_CONSTRUCTOR && br.getKind()==APPLY_CONSTRUCTOR && + ar.getOperator()!=br.getOperator() ){ + return true; + }else{ + EqLists::iterator deq_ia = d_disequalities.find( ar ); + EqLists::iterator deq_ib = d_disequalities.find( br ); + if( deq_ia!=d_disequalities.end() && deq_ib!=d_disequalities.end() ){ + EqList* deq; + if( (*deq_ib).second->size()<(*deq_ia).second->size() ){ + deq = (*deq_ib).second; + }else{ + deq = (*deq_ia).second; + } + for(EqList::const_iterator i = deq->begin(); i != deq->end(); i++) { + TNode deqn = (*i); + TNode sp = find(deqn[0]); + TNode tp = find(deqn[1]); + if( sp==a && tp==b ){ + return true; + }else if( sp==b && tp==a ){ + return true; + } + } + } + return false; + } +} + +Node TheoryDatatypes::getRepresentative( Node a ){ + return find( a ); +} + diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h index 5a4135a3b..783c0ebc7 100644 --- a/src/theory/datatypes/theory_datatypes.h +++ b/src/theory/datatypes/theory_datatypes.h @@ -142,6 +142,8 @@ private: */ CongruenceClosureExplainer d_cce; + //temporary + std::vector< Node > d_preRegTerms; public: TheoryDatatypes(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe); ~TheoryDatatypes(); @@ -150,7 +152,7 @@ public: void addSharedTerm(TNode t); void check(Effort e); - Node getValue(TNode n); + void collectModelInfo( TheoryModel* m ); void shutdown() { } std::string identify() const { return std::string("TheoryDatatypes"); } @@ -180,6 +182,12 @@ private: bool searchForCycle( Node n, Node on, std::map< Node, bool >& visited, NodeBuilder<>& explanation ); +public: + //equality queries + bool hasTerm( Node a ); + bool areEqual( Node a, Node b ); + bool areDisequal( Node a, Node b ); + Node getRepresentative( Node a ); };/* class TheoryDatatypes */ inline bool TheoryDatatypes::hasConflict() { diff --git a/src/theory/datatypes/theory_datatypes_instantiator.cpp b/src/theory/datatypes/theory_datatypes_instantiator.cpp index 6a32466e4..9495e4d48 100644 --- a/src/theory/datatypes/theory_datatypes_instantiator.cpp +++ b/src/theory/datatypes/theory_datatypes_instantiator.cpp @@ -17,6 +17,7 @@ #include "theory/datatypes/theory_datatypes_instantiator.h" #include "theory/datatypes/theory_datatypes.h" #include "theory/theory_engine.h" +#include "theory/quantifiers/term_database.h" using namespace std; using namespace CVC4; @@ -47,15 +48,15 @@ void InstantiatorTheoryDatatypes::processResetInstantiationRound( Theory::Effort } -int InstantiatorTheoryDatatypes::process( Node f, Theory::Effort effort, int e, int limitInst ){ +int InstantiatorTheoryDatatypes::process( Node f, Theory::Effort effort, int e ){ Debug("quant-datatypes") << "Datatypes: Try to solve (" << e << ") for " << f << "... " << std::endl; if( Options::current()->cbqi ){ if( e<2 ){ return InstStrategy::STATUS_UNFINISHED; }else if( e==2 ){ InstMatch m; - for( int j = 0; j<(int)d_quantEngine->getNumInstantiationConstants( f ); j++ ){ - Node i = d_quantEngine->getInstantiationConstant( f, j ); + for( int j = 0; j<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); j++ ){ + Node i = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j ); if( i.getType().isDatatype() ){ Node n = getValueFor( i ); Debug("quant-datatypes-debug") << "Value for " << i << " is " << n << std::endl; @@ -142,10 +143,6 @@ Node InstantiatorTheoryDatatypes::getValueFor( Node n ){ } } -Node InstantiatorTheoryDatatypes::getRepresentative( Node n ){ - return ((TheoryDatatypes*)d_th)->find( n ); -} - InstantiatorTheoryDatatypes::Statistics::Statistics(): d_instantiations("InstantiatorTheoryDatatypes::Instantiations_Total", 0) { @@ -156,3 +153,18 @@ InstantiatorTheoryDatatypes::Statistics::~Statistics(){ StatisticsRegistry::unregisterStat(&d_instantiations); } +bool InstantiatorTheoryDatatypes::hasTerm( Node a ){ + return ((TheoryDatatypes*)d_th)->hasTerm( a ); +} + +bool InstantiatorTheoryDatatypes::areEqual( Node a, Node b ){ + return ((TheoryDatatypes*)d_th)->areEqual( a, b ); +} + +bool InstantiatorTheoryDatatypes::areDisequal( Node a, Node b ){ + return ((TheoryDatatypes*)d_th)->areDisequal( a, b ); +} + +Node InstantiatorTheoryDatatypes::getRepresentative( Node a ){ + return ((TheoryDatatypes*)d_th)->getRepresentative( a ); +} diff --git a/src/theory/datatypes/theory_datatypes_instantiator.h b/src/theory/datatypes/theory_datatypes_instantiator.h index ab5703757..a080465af 100644 --- a/src/theory/datatypes/theory_datatypes_instantiator.h +++ b/src/theory/datatypes/theory_datatypes_instantiator.h @@ -42,11 +42,9 @@ private: /** reset instantiation */ void processResetInstantiationRound( Theory::Effort effort ); /** process at effort */ - int process( Node f, Theory::Effort effort, int e, int limitInst ); + int process( Node f, Theory::Effort effort, int e ); /** get value for */ Node getValueFor( Node n ); - /** get representative */ - Node getRepresentative( Node n ); class Statistics { public: @@ -55,6 +53,12 @@ private: ~Statistics(); }; Statistics d_statistics; +public: + /** general queries about equality */ + bool hasTerm( Node a ); + bool areEqual( Node a, Node b ); + bool areDisequal( Node a, Node b ); + Node getRepresentative( Node a ); };/* class InstantiatiorTheoryDatatypes */ } diff --git a/src/theory/example/theory_uf_tim.h b/src/theory/example/theory_uf_tim.h index 41e58349a..5a6732bc4 100644 --- a/src/theory/example/theory_uf_tim.h +++ b/src/theory/example/theory_uf_tim.h @@ -143,12 +143,11 @@ public: void explain(TNode n) {} /** - * Get a theory value. + * Get model * - * Overloads Node getValue(TNode n); from theory.h. * See theory/theory.h for more information about this method. */ - Node getValue(TNode n) { + void collectModelInfo( TheoryModel* m ){ Unimplemented("TheoryUFTim doesn't support model generation"); } diff --git a/src/theory/inst_match.cpp b/src/theory/inst_match.cpp index 32d6c958b..abcf5aa7f 100644 --- a/src/theory/inst_match.cpp +++ b/src/theory/inst_match.cpp @@ -20,6 +20,10 @@ #include "theory/uf/theory_uf_instantiator.h" #include "theory/uf/theory_uf_candidate_generator.h" #include "theory/uf/equality_engine.h" +#include "theory/quantifiers/model_engine.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers/first_order_model.h" +#include "theory/quantifiers/term_database.h" using namespace std; using namespace CVC4; @@ -29,7 +33,8 @@ using namespace CVC4::theory; bool CandidateGenerator::isLegalCandidate( Node n ){ - return !n.getAttribute(NoMatchAttribute()) && ( !Options::current()->cbqi || !n.hasAttribute(InstConstantAttribute()) ); + return ( !n.getAttribute(NoMatchAttribute()) && ( !Options::current()->cbqi || !n.hasAttribute(InstConstantAttribute()) ) ) || + ( Options::current()->finiteModelFind && n.hasAttribute(ModelBasisArgAttribute()) && n.getAttribute(ModelBasisArgAttribute())==1 ); } void CandidateGeneratorQueue::addCandidate( Node n ) { @@ -115,9 +120,9 @@ void InstMatch::debugPrint( const char* c ){ } void InstMatch::makeComplete( Node f, QuantifiersEngine* qe ){ - for( int i=0; i<(int)qe->d_inst_constants[f].size(); i++ ){ - if( d_map.find( qe->d_inst_constants[f][i] )==d_map.end() ){ - d_map[ qe->d_inst_constants[f][i] ] = qe->getFreeVariableForInstConstant( qe->d_inst_constants[f][i] ); + for( int i=0; i<(int)qe->getTermDatabase()->d_inst_constants[f].size(); i++ ){ + if( d_map.find( qe->getTermDatabase()->d_inst_constants[f][i] )==d_map.end() ){ + d_map[ qe->getTermDatabase()->d_inst_constants[f][i] ] = qe->getTermDatabase()->getFreeVariableForInstConstant( qe->getTermDatabase()->d_inst_constants[f][i] ); } } } @@ -127,7 +132,7 @@ void InstMatch::makeInternal( QuantifiersEngine* qe ){ if( Options::current()->cbqi && it->second.hasAttribute(InstConstantAttribute()) ){ d_map[ it->first ] = qe->getEqualityQuery()->getInternalRepresentative( it->second ); if( Options::current()->cbqi && it->second.hasAttribute(InstConstantAttribute()) ){ - d_map[ it->first ] = qe->getFreeVariableForInstConstant( it->first ); + d_map[ it->first ] = qe->getTermDatabase()->getFreeVariableForInstConstant( it->first ); } } } @@ -137,7 +142,7 @@ void InstMatch::makeRepresentative( QuantifiersEngine* qe ){ for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ d_map[ it->first ] = qe->getEqualityQuery()->getInternalRepresentative( it->second ); if( Options::current()->cbqi && it->second.hasAttribute(InstConstantAttribute()) ){ - d_map[ it->first ] = qe->getFreeVariableForInstConstant( it->first ); + d_map[ it->first ] = qe->getTermDatabase()->getFreeVariableForInstConstant( it->first ); } } } @@ -154,7 +159,7 @@ void InstMatch::computeTermVec( QuantifiersEngine* qe, const std::vector< Node > if( it!=d_map.end() && !it->second.isNull() ){ match.push_back( it->second ); }else{ - match.push_back( qe->getFreeVariableForInstConstant( vars[i] ) ); + match.push_back( qe->getTermDatabase()->getFreeVariableForInstConstant( vars[i] ) ); } } } @@ -169,7 +174,7 @@ void InstMatch::computeTermVec( const std::vector< Node >& vars, std::vector< No void InstMatchTrie::addInstMatch2( QuantifiersEngine* qe, Node f, InstMatch& m, int index, ImtIndexOrder* imtio ){ if( long(index)d_order.size()) ) ){ int i_index = imtio ? imtio->d_order[index] : index; - Node n = m.d_map[ qe->getInstantiationConstant( f, i_index ) ]; + Node n = m.d_map[ qe->getTermDatabase()->getInstantiationConstant( f, i_index ) ]; d_data[n].addInstMatch2( qe, f, m, index+1, imtio ); } } @@ -180,7 +185,7 @@ bool InstMatchTrie::existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m return true; }else{ int i_index = imtio ? imtio->d_order[index] : index; - Node n = m.d_map[ qe->getInstantiationConstant( f, i_index ) ]; + Node n = m.d_map[ qe->getTermDatabase()->getInstantiationConstant( f, i_index ) ]; std::map< Node, InstMatchTrie >::iterator it = d_data.find( n ); if( it!=d_data.end() ){ if( it->second.existsInstMatch( qe, f, m, modEq, index+1, imtio ) ){ @@ -190,7 +195,7 @@ bool InstMatchTrie::existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m if( modEq ){ //check modulo equality if any other instantiation match exists if( ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine()->hasTerm( n ) ){ - eq::EqClassIterator eqc( qe->getEqualityQuery()->getRepresentative( n ), + eq::EqClassIterator eqc( ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine()->getRepresentative( n ), ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine() ); while( !eqc.isFinished() ){ Node en = (*eqc); @@ -344,7 +349,9 @@ bool InstMatchGenerator::getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ) Debug("matching") << "Matching " << t << " against pattern " << d_match_pattern << " (" << m.d_map.size() << ")" << ", " << d_children.size() << std::endl; Assert( !d_match_pattern.isNull() ); - if( d_matchPolicy==MATCH_GEN_INTERNAL_ARITHMETIC ){ + if( qe->d_optMatchIgnoreModelBasis && t.getAttribute(ModelBasisAttribute()) ){ + return true; + }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ARITHMETIC ){ return getMatchArithmetic( t, m, qe ); }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ERROR ){ return false; @@ -421,7 +428,6 @@ bool InstMatchGenerator::getNextMatch2( InstMatch& m, QuantifiersEngine* qe, boo t = d_cg->getNextCandidate(); //if t not null, try to fit it into match m if( !t.isNull() && t.getType()==d_match_pattern.getType() ){ - //Assert( t.getType()==d_match_pattern.getType() ); success = getMatch( t, m, qe ); } }while( !success && !t.isNull() ); @@ -592,16 +598,16 @@ bool InstMatchGenerator::nonunifiable( TNode t0, const std::vector & vars) return false; } -int InstMatchGenerator::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit, bool addSplits ){ +int InstMatchGenerator::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ //now, try to add instantiation for each match produced int addedLemmas = 0; InstMatch m; while( getNextMatch( m, qe ) ){ //m.makeInternal( d_quantEngine->getEqualityQuery() ); m.add( baseMatch ); - if( qe->addInstantiation( f, m, addSplits ) ){ + if( qe->addInstantiation( f, m ) ){ addedLemmas++; - if( instLimit>0 && addedLemmas==instLimit ){ + if( qe->d_optInstLimitActive && qe->d_optInstLimit<=0 ){ return addedLemmas; } } @@ -706,29 +712,62 @@ void InstMatchGeneratorMulti::reset( Node eqc, QuantifiersEngine* qe ){ } } -void InstMatchGeneratorMulti::collectInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr, - std::vector< IndexedTrie >& unique_var_tries, - int trieIndex, int childIndex, int endChildIndex, bool modEq ){ +int InstMatchGeneratorMulti::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ + int addedLemmas = 0; + Debug("smart-multi-trigger") << "Process smart multi trigger" << std::endl; + for( int i=0; i<(int)d_children.size(); i++ ){ + Debug("smart-multi-trigger") << "Calculate matches " << i << std::endl; + std::vector< InstMatch > newMatches; + InstMatch m; + while( d_children[i]->getNextMatch( m, qe ) ){ + m.makeRepresentative( qe ); + newMatches.push_back( InstMatch( &m ) ); + m.clear(); + } + for( int j=0; j<(int)newMatches.size(); j++ ){ + processNewMatch( qe, newMatches[j], i, addedLemmas ); + } + } + return addedLemmas; +} + +void InstMatchGeneratorMulti::processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ){ + //see if these produce new matches + d_children_trie[fromChildIndex].addInstMatch( qe, d_f, m, true ); + //possibly only do the following if we know that new matches will be produced? + //the issue is that instantiations are filtered in quantifiers engine, and so there is no guarentee that + // we can safely skip the following lines, even when we have already produced this match. + Debug("smart-multi-trigger") << "Child " << fromChildIndex << " produced match " << m << std::endl; + //process new instantiations + int childIndex = (fromChildIndex+1)%(int)d_children.size(); + std::vector< IndexedTrie > unique_var_tries; + processNewInstantiations( qe, m, addedLemmas, d_children_trie[childIndex].getTrie(), + unique_var_tries, 0, childIndex, fromChildIndex, true ); +} + +void InstMatchGeneratorMulti::processNewInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr, + std::vector< IndexedTrie >& unique_var_tries, + int trieIndex, int childIndex, int endChildIndex, bool modEq ){ if( childIndex==endChildIndex ){ //now, process unique variables - collectInstantiations2( qe, m, addedLemmas, unique_var_tries, 0 ); + processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, 0 ); }else if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){ int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex]; - Node curr_ic = qe->getInstantiationConstant( d_f, curr_index ); + Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index ); if( m.d_map.find( curr_ic )==m.d_map.end() ){ //if( d_var_to_node[ curr_index ].size()==1 ){ //FIXME // //unique variable(s), defer calculation // unique_var_tries.push_back( IndexedTrie( std::pair< int, int >( childIndex, trieIndex ), tr ) ); // int newChildIndex = (childIndex+1)%(int)d_children.size(); - // collectInstantiations( qe, m, d_children_trie[newChildIndex].getTrie(), unique_var_tries, - // 0, newChildIndex, endChildIndex, modEq ); + // processNewInstantiations( qe, m, d_children_trie[newChildIndex].getTrie(), unique_var_tries, + // 0, newChildIndex, endChildIndex, modEq ); //}else{ //shared and non-set variable, add to InstMatch for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){ InstMatch mn( &m ); mn.d_map[ curr_ic ] = it->first; - collectInstantiations( qe, mn, addedLemmas, &(it->second), unique_var_tries, - trieIndex+1, childIndex, endChildIndex, modEq ); + processNewInstantiations( qe, mn, addedLemmas, &(it->second), unique_var_tries, + trieIndex+1, childIndex, endChildIndex, modEq ); } //} }else{ @@ -736,8 +775,8 @@ void InstMatchGeneratorMulti::collectInstantiations( QuantifiersEngine* qe, Inst Node n = m.d_map[ curr_ic ]; std::map< Node, InstMatchTrie >::iterator it = tr->d_data.find( n ); if( it!=tr->d_data.end() ){ - collectInstantiations( qe, m, addedLemmas, &(it->second), unique_var_tries, - trieIndex+1, childIndex, endChildIndex, modEq ); + processNewInstantiations( qe, m, addedLemmas, &(it->second), unique_var_tries, + trieIndex+1, childIndex, endChildIndex, modEq ); } if( modEq ){ //check modulo equality for other possible instantiations @@ -749,8 +788,8 @@ void InstMatchGeneratorMulti::collectInstantiations( QuantifiersEngine* qe, Inst if( en!=n ){ std::map< Node, InstMatchTrie >::iterator itc = tr->d_data.find( en ); if( itc!=tr->d_data.end() ){ - collectInstantiations( qe, m, addedLemmas, &(itc->second), unique_var_tries, - trieIndex+1, childIndex, endChildIndex, modEq ); + processNewInstantiations( qe, m, addedLemmas, &(itc->second), unique_var_tries, + trieIndex+1, childIndex, endChildIndex, modEq ); } } ++eqc; @@ -760,14 +799,14 @@ void InstMatchGeneratorMulti::collectInstantiations( QuantifiersEngine* qe, Inst } }else{ int newChildIndex = (childIndex+1)%(int)d_children.size(); - collectInstantiations( qe, m, addedLemmas, d_children_trie[newChildIndex].getTrie(), unique_var_tries, - 0, newChildIndex, endChildIndex, modEq ); + processNewInstantiations( qe, m, addedLemmas, d_children_trie[newChildIndex].getTrie(), unique_var_tries, + 0, newChildIndex, endChildIndex, modEq ); } } -void InstMatchGeneratorMulti::collectInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, - std::vector< IndexedTrie >& unique_var_tries, - int uvtIndex, InstMatchTrie* tr, int trieIndex ){ +void InstMatchGeneratorMulti::processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, + std::vector< IndexedTrie >& unique_var_tries, + int uvtIndex, InstMatchTrie* tr, int trieIndex ){ if( uvtIndex<(int)unique_var_tries.size() ){ int childIndex = unique_var_tries[uvtIndex].first.first; if( !tr ){ @@ -776,58 +815,25 @@ void InstMatchGeneratorMulti::collectInstantiations2( QuantifiersEngine* qe, Ins } if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){ int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex]; - Node curr_ic = qe->getInstantiationConstant( d_f, curr_index ); + Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index ); //unique non-set variable, add to InstMatch for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){ InstMatch mn( &m ); mn.d_map[ curr_ic ] = it->first; - collectInstantiations2( qe, mn, addedLemmas, unique_var_tries, uvtIndex, &(it->second), trieIndex+1 ); + processNewInstantiations2( qe, mn, addedLemmas, unique_var_tries, uvtIndex, &(it->second), trieIndex+1 ); } }else{ - collectInstantiations2( qe, m, addedLemmas, unique_var_tries, uvtIndex+1 ); + processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, uvtIndex+1 ); } }else{ //m is an instantiation - if( qe->addInstantiation( d_f, m, true ) ){ + if( qe->addInstantiation( d_f, m ) ){ addedLemmas++; Debug("smart-multi-trigger") << "-> Produced instantiation " << m << std::endl; } } } -int InstMatchGeneratorMulti::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit, bool addSplits ){ - int addedLemmas = 0; - Debug("smart-multi-trigger") << "Process smart multi trigger" << std::endl; - for( int i=0; i<(int)d_children.size(); i++ ){ - Debug("smart-multi-trigger") << "Calculate matches " << i << std::endl; - std::vector< InstMatch > newMatches; - InstMatch m; - while( d_children[i]->getNextMatch( m, qe ) ){ - m.makeRepresentative( qe ); - newMatches.push_back( InstMatch( &m ) ); - m.clear(); - } - for( int j=0; j<(int)newMatches.size(); j++ ){ - processNewMatch( qe, newMatches[j], i, addedLemmas ); - } - } - return addedLemmas; -} - -void InstMatchGeneratorMulti::processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ){ - //see if these produce new matches - d_children_trie[fromChildIndex].addInstMatch( qe, d_f, m, true ); - //possibly only do the following if we know that new matches will be produced? - //the issue is that instantiations are filtered in quantifiers engine, and so there is no guarentee that - // we can safely skip the following lines, even when we have already produced this match. - Debug("smart-multi-trigger") << "Child " << fromChildIndex << " produced match " << m << std::endl; - //collect new instantiations - int childIndex = (fromChildIndex+1)%(int)d_children.size(); - std::vector< IndexedTrie > unique_var_tries; - collectInstantiations( qe, m, addedLemmas, - d_children_trie[childIndex].getTrie(), unique_var_tries, 0, childIndex, fromChildIndex, true ); -} - int InstMatchGeneratorMulti::addTerm( Node f, Node t, QuantifiersEngine* qe ){ Assert( Options::current()->eagerInstQuant ); int addedLemmas = 0; @@ -843,47 +849,44 @@ int InstMatchGeneratorMulti::addTerm( Node f, Node t, QuantifiersEngine* qe ){ return addedLemmas; } -int InstMatchGeneratorSimple::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit, bool addSplits ){ +int InstMatchGeneratorSimple::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ InstMatch m; m.add( baseMatch ); int addedLemmas = 0; if( d_match_pattern.getType()==NodeManager::currentNM()->booleanType() ){ for( int i=0; i<2; i++ ){ - addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_pred_map_trie[i][ d_match_pattern.getOperator() ]), - instLimit, addSplits ); + addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_pred_map_trie[i][ d_match_pattern.getOperator() ]) ); } }else{ - addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_match_pattern.getOperator() ]), - instLimit, addSplits ); + addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_match_pattern.getOperator() ]) ); } return addedLemmas; } -void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, - TermArgTrie* tat, int instLimit, bool addSplits ){ +void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ){ if( argIndex==(int)d_match_pattern.getNumChildren() ){ //m is an instantiation - if( qe->addInstantiation( d_f, m, addSplits ) ){ + if( qe->addInstantiation( d_f, m ) ){ addedLemmas++; Debug("simple-multi-trigger") << "-> Produced instantiation " << m << std::endl; } }else{ if( d_match_pattern[argIndex].getKind()==INST_CONSTANT ){ Node ic = d_match_pattern[argIndex]; - for( std::map< Node, TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){ + for( std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){ Node t = it->first; if( m.d_map[ ic ].isNull() || m.d_map[ ic ]==t ){ Node prev = m.d_map[ ic ]; m.d_map[ ic ] = t; - addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second), instLimit, addSplits ); + addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); m.d_map[ ic ] = prev; } } }else{ Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] ); - std::map< Node, TermArgTrie >::iterator it = tat->d_data.find( r ); + std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r ); if( it!=tat->d_data.end() ){ - addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second), instLimit, addSplits ); + addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); } } } diff --git a/src/theory/inst_match.h b/src/theory/inst_match.h index dcb9190a1..7cc5b2249 100644 --- a/src/theory/inst_match.h +++ b/src/theory/inst_match.h @@ -281,7 +281,7 @@ public: given Node can't match the pattern */ virtual bool nonunifiable( TNode t, const std::vector & vars) = 0; /** add instantiations directly */ - virtual int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit = 0, bool addSplits = false ) = 0; + virtual int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ) = 0; /** add ground term t, called when t is added to term db */ virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) = 0; };/* class IMGenerator */ @@ -350,26 +350,26 @@ public: given Node can't match the pattern */ bool nonunifiable( TNode t, const std::vector & vars); /** add instantiations */ - int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit = 0, bool addSplits = false ); + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); /** add ground term t */ int addTerm( Node f, Node t, QuantifiersEngine* qe ); };/* class InstMatchGenerator */ /** smart multi-trigger implementation */ class InstMatchGeneratorMulti : public IMGenerator { -private: - void processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ); private: /** indexed trie */ typedef std::pair< std::pair< int, int >, InstMatchTrie* > IndexedTrie; - /** collect instantiations */ - void collectInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr, - std::vector< IndexedTrie >& unique_var_tries, - int trieIndex, int childIndex, int endChildIndex, bool modEq ); - /** collect instantiations 2 */ - void collectInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, - std::vector< IndexedTrie >& unique_var_tries, - int uvtIndex, InstMatchTrie* tr = NULL, int trieIndex = 0 ); + /** process new match */ + void processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ); + /** process new instantiations */ + void processNewInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr, + std::vector< IndexedTrie >& unique_var_tries, + int trieIndex, int childIndex, int endChildIndex, bool modEq ); + /** process new instantiations 2 */ + void processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, + std::vector< IndexedTrie >& unique_var_tries, + int uvtIndex, InstMatchTrie* tr = NULL, int trieIndex = 0 ); private: /** var contains (variable indices) for each pattern node */ std::map< Node, std::vector< int > > d_var_contains; @@ -400,12 +400,14 @@ public: given Node can't match the pattern */ bool nonunifiable( TNode t, const std::vector & vars) { return true; } /** add instantiations */ - int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit = 0, bool addSplits = false ); + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); /** add ground term t */ int addTerm( Node f, Node t, QuantifiersEngine* qe ); };/* class InstMatchGeneratorMulti */ -class TermArgTrie; +namespace quantifiers{ + class TermArgTrie; +} /** smart (single)-trigger implementation */ class InstMatchGeneratorSimple : public IMGenerator { @@ -415,8 +417,7 @@ private: /** match term */ Node d_match_pattern; /** add instantiations */ - void addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, - int argIndex, TermArgTrie* tat, int instLimit, bool addSplits ); + void addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ); public: /** constructors */ InstMatchGeneratorSimple( Node f, Node pat ) : d_f( f ), d_match_pattern( pat ){} @@ -432,7 +433,7 @@ public: given Node can't match the pattern */ bool nonunifiable( TNode t, const std::vector & vars) { return true; } /** add instantiations */ - int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit = 0, bool addSplits = false ); + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); /** add ground term t, possibly add instantiations */ int addTerm( Node f, Node t, QuantifiersEngine* qe ); };/* class InstMatchGeneratorSimple */ diff --git a/src/theory/instantiator_default.cpp b/src/theory/instantiator_default.cpp index 4d6ea2fdb..a1766ce3c 100644 --- a/src/theory/instantiator_default.cpp +++ b/src/theory/instantiator_default.cpp @@ -33,7 +33,8 @@ void InstantiatorDefault::assertNode( Node assertion ){ void InstantiatorDefault::processResetInstantiationRound( Theory::Effort effort ){ } -int InstantiatorDefault::process( Node f, Theory::Effort effort, int e, int limitInst ){ +int InstantiatorDefault::process( Node f, Theory::Effort effort, int e ){ + /* if( e < 4 ){ return InstStrategy::STATUS_UNFINISHED; }else if( e == 4 ){ @@ -50,5 +51,6 @@ int InstantiatorDefault::process( Node f, Theory::Effort effort, int e, int limi } d_quantEngine->addInstantiation( f, m ); } + */ return InstStrategy::STATUS_UNKNOWN; } diff --git a/src/theory/instantiator_default.h b/src/theory/instantiator_default.h index 8e0e47231..967a0c1ca 100644 --- a/src/theory/instantiator_default.h +++ b/src/theory/instantiator_default.h @@ -32,7 +32,7 @@ protected: /** reset instantiation round */ void processResetInstantiationRound(Theory::Effort effort); /** process quantifier */ - int process(Node f, Theory::Effort effort, int e, int limitInst = 0); + int process( Node f, Theory::Effort effort, int e ); public: InstantiatorDefault(context::Context* c, QuantifiersEngine* ie, Theory* th); ~InstantiatorDefault() { } diff --git a/src/theory/model.cpp b/src/theory/model.cpp new file mode 100644 index 000000000..03bba185c --- /dev/null +++ b/src/theory/model.cpp @@ -0,0 +1,436 @@ +/********************* */ +/*! \file model.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of model class + **/ + +#include "theory/model.h" +#include "theory/quantifiers_engine.h" +#include "theory/theory_engine.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; + +void RepSet::clear(){ + d_type_reps.clear(); + d_tmap.clear(); +} + +void RepSet::add( Node n ){ + TypeNode t = n.getType(); + d_tmap[ n ] = (int)d_type_reps[t].size(); + d_type_reps[t].push_back( n ); +} + +void RepSet::set( TypeNode t, std::vector< Node >& reps ){ + for( size_t i=0; i >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){ + out << it->first << " : " << std::endl; + for( int i=0; i<(int)it->second.size(); i++ ){ + out << " " << i << ": " << it->second[i] << std::endl; + } + } +#else + for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){ + if( !it->first.isFunction() && !it->first.isPredicate() ){ + out << "(" << it->first << " " << it->second.size(); + out << " ("; + for( int i=0; i<(int)it->second.size(); i++ ){ + if( i>0 ){ out << " "; } + out << it->second[i]; + } + out << ")"; + out << ")" << std::endl; + } + } +#endif +} + +TheoryModel::TheoryModel( context::Context* c, std::string name ) : +d_equalityEngine( c, name ){ + d_true = NodeManager::currentNM()->mkConst( true ); + d_false = NodeManager::currentNM()->mkConst( false ); +} + +void TheoryModel::addDefineFunction( Node n ){ + d_define_funcs.push_back( n ); + d_defines.push_back( 0 ); +} + +void TheoryModel::addDefineType( TypeNode tn ){ + d_define_types.push_back( tn ); + d_defines.push_back( 1 ); +} + +void TheoryModel::toStreamFunction( Node n, std::ostream& out ){ + out << "(" << n; + //out << " : " << n.getType(); + out << " "; + Node value = getValue( n ); + if( n.getType().isSort() ){ + int index = d_ra.getIndexFor( value ); + if( index!=-1 ){ + out << value.getType() << "_" << index; + }else{ + out << value; + } + }else{ + out << value; + } + out << ")" << std::endl; +} + +void TheoryModel::toStreamType( TypeNode tn, std::ostream& out ){ + out << "(" << tn; + if( tn.isSort() ){ + if( d_ra.d_type_reps.find( tn )!=d_ra.d_type_reps.end() ){ + out << " " << d_ra.d_type_reps[tn].size(); + //out << " ("; + //for( size_t i=0; i0 ){ out << " "; } + // out << d_ra.d_type_reps[tn][i]; + //} + //out << ")"; + } + } + out << ")" << std::endl; +} + +void TheoryModel::toStream( std::ostream& out ){ + int funcIndex = 0; + int typeIndex = 0; + for( size_t i=0; i Propositional variable." << std::endl; + // return d_te->getPropEngine()->getValue( n ); + //} + + // special case: value of a constant == itself + if(metakind == kind::metakind::CONSTANT) { + Debug("model") << "-> Constant." << std::endl; + return n; + } + + // see if the value is explicitly set in the model + if( d_equalityEngine.hasTerm( n ) ){ + Debug("model") << "-> Defined term." << std::endl; + return getRepresentative( n ); + }else{ + Node nn; + if( n.getNumChildren()>0 ){ + std::vector< Node > children; + if( metakind == kind::metakind::PARAMETERIZED ){ + Debug("model-debug") << "get operator: " << n.getOperator() << std::endl; + children.push_back( n.getOperator() ); + } + //evaluate the children + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + Node val = getValue( n[i] ); + Debug("model-debug") << i << " : " << n[i] << " -> " << val << std::endl; + Assert( !val.isNull() ); + children.push_back( val ); + } + Debug("model-debug") << "Done eval children" << std::endl; + nn = NodeManager::currentNM()->mkNode( n.getKind(), children ); + }else{ + nn = n; + } + //interpretation is the rewritten form + nn = Rewriter::rewrite( nn ); + + // special case: value of a constant == itself + if(metakind == kind::metakind::CONSTANT) { + Debug("model") << "-> Theory-interpreted term." << std::endl; + return nn; + }else if( d_equalityEngine.hasTerm( nn ) ){ + Debug("model") << "-> Theory-interpreted (defined) term." << std::endl; + return getRepresentative( nn ); + }else{ + Debug("model") << "-> Model-interpreted term." << std::endl; + //otherwise, get the interpreted value in the model + return getInterpretedValue( nn ); + } + } + + ////case for equality + //if( n.getKind()==EQUAL ){ + // Debug("model") << "-> Equality." << std::endl; + // Node n1 = getValue( n[0] ); + // Node n2 = getValue( n[1] ); + // return NodeManager::currentNM()->mkConst( n1==n2 ); + //} +} + +Node TheoryModel::getDomainValue( TypeNode tn, std::vector< Node >& exclude ){ + if( d_ra.d_type_reps.find( tn )!=d_ra.d_type_reps.end() ){ + //try to find a pre-existing arbitrary element + for( size_t i=0; ibooleanType() ){ + if( d_ra.d_type_reps[tn].empty() ){ + return d_false; + }else if( d_ra.d_type_reps[tn].size()==1 ){ + return NodeManager::currentNM()->mkConst( areEqual( d_ra.d_type_reps[tn][0], d_false ) ); + }else{ + return Node::null(); + } + }else if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){ + int val = 0; + do{ + Node r = NodeManager::currentNM()->mkConst( Rational(val) ); + if( std::find( d_ra.d_type_reps[tn].begin(), d_ra.d_type_reps[tn].end(), r )==d_ra.d_type_reps[tn].end() && + !d_equalityEngine.hasTerm( r ) ){ + return r; + } + val++; + }while( true ); + }else{ + //otherwise must make a variable FIXME: how to make constants for other sorts? + //return NodeManager::currentNM()->mkVar( tn ); + return Node::null(); + } +} + +/** assert equality */ +void TheoryModel::assertEquality( Node a, Node b, bool polarity ){ + d_equalityEngine.assertEquality( a.eqNode(b), polarity, Node::null() ); +} + +/** assert predicate */ +void TheoryModel::assertPredicate( Node a, bool polarity ){ + if( a.getKind()==EQUAL ){ + d_equalityEngine.assertEquality( a, polarity, Node::null() ); + }else{ + d_equalityEngine.assertPredicate( a, polarity, Node::null() ); + } +} + +/** assert equality engine */ +void TheoryModel::assertEqualityEngine( eq::EqualityEngine* ee ){ + eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee ); + while( !eqcs_i.isFinished() ){ + Node eqc = (*eqcs_i); + bool predicate = false; + bool predPolarity = false; + if( eqc.getType()==NodeManager::currentNM()->booleanType() ){ + predicate = true; + predPolarity = ee->areEqual( eqc, d_true ); + //FIXME: do we guarentee that all boolean equivalence classes contain either d_true or d_false? + } + eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, ee ); + while( !eqc_i.isFinished() ){ + if( predicate ){ + assertPredicate( *eqc_i, predPolarity ); + }else{ + assertEquality( *eqc_i, eqc, true ); + } + ++eqc_i; + } + ++eqcs_i; + } +} + +bool TheoryModel::hasTerm( Node a ){ + return d_equalityEngine.hasTerm( a ); +} + +Node TheoryModel::getRepresentative( Node a ){ + if( d_equalityEngine.hasTerm( a ) ){ + return d_reps[ d_equalityEngine.getRepresentative( a ) ]; + }else{ + return a; + } +} + +bool TheoryModel::areEqual( Node a, Node b ){ + if( a==b ){ + return true; + }else if( d_equalityEngine.hasTerm( a ) && d_equalityEngine.hasTerm( b ) ){ + return d_equalityEngine.areEqual( a, b ); + }else{ + return false; + } +} + +bool TheoryModel::areDisequal( Node a, Node b ){ + if( d_equalityEngine.hasTerm( a ) && d_equalityEngine.hasTerm( b ) ){ + return d_equalityEngine.areDisequal( a, b, false ); + }else{ + return false; + } +} + +//for debugging +void TheoryModel::printRepresentativeDebug( const char* c, Node r ){ + if( r.isNull() ){ + Debug( c ) << "null"; + }else if( r.getType()==NodeManager::currentNM()->booleanType() ){ + if( areEqual( r, d_true ) ){ + Debug( c ) << "true"; + }else{ + Debug( c ) << "false"; + } + }else{ + Debug( c ) << getRepresentative( r ); + } +} + +void TheoryModel::printRepresentative( std::ostream& out, Node r ){ + Assert( !r.isNull() ); + if( r.isNull() ){ + out << "null"; + }else if( r.getType()==NodeManager::currentNM()->booleanType() ){ + if( areEqual( r, d_true ) ){ + out << "true"; + }else{ + out << "false"; + } + }else{ + out << getRepresentative( r ); + } +} + +DefaultModel::DefaultModel( context::Context* c, std::string name ) : TheoryModel( c, name ){ + +} + +Node DefaultModel::getInterpretedValue( TNode n ){ + Assert( !d_equalityEngine.hasTerm( n ) ); + TypeNode type = n.getType(); + if( type.isFunction() || type.isPredicate() ){ + //DO_THIS? + return n; + }else{ + //first, try to choose an existing term as value + std::vector< Node > v_emp; + Node n2 = getDomainValue( type, v_emp ); + if( !n2.isNull() ){ + return n2; + }else{ + //otherwise, choose new valuse + n2 = getNewDomainValue( type, true ); + if( !n2.isNull() ){ + return n2; + }else{ + return n; + } + } + } +} + +TheoryEngineModelBuilder::TheoryEngineModelBuilder( TheoryEngine* te ) : d_te( te ){ + +} + +void TheoryEngineModelBuilder::buildModel( Model* m ){ + TheoryModel* tm = (TheoryModel*)m; + //reset representative information + tm->d_reps.clear(); + tm->d_ra.clear(); + Debug( "model-builder" ) << "TheoryEngineModelBuilder: Collect model info..." << std::endl; + //collect model info from the theory engine + d_te->collectModelInfo( tm ); + Debug( "model-builder" ) << "TheoryEngineModelBuilder: Build representatives..." << std::endl; + //populate term database, store representatives + eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &tm->d_equalityEngine ); + while( !eqcs_i.isFinished() ){ + Node eqc = (*eqcs_i); + //add terms to model + eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &tm->d_equalityEngine ); + while( !eqc_i.isFinished() ){ + tm->addTerm( *eqc_i ); + ++eqc_i; + } + //choose representative for this equivalence class + Node rep = chooseRepresentative( tm, eqc ); + //store representative in representative set + if( !rep.isNull() ){ + tm->d_reps[ eqc ] = rep; + tm->d_ra.add( rep ); + } + ++eqcs_i; + } + //do model-builder specific initialization + // this should include choosing representatives for equivalence classes that have not yet been + // assigned representatives + processBuildModel( tm ); +} + +Node TheoryEngineModelBuilder::chooseRepresentative( TheoryModel* tm, Node eqc ){ + eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &tm->d_equalityEngine ); + while( !eqc_i.isFinished() ){ + //if constant, use this as representative + if( (*eqc_i).getMetaKind()==kind::metakind::CONSTANT ){ + return *eqc_i; + } + ++eqc_i; + } + return Node::null(); +} + +void TheoryEngineModelBuilder::processBuildModel( TheoryModel* tm ){ + Debug( "model-builder" ) << "TheoryEngineModelBuilder: Complete model..." << std::endl; + //create constants for all unresolved equivalence classes + eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &tm->d_equalityEngine ); + while( !eqcs_i.isFinished() ){ + Node n = *eqcs_i; + if( tm->d_reps.find( n )!=tm->d_reps.end() ){ + TypeNode tn = n.getType(); + //add new constant to equivalence class + Node rep = tm->getNewDomainValue( tn, true ); + if( !rep.isNull() ){ + tm->assertEquality( n, rep, true ); + }else{ + rep = n; + } + tm->d_reps[ n ] = rep; + tm->d_ra.add( rep ); + } + ++eqcs_i; + } +} diff --git a/src/theory/model.h b/src/theory/model.h new file mode 100644 index 000000000..4d6035ae5 --- /dev/null +++ b/src/theory/model.h @@ -0,0 +1,165 @@ +/********************* */ +/*! \file model.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Model class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY_MODEL_H +#define __CVC4__THEORY_MODEL_H + +#include "util/model.h" +#include "theory/uf/equality_engine.h" + +namespace CVC4 { +namespace theory { + +class QuantifiersEngine; + +/** this class stores a representative set */ +class RepSet { +public: + RepSet(){} + ~RepSet(){} + std::map< TypeNode, std::vector< Node > > d_type_reps; + std::map< Node, int > d_tmap; + /** clear the set */ + void clear(); + /** has type */ + bool hasType( TypeNode tn ) { return d_type_reps.find( tn )!=d_type_reps.end(); } + /** add representative for type */ + void add( Node n ); + /** set the representatives for type */ + void set( TypeNode t, std::vector< Node >& reps ); + /** returns index in d_type_reps for node n */ + int getIndexFor( Node n ) { return d_tmap.find( n )!=d_tmap.end() ? d_tmap[n] : -1; } + /** debug print */ + void toStream(std::ostream& out); +}; + +//representative domain +typedef std::vector< int > RepDomain; + +class TheoryEngineModelBuilder; + +/** Theory Model class + * For Model m, should call m.initialize() before using + */ +class TheoryModel : public Model +{ + friend class TheoryEngineModelBuilder; +protected: + /** add term */ + virtual void addTerm( Node n ) {} +private: + /** definitions */ + std::vector< Node > d_define_funcs; + std::vector< TypeNode > d_define_types; + std::vector< int > d_defines; +protected: + /** to stream functions */ + virtual void toStreamFunction( Node n, std::ostream& out ); + virtual void toStreamType( TypeNode tn, std::ostream& out ); +public: + TheoryModel( context::Context* c, std::string name ); + virtual ~TheoryModel(){} + /** equality engine containing all known equalities/disequalities */ + eq::EqualityEngine d_equalityEngine; + /** map of representatives of equality engine to used representatives in representative set */ + std::map< Node, Node > d_reps; + /** representative alphabet */ + RepSet d_ra; + //true/false nodes + Node d_true; + Node d_false; +public: + /** add defined function */ + void addDefineFunction( Node n ); + /** add defined type */ + void addDefineType( TypeNode tn ); + /** + * Get value function. This should be called only after a ModelBuilder has called buildModel(...) + * on this model. + */ + Node getValue( TNode n ); + /** get interpreted value, should be a representative in d_reps */ + virtual Node getInterpretedValue( TNode n ) = 0; + /** get existing domain value, with possible exclusions */ + Node getDomainValue( TypeNode tn, std::vector< Node >& exclude ); + /** get new domain value */ + Node getNewDomainValue( TypeNode tn, bool mkConst = false ); +public: + /** assert equality */ + void assertEquality( Node a, Node b, bool polarity ); + /** assert predicate */ + void assertPredicate( Node a, bool polarity ); + /** assert equality engine */ + void assertEqualityEngine( eq::EqualityEngine* ee ); +public: + //queries about equality + bool hasTerm( Node a ); + Node getRepresentative( Node a ); + bool areEqual( Node a, Node b ); + bool areDisequal( Node a, Node b ); +public: + /** print representative function */ + void printRepresentativeDebug( const char* c, Node r ); + void printRepresentative( std::ostream& out, Node r ); + /** to stream function */ + void toStream( std::ostream& out ); +}; + +//default model class: extends model arbitrarily +class DefaultModel : public TheoryModel +{ +public: + DefaultModel( context::Context* c, std::string name ); + virtual ~DefaultModel(){} +public: + Node getInterpretedValue( TNode n ); +}; + +//incomplete model class: does not extend model +class IncompleteModel : public TheoryModel +{ +public: + IncompleteModel( context::Context* c, std::string name ) : TheoryModel( c, name ){} + virtual ~IncompleteModel(){} +public: + Node getInterpretedValue( TNode n ) { return Node::null(); } +}; + + +class TheoryEngineModelBuilder : public ModelBuilder +{ +protected: + /** pointer to theory engine */ + TheoryEngine* d_te; + /** choose representative */ + virtual Node chooseRepresentative( TheoryModel* tm, Node eqc ); + /** representatives that are current not set */ + virtual void processBuildModel( TheoryModel* tm ); +public: + TheoryEngineModelBuilder( TheoryEngine* te ); + virtual ~TheoryEngineModelBuilder(){} + /** + * Build model function. + */ + void buildModel( Model* m ); +}; + +} +} + +#endif \ No newline at end of file diff --git a/src/theory/quantifiers/Makefile.am b/src/theory/quantifiers/Makefile.am index de74e44f8..ae5b99c06 100644 --- a/src/theory/quantifiers/Makefile.am +++ b/src/theory/quantifiers/Makefile.am @@ -16,6 +16,14 @@ libquantifiers_la_SOURCES = \ instantiation_engine.h \ instantiation_engine.cpp \ model_engine.h \ - model_engine.cpp + model_engine.cpp \ + relevant_domain.h \ + relevant_domain.cpp \ + rep_set_iterator.h \ + rep_set_iterator.cpp \ + term_database.h \ + term_database.cpp \ + first_order_model.h \ + first_order_model.cpp EXTRA_DIST = kinds \ No newline at end of file diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp new file mode 100644 index 000000000..71a48b33d --- /dev/null +++ b/src/theory/quantifiers/first_order_model.cpp @@ -0,0 +1,146 @@ +/********************* */ +/*! \file first_order_model.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of model engine model class + **/ + +#include "theory/quantifiers/first_order_model.h" +#include "theory/quantifiers/rep_set_iterator.h" +#include "theory/quantifiers/model_engine.h" +#include "theory/uf/theory_uf_strong_solver.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; + +FirstOrderModel::FirstOrderModel( QuantifiersEngine* qe, context::Context* c, std::string name ) : DefaultModel( c, name ), +d_term_db( qe->getTermDatabase() ), d_forall_asserts( c ){ + +} + +void FirstOrderModel::initialize(){ + //rebuild models + d_uf_model.clear(); + d_array_model.clear(); + //for each quantifier, collect all operators we care about + for( int i=0; iprintModelEngine ){ + for( std::map< TypeNode, std::vector< Node > >::iterator it = d_ra.d_type_reps.begin(); it != d_ra.d_type_reps.end(); ++it ){ + if( uf::StrongSolverTheoryUf::isRelevantType( it->first ) ){ + Message() << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl; + } + } + } +} + +void FirstOrderModel::initializeModelForTerm( Node n ){ + if( n.getKind()==APPLY_UF ){ + Node op = n.getOperator(); + if( d_uf_model.find( op )==d_uf_model.end() ){ + TypeNode tn = op.getType(); + tn = tn[ (int)tn.getNumChildren()-1 ]; + if( tn==NodeManager::currentNM()->booleanType() || uf::StrongSolverTheoryUf::isRelevantType( tn ) ){ + d_uf_model[ op ] = uf::UfModel( op, this ); + } + } + } + if( n.getKind()!=STORE && n.getType().isArray() ){ + d_array_model[n] = Node::null(); + } + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + initializeModelForTerm( n[i] ); + } +} + +void FirstOrderModel::toStreamFunction( Node n, std::ostream& out ){ + if( d_uf_model.find( n )!=d_uf_model.end() ){ + //d_uf_model[n].toStream( out ); + Node value = d_uf_model[n].getFunctionValue(); + out << "(" << n << " " << value << ")"; + //}else if( d_array_model.find( n )!=d_array_model.end() ){ + //out << "(" << n << " " << d_array_model[n] << ")" << std::endl; + // out << "(" << n << " Array)" << std::endl; + }else{ + DefaultModel::toStreamFunction( n, out ); + } +} + +void FirstOrderModel::toStreamType( TypeNode tn, std::ostream& out ){ + DefaultModel::toStreamType( tn, out ); +} + +Node FirstOrderModel::getInterpretedValue( TNode n ){ + Debug("fo-model") << "get interpreted value " << n << std::endl; + TypeNode type = n.getType(); + if( type.isFunction() || type.isPredicate() ){ + if( d_uf_model.find( n )!=d_uf_model.end() ){ + return d_uf_model[n].getFunctionValue(); + }else{ + return n; + } + }else if( n.getKind()==APPLY_UF ){ + int depIndex; + return d_uf_model[ n.getOperator() ].getValue( n, depIndex ); + } + return DefaultModel::getInterpretedValue( n ); +} + +TermDb* FirstOrderModel::getTermDatabase(){ + return d_term_db; +} + + +void FirstOrderModel::toStream(std::ostream& out){ + DefaultModel::toStream( out ); +#if 0 + out << "---Current Model---" << std::endl; + out << "Representatives: " << std::endl; + d_ra.toStream( out ); + out << "Functions: " << std::endl; + for( std::map< Node, uf::UfModel >::iterator it = d_uf_model.begin(); it != d_uf_model.end(); ++it ){ + it->second.toStream( out ); + out << std::endl; + } +#elif 0 + d_ra.toStream( out ); + //print everything not related to UF in equality engine + eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine ); + while( !eqcs_i.isFinished() ){ + Node eqc = (*eqcs_i); + Node rep = getRepresentative( eqc ); + TypeNode type = rep.getType(); + eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine ); + while( !eqc_i.isFinished() ){ + //do not print things that have interpretations in model + if( (*eqc_i).getMetaKind()!=kind::metakind::CONSTANT && !hasInterpretedValue( *eqc_i ) ){ + out << "(" << (*eqc_i) << " " << rep << ")" << std::endl; + } + ++eqc_i; + } + ++eqcs_i; + } + //print functions + for( std::map< Node, uf::UfModel >::iterator it = d_uf_model.begin(); it != d_uf_model.end(); ++it ){ + it->second.toStream( out ); + out << std::endl; + } +#endif +} \ No newline at end of file diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h new file mode 100644 index 000000000..832acbee3 --- /dev/null +++ b/src/theory/quantifiers/first_order_model.h @@ -0,0 +1,82 @@ +/********************* */ +/*! \file first_order_model.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Model extended classes + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__FIRST_ORDER_MODEL_H +#define __CVC4__FIRST_ORDER_MODEL_H + +#include "theory/model.h" +#include "theory/uf/theory_uf_model.h" + +namespace CVC4 { +namespace theory { + +struct ModelBasisAttributeId {}; +typedef expr::Attribute ModelBasisAttribute; +//for APPLY_UF terms, 1 : term has direct child with model basis attribute, +// 0 : term has no direct child with model basis attribute. +struct ModelBasisArgAttributeId {}; +typedef expr::Attribute ModelBasisArgAttribute; + +class QuantifiersEngine; + +namespace quantifiers{ + +class TermDb; + +class FirstOrderModel : public DefaultModel +{ +private: + //pointer to term database + TermDb* d_term_db; + //for initialize model + void initializeModelForTerm( Node n ); + /** to stream functions */ + void toStreamFunction( Node n, std::ostream& out ); + void toStreamType( TypeNode tn, std::ostream& out ); +public: //for Theory UF: + //models for each UF operator + std::map< Node, uf::UfModel > d_uf_model; +public: //for Theory Arrays: + //default value for each non-store array + std::map< Node, Node > d_array_model; +public: //for Theory Quantifiers: + /** list of quantifiers asserted in the current context */ + context::CDList d_forall_asserts; + /** get number of asserted quantifiers */ + int getNumAssertedQuantifiers() { return (int)d_forall_asserts.size(); } + /** get asserted quantifier */ + Node getAssertedQuantifier( int i ) { return d_forall_asserts[i]; } +public: + FirstOrderModel( QuantifiersEngine* qe, context::Context* c, std::string name ); + virtual ~FirstOrderModel(){} + // initialize the model + void initialize(); + /** get interpreted value */ + Node getInterpretedValue( TNode n ); +public: + /** get term database */ + TermDb* getTermDatabase(); + /** to stream function */ + void toStream( std::ostream& out ); +}; + +} +} +} + +#endif diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp index c1476acb8..fae54c151 100644 --- a/src/theory/quantifiers/instantiation_engine.cpp +++ b/src/theory/quantifiers/instantiation_engine.cpp @@ -18,6 +18,8 @@ #include "theory/theory_engine.h" #include "theory/uf/theory_uf_instantiator.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers/first_order_model.h" using namespace std; using namespace CVC4; @@ -26,15 +28,9 @@ using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::quantifiers; -//#define IE_PRINT_PROCESS_TIMES +InstantiationEngine::InstantiationEngine( QuantifiersEngine* qe, bool setIncomplete ) : +QuantifiersModule( qe ), d_setIncomplete( setIncomplete ){ -InstantiationEngine::InstantiationEngine( TheoryQuantifiers* th ) : -d_th( th ){ - -} - -QuantifiersEngine* InstantiationEngine::getQuantifiersEngine(){ - return d_th->getQuantifiersEngine(); } bool InstantiationEngine::hasAddedCbqiLemma( Node f ) { @@ -46,25 +42,25 @@ void InstantiationEngine::addCbqiLemma( Node f ){ //code for counterexample-based quantifier instantiation Debug("cbqi") << "Do cbqi for " << f << std::endl; //make the counterexample body - //Node ceBody = f[1].substitute( getQuantifiersEngine()->d_vars[f].begin(), getQuantifiersEngine()->d_vars[f].end(), - // getQuantifiersEngine()->d_inst_constants[f].begin(), - // getQuantifiersEngine()->d_inst_constants[f].end() ); + //Node ceBody = f[1].substitute( d_quantEngine->d_vars[f].begin(), d_quantEngine->d_vars[f].end(), + // d_quantEngine->d_inst_constants[f].begin(), + // d_quantEngine->d_inst_constants[f].end() ); //get the counterexample literal - Node ceBody = getQuantifiersEngine()->getCounterexampleBody( f ); - Node ceLit = d_th->getValuation().ensureLiteral( ceBody.notNode() ); + Node ceBody = d_quantEngine->getTermDatabase()->getCounterexampleBody( f ); + Node ceLit = d_quantEngine->getValuation().ensureLiteral( ceBody.notNode() ); d_ce_lit[ f ] = ceLit; - getQuantifiersEngine()->setInstantiationConstantAttr( ceLit, f ); + d_quantEngine->getTermDatabase()->setInstantiationConstantAttr( ceLit, f ); // set attributes, mark all literals in the body of n as dependent on cel //registerLiterals( ceLit, f ); //require any decision on cel to be phase=true - d_th->getOutputChannel().requirePhase( ceLit, true ); + d_quantEngine->getOutputChannel().requirePhase( ceLit, true ); Debug("cbqi-debug") << "Require phase " << ceLit << " = true." << std::endl; //add counterexample lemma NodeBuilder<> nb(kind::OR); nb << f << ceLit; Node lem = nb; Debug("cbqi-debug") << "Counterexample lemma : " << lem << std::endl; - d_th->getOutputChannel().lemma( lem ); + d_quantEngine->getOutputChannel().lemma( lem ); } bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ @@ -72,8 +68,8 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ if( Options::current()->cbqi ){ //check if any cbqi lemma has not been added yet bool addedLemma = false; - for( int i=0; i<(int)getQuantifiersEngine()->getNumAssertedQuantifiers(); i++ ){ - Node f = getQuantifiersEngine()->getAssertedQuantifier( i ); + for( int i=0; i<(int)d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + Node f = d_quantEngine->getModel()->getAssertedQuantifier( i ); if( doCbqi( f ) && !hasAddedCbqiLemma( f ) ){ //add cbqi lemma addCbqiLemma( f ); @@ -87,14 +83,9 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ //if not, proceed to instantiation round Debug("inst-engine") << "IE: Instantiation Round." << std::endl; Debug("inst-engine-ctrl") << "IE: Instantiation Round." << std::endl; - //reset instantiators + //reset the quantifiers engine Debug("inst-engine-ctrl") << "Reset IE" << std::endl; - for( int i=0; igetInstantiator( i ) ){ - getQuantifiersEngine()->getInstantiator( i )->resetInstantiationRound( effort ); - } - } - getQuantifiersEngine()->getTermDatabase()->reset( effort ); + d_quantEngine->resetInstantiationRound( effort ); //iterate over an internal effort level e int e = 0; int eLimit = effort==Theory::EFFORT_LAST_CALL ? 10 : 2; @@ -104,20 +95,19 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ Debug("inst-engine") << "IE: Prepare instantiation (" << e << ")." << std::endl; d_inst_round_status = InstStrategy::STATUS_SAT; //instantiate each quantifier - for( int q=0; qgetNumAssertedQuantifiers(); q++ ){ - Node f = getQuantifiersEngine()->getAssertedQuantifier( q ); + for( int q=0; qgetModel()->getNumAssertedQuantifiers(); q++ ){ + Node f = d_quantEngine->getModel()->getAssertedQuantifier( q ); Debug("inst-engine-debug") << "IE: Instantiate " << f << "..." << std::endl; //if this quantifier is active - if( getQuantifiersEngine()->getActive( f ) ){ - //int e_use = getQuantifiersEngine()->getRelevance( f )==-1 ? e - 1 : e; + if( d_quantEngine->getActive( f ) ){ + //int e_use = d_quantEngine->getRelevance( f )==-1 ? e - 1 : e; int e_use = e; if( e_use>=0 ){ //use each theory instantiator to instantiate f for( int i=0; igetInstantiator( i ) ){ - Debug("inst-engine-debug") << "Do " << getQuantifiersEngine()->getInstantiator( i )->identify() << " " << e_use << std::endl; - int limitInst = 0; - int quantStatus = getQuantifiersEngine()->getInstantiator( i )->doInstantiation( f, effort, e_use, limitInst ); + if( d_quantEngine->getInstantiator( i ) ){ + Debug("inst-engine-debug") << "Do " << d_quantEngine->getInstantiator( i )->identify() << " " << e_use << std::endl; + int quantStatus = d_quantEngine->getInstantiator( i )->doInstantiation( f, effort, e_use ); Debug("inst-engine-debug") << " -> status is " << quantStatus << std::endl; InstStrategy::updateStatus( d_inst_round_status, quantStatus ); } @@ -126,31 +116,31 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ } } //do not consider another level if already added lemma at this level - if( getQuantifiersEngine()->hasAddedLemma() ){ + if( d_quantEngine->hasAddedLemma() ){ d_inst_round_status = InstStrategy::STATUS_UNKNOWN; } e++; } Debug("inst-engine") << "All instantiators finished, # added lemmas = "; - Debug("inst-engine") << (int)getQuantifiersEngine()->d_lemmas_waiting.size() << std::endl; + Debug("inst-engine") << (int)d_quantEngine->d_lemmas_waiting.size() << std::endl; //Notice() << "All instantiators finished, # added lemmas = " << (int)d_lemmas_waiting.size() << std::endl; - if( !getQuantifiersEngine()->hasAddedLemma() ){ + if( !d_quantEngine->hasAddedLemma() ){ Debug("inst-engine-stuck") << "No instantiations produced at this state: " << std::endl; for( int i=0; igetInstantiator( i ) ){ - getQuantifiersEngine()->getInstantiator( i )->debugPrint("inst-engine-stuck"); + if( d_quantEngine->getInstantiator( i ) ){ + d_quantEngine->getInstantiator( i )->debugPrint("inst-engine-stuck"); Debug("inst-engine-stuck") << std::endl; } } Debug("inst-engine-ctrl") << "---Fail." << std::endl; return false; }else{ - Debug("inst-engine-ctrl") << "---Done. " << (int)getQuantifiersEngine()->d_lemmas_waiting.size() << std::endl; -#ifdef IE_PRINT_PROCESS_TIMES - Notice() << "lemmas = " << (int)getQuantifiersEngine()->d_lemmas_waiting.size() << std::endl; -#endif + Debug("inst-engine-ctrl") << "---Done. " << (int)d_quantEngine->d_lemmas_waiting.size() << std::endl; + if( Options::current()->printInstEngine ){ + Message() << "Added lemmas = " << (int)d_quantEngine->d_lemmas_waiting.size() << std::endl; + } //flush lemmas to output channel - getQuantifiersEngine()->flushLemmas( &d_th->getOutputChannel() ); + d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() ); return true; } } @@ -174,42 +164,43 @@ void InstantiationEngine::check( Theory::Effort e ){ } if( performCheck ){ Debug("inst-engine") << "IE: Check " << e << " " << ierCounter << std::endl; -#ifdef IE_PRINT_PROCESS_TIMES - double clSet = double(clock())/double(CLOCKS_PER_SEC); - Notice() << "Run instantiation round " << e << " " << ierCounter << std::endl; -#endif + double clSet = 0; + if( Options::current()->printInstEngine ){ + clSet = double(clock())/double(CLOCKS_PER_SEC); + Message() << "---Instantiation Engine Round, effort = " << e << "---" << std::endl; + } bool quantActive = false; //for each quantifier currently asserted, // such that the counterexample literal is not in positive in d_counterexample_asserts // for( BoolMap::iterator i = d_forall_asserts.begin(); i != d_forall_asserts.end(); i++ ) { // if( (*i).second ) { - Debug("quantifiers") << "quantifiers: check: asserted quantifiers size" - << getQuantifiersEngine()->getNumAssertedQuantifiers() << std::endl; - for( int i=0; i<(int)getQuantifiersEngine()->getNumAssertedQuantifiers(); i++ ){ - Node n = getQuantifiersEngine()->getAssertedQuantifier( i ); + Debug("quantifiers") << "quantifiers: check: asserted quantifiers size" + << d_quantEngine->getModel()->getNumAssertedQuantifiers() << std::endl; + for( int i=0; i<(int)d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + Node n = d_quantEngine->getModel()->getAssertedQuantifier( i ); if( Options::current()->cbqi && hasAddedCbqiLemma( n ) ){ Node cel = d_ce_lit[ n ]; bool active, value; bool ceValue = false; - if( d_th->getValuation().hasSatValue( cel, value ) ){ + if( d_quantEngine->getValuation().hasSatValue( cel, value ) ){ active = value; ceValue = true; }else{ active = true; } - getQuantifiersEngine()->setActive( n, active ); + d_quantEngine->setActive( n, active ); if( active ){ Debug("quantifiers") << " Active : " << n; quantActive = true; }else{ Debug("quantifiers") << " NOT active : " << n; - if( d_th->getValuation().isDecision( cel ) ){ + if( d_quantEngine->getValuation().isDecision( cel ) ){ Debug("quant-req-phase") << "Bad decision : " << cel << std::endl; } //note that the counterexample literal must not be a decision - Assert( !d_th->getValuation().isDecision( cel ) ); + Assert( !d_quantEngine->getValuation().isDecision( cel ) ); } - if( d_th->getValuation().hasSatValue( n, value ) ){ + if( d_quantEngine->getValuation().hasSatValue( n, value ) ){ Debug("quantifiers") << ", value = " << value; } if( ceValue ){ @@ -217,18 +208,18 @@ void InstantiationEngine::check( Theory::Effort e ){ } Debug("quantifiers") << std::endl; }else{ - getQuantifiersEngine()->setActive( n, true ); + d_quantEngine->setActive( n, true ); quantActive = true; Debug("quantifiers") << " Active : " << n << ", no ce assigned." << std::endl; } Debug("quantifiers-relevance") << "Quantifier : " << n << std::endl; - Debug("quantifiers-relevance") << " Relevance : " << getQuantifiersEngine()->getRelevance( n ) << std::endl; - Debug("quantifiers") << " Relevance : " << getQuantifiersEngine()->getRelevance( n ) << std::endl; + Debug("quantifiers-relevance") << " Relevance : " << d_quantEngine->getRelevance( n ) << std::endl; + Debug("quantifiers") << " Relevance : " << d_quantEngine->getRelevance( n ) << std::endl; } //} if( quantActive ){ bool addedLemmas = doInstantiationRound( e ); - //Debug("quantifiers-dec") << "Do instantiation, level = " << d_th->getValuation().getDecisionLevel() << std::endl; + //Debug("quantifiers-dec") << "Do instantiation, level = " << d_quantEngine->getValuation().getDecisionLevel() << std::endl; //for( int i=1; i<=(int)d_valuation.getDecisionLevel(); i++ ){ // Debug("quantifiers-dec") << " " << d_valuation.getDecision( i ) << std::endl; //} @@ -237,9 +228,12 @@ void InstantiationEngine::check( Theory::Effort e ){ if( d_inst_round_status==InstStrategy::STATUS_SAT ){ Debug("inst-engine") << "No instantiation given, returning SAT..." << std::endl; debugSat( SAT_INST_STRATEGY ); - }else{ + }else if( d_setIncomplete ){ Debug("inst-engine") << "No instantiation given, returning unknown..." << std::endl; - d_th->getOutputChannel().setIncomplete(); + d_quantEngine->getOutputChannel().setIncomplete(); + }else{ + Assert( Options::current()->finiteModelFind ); + Debug("inst-engine") << "No instantiation given, defer to another engine..." << std::endl; } } } @@ -250,30 +244,30 @@ void InstantiationEngine::check( Theory::Effort e ){ } } } -#ifdef IE_PRINT_PROCESS_TIMES - double clSet2 = double(clock())/double(CLOCKS_PER_SEC); - Notice() << "Done Run instantiation round " << (clSet2-clSet) << std::endl; -#endif + if( Options::current()->printInstEngine ){ + double clSet2 = double(clock())/double(CLOCKS_PER_SEC); + Message() << "Finished instantiation engine, time = " << (clSet2-clSet) << std::endl; + } } } void InstantiationEngine::registerQuantifier( Node f ){ //Notice() << "do cbqi " << f << " ? " << std::endl; - Node ceBody = getQuantifiersEngine()->getCounterexampleBody( f ); + Node ceBody = d_quantEngine->getTermDatabase()->getCounterexampleBody( f ); if( !doCbqi( f ) ){ - getQuantifiersEngine()->addTermToDatabase( ceBody, true ); + d_quantEngine->addTermToDatabase( ceBody, true ); //need to tell which instantiators will be responsible //by default, just chose the UF instantiator - getQuantifiersEngine()->getInstantiator( theory::THEORY_UF )->setHasConstraintsFrom( f ); + d_quantEngine->getInstantiator( theory::THEORY_UF )->setHasConstraintsFrom( f ); } //take into account user patterns if( f.getNumChildren()==3 ){ - Node subsPat = getQuantifiersEngine()->getSubstitutedNode( f[2], f ); + Node subsPat = d_quantEngine->getTermDatabase()->getSubstitutedNode( f[2], f ); //add patterns for( int i=0; i<(int)subsPat.getNumChildren(); i++ ){ //Notice() << "Add pattern " << subsPat[i] << " for " << f << std::endl; - ((uf::InstantiatorTheoryUf*)getQuantifiersEngine()->getInstantiator( theory::THEORY_UF ))->addUserPattern( f, subsPat[i] ); + ((uf::InstantiatorTheoryUf*)d_quantEngine->getInstantiator( theory::THEORY_UF ))->addUserPattern( f, subsPat[i] ); } } } @@ -337,11 +331,11 @@ bool InstantiationEngine::doCbqi( Node f ){ // registerLiterals( n[i], f ); // } // if( !d_ce_lit[ f ].isNull() ){ -// if( getQuantifiersEngine()->d_te->getPropEngine()->isSatLiteral( n ) && n.getKind()!=NOT ){ +// if( d_quantEngine->d_te->getPropEngine()->isSatLiteral( n ) && n.getKind()!=NOT ){ // if( n!=d_ce_lit[ f ] && n.notNode()!=d_ce_lit[ f ] ){ // Debug("quant-dep-dec") << "Make " << n << " dependent on "; // Debug("quant-dep-dec") << d_ce_lit[ f ] << std::endl; -// d_th->getOutputChannel().dependentDecision( d_ce_lit[ f ], n ); +// d_quantEngine->getOutputChannel().dependentDecision( d_ce_lit[ f ], n ); // } // } // } @@ -351,19 +345,19 @@ bool InstantiationEngine::doCbqi( Node f ){ void InstantiationEngine::debugSat( int reason ){ if( reason==SAT_CBQI ){ //Debug("quantifiers-sat") << "Decisions:" << std::endl; - //for( int i=1; i<=(int)d_th->getValuation().getDecisionLevel(); i++ ){ - // Debug("quantifiers-sat") << " " << i << ": " << d_th->getValuation().getDecision( i ) << std::endl; + //for( int i=1; i<=(int)d_quantEngine->getValuation().getDecisionLevel(); i++ ){ + // Debug("quantifiers-sat") << " " << i << ": " << d_quantEngine->getValuation().getDecision( i ) << std::endl; //} //for( BoolMap::iterator i = d_forall_asserts.begin(); i != d_forall_asserts.end(); i++ ) { // if( (*i).second ) { - for( int i=0; i<(int)getQuantifiersEngine()->getNumAssertedQuantifiers(); i++ ){ - Node f = getQuantifiersEngine()->getAssertedQuantifier( i ); + for( int i=0; i<(int)d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + Node f = d_quantEngine->getModel()->getAssertedQuantifier( i ); Node cel = d_ce_lit[ f ]; Assert( !cel.isNull() ); bool value; - if( d_th->getValuation().hasSatValue( cel, value ) ){ + if( d_quantEngine->getValuation().hasSatValue( cel, value ) ){ if( !value ){ - AlwaysAssert(! d_th->getValuation().isDecision( cel ), + AlwaysAssert(! d_quantEngine->getValuation().isDecision( cel ), "bad decision on counterexample literal"); } } @@ -386,9 +380,9 @@ void InstantiationEngine::propagate( Theory::Effort level ){ //propagate as decision all counterexample literals that are not asserted for( std::map< Node, Node >::iterator it = d_ce_lit.begin(); it != d_ce_lit.end(); ++it ){ bool value; - if( !d_th->getValuation().hasSatValue( it->second, value ) ){ + if( !d_quantEngine->getValuation().hasSatValue( it->second, value ) ){ //if not already set, propagate as decision - d_th->getOutputChannel().propagateAsDecision( it->second ); + d_quantEngine->getOutputChannel().propagateAsDecision( it->second ); Debug("cbqi-prop-as-dec") << "CBQI: propagate as decision " << it->second << std::endl; } } diff --git a/src/theory/quantifiers/instantiation_engine.h b/src/theory/quantifiers/instantiation_engine.h index c6aaed18a..13de210ab 100644 --- a/src/theory/quantifiers/instantiation_engine.h +++ b/src/theory/quantifiers/instantiation_engine.h @@ -28,15 +28,14 @@ namespace quantifiers { class InstantiationEngine : public QuantifiersModule { -private: - TheoryQuantifiers* d_th; - QuantifiersEngine* getQuantifiersEngine(); private: typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap; /** status of instantiation round (one of InstStrategy::STATUS_*) */ int d_inst_round_status; /** map from universal quantifiers to their counterexample literals */ std::map< Node, Node > d_ce_lit; + /** whether the instantiation engine should set incomplete if it cannot answer SAT */ + bool d_setIncomplete; private: bool hasAddedCbqiLemma( Node f ); void addCbqiLemma( Node f ); @@ -59,7 +58,7 @@ private: /** debug sat */ void debugSat( int reason ); public: - InstantiationEngine( TheoryQuantifiers* th ); + InstantiationEngine( QuantifiersEngine* qe, bool setIncomplete = true ); ~InstantiationEngine(){} void check( Theory::Effort e ); diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp index a72b103d1..ad259f864 100644 --- a/src/theory/quantifiers/model_engine.cpp +++ b/src/theory/quantifiers/model_engine.cpp @@ -15,19 +15,23 @@ **/ #include "theory/quantifiers/model_engine.h" +#include "theory/quantifiers/rep_set_iterator.h" #include "theory/theory_engine.h" #include "theory/uf/equality_engine.h" #include "theory/uf/theory_uf.h" #include "theory/uf/theory_uf_strong_solver.h" #include "theory/uf/theory_uf_instantiator.h" +#include "theory/quantifiers/first_order_model.h" +#include "theory/quantifiers/term_database.h" -//#define ME_PRINT_PROCESS_TIMES +//#define ME_PRINT_WARNINGS //#define DISABLE_EVAL_SKIP_MULTIPLE -#define RECONSIDER_FUNC_DEFAULT_VALUE + #define RECONSIDER_FUNC_CONSTANT -#define USE_INDEX_ORDERING -//#define ONE_INST_PER_QUANT_PER_ROUND +#define EVAL_FAIL_SKIP_MULTIPLE +//#define ONE_QUANT_PER_ROUND_INST_GEN +//#define ONE_QUANT_PER_ROUND using namespace std; using namespace CVC4; @@ -36,570 +40,417 @@ using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::quantifiers; -void printRepresentative( const char* c, QuantifiersEngine* qe, Node r ){ - if( r.getType()==NodeManager::currentNM()->booleanType() ){ - if( qe->getEqualityQuery()->areEqual( r, NodeManager::currentNM()->mkConst( true ) ) ){ - Debug( c ) << "true"; - }else{ - Debug( c ) << "false"; - } - }else{ - Debug( c ) << qe->getEqualityQuery()->getRepresentative( r ); - } -} - -RepAlphabet::RepAlphabet( RepAlphabet& ra, QuantifiersEngine* qe ){ - //translate to current representatives - for( std::map< TypeNode, std::vector< Node > >::iterator it = ra.d_type_reps.begin(); it != ra.d_type_reps.end(); ++it ){ - std::vector< Node > reps; - for( int i=0; i<(int)it->second.size(); i++ ){ - //reps.push_back( ie->getEqualityQuery()->getRepresentative( it->second[i] ) ); - reps.push_back( it->second[i] ); - } - set( it->first, reps ); - } -} - -void RepAlphabet::set( TypeNode t, std::vector< Node >& reps ){ - d_type_reps[t].insert( d_type_reps[t].begin(), reps.begin(), reps.end() ); - for( int i=0; i<(int)reps.size(); i++ ){ - d_tmap[ reps[i] ] = i; - } -} - -void RepAlphabet::debugPrint( const char* c, QuantifiersEngine* qe ){ - for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){ - Debug( c ) << it->first << " : " << std::endl; - for( int i=0; i<(int)it->second.size(); i++ ){ - Debug( c ) << " " << i << ": " << it->second[i] << std::endl; - Debug( c ) << " eq_class( " << it->second[i] << " ) : "; - ((uf::InstantiatorTheoryUf*)qe->getInstantiator( THEORY_UF ))->outputEqClass( c, it->second[i] ); - Debug( c ) << std::endl; - } - } -} - -RepAlphabetIterator::RepAlphabetIterator( QuantifiersEngine* qe, Node f, ModelEngine* model ){ - for( size_t i=0; i& indexOrder ){ - d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() ); - initialize( qe, f, model ); -} - -void RepAlphabetIterator::initialize( QuantifiersEngine* qe, Node f, ModelEngine* model ){ - d_f = f; - d_model = model; - //store instantiation constants - for( size_t i=0; igetInstantiationConstant( d_f, i ) ); - d_index.push_back( 0 ); - } - //make the d_var_order mapping - for( size_t i=0; i=0 && d_index[counter]==(int)(d_model->getReps()->d_type_reps[d_f[0][d_index_order[counter]].getType()].size()-1) ){ - counter--; - } - if( counter==-1 ){ - d_index.clear(); - }else{ - for( int i=(int)d_index.size()-1; i>counter; i-- ){ - d_index[i] = 0; - d_model->clearEvalFailed( i ); - } - d_index[counter]++; - d_model->clearEvalFailed( counter ); - } -} - -void RepAlphabetIterator::increment( QuantifiersEngine* qe ){ - if( !isFinished() ){ - increment2( qe, (int)d_index.size()-1 ); - } -} +ModelEngineBuilder::ModelEngineBuilder( QuantifiersEngine* qe ) : +TheoryEngineModelBuilder( qe->getTheoryEngine() ), +d_qe( qe ){ -bool RepAlphabetIterator::isFinished(){ - return d_index.empty(); } -void RepAlphabetIterator::getMatch( QuantifiersEngine* ie, InstMatch& m ){ - for( int i=0; i<(int)d_index.size(); i++ ){ - m.d_map[ ie->getInstantiationConstant( d_f, i ) ] = getTerm( i ); - } +Node ModelEngineBuilder::chooseRepresentative( TheoryModel* tm, Node eqc ){ + return eqc; } -Node RepAlphabetIterator::getTerm( int i ){ - TypeNode tn = d_f[0][d_index_order[i]].getType(); - Assert( d_model->getReps()->d_type_reps.find( tn )!=d_model->getReps()->d_type_reps.end() ); - return d_model->getReps()->d_type_reps[tn][d_index[d_index_order[i]]]; -} - -void RepAlphabetIterator::calculateTerms( QuantifiersEngine* qe ){ - d_terms.clear(); - for( int i=0; igetNumInstantiationConstants( d_f ); i++ ){ - d_terms.push_back( getTerm( i ) ); - } -} - -void RepAlphabetIterator::debugPrint( const char* c ){ - for( int i=0; i<(int)d_index.size(); i++ ){ - Debug( c ) << i << ": " << d_index[i] << ", (" << getTerm( i ) << " / " << d_ic[ i ] << std::endl; - } -} - -void RepAlphabetIterator::debugPrintSmall( const char* c ){ - Debug( c ) << "RI: "; - for( int i=0; i<(int)d_index.size(); i++ ){ - Debug( c ) << d_index[i] << ": " << getTerm( i ) << " "; - } - Debug( c ) << std::endl; -} - -//set value function -void UfModelTree::setValue( QuantifiersEngine* qe, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex ){ - if( d_data.empty() ){ - d_value = v; - }else if( !d_value.isNull() && d_value!=v ){ - d_value = Node::null(); - } - if( argIndex<(int)n.getNumChildren() ){ - //take r = null when argument is the model basis - Node r; - if( ground || !n[ indexOrder[argIndex] ].getAttribute(ModelBasisAttribute()) ){ - r = qe->getEqualityQuery()->getRepresentative( n[ indexOrder[argIndex] ] ); - } - d_data[ r ].setValue( qe, n, v, indexOrder, ground, argIndex+1 ); - } -} - -//get value function -Node UfModelTree::getValue( QuantifiersEngine* qe, Node n, std::vector< int >& indexOrder, int& depIndex, int argIndex ){ - if( !d_value.isNull() && isTotal( n.getOperator(), argIndex ) ){ - //Notice() << "Constant, return " << d_value << ", depIndex = " << argIndex << std::endl; - depIndex = argIndex; - return d_value; - }else{ - Node val; - int childDepIndex[2] = { argIndex, argIndex }; - for( int i=0; i<2; i++ ){ - //first check the argument, then check default - Node r; - if( i==0 ){ - r = qe->getEqualityQuery()->getRepresentative( n[ indexOrder[argIndex] ] ); +void ModelEngineBuilder::processBuildModel( TheoryModel* m ) { + d_addedLemmas = 0; + //only construct first order model if optUseModel() is true + if( optUseModel() ){ + FirstOrderModel* fm = (FirstOrderModel*)m; + //initialize model + fm->initialize(); + //analyze the quantifiers + Debug("fmf-model-debug") << "Analyzing quantifiers..." << std::endl; + analyzeQuantifiers( fm ); + //if applicable, find exceptions + if( optInstGen() ){ + //now, see if we know that any exceptions via InstGen exist + Debug("fmf-model-debug") << "Perform InstGen techniques for quantifiers..." << std::endl; + for( int i=0; igetNumAssertedQuantifiers(); i++ ){ + Node f = fm->getAssertedQuantifier( i ); + if( d_quant_sat.find( f )==d_quant_sat.end() ){ + d_addedLemmas += doInstGen( fm, f ); + if( optOneQuantPerRoundInstGen() && d_addedLemmas>0 ){ + break; + } + } } - std::map< Node, UfModelTree >::iterator it = d_data.find( r ); - if( it!=d_data.end() ){ - val = it->second.getValue( qe, n, indexOrder, childDepIndex[i], argIndex+1 ); - if( !val.isNull() ){ - break; + if( Options::current()->printModelEngine ){ + if( d_addedLemmas>0 ){ + Message() << "InstGen, added lemmas = " << d_addedLemmas << std::endl; + }else{ + Message() << "No InstGen lemmas..." << std::endl; } - }else{ - //argument is not a defined argument: thus, it depends on this argument - childDepIndex[i] = argIndex+1; } + Debug("fmf-model-debug") << "---> Added lemmas = " << d_addedLemmas << std::endl; + } + if( d_addedLemmas==0 ){ + //if no immediate exceptions, build the model + // this model will be an approximation that will need to be tested via exhaustive instantiation + Debug("fmf-model-debug") << "Building model..." << std::endl; + finishBuildModel( fm ); } - //update depIndex - depIndex = childDepIndex[0]>childDepIndex[1] ? childDepIndex[0] : childDepIndex[1]; - //Notice() << "Return " << val << ", depIndex = " << depIndex; - //Notice() << " ( " << childDepIndex[0] << ", " << childDepIndex[1] << " )" << std::endl; - return val; } } -//simplify function -void UfModelTree::simplify( Node op, Node defaultVal, int argIndex ){ - if( argIndex<(int)op.getType().getNumChildren()-1 ){ - std::vector< Node > eraseData; - //first process the default argument - Node r; - std::map< Node, UfModelTree >::iterator it = d_data.find( r ); - if( it!=d_data.end() ){ - if( !defaultVal.isNull() && it->second.d_value==defaultVal ){ - eraseData.push_back( r ); - }else{ - it->second.simplify( op, defaultVal, argIndex+1 ); - if( !it->second.d_value.isNull() && it->second.isTotal( op, argIndex+1 ) ){ - defaultVal = it->second.d_value; +void ModelEngineBuilder::analyzeQuantifiers( FirstOrderModel* fm ){ + d_quant_selection_lits.clear(); + d_quant_sat.clear(); + d_uf_prefs.clear(); + int quantSatInit = 0; + int nquantSatInit = 0; + //analyze the preferences of each quantifier + for( int i=0; i<(int)fm->getNumAssertedQuantifiers(); i++ ){ + Node f = fm->getAssertedQuantifier( i ); + Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl; + std::vector< Node > pro_con[2]; + std::vector< Node > constantSatOps; + bool constantSatReconsider; + //for each asserted quantifier f, + // - determine which literals form model basis for each quantifier + // - check which function/predicates have good and bad definitions according to f + for( std::map< Node, bool >::iterator it = d_qe->d_phase_reqs[f].begin(); + it != d_qe->d_phase_reqs[f].end(); ++it ){ + Node n = it->first; + Node gn = d_qe->getTermDatabase()->getModelBasis( n ); + Debug("fmf-model-req") << " Req: " << n << " -> " << it->second << std::endl; + //calculate preference + int pref = 0; + bool value; + if( d_qe->getValuation().hasSatValue( gn, value ) ){ + if( value!=it->second ){ + //store this literal as a model basis literal + // this literal will force a default values in model that (modulo exceptions) shows + // that f is satisfied by the model + d_quant_selection_lits[f].push_back( value ? n : n.notNode() ); + pref = 1; }else{ - defaultVal = Node::null(); + pref = -1; } } - } - //now see if any children can be removed, and simplify the ones that cannot - for( std::map< Node, UfModelTree >::iterator it = d_data.begin(); it != d_data.end(); ++it ){ - if( !it->first.isNull() ){ - if( !defaultVal.isNull() && it->second.d_value==defaultVal ){ - eraseData.push_back( it->first ); + if( pref!=0 ){ + //Store preferences for UF + bool isConst = !n.hasAttribute(InstConstantAttribute()); + std::vector< Node > uf_terms; + if( gn.getKind()==APPLY_UF ){ + uf_terms.push_back( gn ); + isConst = fm->d_uf_model[gn.getOperator()].isConstant(); + }else if( gn.getKind()==EQUAL ){ + isConst = true; + for( int j=0; j<2; j++ ){ + if( n[j].hasAttribute(InstConstantAttribute()) ){ + if( n[j].getKind()==APPLY_UF ){ + Node op = gn[j].getOperator(); + if( fm->d_uf_model.find( op )!=fm->d_uf_model.end() ){ + uf_terms.push_back( gn[j] ); + isConst = isConst && fm->d_uf_model[op].isConstant(); + }else{ + isConst = false; + } + }else{ + isConst = false; + } + } + } + } + Debug("fmf-model-prefs") << " It is " << ( pref==1 ? "pro" : "con" ); + Debug("fmf-model-prefs") << " the definition of " << n << std::endl; + if( pref==1 && isConst ){ + d_quant_sat[f] = true; + //instead, just note to the model for each uf term that f is pro its definition + constantSatReconsider = false; + constantSatOps.clear(); + for( int j=0; j<(int)uf_terms.size(); j++ ){ + Node op = uf_terms[j].getOperator(); + constantSatOps.push_back( op ); + if( d_uf_prefs[op].d_reconsiderModel ){ + constantSatReconsider = true; + } + } + if( !constantSatReconsider ){ + break; + } }else{ - it->second.simplify( op, defaultVal, argIndex+1 ); + int pcIndex = pref==1 ? 0 : 1; + for( int j=0; j<(int)uf_terms.size(); j++ ){ + pro_con[pcIndex].push_back( uf_terms[j] ); + } } } } - for( int i=0; i<(int)eraseData.size(); i++ ){ - d_data.erase( eraseData[i] ); - } - } -} - -//is total function -bool UfModelTree::isTotal( Node op, int argIndex ){ - if( argIndex==(int)(op.getType().getNumChildren()-1) ){ - return !d_value.isNull(); - }else{ - Node r; - std::map< Node, UfModelTree >::iterator it = d_data.find( r ); - if( it!=d_data.end() ){ - return it->second.isTotal( op, argIndex+1 ); + if( d_quant_sat.find( f )!=d_quant_sat.end() ){ + Debug("fmf-model-prefs") << " * Constant SAT due to definition of ops: "; + for( int i=0; i<(int)constantSatOps.size(); i++ ){ + Debug("fmf-model-prefs") << constantSatOps[i] << " "; + d_uf_prefs[constantSatOps[i]].d_reconsiderModel = false; + } + Debug("fmf-model-prefs") << std::endl; + quantSatInit++; + d_statistics.d_pre_sat_quant += quantSatInit; }else{ - return false; - } - } -} - -Node UfModelTree::getConstantValue( QuantifiersEngine* qe, Node n, std::vector< int >& indexOrder, int argIndex ){ - return d_value; -} - -void indent( const char* c, int ind ){ - for( int i=0; i& indexOrder, int ind, int arg ){ - if( !d_data.empty() ){ - for( std::map< Node, UfModelTree >::iterator it = d_data.begin(); it != d_data.end(); ++it ){ - if( !it->first.isNull() ){ - indent( c, ind ); - Debug( c ) << "if x_" << indexOrder[arg] << " == " << it->first << std::endl; - it->second.debugPrint( c, qe, indexOrder, ind+2, arg+1 ); + nquantSatInit++; + d_statistics.d_pre_nsat_quant += quantSatInit; + //note quantifier's value preferences to models + for( int k=0; k<2; k++ ){ + for( int j=0; j<(int)pro_con[k].size(); j++ ){ + Node op = pro_con[k][j].getOperator(); + Node r = fm->getRepresentative( pro_con[k][j] ); + d_uf_prefs[op].setValuePreference( f, pro_con[k][j], r, k==0 ); + } } } - if( d_data.find( Node::null() )!=d_data.end() ){ - d_data[ Node::null() ].debugPrint( c, qe, indexOrder, ind, arg+1 ); - } - }else{ - indent( c, ind ); - Debug( c ) << "return "; - printRepresentative( c, qe, d_value ); - //Debug( c ) << " { "; - //for( int i=0; i<(int)d_explicit.size(); i++ ){ - // Debug( c ) << d_explicit[i] << " "; - //} - //Debug( c ) << "}"; - Debug( c ) << std::endl; } + Debug("fmf-model-prefs") << "Pre-Model Completion: Quantifiers SAT: " << quantSatInit << " / " << (quantSatInit+nquantSatInit) << std::endl; } -UfModel::UfModel( Node op, ModelEngine* me ) : d_op( op ), d_me( me ), - d_model_constructed( false ), d_reconsider_model( false ){ - - d_tree = UfModelTreeOrdered( op ); TypeNode tn = d_op.getType(); tn = tn[(int)tn.getNumChildren()-1]; Assert( tn==NodeManager::currentNM()->booleanType() || uf::StrongSolverTheoryUf::isRelevantType( tn ) ); //look at ground assertions - for( int i=0; i<(int)d_me->getQuantifiersEngine()->getTermDatabase()->d_op_map[ d_op ].size(); i++ ){ - Node n = d_me->getQuantifiersEngine()->getTermDatabase()->d_op_map[ d_op ][i]; - bool add = true; - if( n.getAttribute(NoMatchAttribute()) ){ - add = false; - //determine if it has model basis attribute - for( int j=0; j<(int)n.getNumChildren(); j++ ){ - if( n[j].getAttribute(ModelBasisAttribute()) ){ - add = true; - break; +int ModelEngineBuilder::doInstGen( FirstOrderModel* fm, Node f ){ + //we wish to add all known exceptions to our model basis literal(s) + // this will help to refine our current model. + //This step is advantageous over exhaustive instantiation, since we are adding instantiations that involve model basis terms, + // effectively acting as partial instantiations instead of pointwise instantiations. + int addedLemmas = 0; + for( int i=0; i<(int)d_quant_selection_lits[f].size(); i++ ){ + bool phase = d_quant_selection_lits[f][i].getKind()!=NOT; + Node lit = d_quant_selection_lits[f][i].getKind()==NOT ? d_quant_selection_lits[f][i][0] : d_quant_selection_lits[f][i]; + Assert( lit.hasAttribute(InstConstantAttribute()) ); + std::vector< Node > tr_terms; + if( lit.getKind()==APPLY_UF ){ + //only match predicates that are contrary to this one, use literal matching + Node eq = NodeManager::currentNM()->mkNode( IFF, lit, !phase ? fm->d_true : fm->d_false ); + fm->getTermDatabase()->setInstantiationConstantAttr( eq, f ); + tr_terms.push_back( eq ); + }else if( lit.getKind()==EQUAL ){ + //collect trigger terms + for( int j=0; j<2; j++ ){ + if( lit[j].hasAttribute(InstConstantAttribute()) ){ + if( lit[j].getKind()==APPLY_UF ){ + tr_terms.push_back( lit[j] ); + }else{ + tr_terms.clear(); + break; + } } } - } - if( add ){ - d_ground_asserts.push_back( n ); - Node r = d_me->getQuantifiersEngine()->getEqualityQuery()->getRepresentative( n ); - d_ground_asserts_reps.push_back( r ); - } - } - //determine if it is constant - if( !d_ground_asserts.empty() ){ - bool isConstant = true; - for( int i=1; i<(int)d_ground_asserts.size(); i++ ){ - if( d_ground_asserts_reps[0]!=d_ground_asserts_reps[i] ){ - isConstant = false; - break; + if( tr_terms.size()==1 && !phase ){ + //equality between a function and a ground term, use literal matching + tr_terms.clear(); + tr_terms.push_back( lit ); } } - if( isConstant ){ - //set constant value - Node t = d_me->getModelBasisApplyUfTerm( d_op ); - Node r = d_ground_asserts_reps[0]; - setValue( t, r, false ); - setModel(); - d_reconsider_model = true; - Debug("fmf-model-cons") << "Function " << d_op << " is the constant function "; - printRepresentative( "fmf-model-cons", d_me->getQuantifiersEngine(), r ); - Debug("fmf-model-cons") << std::endl; + //if applicable, try to add exceptions here + if( !tr_terms.empty() ){ + //make a trigger for these terms, add instantiations + Trigger* tr = Trigger::mkTrigger( d_qe, f, tr_terms ); + //Notice() << "Trigger = " << (*tr) << std::endl; + tr->resetInstantiationRound(); + tr->reset( Node::null() ); + //d_qe->d_optInstMakeRepresentative = false; + //d_qe->d_optMatchIgnoreModelBasis = true; + addedLemmas += tr->addInstantiations( d_quant_basis_match[f] ); } } + return addedLemmas; } -void UfModel::setValue( Node n, Node v, bool ground ){ - d_set_values[ ground ? 1 : 0 ][n] = v; -} - -void UfModel::setModel(){ - makeModel( d_me->getQuantifiersEngine(), d_tree ); - d_model_constructed = true; -} - -void UfModel::clearModel(){ - for( int k=0; k<2; k++ ){ - d_set_values[k].clear(); +void ModelEngineBuilder::finishBuildModel( FirstOrderModel* fm ){ + //build model for UF + for( std::map< Node, uf::UfModel >::iterator it = fm->d_uf_model.begin(); it != fm->d_uf_model.end(); ++it ){ + finishBuildModelUf( fm, it->second ); } - d_tree.clear(); - d_model_constructed = false; -} - -Node UfModel::getConstantValue( QuantifiersEngine* qe, Node n ){ - if( d_model_constructed ){ - return d_tree.getConstantValue( qe, n ); - }else{ - return Node::null(); + //build model for arrays + for( std::map< Node, Node >::iterator it = fm->d_array_model.begin(); it != fm->d_array_model.end(); ++it ){ + //consult the model basis select term + // i.e. the default value for array A is the value of select( A, e ), where e is the model basis term + TypeNode tn = it->first.getType(); + Node selModelBasis = NodeManager::currentNM()->mkNode( SELECT, it->first, fm->getTermDatabase()->getModelBasisTerm( tn[0] ) ); + it->second = fm->getRepresentative( selModelBasis ); } + Debug("fmf-model-debug") << "Done building models." << std::endl; } -bool UfModel::isConstant(){ - Node gn = d_me->getModelBasisApplyUfTerm( d_op ); - Node n = getConstantValue( d_me->getQuantifiersEngine(), gn ); - return !n.isNull(); -} - -void UfModel::buildModel(){ +void ModelEngineBuilder::finishBuildModelUf( FirstOrderModel* fm, uf::UfModel& model ){ + Node op = model.getOperator(); #ifdef RECONSIDER_FUNC_CONSTANT - if( d_model_constructed ){ - if( d_reconsider_model ){ + if( model.isModelConstructed() && model.isConstant() ){ + if( d_uf_prefs[op].d_reconsiderModel ){ //if we are allowed to reconsider default value, then see if the default value can be improved - Node t = d_me->getModelBasisApplyUfTerm( d_op ); - Node v = d_set_values[0][t]; - if( d_value_pro_con[1][v].size()>d_value_pro_con[0][v].size() ){ - Debug("fmf-model-cons-debug") << "Consider changing the default value for " << d_op << std::endl; - clearModel(); + Node t = d_qe->getTermDatabase()->getModelBasisOpTerm( op ); + Node v = model.getConstantValue( t ); + if( d_uf_prefs[op].d_value_pro_con[0][v].empty() ){ + Debug("fmf-model-cons-debug") << "Consider changing the default value for " << op << std::endl; + model.clearModel(); } } } #endif - //now, construct models for each uninterpretted function/predicate - if( !d_model_constructed ){ - Debug("fmf-model-cons") << "Construct model for " << d_op << "..." << std::endl; - //now, set the values in the model - for( int i=0; i<(int)d_ground_asserts.size(); i++ ){ - Node n = d_ground_asserts[i]; - Node v = d_ground_asserts_reps[i]; + if( !model.isModelConstructed() ){ + //construct the model for the uninterpretted function/predicate + bool setDefaultVal = true; + Node defaultTerm = d_qe->getTermDatabase()->getModelBasisOpTerm( op ); + Debug("fmf-model-cons") << "Construct model for " << op << "..." << std::endl; + //set the values in the model + for( size_t i=0; igetQuantifiersEngine(), v ); + fm->printRepresentativeDebug( "fmf-model-cons", v ); Debug("fmf-model-cons") << std::endl; //set it as ground value - setValue( n, v ); - } - //set the default value - //chose defaultVal based on heuristic (the best proportion of "pro" responses) - Node defaultVal; - double maxScore = -1; - for( int i=0; i<(int)d_values.size(); i++ ){ - Node v = d_values[i]; - double score = ( 1.0 + (double)d_value_pro_con[0][v].size() )/( 1.0 + (double)d_value_pro_con[1][v].size() ); - Debug("fmf-model-cons") << " - score( "; - printRepresentative( "fmf-model-cons", d_me->getQuantifiersEngine(), v ); - Debug("fmf-model-cons") << " ) = " << score << std::endl; - if( score>maxScore ){ - defaultVal = v; - maxScore = score; - } - } -#ifdef RECONSIDER_FUNC_DEFAULT_VALUE - if( maxScore<1.0 ){ - //consider finding another value, if possible - Debug("fmf-model-cons-debug") << "Poor choice for default value, score = " << maxScore << std::endl; - TypeNode tn = d_op.getType(); - Node newDefaultVal = d_me->getArbitraryElement( tn[(int)tn.getNumChildren()-1], d_values ); - if( !newDefaultVal.isNull() ){ - defaultVal = newDefaultVal; - Debug("fmf-model-cons-debug") << "-> Change default value to "; - printRepresentative( "fmf-model-cons-debug", d_me->getQuantifiersEngine(), defaultVal ); - Debug("fmf-model-cons-debug") << std::endl; + model.setValue( n, v ); + if( model.optUsePartialDefaults() ){ + //also set as default value if necessary + //if( n.getAttribute(ModelBasisArgAttribute())==1 && !d_term_pro_con[0][n].empty() ){ + if( n.hasAttribute(ModelBasisArgAttribute()) && n.getAttribute(ModelBasisArgAttribute())==1 ){ + model.setValue( n, v, false ); + if( n==defaultTerm ){ + //incidentally already set, we will not need to find a default value + setDefaultVal = false; + } + } }else{ - Debug("fmf-model-cons-debug") << "-> Could not find arbitrary element of type " << tn[(int)tn.getNumChildren()-1] << std::endl; - Debug("fmf-model-cons-debug") << " Excluding: "; - for( int i=0; i<(int)d_values.size(); i++ ){ - Debug("fmf-model-cons-debug") << d_values[i] << " "; + if( n==defaultTerm ){ + model.setValue( n, v, false ); + //incidentally already set, we will not need to find a default value + setDefaultVal = false; } - Debug("fmf-model-cons-debug") << std::endl; } } -#endif - Assert( !defaultVal.isNull() ); - //get the default term (this term must be defined non-ground in model) - Node defaultTerm = d_me->getModelBasisApplyUfTerm( d_op ); - Debug("fmf-model-cons") << " Choose "; - printRepresentative("fmf-model-cons", d_me->getQuantifiersEngine(), defaultVal ); - Debug("fmf-model-cons") << " as default value (" << defaultTerm << ")" << std::endl; - Debug("fmf-model-cons") << " # quantifiers pro = " << d_value_pro_con[0][defaultVal].size() << std::endl; - Debug("fmf-model-cons") << " # quantifiers con = " << d_value_pro_con[1][defaultVal].size() << std::endl; - setValue( defaultTerm, defaultVal, false ); + //set the overall default value if not set already (is this necessary??) + if( setDefaultVal ){ + Debug("fmf-model-cons") << " Choose default value..." << std::endl; + //chose defaultVal based on heuristic, currently the best ratio of "pro" responses + Node defaultVal = d_uf_prefs[op].getBestDefaultValue( defaultTerm, fm ); + Assert( !defaultVal.isNull() ); + model.setValue( defaultTerm, defaultVal, false ); + } Debug("fmf-model-cons") << " Making model..."; - setModel(); - Debug("fmf-model-cons") << " Finished constructing model for " << d_op << "." << std::endl; + model.setModel(); + Debug("fmf-model-cons") << " Finished constructing model for " << op << "." << std::endl; } } -void UfModel::setValuePreference( Node f, Node n, bool isPro ){ - Node v = d_me->getQuantifiersEngine()->getEqualityQuery()->getRepresentative( n ); - //Notice() << "Set value preference " << n << " = " << v << " " << isPro << std::endl; - if( std::find( d_values.begin(), d_values.end(), v )==d_values.end() ){ - d_values.push_back( v ); - } - int index = isPro ? 0 : 1; - if( std::find( d_value_pro_con[index][v].begin(), d_value_pro_con[index][v].end(), f )==d_value_pro_con[index][v].end() ){ - d_value_pro_con[index][v].push_back( f ); - } +bool ModelEngineBuilder::optUseModel() { + return Options::current()->fmfModelBasedInst; } -void UfModel::makeModel( QuantifiersEngine* qe, UfModelTreeOrdered& tree ){ - for( int k=0; k<2; k++ ){ - for( std::map< Node, Node >::iterator it = d_set_values[k].begin(); it != d_set_values[k].end(); ++it ){ - tree.setValue( qe, it->first, it->second, k==1 ); - } - } - tree.simplify(); +bool ModelEngineBuilder::optInstGen(){ + return Options::current()->fmfInstGen; +} + +bool ModelEngineBuilder::optOneQuantPerRoundInstGen(){ +#ifdef ONE_QUANT_PER_ROUND_INST_GEN + return true; +#else + return false; +#endif } -void UfModel::debugPrint( const char* c ){ - //Debug( c ) << "Function " << d_op << std::endl; - //Debug( c ) << " Type: " << d_op.getType() << std::endl; - //Debug( c ) << " Ground asserts:" << std::endl; - //for( int i=0; i<(int)d_ground_asserts.size(); i++ ){ - // Debug( c ) << " " << d_ground_asserts[i] << " = "; - // printRepresentative( c, d_me->getQuantifiersEngine(), d_ground_asserts[i] ); - // Debug( c ) << std::endl; - //} - //Debug( c ) << " Model:" << std::endl; +ModelEngineBuilder::Statistics::Statistics(): + d_pre_sat_quant("ModelEngineBuilder::Status_quant_pre_sat", 0), + d_pre_nsat_quant("ModelEngineBuilder::Status_quant_pre_non_sat", 0) +{ + StatisticsRegistry::registerStat(&d_pre_sat_quant); + StatisticsRegistry::registerStat(&d_pre_nsat_quant); +} - TypeNode t = d_op.getType(); - Debug( c ) << d_op << "( "; - for( int i=0; i<(int)(t.getNumChildren()-1); i++ ){ - Debug( c ) << "x_" << i << " : " << t[i]; - if( i<(int)(t.getNumChildren()-2) ){ - Debug( c ) << ", "; - } - } - Debug( c ) << " ) : " << t[(int)t.getNumChildren()-1] << std::endl; - if( d_tree.isEmpty() ){ - Debug( c ) << " [undefined]" << std::endl; - }else{ - d_tree.debugPrint( c, d_me->getQuantifiersEngine(), 3 ); - Debug( c ) << std::endl; - } - //Debug( c ) << " Phase reqs:" << std::endl; //for( int i=0; i<2; i++ ){ - // for( std::map< Node, std::vector< Node > >::iterator it = d_reqs[i].begin(); it != d_reqs[i].end(); ++it ){ - // Debug( c ) << " " << it->first << std::endl; - // for( int j=0; j<(int)it->second.size(); j++ ){ - // Debug( c ) << " " << it->second[j] << " -> " << (i==1) << std::endl; - // } - // } - //} - //Debug( c ) << std::endl; - //for( int i=0; i<2; i++ ){ - // for( std::map< Node, std::map< Node, std::vector< Node > > >::iterator it = d_eq_reqs[i].begin(); it != d_eq_reqs[i].end(); ++it ){ - // Debug( c ) << " " << "For " << it->first << ":" << std::endl; - // for( std::map< Node, std::vector< Node > >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ - // for( int j=0; j<(int)it2->second.size(); j++ ){ - // Debug( c ) << " " << it2->first << ( i==1 ? "==" : "!=" ) << it2->second[j] << std::endl; - // } - // } - // } - //} +ModelEngineBuilder::Statistics::~Statistics(){ + StatisticsRegistry::unregisterStat(&d_pre_sat_quant); + StatisticsRegistry::unregisterStat(&d_pre_nsat_quant); } //Model Engine constructor -ModelEngine::ModelEngine( TheoryQuantifiers* th ){ - d_th = th; - d_quantEngine = th->getQuantifiersEngine(); - d_ss = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->getTheory( THEORY_UF ))->getStrongSolver(); +ModelEngine::ModelEngine( QuantifiersEngine* qe ) : +QuantifiersModule( qe ), +d_builder( qe ), +d_rel_domain( qe->getModel() ){ + } void ModelEngine::check( Theory::Effort e ){ - if( e==Theory::EFFORT_LAST_CALL ){ - bool quantsInit = true; + if( e==Theory::EFFORT_LAST_CALL && !d_quantEngine->hasAddedLemma() ){ //first, check if we can minimize the model further - if( !d_ss->minimize() ){ + if( !((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->getTheory( THEORY_UF ))->getStrongSolver()->minimize() ){ return; } - if( useModel() ){ - //now, check if any quantifiers are un-initialized - for( int i=0; igetNumAssertedQuantifiers(); i++ ){ - Node f = d_quantEngine->getAssertedQuantifier( i ); - if( !initializeQuantifier( f ) ){ - quantsInit = false; - } + //the following will attempt to build a model and test that it satisfies all asserted universal quantifiers + int addedLemmas = 0; + if( d_builder.optUseModel() ){ + //check if any quantifiers are un-initialized + for( int i=0; igetModel()->getNumAssertedQuantifiers(); i++ ){ + Node f = d_quantEngine->getModel()->getAssertedQuantifier( i ); + addedLemmas += initializeQuantifier( f ); } } - if( quantsInit ){ -#ifdef ME_PRINT_PROCESS_TIMES - Notice() << "---Instantiation Round---" << std::endl; -#endif + if( addedLemmas==0 ){ + //quantifiers are initialized, we begin an instantiation round + double clSet = 0; + if( Options::current()->printModelEngine ){ + clSet = double(clock())/double(CLOCKS_PER_SEC); + Message() << "---Model Engine Round---" << std::endl; + } Debug("fmf-model-debug") << "---Begin Instantiation Round---" << std::endl; ++(d_statistics.d_inst_rounds); - d_quantEngine->getTermDatabase()->reset( e ); - //build the representatives - Debug("fmf-model-debug") << "Building representatives..." << std::endl; - buildRepresentatives(); - if( useModel() ){ - //initialize the model - Debug("fmf-model-debug") << "Initializing model..." << std::endl; - initializeModel(); - //analyze the quantifiers - Debug("fmf-model-debug") << "Analyzing quantifiers..." << std::endl; - analyzeQuantifiers(); - //build the model - Debug("fmf-model-debug") << "Building model..." << std::endl; - for( std::map< Node, UfModel >::iterator it = d_uf_model.begin(); it != d_uf_model.end(); ++it ){ - it->second.buildModel(); + //reset the quantifiers engine + d_quantEngine->resetInstantiationRound( e ); + //initialize the model + Debug("fmf-model-debug") << "Build model..." << std::endl; + d_builder.buildModel( d_quantEngine->getModel() ); + d_quantEngine->d_model_set = true; + //if builder has lemmas, add and return + if( d_builder.d_addedLemmas>0 ){ + addedLemmas += (int)d_builder.d_addedLemmas; + }else{ + //print debug + Debug("fmf-model-complete") << std::endl; + debugPrint("fmf-model-complete"); + //verify we are SAT by trying exhaustive instantiation + if( optUseRelevantDomain() ){ + d_rel_domain.compute(); } - } - //print debug - debugPrint("fmf-model-complete"); - //try exhaustive instantiation - Debug("fmf-model-debug") << "Do exhaustive instantiation..." << std::endl; - int addedLemmas = 0; - for( int i=0; igetNumAssertedQuantifiers(); i++ ){ - Node f = d_quantEngine->getAssertedQuantifier( i ); - if( d_quant_sat.find( f )==d_quant_sat.end() ){ - addedLemmas += instantiateQuantifier( f ); + d_triedLemmas = 0; + d_testLemmas = 0; + d_relevantLemmas = 0; + d_totalLemmas = 0; + Debug("fmf-model-debug") << "Do exhaustive instantiation..." << std::endl; + for( int i=0; igetModel()->getNumAssertedQuantifiers(); i++ ){ + Node f = d_quantEngine->getModel()->getAssertedQuantifier( i ); + if( d_builder.d_quant_sat.find( f )==d_builder.d_quant_sat.end() ){ + addedLemmas += exhaustiveInstantiate( f, optUseRelevantDomain() ); + if( optOneQuantPerRound() && addedLemmas>0 ){ + break; + } + } +#ifdef ME_PRINT_WARNINGS + if( addedLemmas>10000 ){ + break; + } +#endif + } + Debug("fmf-model-debug") << "---> Added lemmas = " << addedLemmas << " / " << d_triedLemmas << " / "; + Debug("fmf-model-debug") << d_testLemmas << " / " << d_relevantLemmas << " / " << d_totalLemmas << std::endl; + if( Options::current()->printModelEngine ){ + Message() << "Added Lemmas = " << addedLemmas << " / " << d_triedLemmas << " / "; + Message() << d_testLemmas << " / " << d_relevantLemmas << " / " << d_totalLemmas << std::endl; + double clSet2 = double(clock())/double(CLOCKS_PER_SEC); + Message() << "Finished model engine, time = " << (clSet2-clSet) << std::endl; + } +#ifdef ME_PRINT_WARNINGS + if( addedLemmas>10000 ){ + Debug("fmf-exit") << std::endl; + debugPrint("fmf-exit"); + exit( 0 ); } - } -#ifdef ME_PRINT_PROCESS_TIMES - Notice() << "Added Lemmas = " << addedLemmas << std::endl; #endif - if( addedLemmas==0 ){ - //debugPrint("fmf-consistent"); - //for( std::map< Node, UfModel >::iterator it = d_uf_model.begin(); it != d_uf_model.end(); ++it ){ - // it->second.simplify(); - //} - Debug("fmf-consistent") << std::endl; - debugPrint("fmf-consistent"); } } - d_quantEngine->flushLemmas( &d_th->getOutputChannel() ); + if( addedLemmas==0 ){ + //CVC4 will answer SAT + Debug("fmf-consistent") << std::endl; + debugPrint("fmf-consistent"); + }else{ + //otherwise, the search will continue + d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() ); + } } } @@ -611,19 +462,31 @@ void ModelEngine::assertNode( Node f ){ } -bool ModelEngine::useModel() { - return Options::current()->fmfModelBasedInst; +bool ModelEngine::optOneInstPerQuantRound(){ + return Options::current()->fmfOneInstPerRound; +} + +bool ModelEngine::optUseRelevantDomain(){ + return Options::current()->fmfRelevantDomain; +} + +bool ModelEngine::optOneQuantPerRound(){ +#ifdef ONE_QUANT_PER_ROUND + return true; +#else + return false; +#endif } -bool ModelEngine::initializeQuantifier( Node f ){ +int ModelEngine::initializeQuantifier( Node f ){ if( d_quant_init.find( f )==d_quant_init.end() ){ d_quant_init[f] = true; Debug("inst-fmf-init") << "Initialize " << f << std::endl; //add the model basis instantiation // This will help produce the necessary information for model completion. - // We do this by extending distinguish ground assertions (those + // We do this by extending distinguish ground assertions (those // containing terms with "model basis" attribute) to hold for all cases. - + ////first, check if any variables are required to be equal //for( std::map< Node, bool >::iterator it = d_quantEngine->d_phase_reqs[f].begin(); // it != d_quantEngine->d_phase_reqs[f].end(); ++it ){ @@ -632,747 +495,167 @@ bool ModelEngine::initializeQuantifier( Node f ){ // Notice() << "Unhandled phase req: " << n << std::endl; // } //} - + std::vector< Node > ics; std::vector< Node > terms; for( int j=0; j<(int)f[0].getNumChildren(); j++ ){ - terms.push_back( getModelBasisTerm( f[0][j].getType() ) ); + Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j ); + Node t = d_quantEngine->getTermDatabase()->getModelBasisTerm( ic.getType() ); + ics.push_back( ic ); + terms.push_back( t ); + //calculate the basis match for f + d_builder.d_quant_basis_match[f].d_map[ ic ] = t; } ++(d_statistics.d_num_quants_init); + //register model basis body + Node n = d_quantEngine->getTermDatabase()->getCounterexampleBody( f ); + Node gn = n.substitute( ics.begin(), ics.end(), terms.begin(), terms.end() ); + d_quantEngine->getTermDatabase()->registerModelBasis( n, gn ); + //add model basis instantiation if( d_quantEngine->addInstantiation( f, terms ) ){ - return false; + return 1; }else{ - //usually shouldn't happen + //shouldn't happen usually, but will occur if x != y is a required literal for f. //Notice() << "No model basis for " << f << std::endl; ++(d_statistics.d_num_quants_init_fail); } } - return true; -} - -void ModelEngine::buildRepresentatives(){ - d_ra.clear(); - //collect all representatives for all types and store as representative alphabet - for( int i=0; igetNumCardinalityTypes(); i++ ){ - TypeNode tn = d_ss->getCardinalityType( i ); - std::vector< Node > reps; - d_ss->getRepresentatives( tn, reps ); - Assert( !reps.empty() ); - //if( (int)reps.size()!=d_ss->getCardinality( tn ) ){ - // Notice() << "InstStrategyFinteModelFind::processResetInstantiationRound: Bad representatives for type." << std::endl; - // Notice() << " " << tn << " has cardinality " << d_ss->getCardinality( tn ); - // Notice() << " but only " << (int)reps.size() << " were given." << std::endl; - // Unimplemented( 27 ); - //} - Debug("fmf-model-debug") << " " << tn << " -> " << reps.size() << std::endl; - Debug("fmf-model-debug") << " "; - for( int i=0; i<(int)reps.size(); i++ ){ - Debug("fmf-model-debug") << reps[i] << " "; - } - Debug("fmf-model-debug") << std::endl; - //set them in the alphabet - d_ra.set( tn, reps ); -#ifdef ME_PRINT_PROCESS_TIMES - Notice() << tn << " has " << reps.size() << " representatives. " << std::endl; -#endif - } + return 0; } -void ModelEngine::initializeModel(){ - d_uf_model.clear(); - d_quant_sat.clear(); - for( int k=0; k<2; k++ ){ - d_pro_con_quant[k].clear(); - } - - ////now analyze quantifiers (temporary) - //for( int i=0; i<(int)d_quantEngine->getNumAssertedQuantifiers(); i++ ){ - // Node f = d_quantEngine->getAssertedQuantifier( i ); - // Debug("fmf-model-req") << "Phase requirements for " << f << ": " << std::endl; - // for( std::map< Node, bool >::iterator it = d_quantEngine->d_phase_reqs[f].begin(); - // it != d_quantEngine->d_phase_reqs[f].end(); ++it ){ - // Node n = it->first; - // Debug("fmf-model-req") << " " << n << " -> " << it->second << std::endl; - // if( n.getKind()==APPLY_UF ){ - // processPredicate( f, n, it->second ); - // }else if( n.getKind()==EQUAL ){ - // processEquality( f, n, it->second ); - // } - // } - //} - for( int i=0; i<(int)d_quantEngine->getNumAssertedQuantifiers(); i++ ){ - Node f = d_quantEngine->getAssertedQuantifier( i ); - initializeUf( f[1] ); - //register model basis terms - std::vector< Node > vars; - std::vector< Node > subs; - for( int j=0; j<(int)f[0].getNumChildren(); j++ ){ - vars.push_back( d_quantEngine->getInstantiationConstant( f, j ) ); - subs.push_back( getModelBasisTerm( f[0][j].getType() ) ); - } - Node n = d_quantEngine->getCounterexampleBody( f ); - Node gn = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); - registerModelBasis( n, gn ); - } -} - -void ModelEngine::analyzeQuantifiers(){ - int quantSatInit = 0; - int nquantSatInit = 0; - //analyze the preferences of each quantifier - for( int i=0; i<(int)d_quantEngine->getNumAssertedQuantifiers(); i++ ){ - Node f = d_quantEngine->getAssertedQuantifier( i ); - Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl; - std::vector< Node > pro_con[2]; - std::vector< Node > pro_con_patterns[2]; - //check which model basis terms have good and bad definitions according to f - for( std::map< Node, bool >::iterator it = d_quantEngine->d_phase_reqs[f].begin(); - it != d_quantEngine->d_phase_reqs[f].end(); ++it ){ - Node n = it->first; - Node gn = d_model_basis[n]; - Debug("fmf-model-req") << " Req: " << n << " -> " << it->second << std::endl; - int pref = 0; - bool isConst = true; - std::vector< Node > uf_terms; - std::vector< Node > uf_term_patterns; - if( gn.getKind()==APPLY_UF ){ - if( d_quantEngine->getEqualityQuery()->hasTerm( gn ) ){ - uf_terms.push_back( gn ); - uf_term_patterns.push_back( n ); - bool phase = areEqual( gn, NodeManager::currentNM()->mkConst( true ) ); - pref = phase!=it->second ? 1 : -1; - } - }else if( gn.getKind()==EQUAL ){ - bool success = true; - for( int j=0; j<2; j++ ){ - if( n[j].getKind()==APPLY_UF ){ - Node op = gn[j].getOperator(); - if( d_uf_model.find( op )!=d_uf_model.end() ){ - Assert( gn[j].getKind()==APPLY_UF ); - uf_terms.push_back( gn[j] ); - uf_term_patterns.push_back( n[j] ); - }else{ - //found undefined uf operator - success = false; - } - }else if( n[j].hasAttribute(InstConstantAttribute()) ){ - isConst = false; - } - } - if( success && !uf_terms.empty() ){ - if( (!it->second && areEqual( gn[0], gn[1] )) || (it->second && areDisequal( gn[0], gn[1] )) ){ - pref = 1; - }else if( (it->second && areEqual( gn[0], gn[1] )) || (!it->second && areDisequal( gn[0], gn[1] )) ){ - pref = -1; - } - } - } - if( pref!=0 ){ - Debug("fmf-model-prefs") << " It is " << ( pref==1 ? "pro" : "con" ); - Debug("fmf-model-prefs") << " the definition of " << n << std::endl; - if( pref==1 ){ - if( isConst ){ - for( int j=0; j<(int)uf_terms.size(); j++ ){ - //the only uf that is initialized are those that are constant - Node op = uf_terms[j].getOperator(); - Assert( d_uf_model.find( op )!=d_uf_model.end() ); - if( !d_uf_model[op].isConstant() ){ - isConst = false; - break; - } - } - if( isConst ){ - d_quant_sat[f] = true; - //we only need to consider current term definition(s) for this quantifier to be satisified, ignore the others - for( int k=0; k<2; k++ ){ - pro_con[k].clear(); - pro_con_patterns[k].clear(); - } - //instead, just note to the model for each uf term that f is pro its definition - for( int j=0; j<(int)uf_terms.size(); j++ ){ - Node op = uf_terms[j].getOperator(); - d_uf_model[op].d_reconsider_model = false; - } - } - } - } - if( d_quant_sat.find( f )!=d_quant_sat.end() ){ - Debug("fmf-model-prefs") << " * Constant SAT due to definition of " << n << std::endl; - break; - }else{ - int pcIndex = pref==1 ? 0 : 1; - for( int j=0; j<(int)uf_terms.size(); j++ ){ - pro_con[pcIndex].push_back( uf_terms[j] ); - pro_con_patterns[pcIndex].push_back( uf_term_patterns[j] ); - } - } - } - } - if( d_quant_sat.find( f )!=d_quant_sat.end() ){ - quantSatInit++; - d_statistics.d_pre_sat_quant += quantSatInit; - }else{ - nquantSatInit++; - d_statistics.d_pre_nsat_quant += quantSatInit; - } - //add quantifier's preferences to vector - for( int k=0; k<2; k++ ){ - for( int j=0; j<(int)pro_con[k].size(); j++ ){ - Node op = pro_con[k][j].getOperator(); - d_uf_model[op].setValuePreference( f, pro_con[k][j], k==0 ); - d_pro_con_quant[k][ f ].push_back( pro_con_patterns[k][j] ); - } - } - } - Debug("fmf-model-prefs") << "Pre-Model Completion: Quantifiers SAT: " << quantSatInit << " / " << (quantSatInit+nquantSatInit) << std::endl; -} - -int ModelEngine::instantiateQuantifier( Node f ){ +int ModelEngine::exhaustiveInstantiate( Node f, bool useRelInstDomain ){ + int tests = 0; int addedLemmas = 0; + int triedLemmas = 0; Debug("inst-fmf-ei") << "Add matches for " << f << "..." << std::endl; Debug("inst-fmf-ei") << " Instantiation Constants: "; for( size_t i=0; igetInstantiationConstant( f, i ) << " "; + Debug("inst-fmf-ei") << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ) << " "; } Debug("inst-fmf-ei") << std::endl; - for( int k=0; k<2; k++ ){ - Debug("inst-fmf-ei") << " " << ( k==0 ? "Pro" : "Con" ) << " definitions:" << std::endl; - for( int i=0; i<(int)d_pro_con_quant[k][f].size(); i++ ){ - Debug("inst-fmf-ei") << " " << d_pro_con_quant[k][f][i] << std::endl; - } - } - if( d_pro_con_quant[0][f].empty() ){ - Debug("inst-fmf-ei") << "WARNING: " << f << " has no pros for default literal definitions" << std::endl; - } - d_eval_failed_lits.clear(); - d_eval_failed.clear(); - d_eval_term_model.clear(); - //d_eval_term_vals.clear(); - //d_eval_term_fv_deps.clear(); - RepAlphabetIterator riter( d_quantEngine, f, this ); - increment( &riter ); -#ifdef ONE_INST_PER_QUANT_PER_ROUND - while( !riter.isFinished() && addedLemmas==0 ){ -#else - while( !riter.isFinished() ){ + if( d_builder.d_quant_selection_lits[f].empty() ){ + Debug("inst-fmf-ei") << "WARNING: " << f << " has no model literal definitions (is f clausified?)" << std::endl; +#ifdef ME_PRINT_WARNINGS + Message() << "WARNING: " << f << " has no model literal definitions (is f clausified?)" << std::endl; #endif - InstMatch m; - riter.getMatch( d_quantEngine, m ); - Debug("fmf-model-eval") << "* Add instantiation " << std::endl; - riter.d_inst_tried++; - if( d_quantEngine->addInstantiation( f, m ) ){ - addedLemmas++; - } - riter.increment( d_quantEngine ); - increment( &riter ); - } - if( Debug.isOn("inst-fmf-ei") ){ - int totalInst = 1; - for( int i=0; i<(int)f[0].getNumChildren(); i++ ){ - totalInst = totalInst * (int)getReps()->d_type_reps[ f[0][i].getType() ].size(); - } - Debug("inst-fmf-ei") << "Finished: " << std::endl; - Debug("inst-fmf-ei") << " Inst Skipped: " << (totalInst-riter.d_inst_tried) << std::endl; - Debug("inst-fmf-ei") << " Inst Tried: " << riter.d_inst_tried << std::endl; - Debug("inst-fmf-ei") << " Inst Added: " << addedLemmas << std::endl; - Debug("inst-fmf-ei") << " # Tests: " << riter.d_inst_tests << std::endl; - } - return addedLemmas; -} - -void ModelEngine::registerModelBasis( Node n, Node gn ){ - if( d_model_basis.find( n )==d_model_basis.end() ){ - d_model_basis[n] = gn; - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - registerModelBasis( n[i], gn[i] ); - } - } -} - -Node ModelEngine::getArbitraryElement( TypeNode tn, std::vector< Node >& exclude ){ - Node retVal; - if( tn==NodeManager::currentNM()->booleanType() ){ - if( exclude.empty() ){ - retVal = NodeManager::currentNM()->mkConst( false ); - }else if( exclude.size()==1 ){ - retVal = NodeManager::currentNM()->mkConst( areEqual( exclude[0], NodeManager::currentNM()->mkConst( false ) ) ); - } - }else if( d_ra.d_type_reps.find( tn )!=d_ra.d_type_reps.end() ){ - for( int i=0; i<(int)d_ra.d_type_reps[tn].size(); i++ ){ - if( std::find( exclude.begin(), exclude.end(), d_ra.d_type_reps[tn][i] )==exclude.end() ){ - retVal = d_ra.d_type_reps[tn][i]; - break; - } - } - } - if( !retVal.isNull() ){ - return d_quantEngine->getEqualityQuery()->getRepresentative( retVal ); }else{ - return Node::null(); - } -} - -Node ModelEngine::getModelBasisTerm( TypeNode tn, int i ){ - return d_ss->getCardinalityTerm( tn ); -} - -Node ModelEngine::getModelBasisApplyUfTerm( Node op ){ - if( d_model_basis_term.find( op )==d_model_basis_term.end() ){ - TypeNode t = op.getType(); - std::vector< Node > children; - children.push_back( op ); - for( int i=0; i<(int)t.getNumChildren()-1; i++ ){ - children.push_back( getModelBasisTerm( t[i] ) ); - } - d_model_basis_term[op] = NodeManager::currentNM()->mkNode( APPLY_UF, children ); - } - return d_model_basis_term[op]; -} - -bool ModelEngine::isModelBasisTerm( Node op, Node n ){ - if( n.getOperator()==op ){ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( !n[i].getAttribute(ModelBasisAttribute()) ){ - return false; - } - } - return true; - }else{ - return false; - } -} - -void ModelEngine::initializeUf( Node n ){ - std::vector< Node > terms; - collectUfTerms( n, terms ); - for( int i=0; i<(int)terms.size(); i++ ){ - initializeUfModel( terms[i].getOperator() ); - } -} - -void ModelEngine::collectUfTerms( Node n, std::vector< Node >& terms ){ - if( n.getKind()==APPLY_UF ){ - terms.push_back( n ); - } - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - collectUfTerms( n[i], terms ); - } -} - -void ModelEngine::initializeUfModel( Node op ){ - if( d_uf_model.find( op )==d_uf_model.end() ){ - TypeNode tn = op.getType(); - tn = tn[ (int)tn.getNumChildren()-1 ]; - if( tn==NodeManager::currentNM()->booleanType() || uf::StrongSolverTheoryUf::isRelevantType( tn ) ){ - d_uf_model[ op ] = UfModel( op, this ); - } - } -} - -void ModelEngine::makeEvalTermModel( Node n ){ - if( d_eval_term_model.find( n )==d_eval_term_model.end() ){ - makeEvalTermIndexOrder( n ); - if( !d_eval_term_use_default_model[n] ){ - Node op = n.getOperator(); - d_eval_term_model[n] = UfModelTreeOrdered( op, d_eval_term_index_order[n] ); - d_uf_model[op].makeModel( d_quantEngine, d_eval_term_model[n] ); - Debug("fmf-model-index-order") << "Make model for " << n << " : " << std::endl; - d_eval_term_model[n].debugPrint( "fmf-model-index-order", d_quantEngine, 2 ); - } - } -} - -struct sortGetMaxVariableNum { - std::map< Node, int > d_max_var_num; - int computeMaxVariableNum( Node n ){ - if( n.getKind()==INST_CONSTANT ){ - return n.getAttribute(InstVarNumAttribute()); - }else if( n.hasAttribute(InstConstantAttribute()) ){ - int maxVal = -1; - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - int val = getMaxVariableNum( n[i] ); - if( val>maxVal ){ - maxVal = val; - } - } - return maxVal; - }else{ - return -1; - } - } - int getMaxVariableNum( Node n ){ - std::map< Node, int >::iterator it = d_max_var_num.find( n ); - if( it==d_max_var_num.end() ){ - int num = computeMaxVariableNum( n ); - d_max_var_num[n] = num; - return num; - }else{ - return it->second; - } - } - bool operator() (Node i,Node j) { return (getMaxVariableNum(i) > argIndex; - std::vector< Node > args; - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( argIndex.find( n[i] )==argIndex.end() ){ - args.push_back( n[i] ); - } - argIndex[n[i]].push_back( i ); - } - sortGetMaxVariableNum sgmvn; - std::sort( args.begin(), args.end(), sgmvn ); - for( int i=0; i<(int)args.size(); i++ ){ - for( int j=0; j<(int)argIndex[ args[i] ].size(); j++ ){ - d_eval_term_index_order[n].push_back( argIndex[ args[i] ][j] ); - } - } - bool useDefault = true; - for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){ - if( i!=d_eval_term_index_order[n][i] ){ - useDefault = false; - break; - } - } - d_eval_term_use_default_model[n] = useDefault; - Debug("fmf-model-index-order") << "Will consider the following index ordering for " << n << " : "; - for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){ - Debug("fmf-model-index-order") << d_eval_term_index_order[n][i] << " "; - } - Debug("fmf-model-index-order") << std::endl; - } -} - -//void ModelEngine::processPredicate( Node f, Node p, bool phase ){ -// Node op = p.getOperator(); -// initializeUfModel( op ); -// d_uf_model[ op ].addRequirement( f, p, phase ); -//} -// -//void ModelEngine::processEquality( Node f, Node eq, bool phase ){ -// for( int i=0; i<2; i++ ){ -// int j = i==0 ? 1 : 0; -// if( eq[i].getKind()==APPLY_UF && eq[i].hasAttribute(InstConstantAttribute()) ){ -// Node op = eq[i].getOperator(); -// initializeUfModel( op ); -// d_uf_model[ op ].addEqRequirement( f, eq[i], eq[j], phase ); -// } -// } -//} - -void ModelEngine::increment( RepAlphabetIterator* rai ){ - if( useModel() ){ - bool success; - do{ - success = true; - if( !rai->isFinished() ){ - //see if instantiation is already true in current model - Debug("fmf-model-eval") << "Evaulating "; - rai->debugPrintSmall("fmf-model-eval"); - //calculate represenative terms we are currently considering - rai->calculateTerms( d_quantEngine ); - rai->d_inst_tests++; - //if eVal is not (int)rai->d_index.size(), then the instantiation is already true in the model, - // and eVal is the highest index in rai which we can safely iterate - int depIndex; - if( evaluate( rai, d_quantEngine->getCounterexampleBody( rai->d_f ), depIndex )==1 ){ - Debug("fmf-model-eval") << " Returned success with depIndex = " << depIndex << std::endl; - //Notice() << "Returned eVal = " << eVal << "/" << rai->d_index.size() << std::endl; - if( depIndex<(int)rai->d_index.size() ){ -#ifdef DISABLE_EVAL_SKIP_MULTIPLE - depIndex = (int)rai->d_index.size()-1; -#endif - rai->increment2( d_quantEngine, depIndex ); - success = false; + Debug("inst-fmf-ei") << " Model literal definitions:" << std::endl; + for( size_t i=0; igetModel() ); + //set the domain for the iterator (the sufficient set of instantiations to try) + if( useRelInstDomain ){ + riter.setDomain( d_rel_domain.d_quant_inst_domain[f] ); + } + RepSetEvaluator reval( d_quantEngine->getModel(), &riter ); + while( !riter.isFinished() && ( addedLemmas==0 || !optOneInstPerQuantRound() ) ){ + d_testLemmas++; + if( d_builder.optUseModel() ){ + //see if instantiation is already true in current model + Debug("fmf-model-eval") << "Evaluating "; + riter.debugPrintSmall("fmf-model-eval"); + Debug("fmf-model-eval") << "Done calculating terms." << std::endl; + tests++; + //if evaluate(...)==1, then the instantiation is already true in the model + // depIndex is the index of the least significant variable that this evaluation relies upon + int depIndex = riter.getNumTerms()-1; + int eval = reval.evaluate( d_quantEngine->getTermDatabase()->getCounterexampleBody( f ), depIndex ); + if( eval==1 ){ + Debug("fmf-model-eval") << " Returned success with depIndex = " << depIndex << std::endl; + riter.increment2( depIndex ); + }else{ + Debug("fmf-model-eval") << " Returned " << (eval==-1 ? "failure" : "unknown") << ", depIndex = " << depIndex << std::endl; + InstMatch m; + riter.getMatch( d_quantEngine, m ); + Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl; + triedLemmas++; + d_triedLemmas++; + if( d_quantEngine->addInstantiation( f, m ) ){ + addedLemmas++; +#ifdef EVAL_FAIL_SKIP_MULTIPLE + if( eval==-1 ){ + riter.increment2( depIndex ); + }else{ + riter.increment(); } +#else + riter.increment(); +#endif }else{ - Debug("fmf-model-eval") << " Returned failure." << std::endl; - } - } - }while( !success ); - } -} - -//if evaluate( rai, n, phaseReq ) = eVal, -// if eVal = rai->d_index.size() -// then the formula n instantiated with rai cannot be proven to be equal to phaseReq -// otherwise, -// each n{rai->d_index[0]/x_0...rai->d_index[eVal]/x_eVal, */x_(eVal+1) ... */x_n } is equal to phaseReq in the current model -int ModelEngine::evaluate( RepAlphabetIterator* rai, Node n, int& depIndex ){ - ++(d_statistics.d_eval_formulas); - //Debug("fmf-model-eval-debug") << "Evaluate " << n << " " << phaseReq << std::endl; - if( n.getKind()==NOT ){ - int val = evaluate( rai, n[0], depIndex ); - return val==1 ? -1 : ( val==-1 ? 1 : 0 ); - }else if( n.getKind()==OR || n.getKind()==AND || n.getKind()==IMPLIES ){ - int baseVal = n.getKind()==AND ? 1 : -1; - int eVal = baseVal; - int posDepIndex = (int)rai->d_index.size(); - int negDepIndex = -1; - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - //evaluate subterm - int childDepIndex; - Node nn = ( i==0 && n.getKind()==IMPLIES ) ? n[i].notNode() : n[i]; - int eValT = evaluate( rai, nn, childDepIndex ); - if( eValT==baseVal ){ - if( eVal==baseVal ){ - if( childDepIndex>negDepIndex ){ - negDepIndex = childDepIndex; - } - } - }else if( eValT==-baseVal ){ - eVal = -baseVal; - if( childDepIndexdepIndex2 ? depIndex1 : depIndex2; - return eVal==eVal2 ? 1 : -1; - } - } - return 0; - }else if( n.getKind()==ITE ){ - int depIndex1; - int eVal = evaluate( rai, n[0], depIndex1 ); - if( eVal==0 ){ - //DO_THIS: evaluate children to see if they are the same value? - return 0; }else{ - int depIndex2; - int eValT = evaluate( rai, n[eVal==1 ? 1 : 2], depIndex2 ); - depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2; - return eValT; - } - }else if( n.getKind()==FORALL ){ - return 0; - }else{ - ////if we know we will fail again, immediately return - //if( d_eval_failed.find( n )!=d_eval_failed.end() ){ - // if( d_eval_failed[n] ){ - // return -1; - // } - //} - //Debug("fmf-model-eval-debug") << "Evaluate literal " << n << std::endl; - //this should be a literal - Node gn = n.substitute( rai->d_ic.begin(), rai->d_ic.end(), rai->d_terms.begin(), rai->d_terms.end() ); - //Debug("fmf-model-eval-debug") << " Ground version = " << gn << std::endl; - int retVal = 0; - std::vector< Node > fv_deps; - if( n.getKind()==APPLY_UF ){ - //case for boolean predicates - Node val = evaluateTerm( n, gn, fv_deps ); - if( d_quantEngine->getEqualityQuery()->hasTerm( val ) ){ - if( areEqual( val, NodeManager::currentNM()->mkConst( true ) ) ){ - retVal = 1; - }else{ - retVal = -1; - } - } - }else if( n.getKind()==EQUAL ){ - //case for equality - retVal = evaluateEquality( n[0], n[1], gn[0], gn[1], fv_deps ); - } - if( retVal!=0 ){ - int maxIndex = -1; - for( int i=0; i<(int)fv_deps.size(); i++ ){ - int index = rai->d_var_order[ fv_deps[i].getAttribute(InstVarNumAttribute()) ]; - if( index>maxIndex ){ - maxIndex = index; - if( index==(int)rai->d_index.size()-1 ){ - break; - } - } + InstMatch m; + riter.getMatch( d_quantEngine, m ); + Debug("fmf-model-eval") << "* Add instantiation " << std::endl; + triedLemmas++; + d_triedLemmas++; + if( d_quantEngine->addInstantiation( f, m ) ){ + addedLemmas++; } - Debug("fmf-model-eval-debug") << "Evaluate literal: return " << retVal << ", depends = " << maxIndex << std::endl; - depIndex = maxIndex; + riter.increment(); } - return retVal; - } -} - -int ModelEngine::evaluateEquality( Node n1, Node n2, Node gn1, Node gn2, std::vector< Node >& fv_deps ){ - ++(d_statistics.d_eval_eqs); - Debug("fmf-model-eval-debug") << "Evaluate equality: " << std::endl; - Debug("fmf-model-eval-debug") << " " << n1 << " = " << n2 << std::endl; - Debug("fmf-model-eval-debug") << " " << gn1 << " = " << gn2 << std::endl; - Node val1 = evaluateTerm( n1, gn1, fv_deps ); - Node val2 = evaluateTerm( n2, gn2, fv_deps ); - Debug("fmf-model-eval-debug") << " Values : "; - printRepresentative( "fmf-model-eval-debug", d_quantEngine, val1 ); - Debug("fmf-model-eval-debug") << " = "; - printRepresentative( "fmf-model-eval-debug", d_quantEngine, val2 ); - Debug("fmf-model-eval-debug") << std::endl; - int retVal = 0; - if( areEqual( val1, val2 ) ){ - retVal = 1; - }else if( areDisequal( val1, val2 ) ){ - retVal = -1; - } - if( retVal!=0 ){ - Debug("fmf-model-eval-debug") << " ---> Success, value = " << (retVal==1) << std::endl; - }else{ - Debug("fmf-model-eval-debug") << " ---> Failed" << std::endl; - } - Debug("fmf-model-eval-debug") << " Value depends on variables: "; - for( int i=0; i<(int)fv_deps.size(); i++ ){ - Debug("fmf-model-eval-debug") << fv_deps[i] << " "; } - Debug("fmf-model-eval-debug") << std::endl; - return retVal; -} - -Node ModelEngine::evaluateTerm( Node n, Node gn, std::vector< Node >& fv_deps ){ - if( n.hasAttribute(InstConstantAttribute()) ){ - if( n.getKind()==INST_CONSTANT ){ - fv_deps.push_back( n ); - return gn; - //}else if( d_eval_term_fv_deps.find( n )!=d_eval_term_fv_deps.end() && - // d_eval_term_fv_deps[n].find( gn )!=d_eval_term_fv_deps[n].end() ){ - // fv_deps.insert( fv_deps.end(), d_eval_term_fv_deps[n][gn].begin(), d_eval_term_fv_deps[n][gn].end() ); - // return d_eval_term_vals[gn]; - }else{ - //Debug("fmf-model-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl; - //first we must evaluate the arguments - Node val = gn; - if( n.getKind()==APPLY_UF ){ - Node op = gn.getOperator(); - //if it is a defined UF, then consult the interpretation - Node gnn = gn; - ++(d_statistics.d_eval_uf_terms); - int depIndex = 0; - //first we must evaluate the arguments - bool childrenChanged = false; - std::vector< Node > children; - children.push_back( op ); - std::map< int, std::vector< Node > > children_var_deps; - //for each argument, calculate its value, and the variables its value depends upon - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - Node nn = evaluateTerm( n[i], gn[i], children_var_deps[i] ); - children.push_back( nn ); - childrenChanged = childrenChanged || nn!=gn[i]; - } - //remake gn if changed - if( childrenChanged ){ - gnn = NodeManager::currentNM()->mkNode( APPLY_UF, children ); - } - if( d_uf_model.find( op )!=d_uf_model.end() ){ -#ifdef USE_INDEX_ORDERING - //make the term model specifically for n - makeEvalTermModel( n ); - //now, consult the model - if( d_eval_term_use_default_model[n] ){ - val = d_uf_model[op].d_tree.getValue( d_quantEngine, gnn, depIndex ); - }else{ - val = d_eval_term_model[ n ].getValue( d_quantEngine, gnn, depIndex ); - } - //Debug("fmf-model-eval-debug") << "Evaluate term " << n << " (" << gn << ", " << gnn << ")" << std::endl; - //d_eval_term_model[ n ].debugPrint("fmf-model-eval-debug", d_quantEngine ); - Assert( !val.isNull() ); -#else - //now, consult the model - val = d_uf_model[op].d_tree.getValue( d_quantEngine, gnn, depIndex ); -#endif - }else{ - d_eval_term_use_default_model[n] = true; - val = gnn; - depIndex = (int)n.getNumChildren(); - } - Debug("fmf-model-eval-debug") << "Evaluate term " << n << " = " << gn << " = " << gnn << " = "; - printRepresentative( "fmf-model-eval-debug", d_quantEngine, val ); - Debug("fmf-model-eval-debug") << ", depIndex = " << depIndex << std::endl; - if( !val.isNull() ){ -#ifdef USE_INDEX_ORDERING - for( int i=0; i >::iterator it = children_var_deps.begin(); it != children_var_deps.end(); ++it ){ - if( it->firstsecond.begin(), it->second.end() ); - } - } -#endif - } - ////cache the result - //d_eval_term_vals[gn] = val; - //d_eval_term_fv_deps[n][gn].insert( d_eval_term_fv_deps[n][gn].end(), fv_deps.begin(), fv_deps.end() ); + d_statistics.d_eval_formulas += reval.d_eval_formulas; + d_statistics.d_eval_eqs += reval.d_eval_eqs; + d_statistics.d_eval_uf_terms += reval.d_eval_uf_terms; + int totalInst = 1; + int relevantInst = 1; + for( size_t i=0; igetModel()->d_ra.d_type_reps[ f[0][i].getType() ].size(); + relevantInst = relevantInst * (int)riter.d_domain[i].size(); + } + d_totalLemmas += totalInst; + d_relevantLemmas += relevantInst; + Debug("inst-fmf-ei") << "Finished: " << std::endl; + Debug("inst-fmf-ei") << " Inst Total: " << totalInst << std::endl; + Debug("inst-fmf-ei") << " Inst Relevant: " << relevantInst << std::endl; + Debug("inst-fmf-ei") << " Inst Tried: " << triedLemmas << std::endl; + Debug("inst-fmf-ei") << " Inst Added: " << addedLemmas << std::endl; + Debug("inst-fmf-ei") << " # Tests: " << tests << std::endl; +///----------- +#ifdef ME_PRINT_WARNINGS + if( addedLemmas>1000 ){ + Notice() << "WARNING: many instantiations produced for " << f << ": " << std::endl; + Notice() << " Inst Total: " << totalInst << std::endl; + Notice() << " Inst Relevant: " << totalRelevant << std::endl; + Notice() << " Inst Tried: " << triedLemmas << std::endl; + Notice() << " Inst Added: " << addedLemmas << std::endl; + Notice() << " # Tests: " << tests << std::endl; + Notice() << std::endl; + if( !d_builder.d_quant_selection_lits[f].empty() ){ + Notice() << " Model literal definitions:" << std::endl; + for( size_t i=0; igetEqualityQuery()->areEqual( a, b ); -} - -bool ModelEngine::areDisequal( Node a, Node b ){ - return d_quantEngine->getEqualityQuery()->areDisequal( a, b ); +#endif +///----------- + return addedLemmas; } void ModelEngine::debugPrint( const char* c ){ - Debug( c ) << "---Current Model---" << std::endl; - Debug( c ) << "Representatives: " << std::endl; - d_ra.debugPrint( c, d_quantEngine ); Debug( c ) << "Quantifiers: " << std::endl; - for( int i=0; i<(int)d_quantEngine->getNumAssertedQuantifiers(); i++ ){ - Node f = d_quantEngine->getAssertedQuantifier( i ); + for( int i=0; i<(int)d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + Node f = d_quantEngine->getModel()->getAssertedQuantifier( i ); Debug( c ) << " "; - if( d_quant_sat.find( f )!=d_quant_sat.end() ){ + if( d_builder.d_quant_sat.find( f )!=d_builder.d_quant_sat.end() ){ Debug( c ) << "*SAT* "; }else{ Debug( c ) << " "; } Debug( c ) << f << std::endl; } - Debug( c ) << "Functions: " << std::endl; - for( std::map< Node, UfModel >::iterator it = d_uf_model.begin(); it != d_uf_model.end(); ++it ){ - it->second.debugPrint( c ); - Debug( c ) << std::endl; - } + //d_quantEngine->getModel()->debugPrint( c ); } ModelEngine::Statistics::Statistics(): d_inst_rounds("ModelEngine::Inst_Rounds", 0), - d_pre_sat_quant("ModelEngine::Status_quant_pre_sat", 0), - d_pre_nsat_quant("ModelEngine::Status_quant_pre_non_sat", 0), d_eval_formulas("ModelEngine::Eval_Formulas", 0 ), d_eval_eqs("ModelEngine::Eval_Equalities", 0 ), d_eval_uf_terms("ModelEngine::Eval_Uf_Terms", 0 ), @@ -1380,8 +663,6 @@ ModelEngine::Statistics::Statistics(): d_num_quants_init_fail("ModelEngine::Num_Quants_No_Basis", 0 ) { StatisticsRegistry::registerStat(&d_inst_rounds); - StatisticsRegistry::registerStat(&d_pre_sat_quant); - StatisticsRegistry::registerStat(&d_pre_nsat_quant); StatisticsRegistry::registerStat(&d_eval_formulas); StatisticsRegistry::registerStat(&d_eval_eqs); StatisticsRegistry::registerStat(&d_eval_uf_terms); @@ -1391,11 +672,11 @@ ModelEngine::Statistics::Statistics(): ModelEngine::Statistics::~Statistics(){ StatisticsRegistry::unregisterStat(&d_inst_rounds); - StatisticsRegistry::unregisterStat(&d_pre_sat_quant); - StatisticsRegistry::unregisterStat(&d_pre_nsat_quant); StatisticsRegistry::unregisterStat(&d_eval_formulas); StatisticsRegistry::unregisterStat(&d_eval_eqs); StatisticsRegistry::unregisterStat(&d_eval_uf_terms); StatisticsRegistry::unregisterStat(&d_num_quants_init); StatisticsRegistry::unregisterStat(&d_num_quants_init_fail); } + + diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h index cf6691918..b01139826 100644 --- a/src/theory/quantifiers/model_engine.h +++ b/src/theory/quantifiers/model_engine.h @@ -11,7 +11,7 @@ ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** - ** \brief Instantiation Engine classes + ** \brief Model Engine classes **/ #include "cvc4_private.h" @@ -21,6 +21,9 @@ #include "theory/quantifiers_engine.h" #include "theory/quantifiers/theory_quantifiers.h" +#include "theory/model.h" +#include "theory/uf/theory_uf_model.h" +#include "theory/quantifiers/relevant_domain.h" namespace CVC4 { namespace theory { @@ -31,312 +34,87 @@ namespace uf{ namespace quantifiers { -/** this class stores a representative alphabet */ -class RepAlphabet { -public: - RepAlphabet(){} - RepAlphabet( RepAlphabet& ra, QuantifiersEngine* qe ); - ~RepAlphabet(){} - std::map< TypeNode, std::vector< Node > > d_type_reps; - std::map< Node, int > d_tmap; - /** clear the alphabet */ - void clear(){ - d_type_reps.clear(); - d_tmap.clear(); - } - /** set the representatives for type */ - void set( TypeNode t, std::vector< Node >& reps ); - /** returns index in d_type_reps for node n */ - int getIndexFor( Node n ) { return d_tmap.find( n )!=d_tmap.end() ? d_tmap[n] : -1; } - /** debug print */ - void debugPrint( const char* c, QuantifiersEngine* qe ); -}; - -class ModelEngine; - -/** this class iterates over a RepAlphabet */ -class RepAlphabetIterator { -private: - void initialize( QuantifiersEngine* qe, Node f, ModelEngine* model ); -public: - RepAlphabetIterator( QuantifiersEngine* qe, Node f, ModelEngine* model ); - RepAlphabetIterator( QuantifiersEngine* qe, Node f, ModelEngine* model, std::vector< int >& indexOrder ); - ~RepAlphabetIterator(){} - //pointer to quantifier - Node d_f; - //pointer to model - ModelEngine* d_model; - //index we are considering - std::vector< int > d_index; - //ordering for variables we are indexing over - // for example, given reps = { a, b } and quantifier forall( x, y, z ) P( x, y, z ) with d_index_order = { 2, 0, 1 }, - // then we consider instantiations in this order: - // a/x a/y a/z - // a/x b/y a/z - // b/x a/y a/z - // b/x b/y a/z - // ... - std::vector< int > d_index_order; - //variables to index they are considered at - // for example, if d_index_order = { 2, 0, 1 } - // then d_var_order = { 0 -> 1, 1 -> 2, 2 -> 0 } - std::map< int, int > d_var_order; - //the instantiation constants of d_f - std::vector< Node > d_ic; - //the current terms we are considering - std::vector< Node > d_terms; -public: - /** increment the iterator */ - void increment2( QuantifiersEngine* qe, int counter ); - void increment( QuantifiersEngine* qe ); - /** is the iterator finished? */ - bool isFinished(); - /** produce the match that this iterator represents */ - void getMatch( QuantifiersEngine* qe, InstMatch& m ); - /** get the i_th term we are considering */ - Node getTerm( int i ); - /** get the number of terms we are considering */ - int getNumTerms() { return d_f[0].getNumChildren(); } - /** refresh d_term to be current with d_index */ - void calculateTerms( QuantifiersEngine* qe ); - /** debug print */ - void debugPrint( const char* c ); - void debugPrintSmall( const char* c ); - //for debugging - int d_inst_tried; - int d_inst_tests; -}; - - -class UfModelTree -{ -public: - UfModelTree(){} - /** the data */ - std::map< Node, UfModelTree > d_data; - /** the value of this tree node (if all paths lead to same value) */ - Node d_value; -public: - //is this model tree empty? - bool isEmpty() { return d_data.empty(); } - //clear - void clear(){ - d_data.clear(); - d_value = Node::null(); - } - /** setValue function - * - * For each argument of n with ModelBasisAttribute() set to true will be considered default arguments if ground=false - * - */ - void setValue( QuantifiersEngine* qe, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex ); - /** getValue function - * - * returns $val, the value of ground term n - * Say n is f( t_0...t_n ) - * depIndex is the index for which every term of the form f( t_0 ... t_depIndex, *,... * ) is equal to $val - * for example, if g( x_0, x_1, x_2 ) := lambda x_0 x_1 x_2. if( x_1==a ) b else c, - * then g( a, a, a ) would return b with depIndex = 1 - * If ground = true, we are asking whether the term n is constant (assumes that all non-model basis arguments are ground) - * - */ - Node getValue( QuantifiersEngine* qe, Node n, std::vector< int >& indexOrder, int& depIndex, int argIndex ); - ///** getConstant Value function - // * - // * given term n, where n may contain model basis arguments - // * if n is constant for its entire domain, then this function returns the value of its domain - // * otherwise, it returns null - // * for example, if f( x_0, x_1 ) := if( x_0 = a ) b else if( x_1 = a ) a else b, - // * then f( a, e ) would return b, while f( e, a ) would return null - // * - // */ - Node getConstantValue( QuantifiersEngine* qe, Node n, std::vector< int >& indexOrder, int argIndex ); - /** simplify function */ - void simplify( Node op, Node defaultVal, int argIndex ); - // is total ? - bool isTotal( Node op, int argIndex ); -public: - void debugPrint( const char* c, QuantifiersEngine* qe, std::vector< int >& indexOrder, int ind = 0, int arg = 0 ); -}; -class UfModelTreeOrdered +//the model builder +class ModelEngineBuilder : public TheoryEngineModelBuilder { -private: - Node d_op; - std::vector< int > d_index_order; - UfModelTree d_tree; -public: - UfModelTreeOrdered(){} - UfModelTreeOrdered( Node op ) : d_op( op ){ - TypeNode tn = d_op.getType(); - for( int i=0; i<(int)(tn.getNumChildren()-1); i++ ){ - d_index_order.push_back( i ); - } - } - UfModelTreeOrdered( Node op, std::vector< int >& indexOrder ) : d_op( op ){ - d_index_order.insert( d_index_order.end(), indexOrder.begin(), indexOrder.end() ); - } - bool isEmpty() { return d_tree.isEmpty(); } - void clear() { d_tree.clear(); } - void setValue( QuantifiersEngine* qe, Node n, Node v, bool ground = true ){ - d_tree.setValue( qe, n, v, d_index_order, ground, 0 ); - } - Node getValue( QuantifiersEngine* qe, Node n, int& depIndex ){ - return d_tree.getValue( qe, n, d_index_order, depIndex, 0 ); - } - Node getConstantValue( QuantifiersEngine* qe, Node n ) { - return d_tree.getConstantValue( qe, n, d_index_order, 0 ); - } - void simplify() { d_tree.simplify( d_op, Node::null(), 0 ); } - bool isTotal() { return d_tree.isTotal( d_op, 0 ); } -public: - void debugPrint( const char* c, QuantifiersEngine* qe, int ind = 0 ){ - d_tree.debugPrint( c, qe, d_index_order, ind ); - } -}; - -class UfModel -{ -//public: - //std::map< Node, std::vector< Node > > d_reqs[2]; - //std::map< Node, std::map< Node, std::vector< Node > > > d_eq_reqs[2]; - ///** add requirement */ - //void addRequirement( Node f, Node p, bool phase ) { d_reqs[ phase ? 1 : 0 ][ f ].push_back( p ); } - ///** add equality requirement */ - //void addEqRequirement( Node f, Node t, Node te, bool phase ) { d_eq_reqs[ phase ? 1 : 0 ][ f ][ t ].push_back( te ); } -private: - Node d_op; - ModelEngine* d_me; - std::vector< Node > d_ground_asserts; - std::vector< Node > d_ground_asserts_reps; - bool d_model_constructed; - //store for set values - std::map< Node, Node > d_set_values[2]; - // preferences for default values - std::vector< Node > d_values; - std::map< Node, std::vector< Node > > d_value_pro_con[2]; - /** set value */ - void setValue( Node n, Node v, bool ground = true ); - /** set model */ - void setModel(); - /** clear model */ - void clearModel(); -public: - UfModel(){} - UfModel( Node op, ModelEngine* qe ); - ~UfModel(){} - //data structure that stores the model - UfModelTreeOrdered d_tree; - //quantifiers that are satisfied because of the constant definition of d_op - bool d_reconsider_model; -public: - /** debug print */ - void debugPrint( const char* c ); - /** get constant value */ - Node getConstantValue( QuantifiersEngine* qe, Node n ); - /** is empty */ - bool isEmpty() { return d_ground_asserts.empty(); } - /** is constant */ - bool isConstant(); -public: - /** build model */ - void buildModel(); - /** make model */ - void makeModel( QuantifiersEngine* qe, UfModelTreeOrdered& tree ); -public: - /** set value preference */ - void setValuePreference( Node f, Node n, bool isPro ); +protected: + //quantifiers engine + QuantifiersEngine* d_qe; + //map from operators to model preference data + std::map< Node, uf::UfModelPreferenceData > d_uf_prefs; + /** choose representative */ + Node chooseRepresentative( TheoryModel* tm, Node eqc ); + /** use constants for representatives */ + void processBuildModel( TheoryModel* m ); + //analyze quantifiers + void analyzeQuantifiers( FirstOrderModel* fm ); + //build model + void finishBuildModel( FirstOrderModel* fm ); + //theory-specific build models + void finishBuildModelUf( FirstOrderModel* fm, uf::UfModel& model ); + //do InstGen techniques for quantifier, return number of lemmas produced + int doInstGen( FirstOrderModel* fm, Node f ); +public: + ModelEngineBuilder( QuantifiersEngine* qe ); + virtual ~ModelEngineBuilder(){} +public: + /** number of lemmas generated while building model */ + int d_addedLemmas; + //map from quantifiers to if are constant SAT + std::map< Node, bool > d_quant_sat; + //map from quantifiers to the instantiation literals that their model is dependent upon + std::map< Node, std::vector< Node > > d_quant_selection_lits; +public: + //map from quantifiers to model basis match + std::map< Node, InstMatch > d_quant_basis_match; + //options + bool optUseModel(); + bool optInstGen(); + bool optOneQuantPerRoundInstGen(); + /** statistics class */ + class Statistics { + public: + IntStat d_pre_sat_quant; + IntStat d_pre_nsat_quant; + Statistics(); + ~Statistics(); + }; + Statistics d_statistics; }; - - - class ModelEngine : public QuantifiersModule { - friend class UfModel; - friend class RepAlphabetIterator; + friend class uf::UfModel; + friend class RepSetIterator; private: - TheoryQuantifiers* d_th; - QuantifiersEngine* d_quantEngine; - uf::StrongSolverTheoryUf* d_ss; + /** builder class */ + ModelEngineBuilder d_builder; +private: //data maintained globally: //which quantifiers have been initialized std::map< Node, bool > d_quant_init; - //map from ops to model basis terms - std::map< Node, Node > d_model_basis_term; - //map from instantiation terms to their model basis equivalent - std::map< Node, Node > d_model_basis; - //the model we are working with - RepAlphabet d_ra; - std::map< Node, UfModel > d_uf_model; - ////map from model basis terms to quantifiers that are pro/con their definition - //std::map< Node, std::vector< Node > > d_quant_pro_con[2]; - //map from quantifiers to model basis terms that are pro the definition of - std::map< Node, std::vector< Node > > d_pro_con_quant[2]; - //map from quantifiers to if are constant SAT - std::map< Node, bool > d_quant_sat; +private: //analysis of current model: + //relevant domain + RelevantDomain d_rel_domain; private: - int evaluate( RepAlphabetIterator* rai, Node n, int& depIndex ); - int evaluateEquality( Node n1, Node n2, Node gn1, Node gn2, std::vector< Node >& fv_deps ); - Node evaluateTerm( Node n, Node gn, std::vector< Node >& fv_deps ); - //temporary storing which literals have failed - void clearEvalFailed( int index ); - std::map< Node, bool > d_eval_failed; - std::map< int, std::vector< Node > > d_eval_failed_lits; - ////temporary storing for values/free variable dependencies - //std::map< Node, Node > d_eval_term_vals; - //std::map< Node, std::map< Node, std::vector< Node > > > d_eval_term_fv_deps; + //options + bool optOneInstPerQuantRound(); + bool optUseRelevantDomain(); + bool optOneQuantPerRound(); private: - //map from terms to the models used to calculate their value - std::map< Node, UfModelTreeOrdered > d_eval_term_model; - std::map< Node, bool > d_eval_term_use_default_model; - void makeEvalTermModel( Node n ); - //index ordering to use for each term - std::map< Node, std::vector< int > > d_eval_term_index_order; - int getMaxVariableNum( int n ); - void makeEvalTermIndexOrder( Node n ); -public: - void increment( RepAlphabetIterator* rai ); + //initialize quantifiers, return number of lemmas produced + int initializeQuantifier( Node f ); + //exhaustively instantiate quantifier (possibly using mbqi), return number of lemmas produced + int exhaustiveInstantiate( Node f, bool useRelInstDomain = false ); private: - //queries about equality - bool areEqual( Node a, Node b ); - bool areDisequal( Node a, Node b ); -private: - bool useModel(); -private: - //initialize quantifiers, return false if lemma needed to be added - bool initializeQuantifier( Node f ); - //build representatives - void buildRepresentatives(); - //initialize model - void initializeModel(); - //analyze quantifiers - void analyzeQuantifiers(); - //instantiate quantifier, return number of lemmas produced - int instantiateQuantifier( Node f ); -private: - //register instantiation terms with their corresponding model basis terms - void registerModelBasis( Node n, Node gn ); - //for building UF model - void initializeUf( Node n ); - void collectUfTerms( Node n, std::vector< Node >& terms ); - void initializeUfModel( Node op ); - //void processPredicate( Node f, Node p, bool phase ); - //void processEquality( Node f, Node eq, bool phase ); + //temporary statistics + int d_triedLemmas; + int d_testLemmas; + int d_totalLemmas; + int d_relevantLemmas; public: - ModelEngine( TheoryQuantifiers* th ); + ModelEngine( QuantifiersEngine* qe ); ~ModelEngine(){} - //get quantifiers engine - QuantifiersEngine* getQuantifiersEngine() { return d_quantEngine; } - //get representatives - RepAlphabet* getReps() { return &d_ra; } - //get arbitrary element - Node getArbitraryElement( TypeNode tn, std::vector< Node >& exclude ); - //get model basis term - Node getModelBasisTerm( TypeNode tn, int i = 0 ); - //get model basis term for op - Node getModelBasisApplyUfTerm( Node op ); - //is model basis term for op - bool isModelBasisTerm( Node op, Node n ); public: void check( Theory::Effort e ); void registerQuantifier( Node f ); @@ -349,8 +127,6 @@ public: class Statistics { public: IntStat d_inst_rounds; - IntStat d_pre_sat_quant; - IntStat d_pre_nsat_quant; IntStat d_eval_formulas; IntStat d_eval_eqs; IntStat d_eval_uf_terms; diff --git a/src/theory/quantifiers/relevant_domain.cpp b/src/theory/quantifiers/relevant_domain.cpp new file mode 100644 index 000000000..e7ae1d1c7 --- /dev/null +++ b/src/theory/quantifiers/relevant_domain.cpp @@ -0,0 +1,173 @@ +/********************* */ +/*! \file relevant_domain.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of relevant domain class + **/ + +#include "theory/quantifiers_engine.h" +#include "theory/quantifiers/relevant_domain.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers/first_order_model.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; + +RelevantDomain::RelevantDomain( FirstOrderModel* m ) : d_model( m ){ + +} + +void RelevantDomain::compute(){ + d_quant_inst_domain.clear(); + for( int i=0; i<(int)d_model->getNumAssertedQuantifiers(); i++ ){ + Node f = d_model->getAssertedQuantifier( i ); + d_quant_inst_domain[f].resize( f[0].getNumChildren() ); + } + //add ground terms to domain (rule 1 of complete instantiation essentially uf fragment) + for( std::map< Node, uf::UfModel >::iterator it = d_model->d_uf_model.begin(); + it != d_model->d_uf_model.end(); ++it ){ + Node op = it->first; + for( int i=0; i<(int)it->second.d_ground_asserts.size(); i++ ){ + Node n = it->second.d_ground_asserts[i]; + //add arguments to domain + for( int j=0; j<(int)n.getNumChildren(); j++ ){ + if( d_model->d_ra.hasType( n[j].getType() ) ){ + Node ra = d_model->getRepresentative( n[j] ); + int raIndex = d_model->d_ra.getIndexFor( ra ); + Assert( raIndex!=-1 ); + if( std::find( d_active_domain[op][j].begin(), d_active_domain[op][j].end(), raIndex )==d_active_domain[op][j].end() ){ + d_active_domain[op][j].push_back( raIndex ); + } + } + } + //add to range + Node r = it->second.d_ground_asserts_reps[i]; + int raIndex = d_model->d_ra.getIndexFor( r ); + Assert( raIndex!=-1 ); + if( std::find( d_active_range[op].begin(), d_active_range[op].end(), raIndex )==d_active_range[op].end() ){ + d_active_range[op].push_back( raIndex ); + } + } + } + //find fixed point for relevant domain computation + bool success; + do{ + success = true; + for( int i=0; i<(int)d_model->getNumAssertedQuantifiers(); i++ ){ + Node f = d_model->getAssertedQuantifier( i ); + //compute the domain of relevant instantiations (rule 3 of complete instantiation, essentially uf fragment) + if( computeRelevantInstantiationDomain( d_model->getTermDatabase()->getCounterexampleBody( f ), Node::null(), -1, d_quant_inst_domain[f] ) ){ + success = false; + } + //extend the possible domain for functions (rule 2 of complete instantiation, essentially uf fragment) + RepDomain range; + if( extendFunctionDomains( d_model->getTermDatabase()->getCounterexampleBody( f ), range ) ){ + success = false; + } + } + }while( !success ); +} + +bool RelevantDomain::computeRelevantInstantiationDomain( Node n, Node parent, int arg, std::vector< RepDomain >& rd ){ + bool domainChanged = false; + if( n.getKind()==INST_CONSTANT ){ + bool domainSet = false; + int vi = n.getAttribute(InstVarNumAttribute()); + Assert( !parent.isNull() ); + if( parent.getKind()==APPLY_UF ){ + //if the child of APPLY_UF term f( ... ), only consider the active domain of f at given argument + Node op = parent.getOperator(); + if( d_active_domain.find( op )!=d_active_domain.end() ){ + for( size_t i=0; id_ra.hasType( tn ) ){ + if( rd[vi].size()!=d_model->d_ra.d_type_reps[tn].size() ){ + rd[vi].clear(); + for( size_t i=0; id_ra.d_type_reps[tn].size(); i++ ){ + rd[vi].push_back( i ); + domainChanged = true; + } + } + }else{ + //infinite domain? + } + } + }else{ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( computeRelevantInstantiationDomain( n[i], n, i, rd ) ){ + domainChanged = true; + } + } + } + return domainChanged; +} + +bool RelevantDomain::extendFunctionDomains( Node n, RepDomain& range ){ + if( n.getKind()==INST_CONSTANT ){ + Node f = n.getAttribute(InstConstantAttribute()); + int var = n.getAttribute(InstVarNumAttribute()); + range.insert( range.begin(), d_quant_inst_domain[f][var].begin(), d_quant_inst_domain[f][var].end() ); + return false; + }else{ + Node op; + if( n.getKind()==APPLY_UF ){ + op = n.getOperator(); + } + bool domainChanged = false; + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + RepDomain childRange; + if( extendFunctionDomains( n[i], childRange ) ){ + domainChanged = true; + } + if( n.getKind()==APPLY_UF ){ + if( d_active_domain.find( op )!=d_active_domain.end() ){ + for( int j=0; j<(int)childRange.size(); j++ ){ + int v = childRange[j]; + if( std::find( d_active_domain[op][i].begin(), d_active_domain[op][i].end(), v )==d_active_domain[op][i].end() ){ + d_active_domain[op][i].push_back( v ); + domainChanged = true; + } + } + }else{ + //do this? + } + } + } + //get the range + if( n.hasAttribute(InstConstantAttribute()) ){ + if( n.getKind()==APPLY_UF && d_active_range.find( op )!=d_active_range.end() ){ + range.insert( range.end(), d_active_range[op].begin(), d_active_range[op].end() ); + }else{ + //infinite range? + } + }else{ + Node r = d_model->getRepresentative( n ); + range.push_back( d_model->d_ra.getIndexFor( r ) ); + } + return domainChanged; + } +} \ No newline at end of file diff --git a/src/theory/quantifiers/relevant_domain.h b/src/theory/quantifiers/relevant_domain.h new file mode 100644 index 000000000..362a39d6a --- /dev/null +++ b/src/theory/quantifiers/relevant_domain.h @@ -0,0 +1,54 @@ +/********************* */ +/*! \file relevant_domain.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief relevant domain class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__RELEVANT_DOMAIN_H +#define __CVC4__RELEVANT_DOMAIN_H + +#include "theory/quantifiers/first_order_model.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class RelevantDomain +{ +private: + FirstOrderModel* d_model; + + //the domain of the arguments for each operator + std::map< Node, std::map< int, RepDomain > > d_active_domain; + //the range for each operator + std::map< Node, RepDomain > d_active_range; + //for computing relevant instantiation domain, return true if changed + bool computeRelevantInstantiationDomain( Node n, Node parent, int arg, std::vector< RepDomain >& rd ); + //for computing extended + bool extendFunctionDomains( Node n, RepDomain& range ); +public: + RelevantDomain( FirstOrderModel* m ); + virtual ~RelevantDomain(){} + //compute the relevant domain + void compute(); + //relevant instantiation domain for each quantifier + std::map< Node, std::vector< RepDomain > > d_quant_inst_domain; +}; + +} +} +} + +#endif diff --git a/src/theory/quantifiers/rep_set_iterator.cpp b/src/theory/quantifiers/rep_set_iterator.cpp new file mode 100644 index 000000000..02041480f --- /dev/null +++ b/src/theory/quantifiers/rep_set_iterator.cpp @@ -0,0 +1,523 @@ +/********************* */ +/*! \file rep_set_iterator.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of relevant domain class + **/ + +#include "theory/quantifiers/rep_set_iterator.h" +#include "theory/quantifiers/model_engine.h" +#include "theory/quantifiers/term_database.h" + +#define USE_INDEX_ORDERING + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; + +RepSetIterator::RepSetIterator( Node f, FirstOrderModel* model ) : d_f( f ), d_model( model ){ + //store instantiation constants + for( size_t i=0; id_ra.d_type_reps[d_f[0][i].getType()].size(); j++ ){ + d_domain[i].push_back( j ); + } + } +} + +void RepSetIterator::setIndexOrder( std::vector< int >& indexOrder ){ + d_index_order.clear(); + d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() ); + //make the d_var_order mapping + for( int i=0; i<(int)d_index_order.size(); i++ ){ + d_var_order[d_index_order[i]] = i; + } +} + +void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){ + d_domain.clear(); + d_domain.insert( d_domain.begin(), domain.begin(), domain.end() ); + //we are done if a domain is empty + for( int i=0; i<(int)d_domain.size(); i++ ){ + if( d_domain[i].empty() ){ + d_index.clear(); + } + } +} + +void RepSetIterator::increment2( int counter ){ + Assert( !isFinished() ); +#ifdef DISABLE_EVAL_SKIP_MULTIPLE + counter = (int)d_index.size()-1; +#endif + //increment d_index + while( counter>=0 && d_index[counter]==(int)(d_domain[counter].size()-1) ){ + counter--; + } + if( counter==-1 ){ + d_index.clear(); + }else{ + for( int i=(int)d_index.size()-1; i>counter; i-- ){ + d_index[i] = 0; + //d_model->clearEvalFailed( i ); + } + d_index[counter]++; + //d_model->clearEvalFailed( counter ); + } +} + +void RepSetIterator::increment(){ + if( !isFinished() ){ + increment2( (int)d_index.size()-1 ); + } +} + +bool RepSetIterator::isFinished(){ + return d_index.empty(); +} + +void RepSetIterator::getMatch( QuantifiersEngine* qe, InstMatch& m ){ + for( int i=0; i<(int)d_index.size(); i++ ){ + m.d_map[ qe->getTermDatabase()->getInstantiationConstant( d_f, d_index_order[i] ) ] = getTerm( i ); + } +} + +Node RepSetIterator::getTerm( int i ){ + TypeNode tn = d_f[0][d_index_order[i]].getType(); + Assert( d_model->d_ra.d_type_reps.find( tn )!=d_model->d_ra.d_type_reps.end() ); + int index = d_index_order[i]; + return d_model->d_ra.d_type_reps[tn][d_domain[index][d_index[index]]]; +} + +void RepSetIterator::debugPrint( const char* c ){ + for( int i=0; i<(int)d_index.size(); i++ ){ + Debug( c ) << i << " : " << d_index[i] << " : " << getTerm( i ) << std::endl; + } +} + +void RepSetIterator::debugPrintSmall( const char* c ){ + Debug( c ) << "RI: "; + for( int i=0; i<(int)d_index.size(); i++ ){ + Debug( c ) << d_index[i] << ": " << getTerm( i ) << " "; + } + Debug( c ) << std::endl; +} + +RepSetEvaluator::RepSetEvaluator( FirstOrderModel* m, RepSetIterator* ri ) : d_model( m ), d_riter( ri ){ + +} + +//if evaluate( n, phaseReq ) = eVal, +// if eVal = d_riter->d_index.size() +// then the formula n instantiated with d_riter cannot be proven to be equal to phaseReq +// otherwise, +// each n{d_riter->d_index[0]/x_0...d_riter->d_index[eVal]/x_eVal, */x_(eVal+1) ... */x_n } is equal to phaseReq in the current model +int RepSetEvaluator::evaluate( Node n, int& depIndex ){ + ++d_eval_formulas; + //Debug("fmf-eval-debug") << "Evaluate " << n << " " << phaseReq << std::endl; + //Notice() << "Eval " << n << std::endl; + if( n.getKind()==NOT ){ + int val = evaluate( n[0], depIndex ); + return val==1 ? -1 : ( val==-1 ? 1 : 0 ); + }else if( n.getKind()==OR || n.getKind()==AND || n.getKind()==IMPLIES ){ + int baseVal = n.getKind()==AND ? 1 : -1; + int eVal = baseVal; + int posDepIndex = d_riter->getNumTerms(); + int negDepIndex = -1; + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + //evaluate subterm + int childDepIndex; + Node nn = ( i==0 && n.getKind()==IMPLIES ) ? n[i].notNode() : n[i]; + int eValT = evaluate( nn, childDepIndex ); + if( eValT==baseVal ){ + if( eVal==baseVal ){ + if( childDepIndex>negDepIndex ){ + negDepIndex = childDepIndex; + } + } + }else if( eValT==-baseVal ){ + eVal = -baseVal; + if( childDepIndexdepIndex2 ? depIndex1 : depIndex2; + return eVal==eVal2 ? 1 : -1; + } + } + return 0; + }else if( n.getKind()==ITE ){ + int depIndex1, depIndex2; + int eVal = evaluate( n[0], depIndex1 ); + if( eVal==0 ){ + //evaluate children to see if they are the same value + int eval1 = evaluate( n[1], depIndex1 ); + if( eval1!=0 ){ + int eval2 = evaluate( n[1], depIndex2 ); + if( eval1==eval2 ){ + depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2; + return eval1; + } + } + }else{ + int eValT = evaluate( n[eVal==1 ? 1 : 2], depIndex2 ); + depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2; + return eValT; + } + return 0; + }else if( n.getKind()==FORALL ){ + return 0; + }else{ + ////if we know we will fail again, immediately return + //if( d_eval_failed.find( n )!=d_eval_failed.end() ){ + // if( d_eval_failed[n] ){ + // return -1; + // } + //} + //Debug("fmf-eval-debug") << "Evaluate literal " << n << std::endl; + //this should be a literal + //Node gn = n.substitute( d_riter->d_ic.begin(), d_riter->d_ic.end(), d_riter->d_terms.begin(), d_riter->d_terms.end() ); + //Debug("fmf-eval-debug") << " Ground version = " << gn << std::endl; + int retVal = 0; + depIndex = d_riter->getNumTerms()-1; + if( n.getKind()==APPLY_UF ){ + //case for boolean predicates + Node val = evaluateTerm( n, depIndex ); + if( d_model->hasTerm( val ) ){ + if( d_model->areEqual( val, d_model->d_true ) ){ + retVal = 1; + }else{ + retVal = -1; + } + } + }else if( n.getKind()==EQUAL ){ + //case for equality + retVal = evaluateEquality( n[0], n[1], depIndex ); + }else{ + std::vector< int > cdi; + Node val = evaluateTermDefault( n, depIndex, cdi ); + if( !val.isNull() ){ + val = Rewriter::rewrite( val ); + if( val==d_model->d_true ){ + retVal = 1; + }else if( val==d_model->d_false ){ + retVal = -1; + } + } + } + if( retVal!=0 ){ + Debug("fmf-eval-debug") << "Evaluate literal: return " << retVal << ", depends = " << depIndex << std::endl; + }else{ + Debug("fmf-eval-amb") << "Neither true nor false : " << n << std::endl; + //std::cout << "Neither true nor false : " << n << std::endl; + } + return retVal; + } +} + +int RepSetEvaluator::evaluateEquality( Node n1, Node n2, int& depIndex ){ + ++d_eval_eqs; + //Notice() << "Eval eq " << n1 << " " << n2 << std::endl; + Debug("fmf-eval-debug") << "Evaluate equality: " << std::endl; + Debug("fmf-eval-debug") << " " << n1 << " = " << n2 << std::endl; + int depIndex1, depIndex2; + Node val1 = evaluateTerm( n1, depIndex1 ); + Node val2 = evaluateTerm( n2, depIndex2 ); + Debug("fmf-eval-debug") << " Values : "; + d_model->printRepresentativeDebug( "fmf-eval-debug", val1 ); + Debug("fmf-eval-debug") << " = "; + d_model->printRepresentativeDebug( "fmf-eval-debug", val2 ); + Debug("fmf-eval-debug") << std::endl; + int retVal = 0; + if( !val1.isNull() && !val2.isNull() ){ + if( d_model->areEqual( val1, val2 ) ){ + retVal = 1; + }else if( d_model->areDisequal( val1, val2 ) ){ + retVal = -1; + }else{ + Node eq = val1.eqNode( val2 ); + eq = Rewriter::rewrite( eq ); + if( eq==d_model->d_true ){ + retVal = 1; + }else if( eq==d_model->d_false ){ + retVal = -1; + } + } + } + if( retVal!=0 ){ + depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2; + Debug("fmf-eval-debug") << " value = " << (retVal==1) << ", depIndex = " << depIndex << std::endl; + }else{ + depIndex = d_riter->getNumTerms()-1; + Debug("fmf-eval-amb") << "Neither equal nor disequal : " << n1 << " , " << n2 << std::endl; + //std::cout << "Neither equal nor disequal : " << n1 << " , " << n2 << std::endl; + } + return retVal; +} + +Node RepSetEvaluator::evaluateTerm( Node n, int& depIndex ){ + //Notice() << "Eval term " << n << std::endl; + if( n.hasAttribute(InstConstantAttribute()) ){ + Node val; + depIndex = d_riter->getNumTerms()-1; + //check the type of n + if( n.getKind()==INST_CONSTANT ){ + int v = n.getAttribute(InstVarNumAttribute()); + depIndex = d_riter->d_var_order[ v ]; + val = d_riter->getTerm( v ); + }else if( n.getKind()==ITE ){ + int depIndex1, depIndex2; + int eval = evaluate( n[0], depIndex1 ); + if( eval==0 ){ + //evaluate children to see if they are the same + Node val1 = evaluateTerm( n[ 1 ], depIndex1 ); + Node val2 = evaluateTerm( n[ 1 ], depIndex1 ); + if( val1==val2 ){ + val = val1; + depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2; + }else{ + return Node::null(); + } + }else{ + val = evaluateTerm( n[ eval==1 ? 1 : 2 ], depIndex2 ); + depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2; + } + }else{ +#if 0 + //for select, pre-process read over writes + if( n.getKind()==SELECT ){ + Node selIndex = evaluateTerm( n[1], depIndex ); + if( selIndex.isNull() ){ + depIndex = d_riter->getNumTerms()-1; + return Node::null(); + } + Node arr = n[0]; + int eval = 1; + while( arr.getKind()==STORE && eval!=0 ){ + int tempIndex; + eval = evaluateEquality( selIndex, arr[1], tempIndex ); + depIndex = tempIndex > depIndex ? tempIndex : depIndex; + if( eval==1 ){ + val = evaluateTerm( arr[2], tempIndex ); + depIndex = tempIndex > depIndex ? tempIndex : depIndex; + return val; + }else if( eval==-1 ){ + arr = arr[0]; + } + } + n = NodeManager::currentNM()->mkNode( SELECT, arr, selIndex ); + } +#endif + //default term evaluate : evaluate all children, recreate the value + std::vector< int > children_depIndex; + val = evaluateTermDefault( n, depIndex, children_depIndex ); + //case split on the type of term + if( n.getKind()==APPLY_UF ){ + Node op = n.getOperator(); + //Debug("fmf-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl; + //if it is a defined UF, then consult the interpretation + ++d_eval_uf_terms; + int argDepIndex = 0; + if( d_model->d_uf_model.find( op )!=d_model->d_uf_model.end() ){ + //make the term model specifically for n + makeEvalUfModel( n ); + //now, consult the model + if( d_eval_uf_use_default[n] ){ + val = d_model->d_uf_model[op].d_tree.getValue( d_model, val, argDepIndex ); + }else{ + val = d_eval_uf_model[ n ].getValue( d_model, val, argDepIndex ); + } + //Debug("fmf-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl; + //d_eval_uf_model[ n ].debugPrint("fmf-eval-debug", d_qe ); + Assert( !val.isNull() ); + }else{ + d_eval_uf_use_default[n] = true; + argDepIndex = (int)n.getNumChildren(); + } + //recalculate the depIndex + depIndex = -1; + for( int i=0; idepIndex ){ + depIndex = children_depIndex[index]; + } + } + Debug("fmf-eval-debug") << "Evaluate term " << n << " = "; + d_model->printRepresentativeDebug( "fmf-eval-debug", val ); + Debug("fmf-eval-debug") << ", depIndex = " << depIndex << std::endl; + }else if( n.getKind()==SELECT ){ + if( d_model->d_array_model.find( n[0] )!=d_model->d_array_model.end() ){ + //consult the default value for the array DO_THIS + //val = Rewriter::rewrite( val ); + //val = d_model->d_array_model[ n[0] ]; + val = Rewriter::rewrite( val ); + }else{ + val = Rewriter::rewrite( val ); + } + }else{ + val = Rewriter::rewrite( val ); + } + } + return val; + }else{ + depIndex = -1; + return n; + } +} + +Node RepSetEvaluator::evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex ){ + //first we must evaluate the arguments + std::vector< Node > children; + if( n.getMetaKind()==kind::metakind::PARAMETERIZED ){ + children.push_back( n.getOperator() ); + } + depIndex = -1; + //for each argument, calculate its value, and the variables its value depends upon + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + childDepIndex.push_back( -1 ); + Node nn = evaluateTerm( n[i], childDepIndex[i] ); + if( nn.isNull() ){ + depIndex = d_riter->getNumTerms()-1; + return nn; + }else{ + children.push_back( nn ); + if( childDepIndex[i]>depIndex ){ + depIndex = childDepIndex[i]; + } + } + } + //recreate the value + return NodeManager::currentNM()->mkNode( n.getKind(), children ); +} + +void RepSetEvaluator::clearEvalFailed( int index ){ + for( int i=0; i<(int)d_eval_failed_lits[index].size(); i++ ){ + d_eval_failed[ d_eval_failed_lits[index][i] ] = false; + } + d_eval_failed_lits[index].clear(); +} + +void RepSetEvaluator::makeEvalUfModel( Node n ){ + if( d_eval_uf_model.find( n )==d_eval_uf_model.end() ){ + makeEvalUfIndexOrder( n ); + if( !d_eval_uf_use_default[n] ){ + Node op = n.getOperator(); + d_eval_uf_model[n] = uf::UfModelTreeOrdered( op, d_eval_term_index_order[n] ); + d_model->d_uf_model[op].makeModel( d_eval_uf_model[n] ); + //Debug("fmf-index-order") << "Make model for " << n << " : " << std::endl; + //d_eval_uf_model[n].debugPrint( "fmf-index-order", d_qe, 2 ); + } + } +} + +struct sortGetMaxVariableNum { + std::map< Node, int > d_max_var_num; + int computeMaxVariableNum( Node n ){ + if( n.getKind()==INST_CONSTANT ){ + return n.getAttribute(InstVarNumAttribute()); + }else if( n.hasAttribute(InstConstantAttribute()) ){ + int maxVal = -1; + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + int val = getMaxVariableNum( n[i] ); + if( val>maxVal ){ + maxVal = val; + } + } + return maxVal; + }else{ + return -1; + } + } + int getMaxVariableNum( Node n ){ + std::map< Node, int >::iterator it = d_max_var_num.find( n ); + if( it==d_max_var_num.end() ){ + int num = computeMaxVariableNum( n ); + d_max_var_num[n] = num; + return num; + }else{ + return it->second; + } + } + bool operator() (Node i,Node j) { return (getMaxVariableNum(i) > argIndex; + std::vector< Node > args; + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( argIndex.find( n[i] )==argIndex.end() ){ + args.push_back( n[i] ); + } + argIndex[n[i]].push_back( i ); + } + sortGetMaxVariableNum sgmvn; + std::sort( args.begin(), args.end(), sgmvn ); + for( int i=0; i<(int)args.size(); i++ ){ + for( int j=0; j<(int)argIndex[ args[i] ].size(); j++ ){ + d_eval_term_index_order[n].push_back( argIndex[ args[i] ][j] ); + } + } + bool useDefault = true; + for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){ + if( i!=d_eval_term_index_order[n][i] ){ + useDefault = false; + break; + } + } + d_eval_uf_use_default[n] = useDefault; + Debug("fmf-index-order") << "Will consider the following index ordering for " << n << " : "; + for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){ + Debug("fmf-index-order") << d_eval_term_index_order[n][i] << " "; + } + Debug("fmf-index-order") << std::endl; +#else + d_eval_uf_use_default[n] = true; +#endif + } +} + + diff --git a/src/theory/quantifiers/rep_set_iterator.h b/src/theory/quantifiers/rep_set_iterator.h new file mode 100644 index 000000000..308d09a38 --- /dev/null +++ b/src/theory/quantifiers/rep_set_iterator.h @@ -0,0 +1,120 @@ +/********************* */ +/*! \file rep_set_iterator.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief rep_set_iterator class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__REP_SET_ITERATOR_H +#define __CVC4__REP_SET_ITERATOR_H + +#include "theory/quantifiers_engine.h" +#include "theory/quantifiers/first_order_model.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +/** this class iterates over a RepSet */ +class RepSetIterator { +public: + RepSetIterator( Node f, FirstOrderModel* model ); + ~RepSetIterator(){} + //pointer to quantifier + Node d_f; + //pointer to model + FirstOrderModel* d_model; + //index we are considering + std::vector< int > d_index; + //domain we are considering + std::vector< RepDomain > d_domain; + //ordering for variables we are indexing over + // for example, given reps = { a, b } and quantifier forall( x, y, z ) P( x, y, z ) with d_index_order = { 2, 0, 1 }, + // then we consider instantiations in this order: + // a/x a/y a/z + // a/x b/y a/z + // b/x a/y a/z + // b/x b/y a/z + // ... + std::vector< int > d_index_order; + //variables to index they are considered at + // for example, if d_index_order = { 2, 0, 1 } + // then d_var_order = { 0 -> 1, 1 -> 2, 2 -> 0 } + std::map< int, int > d_var_order; + //the instantiation constants of d_f + std::vector< Node > d_ic; + //the current terms we are considering + std::vector< Node > d_terms; +public: + /** set index order */ + void setIndexOrder( std::vector< int >& indexOrder ); + /** set domain */ + void setDomain( std::vector< RepDomain >& domain ); + /** increment the iterator */ + void increment2( int counter ); + void increment(); + /** is the iterator finished? */ + bool isFinished(); + /** produce the match that this iterator represents */ + void getMatch( QuantifiersEngine* qe, InstMatch& m ); + /** get the i_th term we are considering */ + Node getTerm( int i ); + /** get the number of terms we are considering */ + int getNumTerms() { return d_f[0].getNumChildren(); } + /** debug print */ + void debugPrint( const char* c ); + void debugPrintSmall( const char* c ); +}; + +class RepSetEvaluator +{ +private: + FirstOrderModel* d_model; + RepSetIterator* d_riter; +private: //for Theory UF: + //map from terms to the models used to calculate their value + std::map< Node, bool > d_eval_uf_use_default; + std::map< Node, uf::UfModelTreeOrdered > d_eval_uf_model; + void makeEvalUfModel( Node n ); + //index ordering to use for each term + std::map< Node, std::vector< int > > d_eval_term_index_order; + int getMaxVariableNum( int n ); + void makeEvalUfIndexOrder( Node n ); +private: + //default evaluate term function + Node evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex ); + //temporary storing which literals have failed + void clearEvalFailed( int index ); + std::map< Node, bool > d_eval_failed; + std::map< int, std::vector< Node > > d_eval_failed_lits; +public: + RepSetEvaluator( FirstOrderModel* m, RepSetIterator* ri ); + virtual ~RepSetEvaluator(){} + /** evaluate functions */ + int evaluate( Node n, int& depIndex ); + int evaluateEquality( Node n1, Node n2, int& depIndex ); + Node evaluateTerm( Node n, int& depIndex ); +public: + //statistics + int d_eval_formulas; + int d_eval_eqs; + int d_eval_uf_terms; +}; + + +} +} +} + +#endif diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp new file mode 100644 index 000000000..55ea693ef --- /dev/null +++ b/src/theory/quantifiers/term_database.cpp @@ -0,0 +1,324 @@ +/********************* */ +/*! \file term_database.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of term databse class + **/ + + #include "theory/quantifiers/term_database.h" + #include "theory/quantifiers_engine.h" + #include "theory/uf/theory_uf_instantiator.h" + #include "theory/theory_engine.h" + #include "theory/quantifiers/first_order_model.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; + + bool TermArgTrie::addTerm2( QuantifiersEngine* qe, Node n, int argIndex ){ + if( argIndex<(int)n.getNumChildren() ){ + Node r = qe->getEqualityQuery()->getRepresentative( n[ argIndex ] ); + std::map< Node, TermArgTrie >::iterator it = d_data.find( r ); + if( it==d_data.end() ){ + d_data[r].addTerm2( qe, n, argIndex+1 ); + return true; + }else{ + return it->second.addTerm2( qe, n, argIndex+1 ); + } + }else{ + //store n in d_data (this should be interpretted as the "data" and not as a reference to a child) + d_data[n].d_data.clear(); + return false; + } + } + + void TermDb::addTerm( Node n, std::vector< Node >& added, bool withinQuant ){ + //don't add terms in quantifier bodies + if( !withinQuant || Options::current()->registerQuantBodyTerms ){ + if( d_processed.find( n )==d_processed.end() ){ + d_processed[n] = true; + //if this is an atomic trigger, consider adding it + if( Trigger::isAtomicTrigger( n ) ){ + if( !n.hasAttribute(InstConstantAttribute()) ){ + Debug("term-db") << "register trigger term " << n << std::endl; + //Notice() << "register trigger term " << n << std::endl; + Node op = n.getOperator(); + d_op_map[op].push_back( n ); + d_type_map[ n.getType() ].push_back( n ); + added.push_back( n ); + + uf::InstantiatorTheoryUf* d_ith = (uf::InstantiatorTheoryUf*)d_quantEngine->getInstantiator( THEORY_UF ); + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + addTerm( n[i], added, withinQuant ); + if( Options::current()->efficientEMatching ){ + if( d_parents[n[i]][op].empty() ){ + //must add parent to equivalence class info + Node nir = d_ith->getRepresentative( n[i] ); + uf::EqClassInfo* eci_nir = d_ith->getEquivalenceClassInfo( nir ); + if( eci_nir ){ + eci_nir->d_pfuns[ op ] = true; + } + } + //add to parent structure + if( std::find( d_parents[n[i]][op][i].begin(), d_parents[n[i]][op][i].end(), n )==d_parents[n[i]][op][i].end() ){ + d_parents[n[i]][op][i].push_back( n ); + } + } + } + if( Options::current()->efficientEMatching ){ + //new term, add n to candidate generators + for( int i=0; i<(int)d_ith->d_cand_gens[op].size(); i++ ){ + d_ith->d_cand_gens[op][i]->addCandidate( n ); + } + } + if( Options::current()->eagerInstQuant ){ + if( !n.hasAttribute(InstLevelAttribute()) && n.getAttribute(InstLevelAttribute())==0 ){ + int addedLemmas = 0; + for( int i=0; i<(int)d_ith->d_op_triggers[op].size(); i++ ){ + addedLemmas += d_ith->d_op_triggers[op][i]->addTerm( n ); + } + //Message() << "Terms, added lemmas: " << addedLemmas << std::endl; + d_quantEngine->flushLemmas( &d_quantEngine->getTheoryEngine()->getTheory( THEORY_QUANTIFIERS )->getOutputChannel() ); + } + } + } + } + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + addTerm( n[i], added, withinQuant ); + } + } + } + } + + void TermDb::reset( Theory::Effort effort ){ + int nonCongruentCount = 0; + int congruentCount = 0; + int alreadyCongruentCount = 0; + //rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms + for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){ + if( !it->second.empty() ){ + if( it->second[0].getType()==NodeManager::currentNM()->booleanType() ){ + d_pred_map_trie[ 0 ][ it->first ].d_data.clear(); + d_pred_map_trie[ 1 ][ it->first ].d_data.clear(); + }else{ + d_func_map_trie[ it->first ].d_data.clear(); + for( int i=0; i<(int)it->second.size(); i++ ){ + Node n = it->second[i]; + if( !n.getAttribute(NoMatchAttribute()) ){ + if( !d_func_map_trie[ it->first ].addTerm( d_quantEngine, n ) ){ + NoMatchAttribute nma; + n.setAttribute(nma,true); + congruentCount++; + }else{ + nonCongruentCount++; + } + }else{ + congruentCount++; + alreadyCongruentCount++; + } + } + } + } + } + for( int i=0; i<2; i++ ){ + Node n = NodeManager::currentNM()->mkConst( i==1 ); + eq::EqClassIterator eqc( d_quantEngine->getEqualityQuery()->getRepresentative( n ), + ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine() ); + while( !eqc.isFinished() ){ + Node en = (*eqc); + if( en.getKind()==APPLY_UF && !en.hasAttribute(InstConstantAttribute()) ){ + if( !en.getAttribute(NoMatchAttribute()) ){ + Node op = en.getOperator(); + if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){ + NoMatchAttribute nma; + en.setAttribute(nma,true); + congruentCount++; + }else{ + nonCongruentCount++; + } + }else{ + alreadyCongruentCount++; + } + } + ++eqc; + } + } + Debug("term-db-cong") << "TermDb: Reset" << std::endl; + Debug("term-db-cong") << "Congruent/Non-Congruent = "; + Debug("term-db-cong") << congruentCount << "(" << alreadyCongruentCount << ") / " << nonCongruentCount << std::endl; +} + +void TermDb::registerModelBasis( Node n, Node gn ){ + if( d_model_basis.find( n )==d_model_basis.end() ){ + d_model_basis[n] = gn; + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + registerModelBasis( n[i], gn[i] ); + } + } +} + +Node TermDb::getModelBasisTerm( TypeNode tn, int i ){ + if( d_model_basis_term.find( tn )==d_model_basis_term.end() ){ + std::stringstream ss; + ss << Expr::setlanguage(Options::current()->outputLanguage); + ss << "e_" << tn; + d_model_basis_term[tn] = NodeManager::currentNM()->mkVar( ss.str(), tn ); + ModelBasisAttribute mba; + d_model_basis_term[tn].setAttribute(mba,true); + } + return d_model_basis_term[tn]; +} + +Node TermDb::getModelBasisOpTerm( Node op ){ + if( d_model_basis_op_term.find( op )==d_model_basis_op_term.end() ){ + TypeNode t = op.getType(); + std::vector< Node > children; + children.push_back( op ); + for( size_t i=0; imkNode( APPLY_UF, children ); + } + return d_model_basis_op_term[op]; +} + +void TermDb::computeModelBasisArgAttribute( Node n ){ + if( !n.hasAttribute(ModelBasisArgAttribute()) ){ + uint64_t val = 0; + //determine if it has model basis attribute + for( int j=0; j<(int)n.getNumChildren(); j++ ){ + if( n[j].getAttribute(ModelBasisAttribute()) ){ + val = 1; + break; + } + } + ModelBasisArgAttribute mbaa; + n.setAttribute( mbaa, val ); + } +} + +void TermDb::makeInstantiationConstantsFor( Node f ){ + if( d_inst_constants.find( f )==d_inst_constants.end() ){ + Debug("quantifiers-engine") << "Instantiation constants for " << f << " : " << std::endl; + for( int i=0; i<(int)f[0].getNumChildren(); i++ ){ + d_vars[f].push_back( f[0][i] ); + //make instantiation constants + Node ic = NodeManager::currentNM()->mkInstConstant( f[0][i].getType() ); + d_inst_constants_map[ic] = f; + d_inst_constants[ f ].push_back( ic ); + Debug("quantifiers-engine") << " " << ic << std::endl; + //set the var number attribute + InstVarNumAttribute ivna; + ic.setAttribute(ivna,i); + } + } +} + +void TermDb::setInstantiationLevelAttr( Node n, uint64_t level ){ + if( !n.hasAttribute(InstLevelAttribute()) ){ + InstLevelAttribute ila; + n.setAttribute(ila,level); + } + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + setInstantiationLevelAttr( n[i], level ); + } +} + + +void TermDb::setInstantiationConstantAttr( Node n, Node f ){ + if( !n.hasAttribute(InstConstantAttribute()) ){ + bool setAttr = false; + if( n.getKind()==INST_CONSTANT ){ + setAttr = true; + }else{ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + setInstantiationConstantAttr( n[i], f ); + if( n[i].hasAttribute(InstConstantAttribute()) ){ + setAttr = true; + } + } + } + if( setAttr ){ + InstConstantAttribute ica; + n.setAttribute(ica,f); + //also set the no-match attribute + NoMatchAttribute nma; + n.setAttribute(nma,true); + } + } +} + + +Node TermDb::getCounterexampleBody( Node f ){ + std::map< Node, Node >::iterator it = d_counterexample_body.find( f ); + if( it==d_counterexample_body.end() ){ + makeInstantiationConstantsFor( f ); + Node n = getSubstitutedNode( f[1], f ); + d_counterexample_body[ f ] = n; + return n; + }else{ + return it->second; + } +} + +Node TermDb::getSkolemizedBody( Node f ){ + Assert( f.getKind()==FORALL ); + if( d_skolem_body.find( f )==d_skolem_body.end() ){ + std::vector< Node > vars; + for( int i=0; i<(int)f[0].getNumChildren(); i++ ){ + Node skv = NodeManager::currentNM()->mkSkolem( f[0][i].getType() ); + d_skolem_constants[ f ].push_back( skv ); + vars.push_back( f[0][i] ); + } + d_skolem_body[ f ] = f[ 1 ].substitute( vars.begin(), vars.end(), + d_skolem_constants[ f ].begin(), d_skolem_constants[ f ].end() ); + if( f.hasAttribute(InstLevelAttribute()) ){ + setInstantiationLevelAttr( d_skolem_body[ f ], f.getAttribute(InstLevelAttribute()) ); + } + } + return d_skolem_body[ f ]; +} + + +Node TermDb::getSubstitutedNode( Node n, Node f ){ + return convertNodeToPattern(n,f,d_vars[f],d_inst_constants[ f ]); +} + +Node TermDb::convertNodeToPattern( Node n, Node f, const std::vector & vars, + const std::vector & inst_constants){ + Node n2 = n.substitute( vars.begin(), vars.end(), + inst_constants.begin(), + inst_constants.end() ); + setInstantiationConstantAttr( n2, f ); + return n2; +} + +Node TermDb::getFreeVariableForInstConstant( Node n ){ + TypeNode tn = n.getType(); + if( d_free_vars.find( tn )==d_free_vars.end() ){ + //if integer or real, make zero + if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){ + Rational z(0); + d_free_vars[tn] = NodeManager::currentNM()->mkConst( z ); + }else{ + if( d_type_map[ tn ].empty() ){ + d_free_vars[tn] = NodeManager::currentNM()->mkVar( tn ); + }else{ + d_free_vars[tn] = d_type_map[ tn ][ 0 ]; + } + } + } + return d_free_vars[tn]; +} \ No newline at end of file diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h new file mode 100644 index 000000000..5bf3d7900 --- /dev/null +++ b/src/theory/quantifiers/term_database.h @@ -0,0 +1,151 @@ +/**********************/ +/*! \file term_database.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief term database class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__QUANTIFIERS_TERM_DATABASE_H +#define __CVC4__QUANTIFIERS_TERM_DATABASE_H + +#include "theory/theory.h" + +#include + +namespace CVC4 { +namespace theory { + +class QuantifiersEngine; + +namespace quantifiers { + +class TermArgTrie { +private: + bool addTerm2( QuantifiersEngine* qe, Node n, int argIndex ); +public: + /** the data */ + std::map< Node, TermArgTrie > d_data; +public: + bool addTerm( QuantifiersEngine* qe, Node n ) { return addTerm2( qe, n, 0 ); } +};/* class TermArgTrie */ + +class TermDb { + friend class ::CVC4::theory::QuantifiersEngine; +private: + /** reference to the quantifiers engine */ + QuantifiersEngine* d_quantEngine; + /** calculated no match terms */ + bool d_matching_active; + /** terms processed */ + std::map< Node, bool > d_processed; +public: + TermDb( QuantifiersEngine* qe ) : d_quantEngine( qe ), d_matching_active( true ){} + ~TermDb(){} + /** map from APPLY_UF operators to ground terms for that operator */ + std::map< Node, std::vector< Node > > d_op_map; + /** map from APPLY_UF functions to trie */ + std::map< Node, TermArgTrie > d_func_map_trie; + /** map from APPLY_UF predicates to trie */ + std::map< Node, TermArgTrie > d_pred_map_trie[2]; + /** map from type nodes to terms of that type */ + std::map< TypeNode, std::vector< Node > > d_type_map; + /** add a term to the database */ + void addTerm( Node n, std::vector< Node >& added, bool withinQuant = false ); + /** reset (calculate which terms are active) */ + void reset( Theory::Effort effort ); + /** set active */ + void setMatchingActive( bool a ) { d_matching_active = a; } + /** get active */ + bool getMatchingActive() { return d_matching_active; } +public: + /** parent structure (for efficient E-matching): + n -> op -> index -> L + map from node "n" to a list of nodes "L", where each node n' in L + has operator "op", and n'["index"] = n. + for example, d_parents[n][f][1] = { f( t1, n ), f( t2, n ), ... } + */ + std::map< Node, std::map< Node, std::map< int, std::vector< Node > > > > d_parents; +private: + //map from types to model basis terms + std::map< TypeNode, Node > d_model_basis_term; + //map from ops to model basis terms + std::map< Node, Node > d_model_basis_op_term; + //map from instantiation terms to their model basis equivalent + std::map< Node, Node > d_model_basis; +public: + //get model basis term + Node getModelBasisTerm( TypeNode tn, int i = 0 ); + //get model basis term for op + Node getModelBasisOpTerm( Node op ); + // compute model basis arg + void computeModelBasisArgAttribute( Node n ); + //register instantiation terms with their corresponding model basis terms + void registerModelBasis( Node n, Node gn ); + //get model basis + Node getModelBasis( Node n ) { return d_model_basis[n]; } +private: + /** map from universal quantifiers to the list of variables */ + std::map< Node, std::vector< Node > > d_vars; + /** map from universal quantifiers to the list of skolem constants */ + std::map< Node, std::vector< Node > > d_skolem_constants; + /** map from universal quantifiers to their skolemized body */ + std::map< Node, Node > d_skolem_body; + /** instantiation constants to universal quantifiers */ + std::map< Node, Node > d_inst_constants_map; + /** map from universal quantifiers to their counterexample body */ + std::map< Node, Node > d_counterexample_body; + /** free variable for instantiation constant type */ + std::map< TypeNode, Node > d_free_vars; +private: + /** make instantiation constants for */ + void makeInstantiationConstantsFor( Node f ); +public: + /** map from universal quantifiers to the list of instantiation constants */ + std::map< Node, std::vector< Node > > d_inst_constants; + /** set instantiation level attr */ + void setInstantiationLevelAttr( Node n, uint64_t level ); + /** set instantiation constant attr */ + void setInstantiationConstantAttr( Node n, Node f ); + /** get the i^th instantiation constant of f */ + Node getInstantiationConstant( Node f, int i ) { return d_inst_constants[f][i]; } + /** get number of instantiation constants for f */ + int getNumInstantiationConstants( Node f ) { return (int)d_inst_constants[f].size(); } + /** get the ce body f[e/x] */ + Node getCounterexampleBody( Node f ); + /** get the skolemized body f[e/x] */ + Node getSkolemizedBody( Node f ); + /** returns node n with bound vars of f replaced by instantiation constants of f + node n : is the futur pattern + node f : is the quantifier containing which bind the variable + return a pattern where the variable are replaced by variable for + instantiation. + */ + Node getSubstitutedNode( Node n, Node f ); + /** same as before but node f is just linked to the new pattern by the + applied attribute + vars the bind variable + nvars the same variable but with an attribute + */ + Node convertNodeToPattern( Node n, Node f, + const std::vector & vars, + const std::vector & nvars); + /** get free variable for instantiation constant */ + Node getFreeVariableForInstConstant( Node n ); +};/* class TermDb */ + +} +} +} + +#endif diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp index ead47e4b0..27310e21b 100644 --- a/src/theory/quantifiers/theory_quantifiers.cpp +++ b/src/theory/quantifiers/theory_quantifiers.cpp @@ -27,11 +27,7 @@ #include #include #include "theory/quantifiers/theory_quantifiers_instantiator.h" - -#define USE_FLIP_DECISION - -//static bool clockSet = false; -//double initClock; +#include "theory/quantifiers/term_database.h" using namespace std; using namespace CVC4; @@ -45,11 +41,6 @@ TheoryQuantifiers::TheoryQuantifiers(Context* c, context::UserContext* u, Output d_numRestarts(0){ d_numInstantiations = 0; d_baseDecLevel = -1; - if( Options::current()->finiteModelFind ){ - qe->addModule( new ModelEngine( this ) ); - }else{ - qe->addModule( new InstantiationEngine( this ) ); - } } @@ -65,10 +56,10 @@ void TheoryQuantifiers::addSharedTerm(TNode t) { void TheoryQuantifiers::notifyEq(TNode lhs, TNode rhs) { Debug("quantifiers-other") << "TheoryQuantifiers::notifyEq(): " << lhs << " = " << rhs << endl; - + } -void TheoryQuantifiers::preRegisterTerm(TNode n) { +void TheoryQuantifiers::preRegisterTerm(TNode n) { Debug("quantifiers-prereg") << "TheoryQuantifiers::preRegisterTerm() " << n << endl; if( n.getKind()==FORALL && !n.hasAttribute(InstConstantAttribute()) ){ getQuantifiersEngine()->registerQuantifier( n ); @@ -97,6 +88,10 @@ Node TheoryQuantifiers::getValue(TNode n) { } } +void TheoryQuantifiers::collectModelInfo( TheoryModel* m ){ + +} + void TheoryQuantifiers::check(Effort e) { CodeTimer codeTimer(d_theoryTime); @@ -119,7 +114,7 @@ void TheoryQuantifiers::check(Effort e) { break; } } - break; + break; default: Unhandled(assertion.getKind()); break; @@ -147,7 +142,7 @@ void TheoryQuantifiers::assertExistential( Node n ){ Assert( n.getKind()== NOT && n[0].getKind()==FORALL ); if( !n[0].hasAttribute(InstConstantAttribute()) ){ if( d_skolemized.find( n )==d_skolemized.end() ){ - Node body = getQuantifiersEngine()->getSkolemizedBody( n[0] ); + Node body = getQuantifiersEngine()->getTermDatabase()->getSkolemizedBody( n[0] ); NodeBuilder<> nb(kind::OR); nb << n[0] << body.notNode(); Node lem = nb; @@ -159,9 +154,6 @@ void TheoryQuantifiers::assertExistential( Node n ){ } bool TheoryQuantifiers::flipDecision(){ -#ifndef USE_FLIP_DECISION - return false; -#else //Debug("quantifiers-flip") << "No instantiation given, flip decision, level = " << d_valuation.getDecisionLevel() << std::endl; //for( int i=1; i<=(int)d_valuation.getDecisionLevel(); i++ ){ // Debug("quantifiers-flip") << " " << d_valuation.getDecision( i ) << std::endl; @@ -179,7 +171,6 @@ bool TheoryQuantifiers::flipDecision(){ return restart(); } return true; -#endif } bool TheoryQuantifiers::restart(){ diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h index 05c3b9695..517786400 100644 --- a/src/theory/quantifiers/theory_quantifiers.h +++ b/src/theory/quantifiers/theory_quantifiers.h @@ -34,6 +34,8 @@ namespace theory { namespace quantifiers { class TheoryEngine; +class ModelEngine; +class InstantiationEngine; class TheoryQuantifiers : public Theory { private: @@ -59,6 +61,7 @@ public: void check(Effort e); void propagate(Effort level); Node getValue(TNode n); + void collectModelInfo( TheoryModel* m ); void shutdown() { } std::string identify() const { return std::string("TheoryQuantifiers"); } bool flipDecision(); diff --git a/src/theory/quantifiers/theory_quantifiers_instantiator.cpp b/src/theory/quantifiers/theory_quantifiers_instantiator.cpp index a5b6cc3bc..84b6c65c7 100644 --- a/src/theory/quantifiers/theory_quantifiers_instantiator.cpp +++ b/src/theory/quantifiers/theory_quantifiers_instantiator.cpp @@ -48,7 +48,7 @@ void InstantiatorTheoryQuantifiers::processResetInstantiationRound( Theory::Effo } -int InstantiatorTheoryQuantifiers::process( Node f, Theory::Effort effort, int e, int limitInst ){ +int InstantiatorTheoryQuantifiers::process( Node f, Theory::Effort effort, int e ){ Debug("quant-quant") << "Quant: Try to solve (" << e << ") for " << f << "... " << std::endl; if( e<5 ){ return InstStrategy::STATUS_UNFINISHED; diff --git a/src/theory/quantifiers/theory_quantifiers_instantiator.h b/src/theory/quantifiers/theory_quantifiers_instantiator.h index 39e34c319..bf17495a1 100644 --- a/src/theory/quantifiers/theory_quantifiers_instantiator.h +++ b/src/theory/quantifiers/theory_quantifiers_instantiator.h @@ -42,7 +42,7 @@ private: /** reset instantiation */ void processResetInstantiationRound( Theory::Effort effort ); /** process at effort */ - int process( Node f, Theory::Effort effort, int e, int limitInst ); + int process( Node f, Theory::Effort effort, int e ); class Statistics { public: diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp index e8a17eadd..e4e3df9be 100644 --- a/src/theory/quantifiers_engine.cpp +++ b/src/theory/quantifiers_engine.cpp @@ -19,7 +19,13 @@ #include "theory/uf/theory_uf_instantiator.h" #include "theory/uf/theory_uf_strong_solver.h" #include "theory/uf/equality_engine.h" +#include "theory/arrays/theory_arrays.h" +#include "theory/datatypes/theory_datatypes.h" #include "theory/quantifiers/quantifiers_rewriter.h" +#include "theory/quantifiers/model_engine.h" +#include "theory/quantifiers/instantiation_engine.h" +#include "theory/quantifiers/first_order_model.h" +#include "theory/quantifiers/term_database.h" using namespace std; using namespace CVC4; @@ -36,11 +42,12 @@ void InstStrategy::resetInstantiationRound( Theory::Effort effort ){ d_no_instantiate_temp.insert( d_no_instantiate_temp.begin(), d_no_instantiate.begin(), d_no_instantiate.end() ); processResetInstantiationRound( effort ); } + /** do instantiation round method */ -int InstStrategy::doInstantiation( Node f, Theory::Effort effort, int e, int limitInst ){ +int InstStrategy::doInstantiation( Node f, Theory::Effort effort, int e ){ if( shouldInstantiate( f ) ){ int origLemmas = d_quantEngine->getNumLemmasWaiting(); - int retVal = process( f, effort, e, limitInst ); + int retVal = process( f, effort, e ); if( d_quantEngine->getNumLemmasWaiting()!=origLemmas ){ for( int i=0; i<(int)d_priority_over.size(); i++ ){ d_priority_over[i]->d_no_instantiate_temp.push_back( f ); @@ -52,156 +59,61 @@ int InstStrategy::doInstantiation( Node f, Theory::Effort effort, int e, int lim } } -bool TermArgTrie::addTerm2( QuantifiersEngine* qe, Node n, int argIndex ){ - if( argIndex<(int)n.getNumChildren() ){ - Node r = qe->getEqualityQuery()->getRepresentative( n[ argIndex ] ); - std::map< Node, TermArgTrie >::iterator it = d_data.find( r ); - if( it==d_data.end() ){ - d_data[r].addTerm2( qe, n, argIndex+1 ); - return true; - }else{ - return it->second.addTerm2( qe, n, argIndex+1 ); - } +QuantifiersEngine::QuantifiersEngine(context::Context* c, TheoryEngine* te): +d_te( te ), +d_active( c ){ + d_eq_query = new EqualityQueryQuantifiersEngine( this ); + d_term_db = new quantifiers::TermDb( this ); + d_hasAddedLemma = false; + + //the model object + d_model = new quantifiers::FirstOrderModel( this, c, "FirstOrderModel" ); + + //add quantifiers modules + if( !Options::current()->finiteModelFind || Options::current()->fmfInstEngine ){ + //the instantiation must set incomplete flag unless finite model finding is turned on + d_inst_engine = new quantifiers::InstantiationEngine( this, !Options::current()->finiteModelFind ); + d_modules.push_back( d_inst_engine ); }else{ - //store n in d_data (this should be interpretted as the "data" and not as a reference to a child) - d_data[n].d_data.clear(); - return false; + d_inst_engine = NULL; } -} - -void TermDb::addTerm( Node n, std::vector< Node >& added, bool withinQuant ){ - //don't add terms in quantifier bodies - if( !withinQuant || Options::current()->registerQuantBodyTerms ){ - if( d_processed.find( n )==d_processed.end() ){ - d_processed[n] = true; - //if this is an atomic trigger, consider adding it - if( Trigger::isAtomicTrigger( n ) ){ - if( !n.hasAttribute(InstConstantAttribute()) ){ - Debug("term-db") << "register trigger term " << n << std::endl; - //Notice() << "register trigger term " << n << std::endl; - Node op = n.getOperator(); - d_op_map[op].push_back( n ); - d_type_map[ n.getType() ].push_back( n ); - added.push_back( n ); - - uf::InstantiatorTheoryUf* d_ith = (uf::InstantiatorTheoryUf*)d_quantEngine->getInstantiator( THEORY_UF ); - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - addTerm( n[i], added, withinQuant ); - if( Options::current()->efficientEMatching ){ - if( d_parents[n[i]][op].empty() ){ - //must add parent to equivalence class info - Node nir = d_ith->getRepresentative( n[i] ); - uf::EqClassInfo* eci_nir = d_ith->getEquivalenceClassInfo( nir ); - if( eci_nir ){ - eci_nir->d_pfuns[ op ] = true; - } - } - //add to parent structure - if( std::find( d_parents[n[i]][op][i].begin(), d_parents[n[i]][op][i].end(), n )==d_parents[n[i]][op][i].end() ){ - d_parents[n[i]][op][i].push_back( n ); - } - } - } - if( Options::current()->efficientEMatching ){ - //new term, add n to candidate generators - for( int i=0; i<(int)d_ith->d_cand_gens[op].size(); i++ ){ - d_ith->d_cand_gens[op][i]->addCandidate( n ); - } - } - if( Options::current()->eagerInstQuant ){ - if( !n.hasAttribute(InstLevelAttribute()) && n.getAttribute(InstLevelAttribute())==0 ){ - int addedLemmas = 0; - for( int i=0; i<(int)d_ith->d_op_triggers[op].size(); i++ ){ - addedLemmas += d_ith->d_op_triggers[op][i]->addTerm( n ); - } - //Message() << "Terms, added lemmas: " << addedLemmas << std::endl; - d_quantEngine->flushLemmas( &d_quantEngine->getTheoryEngine()->getTheory( THEORY_QUANTIFIERS )->getOutputChannel() ); - } - } - } - } - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - addTerm( n[i], added, withinQuant ); - } - } + if( Options::current()->finiteModelFind ){ + d_model_engine = new quantifiers::ModelEngine( this ); + d_modules.push_back( d_model_engine ); + }else{ + d_model_engine = NULL; } -} -void TermDb::reset( Theory::Effort effort ){ - int nonCongruentCount = 0; - int congruentCount = 0; - int alreadyCongruentCount = 0; - //rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms - for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){ - if( !it->second.empty() ){ - if( it->second[0].getType()==NodeManager::currentNM()->booleanType() ){ - d_pred_map_trie[ 0 ][ it->first ].d_data.clear(); - d_pred_map_trie[ 1 ][ it->first ].d_data.clear(); - }else{ - d_func_map_trie[ it->first ].d_data.clear(); - for( int i=0; i<(int)it->second.size(); i++ ){ - Node n = it->second[i]; - if( !n.getAttribute(NoMatchAttribute()) ){ - if( !d_func_map_trie[ it->first ].addTerm( d_quantEngine, n ) ){ - NoMatchAttribute nma; - n.setAttribute(nma,true); - congruentCount++; - }else{ - nonCongruentCount++; - } - }else{ - congruentCount++; - alreadyCongruentCount++; - } - } - } - } - } - for( int i=0; i<2; i++ ){ - Node n = NodeManager::currentNM()->mkConst( i==1 ); - eq::EqClassIterator eqc( d_quantEngine->getEqualityQuery()->getRepresentative( n ), - ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine() ); - while( !eqc.isFinished() ){ - Node en = (*eqc); - if( en.getKind()==APPLY_UF && !en.hasAttribute(InstConstantAttribute()) ){ - if( !en.getAttribute(NoMatchAttribute()) ){ - Node op = en.getOperator(); - if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){ - NoMatchAttribute nma; - en.setAttribute(nma,true); - congruentCount++; - }else{ - nonCongruentCount++; - } - }else{ - alreadyCongruentCount++; - } - } - ++eqc; - } - } - Debug("term-db-cong") << "TermDb: Reset" << std::endl; - Debug("term-db-cong") << "Congruent/Non-Congruent = "; - Debug("term-db-cong") << congruentCount << "(" << alreadyCongruentCount << ") / " << nonCongruentCount << std::endl; + //options + d_optInstCheckDuplicate = true; + d_optInstMakeRepresentative = true; + d_optInstAddSplits = false; + d_optMatchIgnoreModelBasis = false; + d_optInstLimitActive = false; + d_optInstLimit = 0; } +Instantiator* QuantifiersEngine::getInstantiator( int id ){ + return d_te->getTheory( id )->getInstantiator(); +} - -QuantifiersEngine::QuantifiersEngine(context::Context* c, TheoryEngine* te): -d_te( te ), -d_forall_asserts( c ), -d_active( c ){ - d_eq_query = NULL; - d_term_db = new TermDb( this ); +context::Context* QuantifiersEngine::getSatContext(){ + return d_te->getTheory( THEORY_QUANTIFIERS )->getSatContext(); } -Instantiator* QuantifiersEngine::getInstantiator( int id ){ - return d_te->getTheory( id )->getInstantiator(); +OutputChannel& QuantifiersEngine::getOutputChannel(){ + return d_te->getTheory( THEORY_QUANTIFIERS )->getOutputChannel(); +} +/** get default valuation for the quantifiers engine */ +Valuation& QuantifiersEngine::getValuation(){ + return d_te->getTheory( THEORY_QUANTIFIERS )->getValuation(); } void QuantifiersEngine::check( Theory::Effort e ){ CodeTimer codeTimer(d_time); + d_hasAddedLemma = false; + d_model_set = false; if( e==Theory::EFFORT_LAST_CALL ){ ++(d_statistics.d_instantiation_rounds_lc); }else if( e==Theory::EFFORT_FULL ){ @@ -210,9 +122,11 @@ void QuantifiersEngine::check( Theory::Effort e ){ for( int i=0; i<(int)d_modules.size(); i++ ){ d_modules[i]->check( e ); } - //if( e==Theory::EFFORT_FULL ){ - // Notice() << "Done instantiation Round" << std::endl; - //} + //build the model if not done so already + // this happens if no quantifiers are currently asserted and no model-building module is enabled + if( Options::current()->produceModels && e==Theory::EFFORT_LAST_CALL && !d_hasAddedLemma && !d_model_set ){ + d_te->getModelBuilder()->buildModel( d_model ); + } } std::vector QuantifiersEngine::createInstVariable( std::vector & vars ){ @@ -227,25 +141,9 @@ std::vector QuantifiersEngine::createInstVariable( std::vector & var return inst_constant; } -void QuantifiersEngine::makeInstantiationConstantsFor( Node f ){ - if( d_inst_constants.find( f )==d_inst_constants.end() ){ - Debug("quantifiers-engine") << "Instantiation constants for " << f << " : " << std::endl; - for( int i=0; i<(int)f[0].getNumChildren(); i++ ){ - d_vars[f].push_back( f[0][i] ); - //make instantiation constants - Node ic = NodeManager::currentNM()->mkInstConstant( f[0][i].getType() ); - d_inst_constants_map[ic] = f; - d_inst_constants[ f ].push_back( ic ); - Debug("quantifiers-engine") << " " << ic << std::endl; - //set the var number attribute - InstVarNumAttribute ivna; - ic.setAttribute(ivna,i); - } - } -} - void QuantifiersEngine::registerQuantifier( Node f ){ if( std::find( d_quants.begin(), d_quants.end(), f )==d_quants.end() ){ + d_quants.push_back( f ); std::vector< Node > quants; #ifdef REWRITE_ASSERTED_QUANTIFIERS //do assertion-time rewriting of quantifier @@ -277,9 +175,9 @@ void QuantifiersEngine::registerQuantifier( Node f ){ ++(d_statistics.d_num_quant); Assert( quants[q].getKind()==FORALL ); //register quantifier - d_quants.push_back( quants[q] ); + d_r_quants.push_back( quants[q] ); //make instantiation constants for quants[q] - makeInstantiationConstantsFor( quants[q] ); + d_term_db->makeInstantiationConstantsFor( quants[q] ); //compute symbols in quants[q] std::vector< Node > syms; computeSymbols( quants[q][1], syms ); @@ -302,7 +200,7 @@ void QuantifiersEngine::registerQuantifier( Node f ){ for( int i=0; i<(int)d_modules.size(); i++ ){ d_modules[i]->registerQuantifier( quants[q] ); } - Node ceBody = getCounterexampleBody( quants[q] ); + Node ceBody = d_term_db->getCounterexampleBody( quants[q] ); generatePhaseReqs( quants[q], ceBody ); //also register it with the strong solver if( Options::current()->finiteModelFind ){ @@ -315,14 +213,14 @@ void QuantifiersEngine::registerQuantifier( Node f ){ void QuantifiersEngine::registerPattern( std::vector & pattern) { for(std::vector::iterator p = pattern.begin(); p != pattern.end(); ++p){ std::vector< Node > added; - d_term_db->addTerm(*p,added); + getTermDatabase()->addTerm(*p,added); } } void QuantifiersEngine::assertNode( Node f ){ Assert( f.getKind()==FORALL ); for( int j=0; j<(int)d_quant_rewritten[f].size(); j++ ){ - d_forall_asserts.push_back( d_quant_rewritten[f][j] ); + d_model->d_forall_asserts.push_back( d_quant_rewritten[f][j] ); for( int i=0; i<(int)d_modules.size(); i++ ){ d_modules[i]->assertNode( d_quant_rewritten[f][j] ); } @@ -337,20 +235,26 @@ void QuantifiersEngine::propagate( Theory::Effort level ){ } } +void QuantifiersEngine::resetInstantiationRound( Theory::Effort level ){ + for( int i=0; iresetInstantiationRound( level ); + } + } + getTermDatabase()->reset( level ); +} + void QuantifiersEngine::addTermToDatabase( Node n, bool withinQuant ){ - if( d_term_db ){ - std::vector< Node > added; - d_term_db->addTerm( n, added, withinQuant ); + std::vector< Node > added; + getTermDatabase()->addTerm( n, added, withinQuant ); #ifdef COMPUTE_RELEVANCE - for( int i=0; i<(int)added.size(); i++ ){ - if( !withinQuant ){ - setRelevance( added[i].getOperator(), 0 ); - } + for( int i=0; i<(int)added.size(); i++ ){ + if( !withinQuant ){ + setRelevance( added[i].getOperator(), 0 ); } -#endif - }else{ - Notice() << "Warning: no term database for quantifier engine." << std::endl; } +#endif + } bool QuantifiersEngine::addLemma( Node lem ){ @@ -377,8 +281,8 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms ) //} Assert( f.getKind()==FORALL ); Assert( !f.hasAttribute(InstConstantAttribute()) ); - Assert( d_vars[f].size()==terms.size() && d_vars[f].size()==f[0].getNumChildren() ); - Node body = f[ 1 ].substitute( d_vars[f].begin(), d_vars[f].end(), + Assert( d_term_db->d_vars[f].size()==terms.size() && d_term_db->d_vars[f].size()==f[0].getNumChildren() ); + Node body = f[ 1 ].substitute( d_term_db->d_vars[f].begin(), d_term_db->d_vars[f].end(), terms.begin(), terms.end() ); NodeBuilder<> nb(kind::OR); nb << d_rewritten_quant[f].notNode() << body; @@ -411,11 +315,11 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms ) maxInstLevel = terms[i].getAttribute(InstLevelAttribute()); } }else{ - setInstantiationLevelAttr( terms[i], 0 ); + d_term_db->setInstantiationLevelAttr( terms[i], 0 ); } } } - setInstantiationLevelAttr( body, maxInstLevel+1 ); + d_term_db->setInstantiationLevelAttr( body, maxInstLevel+1 ); ++(d_statistics.d_instantiations); d_statistics.d_total_inst_var += (int)terms.size(); d_statistics.d_max_instantiation_level.maxAssign( maxInstLevel+1 ); @@ -426,7 +330,7 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms ) } } -bool QuantifiersEngine::addInstantiation( Node f, InstMatch& m, bool addSplits ){ +bool QuantifiersEngine::addInstantiation( Node f, InstMatch& m ){ m.makeComplete( f, this ); m.makeRepresentative( this ); Debug("quant-duplicate") << "After make rep: " << m << std::endl; @@ -437,7 +341,7 @@ bool QuantifiersEngine::addInstantiation( Node f, InstMatch& m, bool addSplits ) } Debug("quant-duplicate") << " -> Does not exist." << std::endl; std::vector< Node > match; - m.computeTermVec( d_inst_constants[f], match ); + m.computeTermVec( d_term_db->d_inst_constants[f], match ); //old.... //m.makeRepresentative( d_eq_query ); @@ -494,40 +398,16 @@ bool QuantifiersEngine::addSplitEquality( Node n1, Node n2, bool reqPhase, bool } void QuantifiersEngine::flushLemmas( OutputChannel* out ){ - for( int i=0; i<(int)d_lemmas_waiting.size(); i++ ){ - out->lemma( d_lemmas_waiting[i] ); - } - d_lemmas_waiting.clear(); -} - -Node QuantifiersEngine::getCounterexampleBody( Node f ){ - std::map< Node, Node >::iterator it = d_counterexample_body.find( f ); - if( it==d_counterexample_body.end() ){ - makeInstantiationConstantsFor( f ); - Node n = getSubstitutedNode( f[1], f ); - d_counterexample_body[ f ] = n; - return n; - }else{ - return it->second; - } -} - -Node QuantifiersEngine::getSkolemizedBody( Node f ){ - Assert( f.getKind()==FORALL ); - if( d_skolem_body.find( f )==d_skolem_body.end() ){ - std::vector< Node > vars; - for( int i=0; i<(int)f[0].getNumChildren(); i++ ){ - Node skv = NodeManager::currentNM()->mkSkolem( f[0][i].getType() ); - d_skolem_constants[ f ].push_back( skv ); - vars.push_back( f[0][i] ); - } - d_skolem_body[ f ] = f[ 1 ].substitute( vars.begin(), vars.end(), - d_skolem_constants[ f ].begin(), d_skolem_constants[ f ].end() ); - if( f.hasAttribute(InstLevelAttribute()) ){ - setInstantiationLevelAttr( d_skolem_body[ f ], f.getAttribute(InstLevelAttribute()) ); + if( !d_lemmas_waiting.empty() ){ + //take default output channel if none is provided + d_hasAddedLemma = true; + for( int i=0; i<(int)d_lemmas_waiting.size(); i++ ){ + if( out ){ + out->lemma( d_lemmas_waiting[i] ); + } } + d_lemmas_waiting.clear(); } - return d_skolem_body[ f ]; } void QuantifiersEngine::getPhaseReqTerms( Node f, std::vector< Node >& nodes ){ @@ -553,7 +433,7 @@ void QuantifiersEngine::getPhaseReqTerms( Node f, std::vector< Node >& nodes ){ } Debug("literal-matching") << " Make " << prev << " -> " << nodes[i] << std::endl; Assert( prev.hasAttribute(InstConstantAttribute()) ); - setInstantiationConstantAttr( nodes[i], prev.getAttribute(InstConstantAttribute()) ); + d_term_db->setInstantiationConstantAttr( nodes[i], prev.getAttribute(InstConstantAttribute()) ); ++(d_statistics.d_lit_phase_req); }else{ ++(d_statistics.d_lit_phase_nreq); @@ -634,54 +514,6 @@ void QuantifiersEngine::generatePhaseReqs( Node f, Node n ){ } -Node QuantifiersEngine::getSubstitutedNode( Node n, Node f ){ - return convertNodeToPattern(n,f,d_vars[f],d_inst_constants[ f ]); -} - -Node QuantifiersEngine::convertNodeToPattern( Node n, Node f, const std::vector & vars, - const std::vector & inst_constants){ - Node n2 = n.substitute( vars.begin(), vars.end(), - inst_constants.begin(), - inst_constants.end() ); - setInstantiationConstantAttr( n2, f ); - return n2; -} - - -void QuantifiersEngine::setInstantiationLevelAttr( Node n, uint64_t level ){ - if( !n.hasAttribute(InstLevelAttribute()) ){ - InstLevelAttribute ila; - n.setAttribute(ila,level); - } - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - setInstantiationLevelAttr( n[i], level ); - } -} - - -void QuantifiersEngine::setInstantiationConstantAttr( Node n, Node f ){ - if( !n.hasAttribute(InstConstantAttribute()) ){ - bool setAttr = false; - if( n.getKind()==INST_CONSTANT ){ - setAttr = true; - }else{ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - setInstantiationConstantAttr( n[i], f ); - if( n[i].hasAttribute(InstConstantAttribute()) ){ - setAttr = true; - } - } - } - if( setAttr ){ - InstConstantAttribute ica; - n.setAttribute(ica,f); - //also set the no-match attribute - NoMatchAttribute nma; - n.setAttribute(nma,true); - } - } -} - QuantifiersEngine::Statistics::Statistics(): d_num_quant("QuantifiersEngine::Num_Quantifiers", 0), d_instantiation_rounds("QuantifiersEngine::Rounds_Instantiation_Full", 0), @@ -737,24 +569,6 @@ QuantifiersEngine::Statistics::~Statistics(){ StatisticsRegistry::unregisterStat(&d_multi_trigger_instantiations); } -Node QuantifiersEngine::getFreeVariableForInstConstant( Node n ){ - TypeNode tn = n.getType(); - if( d_free_vars.find( tn )==d_free_vars.end() ){ - //if integer or real, make zero - if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){ - Rational z(0); - d_free_vars[tn] = NodeManager::currentNM()->mkConst( z ); - }else{ - if( d_term_db->d_type_map[ tn ].empty() ){ - d_free_vars[tn] = NodeManager::currentNM()->mkVar( tn ); - }else{ - d_free_vars[tn] =d_term_db->d_type_map[ tn ][ 0 ]; - } - } - } - return d_free_vars[tn]; -} - /** compute symbols */ void QuantifiersEngine::computeSymbols( Node n, std::vector< Node >& syms ){ if( n.getKind()==APPLY_UF ){ @@ -786,3 +600,87 @@ void QuantifiersEngine::setRelevance( Node s, int r ){ } } } + + + +bool EqualityQueryQuantifiersEngine::hasTerm( Node a ){ + eq::EqualityEngine* ee = d_qe->getTheoryEngine()->getSharedTermsDatabase()->getEqualityEngine(); + if( ee->hasTerm( a ) ){ + return true; + } + for( int i=0; igetInstantiator( i ) ){ + if( d_qe->getInstantiator( i )->hasTerm( a ) ){ + return true; + } + } + } + return false; +} + +Node EqualityQueryQuantifiersEngine::getRepresentative( Node a ){ + eq::EqualityEngine* ee = d_qe->getTheoryEngine()->getSharedTermsDatabase()->getEqualityEngine(); + if( ee->hasTerm( a ) ){ + return ee->getRepresentative( a ); + } + for( int i=0; igetInstantiator( i ) ){ + if( d_qe->getInstantiator( i )->hasTerm( a ) ){ + return d_qe->getInstantiator( i )->getRepresentative( a ); + } + } + } + return a; +} + +bool EqualityQueryQuantifiersEngine::areEqual( Node a, Node b ){ + if( a==b ){ + return true; + }else{ + eq::EqualityEngine* ee = d_qe->getTheoryEngine()->getSharedTermsDatabase()->getEqualityEngine(); + if( ee->hasTerm( a ) && ee->hasTerm( b ) ){ + if( ee->areEqual( a, b ) ){ + return true; + } + } + for( int i=0; igetInstantiator( i ) ){ + if( d_qe->getInstantiator( i )->areEqual( a, b ) ){ + return true; + } + } + } + //std::cout << "Equal = " << eq_sh << " " << eq_uf << " " << eq_a << " " << eq_dt << std::endl; + return false; + } +} + +bool EqualityQueryQuantifiersEngine::areDisequal( Node a, Node b ){ + eq::EqualityEngine* ee = d_qe->getTheoryEngine()->getSharedTermsDatabase()->getEqualityEngine(); + if( ee->hasTerm( a ) && ee->hasTerm( b ) ){ + if( ee->areDisequal( a, b, false ) ){ + return true; + } + } + for( int i=0; igetInstantiator( i ) ){ + if( d_qe->getInstantiator( i )->areDisequal( a, b ) ){ + return true; + } + } + } + return false; + //std::cout << "Disequal = " << deq_sh << " " << deq_uf << " " << deq_a << " " << deq_dt << std::endl; +} + +Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a ){ + //for( int i=0; igetInstantiator( i ) ){ + // if( d_qe->getInstantiator( i )->hasTerm( a ) ){ + // return d_qe->getInstantiator( i )->getInternalRepresentative( a ); + // } + // } + //} + //return a; + return d_qe->getInstantiator( THEORY_UF )->getInternalRepresentative( a ); +} diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h index d0c5fb00b..5477214b0 100644 --- a/src/theory/quantifiers_engine.h +++ b/src/theory/quantifiers_engine.h @@ -66,7 +66,7 @@ protected: /** reset instantiation */ virtual void processResetInstantiationRound( Theory::Effort effort ) = 0; /** process method */ - virtual int process( Node f, Theory::Effort effort, int e, int limitInst = 0 ) = 0; + virtual int process( Node f, Theory::Effort effort, int e ) = 0; public: InstStrategy( QuantifiersEngine* ie ) : d_quantEngine( ie ){} virtual ~InstStrategy(){} @@ -74,7 +74,7 @@ public: /** reset instantiation */ void resetInstantiationRound( Theory::Effort effort ); /** do instantiation round method */ - int doInstantiation( Node f, Theory::Effort effort, int e, int limitInst = 0 ); + int doInstantiation( Node f, Theory::Effort effort, int e ); /** update status */ static void updateStatus( int& currStatus, int addStatus ){ if( addStatus==STATUS_UNFINISHED ){ @@ -99,9 +99,13 @@ public: };/* class InstStrategy */ class QuantifiersModule { +protected: + QuantifiersEngine* d_quantEngine; public: - QuantifiersModule(){} + QuantifiersModule( QuantifiersEngine* qe ) : d_quantEngine( qe ){} ~QuantifiersModule(){} + //get quantifiers engine + QuantifiersEngine* getQuantifiersEngine() { return d_quantEngine; } /* Call during check registerQuantifier has already been called */ virtual void check( Theory::Effort e ) = 0; /* Called for new quantifiers */ @@ -111,59 +115,17 @@ public: virtual Node explain(TNode n) = 0; };/* class QuantifiersModule */ -class TermArgTrie { -private: - bool addTerm2( QuantifiersEngine* qe, Node n, int argIndex ); -public: - /** the data */ - std::map< Node, TermArgTrie > d_data; -public: - bool addTerm( QuantifiersEngine* qe, Node n ) { return addTerm2( qe, n, 0 ); } -};/* class TermArgTrie */ - -class TermDb { -private: - /** reference to the quantifiers engine */ - QuantifiersEngine* d_quantEngine; - /** calculated no match terms */ - bool d_matching_active; - /** terms processed */ - std::map< Node, bool > d_processed; -public: - TermDb( QuantifiersEngine* qe ) : d_quantEngine( qe ), d_matching_active( true ){} - ~TermDb(){} - /** map from APPLY_UF operators to ground terms for that operator */ - std::map< Node, std::vector< Node > > d_op_map; - /** map from APPLY_UF functions to trie */ - std::map< Node, TermArgTrie > d_func_map_trie; - /** map from APPLY_UF predicates to trie */ - std::map< Node, TermArgTrie > d_pred_map_trie[2]; - /** map from type nodes to terms of that type */ - std::map< TypeNode, std::vector< Node > > d_type_map; - /** add a term to the database */ - void addTerm( Node n, std::vector< Node >& added, bool withinQuant = false ); - /** reset (calculate which terms are active) */ - void reset( Theory::Effort effort ); - /** set active */ - void setMatchingActive( bool a ) { d_matching_active = a; } - /** get active */ - bool getMatchingActive() { return d_matching_active; } -public: - /** parent structure (for efficient E-matching): - n -> op -> index -> L - map from node "n" to a list of nodes "L", where each node n' in L - has operator "op", and n'["index"] = n. - for example, d_parents[n][f][1] = { f( t1, n ), f( t2, n ), ... } - */ - std::map< Node, std::map< Node, std::map< int, std::vector< Node > > > > d_parents; -};/* class TermDb */ - namespace quantifiers { class InstantiationEngine; + class ModelEngine; + class TermDb; + class FirstOrderModel; }/* CVC4::theory::quantifiers */ + class QuantifiersEngine { friend class quantifiers::InstantiationEngine; + friend class quantifiers::ModelEngine; friend class InstMatch; private: typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap; @@ -171,41 +133,35 @@ private: TheoryEngine* d_te; /** vector of modules for quantifiers */ std::vector< QuantifiersModule* > d_modules; + /** instantiation engine */ + quantifiers::InstantiationEngine* d_inst_engine; + /** model engine */ + quantifiers::ModelEngine* d_model_engine; /** equality query class */ EqualityQuery* d_eq_query; - /** list of all quantifiers */ + /** list of all quantifiers (pre-rewrite) */ std::vector< Node > d_quants; - /** list of quantifiers asserted in the current context */ - context::CDList d_forall_asserts; - /** map from universal quantifiers to the list of variables */ - std::map< Node, std::vector< Node > > d_vars; - /** map from universal quantifiers to the list of skolem constants */ - std::map< Node, std::vector< Node > > d_skolem_constants; - /** map from universal quantifiers to their skolemized body */ - std::map< Node, Node > d_skolem_body; - /** map from universal quantifiers to their bound body */ - std::map< Node, Node > d_bound_body; - /** instantiation constants to universal quantifiers */ - std::map< Node, Node > d_inst_constants_map; - /** map from universal quantifiers to their counterexample body */ - std::map< Node, Node > d_counterexample_body; - /** map from universal quantifiers to the list of instantiation constants */ - std::map< Node, std::vector< Node > > d_inst_constants; + /** list of all quantifiers (post-rewrite) */ + std::vector< Node > d_r_quants; /** map from quantifiers to whether they are active */ BoolMap d_active; /** lemmas produced */ std::map< Node, bool > d_lemmas_produced; /** lemmas waiting */ std::vector< Node > d_lemmas_waiting; + /** has added lemma this round */ + bool d_hasAddedLemma; /** inst matches produced for each quantifier */ std::map< Node, InstMatchTrie > d_inst_match_trie; - /** free variable for instantiation constant type */ - std::map< TypeNode, Node > d_free_vars; /** owner of quantifiers */ std::map< Node, Theory* > d_owner; /** term database */ - TermDb* d_term_db; + quantifiers::TermDb* d_term_db; + /** extended model object */ + quantifiers::FirstOrderModel* d_model; + /** has the model been set? */ + bool d_model_set; /** universal quantifiers that have been rewritten */ std::map< Node, std::vector< Node > > d_quant_rewritten; /** map from rewritten universal quantifiers to the quantifier they are the consequence of */ @@ -223,12 +179,6 @@ private: private: /** helper functions compute phase requirements */ static void computePhaseReqs2( Node n, bool polarity, std::map< Node, int >& phaseReqs ); - /** set instantiation level attr */ - void setInstantiationLevelAttr( Node n, uint64_t level ); - /** set instantiation constant attr */ - void setInstantiationConstantAttr( Node n, Node f ); - /** make instantiation constants for */ - void makeInstantiationConstantsFor( Node f ); KEEP_STATISTIC(TimerStat, d_time, "theory::QuantifiersEngine::time"); @@ -241,11 +191,17 @@ public: TheoryEngine* getTheoryEngine() { return d_te; } /** get equality query object */ EqualityQuery* getEqualityQuery() { return d_eq_query; } - /** set equality query object */ - void setEqualityQuery( EqualityQuery* eq ) { d_eq_query = eq; } + /** get instantiation engine */ + quantifiers::InstantiationEngine* getInstantiationEngine() { return d_inst_engine; } + /** get model engine */ + quantifiers::ModelEngine* getModelEngine() { return d_model_engine; } + /** get default sat context for quantifiers engine */ + context::Context* getSatContext(); + /** get default output channel for the quantifiers engine */ + OutputChannel& getOutputChannel(); + /** get default valuation for the quantifiers engine */ + Valuation& getValuation(); public: - /** add module */ - void addModule( QuantifiersModule* qm ) { d_modules.push_back( qm ); } /** check at level */ void check( Theory::Effort e ); /** register (non-rewritten) quantifier */ @@ -256,19 +212,24 @@ public: void assertNode( Node f ); /** propagate */ void propagate( Theory::Effort level ); + /** reset instantiation round */ + void resetInstantiationRound( Theory::Effort level ); + + //create inst variable + std::vector createInstVariable( std::vector & vars ); public: /** add lemma lem */ bool addLemma( Node lem ); /** instantiate f with arguments terms */ bool addInstantiation( Node f, std::vector< Node >& terms ); /** do instantiation specified by m */ - bool addInstantiation( Node f, InstMatch& m, bool addSplits = false ); + bool addInstantiation( Node f, InstMatch& m ); /** split on node n */ bool addSplit( Node n, bool reqPhase = false, bool reqPhasePol = true ); /** add split equality */ bool addSplitEquality( Node n1, Node n2, bool reqPhase = false, bool reqPhasePol = true ); /** has added lemma */ - bool hasAddedLemma() { return !d_lemmas_waiting.empty(); } + bool hasAddedLemma() { return !d_lemmas_waiting.empty() || d_hasAddedLemma; } /** flush lemmas */ void flushLemmas( OutputChannel* out ); /** get number of waiting lemmas */ @@ -278,24 +239,6 @@ public: int getNumQuantifiers() { return (int)d_quants.size(); } /** get quantifier */ Node getQuantifier( int i ) { return d_quants[i]; } - /** get number of asserted quantifiers */ - int getNumAssertedQuantifiers() { return (int)d_forall_asserts.size(); } - /** get asserted quantifier */ - Node getAssertedQuantifier( int i ) { return d_forall_asserts[i]; } - /** get instantiation constants */ - void getInstantiationConstantsFor( Node f, std::vector< Node >& ics ) { - ics.insert( ics.begin(), d_inst_constants[f].begin(), d_inst_constants[f].end() ); - } - /** get the i^th instantiation constant of f */ - Node getInstantiationConstant( Node f, int i ) { return d_inst_constants[f][i]; } - /** get number of instantiation constants for f */ - int getNumInstantiationConstants( Node f ) { return (int)d_inst_constants[f].size(); } - std::vector createInstVariable( std::vector & vars ); -public: - /** get the ce body f[e/x] */ - Node getCounterexampleBody( Node f ); - /** get the skolemized body f[e/x] */ - Node getSkolemizedBody( Node f ); /** set active */ void setActive( Node n, bool val ) { d_active[n] = val; } /** get active */ @@ -316,26 +259,6 @@ public: static void computePhaseReqs( Node n, bool polarity, std::map< Node, bool >& phaseReqs ); /** compute phase requirements */ void generatePhaseReqs( Node f, Node n ); -public: - /** returns node n with bound vars of f replaced by instantiation constants of f - node n : is the futur pattern - node f : is the quantifier containing which bind the variable - return a pattern where the variable are replaced by variable for - instantiation. - */ - Node getSubstitutedNode( Node n, Node f ); - /** same as before but node f is just linked to the new pattern by the - applied attribute - vars the bind variable - nvars the same variable but with an attribute - */ - Node convertNodeToPattern( Node n, Node f, - const std::vector & vars, - const std::vector & nvars); - /** get free variable for instantiation constant */ - Node getFreeVariableForInstConstant( Node n ); - /** get bound variable for variable */ - Node getBoundVariableForVariable( Node n ); public: /** has owner */ bool hasOwner( Node f ) { return d_owner.find( f )!=d_owner.end(); } @@ -344,8 +267,10 @@ public: /** set owner */ void setOwner( Node f, Theory* t ) { d_owner[f] = t; } public: + /** get model */ + quantifiers::FirstOrderModel* getModel() { return d_model; } /** get term database */ - TermDb* getTermDatabase() { return d_term_db; } + quantifiers::TermDb* getTermDatabase() { return d_term_db; } /** add term to database */ void addTermToDatabase( Node n, bool withinQuant = false ); private: @@ -380,8 +305,35 @@ public: ~Statistics(); };/* class QuantifiersEngine::Statistics */ Statistics d_statistics; +public: + /** options */ + bool d_optInstCheckDuplicate; + bool d_optInstMakeRepresentative; + bool d_optInstAddSplits; + bool d_optMatchIgnoreModelBasis; + bool d_optInstLimitActive; + int d_optInstLimit; };/* class QuantifiersEngine */ + + +/** equality query object using theory engine */ +class EqualityQueryQuantifiersEngine : public EqualityQuery +{ +private: + /** pointer to theory engine */ + QuantifiersEngine* d_qe; +public: + EqualityQueryQuantifiersEngine( QuantifiersEngine* qe ) : d_qe( qe ){} + ~EqualityQueryQuantifiersEngine(){} + /** general queries about equality */ + bool hasTerm( Node a ); + Node getRepresentative( Node a ); + bool areEqual( Node a, Node b ); + bool areDisequal( Node a, Node b ); + Node getInternalRepresentative( Node a ); +}; /* EqualityQueryQuantifiersEngine */ + }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/theory/rewriterules/theory_rewriterules.cpp b/src/theory/rewriterules/theory_rewriterules.cpp index 0d7f5005a..265026b39 100644 --- a/src/theory/rewriterules/theory_rewriterules.cpp +++ b/src/theory/rewriterules/theory_rewriterules.cpp @@ -317,13 +317,14 @@ Answer TheoryRewriteRules::addWatchIfDontKnow(Node g0, const RuleInst* ri, const size_t gid){ /** TODO: Should use the representative of g, but should I keep the mapping for myself? */ - /* If it false in one model (current valuation) it's false for all */ - if (useCurrentModel){ - Node val = getValuation().getValue(g0); - Debug("rewriterules") << "getValue:" << g0 << " = " - << val << " is " << (val == d_false) << std::endl; - if (val == d_false) return AFALSE; - }; + //AJR: removed this code after talking with Francois + ///* If it false in one model (current valuation) it's false for all */ + //if (useCurrentModel){ + // Node val = getValuation().getValue(g0); + // Debug("rewriterules") << "getValue:" << g0 << " = " + // << val << " is " << (val == d_false) << std::endl; + // if (val == d_false) return AFALSE; + //}; /** Currently create a node with a literal */ Node g = getValuation().ensureLiteral(g0); GuardedMap::iterator l_i = d_guardeds.find(g); @@ -508,6 +509,10 @@ Node TheoryRewriteRules::explain(TNode n){ return substGuards(&i, TCache ()); } +void TheoryRewriteRules::collectModelInfo( TheoryModel* m ){ + +} + Theory::PPAssertStatus TheoryRewriteRules::ppAssert(TNode in, SubstitutionMap& outSubstitutions) { addRewriteRule(in); return PP_ASSERT_STATUS_UNSOLVED; diff --git a/src/theory/rewriterules/theory_rewriterules.h b/src/theory/rewriterules/theory_rewriterules.h index e47fd2fd4..d1c3eecf3 100644 --- a/src/theory/rewriterules/theory_rewriterules.h +++ b/src/theory/rewriterules/theory_rewriterules.h @@ -30,6 +30,7 @@ #include "theory/inst_match_impl.h" #include "util/stats.h" #include "theory/rewriterules/theory_rewriterules_preprocess.h" +#include "theory/model.h" namespace CVC4 { namespace theory { @@ -182,6 +183,7 @@ private: inside check */ typedef std::vector< RuleInst* > QRuleInsts; QRuleInsts d_ruleinsts_to_add; + public: /** true and false for predicate */ Node d_true; @@ -199,6 +201,7 @@ private: /** Usual function for theories */ void check(Theory::Effort e); Node explain(TNode n); + void collectModelInfo( TheoryModel* m ); void notifyEq(TNode lhs, TNode rhs); std::string identify() const { return "THEORY_REWRITERULES"; diff --git a/src/theory/rewriterules/theory_rewriterules_rules.cpp b/src/theory/rewriterules/theory_rewriterules_rules.cpp index d66fc78cb..c3116aba0 100644 --- a/src/theory/rewriterules/theory_rewriterules_rules.cpp +++ b/src/theory/rewriterules/theory_rewriterules_rules.cpp @@ -22,6 +22,8 @@ #include "theory/rewriterules/theory_rewriterules_preprocess.h" #include "theory/rewriterules/theory_rewriterules.h" +#include "theory/quantifiers/term_database.h" + using namespace std; using namespace CVC4; using namespace CVC4::kind; @@ -72,7 +74,7 @@ inline void addPattern(TheoryRewriteRules & re, TNode r){ if (tri.getKind() == kind::NOT && tri[0].getKind() == kind::APPLY_UF) tri = tri[0]; - pattern.push_back(re.getQuantifiersEngine()-> + pattern.push_back(re.getQuantifiersEngine()->getTermDatabase()-> convertNodeToPattern(tri,r,vars,inst_constants)); } diff --git a/src/theory/shared_terms_database.h b/src/theory/shared_terms_database.h index fb972b73f..7b6527517 100644 --- a/src/theory/shared_terms_database.h +++ b/src/theory/shared_terms_database.h @@ -123,14 +123,14 @@ private: bool propagateEquality(TNode equality, bool polarity); /** Theory engine */ - TheoryEngine* d_theoryEngine; + TheoryEngine* d_theoryEngine; /** Are we in conflict */ context::CDO d_inConflict; - + /** Conflicting terms, if any */ Node d_conflictLHS, d_conflictRHS; - + /** Polarity of the conflict */ bool d_conflictPolarity; @@ -166,7 +166,7 @@ public: */ bool isKnown(TNode literal) const; - /** + /** * Returns an explanation of the propagation that came from the database. */ Node explain(TNode literal) const; @@ -175,10 +175,10 @@ public: * Add an equality to propagate. */ void addEqualityToPropagate(TNode equality); - + /** - * Add a shared term to the database. The shared term is a subterm of the atom and - * should be associated with the given theory. + * Add a shared term to the database. The shared term is a subterm of the atom and + * should be associated with the given theory. */ void addSharedTerm(TNode atom, TNode term, theory::Theory::Set theories); @@ -211,7 +211,7 @@ public: * Get the theories that share the term and have been notified already. */ theory::Theory::Set getNotifiedTheories(TNode term) const; - + /** * Returns true if the term is currently registered as shared with some theory. */ @@ -238,6 +238,10 @@ public: */ bool areDisequal(TNode a, TNode b) const; + /** + * get equality engine + */ + theory::eq::EqualityEngine* getEqualityEngine() { return &d_equalityEngine; } protected: /** diff --git a/src/theory/theory.cpp b/src/theory/theory.cpp index 1dd0a1209..1301da653 100644 --- a/src/theory/theory.cpp +++ b/src/theory/theory.cpp @@ -78,21 +78,21 @@ TheoryId Theory::theoryOf(TheoryOfMode mode, TNode node) { break; case THEORY_OF_TERM_BASED: // Variables - if (node.getMetaKind() == kind::metakind::VARIABLE) { - if (theoryOf(node.getType()) != theory::THEORY_BOOL) { + if (node.getMetaKind() == kind::metakind::VARIABLE) { + if (theoryOf(node.getType()) != theory::THEORY_BOOL) { // We treat the varibables as uninterpreted return s_uninterpretedSortOwner; } else { // Except for the Boolean ones, which we just ignore anyhow return theory::THEORY_BOOL; } - } + } // Constants if (node.getMetaKind() == kind::metakind::CONSTANT) { - // Constants go to the theory of the type + // Constants go to the theory of the type return theoryOf(node.getType()); - } - // Equality + } + // Equality if (node.getKind() == kind::EQUAL) { // If one of them is an ITE, it's irelevant, since they will get replaced out anyhow if (node[0].getKind() == kind::ITE) { @@ -100,7 +100,7 @@ TheoryId Theory::theoryOf(TheoryOfMode mode, TNode node) { } if (node[1].getKind() == kind::ITE) { return theoryOf(node[1].getType()); - } + } // If both sides belong to the same theory the choice is easy TheoryId T1 = theoryOf(node[0]); TheoryId T2 = theoryOf(node[1]); @@ -108,12 +108,12 @@ TheoryId Theory::theoryOf(TheoryOfMode mode, TNode node) { return T1; } TheoryId T3 = theoryOf(node[0].getType()); - // This is a case of + // This is a case of // * x*y = f(z) -> UF // * x = c -> UF // * f(x) = read(a, y) -> either UF or ARRAY // at least one of the theories has to be parametric, i.e. theory of the type is different - // from the theory of the term + // from the theory of the term if (T1 == T3) { return T2; } @@ -122,13 +122,13 @@ TheoryId Theory::theoryOf(TheoryOfMode mode, TNode node) { } // If both are parametric, we take the smaller one (arbitraty) return T1 < T2 ? T1 : T2; - } + } // Regular nodes are owned by the kind - return kindToTheoryId(node.getKind()); - break; + return kindToTheoryId(node.getKind()); + break; default: Unreachable(); - } + } } void Theory::addSharedTermInternal(TNode n) { @@ -194,31 +194,21 @@ void Instantiator::resetInstantiationRound(Theory::Effort effort) { processResetInstantiationRound(effort); } -int Instantiator::doInstantiation(Node f, Theory::Effort effort, int e, int limitInst) { +int Instantiator::doInstantiation(Node f, Theory::Effort effort, int e ) { if(hasConstraintsFrom(f)) { - int origLemmas = d_quantEngine->getNumLemmasWaiting(); - int status = process(f, effort, e, limitInst); - if(limitInst <= 0 || (d_quantEngine->getNumLemmasWaiting()-origLemmas) < limitInst) { - if(d_instStrategies.empty()) { - Debug("inst-engine-inst") << "There are no instantiation strategies allocated." << endl; - } else { - for(int i = 0; i < (int) d_instStrategies.size(); ++i) { - if(isActiveStrategy(d_instStrategies[i])) { - Debug("inst-engine-inst") << d_instStrategies[i]->identify() << " process " << effort << endl; - //call the instantiation strategy's process method - int s_limitInst = limitInst > 0 ? limitInst - (d_quantEngine->getNumLemmasWaiting() - origLemmas) : 0; - int s_status = d_instStrategies[i]->doInstantiation(f, effort, e, s_limitInst); - Debug("inst-engine-inst") << " -> status is " << s_status << endl; - if(limitInst > 0 && (d_quantEngine->getNumLemmasWaiting() - origLemmas) >= limitInst) { - Assert( (d_quantEngine->getNumLemmasWaiting() - origLemmas) == limitInst ); - i = (int) d_instStrategies.size(); - status = InstStrategy::STATUS_UNKNOWN; - } else { - InstStrategy::updateStatus(status, s_status); - } - } else { - Debug("inst-engine-inst") << d_instStrategies[i]->identify() << " is not active." << endl; - } + int status = process(f, effort, e ); + if(d_instStrategies.empty()) { + Debug("inst-engine-inst") << "There are no instantiation strategies allocated." << endl; + } else { + for(int i = 0; i < (int) d_instStrategies.size(); ++i) { + if(isActiveStrategy(d_instStrategies[i])) { + Debug("inst-engine-inst") << d_instStrategies[i]->identify() << " process " << effort << endl; + //call the instantiation strategy's process method + int s_status = d_instStrategies[i]->doInstantiation( f, effort, e ); + Debug("inst-engine-inst") << " -> status is " << s_status << endl; + InstStrategy::updateStatus(status, s_status); + } else { + Debug("inst-engine-inst") << d_instStrategies[i]->identify() << " is not active." << endl; } } } diff --git a/src/theory/theory.h b/src/theory/theory.h index 217972dce..7d003bf25 100644 --- a/src/theory/theory.h +++ b/src/theory/theory.h @@ -50,6 +50,7 @@ namespace theory { class Instantiator; class InstStrategy; class QuantifiersEngine; +class TheoryModel; /** * Information about an assertion for the theories. @@ -330,12 +331,12 @@ public: static inline TheoryId theoryOf(TNode node) { return theoryOf(s_theoryOfMode, node); } - + /** Set the theoryOf mode */ static void setTheoryOfMode(TheoryOfMode mode) { s_theoryOfMode = mode; } - + /** * Set the owner of the uninterpreted sort. */ @@ -545,40 +546,13 @@ public: } /** - * Return the value of a node (typically used after a ). If the - * theory supports model generation but has no value for this node, - * it should return Node::null(). If the theory doesn't support - * model generation at all, or usually would but doesn't in its - * current state, it should throw an exception saying so. - * - * The TheoryEngine is passed in so that you can recursively request - * values for the Node's children. This is important because the - * TheoryEngine takes care of simple cases (metakind CONSTANT, - * Boolean-valued VARIABLES, ...) and can dispatch to other theories - * if that's necessary. Only call your own getValue() recursively - * if you *know* that you are responsible handle the Node you're - * asking for; other theories can use your types, so be careful - * here! To be safe, it's best to delegate back to the - * TheoryEngine (by way of the Valuation proxy object, which avoids - * direct dependence on TheoryEngine). - * - * Usually, you need to handle at least the two cases of EQUAL and - * VARIABLE---EQUAL in case a value of yours is on the LHS of an - * EQUAL, and VARIABLE for variables of your types. You also need - * to support any operators that can survive your rewriter. You - * don't need to handle constants, as they are handled by the - * TheoryEngine. - * - * There are some gotchas here. The user may be requesting the - * value of an expression that wasn't part of the satisfiable - * assertion, or has been declared since. If you don't have a value - * and suspect this situation is the case, return Node::null() - * rather than throwing an exception. - */ - virtual Node getValue(TNode n) { - Unimplemented("Theory %s doesn't support Theory::getValue interface", + * Get all relevant information in this theory regarding the current + * model. This should be called after a call to check( FULL_EFFORT ) + * for all theories with no conflicts and no lemmas added. + */ + virtual void collectModelInfo( TheoryModel* m ){ + Unimplemented("Theory %s doesn't support Theory::getModel interface", identify().c_str()); - return Node::null(); } /** @@ -824,7 +798,7 @@ protected: /** reset instantiation round */ virtual void processResetInstantiationRound( Theory::Effort effort ) = 0; /** process quantifier */ - virtual int process( Node f, Theory::Effort effort, int e, int limitInst = 0 ) = 0; + virtual int process( Node f, Theory::Effort effort, int e ) = 0; public: /** set has constraints from quantifier f */ void setHasConstraintsFrom( Node f ); @@ -844,16 +818,22 @@ public: virtual void preRegisterTerm( Node t ) { } /** assertNode function, assertion was asserted to theory */ virtual void assertNode( Node assertion ){} - /** reset instantiation round */ - void resetInstantiationRound( Theory::Effort effort ); - /** do instantiation method*/ - int doInstantiation( Node f, Theory::Effort effort, int e, int limitInst = 0 ); /** identify */ virtual std::string identify() const { return std::string("Unknown"); } /** print debug information */ virtual void debugPrint( const char* c ) {} - /** get status */ - //int getStatus() { return d_status; } +public: + /** reset instantiation round */ + void resetInstantiationRound( Theory::Effort effort ); + /** do instantiation method*/ + int doInstantiation( Node f, Theory::Effort effort, int e ); +public: + /** general queries about equality */ + virtual bool hasTerm( Node a ) { return false; } + virtual bool areEqual( Node a, Node b ) { return false; } + virtual bool areDisequal( Node a, Node b ) { return false; } + virtual Node getRepresentative( Node a ) { return a; } + virtual Node getInternalRepresentative( Node a ) { return getRepresentative( a ); } };/* class Instantiator */ inline Assertion Theory::get() { diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp index 50682f647..872924385 100644 --- a/src/theory/theory_engine.cpp +++ b/src/theory/theory_engine.cpp @@ -35,8 +35,11 @@ #include "util/node_visitor.h" #include "util/ite_removal.h" +#include "theory/model.h" #include "theory/quantifiers_engine.h" #include "theory/quantifiers/theory_quantifiers.h" +#include "theory/quantifiers/model_engine.h" +#include "theory/quantifiers/first_order_model.h" using namespace std; @@ -53,6 +56,8 @@ TheoryEngine::TheoryEngine(context::Context* context, d_logicInfo(logicInfo), d_sharedTerms(this, context), d_quantEngine(NULL), + d_curr_model(NULL), + d_curr_model_builder(NULL), d_ppCache(), d_possiblePropagations(context), d_hasPropagated(context), @@ -80,6 +85,10 @@ TheoryEngine::TheoryEngine(context::Context* context, // initialize the quantifiers engine d_quantEngine = new QuantifiersEngine(context, this); + //build model information if applicable + d_curr_model = new theory::DefaultModel( context, "DefaultModel" ); + d_curr_model_builder = new theory::TheoryEngineModelBuilder( this ); + Rewriter::init(); StatisticsRegistry::registerStat(&d_combineTheoriesTime); d_true = NodeManager::currentNM()->mkConst(true); @@ -175,7 +184,7 @@ void TheoryEngine::dumpAssertions(const char* tag) { Dump(tag) << CommentCommand("Completeness check"); Dump(tag) << PushCommand(); - // Dump the shared terms + // Dump the shared terms if (d_logicInfo.isSharingEnabled()) { Dump(tag) << CommentCommand("Shared terms"); context::CDList::const_iterator it = theory->shared_terms_begin(), it_end = theory->shared_terms_end(); @@ -186,14 +195,14 @@ void TheoryEngine::dumpAssertions(const char* tag) { } } - // Dump the assertions + // Dump the assertions Dump(tag) << CommentCommand("Assertions"); context::CDList::const_iterator it = theory->facts_begin(), it_end = theory->facts_end(); for (; it != it_end; ++ it) { // Get the assertion Node assertionNode = (*it).assertion; // Purify all the terms - + BoolExpr assertionExpr(assertionNode.toExpr()); if ((*it).isPreregistered) { Dump(tag) << CommentCommand("Preregistered"); @@ -223,24 +232,24 @@ void TheoryEngine::dumpAssertions(const char* tag) { continue; } - // Check equality + // Check equality Dump(tag) << PushCommand(); BoolExpr eqExpr(equality.toExpr()); Dump(tag) << AssertCommand(eqExpr); - Dump(tag) << CheckSatCommand(); + Dump(tag) << CheckSatCommand(); Dump(tag) << PopCommand(); - // Check disequality + // Check disequality Dump(tag) << PushCommand(); BoolExpr diseqExpr(disequality.toExpr()); Dump(tag) << AssertCommand(diseqExpr); - Dump(tag) << CheckSatCommand(); - Dump(tag) << PopCommand(); + Dump(tag) << CheckSatCommand(); + Dump(tag) << PopCommand(); } } } } - + Dump(tag) << PopCommand(); } } @@ -297,8 +306,8 @@ void TheoryEngine::check(Theory::Effort effort) { // If in full effort, we have a fake new assertion just to jumpstart the checking if (Theory::fullEffort(effort)) { d_factsAsserted = true; - } - + } + // Check until done while (d_factsAsserted && !d_inConflict && !d_lemmasAdded) { @@ -335,17 +344,22 @@ void TheoryEngine::check(Theory::Effort effort) { // Must consult quantifiers theory for last call to ensure sat, or otherwise add a lemma if( effort == Theory::EFFORT_FULL && - d_logicInfo.isQuantified() && ! d_inConflict && ! d_lemmasAdded ) { - ((theory::quantifiers::TheoryQuantifiers*) d_theoryTable[THEORY_QUANTIFIERS])->performCheck(Theory::EFFORT_LAST_CALL); - // if we have given up, then possibly flip decision - if(Options::current()->flipDecision) { - if(d_incomplete && !d_inConflict && !d_lemmasAdded) { - if( ((theory::quantifiers::TheoryQuantifiers*) d_theoryTable[THEORY_QUANTIFIERS])->flipDecision() ) { - d_incomplete = false; + if( d_logicInfo.isQuantified() ){ + ((theory::quantifiers::TheoryQuantifiers*) d_theoryTable[THEORY_QUANTIFIERS])->performCheck(Theory::EFFORT_LAST_CALL); + // if we have given up, then possibly flip decision + if(Options::current()->flipDecision) { + if(d_incomplete && !d_inConflict && !d_lemmasAdded) { + if( ((theory::quantifiers::TheoryQuantifiers*) d_theoryTable[THEORY_QUANTIFIERS])->flipDecision() ) { + d_incomplete = false; + } } } + //if returning incomplete or SAT, we have ensured that the model in the quantifiers engine has been built + }else if( Options::current()->produceModels ){ + //must build model at this point + d_curr_model_builder->buildModel( d_curr_model ); } } @@ -354,8 +368,8 @@ void TheoryEngine::check(Theory::Effort effort) { } catch(const theory::Interrupted&) { Trace("theory") << "TheoryEngine::check() => conflict" << endl; } - - // If fulleffort, check all theories + + // If fulleffort, check all theories if(Dump.isOn("theory::fullcheck") && Theory::fullEffort(effort)) { if (!d_inConflict && !d_lemmasAdded) { dumpAssertions("theory::fullcheck"); @@ -415,7 +429,7 @@ void TheoryEngine::combineTheories() { Node literal = value ? equality : equality.notNode(); Node normalizedLiteral = value ? normalizedEquality : normalizedEquality.notNode(); // We're sending the original literal back, backed by the normalized one - if (markPropagation(literal, normalizedLiteral, /* to */ carePair.theory, /* from */ THEORY_SAT_SOLVER)) { + if (markPropagation(literal, normalizedLiteral, /* to */ carePair.theory, /* from */ THEORY_SAT_SOLVER)) { // We assert it, and we know it's preregistereed if it's the same theory bool preregistered = Theory::theoryOf(literal) == carePair.theory; theoryOf(carePair.theory)->assertFact(literal, preregistered); @@ -427,7 +441,7 @@ void TheoryEngine::combineTheories() { } } } - + // We need to split on it Debug("sharing") << "TheoryEngine::combineTheories(): requesting a split " << std::endl; lemma(equality.orNode(equality.notNode()), false, false); @@ -528,23 +542,26 @@ bool TheoryEngine::properExplanation(TNode node, TNode expl) const { return true; } -Node TheoryEngine::getValue(TNode node) { - kind::MetaKind metakind = node.getMetaKind(); - - // special case: prop engine handles boolean vars - if(metakind == kind::metakind::VARIABLE && node.getType().isBoolean()) { - return d_propEngine->getValue(node); +void TheoryEngine::collectModelInfo( theory::TheoryModel* m ){ + //consult each theory to get all relevant information concerning the model + for( int i=0; icollectModelInfo( m ); + } } +} - // special case: value of a constant == itself - if(metakind == kind::metakind::CONSTANT) { - return node; +/* get model */ +TheoryModel* TheoryEngine::getModel(){ + Debug("model") << "TheoryEngine::getModel()" << std::endl; + if( d_logicInfo.isQuantified() ){ + Debug("model") << "Get model from quantifiers engine." << std::endl; + return d_quantEngine->getModel(); + }else{ + Debug("model") << "Get default model." << std::endl; + return d_curr_model; } - - // otherwise ask the theory-in-charge - return theoryOf(node)->getValue(node); - -}/* TheoryEngine::getValue(TNode node) */ +} bool TheoryEngine::presolve() { @@ -777,7 +794,7 @@ bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, the // What and where it came from NodeTheoryPair toExplain(originalAssertion, fromTheoryId, d_propagationMapTimestamp); - // See if the theory already got this literal + // See if the theory already got this literal PropagationMap::const_iterator find = d_propagationMap.find(toAssert); if (find != d_propagationMap.end()) { // The theory already knows this @@ -796,11 +813,11 @@ bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, the void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) { - + Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << ")" << std::endl; - + Assert(toTheoryId != fromTheoryId); - + if (d_inConflict) { return; } @@ -813,7 +830,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId, // We assert it, and we know it's preregistereed toTheory->assertFact(assertion, true); // Mark that we have more information - d_factsAsserted = true; + d_factsAsserted = true; } else { Assert(toTheoryId == THEORY_SAT_SOLVER); // Check for propositional conflict @@ -825,18 +842,18 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId, } else { return; } - } + } d_propagatedLiterals.push_back(assertion); } return; } - + // Polarity of the assertion bool polarity = assertion.getKind() != kind::NOT; - + // Atom of the assertion TNode atom = polarity ? assertion : assertion[0]; - + // If sending to the shared terms database, it's also simple if (toTheoryId == THEORY_BUILTIN) { Assert(atom.getKind() == kind::EQUAL); @@ -845,11 +862,11 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId, } return; } - - // Things from the SAT solver are already normalized, so they go + + // Things from the SAT solver are already normalized, so they go // directly to the apropriate theory if (fromTheoryId == THEORY_SAT_SOLVER) { - // We know that this is normalized, so just send it off to the theory + // We know that this is normalized, so just send it off to the theory if (markPropagation(assertion, assertion, toTheoryId, fromTheoryId)) { // We assert it, and we know it's preregistereed coming from the SAT solver directly theoryOf(toTheoryId)->assertFact(assertion, true); @@ -858,7 +875,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId, } return; } - + // Propagations to the SAT solver are just enqueued for pickup by // the SAT solver later if (toTheoryId == THEORY_SAT_SOLVER) { @@ -898,14 +915,14 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId, // Normalize to lhs < rhs if not a sat literal Assert(atom.getKind() == kind::EQUAL); Assert(atom[0] != atom[1]); - + Node normalizedAtom = atom; if (!d_propEngine->isSatLiteral(normalizedAtom)) { Node reverse = atom[1].eqNode(atom[0]); if (d_propEngine->isSatLiteral(reverse) || atom[0] > atom[1]) { normalizedAtom = reverse; - } - } + } + } Node normalizedAssertion = polarity ? normalizedAtom : normalizedAtom.notNode(); // Try and assert (note that we assert the non-normalized one) @@ -915,7 +932,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId, // Assert away theoryOf(toTheoryId)->assertFact(normalizedAssertion, preregistered); d_factsAsserted = true; - } + } return; } @@ -923,7 +940,7 @@ void TheoryEngine::assertToTheory(TNode assertion, theory::TheoryId toTheoryId, void TheoryEngine::assertFact(TNode literal) { Trace("theory") << "TheoryEngine::assertFact(" << literal << ")" << std::endl; - + d_propEngine->checkTime(); // If we're in conflict, nothing to do @@ -997,7 +1014,7 @@ bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) { } if (theory != THEORY_BUILTIN) { // Assert to the shared terms database - assertToTheory(literal, /* to */ THEORY_BUILTIN, /* from */ theory); + assertToTheory(literal, /* to */ THEORY_BUILTIN, /* from */ theory); } } else { // Just send off to the SAT solver @@ -1075,7 +1092,7 @@ Node TheoryEngine::getExplanation(TNode node) { return explanation; } - // Initial thing to explain + // Initial thing to explain NodeTheoryPair toExplain(node, THEORY_SAT_SOLVER, d_propagationMapTimestamp); Assert(d_propagationMap.find(toExplain) != d_propagationMap.end()); // Create the workplace for explanations @@ -1084,9 +1101,9 @@ Node TheoryEngine::getExplanation(TNode node) { // Process the explanation getExplanation(explanationVector); Node explanation = mkExplanation(explanationVector); - + Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << std::endl; - + return explanation; } @@ -1131,7 +1148,7 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable if(!removable) { d_decisionEngine->addAssertions(additionalLemmas, 1, iteSkolemMap); } - + // Mark that we added some lemmas d_lemmasAdded = true; @@ -1151,7 +1168,7 @@ void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) { Dump("t-conflicts") << CommentCommand("theory conflict: expect unsat") << CheckSatCommand(conflict.toExpr()); } - + // In the multiple-theories case, we need to reconstruct the conflict if (d_logicInfo.isSharingEnabled()) { // Create the workplace for explanations @@ -1184,9 +1201,9 @@ void TheoryEngine::getExplanation(std::vector& explanationVector unsigned i = 0; // Index of the current literal we are processing unsigned j = 0; // Index of the last literal we are keeping - + while (i < explanationVector.size()) { - + // Get the current literal to explain NodeTheoryPair toExplain = explanationVector[i]; @@ -1196,7 +1213,7 @@ void TheoryEngine::getExplanation(std::vector& explanationVector if (toExplain.node.isConst() && toExplain.node.getConst()) { ++ i; continue; - } + } if (toExplain.node.getKind() == kind::NOT && toExplain.node[0].isConst() && !toExplain.node[0].getConst()) { ++ i; continue; @@ -1219,7 +1236,7 @@ void TheoryEngine::getExplanation(std::vector& explanationVector continue; } - // See if it was sent to the theory by another theory + // See if it was sent to the theory by another theory PropagationMap::const_iterator find = d_propagationMap.find(toExplain); if (find != d_propagationMap.end()) { // There is some propagation, check if its a timely one @@ -1244,10 +1261,10 @@ void TheoryEngine::getExplanation(std::vector& explanationVector explanationVector.push_back(newExplain); ++ i; } - + // Keep only the relevant literals explanationVector.resize(j); -} +} void TheoryEngine::ppUnconstrainedSimp(vector& assertions) diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h index 3d70ffa6b..f55c7c258 100644 --- a/src/theory/theory_engine.h +++ b/src/theory/theory_engine.h @@ -42,13 +42,14 @@ #include "util/cache.h" #include "theory/ite_simplifier.h" #include "theory/unconstrained_simplifier.h" +#include "theory/model.h" namespace CVC4 { /** - * A pair of a theory and a node. This is used to mark the flow of + * A pair of a theory and a node. This is used to mark the flow of * propagations between theories. - */ + */ struct NodeTheoryPair { Node node; theory::TheoryId theory; @@ -57,7 +58,7 @@ struct NodeTheoryPair { : node(node), theory(theory), timestamp(timestamp) {} NodeTheoryPair() : theory(theory::THEORY_LAST) {} - // Comparison doesn't take into account the timestamp + // Comparison doesn't take into account the timestamp bool operator == (const NodeTheoryPair& pair) const { return node == pair.node && theory == pair.theory; } @@ -84,7 +85,7 @@ class DecisionEngine; * CVC4. */ class TheoryEngine { - + /** Shared terms database can use the internals notify the theories */ friend class SharedTermsDatabase; @@ -125,6 +126,15 @@ class TheoryEngine { */ theory::QuantifiersEngine* d_quantEngine; + /** + * Default model object + */ + theory::DefaultModel* d_curr_model; + /** + * Model builder object + */ + theory::TheoryEngineModelBuilder* d_curr_model_builder; + typedef std::hash_map NodeMap; typedef std::hash_map TNodeMap; @@ -389,7 +399,7 @@ class TheoryEngine { * Adds a new lemma, returning its status. */ theory::LemmaStatus lemma(TNode node, bool negated, bool removable); - + /** Time spent in theory combination */ TimerStat d_combineTheoriesTime; @@ -432,6 +442,13 @@ public: return d_propEngine; } + /** + * Get a pointer to the underlying sat context. + */ + inline context::Context* getSatContext() const { + return d_context; + } + /** * Get a pointer to the underlying quantifiers engine. */ @@ -472,12 +489,12 @@ private: void assertToTheory(TNode assertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId); /** - * Marks a theory propagation from a theory to a theory where a + * Marks a theory propagation from a theory to a theory where a * theory could be the THEORY_SAT_SOLVER for literals coming from * or being propagated to the SAT solver. If the receiving theory * already recieved the literal, the method returns false, otherwise * it returns true. - * + * * @param assertion the normalized assertion being sent * @param originalAssertion the actual assertion that was sent * @param toTheoryId the theory that is on the receiving end @@ -488,7 +505,7 @@ private: /** * Computes the explanation by travarsing the propagation graph and - * asking relevant theories to explain the propagations. Initially + * asking relevant theories to explain the propagations. Initially * the explanation vector should contain only the element (node, theory) * where the node is the one to be explained, and the theory is the * theory that sent the literal. @@ -623,9 +640,19 @@ public: Node getExplanation(TNode node); /** - * Returns the value of the given node. + * collect model info + */ + void collectModelInfo( theory::TheoryModel* m ); + + /** + * Get the current model */ - Node getValue(TNode node); + theory::TheoryModel* getModel(); + + /** + * Get the model builder + */ + theory::TheoryEngineModelBuilder* getModelBuilder() { return d_curr_model_builder; } /** * Get the theory associated to a given Node. @@ -685,6 +712,8 @@ public: Node ppSimpITE(TNode assertion); void ppUnconstrainedSimp(std::vector& assertions); + SharedTermsDatabase* getSharedTermsDatabase() { return &d_sharedTerms; } + };/* class TheoryEngine */ }/* CVC4 namespace */ diff --git a/src/theory/trigger.cpp b/src/theory/trigger.cpp index d665fef91..55ca07d77 100644 --- a/src/theory/trigger.cpp +++ b/src/theory/trigger.cpp @@ -144,8 +144,8 @@ int Trigger::addTerm( Node t ){ return d_mg->addTerm( d_f, t, d_quantEngine ); } -int Trigger::addInstantiations( InstMatch& baseMatch, int instLimit, bool addSplits ){ - int addedLemmas = d_mg->addInstantiations( d_f, baseMatch, d_quantEngine, instLimit, addSplits ); +int Trigger::addInstantiations( InstMatch& baseMatch ){ + int addedLemmas = d_mg->addInstantiations( d_f, baseMatch, d_quantEngine ); if( addedLemmas>0 ){ Debug("inst-trigger") << "Added " << addedLemmas << " lemmas, trigger was "; for( int i=0; i<(int)d_nodes.size(); i++ ){ diff --git a/src/theory/trigger.h b/src/theory/trigger.h index 457df0ab4..476ef392e 100644 --- a/src/theory/trigger.h +++ b/src/theory/trigger.h @@ -97,7 +97,7 @@ public: public: /** add all available instantiations exhaustively, in any equivalence class if limitInst>0, limitInst is the max # of instantiations to try */ - int addInstantiations( InstMatch& baseMatch, int instLimit = 0, bool addSplits = false ); + int addInstantiations( InstMatch& baseMatch ); /** mkTrigger method ie : quantifier engine; f : forall something .... diff --git a/src/theory/uf/Makefile.am b/src/theory/uf/Makefile.am index 2c9cd3b80..b8446761c 100644 --- a/src/theory/uf/Makefile.am +++ b/src/theory/uf/Makefile.am @@ -22,6 +22,8 @@ libuf_la_SOURCES = \ theory_uf_candidate_generator.h \ theory_uf_candidate_generator.cpp \ inst_strategy.h \ - inst_strategy.cpp + inst_strategy.cpp \ + theory_uf_model.h \ + theory_uf_model.cpp EXTRA_DIST = kinds diff --git a/src/theory/uf/inst_strategy.cpp b/src/theory/uf/inst_strategy.cpp index 2ca2dcb5a..669df055a 100644 --- a/src/theory/uf/inst_strategy.cpp +++ b/src/theory/uf/inst_strategy.cpp @@ -20,6 +20,7 @@ #include "theory/theory_engine.h" #include "theory/uf/theory_uf.h" #include "theory/uf/equality_engine.h" +#include "theory/quantifiers/term_database.h" using namespace std; using namespace CVC4; @@ -34,7 +35,7 @@ using namespace CVC4::theory::uf; struct sortQuantifiersForSymbol { QuantifiersEngine* d_qe; - bool operator() (Node i, Node j) { + bool operator() (Node i, Node j) { int nqfsi = d_qe->getNumQuantifiersForSymbol( i.getOperator() ); int nqfsj = d_qe->getNumQuantifiersForSymbol( j.getOperator() ); if( nqfsid_hasInstantiated[f] = true; } d_solved[f] = false; - } + } Debug("quant-uf-strategy") << "done." << std::endl; } return STATUS_UNKNOWN; @@ -78,8 +79,8 @@ void InstStrategyCheckCESolved::calcSolved( Node f ){ d_th->d_baseMatch[f].clear(); d_solved[ f ]= true; //check if instantiation constants are solved for - for( int j = 0; j<(int)d_quantEngine->getNumInstantiationConstants( f ); j++ ){ - Node i = d_quantEngine->getInstantiationConstant( f, j ); + for( int j = 0; jgetTermDatabase()->getNumInstantiationConstants( f ); j++ ){ + Node i = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j ); Node rep = d_th->getInternalRepresentative( i ); if( !rep.hasAttribute(InstConstantAttribute()) ){ d_th->d_baseMatch[f].d_map[ i ] = rep; @@ -99,7 +100,7 @@ void InstStrategyUserPatterns::processResetInstantiationRound( Theory::Effort ef } } -int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e, int instLimit ){ +int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){ if( e==0 ){ return STATUS_UNFINISHED; }else if( e==1 ){ @@ -114,10 +115,10 @@ int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e, int //#endif } if( processTrigger ){ - //if( d_user_gen[f][i]->isMultiTrigger() ) + //if( d_user_gen[f][i]->isMultiTrigger() ) //Notice() << " Process (user) " << (*d_user_gen[f][i]) << " for " << f << "..." << std::endl; - int numInst = d_user_gen[f][i]->addInstantiations( d_th->d_baseMatch[f], instLimit ); - //if( d_user_gen[f][i]->isMultiTrigger() ) + int numInst = d_user_gen[f][i]->addInstantiations( d_th->d_baseMatch[f] ); + //if( d_user_gen[f][i]->isMultiTrigger() ) //Notice() << " Done, numInst = " << numInst << "." << std::endl; d_th->d_statistics.d_instantiations_user_pattern += numInst; if( d_user_gen[f][i]->isMultiTrigger() ){ @@ -131,7 +132,7 @@ int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e, int } return STATUS_UNKNOWN; } - + void InstStrategyUserPatterns::addUserPattern( Node f, Node pat ){ //add to generators std::vector< Node > nodes; @@ -143,11 +144,11 @@ void InstStrategyUserPatterns::addUserPattern( Node f, Node pat ){ d_quantEngine->getPhaseReqTerms( f, nodes ); //check match option int matchOption = Options::current()->efficientEMatching ? InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH : 0; - d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW, + d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW, Options::current()->smartTriggers ) ); } } - + void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort effort ){ //reset triggers for( std::map< Node, std::map< Trigger*, bool > >::iterator it = d_auto_gen_trigger.begin(); it != d_auto_gen_trigger.end(); ++it ){ @@ -158,7 +159,7 @@ void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort } } -int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e, int instLimit ){ +int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ){ int peffort = f.getNumChildren()==3 ? 2 : 1; //int peffort = f.getNumChildren()==3 ? 2 : 1; //int peffort = 1; @@ -192,10 +193,10 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e, #endif } if( processTrigger ){ - //if( tr->isMultiTrigger() ) + //if( tr->isMultiTrigger() ) Debug("quant-uf-strategy-auto-gen-triggers") << " Process " << (*tr) << "..." << std::endl; - int numInst = tr->addInstantiations( d_th->d_baseMatch[f], instLimit ); - //if( tr->isMultiTrigger() ) + int numInst = tr->addInstantiations( d_th->d_baseMatch[f] ); + //if( tr->isMultiTrigger() ) Debug("quant-uf-strategy-auto-gen-triggers") << " Done, numInst = " << numInst << "." << std::endl; if( d_tr_strategy==Trigger::TS_MIN_TRIGGER ){ d_th->d_statistics.d_instantiations_auto_gen_min += numInst; @@ -222,8 +223,8 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ d_patTerms[0][f].clear(); d_patTerms[1][f].clear(); std::vector< Node > patTermsF; - Trigger::collectPatTerms( d_quantEngine, f, d_quantEngine->getCounterexampleBody( f ), patTermsF, d_tr_strategy, true ); - Debug("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getCounterexampleBody( f ) << std::endl; + Trigger::collectPatTerms( d_quantEngine, f, d_quantEngine->getTermDatabase()->getCounterexampleBody( f ), patTermsF, d_tr_strategy, true ); + Debug("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getTermDatabase()->getCounterexampleBody( f ) << std::endl; Debug("auto-gen-trigger") << " "; for( int i=0; i<(int)patTermsF.size(); i++ ){ Debug("auto-gen-trigger") << patTermsF[i] << " "; @@ -299,7 +300,7 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ int matchOption = Options::current()->efficientEMatching ? InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH : 0; Trigger* tr = NULL; if( d_is_single_trigger[ patTerms[0] ] ){ - tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], matchOption, false, Trigger::TR_RETURN_NULL, + tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], matchOption, false, Trigger::TR_RETURN_NULL, Options::current()->smartTriggers ); d_single_trigger_gen[ patTerms[0] ] = true; }else{ @@ -313,12 +314,12 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ d_made_multi_trigger[f] = true; } //will possibly want to get an old trigger - tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, false, Trigger::TR_GET_OLD, + tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, false, Trigger::TR_GET_OLD, Options::current()->smartTriggers ); } if( tr ){ if( tr->isMultiTrigger() ){ - //disable all other multi triggers + //disable all other multi triggers for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[f].begin(); it != d_auto_gen_trigger[f].end(); ++it ){ if( it->first->isMultiTrigger() ){ d_auto_gen_trigger[f][ it->first ] = false; @@ -344,7 +345,7 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ success = false; if( d_quantEngine->getNumQuantifiersForSymbol( patTerms[index].getOperator() )<=nqfs_curr ){ d_single_trigger_gen[ patTerms[index] ] = true; - Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], matchOption, false, Trigger::TR_RETURN_NULL, + Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], matchOption, false, Trigger::TR_RETURN_NULL, Options::current()->smartTriggers ); if( tr2 ){ //Notice() << "Add additional trigger " << patTerms[index] << std::endl; @@ -368,11 +369,11 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ void InstStrategyAddFailSplits::processResetInstantiationRound( Theory::Effort effort ){ } -int InstStrategyAddFailSplits::process( Node f, Theory::Effort effort, int e, int instLimit ){ +int InstStrategyAddFailSplits::process( Node f, Theory::Effort effort, int e ){ if( e<4 ){ return STATUS_UNFINISHED; }else{ - for( std::map< Node, std::map< Node, std::vector< InstMatchGenerator* > > >::iterator it = InstMatchGenerator::d_match_fails.begin(); + for( std::map< Node, std::map< Node, std::vector< InstMatchGenerator* > > >::iterator it = InstMatchGenerator::d_match_fails.begin(); it != InstMatchGenerator::d_match_fails.end(); ++it ){ for( std::map< Node, std::vector< InstMatchGenerator* > >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ if( !it2->second.empty() ){ @@ -394,7 +395,7 @@ int InstStrategyAddFailSplits::process( Node f, Theory::Effort effort, int e, in void InstStrategyFreeVariable::processResetInstantiationRound( Theory::Effort effort ){ } -int InstStrategyFreeVariable::process( Node f, Theory::Effort effort, int e, int instLimit ){ +int InstStrategyFreeVariable::process( Node f, Theory::Effort effort, int e ){ if( e<5 ){ return STATUS_UNFINISHED; }else{ diff --git a/src/theory/uf/inst_strategy.h b/src/theory/uf/inst_strategy.h index 906169811..09b8087f2 100644 --- a/src/theory/uf/inst_strategy.h +++ b/src/theory/uf/inst_strategy.h @@ -45,9 +45,9 @@ private: void calcSolved( Node f ); /** process functions */ void processResetInstantiationRound( Theory::Effort effort ); - int process( Node f, Theory::Effort effort, int e, int instLimit ); + int process( Node f, Theory::Effort effort, int e ); public: - InstStrategyCheckCESolved( InstantiatorTheoryUf* th, QuantifiersEngine* ie ) : + InstStrategyCheckCESolved( InstantiatorTheoryUf* th, QuantifiersEngine* ie ) : InstStrategy( ie ), d_th( th ){} ~InstStrategyCheckCESolved(){} /** identify */ @@ -64,9 +64,9 @@ private: std::map< Node, int > d_counter; /** process functions */ void processResetInstantiationRound( Theory::Effort effort ); - int process( Node f, Theory::Effort effort, int e, int instLimit ); + int process( Node f, Theory::Effort effort, int e ); public: - InstStrategyUserPatterns( InstantiatorTheoryUf* th, QuantifiersEngine* ie ) : + InstStrategyUserPatterns( InstantiatorTheoryUf* th, QuantifiersEngine* ie ) : InstStrategy( ie ), d_th( th ){} ~InstStrategyUserPatterns(){} public: @@ -109,11 +109,11 @@ private: private: /** process functions */ void processResetInstantiationRound( Theory::Effort effort ); - int process( Node f, Theory::Effort effort, int e, int instLimit ); + int process( Node f, Theory::Effort effort, int e ); /** generate triggers */ void generateTriggers( Node f ); public: - InstStrategyAutoGenTriggers( InstantiatorTheoryUf* th, QuantifiersEngine* ie, int tstrt, int rstrt, int rgfr = -1 ) : + InstStrategyAutoGenTriggers( InstantiatorTheoryUf* th, QuantifiersEngine* ie, int tstrt, int rstrt, int rgfr = -1 ) : InstStrategy( ie ), d_th( th ), d_tr_strategy( tstrt ), d_rlv_strategy( rstrt ), d_generate_additional( false ){ setRegenerateFrequency( rgfr ); } @@ -144,9 +144,9 @@ private: InstantiatorTheoryUf* d_th; /** process functions */ void processResetInstantiationRound( Theory::Effort effort ); - int process( Node f, Theory::Effort effort, int e, int instLimit ); + int process( Node f, Theory::Effort effort, int e ); public: - InstStrategyAddFailSplits( InstantiatorTheoryUf* th, QuantifiersEngine* ie ) : + InstStrategyAddFailSplits( InstantiatorTheoryUf* th, QuantifiersEngine* ie ) : InstStrategy( ie ), d_th( th ){} ~InstStrategyAddFailSplits(){} /** identify */ @@ -163,9 +163,9 @@ private: std::map< Node, bool > d_guessed; /** process functions */ void processResetInstantiationRound( Theory::Effort effort ); - int process( Node f, Theory::Effort effort, int e, int instLimit ); + int process( Node f, Theory::Effort effort, int e ); public: - InstStrategyFreeVariable( InstantiatorTheoryUf* th, QuantifiersEngine* ie ) : + InstStrategyFreeVariable( InstantiatorTheoryUf* th, QuantifiersEngine* ie ) : InstStrategy( ie ), d_th( th ){} ~InstStrategyFreeVariable(){} /** identify */ diff --git a/src/theory/uf/kinds b/src/theory/uf/kinds index ec353dc59..ce8785f86 100644 --- a/src/theory/uf/kinds +++ b/src/theory/uf/kinds @@ -17,7 +17,49 @@ parameterized APPLY_UF VARIABLE 1: "uninterpreted function application" typerule APPLY_UF ::CVC4::theory::uf::UfTypeRule operator CARDINALITY_CONSTRAINT 2 "cardinality constraint" - typerule CARDINALITY_CONSTRAINT ::CVC4::theory::uf::CardinalityConstraintTypeRule +# +# For compact function models +# There are three cases for FUNCTION_MODEL nodes: +# (1) The node has two children, the first being of kind FUNCTION_CASE_SPLIT. The second child specifies a default value. +# (2) The node has one child of kind FUNCTION_CASE_SPLIT. +# (3) The node has one child, it's default value. +# +# Semantics of FUNCTION_MODEL kind-ed nodes. The value of n applied to arguments args is +# +# getValueFM( n, args, 0 ), where: +# +# Node getValueFM( n, args, argIndex ) +# if n.getKind()!=FUNCTION_MODEL +# return n; +# else if (1) +# val = getValueFCS( n[0], args, argIndex ); +# if !val.isNull() +# return val; +# else +# return getValueFM( n[1], args, argIndex+1 ); +# else if (2) +# return getValueFCS( n[0], args, argIndex ); +# else if (3) +# return getValueFM( n[0], args, argIndex+1 ); +# +# Node getValueFCS( n, args, argIndex ) : +# //n.getKind()==FUNCTION_CASE_SPLIT +# //n[j].getKind()==FUNCTION_CASE for all 0<=jassertEqualityEngine( &d_equalityEngine ); +} + void TheoryUF::presolve() { // TimerStat::CodeTimer codeTimer(d_presolveTimer); diff --git a/src/theory/uf/theory_uf.h b/src/theory/uf/theory_uf.h index db417b08c..604b1f44c 100644 --- a/src/theory/uf/theory_uf.h +++ b/src/theory/uf/theory_uf.h @@ -132,8 +132,8 @@ private: Node d_conflictNode; /** - * Should be called to propagate the literal. We use a node here - * since some of the propagated literals are not kept anywhere. + * Should be called to propagate the literal. We use a node here + * since some of the propagated literals are not kept anywhere. */ bool propagate(TNode literal); @@ -193,6 +193,8 @@ public: void preRegisterTerm(TNode term); Node explain(TNode n); + void collectModelInfo( TheoryModel* m ); + void ppStaticLearn(TNode in, NodeBuilder<>& learned); void presolve(); diff --git a/src/theory/uf/theory_uf_candidate_generator.cpp b/src/theory/uf/theory_uf_candidate_generator.cpp index e8aa98aa7..5342188f7 100644 --- a/src/theory/uf/theory_uf_candidate_generator.cpp +++ b/src/theory/uf/theory_uf_candidate_generator.cpp @@ -17,6 +17,7 @@ #include "theory/uf/theory_uf_candidate_generator.h" #include "theory/theory_engine.h" #include "theory/uf/theory_uf.h" +#include "theory/quantifiers/term_database.h" using namespace std; using namespace CVC4; @@ -25,7 +26,7 @@ using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::uf; -CandidateGeneratorTheoryUf::CandidateGeneratorTheoryUf( InstantiatorTheoryUf* ith, Node op ) : +CandidateGeneratorTheoryUf::CandidateGeneratorTheoryUf( InstantiatorTheoryUf* ith, Node op ) : d_op( op ), d_ith( ith ), d_term_iter( -2 ){ Assert( !d_op.isNull() ); } @@ -84,12 +85,12 @@ Node CandidateGeneratorTheoryUf::getNextCandidate(){ } -//CandidateGeneratorTheoryUfDisequal::CandidateGeneratorTheoryUfDisequal( InstantiatorTheoryUf* ith, Node eqc ) : +//CandidateGeneratorTheoryUfDisequal::CandidateGeneratorTheoryUfDisequal( InstantiatorTheoryUf* ith, Node eqc ) : // d_ith( ith ), d_eq_class( eqc ){ // d_eci = NULL; //} //void CandidateGeneratorTheoryUfDisequal::resetInstantiationRound(){ -// +// //} ////we will iterate over all terms that are disequal from eqc //void CandidateGeneratorTheoryUfDisequal::reset( Node eqc ){ @@ -119,12 +120,12 @@ Node CandidateGeneratorTheoryUf::getNextCandidate(){ //} -CandidateGeneratorTheoryUfLitEq::CandidateGeneratorTheoryUfLitEq( InstantiatorTheoryUf* ith, Node mpat ) : +CandidateGeneratorTheoryUfLitEq::CandidateGeneratorTheoryUfLitEq( InstantiatorTheoryUf* ith, Node mpat ) : d_match_pattern( mpat ), d_ith( ith ){ - + } void CandidateGeneratorTheoryUfLitEq::resetInstantiationRound(){ - + } void CandidateGeneratorTheoryUfLitEq::reset( Node eqc ){ d_eq = eq::EqClassesIterator( ((TheoryUF*)d_ith->getTheory())->getEqualityEngine() ); @@ -142,15 +143,15 @@ Node CandidateGeneratorTheoryUfLitEq::getNextCandidate(){ } -CandidateGeneratorTheoryUfLitDeq::CandidateGeneratorTheoryUfLitDeq( InstantiatorTheoryUf* ith, Node mpat ) : +CandidateGeneratorTheoryUfLitDeq::CandidateGeneratorTheoryUfLitDeq( InstantiatorTheoryUf* ith, Node mpat ) : d_match_pattern( mpat ), d_ith( ith ){ - + } void CandidateGeneratorTheoryUfLitDeq::resetInstantiationRound(){ - + } void CandidateGeneratorTheoryUfLitDeq::reset( Node eqc ){ - Node false_term = ((TheoryUF*)d_ith->getTheory())->getEqualityEngine()->getRepresentative( + Node false_term = ((TheoryUF*)d_ith->getTheory())->getEqualityEngine()->getRepresentative( NodeManager::currentNM()->mkConst(false) ); d_eqc_false = eq::EqClassIterator( false_term, ((TheoryUF*)d_ith->getTheory())->getEqualityEngine() ); } diff --git a/src/theory/uf/theory_uf_instantiator.cpp b/src/theory/uf/theory_uf_instantiator.cpp index 9fdcb5952..e3999c163 100644 --- a/src/theory/uf/theory_uf_instantiator.cpp +++ b/src/theory/uf/theory_uf_instantiator.cpp @@ -18,7 +18,7 @@ #include "theory/theory_engine.h" #include "theory/uf/theory_uf.h" #include "theory/uf/equality_engine.h" -//#include "theory/uf/inst_strategy_model_find.h" +#include "theory/quantifiers/term_database.h" using namespace std; using namespace CVC4; @@ -32,7 +32,7 @@ EqClassInfo::EqClassInfo( context::Context* c ) : d_funs( c ), d_pfuns( c ), d_d } //set member -void EqClassInfo::setMember( Node n, TermDb* db ){ +void EqClassInfo::setMember( Node n, quantifiers::TermDb* db ){ if( n.getKind()==APPLY_UF ){ d_funs[n.getOperator()] = true; } @@ -65,15 +65,7 @@ void EqClassInfo::merge( EqClassInfo* eci ){ InstantiatorTheoryUf::InstantiatorTheoryUf(context::Context* c, CVC4::theory::QuantifiersEngine* qe, Theory* th) : Instantiator( c, qe, th ) { - qe->setEqualityQuery( new EqualityQueryInstantiatorTheoryUf( this ) ); - - if( Options::current()->finiteModelFind ){ - //if( Options::current()->cbqi ){ - // addInstStrategy( new InstStrategyCheckCESolved( this, qe ) ); - //} - //addInstStrategy( new InstStrategyFiniteModelFind( c, this, ((TheoryUF*)th)->getStrongSolver(), qe ) ); - qe->getTermDatabase()->setMatchingActive( false ); - }else{ + if( !Options::current()->finiteModelFind || Options::current()->fmfInstEngine ){ if( Options::current()->cbqi ){ addInstStrategy( new InstStrategyCheckCESolved( this, qe ) ); } @@ -88,7 +80,9 @@ Instantiator( c, qe, th ) i_ag->setGenerateAdditional( true ); addInstStrategy( i_ag ); //addInstStrategy( new InstStrategyAddFailSplits( this, ie ) ); - addInstStrategy( new InstStrategyFreeVariable( this, qe ) ); + if( !Options::current()->finiteModelFind ){ + addInstStrategy( new InstStrategyFreeVariable( this, qe ) ); + } //d_isup->setPriorityOver( i_ag ); //d_isup->setPriorityOver( i_agm ); //i_ag->setPriorityOver( i_agm ); @@ -125,7 +119,7 @@ void InstantiatorTheoryUf::processResetInstantiationRound( Theory::Effort effort d_ground_reps.clear(); } -int InstantiatorTheoryUf::process( Node f, Theory::Effort effort, int e, int instLimit ){ +int InstantiatorTheoryUf::process( Node f, Theory::Effort effort, int e ){ Debug("quant-uf") << "UF: Try to solve (" << e << ") for " << f << "... " << std::endl; return InstStrategy::STATUS_SAT; } @@ -405,7 +399,7 @@ bool InstantiatorTheoryUf::collectParentsTermsIps( Node n, Node f, int arg, std: eqc_iter++; } }else{ - TermDb* db = d_quantEngine->getTermDatabase(); + quantifiers::TermDb* db = d_quantEngine->getTermDatabase(); //see if parent f exists from argument arg if( db->d_parents.find( n )!=db->d_parents.end() ){ if( db->d_parents[n].find( f )!=db->d_parents[n].end() ){ @@ -481,7 +475,7 @@ void InstantiatorTheoryUf::registerCandidateGenerator( CandidateGenerator* cg, N //take all terms from the uf term db and add to candidate generator Node op = pat.getOperator(); - TermDb* db = d_quantEngine->getTermDatabase(); + quantifiers::TermDb* db = d_quantEngine->getTermDatabase(); for( int i=0; i<(int)db->d_op_map[op].size(); i++ ){ cg->addCandidate( db->d_op_map[op][i] ); } diff --git a/src/theory/uf/theory_uf_instantiator.h b/src/theory/uf/theory_uf_instantiator.h index e50e3823c..4ddc01986 100644 --- a/src/theory/uf/theory_uf_instantiator.h +++ b/src/theory/uf/theory_uf_instantiator.h @@ -31,7 +31,9 @@ namespace CVC4 { namespace theory { -class TermDb; +namespace quantifiers{ + class TermDb; +} namespace uf { @@ -56,7 +58,7 @@ public: EqClassInfo( context::Context* c ); ~EqClassInfo(){} //set member - void setMember( Node n, TermDb* db ); + void setMember( Node n, quantifiers::TermDb* db ); //has function "funs" bool hasFunction( Node op ); //has parent "pfuns" @@ -67,7 +69,7 @@ public: class InstantiatorTheoryUf : public Instantiator{ friend class ::CVC4::theory::InstMatchGenerator; - friend class ::CVC4::theory::TermDb; + friend class ::CVC4::theory::quantifiers::TermDb; protected: typedef context::CDHashMap BoolMap; typedef context::CDHashMap IntMap; @@ -95,7 +97,7 @@ private: /** reset instantiation */ void processResetInstantiationRound( Theory::Effort effort ); /** calculate matches for quantifier f at effort */ - int process( Node f, Theory::Effort effort, int e, int instLimit ); + int process( Node f, Theory::Effort effort, int e ); public: /** statistics class */ class Statistics { diff --git a/src/theory/uf/theory_uf_model.cpp b/src/theory/uf/theory_uf_model.cpp new file mode 100644 index 000000000..a85dea997 --- /dev/null +++ b/src/theory/uf/theory_uf_model.cpp @@ -0,0 +1,554 @@ +/********************* */ +/*! \file theory_uf_model.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of Theory UF Model + **/ + +#include "theory/quantifiers/model_engine.h" +#include "theory/theory_engine.h" +#include "theory/uf/equality_engine.h" +#include "theory/uf/theory_uf.h" +#include "theory/uf/theory_uf_strong_solver.h" +#include "theory/uf/theory_uf_instantiator.h" +#include "theory/quantifiers/first_order_model.h" +#include "theory/quantifiers/term_database.h" + +#define RECONSIDER_FUNC_DEFAULT_VALUE +#define USE_PARTIAL_DEFAULT_VALUES + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::uf; + +//clear +void UfModelTree::clear(){ + d_data.clear(); + d_value = Node::null(); +} + +bool UfModelTree::hasConcreteArgumentDefinition(){ + if( d_data.size()>1 ){ + return true; + }else if( d_data.empty() ){ + return false; + }else{ + Node r; + return d_data.find( r )==d_data.end(); + } +} + +//set value function +void UfModelTree::setValue( TheoryModel* m, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex ){ + if( d_data.empty() ){ + d_value = v; + }else if( !d_value.isNull() && d_value!=v ){ + d_value = Node::null(); + } + if( argIndex<(int)n.getNumChildren() ){ + //take r = null when argument is the model basis + Node r; + if( ground || !n[ indexOrder[argIndex] ].getAttribute(ModelBasisAttribute()) ){ + r = m->getRepresentative( n[ indexOrder[argIndex] ] ); + } + d_data[ r ].setValue( m, n, v, indexOrder, ground, argIndex+1 ); + } +} + +//get value function +Node UfModelTree::getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int& depIndex, int argIndex ){ + if( !d_value.isNull() && isTotal( n.getOperator(), argIndex ) ){ + //Notice() << "Constant, return " << d_value << ", depIndex = " << argIndex << std::endl; + depIndex = argIndex; + return d_value; + }else{ + Node val; + int childDepIndex[2] = { argIndex, argIndex }; + for( int i=0; i<2; i++ ){ + //first check the argument, then check default + Node r; + if( i==0 ){ + r = m->getRepresentative( n[ indexOrder[argIndex] ] ); + } + std::map< Node, UfModelTree >::iterator it = d_data.find( r ); + if( it!=d_data.end() ){ + val = it->second.getValue( m, n, indexOrder, childDepIndex[i], argIndex+1 ); + if( !val.isNull() ){ + break; + } + }else{ + //argument is not a defined argument: thus, it depends on this argument + childDepIndex[i] = argIndex+1; + } + } + //update depIndex + depIndex = childDepIndex[0]>childDepIndex[1] ? childDepIndex[0] : childDepIndex[1]; + //Notice() << "Return " << val << ", depIndex = " << depIndex; + //Notice() << " ( " << childDepIndex[0] << ", " << childDepIndex[1] << " )" << std::endl; + return val; + } +} + +Node UfModelTree::getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, std::vector< int >& depIndex, int argIndex ){ + if( argIndex==(int)indexOrder.size() ){ + return d_value; + }else{ + Node val; + bool depArg = false; + //will try concrete value first, then default + for( int i=0; i<2; i++ ){ + Node r; + if( i==0 ){ + r = m->getRepresentative( n[ indexOrder[argIndex] ] ); + } + std::map< Node, UfModelTree >::iterator it = d_data.find( r ); + if( it!=d_data.end() ){ + val = it->second.getValue( m, n, indexOrder, depIndex, argIndex+1 ); + //we have found a value + if( !val.isNull() ){ + if( i==0 ){ + depArg = true; + } + break; + } + } + } + //it depends on this argument if we found it via concrete argument value, + // or if found by default/disequal from some concrete argument value(s). + if( depArg || hasConcreteArgumentDefinition() ){ + if( std::find( depIndex.begin(), depIndex.end(), indexOrder[argIndex] )==depIndex.end() ){ + depIndex.push_back( indexOrder[argIndex] ); + } + } + return val; + } +} + +Node UfModelTree::getFunctionValue(){ + if( !d_data.empty() ){ + Node defaultValue; + std::vector< Node > caseValues; + for( std::map< Node, UfModelTree >::iterator it = d_data.begin(); it != d_data.end(); ++it ){ + if( it->first.isNull() ){ + defaultValue = it->second.getFunctionValue(); + }else{ + caseValues.push_back( NodeManager::currentNM()->mkNode( FUNCTION_CASE, it->first, it->second.getFunctionValue() ) ); + } + } + if( caseValues.empty() && defaultValue.getKind()!=FUNCTION_CASE_SPLIT && defaultValue.getKind()!=FUNCTION_MODEL ){ + return defaultValue; + }else{ + std::vector< Node > children; + if( !caseValues.empty() ){ + children.push_back( NodeManager::currentNM()->mkNode( FUNCTION_CASE_SPLIT, caseValues ) ); + } + if( !defaultValue.isNull() ){ + children.push_back( defaultValue ); + } + return NodeManager::currentNM()->mkNode( FUNCTION_MODEL, children ); + } + }else{ + Assert( !d_value.isNull() ); + return d_value; + } +} + +//simplify function +void UfModelTree::simplify( Node op, Node defaultVal, int argIndex ){ + if( argIndex<(int)op.getType().getNumChildren()-1 ){ + std::vector< Node > eraseData; + //first process the default argument + Node r; + std::map< Node, UfModelTree >::iterator it = d_data.find( r ); + if( it!=d_data.end() ){ + if( !defaultVal.isNull() && it->second.d_value==defaultVal ){ + eraseData.push_back( r ); + }else{ + it->second.simplify( op, defaultVal, argIndex+1 ); + if( !it->second.d_value.isNull() && it->second.isTotal( op, argIndex+1 ) ){ + defaultVal = it->second.d_value; + }else{ + defaultVal = Node::null(); + if( it->second.isEmpty() ){ + eraseData.push_back( r ); + } + } + } + } + //now see if any children can be removed, and simplify the ones that cannot + for( std::map< Node, UfModelTree >::iterator it = d_data.begin(); it != d_data.end(); ++it ){ + if( !it->first.isNull() ){ + if( !defaultVal.isNull() && it->second.d_value==defaultVal ){ + eraseData.push_back( it->first ); + }else{ + it->second.simplify( op, defaultVal, argIndex+1 ); + if( it->second.isEmpty() ){ + eraseData.push_back( it->first ); + } + } + } + } + for( int i=0; i<(int)eraseData.size(); i++ ){ + d_data.erase( eraseData[i] ); + } + } +} + +//is total function +bool UfModelTree::isTotal( Node op, int argIndex ){ + if( argIndex==(int)(op.getType().getNumChildren()-1) ){ + return !d_value.isNull(); + }else{ + Node r; + std::map< Node, UfModelTree >::iterator it = d_data.find( r ); + if( it!=d_data.end() ){ + return it->second.isTotal( op, argIndex+1 ); + }else{ + return false; + } + } +} + +Node UfModelTree::getConstantValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int argIndex ){ + return d_value; +} + +void indent( std::ostream& out, int ind ){ + for( int i=0; i& indexOrder, int ind, int arg ){ + if( !d_data.empty() ){ + for( std::map< Node, UfModelTree >::iterator it = d_data.begin(); it != d_data.end(); ++it ){ + if( !it->first.isNull() ){ + indent( out, ind ); + out << "if x_" << indexOrder[arg] << " == " << it->first << std::endl; + it->second.debugPrint( out, m, indexOrder, ind+2, arg+1 ); + } + } + if( d_data.find( Node::null() )!=d_data.end() ){ + d_data[ Node::null() ].debugPrint( out, m, indexOrder, ind, arg+1 ); + } + }else{ + indent( out, ind ); + out << "return "; + m->printRepresentative( out, d_value ); + //out << " { "; + //for( int i=0; i<(int)d_explicit.size(); i++ ){ + // out << d_explicit[i] << " "; + //} + //out << "}"; + out << std::endl; + } +} + +UfModel::UfModel( Node op, quantifiers::FirstOrderModel* m ) : d_model( m ), d_op( op ), +d_model_constructed( false ){ + d_tree = UfModelTreeOrdered( op ); + TypeNode tn = d_op.getType(); + tn = tn[(int)tn.getNumChildren()-1]; + Assert( tn==NodeManager::currentNM()->booleanType() || tn.isDatatype() || uf::StrongSolverTheoryUf::isRelevantType( tn ) ); + //look at ground assertions + for( size_t i=0; igetTermDatabase()->d_op_map[ d_op ].size(); i++ ){ + Node n = d_model->getTermDatabase()->d_op_map[ d_op ][i]; + d_model->getTermDatabase()->computeModelBasisArgAttribute( n ); + if( !n.getAttribute(NoMatchAttribute()) || n.getAttribute(ModelBasisArgAttribute())==1 ){ + Node r = d_model->getRepresentative( n ); + d_ground_asserts_reps.push_back( r ); + d_ground_asserts.push_back( n ); + } + } + //determine if it is constant + if( !d_ground_asserts.empty() ){ + bool isConstant = true; + for( int i=1; i<(int)d_ground_asserts.size(); i++ ){ + if( d_ground_asserts_reps[0]!=d_ground_asserts_reps[i] ){ + isConstant = false; + break; + } + } + if( isConstant ){ + //set constant value + Node t = d_model->getTermDatabase()->getModelBasisOpTerm( d_op ); + Node r = d_ground_asserts_reps[0]; + setValue( t, r, false ); + setModel(); + Debug("fmf-model-cons") << "Function " << d_op << " is the constant function "; + d_model->printRepresentativeDebug( "fmf-model-cons", r ); + Debug("fmf-model-cons") << std::endl; + } + } +} + +Node UfModel::getIntersection( Node n1, Node n2, bool& isGround ){ + //Notice() << "Get intersection " << n1 << " " << n2 << std::endl; + isGround = true; + std::vector< Node > children; + children.push_back( n1.getOperator() ); + for( int i=0; i<(int)n1.getNumChildren(); i++ ){ + if( n1[i]==n2[i] ){ + if( n1[i].getAttribute(ModelBasisAttribute()) ){ + isGround = false; + } + children.push_back( n1[i] ); + }else if( n1[i].getAttribute(ModelBasisAttribute()) ){ + children.push_back( n2[i] ); + }else if( n2[i].getAttribute(ModelBasisAttribute()) ){ + children.push_back( n1[i] ); + }else if( d_model->areEqual( n1[i], n2[i] ) ){ + children.push_back( n1[i] ); + }else{ + return Node::null(); + } + } + return NodeManager::currentNM()->mkNode( APPLY_UF, children ); +} + +void UfModel::setValue( Node n, Node v, bool ground, bool isReq ){ + Assert( !n.isNull() ); + Assert( !v.isNull() ); + d_set_values[ isReq ? 1 : 0 ][ ground ? 1 : 0 ][n] = v; + if( optUsePartialDefaults() ){ + if( !ground ){ + int defSize = (int)d_defaults.size(); + for( int i=0; i& depIndex ){ + return d_tree.getValue( d_model, n, depIndex ); +} + +Node UfModel::getConstantValue( Node n ){ + if( d_model_constructed ){ + return d_tree.getConstantValue( d_model, n ); + }else{ + return Node::null(); + } +} + +Node UfModel::getFunctionValue(){ + if( d_func_value.isNull() && d_model_constructed ){ + d_func_value = d_tree.getFunctionValue(); + } + return d_func_value; +} + +bool UfModel::isConstant(){ + Node gn = d_model->getTermDatabase()->getModelBasisOpTerm( d_op ); + Node n = getConstantValue( gn ); + return !n.isNull(); +} + +bool UfModel::optUsePartialDefaults(){ +#ifdef USE_PARTIAL_DEFAULT_VALUES + return true; +#else + return false; +#endif +} + +void UfModel::setModel(){ + makeModel( d_tree ); + d_model_constructed = true; + d_func_value = Node::null(); + + //for debugging, make sure model satisfies all ground assertions + for( size_t i=0; i::iterator it = d_set_values[j][k].begin(); it != d_set_values[j][k].end(); ++it ){ + tree.setValue( d_model, it->first, it->second, k==1 ); + } + } + } + tree.simplify(); +} + +void UfModel::toStream(std::ostream& out){ + //out << "Function " << d_op << std::endl; + //out << " Type: " << d_op.getType() << std::endl; + //out << " Ground asserts:" << std::endl; + //for( int i=0; i<(int)d_ground_asserts.size(); i++ ){ + // out << " " << d_ground_asserts[i] << " = "; + // d_model->printRepresentative( out, d_ground_asserts[i] ); + // out << std::endl; + //} + //out << " Model:" << std::endl; + + TypeNode t = d_op.getType(); + out << d_op << "( "; + for( int i=0; i<(int)(t.getNumChildren()-1); i++ ){ + out << "x_" << i << " : " << t[i]; + if( i<(int)(t.getNumChildren()-2) ){ + out << ", "; + } + } + out << " ) : " << t[(int)t.getNumChildren()-1] << std::endl; + if( d_tree.isEmpty() ){ + out << " [undefined]" << std::endl; + }else{ + d_tree.debugPrint( out, d_model, 3 ); + out << std::endl; + } + //out << " Phase reqs:" << std::endl; //for( int i=0; i<2; i++ ){ + // for( std::map< Node, std::vector< Node > >::iterator it = d_reqs[i].begin(); it != d_reqs[i].end(); ++it ){ + // out << " " << it->first << std::endl; + // for( int j=0; j<(int)it->second.size(); j++ ){ + // out << " " << it->second[j] << " -> " << (i==1) << std::endl; + // } + // } + //} + //out << std::endl; + //for( int i=0; i<2; i++ ){ + // for( std::map< Node, std::map< Node, std::vector< Node > > >::iterator it = d_eq_reqs[i].begin(); it != d_eq_reqs[i].end(); ++it ){ + // out << " " << "For " << it->first << ":" << std::endl; + // for( std::map< Node, std::vector< Node > >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ + // for( int j=0; j<(int)it2->second.size(); j++ ){ + // out << " " << it2->first << ( i==1 ? "==" : "!=" ) << it2->second[j] << std::endl; + // } + // } + // } + //} +} + +Node UfModel::toIte2( Node fm_node, std::vector< Node >& args, int index, Node defaultNode ){ + if( fm_node.getKind()==FUNCTION_MODEL ){ + if( fm_node[0].getKind()==FUNCTION_CASE_SPLIT ){ + Node retNode; + Node childDefaultNode = defaultNode; + //get new default + if( fm_node.getNumChildren()==2 ){ + childDefaultNode = toIte2( fm_node[1], args, index+1, defaultNode ); + } + retNode = childDefaultNode; + for( int i=(int)fm_node[0].getNumChildren()-1; i>=0; i-- ){ + Node childNode = toIte2( fm_node[0][1], args, index+1, childDefaultNode ); + retNode = NodeManager::currentNM()->mkNode( ITE, args[index].eqNode( fm_node[0][0] ), childNode, retNode ); + } + return retNode; + }else{ + return toIte2( fm_node[0], args, index+1, defaultNode ); + } + }else{ + return fm_node; + } +} + + +void UfModelPreferenceData::setValuePreference( Node f, Node n, Node r, bool isPro ){ + if( std::find( d_values.begin(), d_values.end(), r )==d_values.end() ){ + d_values.push_back( r ); + } + int index = isPro ? 0 : 1; + if( std::find( d_value_pro_con[index][r].begin(), d_value_pro_con[index][r].end(), f )==d_value_pro_con[index][r].end() ){ + d_value_pro_con[index][r].push_back( f ); + } + d_term_pro_con[index][n].push_back( f ); +} + +Node UfModelPreferenceData::getBestDefaultValue( Node defaultTerm, TheoryModel* m ){ + Node defaultVal; + double maxScore = -1; + for( size_t i=0; iprintRepresentativeDebug( "fmf-model-cons", v ); + Debug("fmf-model-cons") << " ) = " << score << std::endl; + if( score>maxScore ){ + defaultVal = v; + maxScore = score; + } + } +#ifdef RECONSIDER_FUNC_DEFAULT_VALUE + if( maxScore<1.0 ){ + //consider finding another value, if possible + Debug("fmf-model-cons-debug") << "Poor choice for default value, score = " << maxScore << std::endl; + TypeNode tn = defaultTerm.getType(); + Node newDefaultVal = m->getDomainValue( tn, d_values ); + if( !newDefaultVal.isNull() ){ + defaultVal = newDefaultVal; + Debug("fmf-model-cons-debug") << "-> Change default value to "; + m->printRepresentativeDebug( "fmf-model-cons-debug", defaultVal ); + Debug("fmf-model-cons-debug") << std::endl; + }else{ + Debug("fmf-model-cons-debug") << "-> Could not find arbitrary element of type " << tn[(int)tn.getNumChildren()-1] << std::endl; + Debug("fmf-model-cons-debug") << " Excluding: "; + for( int i=0; i<(int)d_values.size(); i++ ){ + Debug("fmf-model-cons-debug") << d_values[i] << " "; + } + Debug("fmf-model-cons-debug") << std::endl; + } + } +#endif + //get the default term (this term must be defined non-ground in model) + Debug("fmf-model-cons") << " Choose "; + m->printRepresentativeDebug("fmf-model-cons", defaultVal ); + Debug("fmf-model-cons") << " as default value (" << defaultTerm << ")" << std::endl; + Debug("fmf-model-cons") << " # quantifiers pro = " << d_value_pro_con[0][defaultVal].size() << std::endl; + Debug("fmf-model-cons") << " # quantifiers con = " << d_value_pro_con[1][defaultVal].size() << std::endl; + return defaultVal; +} \ No newline at end of file diff --git a/src/theory/uf/theory_uf_model.h b/src/theory/uf/theory_uf_model.h new file mode 100644 index 000000000..406c7ff3c --- /dev/null +++ b/src/theory/uf/theory_uf_model.h @@ -0,0 +1,216 @@ +/********************* */ +/*! \file theory_uf_model.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Model for Theory UF + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY_UF_MODEL_H +#define __CVC4__THEORY_UF_MODEL_H + +#include "theory/model.h" + +namespace CVC4 { +namespace theory { + +namespace quantifiers{ + class FirstOrderModel; +} + +namespace uf { + +class UfModelTree +{ +public: + UfModelTree(){} + /** the data */ + std::map< Node, UfModelTree > d_data; + /** the value of this tree node (if all paths lead to same value) */ + Node d_value; + /** has concrete argument defintion */ + bool hasConcreteArgumentDefinition(); +public: + //is this model tree empty? + bool isEmpty() { return d_data.empty() && d_value.isNull(); } + //clear + void clear(); + /** setValue function + * + * For each argument of n with ModelBasisAttribute() set to true will be considered default arguments if ground=false + * + */ + void setValue( TheoryModel* m, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex ); + /** getValue function + * + * returns $val, the value of ground term n + * Say n is f( t_0...t_n ) + * depIndex is the index for which every term of the form f( t_0 ... t_depIndex, *,... * ) is equal to $val + * for example, if g( x_0, x_1, x_2 ) := lambda x_0 x_1 x_2. if( x_1==a ) b else c, + * then g( a, a, a ) would return b with depIndex = 1 + * If ground = true, we are asking whether the term n is constant (assumes that all non-model basis arguments are ground) + * + */ + Node getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int& depIndex, int argIndex ); + Node getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, std::vector< int >& depIndex, int argIndex ); + ///** getConstant Value function + // * + // * given term n, where n may contain model basis arguments + // * if n is constant for its entire domain, then this function returns the value of its domain + // * otherwise, it returns null + // * for example, if f( x_0, x_1 ) := if( x_0 = a ) b else if( x_1 = a ) a else b, + // * then f( a, e ) would return b, while f( e, a ) would return null + // * + // */ + Node getConstantValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int argIndex ); + /** getFunctionValue */ + Node getFunctionValue(); + /** simplify function */ + void simplify( Node op, Node defaultVal, int argIndex ); + // is total ? + bool isTotal( Node op, int argIndex ); +public: + void debugPrint( std::ostream& out, TheoryModel* m, std::vector< int >& indexOrder, int ind = 0, int arg = 0 ); +}; + +class UfModelTreeOrdered +{ +private: + Node d_op; + std::vector< int > d_index_order; + UfModelTree d_tree; +public: + UfModelTreeOrdered(){} + UfModelTreeOrdered( Node op ) : d_op( op ){ + TypeNode tn = d_op.getType(); + for( int i=0; i<(int)(tn.getNumChildren()-1); i++ ){ + d_index_order.push_back( i ); + } + } + UfModelTreeOrdered( Node op, std::vector< int >& indexOrder ) : d_op( op ){ + d_index_order.insert( d_index_order.end(), indexOrder.begin(), indexOrder.end() ); + } + bool isEmpty() { return d_tree.isEmpty(); } + void clear() { d_tree.clear(); } + void setValue( TheoryModel* m, Node n, Node v, bool ground = true ){ + d_tree.setValue( m, n, v, d_index_order, ground, 0 ); + } + Node getValue( TheoryModel* m, Node n, int& depIndex ){ + return d_tree.getValue( m, n, d_index_order, depIndex, 0 ); + } + Node getValue( TheoryModel* m, Node n, std::vector< int >& depIndex ){ + return d_tree.getValue( m, n, d_index_order, depIndex, 0 ); + } + Node getConstantValue( TheoryModel* m, Node n ) { + return d_tree.getConstantValue( m, n, d_index_order, 0 ); + } + Node getFunctionValue(){ + return d_tree.getFunctionValue(); + } + void simplify() { d_tree.simplify( d_op, Node::null(), 0 ); } + bool isTotal() { return d_tree.isTotal( d_op, 0 ); } +public: + void debugPrint( std::ostream& out, TheoryModel* m, int ind = 0 ){ + d_tree.debugPrint( out, m, d_index_order, ind ); + } +}; + +class UfModel +{ +private: + quantifiers::FirstOrderModel* d_model; + //the operator this model is for + Node d_op; + //is model constructed + bool d_model_constructed; + //store for set values + std::map< Node, Node > d_set_values[2][2]; +private: + // defaults + std::vector< Node > d_defaults; + Node getIntersection( Node n1, Node n2, bool& isGround ); +public: + UfModel(){} + UfModel( Node op, quantifiers::FirstOrderModel* m ); + ~UfModel(){} + //ground terms for this operator + std::vector< Node > d_ground_asserts; + //the representatives they are equal to + std::vector< Node > d_ground_asserts_reps; + //data structure that stores the model + UfModelTreeOrdered d_tree; + //node equivalent of this model + Node d_func_value; +public: + /** get operator */ + Node getOperator() { return d_op; } + /** debug print */ + void toStream( std::ostream& out ); + /** set value */ + void setValue( Node n, Node v, bool ground = true, bool isReq = true ); + /** get value, return arguments that the value depends on */ + Node getValue( Node n, int& depIndex ); + Node getValue( Node n, std::vector< int >& depIndex ); + /** get constant value */ + Node getConstantValue( Node n ); + /** get function value for this function */ + Node getFunctionValue(); + /** is model constructed */ + bool isModelConstructed() { return d_model_constructed; } + /** is empty */ + bool isEmpty() { return d_ground_asserts.empty(); } + /** is constant */ + bool isConstant(); + /** uses partial default values */ + bool optUsePartialDefaults(); +public: + /** set model */ + void setModel(); + /** clear model */ + void clearModel(); + /** make model */ + void makeModel( UfModelTreeOrdered& tree ); +public: + /** set value preference */ + void setValuePreference( Node f, Node n, bool isPro ); +private: + //helper for to ITE function. + static Node toIte2( Node fm_node, std::vector< Node >& args, int index, Node defaultNode ); +public: + /** to ITE function for function model nodes */ + static Node toIte( Node fm_node, std::vector< Node >& args ) { return toIte2( fm_node, args, 0, Node::null() ); } +}; + +//this class stores temporary information useful to model engine for constructing model +class UfModelPreferenceData +{ +public: + UfModelPreferenceData() : d_reconsiderModel( false ){} + virtual ~UfModelPreferenceData(){} + // preferences for default values + std::vector< Node > d_values; + std::map< Node, std::vector< Node > > d_value_pro_con[2]; + std::map< Node, std::vector< Node > > d_term_pro_con[2]; + bool d_reconsiderModel; + /** set value preference */ + void setValuePreference( Node f, Node n, Node r, bool isPro ); + /** get best default value */ + Node getBestDefaultValue( Node defaultTerm, TheoryModel* m ); +}; + + +} +} +} + +#endif diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp index ebbbb139d..e2dd55174 100644 --- a/src/theory/uf/theory_uf_strong_solver.cpp +++ b/src/theory/uf/theory_uf_strong_solver.cpp @@ -19,8 +19,12 @@ #include "theory/uf/equality_engine.h" #include "theory/uf/theory_uf_instantiator.h" #include "theory/theory_engine.h" +#include "theory/quantifiers/term_database.h" -//#define USE_REGION_SAT +//#define USE_SMART_SPLITS +//#define ONE_SPLIT_REGION +//#define DISABLE_QUICK_CLIQUE_CHECKS +//#define COMBINE_REGIONS_SMALL_INTO_LARGE using namespace std; using namespace CVC4; @@ -29,6 +33,10 @@ using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::uf; +void StrongSolverTheoryUf::ConflictFind::Region::addRep( Node n ) { + setRep( n, true ); +} + void StrongSolverTheoryUf::ConflictFind::Region::takeNode( StrongSolverTheoryUf::ConflictFind::Region* r, Node n ){ //Debug("uf-ss") << "takeNode " << r << " " << n << std::endl; //Debug("uf-ss") << "r : " << std::endl; @@ -64,7 +72,6 @@ void StrongSolverTheoryUf::ConflictFind::Region::takeNode( StrongSolverTheoryUf: } //remove representative r->setRep( n, false ); - //Debug("uf-ss") << "done takeNode " << r << " " << n << std::endl; } void StrongSolverTheoryUf::ConflictFind::Region::combine( StrongSolverTheoryUf::ConflictFind::Region* r ){ @@ -98,29 +105,6 @@ void StrongSolverTheoryUf::ConflictFind::Region::combine( StrongSolverTheoryUf:: r->d_valid = false; } -void StrongSolverTheoryUf::ConflictFind::Region::setRep( Node n, bool valid ){ - Assert( hasRep( n )!=valid ); - if( d_nodes.find( n )==d_nodes.end() && valid ){ - d_nodes[n] = new RegionNodeInfo( d_cf->d_th->getSatContext() ); - } - d_nodes[n]->d_valid = valid; - d_reps_size = d_reps_size + ( valid ? 1 : -1 ); - if( d_testClique.find( n )!=d_testClique.end() && d_testClique[n] ){ - Assert( !valid ); - d_testClique[n] = false; - d_testCliqueSize = d_testCliqueSize - 1; - //remove all splits involving n - for( NodeBoolMap::iterator it = d_splits.begin(); it != d_splits.end(); ++it ){ - if( (*it).second ){ - if( (*it).first[0]==n || (*it).first[1]==n ){ - d_splits[ (*it).first ] = false; - d_splitsSize = d_splitsSize - 1; - } - } - } - } -} - /** setEqual */ void StrongSolverTheoryUf::ConflictFind::Region::setEqual( Node a, Node b ){ Assert( hasRep( a ) && hasRep( b ) ); @@ -170,13 +154,47 @@ void StrongSolverTheoryUf::ConflictFind::Region::setDisequal( Node n1, Node n2, } } +void StrongSolverTheoryUf::ConflictFind::Region::setRep( Node n, bool valid ){ + Assert( hasRep( n )!=valid ); + if( valid && d_nodes.find( n )==d_nodes.end() ){ + d_nodes[n] = new RegionNodeInfo( d_cf->d_th->getSatContext() ); + } + d_nodes[n]->d_valid = valid; + d_reps_size = d_reps_size + ( valid ? 1 : -1 ); + //removing a member of the test clique from this region + if( d_testClique.find( n )!=d_testClique.end() && d_testClique[n] ){ + Assert( !valid ); + d_testClique[n] = false; + d_testCliqueSize = d_testCliqueSize - 1; + //remove all splits involving n + for( NodeBoolMap::iterator it = d_splits.begin(); it != d_splits.end(); ++it ){ + if( (*it).second ){ + if( (*it).first[0]==n || (*it).first[1]==n ){ + d_splits[ (*it).first ] = false; + d_splitsSize = d_splitsSize - 1; + } + } + } + } +} + bool StrongSolverTheoryUf::ConflictFind::Region::isDisequal( Node n1, Node n2, int type ){ RegionNodeInfo::DiseqList* del = d_nodes[ n1 ]->d_disequalities[type]; return del->d_disequalities.find( n2 )!=del->d_disequalities.end() && del->d_disequalities[n2]; } +struct sortInternalDegree { + StrongSolverTheoryUf::ConflictFind::Region* r; + bool operator() (Node i,Node j) { return (r->d_nodes[i]->getNumInternalDisequalities()>r->d_nodes[j]->getNumInternalDisequalities());} +}; + +struct sortExternalDegree { + StrongSolverTheoryUf::ConflictFind::Region* r; + bool operator() (Node i,Node j) { return (r->d_nodes[i]->getNumExternalDisequalities()>r->d_nodes[j]->getNumExternalDisequalities());} +}; + bool StrongSolverTheoryUf::ConflictFind::Region::getMustCombine( int cardinality ){ - if( d_total_diseq_external>=long(cardinality) ){ + if( Options::current()->ufssRegions && d_total_diseq_external>=long(cardinality) ){ //The number of external disequalities is greater than or equal to cardinality. //Thus, a clique of size cardinality+1 may exist between nodes in d_regions[i] and other regions //Check if this is actually the case: must have n nodes with outgoing degree (cardinality+1-n) for some n>0 @@ -189,7 +207,7 @@ bool StrongSolverTheoryUf::ConflictFind::Region::getMustCombine( int cardinality if( outDeg>=cardinality ){ //we have 1 node of degree greater than (cardinality) return true; - }else if( outDeg>0 ){ + }else if( outDeg>=1 ){ degrees.push_back( outDeg ); if( (int)degrees.size()>=cardinality ){ //we have (cardinality) nodes of degree 1 @@ -199,6 +217,12 @@ bool StrongSolverTheoryUf::ConflictFind::Region::getMustCombine( int cardinality } } } + //static int gmcCount = 0; + //gmcCount++; + //if( gmcCount%100==0 ){ + // std::cout << gmcCount << " " << cardinality << std::endl; + //} + //this should happen relatively infrequently.... std::sort( degrees.begin(), degrees.end() ); for( int i=0; i<(int)degrees.size(); i++ ){ if( degrees[i]>=cardinality+1-((int)degrees.size()-i) ){ @@ -209,15 +233,9 @@ bool StrongSolverTheoryUf::ConflictFind::Region::getMustCombine( int cardinality return false; } -struct sortInternalDegree { - StrongSolverTheoryUf::ConflictFind::Region* r; - bool operator() (Node i,Node j) { return (r->d_nodes[i]->getNumInternalDisequalities()>r->d_nodes[j]->getNumInternalDisequalities());} -}; - - bool StrongSolverTheoryUf::ConflictFind::Region::check( Theory::Effort level, int cardinality, std::vector< Node >& clique ){ if( d_reps_size>long(cardinality) ){ - if( d_reps_size>long(cardinality) && d_total_diseq_internal==d_reps_size*( d_reps_size - 1 ) ){ + if( d_total_diseq_internal==d_reps_size*( d_reps_size - 1 ) ){ //quick clique check, all reps form a clique for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){ if( it->second->d_valid ){ @@ -225,7 +243,7 @@ bool StrongSolverTheoryUf::ConflictFind::Region::check( Theory::Effort level, in } } return true; - }else{ + }else if( Options::current()->ufssRegions || Options::current()->ufssEagerSplits || level==Theory::EFFORT_FULL ){ //build test clique, up to size cardinality+1 if( d_testCliqueSize<=long(cardinality) ){ std::vector< Node > newClique; @@ -233,7 +251,9 @@ bool StrongSolverTheoryUf::ConflictFind::Region::check( Theory::Effort level, in for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){ //if not in the test clique, add it to the set of new members if( it->second->d_valid && ( d_testClique.find( it->first )==d_testClique.end() || !d_testClique[ it->first ] ) ){ + //if( it->second->getNumInternalDisequalities()>cardinality || level==Theory::EFFORT_FULL ){ newClique.push_back( it->first ); + //} } } //choose remaining nodes with the highest degrees @@ -282,8 +302,8 @@ bool StrongSolverTheoryUf::ConflictFind::Region::check( Theory::Effort level, in d_testCliqueSize = d_testCliqueSize + 1; } } - Assert( d_testCliqueSize==long(cardinality+1) ); - if( d_splitsSize==0 ){ + //check if test clique has larger size than cardinality, and forms a clique + if( d_testCliqueSize>=long(cardinality+1) && d_splitsSize==0 ){ //test clique is a clique for( NodeBoolMap::iterator it = d_testClique.begin(); it != d_testClique.end(); ++it ){ if( (*it).second ){ @@ -297,7 +317,31 @@ bool StrongSolverTheoryUf::ConflictFind::Region::check( Theory::Effort level, in return false; } +void StrongSolverTheoryUf::ConflictFind::Region::getRepresentatives( std::vector< Node >& reps ){ + for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){ + RegionNodeInfo* rni = it->second; + if( rni->d_valid ){ + reps.push_back( it->first ); + } + } +} + +void StrongSolverTheoryUf::ConflictFind::Region::getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities ){ + for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){ + RegionNodeInfo* rni = it->second; + if( rni->d_valid ){ + RegionNodeInfo::DiseqList* del = rni->d_disequalities[0]; + for( NodeBoolMap::iterator it2 = del->d_disequalities.begin(); it2 != del->d_disequalities.end(); ++it2 ){ + if( (*it2).second ){ + num_ext_disequalities[ (*it2).first ]++; + } + } + } + } +} + Node StrongSolverTheoryUf::ConflictFind::Region::getBestSplit(){ +#ifndef USE_SMART_SPLITS //take the first split you find for( NodeBoolMap::iterator it = d_splits.begin(); it != d_splits.end(); ++it ){ if( (*it).second ){ @@ -305,6 +349,60 @@ Node StrongSolverTheoryUf::ConflictFind::Region::getBestSplit(){ } } return Node::null(); +#else + std::vector< Node > splits; + for( NodeBoolMap::iterator it = d_splits.begin(); it != d_splits.end(); ++it ){ + if( (*it).second ){ + splits.push_back( (*it).first ); + } + } + if( splits.size()>1 ){ + std::map< Node, std::map< Node, bool > > ops; + Debug("uf-ss-split") << "Choice for splits: " << std::endl; + double maxScore = -1; + int maxIndex; + for( int i=0; i<(int)splits.size(); i++ ){ + Debug("uf-ss-split") << " " << splits[i] << std::endl; + for( int j=0; j<2; j++ ){ + if( ops.find( splits[i][j] )==ops.end() ){ + EqClassIterator eqc( splits[i][j], ((uf::TheoryUF*)d_cf->d_th)->getEqualityEngine() ); + while( !eqc.isFinished() ){ + Node n = (*eqc); + if( n.getKind()==APPLY_UF ){ + ops[ splits[i][j] ][ n.getOperator() ] = true; + } + ++eqc; + } + } + } + //now, compute score + int common[2] = { 0, 0 }; + for( int j=0; j<2; j++ ){ + int j2 = j==0 ? 1 : 0; + for( std::map< Node, bool >::iterator it = ops[ splits[i][j] ].begin(); it != ops[ splits[i][j] ].end(); ++it ){ + if( ops[ splits[i][j2] ].find( it->first )!=ops[ splits[i][j2] ].end() ){ + common[0]++; + }else{ + common[1]++; + } + } + } + double score = ( 1.0 + (double)common[0] )/( 1.0 + (double)common[1] ); + if( score>maxScore ){ + maxScore = score; + maxIndex = i; + } + } + //if( maxIndex!=0 ){ + // std::cout << "Chose maxIndex = " << maxIndex << std::endl; + //} + return splits[maxIndex]; + }else if( !splits.empty() ){ + return splits[0]; + }else{ + return Node::null(); + } +#endif } void StrongSolverTheoryUf::ConflictFind::Region::addSplit( OutputChannel* out ){ @@ -324,15 +422,6 @@ void StrongSolverTheoryUf::ConflictFind::Region::addSplit( OutputChannel* out ){ out->requirePhase( s, true ); } -void StrongSolverTheoryUf::ConflictFind::Region::getRepresentatives( std::vector< Node >& reps ){ - for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){ - RegionNodeInfo* rni = it->second; - if( rni->d_valid ){ - reps.push_back( it->first ); - } - } -} - bool StrongSolverTheoryUf::ConflictFind::Region::minimize( OutputChannel* out ){ if( hasSplits() ){ addSplit( out ); @@ -342,20 +431,6 @@ bool StrongSolverTheoryUf::ConflictFind::Region::minimize( OutputChannel* out ){ } } -void StrongSolverTheoryUf::ConflictFind::Region::getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities ){ - for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){ - RegionNodeInfo* rni = it->second; - if( rni->d_valid ){ - RegionNodeInfo::DiseqList* del = rni->d_disequalities[0]; - for( NodeBoolMap::iterator it2 = del->d_disequalities.begin(); it2 != del->d_disequalities.end(); ++it2 ){ - if( (*it2).second ){ - num_ext_disequalities[ (*it2).first ]++; - } - } - } - } -} - void StrongSolverTheoryUf::ConflictFind::Region::debugPrint( const char* c, bool incClique ){ Debug( c ) << "Num reps: " << d_reps_size << std::endl; for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){ @@ -398,35 +473,6 @@ void StrongSolverTheoryUf::ConflictFind::Region::debugPrint( const char* c, bool } } -void StrongSolverTheoryUf::ConflictFind::combineRegions( int ai, int bi ){ - Debug("uf-ss-region") << "uf-ss: Combine Region #" << bi << " with Region #" << ai << std::endl; - Assert( isValid( ai ) && isValid( bi ) ); - for( std::map< Node, Region::RegionNodeInfo* >::iterator it = d_regions[bi]->d_nodes.begin(); it != d_regions[bi]->d_nodes.end(); ++it ){ - Region::RegionNodeInfo* rni = it->second; - if( rni->d_valid ){ - d_regions_map[ it->first ] = ai; - } - } - //update regions disequal DO_THIS? - d_regions[ai]->combine( d_regions[bi] ); - d_regions[bi]->d_valid = false; -} - -void StrongSolverTheoryUf::ConflictFind::moveNode( Node n, int ri ){ - Debug("uf-ss-region") << "uf-ss: Move node " << n << " to Region #" << ri << std::endl; - Assert( isValid( d_regions_map[ n ] ) ); - Assert( isValid( ri ) ); - ////update regions disequal DO_THIS? - //Region::RegionNodeInfo::DiseqList* del = d_regions[ d_regions_map[n] ]->d_nodes[n]->d_disequalities[0]; - //for( NodeBoolMap::iterator it = del->d_disequalities.begin(); it != del->d_disequalities.end(); ++it ){ - // if( (*it).second ){ - // } - //} - //move node to region ri - d_regions[ri]->takeNode( d_regions[ d_regions_map[n] ], n ); - d_regions_map[n] = ri; -} - int StrongSolverTheoryUf::ConflictFind::getNumDisequalitiesToRegion( Node n, int ri ){ int ni = d_regions_map[n]; int counter = 0; @@ -448,10 +494,6 @@ void StrongSolverTheoryUf::ConflictFind::getDisequalitiesToRegions( int ri, std: Region::RegionNodeInfo::DiseqList* del = it->second->d_disequalities[0]; for( NodeBoolMap::iterator it2 = del->d_disequalities.begin(); it2 != del->d_disequalities.end(); ++it2 ){ if( (*it2).second ){ - //if( !isValid( d_regions_map[ (*it2).first ] ) ){ - // Debug( "uf-ss-temp" ) << "^^^" << ri << " " << d_regions_map[ (*it2).first ].get() << std::endl; - // debugPrint( "uf-ss-temp" ); - //} Assert( isValid( d_regions_map[ (*it2).first ] ) ); //Notice() << "Found disequality with " << (*it2).first << ", region = " << d_regions_map[ (*it2).first ] << std::endl; regions_diseq[ d_regions_map[ (*it2).first ] ]++; @@ -542,18 +584,21 @@ void StrongSolverTheoryUf::ConflictFind::explainClique( std::vector< Node >& cli /** new node */ void StrongSolverTheoryUf::ConflictFind::newEqClass( Node n ){ if( d_regions_map.find( n )==d_regions_map.end() ){ + if( !Options::current()->ufssRegions ){ + //if not using regions, always add new equivalence classes to region index = 0 + d_regions_index = 0; + } d_regions_map[n] = d_regions_index; Debug("uf-ss") << "StrongSolverTheoryUf: New Eq Class " << n << std::endl; Debug("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size() << std::endl; if( d_regions_indexdebugPrint("uf-ss-debug",true); d_regions[ d_regions_index ]->d_valid = true; - //Assert( d_regions[ d_regions_index ]->d_valid ); - Assert( d_regions[ d_regions_index ]->getNumReps()==0 ); + Assert( !Options::current()->ufssRegions || d_regions[ d_regions_index ]->getNumReps()==0 ); }else{ d_regions.push_back( new Region( this, d_th->getSatContext() ) ); } - d_regions[ d_regions_index ]->setRep( n, true ); + d_regions[ d_regions_index ]->addRep( n ); d_regions_index = d_regions_index + 1; d_reps = d_reps + 1; } @@ -571,14 +616,14 @@ void StrongSolverTheoryUf::ConflictFind::merge( Node a, Node b ){ int bi = d_regions_map[b]; Debug("uf-ss") << " regions: " << ai << " " << bi << std::endl; if( ai!=bi ){ - if( d_regions[ai]->getNumReps()==1 ){ - combineRegions( bi, ai ); - d_regions[bi]->setEqual( a, b ); - checkRegion( bi ); + if( d_regions[ai]->getNumReps()==1 ){ + int ri = combineRegions( bi, ai ); + d_regions[ri]->setEqual( a, b ); + checkRegion( ri ); }else if( d_regions[bi]->getNumReps()==1 ){ - combineRegions( ai, bi ); - d_regions[ai]->setEqual( a, b ); - checkRegion( ai ); + int ri = combineRegions( ai, bi ); + d_regions[ri]->setEqual( a, b ); + checkRegion( ri ); }else{ // either move a to d_regions[bi], or b to d_regions[ai] int aex = d_regions[ai]->d_nodes[a]->getNumInternalDisequalities() - getNumDisequalitiesToRegion( a, bi ); @@ -652,7 +697,7 @@ void StrongSolverTheoryUf::ConflictFind::assertCardinality( int c, bool val ){ } } -bool StrongSolverTheoryUf::ConflictFind::checkRegion( int ri, bool rec ){ +void StrongSolverTheoryUf::ConflictFind::checkRegion( int ri, bool rec ){ if( isValid(ri) ){ Assert( d_cardinality>0 ); //first check if region is in conflict @@ -660,61 +705,98 @@ bool StrongSolverTheoryUf::ConflictFind::checkRegion( int ri, bool rec ){ if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){ //explain clique explainClique( clique, &d_th->getOutputChannel() ); - return false; }else if( d_regions[ri]->getMustCombine( d_cardinality ) ){ - //this region must merge with another - Debug("uf-ss-check-region") << "We must combine Region #" << ri << ". " << std::endl; - d_regions[ri]->debugPrint("uf-ss-check-region"); ////alternatively, check if we can reduce the number of external disequalities by moving single nodes //for( std::map< Node, bool >::iterator it = d_regions[i]->d_reps.begin(); it != d_regions[i]->d_reps.end(); ++it ){ // if( it->second ){ // int inDeg = d_regions[i]->d_disequalities_size[1][ it-> first ]; - // int outDeg = d_regions[i]->d_disequalities_size[1][ it-> first ]; + // int outDeg = d_regions[i]->d_disequalities_size[0][ it-> first ]; // if( inDeg regions_diseq; - getDisequalitiesToRegions( ri, regions_diseq ); - for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){ - Debug("uf-ss-check-region") << it->first << " : " << it->second << std::endl; + int riNew = forceCombineRegion( ri, true ); + if( riNew>=0 && rec ){ + checkRegion( riNew, rec ); } - for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){ - Assert( it->first!=ri ); - Assert( isValid( it->first ) ); - Assert( d_regions[ it->first ]->getNumReps()>0 ); - double tempScore = double(it->second)/double(d_regions[it->first]->getNumReps() ); - if( tempScore>maxScore ){ - maxRegion = it->first; - maxScore = tempScore; - } + } + } +} + +int StrongSolverTheoryUf::ConflictFind::forceCombineRegion( int ri, bool useDensity ){ + if( !useDensity ){ + for( int i=0; i<(int)d_regions_index; i++ ){ + if( ri!=i && d_regions[i]->d_valid ){ + return combineRegions( ri, i ); } - Assert( maxRegion!=-1 ); + } + return -1; + }else{ + //this region must merge with another + Debug("uf-ss-check-region") << "We must combine Region #" << ri << ". " << std::endl; + d_regions[ri]->debugPrint("uf-ss-check-region"); + //take region with maximum disequality density + double maxScore = 0; + int maxRegion = -1; + std::map< int, int > regions_diseq; + getDisequalitiesToRegions( ri, regions_diseq ); + for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){ + Debug("uf-ss-check-region") << it->first << " : " << it->second << std::endl; + } + for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){ + Assert( it->first!=ri ); + Assert( isValid( it->first ) ); + Assert( d_regions[ it->first ]->getNumReps()>0 ); + double tempScore = double(it->second)/double(d_regions[it->first]->getNumReps() ); + if( tempScore>maxScore ){ + maxRegion = it->first; + maxScore = tempScore; + } + } + if( maxRegion!=-1 ){ Debug("uf-ss-check-region") << "Combine with region #" << maxRegion << ":" << std::endl; d_regions[maxRegion]->debugPrint("uf-ss-check-region"); - combineRegions( ri, maxRegion ); - if( rec ){ - checkRegion( ri, rec ); - } - //std::vector< Node > clique; - //if( d_regions[ri]->check( Theory::EFFORT_STANDARD, cardinality, clique ) ){ - // //explain clique - // Notice() << "found clique " << std::endl; - //} - return true; + return combineRegions( ri, maxRegion ); } + return -1; } - return false; +} + + +int StrongSolverTheoryUf::ConflictFind::combineRegions( int ai, int bi ){ +#ifdef COMBINE_REGIONS_SMALL_INTO_LARGE + if( d_regions[ai]->getNumReps()getNumReps() ){ + return combineRegions( bi, ai ); + } +#endif + Debug("uf-ss-region") << "uf-ss: Combine Region #" << bi << " with Region #" << ai << std::endl; + Assert( isValid( ai ) && isValid( bi ) ); + for( std::map< Node, Region::RegionNodeInfo* >::iterator it = d_regions[bi]->d_nodes.begin(); it != d_regions[bi]->d_nodes.end(); ++it ){ + Region::RegionNodeInfo* rni = it->second; + if( rni->d_valid ){ + d_regions_map[ it->first ] = ai; + } + } + //update regions disequal DO_THIS? + d_regions[ai]->combine( d_regions[bi] ); + d_regions[bi]->d_valid = false; + return ai; +} + +void StrongSolverTheoryUf::ConflictFind::moveNode( Node n, int ri ){ + Debug("uf-ss-region") << "uf-ss: Move node " << n << " to Region #" << ri << std::endl; + Assert( isValid( d_regions_map[ n ] ) ); + Assert( isValid( ri ) ); + //move node to region ri + d_regions[ri]->takeNode( d_regions[ d_regions_map[n] ], n ); + d_regions_map[n] = ri; } bool StrongSolverTheoryUf::ConflictFind::disambiguateTerms( OutputChannel* out ){ Debug("uf-ss-disamb") << "Disambiguate terms." << std::endl; bool lemmaAdded = false; //otherwise, determine ambiguous pairs of ground terms for relevant sorts - TermDb* db = d_th->getQuantifiersEngine()->getTermDatabase(); + quantifiers::TermDb* db = d_th->getQuantifiersEngine()->getTermDatabase(); for( std::map< Node, std::vector< Node > >::iterator it = db->d_op_map.begin(); it != db->d_op_map.end(); ++it ){ Debug("uf-ss-disamb") << "Check " << it->first << std::endl; if( it->second.size()>1 ){ @@ -798,22 +880,29 @@ void StrongSolverTheoryUf::ConflictFind::check( Theory::Effort level, OutputChan } } } - if( level==Theory::EFFORT_FULL ){ + bool addedLemma = false; + //do splitting on demand + if( level==Theory::EFFORT_FULL || Options::current()->ufssEagerSplits ){ Debug("uf-ss-debug") << "Add splits?" << std::endl; - //see if we have any recommended splits - bool addedLemma = false; + //see if we have any recommended splits from large regions for( int i=0; i<(int)d_regions_index; i++ ){ - if( d_regions[i]->d_valid ){ + if( d_regions[i]->d_valid && d_regions[i]->getNumReps()>d_cardinality ){ if( d_regions[i]->hasSplits() ){ d_regions[i]->addSplit( out ); addedLemma = true; ++( d_th->getStrongSolver()->d_statistics.d_split_lemmas ); +#ifdef ONE_SPLIT_REGION + break; +#endif } } } + } + //force continuation via term disambiguation or combination of regions + if( level==Theory::EFFORT_FULL ){ if( !addedLemma ){ Debug("uf-ss") << "No splits added." << std::endl; - if( Options::current()->fmfRegionSat ){ + if( Options::current()->ufssColoringSat ){ //otherwise, try to disambiguate individual terms if( !disambiguateTerms( out ) ){ //no disequalities can be propagated @@ -825,18 +914,18 @@ void StrongSolverTheoryUf::ConflictFind::check( Theory::Effort level, OutputChan debugPrint("uf-ss-sat"); } }else{ - //naive strategy. combine the first two valid regions - int regIndex = -1; + bool recheck = false; + //naive strategy, force region combination involving the first valid region for( int i=0; i<(int)d_regions_index; i++ ){ if( d_regions[i]->d_valid ){ - if( regIndex==-1 ){ - regIndex = i; - }else{ - combineRegions( regIndex, i ); - check( level, out ); - } + forceCombineRegion( i, false ); + recheck = true; + break; } } + if( recheck ){ + check( level, out ); + } } } } @@ -846,8 +935,7 @@ void StrongSolverTheoryUf::ConflictFind::check( Theory::Effort level, OutputChan void StrongSolverTheoryUf::ConflictFind::propagate( Theory::Effort level, OutputChannel* out ){ Assert( d_cardinality>0 ); - - //propagate the current cardinality as a decision literal + //propagate the current cardinality as a decision literal, if not already asserted Node cn = d_cardinality_literal[ d_cardinality ]; Debug("uf-ss-prop-as-dec") << "Propagate as decision " << d_type << ", cardinality = " << d_cardinality << std::endl; Assert( !cn.isNull() ); @@ -856,7 +944,6 @@ void StrongSolverTheoryUf::ConflictFind::propagate( Theory::Effort level, Output Debug("uf-ss-prop-as-dec") << "Propagate as decision " << d_cardinality_literal[ d_cardinality ]; Debug("uf-ss-prop-as-dec") << " " << d_cardinality_literal[ d_cardinality ][0].getType() << std::endl; } - } void StrongSolverTheoryUf::ConflictFind::debugPrint( const char* c ){ @@ -913,7 +1000,7 @@ void StrongSolverTheoryUf::ConflictFind::setCardinality( int c, OutputChannel* o } void StrongSolverTheoryUf::ConflictFind::getRepresentatives( std::vector< Node >& reps ){ - if( !Options::current()->fmfRegionSat ){ + if( !Options::current()->ufssColoringSat ){ bool foundRegion = false; for( int i=0; i<(int)d_regions_index; i++ ){ //should not have multiple regions at this point @@ -932,6 +1019,8 @@ void StrongSolverTheoryUf::ConflictFind::getRepresentatives( std::vector< Node > } bool StrongSolverTheoryUf::ConflictFind::minimize( OutputChannel* out ){ + //ensure that model forms a clique: + // if two equivalence classes are neither equal nor disequal, add a split int validRegionIndex = -1; for( int i=0; i<(int)d_regions_index; i++ ){ if( d_regions[i]->d_valid ){ @@ -956,10 +1045,9 @@ Node StrongSolverTheoryUf::ConflictFind::getCardinalityLemma(){ if( d_cardinality_lemma.find( d_cardinality )==d_cardinality_lemma.end() ){ if( d_cardinality_lemma_term.isNull() ){ std::stringstream ss; - ss << "fmf_term_" << d_type; + ss << Expr::setlanguage(Options::current()->outputLanguage); + ss << "t_" << d_type; d_cardinality_lemma_term = NodeManager::currentNM()->mkVar( ss.str(), d_type ); - ModelBasisAttribute mba; - d_cardinality_lemma_term.setAttribute(mba,true); } Node lem = NodeManager::currentNM()->mkNode( CARDINALITY_CONSTRAINT, d_cardinality_lemma_term, NodeManager::currentNM()->mkConst( Rational( d_cardinality ) ) ); @@ -1001,8 +1089,6 @@ void StrongSolverTheoryUf::merge( Node a, Node b ){ Debug("uf-ss-solver") << "StrongSolverTheoryUf: Merge " << a << " " << b << " " << tn << std::endl; c->merge( a, b ); } - //else if( isRelevantType( tn ) ){ - //} } /** assert terms are disequal */ @@ -1015,8 +1101,6 @@ void StrongSolverTheoryUf::assertDisequal( Node a, Node b, Node reason ){ //Assert( d_th->d_equalityEngine.getRepresentative( b )==b ); c->assertDisequal( a, b, reason ); } - //else if( isRelevantType( tn ) ){ - //} } /** assert a node */ @@ -1187,14 +1271,14 @@ void StrongSolverTheoryUf::getRepresentatives( TypeNode t, std::vector< Node >& } } -Node StrongSolverTheoryUf::getCardinalityTerm( TypeNode t ){ - ConflictFind* c = getConflictFind( t ); - if( c ){ - return c->getCardinalityTerm(); - }else{ - return Node::null(); - } -} +//Node StrongSolverTheoryUf::getCardinalityTerm( TypeNode t ){ +// ConflictFind* c = getConflictFind( t ); +// if( c ){ +// return c->getCardinalityTerm(); +// }else{ +// return Node::null(); +// } +//} bool StrongSolverTheoryUf::minimize(){ for( std::map< TypeNode, ConflictFind* >::iterator it = d_conf_find.begin(); it != d_conf_find.end(); ++it ){ @@ -1252,7 +1336,8 @@ bool StrongSolverTheoryUf::isRelevantType( TypeNode t ){ t!=NodeManager::currentNM()->realType() && t!=NodeManager::currentNM()->builtinOperatorType() && !t.isFunction() && - !t.isDatatype(); + !t.isDatatype() && + !t.isArray(); } bool StrongSolverTheoryUf::involvesRelevantType( Node n ){ diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h index dde24394a..bd4c4cb22 100644 --- a/src/theory/uf/theory_uf_strong_solver.h +++ b/src/theory/uf/theory_uf_strong_solver.h @@ -29,10 +29,6 @@ namespace CVC4 { namespace theory { - -struct ModelBasisAttributeId {}; -typedef expr::Attribute ModelBasisAttribute; - namespace uf { class TheoryUF; @@ -43,6 +39,7 @@ protected: typedef context::CDHashMap NodeIntMap; typedef context::CDChunkList NodeList; typedef context::CDList BoolList; + typedef context::CDList IntList; typedef context::CDHashMap TypeNodeBoolMap; public: /** information for incremental conflict/clique finding for a particular sort */ @@ -74,7 +71,8 @@ public: DiseqList d_external; public: /** constructor */ - RegionNodeInfo( context::Context* c ) : d_internal( c ), d_external( c ), d_valid( c, true ){ + RegionNodeInfo( context::Context* c ) : + d_internal( c ), d_external( c ), d_valid( c, true ){ d_disequalities[0] = &d_internal; d_disequalities[1] = &d_external; } @@ -103,6 +101,9 @@ public: context::CDO< unsigned > d_total_diseq_external; //total disequality size (internal) context::CDO< unsigned > d_total_diseq_internal; + private: + /** set rep */ + void setRep( Node n, bool valid ); public: //constructor Region( ConflictFind* cf, context::Context* c ) : d_cf( cf ), d_testClique( c ), d_testCliqueSize( c, 0 ), @@ -115,37 +116,40 @@ public: //whether region is valid context::CDO< bool > d_valid; public: - //get num reps - int getNumReps() { return d_reps_size; } - // has representative - bool hasRep( Node n ) { return d_nodes.find( n )!=d_nodes.end() && d_nodes[n]->d_valid; } + /** add rep */ + void addRep( Node n ); //take node from region void takeNode( Region* r, Node n ); //merge with other region void combine( Region* r ); - /** set rep */ - void setRep( Node n, bool valid ); /** merge */ void setEqual( Node a, Node b ); //set n1 != n2 to value 'valid', type is whether it is internal/external void setDisequal( Node n1, Node n2, int type, bool valid ); + public: + //get num reps + int getNumReps() { return d_reps_size; } + //get test clique size + int getTestCliqueSize() { return d_testCliqueSize; } + // has representative + bool hasRep( Node n ) { return d_nodes.find( n )!=d_nodes.end() && d_nodes[n]->d_valid; } // is disequal bool isDisequal( Node n1, Node n2, int type ); - public: /** get must merge */ bool getMustCombine( int cardinality ); - /** check for cliques */ - bool check( Theory::Effort level, int cardinality, std::vector< Node >& clique ); /** has splits */ bool hasSplits() { return d_splitsSize>0; } - /** add split */ - void addSplit( OutputChannel* out ); /** get representatives */ void getRepresentatives( std::vector< Node >& reps ); - /** minimize */ - bool minimize( OutputChannel* out ); /** get external disequalities */ void getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities ); + public: + /** check for cliques */ + bool check( Theory::Effort level, int cardinality, std::vector< Node >& clique ); + /** add split */ + void addSplit( OutputChannel* out ); + /** minimize */ + bool minimize( OutputChannel* out ); //print debug void debugPrint( const char* c, bool incClique = false ); }; @@ -167,22 +171,25 @@ public: /** whether two terms are ambiguous (indexed by equalities) */ NodeBoolMap d_term_amb; private: - /** merge regions */ - void combineRegions( int ai, int bi ); - /** move node n to region ri */ - void moveNode( Node n, int ri ); /** get number of disequalities from node n to region ri */ int getNumDisequalitiesToRegion( Node n, int ri ); /** get number of disequalities from Region r to other regions */ void getDisequalitiesToRegions( int ri, std::map< int, int >& regions_diseq ); - /** check if we need to combine region ri */ - bool checkRegion( int ri, bool rec = true ); /** explain clique */ void explainClique( std::vector< Node >& clique, OutputChannel* out ); /** is valid */ bool isValid( int ri ) { return ri>=0 && ri<(int)d_regions_index && d_regions[ ri ]->d_valid; } /** check ambiguous terms */ bool disambiguateTerms( OutputChannel* out ); + private: + /** check if we need to combine region ri */ + void checkRegion( int ri, bool rec = true ); + /** force combine region */ + int forceCombineRegion( int ri, bool useDensity = true ); + /** merge regions */ + int combineRegions( int ai, int bi ); + /** move node n to region ri */ + void moveNode( Node n, int ri ); private: /** cardinality operating with */ context::CDO< int > d_cardinality; @@ -226,7 +233,7 @@ public: /** get representatives */ void getRepresentatives( std::vector< Node >& reps ); /** get model basis term */ - Node getCardinalityTerm() { return d_cardinality_lemma_term; } + //Node getCardinalityTerm() { return d_cardinality_lemma_term; } /** minimize */ bool minimize( OutputChannel* out ); /** get cardinality lemma */ @@ -293,7 +300,7 @@ public: /** get representatives */ void getRepresentatives( TypeNode t, std::vector< Node >& reps ); /** get cardinality term */ - Node getCardinalityTerm( TypeNode t ); + //Node getCardinalityTerm( TypeNode t ); /** minimize */ bool minimize(); diff --git a/src/theory/uf/theory_uf_type_rules.h b/src/theory/uf/theory_uf_type_rules.h index 34a8a805b..d00b69398 100644 --- a/src/theory/uf/theory_uf_type_rules.h +++ b/src/theory/uf/theory_uf_type_rules.h @@ -70,7 +70,69 @@ public: } return nodeManager->booleanType(); } -};/* class UfTypeRule */ +};/* class CardinalityConstraintTypeRule */ + +class FunctionModelTypeRule { +public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) + throw(TypeCheckingExceptionPrivate) { + TypeNode tn = n[0].getType(check); + if( check ){ + if( n.getNumChildren()==2 ){ + if( n[0].getKind()!=kind::FUNCTION_CASE_SPLIT ){ + throw TypeCheckingExceptionPrivate(n, "improper function model representation : first child must be case split"); + } + TypeNode tn2 = n[1].getType(check); + if( tn!=tn2 ){ + std::stringstream ss; + ss << "function model has inconsistent return types : " << tn << " " << tn2; + throw TypeCheckingExceptionPrivate(n, ss.str()); + } + } + } + return tn; + } +};/* class FunctionModelTypeRule */ + +class FunctionCaseSplitTypeRule { +public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) + throw(TypeCheckingExceptionPrivate) { + TypeNode retType = n[0][1].getType(check); + if( check ){ + TypeNode argType = n[0][0].getType(check); + for( size_t i=0; igetValue(n); -} - bool Valuation::isSatLiteral(TNode n) const { return d_engine->getPropEngine()->isSatLiteral(n); } diff --git a/src/theory/valuation.h b/src/theory/valuation.h index 11467c8db..7f3a00ec1 100644 --- a/src/theory/valuation.h +++ b/src/theory/valuation.h @@ -64,8 +64,6 @@ public: d_engine(engine) { } - Node getValue(TNode n) const; - /* * Return true if n has an associated SAT literal */ diff --git a/src/util/Makefile.am b/src/util/Makefile.am index cded1e5a3..43cc15ec9 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -73,7 +73,9 @@ libutil_la_SOURCES = \ ite_removal.h \ ite_removal.cpp \ node_visitor.h \ - index.h + index.h \ + model.h \ + model.cpp libutil_la_LIBADD = \ @builddir@/libutilcudd.la diff --git a/src/util/dump.h b/src/util/dump.h index 7318af1a5..382092474 100644 --- a/src/util/dump.h +++ b/src/util/dump.h @@ -103,7 +103,7 @@ public: std::string s = ss.str(); CVC4dumpstream(getStream(), d_commands) << CommentCommand(s + " is " + comment) - << DeclareFunctionCommand(s, e.getType()); + << DeclareFunctionCommand(s, e, e.getType()); } } diff --git a/src/util/model.cpp b/src/util/model.cpp new file mode 100644 index 000000000..081624c5d --- /dev/null +++ b/src/util/model.cpp @@ -0,0 +1,15 @@ +/********************* */ +/*! \file model.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief implementation of Model class + **/ \ No newline at end of file diff --git a/src/util/model.h b/src/util/model.h new file mode 100644 index 000000000..7e0f5a723 --- /dev/null +++ b/src/util/model.h @@ -0,0 +1,42 @@ +/********************* */ +/*! \file model.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Model class + **/ + +#include "cvc4_public.h" + +#ifndef __CVC4__MODEL_H +#define __CVC4__MODEL_H + +#include + +namespace CVC4 { + +class Model +{ +public: + virtual void toStream(std::ostream& out) = 0; +};/* class Model */ + +class ModelBuilder +{ +public: + ModelBuilder(){} + virtual ~ModelBuilder(){} + virtual void buildModel( Model* m ) = 0; +};/* class ModelBuilder */ + +}/* CVC4 namespace */ + +#endif /* __CVC4__MODEL_H */ diff --git a/src/util/options.cpp b/src/util/options.cpp index 2352ae503..e9efab5dd 100644 --- a/src/util/options.cpp +++ b/src/util/options.cpp @@ -149,14 +149,22 @@ Options::Options() : instWhenMode(INST_WHEN_FULL_LAST_CALL), eagerInstQuant(false), finiteModelFind(false), - fmfRegionSat(false), + ufssEagerSplits(false), + ufssRegions(true), + ufssColoringSat(false), fmfModelBasedInst(true), + fmfInstGen(true), + fmfOneInstPerRound(false), + fmfInstEngine(false), + fmfRelevantDomain(false), efficientEMatching(false), literalMatchMode(LITERAL_MATCH_NONE), cbqi(false), cbqiSetByUser(false), userPatternsQuant(true), flipDecision(false), + printInstEngine(false), + printModelEngine(false), lemmaOutputChannel(NULL), lemmaInputChannel(NULL), threads(2),// default should be 1 probably, but say 2 for now @@ -275,6 +283,7 @@ Additional CVC4 options:\n\ --enable-symmetry-breaker turns on UF symmetry breaker (Deharbe et al.,\n\ CADE 2011) [on by default only for QF_UF]\n\ --disable-symmetry-breaker turns off UF symmetry breaker\n\ + QUANTIFIERS:\n\ --disable-miniscope-quant disable miniscope quantifiers\n\ --disable-miniscope-quant-fv disable miniscope quantifiers for ground subformulas\n\ --disable-prenex-quant disable prenexing of quantified formulas\n\ @@ -282,18 +291,26 @@ Additional CVC4 options:\n\ --cnf-quant apply CNF conversion to quantified formulas\n\ --pre-skolem-quant apply skolemization eagerly to bodies of quantified formulas\n\ --disable-smart-triggers disable smart triggers\n\ - --register-quant-body-terms consider terms within bodies of quantified formulas for matching\n\ + --register-quant-body-terms consider ground terms within bodies of quantified formulas for matching\n\ --inst-when=MODE when to apply instantiation\n\ --eager-inst-quant apply quantifier instantiation eagerly\n\ - --finite-model-find use finite model finding heuristic for quantifier instantiation\n\ - --use-fmf-region-sat use region-based SAT heuristic for finite model finding\n\ - --disable-fmf-model-inst disable model-based instantiation for finite model finding\n\ --efficient-e-matching use efficient E-matching\n\ --literal-matching=MODE choose literal matching mode\n\ --enable-cbqi turns on counterexample-based quantifier instantiation [off by default]\n\ --disable-cbqi turns off counterexample-based quantifier instantiation\n\ --ignore-user-patterns ignore user-provided patterns for quantifier instantiation\n\ --enable-flip-decision turns on flip decision heuristic\n\ + FINITE_MODEL_FINDING:\n\ + --finite-model-find use finite model finding heuristic for quantifier instantiation\n\ + --disable-uf-ss-regions disable region-based method for discovering cliques and splits in uf strong solver\n\ + --uf-ss-eager-split add splits eagerly for uf strong solver\n\ + --uf-ss-coloring-sat use coloring-based SAT heuristic for uf strong solver\n\ + --disable-fmf-mbqi disable model-based quantifier instantiation for finite model finding\n\ + --disable-fmf-inst-gen disable Inst-Gen instantiation techniques for finite model finding\n\ + --fmf-one-inst-per-round only add one instantiation per quantifier per round for fmf\n\ + --fmf-inst-engine use instantiation engine in conjunction with finite model finding\n\ + --fmf-relevant-domain use relevant domain computation, similar to complete instantiation (Ge, deMoura 09)\n\ + OTHER:\n\ --disable-dio-solver turns off Linear Diophantine Equation solver (Griggio, JSAT 2012)\n\ --disable-arith-rewrite-equalities turns off the preprocessing rewrite turning equalities into a conjunction of inequalities.\n\ --threads=N sets the number of solver threads\n\ @@ -379,6 +396,36 @@ justification-must\n\ + near leaves (don't expect it to work well) [Unimplemented]\n\ "; +static const string instWhenHelp = "\ +Modes currently supported by the --inst-when option:\n\ +\n\ +full\n\ ++ Run instantiation round at full effort, before theory combination.\n\ +\n\ +full-last-call (default)\n\ ++ Alternate running instantiation rounds at full effort and last\n\ + call. In other words, interleave instantiation and theory combination.\n\ +\n\ +last-call\n\ ++ Run instantiation at last call effort, after theory combination.\n\ +\n\ +"; + +static const string literalMatchHelp = "\ +Literal match modes currently supported by the --literal-match option:\n\ +\n\ +none (default)\n\ ++ Do not use literal matching.\n\ +\n\ +predicate\n\ ++ Consider the phase requirements of predicate literals when applying heuristic\n\ + quantifier instantiation. For example, the trigger P( x ) in the quantified \n\ + formula forall( x ). ( P( x ) V ~Q( x ) ) will only be matched with ground\n\ + terms P( t ) where P( t ) is in the equivalence class of false, and likewise\n\ + Q( x ) with Q( s ) where Q( s ) is in the equivalence class of true.\n\ +\n\ +"; + static const string dumpHelp = "\ Dump modes currently supported by the --dump option:\n\ \n\ @@ -581,14 +628,22 @@ enum OptionValue { INST_WHEN, EAGER_INST_QUANT, FINITE_MODEL_FIND, - FMF_REGION_SAT, + DISABLE_UF_SS_REGIONS, + UF_SS_EAGER_SPLIT, + UF_SS_COLORING_SAT, DISABLE_FMF_MODEL_BASED_INST, + DISABLE_FMF_INST_GEN, + FMF_ONE_INST_PER_ROUND, + FMF_INST_ENGINE, + FMF_RELEVANT_DOMAIN, EFFICIENT_E_MATCHING, LITERAL_MATCHING, ENABLE_CBQI, DISABLE_CBQI, IGNORE_USER_PATTERNS, ENABLE_FLIP_DECISION, + PRINT_MODEL_ENGINE, + PRINT_INST_ENGINE, PARALLEL_THREADS, PARALLEL_SEPARATE_OUTPUT, PORTFOLIO_FILTER_LENGTH, @@ -710,14 +765,22 @@ static struct option cmdlineOptions[] = { { "inst-when", required_argument, NULL, INST_WHEN }, { "eager-inst-quant", no_argument, NULL, EAGER_INST_QUANT }, { "finite-model-find", no_argument, NULL, FINITE_MODEL_FIND }, - { "use-fmf-region-sat", no_argument, NULL, FMF_REGION_SAT }, - { "disable-fmf-model-inst", no_argument, NULL, DISABLE_FMF_MODEL_BASED_INST }, + { "disable-uf-ss-regions", no_argument, NULL, DISABLE_UF_SS_REGIONS }, + { "uf-ss-eager-split", no_argument, NULL, UF_SS_EAGER_SPLIT }, + { "uf-ss-coloring-sat", no_argument, NULL, UF_SS_COLORING_SAT }, + { "disable-fmf-mbqi", no_argument, NULL, DISABLE_FMF_MODEL_BASED_INST }, + { "disable-fmf-inst-gen", no_argument, NULL, DISABLE_FMF_INST_GEN }, + { "fmf-one-inst-per-round", no_argument, NULL, FMF_ONE_INST_PER_ROUND }, + { "fmf-inst-engine", no_argument, NULL, FMF_INST_ENGINE }, + { "fmf-relevant-domain", no_argument, NULL, FMF_RELEVANT_DOMAIN }, { "efficient-e-matching", no_argument, NULL, EFFICIENT_E_MATCHING }, { "literal-matching", required_argument, NULL, LITERAL_MATCHING }, { "enable-cbqi", no_argument, NULL, ENABLE_CBQI }, { "disable-cbqi", no_argument, NULL, DISABLE_CBQI }, { "ignore-user-patterns", no_argument, NULL, IGNORE_USER_PATTERNS }, { "enable-flip-decision", no_argument, NULL, ENABLE_FLIP_DECISION }, + { "print-m-e", no_argument, NULL, PRINT_MODEL_ENGINE }, + { "print-i-e", no_argument, NULL, PRINT_INST_ENGINE }, { "threads", required_argument, NULL, PARALLEL_THREADS }, { "separate-output", no_argument, NULL, PARALLEL_SEPARATE_OUTPUT }, { "filter-lemma-length", required_argument, NULL, PORTFOLIO_FILTER_LENGTH }, @@ -1071,7 +1134,7 @@ throw(OptionException) { if(i == 0) { Warning() << "Decision budget is 0. Consider using internal decision heuristic and " << std::endl << " removing this option." << std::endl; - + } decisionOptions.maxRelTimeAsPermille = (unsigned short)i; } @@ -1247,7 +1310,7 @@ throw(OptionException) { } else if(!strcmp(optarg, "last-call")) { instWhenMode = INST_WHEN_LAST_CALL; } else if(!strcmp(optarg, "help")) { - //puts(instWhenHelp.c_str()); + puts(instWhenHelp.c_str()); exit(1); } else { throw OptionException(string("unknown option for --inst-when: `") + @@ -1260,12 +1323,30 @@ throw(OptionException) { case FINITE_MODEL_FIND: finiteModelFind = true; break; - case FMF_REGION_SAT: - fmfRegionSat = true; + case DISABLE_UF_SS_REGIONS: + ufssRegions = false; + break; + case UF_SS_EAGER_SPLIT: + ufssEagerSplits = true; + break; + case UF_SS_COLORING_SAT: + ufssColoringSat = true; break; case DISABLE_FMF_MODEL_BASED_INST: fmfModelBasedInst = false; break; + case DISABLE_FMF_INST_GEN: + fmfInstGen = false; + break; + case FMF_ONE_INST_PER_ROUND: + fmfOneInstPerRound = true; + break; + case FMF_INST_ENGINE: + fmfInstEngine = true; + break; + case FMF_RELEVANT_DOMAIN: + fmfRelevantDomain = true; + break; case EFFICIENT_E_MATCHING: efficientEMatching = true; break; @@ -1277,7 +1358,7 @@ throw(OptionException) { } else if(!strcmp(optarg, "equality")) { literalMatchMode = LITERAL_MATCH_EQUALITY; } else if(!strcmp(optarg, "help")) { - //puts(literalMatchHelp.c_str()); + puts(literalMatchHelp.c_str()); exit(1); } else { throw OptionException(string("unknown option for --literal-matching: `") + @@ -1298,6 +1379,12 @@ throw(OptionException) { case ENABLE_FLIP_DECISION: flipDecision = true; break; + case PRINT_MODEL_ENGINE: + printModelEngine = true; + break; + case PRINT_INST_ENGINE: + printInstEngine = true; + break; case TIME_LIMIT: { int i = atoi(optarg); diff --git a/src/util/options.h b/src/util/options.h index f423260b0..d89265b55 100644 --- a/src/util/options.h +++ b/src/util/options.h @@ -147,7 +147,7 @@ struct CVC4_PUBLIC Options { DecisionMode decisionMode; /** Whether the user set the decision strategy */ bool decisionModeSetByUser; - /** + /** * Extra settings for decision stuff, varies by strategy enabled * - With DECISION_STRATEGY_RELEVANCY * > Least significant bit: true if one should only decide on leaves @@ -414,15 +414,46 @@ struct CVC4_PUBLIC Options { bool finiteModelFind; /** - * Whether to use region-based SAT for finite model finding + * Whether to use eager splitting on demand for finite model finding + */ + bool ufssEagerSplits; + + /** + * Whether to use region-based approach for finite model finding + */ + bool ufssRegions; + + /** + * Whether to use coloring-based methods for determining whether a model of + * currently cardinality exists. */ - bool fmfRegionSat; + bool ufssColoringSat; /** * Whether to use model-based exhaustive instantiation for finite model finding */ bool fmfModelBasedInst; + /** + * Whether to use Inst-Gen techniques for finite model finding + */ + bool fmfInstGen; + + /* + * Whether to only add only instantiation per quantifier per round for finite model finding + */ + bool fmfOneInstPerRound; + + /* + * Whether to use instantiation engine in conjunction with finite model finding + */ + bool fmfInstEngine; + + /* + * Whether to compute relevant domains, in the manner of Complete Instantiation for Quantified Formulas [Ge, deMoura 09] + */ + bool fmfRelevantDomain; + /** * Whether to use efficient E-matching */ @@ -462,6 +493,12 @@ struct CVC4_PUBLIC Options { */ bool flipDecision; + /** + * print details for instantiation/model engine + */ + bool printInstEngine; + bool printModelEngine; + /** The output channel to receive notfication events for new lemmas */ LemmaOutputChannel* lemmaOutputChannel; LemmaInputChannel* lemmaInputChannel; -- 2.30.2