diff options
87 files changed, 5218 insertions, 2906 deletions
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::vector<std::stri } } else { Debug("parser") << " " << *i << " not declared" << std::endl; - PARSER_STATE->mkVar(*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*>( 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" @@ -386,6 +387,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 * support and produce-proofs is on. @@ -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 <stdint.h> @@ -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<Rational>(); - } - 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<Rational>(); - } - 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<Rational>() / - d_valuation.getValue(n[1]).getConst<Rational>() ); - - case kind::LT: // 2 args - return nodeManager->mkConst( d_valuation.getValue(n[0]).getConst<Rational>() < - d_valuation.getValue(n[1]).getConst<Rational>() ); - - case kind::LEQ: // 2 args - return nodeManager->mkConst( d_valuation.getValue(n[0]).getConst<Rational>() <= - d_valuation.getValue(n[1]).getConst<Rational>() ); - - case kind::GT: // 2 args - return nodeManager->mkConst( d_valuation.getValue(n[0]).getConst<Rational>() > - d_valuation.getValue(n[1]).getConst<Rational>() ); - - case kind::GEQ: // 2 args - return nodeManager->mkConst( d_valuation.getValue(n[0]).getConst<Rational>() >= - d_valuation.getValue(n[1]).getConst<Rational>() ); - - 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; i<d_quantEngine->getNumInstantiationConstants( f ); i++ ){ -// Node ic = d_quantEngine->getInstantiationConstant( f, i ); +// for( int i=0; i<d_quantEngine->getTermDatabase()->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 "<<lem<<"\n"; diff --git a/src/theory/arrays/theory_arrays.h b/src/theory/arrays/theory_arrays.h index 25797dda3..6787f8ad8 100644 --- a/src/theory/arrays/theory_arrays.h +++ b/src/theory/arrays/theory_arrays.h @@ -219,7 +219,7 @@ class TheoryArrays : public Theory { private: public: - Node getValue(TNode n); + void collectModelInfo( TheoryModel* m ); ///////////////////////////////////////////////////////////////////////////// // NOTIFICATIONS @@ -346,6 +346,12 @@ class TheoryArrays : public Theory { void queueRowLemma(RowLemmaType lem); void dischargeLemmas(); + public: + + eq::EqualityEngine* getEqualityEngine() { + return &d_equalityEngine; + } + };/* class TheoryArrays */ }/* CVC4::theory::arrays namespace */ diff --git a/src/theory/arrays/theory_arrays_instantiator.cpp b/src/theory/arrays/theory_arrays_instantiator.cpp index 334d70eea..2e446c57f 100644 --- a/src/theory/arrays/theory_arrays_instantiator.cpp +++ b/src/theory/arrays/theory_arrays_instantiator.cpp @@ -51,6 +51,35 @@ void InstantiatorTheoryArrays::processResetInstantiationRound( Theory::Effort ef } -int InstantiatorTheoryArrays::process( Node f, Theory::Effort effort, int e, int limitInst ){ +int InstantiatorTheoryArrays::process( Node f, Theory::Effort effort, int e ){ return InstStrategy::STATUS_SAT; } + +bool InstantiatorTheoryArrays::hasTerm( Node a ){ + return ((TheoryArrays*)d_th)->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<bool>()); - } - - 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<bool>()) { - 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<bool>() == v1.getConst<bool>() ); - } - - 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<bool>()); - } - if(! v1.isNull()) { - value = value || v1.getConst<bool>(); - } - 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<bool>()) { - 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<bool>() != v1.getConst<bool>() ); - } - - 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<bool>() ? v1.getConst<bool>() : v2.getConst<bool>() ); - } - - 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<TNode> new_assertions; + std::vector<TNode> 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<TNode>& 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 <map> @@ -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<CongruenceChannel, CONGRUENCE_OPERATORS_2 (kind::APPLY_CONSTRUCTOR, kind::APPLY_SELECTOR)> 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)<long(f[0].getNumChildren()) && ( !imtio || long(index)<long(imtio->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<Node> & 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<Node> & 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,7 +350,7 @@ public: given Node can't match the pattern */ bool nonunifiable( TNode t, const std::vector<Node> & 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 */ @@ -358,18 +358,18 @@ public: /** 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<Node> & 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<Node> & 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<reps.size(); i++ ){
+ d_tmap[ reps[i] ] = i;
+ }
+ d_type_reps[t].insert( d_type_reps[t].begin(), reps.begin(), reps.end() );
+}
+
+void RepSet::toStream(std::ostream& out){
+#if 0
+ for( std::map< TypeNode, std::vector< Node > >::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; i<d_ra.d_type_reps[tn].size(); i++ ){
+ // if( i>0 ){ 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<d_defines.size(); i++ ){
+ if( d_defines[i]==0 ){
+ toStreamFunction( d_define_funcs[funcIndex], out );
+ funcIndex++;
+ }else if( d_defines[i]==1 ){
+ toStreamType( d_define_types[typeIndex], out );
+ typeIndex++;
+ }
+ }
+}
+
+Node TheoryModel::getValue( TNode n ){
+ Debug("model") << "TheoryModel::getValue " << n << std::endl;
+
+ kind::MetaKind metakind = n.getMetaKind();
+
+ //// special case: prop engine handles boolean vars
+ //if(metakind == kind::metakind::VARIABLE && n.getType().isBoolean()) {
+ // Debug("model") << "-> 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; i<d_ra.d_type_reps[tn].size(); i++ ){
+ if( std::find( exclude.begin(), exclude.end(), d_ra.d_type_reps[tn][i] )==exclude.end() ){
+ return d_ra.d_type_reps[tn][i];
+ }
+ }
+ }
+ return Node::null();
+}
+
+//FIXME: use the theory enumerator to generate constants here
+Node TheoryModel::getNewDomainValue( TypeNode tn, bool mkConst ){
+ if( tn==NodeManager::currentNM()->booleanType() ){
+ 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; i<getNumAssertedQuantifiers(); i++ ){
+ Node f = getAssertedQuantifier( i );
+ //initialize model for term
+ initializeModelForTerm( f[1] );
+ }
+
+ if( Options::current()->printModelEngine ){
+ 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<ModelBasisAttributeId, bool> 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<ModelBasisArgAttributeId, uint64_t> 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<Node> 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; i<theory::THEORY_LAST; i++ ){ - if( getQuantifiersEngine()->getInstantiator( 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; q<getQuantifiersEngine()->getNumAssertedQuantifiers(); q++ ){ - Node f = getQuantifiersEngine()->getAssertedQuantifier( q ); + for( int q=0; q<d_quantEngine->getModel()->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; i<theory::THEORY_LAST; i++ ){ - if( getQuantifiersEngine()->getInstantiator( 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; i<theory::THEORY_LAST; i++ ){ - if( getQuantifiersEngine()->getInstantiator( 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 @@ -29,14 +29,13 @@ 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<f[0].getNumChildren(); i++ ){ - d_index_order.push_back( i ); - } - initialize( qe, f, model ); -} - -RepAlphabetIterator::RepAlphabetIterator( QuantifiersEngine* qe, Node f, ModelEngine* model, std::vector< int >& 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; i<f[0].getNumChildren(); i++ ){ - d_ic.push_back( qe->getInstantiationConstant( d_f, i ) ); - d_index.push_back( 0 ); - } - //make the d_var_order mapping - for( size_t i=0; i<d_index_order.size(); i++ ){ - d_var_order[d_index_order[i]] = i; - } - //for testing - d_inst_tried = 0; - d_inst_tests = 0; -} - -void RepAlphabetIterator::increment2( QuantifiersEngine* qe, int counter ){ - Assert( !isFinished() ); - //increment d_index - while( counter>=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; i<qe->getNumInstantiationConstants( 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; i<fm->getNumAssertedQuantifiers(); 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<ind; i++ ){ - Debug( c ) << " "; - } -} - -void UfModelTree::debugPrint( const char* c, QuantifiersEngine* qe, std::vector< int >& 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; i<model.d_ground_asserts.size(); i++ ){ + Node n = model.d_ground_asserts[i]; + Node v = model.d_ground_asserts_reps[i]; //if this assertion did not help the model, just consider it ground //set n = v in the model tree Debug("fmf-model-cons") << " Set " << n << " = "; - printRepresentative( "fmf-model-cons", d_me->getQuantifiersEngine(), 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; i<d_quantEngine->getNumAssertedQuantifiers(); 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; i<d_quantEngine->getModel()->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; i<d_quantEngine->getNumAssertedQuantifiers(); 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; i<d_quantEngine->getModel()->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; i<d_ss->getNumCardinalityTypes(); 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; i<f[0].getNumChildren(); i++ ){ - Debug("inst-fmf-ei") << d_quantEngine->getInstantiationConstant( 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)<getMaxVariableNum(j));} -}; - -void ModelEngine::makeEvalTermIndexOrder( Node n ){ - if( d_eval_term_index_order.find( n )==d_eval_term_index_order.end() ){ - //sort arguments in order of least significant vs. most significant variable in default ordering - std::map< Node, std::vector< int > > 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; i<d_builder.d_quant_selection_lits[f].size(); i++ ){ + Debug("inst-fmf-ei") << " " << d_builder.d_quant_selection_lits[f][i] << std::endl; + } + } + RepSetIterator riter( f, d_quantEngine->getModel() ); + //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( childDepIndex<posDepIndex ){ - posDepIndex = childDepIndex; - if( posDepIndex==-1 ){ - break; - } - } - }else if( eValT==0 ){ - if( eVal==baseVal ){ - eVal = 0; + Debug("ajr-temp") << "* Failed Add instantiation " << m << std::endl; + riter.increment(); } } - } - if( eVal!=0 ){ - depIndex = eVal==-baseVal ? posDepIndex : negDepIndex; - return eVal; - }else{ - return 0; - } - }else if( n.getKind()==IFF || n.getKind()==XOR ){ - int depIndex1; - int eVal = evaluate( rai, n[0], depIndex1 ); - if( eVal!=0 ){ - int depIndex2; - int eVal2 = evaluate( rai, n.getKind()==XOR ? n[1].notNode() : n[1], depIndex2 ); - if( eVal2!=0 ){ - depIndex = depIndex1>depIndex2 ? 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<depIndex; i++ ){ - int index = d_eval_term_use_default_model[n] ? i : d_eval_term_index_order[n][i]; - Debug("fmf-model-eval-debug") << "Add variables from " << index << "..." << std::endl; - fv_deps.insert( fv_deps.end(), children_var_deps[index].begin(), - children_var_deps[index].end() ); - } -#else - //calculate the free variables that the value depends on : take those in children_var_deps[0...depIndex-1] - for( std::map< int, std::vector< Node > >::iterator it = children_var_deps.begin(); it != children_var_deps.end(); ++it ){ - if( it->first<depIndex ){ - fv_deps.insert( fv_deps.end(), it->second.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; i<f[0].getNumChildren(); i++ ){ + totalInst = totalInst * (int)d_quantEngine->getModel()->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; i<d_builder.d_quant_selection_lits[f].size(); i++ ){ + Notice() << " " << d_builder.d_quant_selection_lits[f][i] << std::endl; } - return val; + Notice() << std::endl; } - }else{ - return n; - } -} - -void ModelEngine::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(); -} - -bool ModelEngine::areEqual( Node a, Node b ){ - return d_quantEngine->getEqualityQuery()->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; i<d_active_domain[op][arg].size(); i++ ){
+ int d = d_active_domain[op][arg][i];
+ if( std::find( rd[vi].begin(), rd[vi].end(), d )==rd[vi].end() ){
+ rd[vi].push_back( d );
+ domainChanged = true;
+ }
+ }
+ domainSet = true;
+ }
+ }
+ if( !domainSet ){
+ //otherwise, we must consider the entire domain
+ TypeNode tn = n.getType();
+ if( d_model->d_ra.hasType( tn ) ){
+ if( rd[vi].size()!=d_model->d_ra.d_type_reps[tn].size() ){
+ rd[vi].clear();
+ for( size_t i=0; i<d_model->d_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; i<f[0].getNumChildren(); i++ ){
+ d_index.push_back( 0 );
+ }
+ for( size_t i=0; i<f[0].getNumChildren(); i++ ){
+ //store default index order
+ d_index_order.push_back( i );
+ d_var_order[i] = i;
+ //store default domain
+ d_domain.push_back( RepDomain() );
+ for( int j=0; j<(int)d_model->d_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( childDepIndex<posDepIndex ){
+ posDepIndex = childDepIndex;
+ if( posDepIndex==-1 ){
+ break;
+ }
+ }
+ }else if( eValT==0 ){
+ if( eVal==baseVal ){
+ eVal = 0;
+ }
+ }
+ }
+ if( eVal!=0 ){
+ depIndex = eVal==-baseVal ? posDepIndex : negDepIndex;
+ return eVal;
+ }else{
+ return 0;
+ }
+ }else if( n.getKind()==IFF || n.getKind()==XOR ){
+ int depIndex1;
+ int eVal = evaluate( n[0], depIndex1 );
+ if( eVal!=0 ){
+ int depIndex2;
+ int eVal2 = evaluate( n.getKind()==XOR ? n[1].notNode() : n[1], depIndex2 );
+ if( eVal2!=0 ){
+ depIndex = depIndex1>depIndex2 ? 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; i<argDepIndex; i++ ){
+ int index = d_eval_uf_use_default[n] ? i : d_eval_term_index_order[n][i];
+ Debug("fmf-eval-debug") << "Add variables from " << index << "..." << std::endl;
+ if( children_depIndex[index]>depIndex ){
+ 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)<getMaxVariableNum(j));}
+};
+
+void RepSetEvaluator::makeEvalUfIndexOrder( Node n ){
+ if( d_eval_term_index_order.find( n )==d_eval_term_index_order.end() ){
+#ifdef USE_INDEX_ORDERING
+ //sort arguments in order of least significant vs. most significant variable in default ordering
+ std::map< Node, std::vector< int > > 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; i<t.getNumChildren()-1; i++ ){
+ children.push_back( getModelBasisTerm( t[i] ) );
+ }
+ d_model_basis_op_term[op] = NodeManager::currentNM()->mkNode( 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<Node> & vars,
+ const std::vector<Node> & 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 <map>
+
+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<Node> & vars,
+ const std::vector<Node> & 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 <map> #include <time.h> #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<Node> QuantifiersEngine::createInstVariable( std::vector<Node> & vars ){ @@ -227,25 +141,9 @@ std::vector<Node> QuantifiersEngine::createInstVariable( std::vector<Node> & 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<Node> & pattern) { for(std::vector<Node>::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; i<theory::THEORY_LAST; i++ ){ + if( getInstantiator( i ) ){ + getInstantiator( i )->resetInstantiationRound( 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<Node> & vars, - const std::vector<Node> & 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; i<theory::THEORY_LAST; i++ ){ + if( d_qe->getInstantiator( 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; i<theory::THEORY_LAST; i++ ){ + if( d_qe->getInstantiator( 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; i<theory::THEORY_LAST; i++ ){ + if( d_qe->getInstantiator( 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; i<theory::THEORY_LAST; i++ ){ + if( d_qe->getInstantiator( 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; i<theory::THEORY_LAST; i++ ){ + // if( d_qe->getInstantiator( 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<Node> 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<Node> createInstVariable( std::vector<Node> & 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<Node> createInstVariable( std::vector<Node> & 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 */ @@ -317,26 +260,6 @@ public: /** 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<Node> & vars, - const std::vector<Node> & 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(); } /** get owner */ @@ -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<bool> 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<bool>(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<TNode>::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<Assertion>::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; i<theory::THEORY_LAST; i++ ){ + if( d_theoryTable[i] ){ + d_theoryTable[i]->collectModelInfo( 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<NodeTheoryPair>& 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<NodeTheoryPair>& explanationVector if (toExplain.node.isConst() && toExplain.node.getConst<bool>()) { ++ i; continue; - } + } if (toExplain.node.getKind() == kind::NOT && toExplain.node[0].isConst() && !toExplain.node[0].getConst<bool>()) { ++ i; continue; @@ -1219,7 +1236,7 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& 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<NodeTheoryPair>& explanationVector explanationVector.push_back(newExplain); ++ i; } - + // Keep only the relevant literals explanationVector.resize(j); -} +} void TheoryEngine::ppUnconstrainedSimp(vector<Node>& 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<Node, Node, NodeHashFunction> NodeMap; typedef std::hash_map<TNode, Node, TNodeHashFunction> 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; @@ -433,6 +443,13 @@ public: } /** + * Get a pointer to the underlying sat context. + */ + inline context::Context* getSatContext() const { + return d_context; + } + + /** * Get a pointer to the underlying quantifiers engine. */ theory::QuantifiersEngine* getQuantifiersEngine() const { @@ -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<Node>& 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( nqfsi<nqfsj ){ @@ -54,7 +55,7 @@ void InstStrategyCheckCESolved::processResetInstantiationRound( Theory::Effort e } } -int InstStrategyCheckCESolved::process( Node f, Theory::Effort effort, int e, int instLimit ){ +int InstStrategyCheckCESolved::process( Node f, Theory::Effort effort, int e ){ if( e==0 ){ //calc solved if not done so already if( d_solved.find( f )==d_solved.end() ){ @@ -68,7 +69,7 @@ int InstStrategyCheckCESolved::process( Node f, Theory::Effort effort, int e, in //d_quantEngine->d_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; j<d_quantEngine->getTermDatabase()->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<=j<n.getNumChildren() +# if( args[argIndex]=n[i][0] for some i) +# return getValueFM( n[i][1], args, argIndex+1 ); +# else +# return null; +# + +operator FUNCTION_MODEL 1:2 "function model" +typerule FUNCTION_MODEL ::CVC4::theory::uf::FunctionModelTypeRule + +operator FUNCTION_CASE_SPLIT 1: "function case split" +typerule FUNCTION_CASE_SPLIT ::CVC4::theory::uf::FunctionCaseSplitTypeRule + +operator FUNCTION_CASE 2 "function case" +typerule FUNCTION_CASE ::CVC4::theory::uf::FunctionCaseTypeRule + endtheory diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp index 5d36cd082..ac194d5ed 100644 --- a/src/theory/uf/theory_uf.cpp +++ b/src/theory/uf/theory_uf.cpp @@ -20,6 +20,7 @@ #include "theory/uf/theory_uf.h" #include "theory/uf/theory_uf_instantiator.h" #include "theory/uf/theory_uf_strong_solver.h" +#include "theory/model.h" using namespace std; using namespace CVC4; @@ -173,6 +174,10 @@ Node TheoryUF::explain(TNode literal) { return mkAnd(assumptions); } +void TheoryUF::collectModelInfo( TheoryModel* m ){ + m->assertEqualityEngine( &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<bool>(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<Node, bool, NodeHashFunction> BoolMap; typedef context::CDHashMap<Node, int, NodeHashFunction> 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<ind; i++ ){
+ out << " ";
+ }
+}
+
+void UfModelTree::debugPrint( std::ostream& out, TheoryModel* m, std::vector< int >& 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; i<d_model->getTermDatabase()->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<defSize; i++ ){
+ bool isGround;
+ //for soundness, to allow variable order-independent function interpretations,
+ // we must ensure that the intersection of all default terms
+ // is also defined.
+ //for example, if we have that f( e, a ) = ..., and f( b, e ) = ...,
+ // then we must define f( b, a ).
+ Node ni = getIntersection( n, d_defaults[i], isGround );
+ if( !ni.isNull() ){
+ //if the intersection exists, and is not already defined
+ if( d_set_values[0][ isGround ? 1 : 0 ].find( ni )==d_set_values[0][ isGround ? 1 : 0 ].end() &&
+ d_set_values[1][ isGround ? 1 : 0 ].find( ni )==d_set_values[1][ isGround ? 1 : 0 ].end() ){
+ //use the current value
+ setValue( ni, v, isGround, false );
+ }
+ }
+ }
+ d_defaults.push_back( n );
+ }
+ if( isReq && d_set_values[0][ ground ? 1 : 0 ].find( n )!=d_set_values[0][ ground ? 1 : 0 ].end()){
+ d_set_values[0][ ground ? 1 : 0 ].erase( n );
+ }
+ }
+}
+
+Node UfModel::getValue( Node n, int& depIndex ){
+ return d_tree.getValue( d_model, n, depIndex );
+}
+
+Node UfModel::getValue( Node n, std::vector< int >& 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<d_ground_asserts.size(); i++ ){
+ int depIndex;
+ Node n = d_tree.getValue( d_model, d_ground_asserts[i], depIndex );
+ if( n!=d_ground_asserts_reps[i] ){
+ Debug("fmf-bad") << "Bad model : " << d_ground_asserts[i] << " := ";
+ d_model->printRepresentativeDebug("fmf-bad", n );
+ Debug("fmf-bad") << " != ";
+ d_model->printRepresentativeDebug("fmf-bad", d_ground_asserts_reps[i] );
+ Debug("fmf-bad") << std::endl;
+ }
+ }
+}
+
+void UfModel::clearModel(){
+ for( int j=0; j<2; j++ ){
+ for( int k=0; k<2; k++ ){
+ d_set_values[j][k].clear();
+ }
+ }
+ d_tree.clear();
+ d_model_constructed = false;
+}
+
+void UfModel::makeModel( UfModelTreeOrdered& tree ){
+ for( int j=0; j<2; j++ ){
+ for( int k=0; k<2; k++ ){
+ for( std::map< Node, Node >::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; i<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( ";
+ m->printRepresentativeDebug( "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_index<d_regions.size() ){ d_regions[ d_regions_index ]->debugPrint("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<outDeg ){ // } // } //} - //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; + 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()<d_regions[bi]->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<ModelBasisAttributeId, bool> ModelBasisAttribute; - namespace uf { class TheoryUF; @@ -43,6 +39,7 @@ protected: typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap; typedef context::CDChunkList<Node> NodeList; typedef context::CDList<bool> BoolList; + typedef context::CDList<bool> IntList; typedef context::CDHashMap<TypeNode, bool, TypeNodeHashFunction> 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,16 +171,10 @@ 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 */ @@ -184,6 +182,15 @@ public: /** 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; /** type */ @@ -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; i<n.getNumChildren(); i++ ){ + TypeNode argType2 = n[i][0].getType(check); + if( argType!=argType2 ){ + std::stringstream ss; + ss << "function case split has inconsistent argument types : " << argType << " " << argType2; + throw TypeCheckingExceptionPrivate(n, ss.str()); + } + TypeNode retType2 = n[i][1].getType(check); + if( retType!=retType2 ){ + std::stringstream ss; + ss << "function case split has inconsistent return types : " << retType << " " << retType2; + throw TypeCheckingExceptionPrivate(n, ss.str()); + } + } + } + return retType; + } +};/* class FunctionCaseSplitTypeRule */ + + +class FunctionCaseTypeRule { +public: + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) + throw(TypeCheckingExceptionPrivate) { + TypeNode retType = n[1].getType(check); + if( check ){ + TypeNode argType = n[0].getType(check); + } + return retType; + } +};/* class FunctionCaseTypeRule */ + }/* CVC4::theory::uf namespace */ }/* CVC4::theory namespace */ diff --git a/src/theory/valuation.cpp b/src/theory/valuation.cpp index ef02f6278..948a7a130 100644 --- a/src/theory/valuation.cpp +++ b/src/theory/valuation.cpp @@ -55,11 +55,6 @@ bool equalityStatusCompatible(EqualityStatus s1, EqualityStatus s2) { } } - -Node Valuation::getValue(TNode n) const { - return d_engine->getValue(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 <iostream>
+
+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,9 +414,20 @@ 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 @@ -424,6 +435,26 @@ struct CVC4_PUBLIC Options { 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 */ bool efficientEMatching; @@ -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; |