From 4bfa927dac67bbcadf219f70e61f1d123e33944b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fran=C3=A7ois=20Bobot?= Date: Fri, 27 Jul 2012 13:36:32 +0000 Subject: [PATCH] Merge quantifiers2-trunk: - new syntax for rewrite rules - better rewrite rules theory - remove the rewriting with rewrite rules during ppRewrite temporarily - theory can define their own candidate generator - define a general candidate generator (inefficient ask to every theory) - split inst_match between the pattern matching used for quantifiers (inst_match.*) and the one used for rewrite rules (rr_inst_match.*): - the pattern matching is less exhaustive for quantifiers, - the one for rewrite rules can use efficient-e-matching. --- src/context/cdo.h | 4 +- src/context/cdqueue.h | 4 +- src/expr/command.cpp | 213 +++ src/expr/command.h | 63 + src/expr/node.h | 19 + src/parser/smt2/Smt2.g | 123 ++ src/printer/smt2/smt2_printer.cpp | 8 +- src/theory/Makefile.am | 6 +- .../arith/theory_arith_instantiator.cpp | 2 +- .../arrays/theory_arrays_instantiator.cpp | 14 + .../arrays/theory_arrays_instantiator.h | 6 +- src/theory/datatypes/Makefile.am | 3 +- src/theory/datatypes/theory_datatypes.h | 8 + .../theory_datatypes_candidate_generator.h | 67 + .../theory_datatypes_instantiator.cpp | 12 +- .../datatypes/theory_datatypes_instantiator.h | 9 +- src/theory/inst_match.cpp | 77 +- src/theory/inst_match.h | 132 +- src/theory/instantiator_default.cpp | 2 +- .../quantifiers/instantiation_engine.cpp | 4 +- src/theory/quantifiers/model_engine.cpp | 3 +- src/theory/quantifiers/rep_set_iterator.cpp | 2 +- src/theory/quantifiers/term_database.cpp | 689 ++++---- src/theory/quantifiers/term_database.h | 8 +- src/theory/quantifiers/theory_quantifiers.h | 3 +- src/theory/quantifiers_engine.cpp | 279 +++- src/theory/quantifiers_engine.h | 46 +- .../rewriterules/theory_rewriterules.cpp | 328 ++-- src/theory/rewriterules/theory_rewriterules.h | 33 +- .../rewriterules/theory_rewriterules_params.h | 14 +- .../theory_rewriterules_rules.cpp | 131 +- .../theory_rewriterules_type_rules.h | 6 +- src/theory/rr_inst_match.cpp | 1447 +++++++++++++++++ src/theory/rr_inst_match.h | 263 +++ src/theory/rr_inst_match_impl.h | 128 ++ src/theory/rr_trigger.cpp | 523 ++++++ src/theory/rr_trigger.h | 176 ++ src/theory/theory.h | 10 + src/theory/theory_engine.h | 11 +- src/theory/trigger.cpp | 1 + src/theory/trigger.h | 3 + src/theory/uf/equality_engine.cpp | 4 + src/theory/uf/equality_engine.h | 4 +- src/theory/uf/inst_strategy.cpp | 3 +- src/theory/uf/inst_strategy.h | 9 +- .../uf/theory_uf_candidate_generator.cpp | 11 + src/theory/uf/theory_uf_candidate_generator.h | 147 +- src/theory/uf/theory_uf_instantiator.cpp | 595 +++++-- src/theory/uf/theory_uf_instantiator.h | 364 ++++- src/util/options.cpp | 10 +- src/util/options.h | 5 + test/regress/regress0/Makefile.am | 2 +- test/regress/regress0/quantifiers/Makefile.am | 2 - .../regress/regress0/rewriterules/Makefile.am | 7 +- .../rewriterules/datatypes_clark.smt2 | 176 +- .../datatypes_clark_quantification.smt2 | 264 +++ .../regress0/rewriterules/length_gen_010.smt2 | 10 +- .../regress0/rewriterules/native_arrays.smt2 | 34 + .../rewriterules/native_datatypes.smt2 | 33 + .../rewriterules/native_datatypes2.smt2 | 35 + .../reachability_back_to_the_future.smt2 | 54 + ...chability_back_to_the_future_extended.smt2 | 72 + .../reachability_bbttf_eT_arrays.smt2 | 332 ++++ .../reachability_bttf_ext_Thomas.smt2 | 211 +++ .../regress0/rewriterules/relation.smt2 | 27 + .../set_A_new_fast_tableau-base.smt2 | 102 +- .../set_A_new_fast_tableau-base_sat.smt2 | 103 +- .../rewriterules/simulate_rewritting.smt2 | 24 + .../test_efficient_ematching.smt2 | 35 + 69 files changed, 6552 insertions(+), 1003 deletions(-) create mode 100644 src/theory/datatypes/theory_datatypes_candidate_generator.h create mode 100644 src/theory/rr_inst_match.cpp create mode 100644 src/theory/rr_inst_match.h create mode 100644 src/theory/rr_inst_match_impl.h create mode 100644 src/theory/rr_trigger.cpp create mode 100644 src/theory/rr_trigger.h create mode 100644 test/regress/regress0/rewriterules/datatypes_clark_quantification.smt2 create mode 100644 test/regress/regress0/rewriterules/native_arrays.smt2 create mode 100644 test/regress/regress0/rewriterules/native_datatypes.smt2 create mode 100644 test/regress/regress0/rewriterules/native_datatypes2.smt2 create mode 100644 test/regress/regress0/rewriterules/reachability_back_to_the_future.smt2 create mode 100644 test/regress/regress0/rewriterules/reachability_back_to_the_future_extended.smt2 create mode 100644 test/regress/regress0/rewriterules/reachability_bbttf_eT_arrays.smt2 create mode 100644 test/regress/regress0/rewriterules/reachability_bttf_ext_Thomas.smt2 create mode 100644 test/regress/regress0/rewriterules/relation.smt2 create mode 100644 test/regress/regress0/rewriterules/simulate_rewritting.smt2 create mode 100644 test/regress/regress0/rewriterules/test_efficient_ematching.smt2 diff --git a/src/context/cdo.h b/src/context/cdo.h index 025e8e337..1fc1eebe6 100644 --- a/src/context/cdo.h +++ b/src/context/cdo.h @@ -59,7 +59,7 @@ protected: * using the ContextMemoryManager. */ virtual ContextObj* save(ContextMemoryManager* pCMM) { - Debug("context") << "save cdo " << this << " (value " << get() << ")"; + Debug("context") << "save cdo " << this; ContextObj* p = new(pCMM) CDO(*this); Debug("context") << " to " << p << std::endl; return p; @@ -70,7 +70,7 @@ protected: * saved data back from the saved copy using operator= for T. */ virtual void restore(ContextObj* pContextObj) { - //Debug("context") << "restore cdo " << this << " from " << get(); + //Debug("context") << "restore cdo " << this; d_data = ((CDO*) pContextObj)->d_data; //Debug("context") << " to " << get() << std::endl; } diff --git a/src/context/cdqueue.h b/src/context/cdqueue.h index b43217cfe..abdcc0493 100644 --- a/src/context/cdqueue.h +++ b/src/context/cdqueue.h @@ -63,7 +63,7 @@ protected: * We assume that the base class do the job inside their copy constructor. */ ContextObj* save(ContextMemoryManager* pCMM) { - ContextObj* data = new(pCMM) CDQueue(*this); + ContextObj* data = new(pCMM) CDQueue(*this); // We save the d_size in d_lastsave and we should never destruct below this // indices before the corresponding restore. d_lastsave = ParentType::d_size; @@ -83,7 +83,7 @@ protected: * the list pointer and the allocated size are not changed. */ void restore(ContextObj* data) { - CDQueue* qdata = static_cast*>(data); + CDQueue* qdata = static_cast*>(data); d_iter = qdata->d_iter; d_lastsave = qdata->d_lastsave; ParentType::restore(data); diff --git a/src/expr/command.cpp b/src/expr/command.cpp index f4b40cbb3..12830a618 100644 --- a/src/expr/command.cpp +++ b/src/expr/command.cpp @@ -1137,6 +1137,219 @@ Command* DatatypeDeclarationCommand::clone() const { return new DatatypeDeclarationCommand(d_datatypes); } +/* class RewriteRuleCommand */ + +RewriteRuleCommand::RewriteRuleCommand(const VExpr & vars, + const std::vector< Expr> & guards, + const Expr & head, const Expr & body, + Triggers triggers) throw() : + d_vars(vars), d_guards(guards), d_head(head), d_body(body), d_triggers(triggers) { +} + +RewriteRuleCommand::RewriteRuleCommand(const VExpr & vars, + const Expr & head, const Expr & body) throw() : + d_vars(vars), d_head(head), d_body(body) { +} + +const RewriteRuleCommand::VExpr & RewriteRuleCommand::getVars() const throw(){ + return d_vars; +}; +const RewriteRuleCommand::VExpr & RewriteRuleCommand::getGuards() const throw(){ + return d_guards; +}; +const Expr & RewriteRuleCommand::getHead() const throw(){ + return d_head; +}; +const Expr & RewriteRuleCommand::getBody() const throw(){ + return d_body; +}; +const RewriteRuleCommand::Triggers & RewriteRuleCommand::getTriggers() const throw(){ + return d_triggers; +}; + + +void RewriteRuleCommand::invoke(SmtEngine* smtEngine) throw() { + try { + ExprManager* em = smtEngine->getExprManager(); + /** build vars list */ + Expr vars = em->mkExpr(kind::BOUND_VAR_LIST, d_vars); + /** build guards list */ + Expr guards; + if(d_guards.size() == 0) guards = em->mkConst(true); + else if(d_guards.size() == 1) guards = d_guards[0]; + else guards = em->mkExpr(kind::AND,d_guards); + /** build expression */ + Expr expr; + if( d_triggers.empty() ){ + expr = em->mkExpr(kind::RR_REWRITE,vars,guards,d_head,d_body); + } else { + /** build triggers list */ + std::vector vtriggers; + vtriggers.reserve(d_triggers.size()); + for(Triggers::const_iterator i = d_triggers.begin(), + end = d_triggers.end(); i != end; ++i){ + vtriggers.push_back(em->mkExpr(kind::INST_PATTERN,*i)); + } + Expr triggers = em->mkExpr(kind::INST_PATTERN_LIST,vtriggers); + expr = em->mkExpr(kind::RR_REWRITE,vars,guards,d_head,d_body,triggers); + } + smtEngine->assertFormula(expr); + d_commandStatus = CommandSuccess::instance(); + } catch(exception& e) { + d_commandStatus = new CommandFailure(e.what()); + } +} + +Command* RewriteRuleCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) { + /** Convert variables */ + VExpr vars; vars.reserve(d_vars.size()); + for(VExpr::iterator i = d_vars.begin(), end = d_vars.end(); + i == end; ++i){ + vars.push_back(i->exportTo(exprManager, variableMap)); + }; + /** Convert guards */ + VExpr guards; guards.reserve(d_guards.size()); + for(VExpr::iterator i = d_guards.begin(), end = d_guards.end(); + i == end; ++i){ + guards.push_back(i->exportTo(exprManager, variableMap)); + }; + /** Convert triggers */ + Triggers triggers; triggers.resize(d_triggers.size()); + for(size_t i = 0, end = d_triggers.size(); + i < end; ++i){ + triggers[i].reserve(d_triggers[i].size()); + for(VExpr::iterator j = d_triggers[i].begin(), jend = d_triggers[i].end(); + j == jend; ++i){ + triggers[i].push_back(j->exportTo(exprManager, variableMap)); + }; + }; + /** Convert head and body */ + Expr head = d_head.exportTo(exprManager, variableMap); + Expr body = d_body.exportTo(exprManager, variableMap); + /** Create the converted rules */ + return new RewriteRuleCommand(vars,guards,head,body,triggers); +} + +Command* RewriteRuleCommand::clone() const { + return new RewriteRuleCommand(d_vars,d_guards,d_head,d_body,d_triggers); +} + +/* class PropagateRuleCommand */ + +PropagateRuleCommand::PropagateRuleCommand(const VExpr & vars, + const VExpr & guards, + const VExpr & heads, + const Expr & body, + const Triggers triggers, + bool deduction + ) throw() : + d_vars(vars), d_guards(guards), d_heads(heads), d_body(body), d_triggers(triggers), d_deduction(deduction) { +} + +PropagateRuleCommand::PropagateRuleCommand(const VExpr & vars, + const VExpr & heads, + const Expr & body, + bool deduction + ) throw() : + d_vars(vars), d_heads(heads), d_body(body), d_deduction(deduction) { +} + +const PropagateRuleCommand::VExpr & PropagateRuleCommand::getVars() const throw(){ + return d_vars; +}; +const PropagateRuleCommand::VExpr & PropagateRuleCommand::getGuards() const throw(){ + return d_guards; +}; +const PropagateRuleCommand::VExpr & PropagateRuleCommand::getHeads() const throw(){ + return d_heads; +}; +const Expr & PropagateRuleCommand::getBody() const throw(){ + return d_body; +}; +const PropagateRuleCommand::Triggers & PropagateRuleCommand::getTriggers() const throw(){ + return d_triggers; +}; +bool PropagateRuleCommand::isDeduction() const throw(){ + return d_deduction; +}; + + +void PropagateRuleCommand::invoke(SmtEngine* smtEngine) throw() { + try { + ExprManager* em = smtEngine->getExprManager(); + /** build vars list */ + Expr vars = em->mkExpr(kind::BOUND_VAR_LIST, d_vars); + /** build guards list */ + Expr guards; + if(d_guards.size() == 0) guards = em->mkConst(true); + else if(d_guards.size() == 1) guards = d_guards[0]; + else guards = em->mkExpr(kind::AND,d_guards); + /** build heads list */ + Expr heads; + if(d_heads.size() == 1) heads = d_heads[0]; + else heads = em->mkExpr(kind::AND,d_heads); + /** build expression */ + Expr expr; + if( d_triggers.empty() ){ + expr = em->mkExpr(kind::RR_REWRITE,vars,guards,heads,d_body); + } else { + /** build triggers list */ + std::vector vtriggers; + vtriggers.reserve(d_triggers.size()); + for(Triggers::const_iterator i = d_triggers.begin(), + end = d_triggers.end(); i != end; ++i){ + vtriggers.push_back(em->mkExpr(kind::INST_PATTERN,*i)); + } + Expr triggers = em->mkExpr(kind::INST_PATTERN_LIST,vtriggers); + expr = em->mkExpr(kind::RR_REWRITE,vars,guards,heads,d_body,triggers); + } + smtEngine->assertFormula(expr); + d_commandStatus = CommandSuccess::instance(); + } catch(exception& e) { + d_commandStatus = new CommandFailure(e.what()); + } +} + +Command* PropagateRuleCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) { + /** Convert variables */ + VExpr vars; vars.reserve(d_vars.size()); + for(VExpr::iterator i = d_vars.begin(), end = d_vars.end(); + i == end; ++i){ + vars.push_back(i->exportTo(exprManager, variableMap)); + }; + /** Convert guards */ + VExpr guards; guards.reserve(d_guards.size()); + for(VExpr::iterator i = d_guards.begin(), end = d_guards.end(); + i == end; ++i){ + guards.push_back(i->exportTo(exprManager, variableMap)); + }; + /** Convert heads */ + VExpr heads; heads.reserve(d_heads.size()); + for(VExpr::iterator i = d_heads.begin(), end = d_heads.end(); + i == end; ++i){ + heads.push_back(i->exportTo(exprManager, variableMap)); + }; + /** Convert triggers */ + Triggers triggers; triggers.resize(d_triggers.size()); + for(size_t i = 0, end = d_triggers.size(); + i < end; ++i){ + triggers[i].reserve(d_triggers[i].size()); + for(VExpr::iterator j = d_triggers[i].begin(), jend = d_triggers[i].end(); + j == jend; ++i){ + triggers[i].push_back(j->exportTo(exprManager, variableMap)); + }; + }; + /** Convert head and body */ + Expr body = d_body.exportTo(exprManager, variableMap); + /** Create the converted rules */ + return new PropagateRuleCommand(vars,guards,heads,body,triggers); +} + +Command* PropagateRuleCommand::clone() const { + return new PropagateRuleCommand(d_vars,d_guards,d_heads,d_body,d_triggers); +} + + /* output stream insertion operator for benchmark statuses */ std::ostream& operator<<(std::ostream& out, BenchmarkStatus status) throw() { diff --git a/src/expr/command.h b/src/expr/command.h index 123fe0182..9f1722f9f 100644 --- a/src/expr/command.h +++ b/src/expr/command.h @@ -599,6 +599,69 @@ public: Command* clone() const; };/* class DatatypeDeclarationCommand */ +class CVC4_PUBLIC RewriteRuleCommand : public Command { +protected: + typedef std::vector< Expr > VExpr; + VExpr d_vars; + VExpr d_guards; + Expr d_head; + Expr d_body; + typedef std::vector< std::vector< Expr > > Triggers; + Triggers d_triggers; +public: + RewriteRuleCommand(const VExpr & vars, + const std::vector< Expr> & guards, + const Expr & head, const Expr & body, + Triggers d_triggers + ) throw(); + RewriteRuleCommand(const VExpr & vars, + const Expr & head, const Expr & body) throw(); + ~RewriteRuleCommand() throw() {} + const VExpr & getVars() const throw(); + const VExpr & getGuards() const throw(); + const Expr & getHead() const throw(); + const Expr & getBody() const throw(); + const Triggers & getTriggers() const throw(); + void invoke(SmtEngine* smtEngine) throw(); + Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap); + Command* clone() const; +};/* class RewriteRuleCommand */ + +class CVC4_PUBLIC PropagateRuleCommand : public Command { +protected: + typedef std::vector< Expr > VExpr; + VExpr d_vars; + VExpr d_guards; + VExpr d_heads; + Expr d_body; + typedef std::vector< std::vector< Expr > > Triggers; + Triggers d_triggers; + bool d_deduction; +public: + PropagateRuleCommand(const VExpr & vars, + const VExpr & guards, + const VExpr & heads, + const Expr & body, + Triggers d_triggers, + /* true if we want a deduction rule */ + bool d_deduction = false + ) throw(); + PropagateRuleCommand(const VExpr & vars, + const VExpr & heads, const Expr & body, + bool d_deduction = false) throw(); + ~PropagateRuleCommand() throw() {} + const VExpr & getVars() const throw(); + const VExpr & getGuards() const throw(); + const VExpr & getHeads() const throw(); + const Expr & getBody() const throw(); + const Triggers & getTriggers() const throw(); + bool isDeduction() const throw(); + void invoke(SmtEngine* smtEngine) throw(); + Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap); + Command* clone() const; +};/* class PropagateRuleCommand */ + + class CVC4_PUBLIC QuitCommand : public Command { public: QuitCommand() throw(); diff --git a/src/expr/node.h b/src/expr/node.h index 0b150d25d..b0fda3354 100644 --- a/src/expr/node.h +++ b/src/expr/node.h @@ -892,6 +892,25 @@ inline std::ostream& operator<<(std::ostream& out, TNode n) { return out; } +/** + * Serializes a vector of node to the given stream. + * + * @param out the output stream to use + * @param ns the vector of nodes to output to the stream + * @return the stream + */ +template +inline std::ostream& operator<<(std::ostream& out, + const std::vector< NodeTemplate > & ns) { + for(typename std::vector< NodeTemplate >::const_iterator + i=ns.begin(), end=ns.end(); + i != end; ++i){ + out << *i; + } + return out; +} + + }/* CVC4 namespace */ #include diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g index be5a797bf..56fa93a94 100644 --- a/src/parser/smt2/Smt2.g +++ b/src/parser/smt2/Smt2.g @@ -398,6 +398,126 @@ extendedCommand[CVC4::Command*& cmd] } | { cmd = new EchoCommand(); } ) + | rewriterulesCommand[cmd] + ; + +rewriterulesCommand[CVC4::Command*& cmd] +@declarations { + std::vector > sortedVarNames; + std::vector args, guards, heads, triggers; + Expr head, body, expr, expr2, bvl; + Kind kind; +} + : /* rewrite rules */ + REWRITE_RULE_TOK + LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK + { + kind = CVC4::kind::RR_REWRITE; + PARSER_STATE->pushScope(); + for(std::vector >::const_iterator i = + sortedVarNames.begin(), iend = sortedVarNames.end(); + i != iend; + ++i) { + args.push_back(PARSER_STATE->mkVar((*i).first, (*i).second)); + } + bvl = MK_EXPR(kind::BOUND_VAR_LIST, args); + } + LPAREN_TOK (termList[guards,expr])? RPAREN_TOK + term[head, expr2] term[body, expr2] + LPAREN_TOK ( pattern[expr] { triggers.push_back( expr ); } )* RPAREN_TOK + { + args.clear(); + args.push_back(head); + args.push_back(body); + /* triggers */ + if( !triggers.empty() ){ + expr2 = MK_EXPR(kind::INST_PATTERN_LIST, triggers); + args.push_back(expr2); + }; + expr = MK_EXPR(kind, args); + args.clear(); + args.push_back(bvl); + /* guards */ + switch( guards.size() ){ + case 0: + args.push_back(MK_CONST(bool(true))); break; + case 1: + args.push_back(guards[0]); break; + default: + expr2 = MK_EXPR(kind::AND, guards); + args.push_back(expr2); break; + }; + args.push_back(expr); + expr = MK_EXPR(CVC4::kind::REWRITE_RULE, args); + cmd = new AssertCommand(expr); } + /* propagation rule */ + | rewritePropaKind[kind] + LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK + { + PARSER_STATE->pushScope(); + for(std::vector >::const_iterator i = + sortedVarNames.begin(), iend = sortedVarNames.end(); + i != iend; + ++i) { + args.push_back(PARSER_STATE->mkVar((*i).first, (*i).second)); + } + bvl = MK_EXPR(kind::BOUND_VAR_LIST, args); + } + LPAREN_TOK (termList[guards,expr])? RPAREN_TOK + LPAREN_TOK (termList[heads,expr])? RPAREN_TOK + term[body, expr2] + LPAREN_TOK ( pattern[expr] { triggers.push_back( expr ); } )* RPAREN_TOK + { + args.clear(); + /* heads */ + switch( heads.size() ){ + case 0: + args.push_back(MK_CONST(bool(true))); break; + case 1: + args.push_back(heads[0]); break; + default: + expr2 = MK_EXPR(kind::AND, heads); + args.push_back(expr2); break; + }; + args.push_back(body); + /* triggers */ + if( !triggers.empty() ){ + expr2 = MK_EXPR(kind::INST_PATTERN_LIST, triggers); + args.push_back(expr2); + }; + expr = MK_EXPR(kind, args); + args.clear(); + args.push_back(bvl); + /* guards */ + switch( guards.size() ){ + case 0: + args.push_back(MK_CONST(bool(true))); break; + case 1: + args.push_back(guards[0]); break; + default: + expr2 = MK_EXPR(kind::AND, guards); + args.push_back(expr2); break; + }; + args.push_back(expr); + expr = MK_EXPR(CVC4::kind::REWRITE_RULE, args); + cmd = new AssertCommand(expr); } + ; + +rewritePropaKind[CVC4::Kind& kind] + : + REDUCTION_RULE_TOK { $kind = CVC4::kind::RR_REDUCTION; } + | PROPAGATION_RULE_TOK { $kind = CVC4::kind::RR_DEDUCTION; } + ; + +pattern[CVC4::Expr& expr] +@declarations { + std::vector patexpr; +} + : LPAREN_TOK termList[patexpr,expr] RPAREN_TOK + { + expr = MK_EXPR(kind::INST_PATTERN, patexpr); + //std::cout << "parsed pattern expr " << retExpr << std::endl; + } ; simpleSymbolicExpr[CVC4::SExpr& sexpr] @@ -1076,6 +1196,9 @@ POP_TOK : 'pop'; DECLARE_DATATYPES_TOK : 'declare-datatypes'; GET_MODEL_TOK : 'get-model'; ECHO_TOK : 'echo'; +REWRITE_RULE_TOK : 'assert-rewrite'; +REDUCTION_RULE_TOK : 'assert-reduction'; +PROPAGATION_RULE_TOK : 'assert-propagation'; // attributes ATTRIBUTE_PATTERN_TOK : ':pattern'; diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp index a3b22ac24..892de551c 100644 --- a/src/printer/smt2/smt2_printer.cpp +++ b/src/printer/smt2/smt2_printer.cpp @@ -282,7 +282,7 @@ void Smt2Printer::toStream(std::ostream& out, TNode n, case kind::FORALL: out << "forall "; break; case kind::EXISTS: out << "exists "; break; case kind::BOUND_VAR_LIST: - out << '('; + // the left parenthesis is already printed (before the switch) for(TNode::iterator i = n.begin(), iend = n.end(); i != iend; ) { @@ -290,8 +290,10 @@ void Smt2Printer::toStream(std::ostream& out, TNode n, (*i).toStream(out, toDepth < 0 ? toDepth : toDepth - 1, types, language::output::LANG_SMTLIB_V2); out << ' '; - (*i).getType().toStream(out, toDepth < 0 ? toDepth : toDepth - 1, - false, language::output::LANG_SMTLIB_V2); + out << (*i).getType(); + // The following code do stange things + // (*i).getType().toStream(out, toDepth < 0 ? toDepth : toDepth - 1, + // false, language::output::LANG_SMTLIB_V2); out << ')'; if(++i != iend) { out << ' '; diff --git a/src/theory/Makefile.am b/src/theory/Makefile.am index 1aae03aa5..2bd85f712 100644 --- a/src/theory/Makefile.am +++ b/src/theory/Makefile.am @@ -40,8 +40,12 @@ libtheory_la_SOURCES = \ quantifiers_engine.cpp \ instantiator_default.h \ instantiator_default.cpp \ + rr_inst_match.h \ + rr_inst_match_impl.h \ + rr_inst_match.cpp \ + rr_trigger.h \ + rr_trigger.cpp \ inst_match.h \ - inst_match_impl.h \ inst_match.cpp \ trigger.h \ trigger.cpp \ diff --git a/src/theory/arith/theory_arith_instantiator.cpp b/src/theory/arith/theory_arith_instantiator.cpp index c4cb2f493..ab3a1548e 100644 --- a/src/theory/arith/theory_arith_instantiator.cpp +++ b/src/theory/arith/theory_arith_instantiator.cpp @@ -376,7 +376,7 @@ bool InstantiatorTheoryArith::doInstantiation2( Node f, Node term, ArithVar x, I } instVal = Rewriter::rewrite( instVal ); //use as instantiation value for var - m.d_map[ var ] = instVal; + m.set(var, instVal); Debug("quant-arith") << "Add instantiation " << m << std::endl; return d_quantEngine->addInstantiation( f, m ); } diff --git a/src/theory/arrays/theory_arrays_instantiator.cpp b/src/theory/arrays/theory_arrays_instantiator.cpp index 2e446c57f..ca9001fe5 100644 --- a/src/theory/arrays/theory_arrays_instantiator.cpp +++ b/src/theory/arrays/theory_arrays_instantiator.cpp @@ -17,6 +17,7 @@ #include "theory/theory_engine.h" #include "theory/arrays/theory_arrays_instantiator.h" #include "theory/arrays/theory_arrays.h" +#include "theory/uf/theory_uf_candidate_generator.h" using namespace std; using namespace CVC4; @@ -83,3 +84,16 @@ Node InstantiatorTheoryArrays::getRepresentative( Node a ){ } } +rrinst::CandidateGenerator* InstantiatorTheoryArrays::getRRCanGenClasses(){ + arrays::TheoryArrays* ar = static_cast(getTheory()); + eq::EqualityEngine* ee = + static_cast(ar->getEqualityEngine()); + return new eq::rrinst::CandidateGeneratorTheoryEeClasses(ee); +} + +rrinst::CandidateGenerator* InstantiatorTheoryArrays::getRRCanGenClass(){ + arrays::TheoryArrays* ar = static_cast(getTheory()); + eq::EqualityEngine* ee = + static_cast(ar->getEqualityEngine()); + return new eq::rrinst::CandidateGeneratorTheoryEeClass(ee); +} diff --git a/src/theory/arrays/theory_arrays_instantiator.h b/src/theory/arrays/theory_arrays_instantiator.h index ade43fdb0..f711229b2 100644 --- a/src/theory/arrays/theory_arrays_instantiator.h +++ b/src/theory/arrays/theory_arrays_instantiator.h @@ -21,6 +21,7 @@ #define __CVC4__INSTANTIATOR_THEORY_ARRAYS_H #include "theory/quantifiers_engine.h" +#include "theory/uf/equality_engine.h" namespace CVC4 { namespace theory { @@ -48,10 +49,13 @@ public: bool areEqual( Node a, Node b ); bool areDisequal( Node a, Node b ); Node getRepresentative( Node a ); + /** general creators of candidate generators */ + rrinst::CandidateGenerator* getRRCanGenClasses(); + rrinst::CandidateGenerator* getRRCanGenClass(); };/* class Instantiatior */ } } } -#endif \ No newline at end of file +#endif diff --git a/src/theory/datatypes/Makefile.am b/src/theory/datatypes/Makefile.am index 14bbf64d4..f282ce74d 100644 --- a/src/theory/datatypes/Makefile.am +++ b/src/theory/datatypes/Makefile.am @@ -16,6 +16,7 @@ libdatatypes_la_SOURCES = \ explanation_manager.h \ explanation_manager.cpp \ theory_datatypes_instantiator.h \ - theory_datatypes_instantiator.cpp + theory_datatypes_instantiator.cpp \ + theory_datatypes_candidate_generator.h EXTRA_DIST = kinds diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h index 783c0ebc7..80c20a7d9 100644 --- a/src/theory/datatypes/theory_datatypes.h +++ b/src/theory/datatypes/theory_datatypes.h @@ -38,9 +38,17 @@ namespace theory { namespace datatypes { class InstantiatorTheoryDatatypes; +class EqualityQueryTheory; + +namespace rrinst{ + class CandidateGeneratorTheoryClass; +} class TheoryDatatypes : public Theory { friend class InstantiatorTheoryDatatypes; + friend class EqualityQueryTheory; + friend class rrinst::CandidateGeneratorTheoryClass; + private: typedef context::CDChunkList EqList; typedef context::CDHashMap EqLists; diff --git a/src/theory/datatypes/theory_datatypes_candidate_generator.h b/src/theory/datatypes/theory_datatypes_candidate_generator.h new file mode 100644 index 000000000..46c7ce7fb --- /dev/null +++ b/src/theory/datatypes/theory_datatypes_candidate_generator.h @@ -0,0 +1,67 @@ +/********************* */ +/*! \file theory_uf_candidate generator.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 Theory datatypes candidate generator + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY_DATATYPES_CANDIDATE_GENERATOR_H +#define __CVC4__THEORY_DATATYPES_CANDIDATE_GENERATOR_H + +#include "theory/quantifiers_engine.h" +#include "theory/datatypes/theory_datatypes.h" +#include "theory/rr_inst_match.h" + +namespace CVC4 { +namespace theory { +namespace datatypes { + +namespace rrinst { +typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator; + +// Just iterate amoung the equivalence class of the given node +// node::Null() *can't* be given to reset +class CandidateGeneratorTheoryClass : public CandidateGenerator{ +private: + //instantiator pointer + TheoryDatatypes* d_th; + //the equality class iterator + TheoryDatatypes::EqListN::const_iterator d_eqc_i; + TheoryDatatypes::EqListN* d_eqc; +public: + CandidateGeneratorTheoryClass( TheoryDatatypes* th): d_th( th ), d_eqc(NULL){} + ~CandidateGeneratorTheoryClass(){} + void resetInstantiationRound(){}; + void reset( TNode n ){ + TheoryDatatypes::EqListsN::const_iterator i = d_th->d_equivalence_class.find(n); + if(i == d_th->d_equivalence_class.end()){ + d_eqc = NULL; + } else { + d_eqc = (*i).second; + d_eqc_i = d_eqc->begin(); + } + }; //* the argument is not used + TNode getNextCandidate(){ + if( d_eqc == NULL || d_eqc_i == d_eqc->end() ) return Node::null(); + return *(d_eqc_i++); + }; +}; + + +} +} +} +} + +#endif /* __CVC4__THEORY_DATATYPES_CANDIDATE_GENERATOR_H */ diff --git a/src/theory/datatypes/theory_datatypes_instantiator.cpp b/src/theory/datatypes/theory_datatypes_instantiator.cpp index 9495e4d48..57e9324df 100644 --- a/src/theory/datatypes/theory_datatypes_instantiator.cpp +++ b/src/theory/datatypes/theory_datatypes_instantiator.cpp @@ -15,6 +15,7 @@ **/ #include "theory/datatypes/theory_datatypes_instantiator.h" +#include "theory/datatypes/theory_datatypes_candidate_generator.h" #include "theory/datatypes/theory_datatypes.h" #include "theory/theory_engine.h" #include "theory/quantifiers/term_database.h" @@ -26,9 +27,9 @@ using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::datatypes; -InstantiatorTheoryDatatypes::InstantiatorTheoryDatatypes(context::Context* c, QuantifiersEngine* ie, Theory* th) : -Instantiator( c, ie, th ){ +InstantiatorTheoryDatatypes::InstantiatorTheoryDatatypes(context::Context* c, QuantifiersEngine* ie, TheoryDatatypes* th) : +Instantiator( c, ie, th ){ } void InstantiatorTheoryDatatypes::assertNode( Node assertion ){ @@ -60,7 +61,7 @@ int InstantiatorTheoryDatatypes::process( Node f, Theory::Effort effort, int e ) if( i.getType().isDatatype() ){ Node n = getValueFor( i ); Debug("quant-datatypes-debug") << "Value for " << i << " is " << n << std::endl; - m.d_map[ i ] = n; + m.set(i,n); } } d_quantEngine->addInstantiation( f, m ); @@ -168,3 +169,8 @@ bool InstantiatorTheoryDatatypes::areDisequal( Node a, Node b ){ Node InstantiatorTheoryDatatypes::getRepresentative( Node a ){ return ((TheoryDatatypes*)d_th)->getRepresentative( a ); } + +CVC4::theory::rrinst::CandidateGenerator* InstantiatorTheoryDatatypes::getRRCanGenClass(){ + TheoryDatatypes* th = static_cast(getTheory()); + return new datatypes::rrinst::CandidateGeneratorTheoryClass(th); +} diff --git a/src/theory/datatypes/theory_datatypes_instantiator.h b/src/theory/datatypes/theory_datatypes_instantiator.h index a080465af..fd7190a22 100644 --- a/src/theory/datatypes/theory_datatypes_instantiator.h +++ b/src/theory/datatypes/theory_datatypes_instantiator.h @@ -28,10 +28,12 @@ namespace CVC4 { namespace theory { namespace datatypes { +class TheoryDatatypes; + class InstantiatorTheoryDatatypes : public Instantiator{ friend class QuantifiersEngine; public: - InstantiatorTheoryDatatypes(context::Context* c, QuantifiersEngine* ie, Theory* th); + InstantiatorTheoryDatatypes(context::Context* c, QuantifiersEngine* ie, TheoryDatatypes* th); ~InstantiatorTheoryDatatypes() {} /** assertNode function, assertion is asserted to theory */ @@ -59,10 +61,13 @@ public: bool areEqual( Node a, Node b ); bool areDisequal( Node a, Node b ); Node getRepresentative( Node a ); + /** general creators of candidate generators */ + CVC4::theory::rrinst::CandidateGenerator* getRRCanGenClass(); };/* class InstantiatiorTheoryDatatypes */ + } } } -#endif \ No newline at end of file +#endif diff --git a/src/theory/inst_match.cpp b/src/theory/inst_match.cpp index abcf5aa7f..4f1bfe67e 100644 --- a/src/theory/inst_match.cpp +++ b/src/theory/inst_match.cpp @@ -30,6 +30,7 @@ using namespace CVC4; using namespace CVC4::kind; using namespace CVC4::context; using namespace CVC4::theory; +using namespace CVC4::theory::inst; bool CandidateGenerator::isLegalCandidate( Node n ){ @@ -71,16 +72,24 @@ InstMatch::InstMatch( InstMatch* m ) { d_map = m->d_map; } -bool InstMatch::setMatch( EqualityQuery* q, Node v, Node m ){ - if( d_map.find( v )==d_map.end() ){ - d_map[v] = m; +bool InstMatch::setMatch( EqualityQuery* q, TNode v, TNode m, bool & set ){ + std::map< Node, Node >::iterator vn = d_map.find( v ); + if( vn==d_map.end() ){ + set = true; + this->set(v,m); Debug("matching-debug") << "Add partial " << v << "->" << m << std::endl; return true; }else{ - return q->areEqual( d_map[v], m ); + set = false; + return q->areEqual( vn->second, m ); } } +bool InstMatch::setMatch( EqualityQuery* q, TNode v, TNode m ){ + bool set; + return setMatch(q,v,m,set); +} + bool InstMatch::add( InstMatch& m ){ for( std::map< Node, Node >::iterator it = m.d_map.begin(); it != m.d_map.end(); ++it ){ if( d_map.find( it->first )==d_map.end() ){ @@ -174,7 +183,7 @@ void InstMatch::computeTermVec( const std::vector< Node >& vars, std::vector< No void InstMatchTrie::addInstMatch2( QuantifiersEngine* qe, Node f, InstMatch& m, int index, ImtIndexOrder* imtio ){ if( long(index)d_order.size()) ) ){ int i_index = imtio ? imtio->d_order[index] : index; - Node n = m.d_map[ qe->getTermDatabase()->getInstantiationConstant( f, i_index ) ]; + Node n = m.get( qe->getTermDatabase()->getInstantiationConstant( f, i_index ) ); d_data[n].addInstMatch2( qe, f, m, index+1, imtio ); } } @@ -185,7 +194,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->getTermDatabase()->getInstantiationConstant( f, i_index ) ]; + Node n = m.get( 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 ) ){ @@ -301,10 +310,10 @@ void InstMatchGenerator::initializePattern( Node pat, QuantifiersEngine* qe ){ //we will be producing candidates via literal matching heuristics if( d_pattern.getKind()!=NOT ){ //candidates will be all equalities - d_cg = new uf::CandidateGeneratorTheoryUfLitEq( ith, d_match_pattern ); + d_cg = new uf::inst::CandidateGeneratorTheoryUfLitEq( ith, d_match_pattern ); }else{ //candidates will be all disequalities - d_cg = new uf::CandidateGeneratorTheoryUfLitDeq( ith, d_match_pattern ); + d_cg = new uf::inst::CandidateGeneratorTheoryUfLitDeq( ith, d_match_pattern ); } }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){ Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); @@ -313,20 +322,16 @@ void InstMatchGenerator::initializePattern( Node pat, QuantifiersEngine* qe ){ }else{ Assert( Trigger::isAtomicTrigger( d_match_pattern ) ); //we are matching only in a particular equivalence class - d_cg = new uf::CandidateGeneratorTheoryUf( ith, d_match_pattern.getOperator() ); + d_cg = new uf::inst::CandidateGeneratorTheoryUf( ith, d_match_pattern.getOperator() ); //store the equivalence class that we will call d_cg->reset( ... ) on d_eq_class = d_pattern[1]; } }else if( Trigger::isAtomicTrigger( d_match_pattern ) ){ - if( d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ){ - //we will manually add candidates to queue - d_cg = new CandidateGeneratorQueue; - //register this candidate generator - ith->registerCandidateGenerator( d_cg, d_match_pattern ); - }else{ - //we will be scanning lists trying to find d_match_pattern.getOperator() - d_cg = new uf::CandidateGeneratorTheoryUf( ith, d_match_pattern.getOperator() ); - } + //if( d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ){ + //Warning() << "Currently efficient e matching is not taken into account for quantifiers: " << d_pattern << std::endl; + //} + //we will be scanning lists trying to find d_match_pattern.getOperator() + d_cg = new uf::inst::CandidateGeneratorTheoryUf( ith, d_match_pattern.getOperator() ); }else{ d_cg = new CandidateGeneratorQueue; if( !Trigger::getPatternArithmetic( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){ @@ -347,7 +352,7 @@ void InstMatchGenerator::initializePattern( Node pat, QuantifiersEngine* qe ){ /** get match (not modulo equality) */ 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; + << m.size() << ")" << ", " << d_children.size() << std::endl; Assert( !d_match_pattern.isNull() ); if( qe->d_optMatchIgnoreModelBasis && t.getAttribute(ModelBasisAttribute()) ){ return true; @@ -373,9 +378,9 @@ bool InstMatchGenerator::getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ) //match is in conflict Debug("matching-debug") << "Match in conflict " << t[i] << " and " << d_match_pattern[i] << " because " - << partial[0].d_map[d_match_pattern[i]] + << partial[0].get(d_match_pattern[i]) << std::endl; - Debug("matching-fail") << "Match fail: " << partial[0].d_map[d_match_pattern[i]] << " and " << t[i] << std::endl; + Debug("matching-fail") << "Match fail: " << partial[0].get(d_match_pattern[i]) << " and " << t[i] << std::endl; return false; } } @@ -443,14 +448,14 @@ bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEn for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ Debug("matching-arith") << it->first << " -> " << it->second << std::endl; if( !it->first.isNull() ){ - if( m.d_map.find( it->first )==m.d_map.end() ){ + if( m.find( it->first )==m.end() ){ //see if we can choose this to set if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){ ic = it->first; } }else{ - Debug("matching-arith") << "already set " << m.d_map[ it->first ] << std::endl; - Node tm = m.d_map[ it->first ]; + Debug("matching-arith") << "already set " << m.get( it->first ) << std::endl; + Node tm = m.get( it->first ); if( !it->second.isNull() ){ tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm ); } @@ -473,12 +478,12 @@ bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEn Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst() ); tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm ); } - m.d_map[ ic ] = Rewriter::rewrite( tm ); + m.set( ic, Rewriter::rewrite( tm )); //set the rest to zeros for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ if( !it->first.isNull() ){ - if( m.d_map.find( it->first )==m.d_map.end() ){ - m.d_map[ it->first ] = NodeManager::currentNM()->mkConst( Rational(0) ); + if( m.find( it->first )==m.end() ){ + m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) ) ); } } } @@ -754,7 +759,7 @@ void InstMatchGeneratorMulti::processNewInstantiations( QuantifiersEngine* qe, I }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->getTermDatabase()->getInstantiationConstant( d_f, curr_index ); - if( m.d_map.find( curr_ic )==m.d_map.end() ){ + if( m.find( curr_ic )==m.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 ) ); @@ -765,14 +770,14 @@ void InstMatchGeneratorMulti::processNewInstantiations( QuantifiersEngine* qe, I //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; + mn.set( curr_ic, it->first); processNewInstantiations( qe, mn, addedLemmas, &(it->second), unique_var_tries, trieIndex+1, childIndex, endChildIndex, modEq ); } //} }else{ //shared and set variable, try to merge - Node n = m.d_map[ curr_ic ]; + Node n = m.get( curr_ic ); std::map< Node, InstMatchTrie >::iterator it = tr->d_data.find( n ); if( it!=tr->d_data.end() ){ processNewInstantiations( qe, m, addedLemmas, &(it->second), unique_var_tries, @@ -819,7 +824,7 @@ void InstMatchGeneratorMulti::processNewInstantiations2( QuantifiersEngine* qe, //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; + mn.set( curr_ic, it->first); processNewInstantiations2( qe, mn, addedLemmas, unique_var_tries, uvtIndex, &(it->second), trieIndex+1 ); } }else{ @@ -875,11 +880,11 @@ void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngin Node ic = d_match_pattern[argIndex]; 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; + if( m.get( ic ).isNull() || m.get( ic )==t ){ + Node prev = m.get( ic ); + m.set( ic, t); addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); - m.d_map[ ic ] = prev; + m.set( ic, prev); } } }else{ @@ -897,7 +902,7 @@ int InstMatchGeneratorSimple::addTerm( Node f, Node t, QuantifiersEngine* qe ){ InstMatch m; for( int i=0; i<(int)t.getNumChildren(); i++ ){ if( d_match_pattern[i].getKind()==INST_CONSTANT ){ - m.d_map[d_match_pattern[i]] = t[i]; + m.set(d_match_pattern[i], t[i]); }else if( !qe->getEqualityQuery()->areEqual( d_match_pattern[i], t[i] ) ){ return 0; } diff --git a/src/theory/inst_match.h b/src/theory/inst_match.h index 7cc5b2249..31a59b261 100644 --- a/src/theory/inst_match.h +++ b/src/theory/inst_match.h @@ -44,14 +44,40 @@ typedef expr::Attribute< NoMatchAttributeId, true // context dependent > NoMatchAttribute; +// attribute for "contains instantiation constants from" +struct InstConstantAttributeId {}; +typedef expr::Attribute InstConstantAttribute; + +struct InstLevelAttributeId {}; +typedef expr::Attribute InstLevelAttribute; + +struct InstVarNumAttributeId {}; +typedef expr::Attribute InstVarNumAttribute; + +// Attribute that tell if a node have been asserted in this branch +struct AvailableInTermDbId {}; +/** use the special for boolean flag */ +typedef expr::Attribute AvailableInTermDb; + + class QuantifiersEngine; +namespace quantifiers{ + class TermArgTrie; +} -namespace uf { +namespace uf{ class InstantiatorTheoryUf; class TheoryUF; }/* CVC4::theory::uf namespace */ -class CandidateGenerator { +namespace inst { + +class CandidateGenerator +{ public: CandidateGenerator(){} ~CandidateGenerator(){} @@ -95,7 +121,7 @@ public: class EqualityQuery { public: EqualityQuery(){} - ~EqualityQuery(){} + virtual ~EqualityQuery(){}; /** contains term */ virtual bool hasTerm( Node a ) = 0; /** get the representative of the equivalence class of a */ @@ -113,12 +139,16 @@ public: /** basic class defining an instantiation */ class InstMatch { + /* map from variable to ground terms */ + std::map< Node, Node > d_map; public: InstMatch(); InstMatch( InstMatch* m ); /** set the match of v to m */ - bool setMatch( EqualityQuery* q, Node v, Node m ); + bool setMatch( EqualityQuery* q, TNode v, TNode m ); + /* This version tell if the variable has been set */ + bool setMatch( EqualityQuery* q, TNode v, TNode m, bool & set); /** fill all unfilled values with m */ bool add( InstMatch& m ); /** if compatible, fill all unfilled values with m and return true @@ -140,10 +170,30 @@ public: void computeTermVec( const std::vector< Node >& vars, std::vector< Node >& match ); /** clear */ void clear(){ d_map.clear(); } + /** erase */ + template + void erase(Iterator begin, Iterator end){ + for(Iterator i = begin; i != end; ++i){ + d_map.erase(*i); + }; + } + void erase(Node node){ d_map.erase(node); } /** is_empty */ bool empty(){ return d_map.empty(); } - /* map from variable to ground terms */ - std::map< Node, Node > d_map; + /** set */ + void set(TNode var, TNode n){ + //std::cout << "var.getType() " << var.getType() << "n.getType() " << n.getType() << std::endl ; + Assert( !var.isNull() ); + Assert( n.isNull() ||// For a strange use in inst_match.cpp InstMatchGeneratorSimple::addInstantiations + var.getType() == n.getType() ); + d_map[var] = n; + } + Node get(TNode var){ return d_map[var]; } + size_t size(){ return d_map.size(); } + /* iterator */ + std::map< Node, Node >::iterator begin(){ return d_map.begin(); }; + std::map< Node, Node >::iterator end(){ return d_map.end(); }; + std::map< Node, Node >::iterator find(Node var){ return d_map.find(var); }; /* Node used for matching the trigger only for mono-trigger (just for efficiency because I need only that) */ Node d_matched; @@ -207,67 +257,6 @@ public: } };/* class InstMatchTrieOrdered */ -template -class InstMatchTrie2 { -private: - - class Tree { - public: - typedef std::hash_map< Node, Tree *, NodeHashFunction > MLevel; - MLevel e; - const size_t level; //context level of creation - Tree() CVC4_UNDEFINED; - const Tree & operator =(const Tree & t) CVC4_UNDEFINED; - Tree(size_t l): level(l) {}; - ~Tree(){ - for(typename MLevel::iterator i = e.begin(); i!=e.end(); ++i) - delete(i->second); - }; - };/* class InstMatchTrie2::Tree */ - - - typedef std::pair Mod; - - class CleanUp { - public: - inline void operator()(Mod * m){ - typename Tree::MLevel::iterator i = m->first->e.find(m->second); - Assert (i != m->first->e.end()); //should not have been already removed - m->first->e.erase(i); - } - };/* class InstMatchTrie2::CleanUp */ - - EqualityQuery* d_eQ; - eq::EqualityEngine* d_eE; - - /* before for the order of destruction */ - Tree d_data; - - context::Context* d_context; - context::CDList > d_mods; - - typedef std::map::const_iterator mapIter; - - /** add the substitution given by the iterator*/ - void addSubTree( Tree* root, mapIter current, mapIter end, size_t currLevel); - /** test if it exists match, modulo uf-equations if modEq is true if - * return false the deepest point of divergence is put in [e] and - * [diverge]. - */ - bool existsInstMatch( Tree* root, - mapIter & current, mapIter& end, - Tree*& e, mapIter& diverge) const; - -public: - InstMatchTrie2(context::Context* c, QuantifiersEngine* q); - InstMatchTrie2(const InstMatchTrie2&) CVC4_UNDEFINED; - const InstMatchTrie2& operator=(const InstMatchTrie2 & e) CVC4_UNDEFINED; - /** add match m in the trie, - modEq specify to take into account equalities, - return true if it was never seen */ - bool addInstMatch( InstMatch& m); -};/* class InstMatchTrie2 */ - /** base class for producing InstMatch objects */ class IMGenerator { public: @@ -405,10 +394,6 @@ public: int addTerm( Node f, Node t, QuantifiersEngine* qe ); };/* class InstMatchGeneratorMulti */ -namespace quantifiers{ - class TermArgTrie; -} - /** smart (single)-trigger implementation */ class InstMatchGeneratorSimple : public IMGenerator { private: @@ -438,6 +423,11 @@ public: int addTerm( Node f, Node t, QuantifiersEngine* qe ); };/* class InstMatchGeneratorSimple */ +}/* CVC4::theory::inst namespace */ + +typedef CVC4::theory::inst::InstMatch InstMatch; +typedef CVC4::theory::inst::EqualityQuery EqualityQuery; + }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/theory/instantiator_default.cpp b/src/theory/instantiator_default.cpp index a1766ce3c..cff16962a 100644 --- a/src/theory/instantiator_default.cpp +++ b/src/theory/instantiator_default.cpp @@ -46,7 +46,7 @@ int InstantiatorDefault::process( Node f, Theory::Effort effort, int e ){ if( d_quantEngine->getTheoryEngine()->theoryOf( i )==getTheory() ){ //if it belongs to this theory Node val = d_th->getValue( i ); Debug("quant-default") << "Default Instantiate for " << d_th->getId() << ", setting " << i << " = " << val << std::endl; - m.d_map[ i ] = val; + m.set( i, val); } } d_quantEngine->addInstantiation( f, m ); diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp index fae54c151..2b79cd8b9 100644 --- a/src/theory/quantifiers/instantiation_engine.cpp +++ b/src/theory/quantifiers/instantiation_engine.cpp @@ -104,7 +104,7 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ int e_use = e; if( e_use>=0 ){ //use each theory instantiator to instantiate f - for( int i=0; igetInstantiator( i ) ){ Debug("inst-engine-debug") << "Do " << d_quantEngine->getInstantiator( i )->identify() << " " << e_use << std::endl; int quantStatus = d_quantEngine->getInstantiator( i )->doInstantiation( f, effort, e_use ); @@ -126,7 +126,7 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){ //Notice() << "All instantiators finished, # added lemmas = " << (int)d_lemmas_waiting.size() << std::endl; if( !d_quantEngine->hasAddedLemma() ){ Debug("inst-engine-stuck") << "No instantiations produced at this state: " << std::endl; - for( int i=0; igetInstantiator( i ) ){ d_quantEngine->getInstantiator( i )->debugPrint("inst-engine-stuck"); Debug("inst-engine-stuck") << std::endl; diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp index ad259f864..663f270eb 100644 --- a/src/theory/quantifiers/model_engine.cpp +++ b/src/theory/quantifiers/model_engine.cpp @@ -39,6 +39,7 @@ using namespace CVC4::kind; using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::quantifiers; +using namespace CVC4::theory::inst; ModelEngineBuilder::ModelEngineBuilder( QuantifiersEngine* qe ) : TheoryEngineModelBuilder( qe->getTheoryEngine() ), @@ -503,7 +504,7 @@ int ModelEngine::initializeQuantifier( Node f ){ 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_builder.d_quant_basis_match[f].set( ic, t); } ++(d_statistics.d_num_quants_init); //register model basis body diff --git a/src/theory/quantifiers/rep_set_iterator.cpp b/src/theory/quantifiers/rep_set_iterator.cpp index 02041480f..a29f815db 100644 --- a/src/theory/quantifiers/rep_set_iterator.cpp +++ b/src/theory/quantifiers/rep_set_iterator.cpp @@ -97,7 +97,7 @@ bool RepSetIterator::isFinished(){ 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 ); + m.set( qe->getTermDatabase()->getInstantiationConstant( d_f, d_index_order[i] ), getTerm( i )); } } diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp index 55ea693ef..55715353d 100644 --- a/src/theory/quantifiers/term_database.cpp +++ b/src/theory/quantifiers/term_database.cpp @@ -1,324 +1,365 @@ -/********************* */ -/*! \file term_database.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Implementation of term databse class - **/ - - #include "theory/quantifiers/term_database.h" - #include "theory/quantifiers_engine.h" - #include "theory/uf/theory_uf_instantiator.h" - #include "theory/theory_engine.h" - #include "theory/quantifiers/first_order_model.h" - -using namespace std; -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::quantifiers; - - bool TermArgTrie::addTerm2( QuantifiersEngine* qe, Node n, int argIndex ){ - if( argIndex<(int)n.getNumChildren() ){ - Node r = qe->getEqualityQuery()->getRepresentative( n[ argIndex ] ); - std::map< Node, TermArgTrie >::iterator it = d_data.find( r ); - if( it==d_data.end() ){ - d_data[r].addTerm2( qe, n, argIndex+1 ); - return true; - }else{ - return it->second.addTerm2( qe, n, argIndex+1 ); - } - }else{ - //store n in d_data (this should be interpretted as the "data" and not as a reference to a child) - d_data[n].d_data.clear(); - return false; - } - } - - void TermDb::addTerm( Node n, std::vector< Node >& added, bool withinQuant ){ - //don't add terms in quantifier bodies - if( !withinQuant || Options::current()->registerQuantBodyTerms ){ - if( d_processed.find( n )==d_processed.end() ){ - d_processed[n] = true; - //if this is an atomic trigger, consider adding it - if( Trigger::isAtomicTrigger( n ) ){ - if( !n.hasAttribute(InstConstantAttribute()) ){ - Debug("term-db") << "register trigger term " << n << std::endl; - //Notice() << "register trigger term " << n << std::endl; - Node op = n.getOperator(); - d_op_map[op].push_back( n ); - d_type_map[ n.getType() ].push_back( n ); - added.push_back( n ); - - uf::InstantiatorTheoryUf* d_ith = (uf::InstantiatorTheoryUf*)d_quantEngine->getInstantiator( THEORY_UF ); - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - addTerm( n[i], added, withinQuant ); - if( Options::current()->efficientEMatching ){ - if( d_parents[n[i]][op].empty() ){ - //must add parent to equivalence class info - Node nir = d_ith->getRepresentative( n[i] ); - uf::EqClassInfo* eci_nir = d_ith->getEquivalenceClassInfo( nir ); - if( eci_nir ){ - eci_nir->d_pfuns[ op ] = true; - } - } - //add to parent structure - if( std::find( d_parents[n[i]][op][i].begin(), d_parents[n[i]][op][i].end(), n )==d_parents[n[i]][op][i].end() ){ - d_parents[n[i]][op][i].push_back( n ); - } - } - } - if( Options::current()->efficientEMatching ){ - //new term, add n to candidate generators - for( int i=0; i<(int)d_ith->d_cand_gens[op].size(); i++ ){ - d_ith->d_cand_gens[op][i]->addCandidate( n ); - } - } - if( Options::current()->eagerInstQuant ){ - if( !n.hasAttribute(InstLevelAttribute()) && n.getAttribute(InstLevelAttribute())==0 ){ - int addedLemmas = 0; - for( int i=0; i<(int)d_ith->d_op_triggers[op].size(); i++ ){ - addedLemmas += d_ith->d_op_triggers[op][i]->addTerm( n ); - } - //Message() << "Terms, added lemmas: " << addedLemmas << std::endl; - d_quantEngine->flushLemmas( &d_quantEngine->getTheoryEngine()->getTheory( THEORY_QUANTIFIERS )->getOutputChannel() ); - } - } - } - } - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - addTerm( n[i], added, withinQuant ); - } - } - } - } - - void TermDb::reset( Theory::Effort effort ){ - int nonCongruentCount = 0; - int congruentCount = 0; - int alreadyCongruentCount = 0; - //rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms - for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){ - if( !it->second.empty() ){ - if( it->second[0].getType()==NodeManager::currentNM()->booleanType() ){ - d_pred_map_trie[ 0 ][ it->first ].d_data.clear(); - d_pred_map_trie[ 1 ][ it->first ].d_data.clear(); - }else{ - d_func_map_trie[ it->first ].d_data.clear(); - for( int i=0; i<(int)it->second.size(); i++ ){ - Node n = it->second[i]; - if( !n.getAttribute(NoMatchAttribute()) ){ - if( !d_func_map_trie[ it->first ].addTerm( d_quantEngine, n ) ){ - NoMatchAttribute nma; - n.setAttribute(nma,true); - congruentCount++; - }else{ - nonCongruentCount++; - } - }else{ - congruentCount++; - alreadyCongruentCount++; - } - } - } - } - } - for( int i=0; i<2; i++ ){ - Node n = NodeManager::currentNM()->mkConst( i==1 ); - eq::EqClassIterator eqc( d_quantEngine->getEqualityQuery()->getRepresentative( n ), - ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine() ); - while( !eqc.isFinished() ){ - Node en = (*eqc); - if( en.getKind()==APPLY_UF && !en.hasAttribute(InstConstantAttribute()) ){ - if( !en.getAttribute(NoMatchAttribute()) ){ - Node op = en.getOperator(); - if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){ - NoMatchAttribute nma; - en.setAttribute(nma,true); - congruentCount++; - }else{ - nonCongruentCount++; - } - }else{ - alreadyCongruentCount++; - } - } - ++eqc; - } - } - Debug("term-db-cong") << "TermDb: Reset" << std::endl; - Debug("term-db-cong") << "Congruent/Non-Congruent = "; - Debug("term-db-cong") << congruentCount << "(" << alreadyCongruentCount << ") / " << nonCongruentCount << std::endl; -} - -void TermDb::registerModelBasis( Node n, Node gn ){ - if( d_model_basis.find( n )==d_model_basis.end() ){ - d_model_basis[n] = gn; - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - registerModelBasis( n[i], gn[i] ); - } - } -} - -Node TermDb::getModelBasisTerm( TypeNode tn, int i ){ - if( d_model_basis_term.find( tn )==d_model_basis_term.end() ){ - std::stringstream ss; - ss << Expr::setlanguage(Options::current()->outputLanguage); - ss << "e_" << tn; - d_model_basis_term[tn] = NodeManager::currentNM()->mkVar( ss.str(), tn ); - ModelBasisAttribute mba; - d_model_basis_term[tn].setAttribute(mba,true); - } - return d_model_basis_term[tn]; -} - -Node TermDb::getModelBasisOpTerm( Node op ){ - if( d_model_basis_op_term.find( op )==d_model_basis_op_term.end() ){ - TypeNode t = op.getType(); - std::vector< Node > children; - children.push_back( op ); - for( size_t i=0; imkNode( APPLY_UF, children ); - } - return d_model_basis_op_term[op]; -} - -void TermDb::computeModelBasisArgAttribute( Node n ){ - if( !n.hasAttribute(ModelBasisArgAttribute()) ){ - uint64_t val = 0; - //determine if it has model basis attribute - for( int j=0; j<(int)n.getNumChildren(); j++ ){ - if( n[j].getAttribute(ModelBasisAttribute()) ){ - val = 1; - break; - } - } - ModelBasisArgAttribute mbaa; - n.setAttribute( mbaa, val ); - } -} - -void TermDb::makeInstantiationConstantsFor( Node f ){ - if( d_inst_constants.find( f )==d_inst_constants.end() ){ - Debug("quantifiers-engine") << "Instantiation constants for " << f << " : " << std::endl; - for( int i=0; i<(int)f[0].getNumChildren(); i++ ){ - d_vars[f].push_back( f[0][i] ); - //make instantiation constants - Node ic = NodeManager::currentNM()->mkInstConstant( f[0][i].getType() ); - d_inst_constants_map[ic] = f; - d_inst_constants[ f ].push_back( ic ); - Debug("quantifiers-engine") << " " << ic << std::endl; - //set the var number attribute - InstVarNumAttribute ivna; - ic.setAttribute(ivna,i); - } - } -} - -void TermDb::setInstantiationLevelAttr( Node n, uint64_t level ){ - if( !n.hasAttribute(InstLevelAttribute()) ){ - InstLevelAttribute ila; - n.setAttribute(ila,level); - } - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - setInstantiationLevelAttr( n[i], level ); - } -} - - -void TermDb::setInstantiationConstantAttr( Node n, Node f ){ - if( !n.hasAttribute(InstConstantAttribute()) ){ - bool setAttr = false; - if( n.getKind()==INST_CONSTANT ){ - setAttr = true; - }else{ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - setInstantiationConstantAttr( n[i], f ); - if( n[i].hasAttribute(InstConstantAttribute()) ){ - setAttr = true; - } - } - } - if( setAttr ){ - InstConstantAttribute ica; - n.setAttribute(ica,f); - //also set the no-match attribute - NoMatchAttribute nma; - n.setAttribute(nma,true); - } - } -} - - -Node TermDb::getCounterexampleBody( Node f ){ - std::map< Node, Node >::iterator it = d_counterexample_body.find( f ); - if( it==d_counterexample_body.end() ){ - makeInstantiationConstantsFor( f ); - Node n = getSubstitutedNode( f[1], f ); - d_counterexample_body[ f ] = n; - return n; - }else{ - return it->second; - } -} - -Node TermDb::getSkolemizedBody( Node f ){ - Assert( f.getKind()==FORALL ); - if( d_skolem_body.find( f )==d_skolem_body.end() ){ - std::vector< Node > vars; - for( int i=0; i<(int)f[0].getNumChildren(); i++ ){ - Node skv = NodeManager::currentNM()->mkSkolem( f[0][i].getType() ); - d_skolem_constants[ f ].push_back( skv ); - vars.push_back( f[0][i] ); - } - d_skolem_body[ f ] = f[ 1 ].substitute( vars.begin(), vars.end(), - d_skolem_constants[ f ].begin(), d_skolem_constants[ f ].end() ); - if( f.hasAttribute(InstLevelAttribute()) ){ - setInstantiationLevelAttr( d_skolem_body[ f ], f.getAttribute(InstLevelAttribute()) ); - } - } - return d_skolem_body[ f ]; -} - - -Node TermDb::getSubstitutedNode( Node n, Node f ){ - return convertNodeToPattern(n,f,d_vars[f],d_inst_constants[ f ]); -} - -Node TermDb::convertNodeToPattern( Node n, Node f, const std::vector & vars, - const std::vector & inst_constants){ - Node n2 = n.substitute( vars.begin(), vars.end(), - inst_constants.begin(), - inst_constants.end() ); - setInstantiationConstantAttr( n2, f ); - return n2; -} - -Node TermDb::getFreeVariableForInstConstant( Node n ){ - TypeNode tn = n.getType(); - if( d_free_vars.find( tn )==d_free_vars.end() ){ - //if integer or real, make zero - if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){ - Rational z(0); - d_free_vars[tn] = NodeManager::currentNM()->mkConst( z ); - }else{ - if( d_type_map[ tn ].empty() ){ - d_free_vars[tn] = NodeManager::currentNM()->mkVar( tn ); - }else{ - d_free_vars[tn] = d_type_map[ tn ][ 0 ]; - } - } - } - return d_free_vars[tn]; -} \ No newline at end of file +/********************* */ +/*! \file term_database.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): bobot + ** 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; + +using namespace CVC4::theory::inst; + 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 addTermEfficient( Node n, std::set< Node >& added){ + static AvailableInTermDb aitdi; + if (Trigger::isAtomicTrigger( n ) && !n.getAttribute(aitdi)){ + //Already processed but new in this branch + n.setAttribute(aitdi,true); + added.insert( n ); + for( size_t i=0; i< n.getNumChildren(); i++ ){ + addTermEfficient(n[i],added); + } + } + +} + + +void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){ + //don't add terms in quantifier bodies + if( withinQuant && !Options::current()->registerQuantBodyTerms ){ + return; + } + if( d_processed.find( n )==d_processed.end() ){ + ++(d_quantEngine->d_statistics.d_term_in_termdb); + d_processed.insert(n); + n.setAttribute(AvailableInTermDb(),true); + //if this is an atomic trigger, consider adding it + //Call the children? + if( Trigger::isAtomicTrigger( n ) || n.getKind() == kind::APPLY_CONSTRUCTOR ){ + if( !n.hasAttribute(InstConstantAttribute()) ){ + Debug("term-db") << "register trigger term " << n << std::endl; + //std::cout << "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.insert( 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 ); + Assert(!getParents(n[i],op,i).empty()); + } + } + 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() ); + } + } + } + } + }else{ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + addTerm( n[i], added, withinQuant ); + } + } + }else{ + if( Options::current()->efficientEMatching && + !n.hasAttribute(InstConstantAttribute())){ + //Efficient e-matching must be notified + //The term in triggers are not important here + Debug("term-db") << "New in this branch term " << n << std::endl; + addTermEfficient(n,added); + } + } +}; + + void TermDb::reset( Theory::Effort effort ){ + int nonCongruentCount = 0; + int congruentCount = 0; + int alreadyCongruentCount = 0; + //rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms + for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){ + if( !it->second.empty() ){ + if( it->second[0].getType()==NodeManager::currentNM()->booleanType() ){ + d_pred_map_trie[ 0 ][ it->first ].d_data.clear(); + d_pred_map_trie[ 1 ][ it->first ].d_data.clear(); + }else{ + d_func_map_trie[ it->first ].d_data.clear(); + for( int i=0; i<(int)it->second.size(); i++ ){ + Node n = it->second[i]; + if( !n.getAttribute(NoMatchAttribute()) ){ + if( !d_func_map_trie[ it->first ].addTerm( d_quantEngine, n ) ){ + NoMatchAttribute nma; + n.setAttribute(nma,true); + congruentCount++; + }else{ + nonCongruentCount++; + } + }else{ + congruentCount++; + alreadyCongruentCount++; + } + } + } + } + } + for( int i=0; i<2; i++ ){ + Node n = NodeManager::currentNM()->mkConst( i==1 ); + eq::EqClassIterator eqc( d_quantEngine->getEqualityQuery()->getRepresentative( n ), + ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine() ); + while( !eqc.isFinished() ){ + Node en = (*eqc); + if( en.getKind()==APPLY_UF && !en.hasAttribute(InstConstantAttribute()) ){ + if( !en.getAttribute(NoMatchAttribute()) ){ + Node op = en.getOperator(); + if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){ + NoMatchAttribute nma; + en.setAttribute(nma,true); + congruentCount++; + }else{ + nonCongruentCount++; + } + }else{ + alreadyCongruentCount++; + } + } + ++eqc; + } + } + Debug("term-db-cong") << "TermDb: Reset" << std::endl; + Debug("term-db-cong") << "Congruent/Non-Congruent = "; + Debug("term-db-cong") << congruentCount << "(" << alreadyCongruentCount << ") / " << nonCongruentCount << std::endl; +} + +void TermDb::registerModelBasis( Node n, Node gn ){ + if( d_model_basis.find( n )==d_model_basis.end() ){ + d_model_basis[n] = gn; + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + registerModelBasis( n[i], gn[i] ); + } + } +} + +Node TermDb::getModelBasisTerm( TypeNode tn, int i ){ + if( d_model_basis_term.find( tn )==d_model_basis_term.end() ){ + std::stringstream ss; + ss << Expr::setlanguage(Options::current()->outputLanguage); + ss << "e_" << tn; + d_model_basis_term[tn] = NodeManager::currentNM()->mkVar( ss.str(), tn ); + ModelBasisAttribute mba; + d_model_basis_term[tn].setAttribute(mba,true); + } + return d_model_basis_term[tn]; +} + +Node TermDb::getModelBasisOpTerm( Node op ){ + if( d_model_basis_op_term.find( op )==d_model_basis_op_term.end() ){ + TypeNode t = op.getType(); + std::vector< Node > children; + children.push_back( op ); + for( size_t i=0; imkNode( APPLY_UF, children ); + } + return d_model_basis_op_term[op]; +} + +void TermDb::computeModelBasisArgAttribute( Node n ){ + if( !n.hasAttribute(ModelBasisArgAttribute()) ){ + uint64_t val = 0; + //determine if it has model basis attribute + for( int j=0; j<(int)n.getNumChildren(); j++ ){ + if( n[j].getAttribute(ModelBasisAttribute()) ){ + val = 1; + break; + } + } + ModelBasisArgAttribute mbaa; + n.setAttribute( mbaa, val ); + } +} + +void TermDb::makeInstantiationConstantsFor( Node f ){ + if( d_inst_constants.find( f )==d_inst_constants.end() ){ + Debug("quantifiers-engine") << "Instantiation constants for " << f << " : " << std::endl; + for( int i=0; i<(int)f[0].getNumChildren(); i++ ){ + d_vars[f].push_back( f[0][i] ); + //make instantiation constants + Node ic = NodeManager::currentNM()->mkInstConstant( f[0][i].getType() ); + d_inst_constants_map[ic] = f; + d_inst_constants[ f ].push_back( ic ); + Debug("quantifiers-engine") << " " << ic << std::endl; + //set the var number attribute + InstVarNumAttribute ivna; + ic.setAttribute(ivna,i); + } + } +} + +void TermDb::setInstantiationLevelAttr( Node n, uint64_t level ){ + if( !n.hasAttribute(InstLevelAttribute()) ){ + InstLevelAttribute ila; + n.setAttribute(ila,level); + } + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + setInstantiationLevelAttr( n[i], level ); + } +} + + +void TermDb::setInstantiationConstantAttr( Node n, Node f ){ + if( !n.hasAttribute(InstConstantAttribute()) ){ + bool setAttr = false; + if( n.getKind()==INST_CONSTANT ){ + setAttr = true; + }else{ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + setInstantiationConstantAttr( n[i], f ); + if( n[i].hasAttribute(InstConstantAttribute()) ){ + setAttr = true; + } + } + } + if( setAttr ){ + InstConstantAttribute ica; + n.setAttribute(ica,f); + //also set the no-match attribute + NoMatchAttribute nma; + n.setAttribute(nma,true); + } + } +} + + +Node TermDb::getCounterexampleBody( Node f ){ + std::map< Node, Node >::iterator it = d_counterexample_body.find( f ); + if( it==d_counterexample_body.end() ){ + makeInstantiationConstantsFor( f ); + Node n = getSubstitutedNode( f[1], f ); + d_counterexample_body[ f ] = n; + return n; + }else{ + return it->second; + } +} + +Node TermDb::getSkolemizedBody( Node f ){ + Assert( f.getKind()==FORALL ); + if( d_skolem_body.find( f )==d_skolem_body.end() ){ + std::vector< Node > vars; + for( int i=0; i<(int)f[0].getNumChildren(); i++ ){ + Node skv = NodeManager::currentNM()->mkSkolem( f[0][i].getType() ); + d_skolem_constants[ f ].push_back( skv ); + vars.push_back( f[0][i] ); + } + d_skolem_body[ f ] = f[ 1 ].substitute( vars.begin(), vars.end(), + d_skolem_constants[ f ].begin(), d_skolem_constants[ f ].end() ); + if( f.hasAttribute(InstLevelAttribute()) ){ + setInstantiationLevelAttr( d_skolem_body[ f ], f.getAttribute(InstLevelAttribute()) ); + } + } + return d_skolem_body[ f ]; +} + + +Node TermDb::getSubstitutedNode( Node n, Node f ){ + return convertNodeToPattern(n,f,d_vars[f],d_inst_constants[ f ]); +} + +Node TermDb::convertNodeToPattern( Node n, Node f, const std::vector & vars, + const std::vector & inst_constants){ + Node n2 = n.substitute( vars.begin(), vars.end(), + inst_constants.begin(), + inst_constants.end() ); + setInstantiationConstantAttr( n2, f ); + return n2; +} + +Node TermDb::getFreeVariableForInstConstant( Node n ){ + TypeNode tn = n.getType(); + if( d_free_vars.find( tn )==d_free_vars.end() ){ + //if integer or real, make zero + if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){ + Rational z(0); + d_free_vars[tn] = NodeManager::currentNM()->mkConst( z ); + }else{ + if( d_type_map[ tn ].empty() ){ + d_free_vars[tn] = NodeManager::currentNM()->mkVar( tn ); + }else{ + d_free_vars[tn] = d_type_map[ tn ][ 0 ]; + } + } + } + return d_free_vars[tn]; +} + +const std::vector & TermDb::getParents(TNode n, TNode f, int arg){ + std::hash_map< Node, std::hash_map< Node, std::hash_map< int, std::vector< Node > >,NodeHashFunction >,NodeHashFunction >::const_iterator + rn = d_parents.find( n ); + if( rn !=d_parents.end() ){ + std::hash_map< Node, std::hash_map< int, std::vector< Node > > , NodeHashFunction > ::const_iterator + rf = rn->second.find(f); + if( rf != rn->second.end() ){ + std::hash_map< int, std::vector< Node > > ::const_iterator + ra = rf->second.find(arg); + if( ra != rf->second.end() ){ + return ra->second; + } + } + } + static std::vector empty; + return empty; +} diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h index 5bf3d7900..5004a82dc 100644 --- a/src/theory/quantifiers/term_database.h +++ b/src/theory/quantifiers/term_database.h @@ -48,7 +48,7 @@ private: /** calculated no match terms */ bool d_matching_active; /** terms processed */ - std::map< Node, bool > d_processed; + std::hash_set< Node, NodeHashFunction > d_processed; public: TermDb( QuantifiersEngine* qe ) : d_quantEngine( qe ), d_matching_active( true ){} ~TermDb(){} @@ -61,7 +61,7 @@ public: /** 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 ); + void addTerm( Node n, std::set< Node >& added, bool withinQuant = false ); /** reset (calculate which terms are active) */ void reset( Theory::Effort effort ); /** set active */ @@ -75,7 +75,9 @@ public: 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; + /* Todo replace int by size_t */ + std::hash_map< Node, std::hash_map< Node, std::hash_map< int, std::vector< Node > >, NodeHashFunction > , NodeHashFunction > d_parents; + const std::vector & getParents(TNode n, TNode f, int arg); private: //map from types to model basis terms std::map< TypeNode, Node > d_model_basis_term; diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h index 517786400..1e42abd22 100644 --- a/src/theory/quantifiers/theory_quantifiers.h +++ b/src/theory/quantifiers/theory_quantifiers.h @@ -30,10 +30,11 @@ #include namespace CVC4 { +class TheoryEngine; + namespace theory { namespace quantifiers { -class TheoryEngine; class ModelEngine; class InstantiationEngine; diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp index e4e3df9be..448224b81 100644 --- a/src/theory/quantifiers_engine.cpp +++ b/src/theory/quantifiers_engine.cpp @@ -32,6 +32,7 @@ using namespace CVC4; using namespace CVC4::kind; using namespace CVC4::context; using namespace CVC4::theory; +using namespace CVC4::theory::inst; //#define COMPUTE_RELEVANCE //#define REWRITE_ASSERTED_QUANTIFIERS @@ -93,7 +94,11 @@ d_active( c ){ d_optInstLimit = 0; } -Instantiator* QuantifiersEngine::getInstantiator( int id ){ +QuantifiersEngine::~QuantifiersEngine(){ + delete(d_term_db); +} + +Instantiator* QuantifiersEngine::getInstantiator( theory::TheoryId id ){ return d_te->getTheory( id )->getInstantiator(); } @@ -212,7 +217,7 @@ void QuantifiersEngine::registerQuantifier( Node f ){ void QuantifiersEngine::registerPattern( std::vector & pattern) { for(std::vector::iterator p = pattern.begin(); p != pattern.end(); ++p){ - std::vector< Node > added; + std::set< Node > added; getTermDatabase()->addTerm(*p,added); } } @@ -236,7 +241,7 @@ void QuantifiersEngine::propagate( Theory::Effort level ){ } void QuantifiersEngine::resetInstantiationRound( Theory::Effort level ){ - for( int i=0; iresetInstantiationRound( level ); } @@ -245,13 +250,19 @@ void QuantifiersEngine::resetInstantiationRound( Theory::Effort level ){ } void QuantifiersEngine::addTermToDatabase( Node n, bool 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 ); + std::set< Node > added; + getTermDatabase()->addTerm( n, added, withinQuant ); + if( Options::current()->efficientEMatching ){ + uf::InstantiatorTheoryUf* d_ith = (uf::InstantiatorTheoryUf*)getInstantiator( THEORY_UF ); + d_ith->newTerms(added); } +#ifdef COMPUTE_RELEVANCE + //added contains also the Node that just have been asserted in this branch + for( std::set< Node >::iterator i=added.begin(), end=added.end(); + i!=end; i++ ){ + if( !withinQuant ){ + setRelevance( i->getOperator(), 0 ); + } } #endif @@ -530,7 +541,15 @@ QuantifiersEngine::Statistics::Statistics(): d_triggers("QuantifiersEngine::Triggers", 0), d_simple_triggers("QuantifiersEngine::Triggers_Simple", 0), d_multi_triggers("QuantifiersEngine::Triggers_Multi", 0), - d_multi_trigger_instantiations("QuantifiersEngine::Multi_Trigger_Instantiations", 0) + d_multi_trigger_instantiations("QuantifiersEngine::Multi_Trigger_Instantiations", 0), + d_term_in_termdb("QuantifiersEngine::Term_in_TermDb", 0), + d_num_mono_candidates("QuantifiersEngine::NumMonoCandidates", 0), + d_num_mono_candidates_new_term("QuantifiersEngine::NumMonoCandidatesNewTerm", 0), + d_num_multi_candidates("QuantifiersEngine::NumMultiCandidates", 0), + d_mono_candidates_cache_hit("QuantifiersEngine::MonoCandidatesCacheHit", 0), + d_mono_candidates_cache_miss("QuantifiersEngine::MonoCandidatesCacheMiss", 0), + d_multi_candidates_cache_hit("QuantifiersEngine::MultiCandidatesCacheHit", 0), + d_multi_candidates_cache_miss("QuantifiersEngine::MultiCandidatesCacheMiss", 0) { StatisticsRegistry::registerStat(&d_num_quant); StatisticsRegistry::registerStat(&d_instantiation_rounds); @@ -548,6 +567,14 @@ QuantifiersEngine::Statistics::Statistics(): StatisticsRegistry::registerStat(&d_simple_triggers); StatisticsRegistry::registerStat(&d_multi_triggers); StatisticsRegistry::registerStat(&d_multi_trigger_instantiations); + StatisticsRegistry::registerStat(&d_term_in_termdb); + StatisticsRegistry::registerStat(&d_num_mono_candidates); + StatisticsRegistry::registerStat(&d_num_mono_candidates_new_term); + StatisticsRegistry::registerStat(&d_num_multi_candidates); + StatisticsRegistry::registerStat(&d_mono_candidates_cache_hit); + StatisticsRegistry::registerStat(&d_mono_candidates_cache_miss); + StatisticsRegistry::registerStat(&d_multi_candidates_cache_hit); + StatisticsRegistry::registerStat(&d_multi_candidates_cache_miss); } QuantifiersEngine::Statistics::~Statistics(){ @@ -567,6 +594,14 @@ QuantifiersEngine::Statistics::~Statistics(){ StatisticsRegistry::unregisterStat(&d_simple_triggers); StatisticsRegistry::unregisterStat(&d_multi_triggers); StatisticsRegistry::unregisterStat(&d_multi_trigger_instantiations); + StatisticsRegistry::unregisterStat(&d_term_in_termdb); + StatisticsRegistry::unregisterStat(&d_num_mono_candidates); + StatisticsRegistry::unregisterStat(&d_num_mono_candidates_new_term); + StatisticsRegistry::unregisterStat(&d_num_multi_candidates); + StatisticsRegistry::unregisterStat(&d_mono_candidates_cache_hit); + StatisticsRegistry::unregisterStat(&d_mono_candidates_cache_miss); + StatisticsRegistry::unregisterStat(&d_multi_candidates_cache_hit); + StatisticsRegistry::unregisterStat(&d_multi_candidates_cache_miss); } /** compute symbols */ @@ -608,7 +643,7 @@ bool EqualityQueryQuantifiersEngine::hasTerm( Node a ){ if( ee->hasTerm( a ) ){ return true; } - for( int i=0; igetInstantiator( i ) ){ if( d_qe->getInstantiator( i )->hasTerm( a ) ){ return true; @@ -623,7 +658,7 @@ Node EqualityQueryQuantifiersEngine::getRepresentative( Node a ){ if( ee->hasTerm( a ) ){ return ee->getRepresentative( a ); } - for( int i=0; igetInstantiator( i ) ){ if( d_qe->getInstantiator( i )->hasTerm( a ) ){ return d_qe->getInstantiator( i )->getRepresentative( a ); @@ -643,7 +678,7 @@ bool EqualityQueryQuantifiersEngine::areEqual( Node a, Node b ){ return true; } } - for( int i=0; igetInstantiator( i ) ){ if( d_qe->getInstantiator( i )->areEqual( a, b ) ){ return true; @@ -662,7 +697,7 @@ bool EqualityQueryQuantifiersEngine::areDisequal( Node a, Node b ){ return true; } } - for( int i=0; igetInstantiator( i ) ){ if( d_qe->getInstantiator( i )->areDisequal( a, b ) ){ return true; @@ -674,7 +709,7 @@ bool EqualityQueryQuantifiersEngine::areDisequal( Node a, Node b ){ } Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a ){ - //for( int i=0; igetInstantiator( i ) ){ // if( d_qe->getInstantiator( i )->hasTerm( a ) ){ // return d_qe->getInstantiator( i )->getInternalRepresentative( a ); @@ -684,3 +719,217 @@ Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a ){ //return a; return d_qe->getInstantiator( THEORY_UF )->getInternalRepresentative( a ); } + +inst::EqualityQuery* QuantifiersEngine::getEqualityQuery(TypeNode t) { + /** Should use skeleton (in order to have the type and the kind + or any needed other information) instead of only the type */ + + // TheoryId id = Theory::theoryOf(t); + // inst::EqualityQuery* eq = d_eq_query_arr[id]; + // if(eq == NULL) return d_eq_query_arr[theory::THEORY_UF]; + // else return eq; + + /** hack because the generic one is too slow */ + // TheoryId id = Theory::theoryOf(t); + // if( true || id == theory::THEORY_UF){ + // uf::InstantiatorTheoryUf* ith = static_cast( getInstantiator( theory::THEORY_UF )); + // return new uf::EqualityQueryInstantiatorTheoryUf(ith); + // } + // inst::EqualityQuery* eq = d_eq_query_arr[id]; + // if(eq == NULL) return d_eq_query_arr[theory::THEORY_UF]; + // else return eq; + + + //Currently we use the generic EqualityQuery + return getEqualityQuery(); +} + + +// // Just iterate amoung the equivalence class of the given node +// // node::Null() *can't* be given to reset +// class CandidateGeneratorClassGeneric : public CandidateGenerator{ +// private: +// //instantiator pointer +// EqualityEngine* d_ee; +// //the equality class iterator +// eq::EqClassIterator d_eqc; +// /* For the case where the given term doesn't exists in uf */ +// Node d_retNode; +// public: +// CandidateGeneratorTheoryEeClass( EqualityEngine* ee): d_ee( ee ){} +// ~CandidateGeneratorTheoryEeClass(){} +// void resetInstantiationRound(){}; +// void reset( TNode eqc ){ +// Assert(!eqc.isNull()); +// if( d_ee->hasTerm( eqc ) ){ +// /* eqc is in uf */ +// eqc = d_ee->getRepresentative( eqc ); +// d_eqc = eq::EqClassIterator( eqc, d_ee ); +// d_retNode = Node::null(); +// }else{ +// /* If eqc if not a term known by uf, it is the only one in its +// equivalence class. So we will return only it */ +// d_retNode = eqc; +// d_eqc = eq::EqClassIterator(); +// } +// }; //* the argument is not used +// TNode getNextCandidate(){ +// if(d_retNode.isNull()){ +// if( !d_eqc.isFinished() ) return (*(d_eqc++)); +// else return Node::null(); +// }else{ +// /* the case where eqc not in uf */ +// Node ret = d_retNode; +// d_retNode = Node::null(); /* d_eqc.isFinished() must be true */ +// return ret; +// } +// }; +// }; + + +class GenericCandidateGeneratorClasses: public rrinst::CandidateGenerator{ + + /** The candidate generators */ + rrinst::CandidateGenerator* d_can_gen[theory::THEORY_LAST]; + /** The current theory which candidategenerator is used */ + TheoryId d_can_gen_id; + +public: + GenericCandidateGeneratorClasses(QuantifiersEngine * qe){ + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + if(qe->getInstantiator(i) != NULL) + d_can_gen[i] = qe->getInstantiator(i)->getRRCanGenClasses(); + else d_can_gen[i] = NULL; + }; + } + + ~GenericCandidateGeneratorClasses(){ + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + delete(d_can_gen[i]); + }; + } + + void resetInstantiationRound(){ + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + if(d_can_gen[i] != NULL) d_can_gen[i]->resetInstantiationRound(); + }; + d_can_gen_id=THEORY_FIRST; + } + + void reset(TNode eqc){ + Assert(eqc.isNull()); + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + if(d_can_gen[i] != NULL) d_can_gen[i]->reset(eqc); + }; + d_can_gen_id=THEORY_FIRST; + lookForNextTheory(); + } + + TNode getNextCandidate(){ + Assert(THEORY_FIRST <= d_can_gen_id && d_can_gen_id <= THEORY_LAST); + /** No more */ + if(d_can_gen_id == THEORY_LAST) return TNode::null(); + /** Try with this theory */ + TNode cand = d_can_gen[d_can_gen_id]->getNextCandidate(); + if( !cand.isNull() ) return cand; + lookForNextTheory(); + return getNextCandidate(); + } + + void lookForNextTheory(){ + do{ /* look for the next available generator */ + ++d_can_gen_id; + } while( d_can_gen_id < THEORY_LAST && d_can_gen[d_can_gen_id] == NULL); + } + +}; + +class GenericCandidateGeneratorClass: public rrinst::CandidateGenerator{ + + /** The candidate generators */ + rrinst::CandidateGenerator* d_can_gen[theory::THEORY_LAST]; + /** The current theory which candidategenerator is used */ + TheoryId d_can_gen_id; + /** current node to look for equivalence class */ + Node d_node; + /** QuantifierEngine */ + QuantifiersEngine* d_qe; + +public: + GenericCandidateGeneratorClass(QuantifiersEngine * qe): d_qe(qe) { + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + if(d_qe->getInstantiator(i) != NULL) + d_can_gen[i] = d_qe->getInstantiator(i)->getRRCanGenClass(); + else d_can_gen[i] = NULL; + }; + } + + ~GenericCandidateGeneratorClass(){ + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + delete(d_can_gen[i]); + }; + } + + void resetInstantiationRound(){ + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + if(d_can_gen[i] != NULL) d_can_gen[i]->resetInstantiationRound(); + }; + d_can_gen_id=THEORY_FIRST; + } + + void reset(TNode eqc){ + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + if(d_can_gen[i] != NULL) d_can_gen[i]->reset(eqc); + }; + d_can_gen_id=THEORY_FIRST; + d_node = eqc; + lookForNextTheory(); + } + + TNode getNextCandidate(){ + Assert(THEORY_FIRST <= d_can_gen_id && d_can_gen_id <= THEORY_LAST); + /** No more */ + if(d_can_gen_id == THEORY_LAST) return TNode::null(); + /** Try with this theory */ + TNode cand = d_can_gen[d_can_gen_id]->getNextCandidate(); + if( !cand.isNull() ) return cand; + lookForNextTheory(); + return getNextCandidate(); + } + + void lookForNextTheory(){ + do{ /* look for the next available generator, where the element is */ + ++d_can_gen_id; + } while( + d_can_gen_id < THEORY_LAST && + (d_can_gen[d_can_gen_id] == NULL || + !d_qe->getInstantiator( d_can_gen_id )->hasTerm( d_node )) + ); + } + +}; + + +rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClasses() { + return new GenericCandidateGeneratorClasses(this); +} + +rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClass() { + return new GenericCandidateGeneratorClass(this); +} + +rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClasses(TypeNode t) { + // TheoryId id = Theory::theoryOf(t); + // rrinst::CandidateGenerator* eq = getInstantiator(id)->getRRCanGenClasses(); + // if(eq == NULL) return getInstantiator(id)->getRRCanGenClasses(); + // else return eq; + return getRRCanGenClasses(); +} + +rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClass(TypeNode t) { + // TheoryId id = Theory::theoryOf(t); + // rrinst::CandidateGenerator* eq = getInstantiator(id)->getRRCanGenClass(); + // if(eq == NULL) return getInstantiator(id)->getRRCanGenClass(); + // else return eq; + return getRRCanGenClass(); +} diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h index 5477214b0..157c0ac53 100644 --- a/src/theory/quantifiers_engine.h +++ b/src/theory/quantifiers_engine.h @@ -21,7 +21,8 @@ #include "theory/theory.h" #include "util/hash.h" -#include "theory/trigger.h" +#include "theory/inst_match.h" +#include "theory/rr_inst_match.h" #include "util/stats.h" @@ -33,16 +34,6 @@ namespace CVC4 { class TheoryEngine; -// attribute for "contains instantiation constants from" -struct InstConstantAttributeId {}; -typedef expr::Attribute InstConstantAttribute; - -struct InstLevelAttributeId {}; -typedef expr::Attribute InstLevelAttribute; - -struct InstVarNumAttributeId {}; -typedef expr::Attribute InstVarNumAttribute; - namespace theory { class QuantifiersEngine; @@ -126,7 +117,7 @@ namespace quantifiers { class QuantifiersEngine { friend class quantifiers::InstantiationEngine; friend class quantifiers::ModelEngine; - friend class InstMatch; + friend class inst::InstMatch; private: typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap; /** reference to theory engine object */ @@ -139,7 +130,7 @@ private: quantifiers::ModelEngine* d_model_engine; /** equality query class */ EqualityQuery* d_eq_query; - +public: /** list of all quantifiers (pre-rewrite) */ std::vector< Node > d_quants; /** list of all quantifiers (post-rewrite) */ @@ -153,7 +144,7 @@ private: /** has added lemma this round */ bool d_hasAddedLemma; /** inst matches produced for each quantifier */ - std::map< Node, InstMatchTrie > d_inst_match_trie; + std::map< Node, inst::InstMatchTrie > d_inst_match_trie; /** owner of quantifiers */ std::map< Node, Theory* > d_owner; /** term database */ @@ -184,13 +175,24 @@ private: public: QuantifiersEngine(context::Context* c, TheoryEngine* te); - ~QuantifiersEngine(){} + ~QuantifiersEngine(); /** get instantiator for id */ - Instantiator* getInstantiator( int id ); + Instantiator* getInstantiator( theory::TheoryId id ); /** get theory engine */ TheoryEngine* getTheoryEngine() { return d_te; } - /** get equality query object */ - EqualityQuery* getEqualityQuery() { return d_eq_query; } + /** get equality query object for the given type. The default is the + generic one */ + inst::EqualityQuery* getEqualityQuery(TypeNode t); + inst::EqualityQuery* getEqualityQuery() { + return d_eq_query; + } + /** get equality query object for the given type. The default is the + one of UF */ + rrinst::CandidateGenerator* getRRCanGenClasses(TypeNode t); + rrinst::CandidateGenerator* getRRCanGenClass(TypeNode t); + /* generic candidate generator */ + rrinst::CandidateGenerator* getRRCanGenClasses(); + rrinst::CandidateGenerator* getRRCanGenClass(); /** get instantiation engine */ quantifiers::InstantiationEngine* getInstantiationEngine() { return d_inst_engine; } /** get model engine */ @@ -301,6 +303,14 @@ public: IntStat d_simple_triggers; IntStat d_multi_triggers; IntStat d_multi_trigger_instantiations; + IntStat d_term_in_termdb; + IntStat d_num_mono_candidates; + IntStat d_num_mono_candidates_new_term; + IntStat d_num_multi_candidates; + IntStat d_mono_candidates_cache_hit; + IntStat d_mono_candidates_cache_miss; + IntStat d_multi_candidates_cache_hit; + IntStat d_multi_candidates_cache_miss; Statistics(); ~Statistics(); };/* class QuantifiersEngine::Statistics */ diff --git a/src/theory/rewriterules/theory_rewriterules.cpp b/src/theory/rewriterules/theory_rewriterules.cpp index 265026b39..57bc6d9cf 100644 --- a/src/theory/rewriterules/theory_rewriterules.cpp +++ b/src/theory/rewriterules/theory_rewriterules.cpp @@ -23,6 +23,8 @@ #include "theory/rewriterules/theory_rewriterules_preprocess.h" #include "theory/rewriter.h" +#include "util/options.h" + using namespace std; using namespace CVC4; @@ -30,6 +32,7 @@ using namespace CVC4::kind; using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::rewriterules; +using namespace CVC4::theory::rrinst; namespace CVC4 { @@ -69,14 +72,14 @@ size_t RuleInst::findGuard(TheoryRewriteRules & re, size_t start)const{ Node g = substNode(re,rule->guards[start],cache); switch(re.addWatchIfDontKnow(g,this,start)){ case ATRUE: - Debug("rewriterules") << g << "is true" << std::endl; + Debug("rewriterules::guards") << g << "is true" << std::endl; ++start; continue; case AFALSE: - Debug("rewriterules") << g << "is false" << std::endl; + Debug("rewriterules::guards") << g << "is false" << std::endl; return -1; case ADONTKNOW: - Debug("rewriterules") << g << "is unknown" << std::endl; + Debug("rewriterules::guards") << g << "is unknown" << std::endl; return start; } } @@ -132,31 +135,31 @@ TheoryRewriteRules::TheoryRewriteRules(context::Context* c, QuantifiersEngine* qe) : Theory(THEORY_REWRITERULES, c, u, out, valuation, logicInfo, qe), d_rules(c), d_ruleinsts(c), d_guardeds(c), d_checkLevel(c,0), - d_explanations(c), d_ruleinsts_to_add() + d_explanations(c), d_ruleinsts_to_add(), d_ppAssert_on(false) { d_true = NodeManager::currentNM()->mkConst(true); d_false = NodeManager::currentNM()->mkConst(false); - Debug("rewriterules") << Node::setdepth(-1); - Debug("rewriterules-rewrite") << Node::setdepth(-1); } void TheoryRewriteRules::addMatchRuleTrigger(const RewriteRule * r, InstMatch & im, bool delay){ ++r->nb_matched; + ++d_statistics.d_match_found; if(rewrite_instantiation) im.applyRewrite(); if(representative_instantiation) im.makeRepresentative( getQuantifiersEngine() ); if(!cache_match || !r->inCache(*this,im)){ ++r->nb_applied; + ++d_statistics.d_cache_miss; std::vector subst; im.computeTermVec(getQuantifiersEngine(), r->inst_vars , subst); RuleInst * ri = new RuleInst(*this,r,subst, r->directrr ? im.d_matched : Node::null()); - Debug("rewriterules") << "One matching found" - << (delay? "(delayed)":"") - << ":" << *ri << std::endl; + Debug("rewriterules::matching") << "One matching found" + << (delay? "(delayed)":"") + << ":" << *ri << std::endl; // Find the first non verified guard, don't save the rule if the // rule can already be fired In fact I save it otherwise strange // things append. @@ -168,6 +171,8 @@ void TheoryRewriteRules::addMatchRuleTrigger(const RewriteRule * r, d_ruleinsts.push_back(ri); else delete(ri); }; + }else{ + ++d_statistics.d_cache_hit; }; } @@ -179,7 +184,11 @@ void TheoryRewriteRules::check(Effort level) { while(!done()) { // Get all the assertions // TODO: Test that it have already been ppAsserted - get(); + + //if we are here and ppAssert has not been done + // that means that ppAssert is off so we need to assert now + if(!d_ppAssert_on) addRewriteRule(get()); + else get(); // Assertion assertion = get(); // TNode fact = assertion.assertion; @@ -190,30 +199,30 @@ void TheoryRewriteRules::check(Effort level) { }; - Debug("rewriterules") << "Check:" << d_checkLevel << (level==EFFORT_FULL? " EFFORT_FULL":"") << std::endl; + Debug("rewriterules::check") << "RewriteRules::Check start " << d_checkLevel << (level==EFFORT_FULL? " EFFORT_FULL":"") << std::endl; /** Test each rewrite rule */ for(size_t rid = 0, end = d_rules.size(); rid < end; ++rid) { RewriteRule * r = d_rules[rid]; if (level!=EFFORT_FULL && r->d_split) continue; - Debug("rewriterules") << " rule: " << r << std::endl; + Debug("rewriterules::check") << "RewriteRules::Check rule: " << *r << std::endl; Trigger & tr = r->trigger; //reset instantiation round for trigger (set up match production) tr.resetInstantiationRound(); - //begin iterating from the first match produced by the trigger - tr.reset( Node::null() ); /** Test the possible matching one by one */ - InstMatch im; - while(tr.getNextMatch( im )){ + while(tr.getNextMatch()){ + InstMatch im = tr.getInstMatch(); addMatchRuleTrigger(r, im, true); - im.clear(); } } const bool do_notification = d_checkLevel == 0 || level==EFFORT_FULL; bool polldone = false; + if(level==EFFORT_FULL) ++d_statistics.d_full_check; + else ++d_statistics.d_check; + GuardedMap::const_iterator p = d_guardeds.begin(); do{ @@ -221,7 +230,7 @@ void TheoryRewriteRules::check(Effort level) { //dequeue instantiated rules for(; !d_ruleinsts_to_add.empty();){ RuleInst * ri = d_ruleinsts_to_add.back(); d_ruleinsts_to_add.pop_back(); - if(simulateRewritting && ri->alreadyRewritten(*this)) break; + if(simulateRewritting && ri->alreadyRewritten(*this)) continue; if(ri->findGuard(*this, 0) != ri->rule->guards.size()) d_ruleinsts.push_back(ri); else delete(ri); @@ -239,7 +248,7 @@ void TheoryRewriteRules::check(Effort level) { bool value; if(getValuation().hasSatValue(g,value)){ if(value) polldone = true; //One guard is true so pass n check - Debug("rewriterules") << "Poll value:" << g + Debug("rewriterules::guards") << "Poll value:" << g << " is " << (value ? "true" : "false") << std::endl; notification(g,value); //const Guarded & glast2 = (*l)[l->size()-1]; @@ -266,14 +275,14 @@ void TheoryRewriteRules::check(Effort level) { // If it has a value it should already has been notified bool value; value = value; // avoiding the warning in non debug mode Assert(!getValuation().hasSatValue(g,value)); - Debug("rewriterules") << "Narrowing on:" << g << std::endl; + Debug("rewriterules::check") << "RewriteRules::Check Narrowing on:" << g << std::endl; /** Can split on already rewritten instrule... but... */ getOutputChannel().split(g); } } Assert(d_ruleinsts_to_add.empty()); - Debug("rewriterules") << "Check done:" << d_checkLevel << std::endl; + Debug("rewriterules::check") << "RewriteRules::Check done " << d_checkLevel << std::endl; }; @@ -283,7 +292,13 @@ Trigger TheoryRewriteRules::createTrigger( TNode n, std::vector & pattern // Debug("rewriterules") << "createTrigger:"; getQuantifiersEngine()->registerPattern(pattern); return *Trigger::mkTrigger(getQuantifiersEngine(),n,pattern, - match_gen_kind, true); + Options::current()->efficientEMatching? + Trigger::MATCH_GEN_EFFICIENT_E_MATCH : + Trigger::MATCH_GEN_DEFAULT, + true, + Trigger::TR_MAKE_NEW, + false); + // Options::current()->smartMultiTriggers); }; bool TheoryRewriteRules::notifyIfKnown(const GList * const ltested, @@ -299,9 +314,9 @@ bool TheoryRewriteRules::notifyIfKnown(const GList * const ltested, void TheoryRewriteRules::notification(GList * const lpropa, bool b){ if (b){ - for(GList::const_iterator g = lpropa->begin(); - g != lpropa->end(); ++g) { - (*g).nextGuard(*this); + for(size_t ig = 0; + ig != lpropa->size(); ++ig) { + (*lpropa)[ig].nextGuard(*this); }; lpropa->push_back(Guarded(RULEINST_TRUE,0)); }else{ @@ -315,16 +330,6 @@ void TheoryRewriteRules::notification(GList * const lpropa, bool b){ 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? */ - //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); @@ -384,68 +389,119 @@ void TheoryRewriteRules::notifyEq(TNode lhs, TNode rhs) { }; +Node TheoryRewriteRules::normalizeConjunction(NodeBuilder<> & conjunction){ + Assert(conjunction.getKind() == kind::AND); + switch(conjunction.getNumChildren()){ + case 0: + return d_true; + case 1: + return conjunction[0]; + default: + return conjunction; + } + +} + +void explainInstantiation(const RuleInst *inst, TNode substHead, NodeBuilder<> & conjunction ){ + TypeNode booleanType = NodeManager::currentNM()->booleanType(); + // if the rule is directly applied by the rewriter, + // we should take care to use the representative that can't be directly rewritable: + // If "car(a)" is somewhere and we know that "a = cons(x,l)" we shouldn't + // add the constraint car(cons(x,l) = x because it is rewritten to x = x. + // But we should say cons(a) = x + Assert(!inst->d_matched.isNull()); + Assert( inst->d_matched.getKind() == kind::APPLY_UF); + Assert( substHead.getKind() == kind::APPLY_UF ); + Assert( inst->d_matched.getOperator() == substHead.getOperator() ); + Assert(conjunction.getKind() == kind::AND); + // replace the left hand side by the term really matched + NodeBuilder<2> nb; + for(size_t i = 0, + iend = inst->d_matched.getNumChildren(); i < iend; ++i){ + nb.clear( inst->d_matched[i].getType(false) == booleanType ? + kind::IFF : kind::EQUAL ); + nb << inst->d_matched[i] << substHead[i]; + conjunction << static_cast(nb); + } +} + +Node skolemizeBody( Node f ){ + /*TODO skolemize the subformula of s with constant or skolemize + directly in the body of the rewrite rule with an uninterpreted + function. + */ + if ( f.getKind()!=EXISTS ) return f; + std::vector< Node > vars; + std::vector< Node > csts; + for( int i=0; i<(int)f[0].getNumChildren(); i++ ){ + csts.push_back( NodeManager::currentNM()->mkSkolem( f[0][i].getType()) ); + vars.push_back( f[0][i] ); + } + return f[ 1 ].substitute( vars.begin(), vars.end(), + csts.begin(), csts.end() ); +} + + void TheoryRewriteRules::propagateRule(const RuleInst * inst, TCache cache){ // Debug("rewriterules") << "A rewrite rules is verified. Add lemma:"; - Debug("rewriterules") << "propagateRule" << *inst << std::endl; + Debug("rewriterules::propagate") << "propagateRule" << *inst << std::endl; const RewriteRule * rule = inst->rule; ++rule->nb_applied; // Can be more something else than an equality in fact (eg. propagation rule) - Node equality = inst->substNode(*this,rule->body,cache); + Node equality = skolemizeBody(inst->substNode(*this,rule->body,cache)); if(propagate_as_lemma){ Node lemma = equality; - if(rule->guards.size() > 0){ - // TODO: problem with reduction rule => instead of <=> - lemma = substGuards(inst, cache).impNode(equality); - }; if(rule->directrr){ - TypeNode booleanType = NodeManager::currentNM()->booleanType(); - // if the rule is directly applied by the rewriter, - // we should take care to use the representative that can't be directly rewritable: - // If "car(a)" is somewhere and we know that "a = cons(x,l)" we shouldn't - // add the constraint car(cons(x,l) = x because it is rewritten to x = x. - // But we should say cons(a) = x - Assert(lemma.getKind() == kind::EQUAL || - lemma.getKind() == kind::IMPLIES); - Assert(!inst->d_matched.isNull()); - Assert( inst->d_matched.getOperator() == lemma[0].getOperator() ); - // replace the left hand side by the term really matched + NodeBuilder<> conjunction(kind::AND); + explainInstantiation(inst, + rule->guards.size() > 0? + inst->substNode(*this,rule->guards[0],cache) : equality[0], + conjunction); Debug("rewriterules-directrr") << "lemma:" << lemma << " :: " << inst->d_matched; - Node hyp; - NodeBuilder<2> nb; - if(inst->d_matched.getNumChildren() == 1){ - nb.clear( inst->d_matched[0].getType(false) == booleanType ? - kind::IFF : kind::EQUAL ); - nb << inst->d_matched[0] << lemma[0][0]; - hyp = nb; - }else{ - NodeBuilder<> andb(kind::AND); - for(size_t i = 0, - iend = inst->d_matched.getNumChildren(); i < iend; ++i){ - nb.clear( inst->d_matched[i].getType(false) == booleanType ? - kind::IFF : kind::EQUAL ); - nb << inst->d_matched[i] << lemma[0][i]; - andb << static_cast(nb); - } - hyp = andb; - }; - nb.clear(lemma.getKind()); - nb << inst->d_matched << lemma[1]; - lemma = hyp.impNode(static_cast(nb)); + //rewrite rule + TypeNode booleanType = NodeManager::currentNM()->booleanType(); + if(equality[1].getType(false) == booleanType) + equality = inst->d_matched.iffNode(equality[1]); + else equality = inst->d_matched.eqNode(equality[1]); + lemma = normalizeConjunction(conjunction).impNode(equality); Debug("rewriterules-directrr") << " -> " << lemma << std::endl; - }; - // Debug("rewriterules") << "lemma:" << lemma << std::endl; + } + else if(rule->guards.size() > 0){ + // We can use implication for reduction rules since the head is known + // to be true + NodeBuilder<> conjunction(kind::AND); + substGuards(inst,cache,conjunction); + lemma = normalizeConjunction(conjunction).impNode(equality); + } + Debug("rewriterules::propagate") << "propagated " << lemma << std::endl; getOutputChannel().lemma(lemma); }else{ - Assert(!direct_rewrite); - Node lemma_lit = getValuation().ensureLiteral(equality); + Node lemma_lit = equality; + if(rule->directrr && rule->guards.size() == 0) + lemma_lit = inst->d_matched.eqNode(equality[1]); // rewrite rules + lemma_lit = getValuation().ensureLiteral(lemma_lit); ExplanationMap::const_iterator p = d_explanations.find(lemma_lit); if(p!=d_explanations.end()) return; //Already propagated bool value; if(getValuation().hasSatValue(lemma_lit,value)){ /* Already assigned */ if (!value){ - Node conflict = substGuards(inst,cache,lemma_lit); - getOutputChannel().conflict(conflict); + NodeBuilder<> conflict(kind::AND); + + if(rule->directrr){ + explainInstantiation(inst, + rule->guards.size() > 0? + inst->substNode(*this,rule->guards[0],cache) : equality[0], + conflict); + if(rule->guards.size() > 0){ + //reduction rule + Assert(rule->guards.size() == 1); + conflict << inst->d_matched; //this one will be two times + } + } + substGuards(inst,cache,conflict); + conflict << lemma_lit; + getOutputChannel().conflict(normalizeConjunction(conflict)); }; }else{ getOutputChannel().propagate(lemma_lit); @@ -456,57 +512,79 @@ void TheoryRewriteRules::propagateRule(const RuleInst * inst, TCache cache){ if(simulateRewritting){ static NoMatchAttribute rewrittenNodeAttribute; // Tag the rewritted terms - for(std::vector::iterator i = rule->to_remove.begin(); - i == rule->to_remove.end(); ++i){ - (*i).setAttribute(rewrittenNodeAttribute,true); + // for(std::vector::iterator i = rule->to_remove.begin(); + // i == rule->to_remove.end(); ++i){ + // (*i).setAttribute(rewrittenNodeAttribute,true); + // }; + for(size_t i = 0; i < rule->to_remove.size(); ++i){ + Node rewritten = inst->substNode(*this,rule->to_remove[i],cache); + Debug("rewriterules::simulateRewriting") << "tag " << rewritten << " as rewritten" << std::endl; + rewritten.setAttribute(rewrittenNodeAttribute,true); }; + }; - //Verify that this instantiation can't immediately fire another rule - for(RewriteRule::BodyMatch::const_iterator p = rule->body_match.begin(); - p != rule->body_match.end(); ++p){ - RewriteRule * r = (*p).second; - // Debug("rewriterules") << " rule: " << r << std::endl; - // Use trigger2 since we can be in check - Trigger & tr = r->trigger_for_body_match; - InstMatch im; - TNode m = inst->substNode(*this,(*p).first, cache); - tr.getMatch(m,im); - if(!im.empty()){ - im.d_matched = m; - addMatchRuleTrigger(r, im); + if ( compute_opt && !rule->body_match.empty() ){ + + uf::TheoryUF* uf = static_cast(getQuantifiersEngine()->getTheoryEngine()->getTheory( theory::THEORY_UF )); + eq::EqualityEngine* ee = + static_cast(uf->getEqualityEngine()); + + //Verify that this instantiation can't immediately fire another rule + for(RewriteRule::BodyMatch::const_iterator p = rule->body_match.begin(); + p != rule->body_match.end(); ++p){ + RewriteRule * r = (*p).second; + // Use trigger2 since we can be in check + ApplyMatcher * tr = r->trigger_for_body_match; + Assert(tr != NULL); + tr->resetInstantiationRound(getQuantifiersEngine()); + InstMatch im; + TNode m = inst->substNode(*this,(*p).first, cache); + Assert( m.getKind() == kind::APPLY_UF ); + ee->addTerm(m); + if( tr->reset(m,im,getQuantifiersEngine()) ){ + im.d_matched = m; + Debug("rewriterules::matching") << "SimulatedRewrite: " << std::endl; + addMatchRuleTrigger(r, im); + } } + } }; - -Node TheoryRewriteRules::substGuards(const RuleInst *inst, +void TheoryRewriteRules::substGuards(const RuleInst *inst, TCache cache, - /* Already substituted */ - Node last){ + NodeBuilder<> & conjunction){ const RewriteRule * r = inst->rule; - /** No guards */ - const size_t size = r->guards.size(); - if(size == 0) return (last.isNull()?d_true:last); - /** One guard */ - if(size == 1 && last.isNull()) return inst->substNode(*this,r->guards[0],cache); /** Guards */ /* TODO remove the duplicate with a set like in uf? */ - NodeBuilder<> conjunction(kind::AND); for(std::vector::const_iterator p = r->guards.begin(); p != r->guards.end(); ++p) { Assert(!p->isNull()); conjunction << inst->substNode(*this,*p,cache); }; - if (!last.isNull()) conjunction << last; - return conjunction; } Node TheoryRewriteRules::explain(TNode n){ ExplanationMap::const_iterator p = d_explanations.find(n); Assert(p!=d_explanations.end(),"I forget the explanation..."); - RuleInst i = (*p).second; - //Notice() << n << "<-" << *(i.rule) << std::endl; - return substGuards(&i, TCache ()); + RuleInst inst = (*p).second; + const RewriteRule * rule = inst.rule; + TCache cache; + NodeBuilder<> explanation(kind::AND); + if(rule->directrr){ + explainInstantiation(&inst, + rule->guards.size() > 0? + inst.substNode(*this,rule->guards[0],cache): + inst.substNode(*this,rule->body[0] ,cache), + explanation); + if(rule->guards.size() > 0){ + //reduction rule + Assert(rule->guards.size() == 1); + explanation << inst.d_matched; //this one will be two times + } + }; + substGuards(&inst, cache ,explanation); + return normalizeConjunction(explanation); } void TheoryRewriteRules::collectModelInfo( TheoryModel* m ){ @@ -515,9 +593,39 @@ void TheoryRewriteRules::collectModelInfo( TheoryModel* m ){ Theory::PPAssertStatus TheoryRewriteRules::ppAssert(TNode in, SubstitutionMap& outSubstitutions) { addRewriteRule(in); + d_ppAssert_on = true; return PP_ASSERT_STATUS_UNSOLVED; } +TheoryRewriteRules::Statistics::Statistics(): + d_num_rewriterules("TheoryRewriteRules::Num_RewriteRules", 0), + d_check("TheoryRewriteRules::Check", 0), + d_full_check("TheoryRewriteRules::FullCheck", 0), + d_poll("TheoryRewriteRules::Poll", 0), + d_match_found("TheoryRewriteRules::MatchFound", 0), + d_cache_hit("TheoryRewriteRules::CacheHit", 0), + d_cache_miss("TheoryRewriteRules::CacheMiss", 0) +{ + StatisticsRegistry::registerStat(&d_num_rewriterules); + StatisticsRegistry::registerStat(&d_check); + StatisticsRegistry::registerStat(&d_full_check); + StatisticsRegistry::registerStat(&d_poll); + StatisticsRegistry::registerStat(&d_match_found); + StatisticsRegistry::registerStat(&d_cache_hit); + StatisticsRegistry::registerStat(&d_cache_miss); +} + +TheoryRewriteRules::Statistics::~Statistics(){ + StatisticsRegistry::unregisterStat(&d_num_rewriterules); + StatisticsRegistry::unregisterStat(&d_check); + StatisticsRegistry::unregisterStat(&d_full_check); + StatisticsRegistry::unregisterStat(&d_poll); + StatisticsRegistry::unregisterStat(&d_match_found); + StatisticsRegistry::unregisterStat(&d_cache_hit); + StatisticsRegistry::unregisterStat(&d_cache_miss); +} + + }/* CVC4::theory::rewriterules namespace */ }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/theory/rewriterules/theory_rewriterules.h b/src/theory/rewriterules/theory_rewriterules.h index d1c3eecf3..fcbdfe8b9 100644 --- a/src/theory/rewriterules/theory_rewriterules.h +++ b/src/theory/rewriterules/theory_rewriterules.h @@ -27,7 +27,9 @@ #include "theory/theory_engine.h" #include "theory/quantifiers_engine.h" #include "context/context_mm.h" -#include "theory/inst_match_impl.h" +#include "theory/rr_inst_match_impl.h" +#include "theory/rr_trigger.h" +#include "theory/rr_inst_match.h" #include "util/stats.h" #include "theory/rewriterules/theory_rewriterules_preprocess.h" #include "theory/model.h" @@ -35,6 +37,8 @@ namespace CVC4 { namespace theory { namespace rewriterules { +using namespace CVC4::theory::rrinst; +typedef CVC4::theory::rrinst::Trigger Trigger; typedef std::hash_map TCache; @@ -45,6 +49,7 @@ typedef std::hash_map TCache; class RewriteRule{ public: // constant + const size_t id; //for debugging const bool d_split; mutable Trigger trigger; std::vector guards; @@ -58,7 +63,7 @@ typedef std::hash_map TCache; rule) */ typedef context::CDList< std::pair > BodyMatch; mutable BodyMatch body_match; - mutable Trigger trigger_for_body_match; // used because we can be matching + mutable ApplyMatcher * trigger_for_body_match; // used because we can be matching // trigger when we need new match. // So currently we use another // trigger for that. @@ -70,7 +75,7 @@ typedef std::hash_map TCache; const bool directrr; RewriteRule(TheoryRewriteRules & re, - Trigger & tr, Trigger & tr2, + Trigger & tr, ApplyMatcher * tr2, std::vector & g, Node b, TNode nt, std::vector & fv,std::vector & iv, std::vector & to_r, bool drr); @@ -183,6 +188,7 @@ private: inside check */ typedef std::vector< RuleInst* > QRuleInsts; QRuleInsts d_ruleinsts_to_add; + bool d_ppAssert_on; //Indicate if a ppAssert have been done public: /** true and false for predicate */ @@ -240,15 +246,17 @@ private: already true */ bool notifyIfKnown(const GList * const ltested, GList * const lpropa); - Node substGuards(const RuleInst * inst, + void substGuards(const RuleInst * inst, TCache cache, - Node last = Node::null()); + NodeBuilder<> & conjunction); void addRewriteRule(const Node r); void computeMatchBody ( const RewriteRule * r, size_t start = 0); void addMatchRuleTrigger(const RewriteRule* r, InstMatch & im, bool delay = true); + Node normalizeConjunction(NodeBuilder<> & conjunction); + /* rewrite pattern */ typedef std::hash_map< Node, rewriter::RRPpRewrite*, NodeHashFunction > RegisterRRPpRewrite; RegisterRRPpRewrite d_registeredRRPpRewrite; @@ -257,6 +265,21 @@ private: rewriter::Subst & pvars, rewriter::Subst & vars); + /** statistics class */ + class Statistics { + public: + IntStat d_num_rewriterules; + IntStat d_check; + IntStat d_full_check; + IntStat d_poll; + IntStat d_match_found; + IntStat d_cache_hit; + IntStat d_cache_miss; + Statistics(); + ~Statistics(); + }; + Statistics d_statistics; + };/* class TheoryRewriteRules */ }/* CVC4::theory::rewriterules namespace */ diff --git a/src/theory/rewriterules/theory_rewriterules_params.h b/src/theory/rewriterules/theory_rewriterules_params.h index 9ab2ae3e7..de51215d1 100644 --- a/src/theory/rewriterules/theory_rewriterules_params.h +++ b/src/theory/rewriterules/theory_rewriterules_params.h @@ -17,7 +17,6 @@ ** \todo document this file **/ - #ifndef __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_PARAMS_H #define __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_PARAMS_H @@ -58,7 +57,7 @@ static const bool representative_instantiation = false; Allow to break loop with other theories. */ -static const size_t checkSlowdown = 10; +static const size_t checkSlowdown = 0; /** Use the current model to eliminate guard before asking for notification @@ -68,14 +67,7 @@ static const bool useCurrentModel = false; /** Simulate rewriting by tagging rewritten terms. */ -static const bool simulateRewritting = false; - -/** - Choose the kind of matching to use: - - InstMatchGenerator::MATCH_GEN_DEFAULT 0 - - InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH 1 -*/ -static const int match_gen_kind = 0; +static const bool simulateRewritting = true; /** Do narrowing at full effort @@ -85,7 +77,7 @@ static const bool narrowing_full_effort = false; /** Direct rewrite: Add rewrite rules directly in the rewriter. */ -static const bool direct_rewrite = true; +static const bool direct_rewrite = false; }/* CVC4::theory::rewriterules namespace */ }/* CVC4::theory namespace */ diff --git a/src/theory/rewriterules/theory_rewriterules_rules.cpp b/src/theory/rewriterules/theory_rewriterules_rules.cpp index c3116aba0..1ad8fdaa7 100644 --- a/src/theory/rewriterules/theory_rewriterules_rules.cpp +++ b/src/theory/rewriterules/theory_rewriterules_rules.cpp @@ -21,6 +21,7 @@ #include "theory/rewriterules/theory_rewriterules_params.h" #include "theory/rewriterules/theory_rewriterules_preprocess.h" #include "theory/rewriterules/theory_rewriterules.h" +#include "util/options.h" #include "theory/quantifiers/term_database.h" @@ -30,12 +31,46 @@ using namespace CVC4::kind; using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::rewriterules; +using namespace CVC4::theory::rrinst; namespace CVC4 { namespace theory { namespace rewriterules { +// TODO replace by a real dictionnary +// We should create a real substitution? slower more precise +// We don't do that often +bool nonunifiable( TNode t0, TNode pattern, const std::vector & vars){ + typedef std::vector > tstack; + tstack stack(1,std::make_pair(t0,pattern)); // t * pat + + while(!stack.empty()){ + const std::pair p = stack.back(); stack.pop_back(); + const TNode & t = p.first; + const TNode & pat = p.second; + + // t or pat is a variable currently we consider that can match anything + if( find(vars.begin(),vars.end(),t) != vars.end() ) continue; + if( pat.getKind() == INST_CONSTANT ) continue; + + // t and pat are nonunifiable + if( !Trigger::isAtomicTrigger( t ) || !Trigger::isAtomicTrigger( pat ) ) { + if(t == pat) continue; + else return true; + }; + if( t.getOperator() != pat.getOperator() ) return true; + + //put the children on the stack + for( size_t i=0; i < pat.getNumChildren(); i++ ){ + stack.push_back(std::make_pair(t[i],pat[i])); + }; + } + // The heuristic can't find non-unifiability + return false; +} + + void TheoryRewriteRules::computeMatchBody ( const RewriteRule * rule, size_t start){ std::vector stack(1,rule->new_terms); @@ -50,9 +85,9 @@ void TheoryRewriteRules::computeMatchBody ( const RewriteRule * rule, if( t.getKind() == APPLY_UF ){ for(size_t rid = start, end = d_rules.size(); rid < end; ++rid) { RewriteRule * r = d_rules[rid]; - if(r->d_split) continue; - Trigger & tr = const_cast (r->trigger_for_body_match); - if(!tr.nonunifiable(t, rule->free_vars)){ + if(r->d_split || r->trigger_for_body_match == NULL) continue; + //the split rules are not computed and the one with multi-pattern + if( !nonunifiable(t, r->trigger_for_body_match->d_pattern, rule->free_vars)){ rule->body_match.push_back(std::make_pair(t,r)); } } @@ -74,7 +109,10 @@ 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()->getTermDatabase()-> + pattern.push_back( + Options::current()->rewriteRulesAsAxioms? + static_cast(tri): + re.getQuantifiersEngine()->getTermDatabase()-> convertNodeToPattern(tri,r,vars,inst_constants)); } @@ -106,6 +144,7 @@ bool checkPatternVars(const std::vector & pattern, void TheoryRewriteRules::addRewriteRule(const Node r) { Assert(r.getKind() == kind::REWRITE_RULE); + Kind rrkind = r[2].getKind(); /* Replace variables by Inst_* variable and tag the terms that contain them */ std::vector vars; @@ -125,16 +164,20 @@ void TheoryRewriteRules::addRewriteRule(const Node r) when fired */ /* shortcut */ TNode head = r[2][0]; - switch(r[2].getKind()){ + TypeNode booleanType = NodeManager::currentNM()->booleanType(); + switch(rrkind){ case kind::RR_REWRITE: /* Equality */ to_remove.push_back(head); addPattern(*this,head,pattern,vars,inst_constants,r); - body = head.eqNode(body); + if(head.getType(false) == booleanType) body = head.iffNode(body); + else body = head.eqNode(body); break; case kind::RR_REDUCTION: /** Add head to remove */ - to_remove.push_back(head); + for(Node::iterator i = head.begin(); i != head.end(); ++i) { + to_remove.push_back(*i); + }; case kind::RR_DEDUCTION: /** Add head to guards and pattern */ switch(head.getKind()){ @@ -171,32 +214,65 @@ void TheoryRewriteRules::addRewriteRule(const Node r) }; /* Add the other triggers */ if( r[2].getNumChildren() >= 3 ) - for(Node::iterator i = r[2][2].begin(); i != r[2][2].end(); ++i) { + for(Node::iterator i = r[2][2][0].begin(); i != r[2][2][0].end(); ++i) { // todo test during typing that its a good term (no not, atom, or term...) - addPattern(*this,(*i)[0],pattern,vars,inst_constants,r); + addPattern(*this,*i,pattern,vars,inst_constants,r); }; // Assert(pattern.size() == 1, "currently only single pattern are supported"); + + + + + //If we convert to usual axioms + if(Options::current()->rewriteRulesAsAxioms){ + NodeBuilder<> forallB(kind::FORALL); + forallB << r[0]; + NodeBuilder<> guardsB(kind::AND); + guardsB.append(guards); + forallB << normalizeConjunction(guardsB).impNode(body); + NodeBuilder<> patternB(kind::INST_PATTERN); + patternB.append(pattern); + NodeBuilder<> patternListB(kind::INST_PATTERN_LIST); + patternListB << static_cast(patternB); + forallB << static_cast(patternListB); + getOutputChannel().lemma((Node) forallB); + return; + } + + //turn all to propagate + // if(true){ + // NodeBuilder<> guardsB(kind::AND); + // guardsB.append(guards); + // body = normalizeConjunction(guardsB).impNode(body); + // guards.clear(); + // rrkind = kind::RR_DEDUCTION; + // } + + //Every variable must be seen in the pattern if (!checkPatternVars(pattern,inst_constants)){ - Warning() << "The rule" << r << + Warning() << Node::setdepth(-1) << "The rule" << r << " has been removed since it doesn't contain every variables." << std::endl; return; } + //Add to direct rewrite rule bool directrr = false; if(direct_rewrite && - ((guards.size() == 0 && r[2].getKind() == kind::RR_REWRITE) || - (guards.size() == 1 && r[2].getKind() == kind::RR_REDUCTION)) + guards.size() == 0 && rrkind == kind::RR_REWRITE && pattern.size() == 1){ directrr = addRewritePattern(pattern[0],new_terms, inst_constants, vars); } + // final construction Trigger trigger = createTrigger(r,pattern); - Trigger trigger2 = createTrigger(r,pattern); //Hack - RewriteRule * rr = new RewriteRule(*this, trigger, trigger2, + ApplyMatcher * applymatcher = + pattern.size() == 1 && pattern[0].getKind() == kind::APPLY_UF? + new ApplyMatcher(pattern[0],getQuantifiersEngine()) : NULL; + RewriteRule * rr = new RewriteRule(*this, trigger, applymatcher, guards, body, new_terms, vars, inst_constants, to_remove, directrr); @@ -209,7 +285,7 @@ void TheoryRewriteRules::addRewriteRule(const Node r) computeMatchBody(d_rules[rid], d_rules.size() - 1); - Debug("rewriterules") << "created rewriterule"<< (rr->d_split?"(split)":"") << ":(" << d_rules.size() - 1 << ")" + Debug("rewriterules::new") << "created rewriterule"<< (rr->d_split?"(split)":"") << ":(" << d_rules.size() - 1 << ")" << *rr << std::endl; } @@ -227,7 +303,7 @@ bool willDecide(TNode node, bool positive = true){ case XOR: return true; case IMPLIES: - return false; + return true; case ITE: return true; case NOT: @@ -237,45 +313,50 @@ bool willDecide(TNode node, bool positive = true){ } } - +static size_t id_next = 0; RewriteRule::RewriteRule(TheoryRewriteRules & re, - Trigger & tr, Trigger & tr2, + Trigger & tr, ApplyMatcher * applymatcher, std::vector & g, Node b, TNode nt, std::vector & fv,std::vector & iv, std::vector & to_r, bool drr) : - d_split(willDecide(b)), + id(++id_next), d_split(willDecide(b)), trigger(tr), body(b), new_terms(nt), free_vars(), inst_vars(), - body_match(re.getSatContext()),trigger_for_body_match(tr2), + body_match(re.getSatContext()),trigger_for_body_match(applymatcher), d_cache(re.getSatContext(),re.getQuantifiersEngine()), directrr(drr){ free_vars.swap(fv); inst_vars.swap(iv); guards.swap(g); to_remove.swap(to_r); }; bool RewriteRule::inCache(TheoryRewriteRules & re, InstMatch & im)const{ - return !d_cache.addInstMatch(im); + bool res = !d_cache.addInstMatch(im); + Debug("rewriterules::matching") << "rewriterules::cache " << im + << (res ? " HIT" : " MISS") << std::endl; + return res; }; /** A rewrite rule */ void RewriteRule::toStream(std::ostream& out) const{ + out << "[" << id << "] "; for(std::vector::const_iterator iter = guards.begin(); iter != guards.end(); ++iter){ out << *iter; }; out << "=>" << body << std::endl; - out << "["; + out << "{"; for(BodyMatch::const_iterator iter = body_match.begin(); iter != body_match.end(); ++iter){ - out << (*iter).first << "(" << (*iter).second << ")" << ","; + out << (*iter).first << "[" << (*iter).second->id << "]" << ","; }; - out << "]" << (directrr?"*":"") << std::endl; + out << "}" << (directrr?"*":"") << std::endl; } RewriteRule::~RewriteRule(){ - Debug("rewriterule-stats") << *this + Debug("rewriterule::stats") << *this << " (" << nb_matched << "," << nb_applied << "," << nb_propagated << ")" << std::endl; + delete(trigger_for_body_match); } bool TheoryRewriteRules::addRewritePattern(TNode pattern, TNode body, diff --git a/src/theory/rewriterules/theory_rewriterules_type_rules.h b/src/theory/rewriterules/theory_rewriterules_type_rules.h index 8bc4522a1..605324b20 100644 --- a/src/theory/rewriterules/theory_rewriterules_type_rules.h +++ b/src/theory/rewriterules/theory_rewriterules_type_rules.h @@ -45,16 +45,16 @@ public: Assert(n.getKind() == kind::REWRITE_RULE && n.getNumChildren()==3 ); if( check ){ if( n[ 0 ].getType(check)!=nodeManager->boundVarListType() ){ - throw TypeCheckingExceptionPrivate(n, + throw TypeCheckingExceptionPrivate(n[0], "first argument of rewrite rule is not bound var list"); } if( n[ 1 ].getType(check)!=nodeManager->booleanType() ){ - throw TypeCheckingExceptionPrivate(n, + throw TypeCheckingExceptionPrivate(n[1], "guard of rewrite rule is not an actual guard"); } if( n[2].getType(check) != TypeNode(nodeManager->mkTypeConst(RRHB_TYPE))){ - throw TypeCheckingExceptionPrivate(n, + throw TypeCheckingExceptionPrivate(n[2], "not a correct rewrite rule"); } } diff --git a/src/theory/rr_inst_match.cpp b/src/theory/rr_inst_match.cpp new file mode 100644 index 000000000..3ba0c8d32 --- /dev/null +++ b/src/theory/rr_inst_match.cpp @@ -0,0 +1,1447 @@ +/********************* */ +/*! \file inst_match.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 inst match class + **/ + +#include "theory/inst_match.h" +#include "theory/rr_inst_match.h" +#include "theory/rr_trigger.h" +#include "theory/rr_inst_match_impl.h" +#include "theory/theory_engine.h" +#include "theory/quantifiers_engine.h" +#include "theory/uf/theory_uf_instantiator.h" +#include "theory/uf/theory_uf_candidate_generator.h" +#include "theory/datatypes/theory_datatypes_candidate_generator.h" +#include "theory/uf/equality_engine.h" +#include "theory/arrays/theory_arrays.h" + +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::rrinst; +using namespace CVC4::theory::uf::rrinst; +using namespace CVC4::theory::eq::rrinst; + +namespace CVC4{ +namespace theory{ +namespace rrinst{ + +typedef CVC4::theory::inst::InstMatch InstMatch; +typedef CVC4::theory::inst::CandidateGeneratorQueue CandidateGeneratorQueue; + +template +class InstMatchTrie2Pairs +{ + typename std::vector< std::vector < typename InstMatchTrie2Gen::Tree > > d_data; + InstMatchTrie2Gen d_backtrack; +public: + InstMatchTrie2Pairs(context::Context* c, QuantifiersEngine* q, size_t n): + d_backtrack(c,q) { + // resize to a triangle + // + // | * + // | * * + // | * * * + // | -----> i + d_data.resize(n); + for(size_t i=0; i < n; ++i){ + d_data[i].resize(i+1,typename InstMatchTrie2Gen::Tree(0)); + } + }; + InstMatchTrie2Pairs(const InstMatchTrie2Pairs &) CVC4_UNDEFINED; + const InstMatchTrie2Pairs & operator =(const InstMatchTrie2Pairs & e) CVC4_UNDEFINED; + /** add match m in the trie, + return true if it was never seen */ + inline bool addInstMatch( size_t i, size_t j, InstMatch& m){ + size_t k = std::min(i,j); + size_t l = std::max(i,j); + return d_backtrack.addInstMatch(m,&(d_data[l][k])); + }; + inline bool addInstMatch( size_t i, InstMatch& m){ + return d_backtrack.addInstMatch(m,&(d_data[i][i])); + }; + +}; + + +// Currently the implementation doesn't take into account that +// variable should have the same value given. +// TODO use the d_children way perhaps +// TODO replace by a real dictionnary +// We should create a real substitution? slower more precise +// We don't do that often +bool nonunifiable( TNode t0, TNode pat, const std::vector & vars){ + if(pat.isNull()) return true; + + typedef std::vector > tstack; + tstack stack(1,std::make_pair(t0,pat)); // t * pat + + while(!stack.empty()){ + const std::pair p = stack.back(); stack.pop_back(); + const TNode & t = p.first; + const TNode & pat = p.second; + + // t or pat is a variable currently we consider that can match anything + if( find(vars.begin(),vars.end(),t) != vars.end() ) continue; + if( pat.getKind() == INST_CONSTANT ) continue; + + // t and pat are nonunifiable + if( !Trigger::isAtomicTrigger( t ) || !Trigger::isAtomicTrigger( pat ) ) { + if(t == pat) continue; + else return true; + }; + if( t.getOperator() != pat.getOperator() ) return true; + + //put the children on the stack + for( size_t i=0; i < pat.getNumChildren(); i++ ){ + stack.push_back(std::make_pair(t[i],pat[i])); + }; + } + // The heuristic can't find non-unifiability + return false; +}; + +/** New things */ +class DumbMatcher: public Matcher{ + void resetInstantiationRound( QuantifiersEngine* qe ){}; + bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ){ + return false; + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return false; + } +}; + +class DumbPatMatcher: public PatMatcher{ + void resetInstantiationRound( QuantifiersEngine* qe ){}; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + return false; + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return false; + } +}; + + +/* The order of the matching is: + reset arg1, nextMatch arg1, reset arg2, nextMatch arg2, ... */ +ApplyMatcher::ApplyMatcher( Node pat, QuantifiersEngine* qe): d_pattern(pat){ + // Assert( pat.hasAttribute(InstConstantAttribute()) ); + + //set-up d_variables, d_constants, d_childrens + for( size_t i=0; i< d_pattern.getNumChildren(); ++i ){ + EqualityQuery* q = qe->getEqualityQuery(d_pattern[i].getType()); + Assert( q != NULL ); + if( d_pattern[i].hasAttribute(InstConstantAttribute()) ){ + if( d_pattern[i].getKind()==INST_CONSTANT ){ + //It's a variable + d_variables.push_back(make_triple((TNode)d_pattern[i],i,q)); + }else{ + //It's neither a constant argument neither a variable + //we create the matcher for the subpattern + d_childrens.push_back(make_triple(mkMatcher((TNode)d_pattern[i], qe),i,q)); + }; + }else{ + // It's a constant + d_constants.push_back(make_triple((TNode)d_pattern[i],i,q)); + } + } +} + +void ApplyMatcher::resetInstantiationRound( QuantifiersEngine* qe ){ + for( size_t i=0; i< d_childrens.size(); i++ ){ + d_childrens[i].first->resetInstantiationRound( qe ); + } +} + +bool ApplyMatcher::reset(TNode t, InstMatch & m, QuantifiersEngine* qe){ + Debug("matching") << "Matching " << t << " against pattern " << d_pattern << " (" + << m.size() << ")" << std::endl; + + //if t is null + Assert( !t.isNull() ); + Assert( !t.hasAttribute(InstConstantAttribute()) ); + Assert( t.getKind()==d_pattern.getKind() ); + Assert( (t.getKind()!=APPLY_UF && t.getKind()!=APPLY_CONSTRUCTOR) + || t.getOperator()==d_pattern.getOperator() ); + + typedef std::vector< triple >::iterator iterator; + for(iterator i = d_constants.begin(), end = d_constants.end(); + i != end; ++i){ + if( !i->third->areEqual( i->first, t[i->second] ) ){ + Debug("matching-fail") << "Match fail arg: " << i->first << " and " << t[i->second] << std::endl; + //setMatchFail( qe, d_pattern[i], t[i] ); + //ground arguments are not equal + return false; + } + } + + d_binded.clear(); + bool set; + for(iterator i = d_variables.begin(), end = d_variables.end(); + i != end; ++i){ + if( !m.setMatch( i->third, i->first, t[i->second], set) ){ + //match is in conflict + Debug("matching-debug") << "Match in conflict " << t[i->second] << " and " + << i->first << " because " + << m.get(i->first) + << std::endl; + Debug("matching-fail") << "Match fail: " << m.get(i->first) << " and " << t[i->second] << std::endl; + //setMatchFail( qe, partial[0].d_map[d_pattern[i]], t[i] ); + m.erase(d_binded.begin(), d_binded.end()); + return false; + }else{ + if(set){ //The variable has just been set + d_binded.push_back(i->first); + } + } + } + + //now, fit children into match + //we will be requesting candidates for matching terms for each child + d_reps.clear(); + for( size_t i=0; i< d_childrens.size(); i++ ){ + Debug("matching-debug") << "Take the representative of " << t[ d_childrens[i].second ] << std::endl; + Assert( d_childrens[i].third->hasTerm(t[ d_childrens[i].second ]) ); + Node rep = d_childrens[i].third->getRepresentative( t[ d_childrens[i].second ] ); + d_reps.push_back( rep ); + } + + if(d_childrens.size() == 0) return true; + else return getNextMatch(m, qe, true); +} + +bool ApplyMatcher::getNextMatch(InstMatch& m, QuantifiersEngine* qe, bool reset){ + Assert(d_childrens.size() > 0); + const size_t max = d_childrens.size() - 1; + size_t index = reset ? 0 : max; + Assert(d_childrens.size() == d_reps.size()); + while(true){ + if(reset ? + d_childrens[index].first->reset( d_reps[index], m, qe ) : + d_childrens[index].first->getNextMatch( m, qe )){ + if(index==max) return true; + ++index; + reset=true; + }else{ + if(index==0){ + m.erase(d_binded.begin(), d_binded.end()); + return false; + } + --index; + reset=false; + }; + } +} + +bool ApplyMatcher::getNextMatch(InstMatch& m, QuantifiersEngine* qe){ + if(d_childrens.size() == 0){ + m.erase(d_binded.begin(), d_binded.end()); + return false; + } else return getNextMatch(m, qe, false); +} + +/** Proxy that call the sub-matcher on the result return by the given candidate generator */ +template +class CandidateGeneratorMatcher: public Matcher{ + /** candidate generator */ + CG d_cg; + /** the sub-matcher */ + M d_m; +public: + CandidateGeneratorMatcher(CG cg, M m): d_cg(cg), d_m(m) + {/* last is Null */}; + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cg.resetInstantiationRound(); + d_m.resetInstantiationRound(qe); + }; + bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ){ + d_cg.reset(n); + return findMatch(m,qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + // The sub-matcher has another match + return d_m.getNextMatch(m, qe) || findMatch(m,qe); + } +private: + bool findMatch( InstMatch& m, QuantifiersEngine* qe ){ + // Otherwise try to find a new candidate that has at least one match + while(true){ + TNode n = d_cg.getNextCandidate();//kept somewhere Term-db + Debug("matching") << "GenCand " << n << " (" << this << ")" << std::endl; + if(n.isNull()) return false; + if(d_m.reset(n,m,qe)) return true; + }; + } +}; + +/** Proxy that call the sub-matcher on the result return by the given candidate generator */ +template +class PatOfMatcher: public PatMatcher{ + M d_m; +public: + inline PatOfMatcher(M m): d_m(m){} + void resetInstantiationRound(QuantifiersEngine* qe){ + d_m.resetInstantiationRound(qe); + } + bool reset(InstMatch& m, QuantifiersEngine* qe){ + return d_m.reset(Node::null(),m,qe); + }; + bool getNextMatch(InstMatch& m, QuantifiersEngine* qe){ + return d_m.getNextMatch(m,qe); + }; +}; + +class ArithMatcher: public Matcher{ +private: + /** for arithmetic matching */ + std::map< Node, Node > d_arith_coeffs; + /** get the match against ground term or formula t. + d_match_mattern and t should have the same shape. + only valid for use where !d_match_pattern.isNull(). + */ + /** the variable that are set by this matcher */ + std::vector< TNode > d_binded; /* TNode because the variables are already in d_arith_coeffs */ + Node d_pattern; //for debugging +public: + ArithMatcher(Node pat, QuantifiersEngine* qe); + void resetInstantiationRound( QuantifiersEngine* qe ){}; + bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ); + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ); +}; + +/** Match just a variable */ +class VarMatcher: public Matcher{ + Node d_var; + bool d_binded; /* True if the reset bind the variable to some value */ + EqualityQuery* d_q; +public: + VarMatcher(Node var, QuantifiersEngine* qe): d_var(var), d_binded(false){ + d_q = qe->getEqualityQuery(var.getType()); + } + void resetInstantiationRound( QuantifiersEngine* qe ){}; + bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ){ + if(!m.setMatch( d_q, d_var, n, d_binded )){ + //match is in conflict + Debug("matching-fail") << "Match fail: " << m.get(d_var) + << " and " << n << std::endl; + return false; + } else return true; + }; + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + //match is in conflict + if (d_binded) m.erase(d_var); + return false; + } +}; + +template +class TestMatcher: public Matcher{ + M d_m; + Test d_test; +public: + inline TestMatcher(M m, Test test): d_m(m), d_test(test){} + inline void resetInstantiationRound(QuantifiersEngine* qe){ + d_m.resetInstantiationRound(qe); + } + inline bool reset(TNode n, InstMatch& m, QuantifiersEngine* qe){ + return d_test(n) && d_m.reset(n, m, qe); + } + inline bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_m.getNextMatch(m, qe); + } +}; + +class LegalOpTest/*: public unary_function*/ { + Node d_op; +public: + inline LegalOpTest(Node op): d_op(op){} + inline bool operator() (TNode n) { + return + CandidateGenerator::isLegalCandidate(n) && + // ( // n.getKind()==SELECT || n.getKind()==STORE || + // n.getKind()==APPLY_UF || n.getKind()==APPLY_CONSTRUCTOR) && + n.hasOperator() && + n.getOperator()==d_op; + }; +}; + +class LegalKindTest/* : public unary_function*/ { + Kind d_kind; +public: + inline LegalKindTest(Kind kind): d_kind(kind){} + inline bool operator() (TNode n) { + return + CandidateGenerator::isLegalCandidate(n) && + n.getKind()==d_kind; + }; +}; + +class LegalTypeTest/* : public unary_function*/ { + TypeNode d_type; +public: + inline LegalTypeTest(TypeNode type): d_type(type){} + inline bool operator() (TNode n) { + return + CandidateGenerator::isLegalCandidate(n) && + n.getType()==d_type; + }; +}; + +class LegalTest/* : public unary_function*/ { +public: + inline bool operator() (TNode n) { + return CandidateGenerator::isLegalCandidate(n); + }; +}; + +size_t numFreeVar(TNode t){ + size_t n = 0; + for( size_t i=0, size =t.getNumChildren(); i < size; ++i ){ + if( t[i].hasAttribute(InstConstantAttribute()) ){ + if( t[i].getKind()==INST_CONSTANT ){ + //variable + ++n; + }else{ + //neither variable nor constant + n += numFreeVar(t[i]); + } + } + } + return n; +} + +class OpMatcher: public Matcher{ + /* The matcher */ + typedef ApplyMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2> AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + Assert( pat.getKind() == kind::APPLY_UF ); + /** In reverse order of matcher sequence */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good operator */ + AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator())); + /** Iter on the equivalence class of the given term */ + uf::TheoryUF* uf = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )); + eq::EqualityEngine* ee = + static_cast(uf->getEqualityEngine()); + CandidateGeneratorTheoryEeClass cdtUfEq(ee); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtUfEq,am2); + return am1; + } + size_t d_num_var; + Node d_pat; +public: + OpMatcher( Node pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)),d_num_var(numFreeVar(pat)), + d_pat(pat) {} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ + // size_t m_size = m.d_map.size(); + // if(m_size == d_num_var){ + // uf::EqualityEngine* ee = (static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )))->getEqualityEngine(); + // std::cout << "!"; + // return ee->areEqual(m.subst(d_pat),t); + // }else{ + // std::cout << m.d_map.size() << std::endl; + return d_cgm.reset(t, m, qe); + // } + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +class DatatypesMatcher: public Matcher{ + /* The matcher */ + typedef ApplyMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< datatypes::rrinst::CandidateGeneratorTheoryClass, AuxMatcher2> AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + Assert( pat.getKind() == kind::APPLY_CONSTRUCTOR, + "For datatypes only constructor are accepted in pattern" ); + /** In reverse order of matcher sequence */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good operator */ + AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator())); + /** Iter on the equivalence class of the given term */ + datatypes::TheoryDatatypes* dt = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_DATATYPES )); + datatypes::rrinst::CandidateGeneratorTheoryClass cdtDtEq(dt); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtDtEq,am2); + return am1; + } + Node d_pat; +public: + DatatypesMatcher( Node pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)), + d_pat(pat) {} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ + Debug("matching") << "datatypes: " << t << " matches " << d_pat << std::endl; + return d_cgm.reset(t, m, qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +class ArrayMatcher: public Matcher{ + /* The matcher */ + typedef ApplyMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalKindTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2> AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + Assert( pat.getKind() == kind::SELECT || pat.getKind() == kind::STORE ); + /** In reverse order of matcher sequence */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good operator */ + AuxMatcher2 am2(am3, LegalKindTest(pat.getKind())); + /** Iter on the equivalence class of the given term */ + arrays::TheoryArrays* ar = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_ARRAY )); + eq::EqualityEngine* ee = + static_cast(ar->getEqualityEngine()); + CandidateGeneratorTheoryEeClass cdtUfEq(ee); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtUfEq,am2); + return am1; + } + size_t d_num_var; + Node d_pat; +public: + ArrayMatcher( Node pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)),d_num_var(numFreeVar(pat)), + d_pat(pat) {} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ + // size_t m_size = m.d_map.size(); + // if(m_size == d_num_var){ + // uf::EqualityEngine* ee = (static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )))->getEqualityEngine(); + // std::cout << "!"; + // return ee->areEqual(m.subst(d_pat),t); + // }else{ + // std::cout << m.d_map.size() << std::endl; + return d_cgm.reset(t, m, qe); + // } + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +class AllOpMatcher: public PatMatcher{ + /* The matcher */ + typedef ApplyMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryUfOp, AuxMatcher2> AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + Assert( pat.hasOperator() ); + /** In reverse order of matcher sequence */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good operator */ + AuxMatcher2 am2(am3,LegalTest()); + /** Iter on the equivalence class of the given term */ + TermDb* tdb = qe->getTermDatabase(); + CandidateGeneratorTheoryUfOp cdtUfEq(pat.getOperator(),tdb); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtUfEq,am2); + return am1; + } + size_t d_num_var; + Node d_pat; +public: + AllOpMatcher( TNode pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)), d_num_var(numFreeVar(pat)), + d_pat(pat) {} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + // std::cout << m.d_map.size() << "/" << d_num_var << std::endl; + return d_cgm.reset(Node::null(), m, qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +template /** true classes | false class */ +class GenericCandidateGeneratorClasses: public CandidateGenerator{ +private: + CandidateGenerator* d_cg; + QuantifiersEngine* d_qe; + +public: + void mkCandidateGenerator(){ + if(classes) + d_cg = d_qe->getRRCanGenClasses(); + else + d_cg = d_qe->getRRCanGenClass(); + } + + GenericCandidateGeneratorClasses(QuantifiersEngine* qe): + d_qe(qe) { + mkCandidateGenerator(); + } + ~GenericCandidateGeneratorClasses(){ + delete(d_cg); + } + const GenericCandidateGeneratorClasses & operator =(const GenericCandidateGeneratorClasses & m){ + mkCandidateGenerator(); + return m; + }; + GenericCandidateGeneratorClasses(const GenericCandidateGeneratorClasses & m): + d_qe(m.d_qe){ + mkCandidateGenerator(); + } + void resetInstantiationRound(){ + d_cg->resetInstantiationRound(); + }; + void reset( TNode eqc ){ + Assert( !classes || eqc.isNull() ); + d_cg->reset(eqc); + }; //* the argument is not used + TNode getNextCandidate(){ + return d_cg->getNextCandidate(); + }; +}; /* MetaCandidateGeneratorClasses */ + + +class GenericMatcher: public Matcher{ + /* The matcher */ + typedef ApplyMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< GenericCandidateGeneratorClasses, AuxMatcher2> AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + /** In reverse order of matcher sequence */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good operator */ + AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator())); + /** Iter on the equivalence class of the given term */ + GenericCandidateGeneratorClasses cdtG(qe); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtG,am2); + return am1; + } + Node d_pat; +public: + GenericMatcher( Node pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)), + d_pat(pat) {} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.reset(t, m, qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + + +class GenericPatMatcher: public PatMatcher{ + /* The matcher */ + typedef ApplyMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< GenericCandidateGeneratorClasses, AuxMatcher2> AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + /** In reverse order of matcher sequence */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good operator */ + AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator())); + /** Iter on the equivalence class of the given term */ + GenericCandidateGeneratorClasses cdtG(qe); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtG,am2); + return am1; + } + Node d_pat; +public: + GenericPatMatcher( Node pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)), + d_pat(pat) {} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.reset(Node::null(), m, qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +class MetaCandidateGeneratorClasses: public CandidateGenerator{ +private: + CandidateGenerator* d_cg; + TypeNode d_ty; + TheoryEngine* d_te; + +public: + CandidateGenerator* mkCandidateGenerator(TypeNode ty, TheoryEngine* te){ + Debug("inst-match-gen") << "MetaCandidateGenerator for type: " << ty + << " Theory : " << Theory::theoryOf(ty) << std::endl; + if( Theory::theoryOf(ty) == theory::THEORY_DATATYPES ){ + // datatypes::TheoryDatatypes* dt = static_cast(te->getTheory( theory::THEORY_DATATYPES )); + // return new datatypes::rrinst::CandidateGeneratorTheoryClasses(dt); + Unimplemented("MetaCandidateGeneratorClasses for THEORY_DATATYPES"); + }else if ( Theory::theoryOf(ty) == theory::THEORY_ARRAY ){ + arrays::TheoryArrays* ar = static_cast(te->getTheory( theory::THEORY_ARRAY )); + eq::EqualityEngine* ee = + static_cast(ar->getEqualityEngine()); + return new CandidateGeneratorTheoryEeClasses(ee); + } else { + uf::TheoryUF* uf = static_cast(te->getTheory( theory::THEORY_UF )); + eq::EqualityEngine* ee = + static_cast(uf->getEqualityEngine()); + return new CandidateGeneratorTheoryEeClasses(ee); + } + } + MetaCandidateGeneratorClasses(TypeNode ty, TheoryEngine* te): + d_ty(ty), d_te(te) { + d_cg = mkCandidateGenerator(ty,te); + } + ~MetaCandidateGeneratorClasses(){ + delete(d_cg); + } + const MetaCandidateGeneratorClasses & operator =(const MetaCandidateGeneratorClasses & m){ + d_cg = mkCandidateGenerator(m.d_ty, m.d_te); + return m; + }; + MetaCandidateGeneratorClasses(const MetaCandidateGeneratorClasses & m): + d_ty(m.d_ty), d_te(m.d_te){ + d_cg = mkCandidateGenerator(m.d_ty, m.d_te); + } + void resetInstantiationRound(){ + d_cg->resetInstantiationRound(); + }; + void reset( TNode eqc ){ + d_cg->reset(eqc); + }; //* the argument is not used + TNode getNextCandidate(){ + return d_cg->getNextCandidate(); + }; +}; /* MetaCandidateGeneratorClasses */ + +/** Match just a variable */ +class AllVarMatcher: public PatMatcher{ +private: + /* generator */ + typedef VarMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalTypeTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< MetaCandidateGeneratorClasses, AuxMatcher2 > AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(TNode pat, QuantifiersEngine* qe){ + Assert( pat.getKind()==INST_CONSTANT ); + TypeNode ty = pat.getType(); + Debug("inst-match-gen") << "create AllVarMatcher for type: " << ty << std::endl; + /** In reverse order of matcher sequence */ + /** Distribute it to all the pattern */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good type */ + AuxMatcher2 am2(am3,LegalTypeTest(ty)); + /** Generate one term by eq classes */ + MetaCandidateGeneratorClasses mcdt(ty,qe->getTheoryEngine()); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(mcdt,am2); + return am1; + } +public: + AllVarMatcher( TNode pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)){} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.reset(Node::null(), m, qe); //cdtUfEq doesn't use it's argument for reset + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +/** Match all the pattern with the same term */ +class SplitMatcher: public Matcher{ +private: + const size_t size; + ApplyMatcher d_m; /** Use ApplyMatcher by creating a fake application */ +public: + SplitMatcher(std::vector< Node > pats, QuantifiersEngine* qe): + size(pats.size()), + d_m(NodeManager::currentNM()->mkNode(kind::INST_PATTERN,pats), qe) {} + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_m.resetInstantiationRound(qe); + }; + bool reset( TNode ex, InstMatch& m, QuantifiersEngine* qe ){ + NodeBuilder<> n(kind::INST_PATTERN); + for(size_t i = 0; i < size; ++i) n << ex; + Node nn = n; + return d_m.reset(nn,m,qe); + }; + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return getNextMatch(m, qe); + } +}; + + +/** Match uf term in a fixed equivalence class */ +class UfCstEqMatcher: public PatMatcher{ +private: + /* equivalence class to match */ + Node d_cst; + /* generator */ + OpMatcher d_cgm; +public: + UfCstEqMatcher( Node pat, Node cst, QuantifiersEngine* qe ): + d_cst(cst), + d_cgm(OpMatcher(pat,qe)) {}; + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.reset(d_cst, m, qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +/** Match equalities */ +class UfEqMatcher: public PatMatcher{ +private: + /* generator */ + typedef SplitMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalTypeTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClasses, AuxMatcher2 > AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(std::vector & pat, QuantifiersEngine* qe){ + Assert( pat.size() > 0); + TypeNode ty = pat[0].getType(); + for(size_t i = 1; i < pat.size(); ++i){ + Assert(pat[i].getType() == ty); + } + /** In reverse order of matcher sequence */ + /** Distribute it to all the pattern */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good type */ + AuxMatcher2 am2(am3,LegalTypeTest(ty)); + /** Generate one term by eq classes */ + uf::TheoryUF* uf = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )); + eq::EqualityEngine* ee = + static_cast(uf->getEqualityEngine()); + CandidateGeneratorTheoryEeClasses cdtUfEq(ee); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtUfEq,am2); + return am1; + } +public: + UfEqMatcher( std::vector & pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)){} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.reset(Node::null(), m, qe); //cdtUfEq doesn't use it's argument for reset + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + + +/** Match dis-equalities */ +class UfDeqMatcher: public PatMatcher{ +private: + /* generator */ + typedef ApplyMatcher AuxMatcher3; + + class EqTest/* : public unary_function*/ { + TypeNode d_type; + public: + inline EqTest(TypeNode type): d_type(type){}; + inline bool operator() (Node n) { + return + CandidateGenerator::isLegalCandidate(n) && + n.getKind() == kind::EQUAL && + n[0].getType()==d_type; + }; + }; + typedef TestMatcher< AuxMatcher3, EqTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2 > AuxMatcher1; + AuxMatcher1 d_cgm; + Node false_term; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + Assert( pat.getKind() == kind::NOT); + TNode eq = pat[0]; + Assert( eq.getKind() == kind::EQUAL); + TypeNode ty = eq[0].getType(); + /** In reverse order of matcher sequence */ + /** Distribute it to all the pattern */ + AuxMatcher3 am3(eq,qe); + /** Keep only the one that have the good type */ + AuxMatcher2 am2(am3,EqTest(ty)); + /** Will generate all the terms of the eq class of false */ + uf::TheoryUF* uf = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )); + eq::EqualityEngine* ee = + static_cast(uf->getEqualityEngine()); + CandidateGeneratorTheoryEeClass cdtUfEq(ee); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtUfEq,am2); + return am1; + } +public: + UfDeqMatcher( Node pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)), + false_term((static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )))->getEqualityEngine()-> + getRepresentative(NodeManager::currentNM()->mkConst(false) )){}; + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.reset(false_term, m, qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +Matcher* mkMatcher( Node pat, QuantifiersEngine* qe ){ + Debug("inst-match-gen") << "mkMatcher: Pattern term is " << pat << std::endl; + + // if( pat.getKind() == kind::APPLY_UF){ + // return new OpMatcher(pat, qe); + // } else if( pat.getKind() == kind::APPLY_CONSTRUCTOR ){ + // return new DatatypesMatcher(pat, qe); + // } else if( pat.getKind() == kind::SELECT || pat.getKind() == kind::STORE ){ + // return new ArrayMatcher(pat, qe); + if( pat.getKind() == kind::APPLY_UF || + pat.getKind() == kind::APPLY_CONSTRUCTOR || + pat.getKind() == kind::SELECT || pat.getKind() == kind::STORE ){ + return new GenericMatcher(pat, qe); + } else { /* Arithmetic? */ + /** TODO: something simpler to see if the pattern is a good + arithmetic pattern */ + std::map< Node, Node > d_arith_coeffs; + if( !Trigger::getPatternArithmetic( pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) ){ + std::cout << "(?) Unknown matching pattern is " << pat << std::endl; + Unimplemented("pattern not implemented"); + return new DumbMatcher(); + }else{ + Debug("matching-arith") << "Generated arithmetic pattern for " << pat << ": " << std::endl; + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; + } + ArithMatcher am3 (pat, qe); + TestMatcher + am2(am3,LegalTypeTest(pat.getType())); + /* generator */ + uf::TheoryUF* uf = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )); + eq::EqualityEngine* ee = + static_cast (uf->getEqualityEngine()); + CandidateGeneratorTheoryEeClass cdtUfEq(ee); + return new CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, + TestMatcher > (cdtUfEq,am2); + } + } +}; + +PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe ){ + Debug("inst-match-gen") << "Pattern term is " << pat << std::endl; + Assert( pat.hasAttribute(InstConstantAttribute()) ); + + if( pat.getKind()==kind::NOT && pat[0].getKind() == kind::EQUAL){ + /* Difference */ + return new UfDeqMatcher(pat, qe); + } else if (pat.getKind() == kind::EQUAL){ + if( !pat[0].hasAttribute(InstConstantAttribute() )){ + Assert(pat[1].hasAttribute(InstConstantAttribute())); + return new UfCstEqMatcher(pat[1], pat[0], qe); + }else if( !pat[1].hasAttribute(InstConstantAttribute() )){ + Assert(pat[0].hasAttribute(InstConstantAttribute())); + return new UfCstEqMatcher(pat[0], pat[1], qe); + }else{ + std::vector< Node > pats(pat.begin(),pat.end()); + return new UfEqMatcher(pats,qe); + } + } else if( Trigger::isAtomicTrigger( pat ) ){ + return new AllOpMatcher(pat, qe); + // return new GenericPatMatcher(pat, qe); + } else if( pat.getKind()==INST_CONSTANT ){ + // just a variable + return new AllVarMatcher(pat, qe); + } else { /* Arithmetic? */ + /** TODO: something simpler to see if the pattern is a good + arithmetic pattern */ + std::map< Node, Node > d_arith_coeffs; + if( !Trigger::getPatternArithmetic( pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) ){ + Debug("inst-match-gen") << "(?) Unknown matching pattern is " << pat << std::endl; + std::cout << "(?) Unknown matching pattern is " << pat << std::endl; + return new DumbPatMatcher(); + }else{ + Debug("matching-arith") << "Generated arithmetic pattern for " << pat << ": " << std::endl; + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; + } + ArithMatcher am3 (pat, qe); + TestMatcher + am2(am3,LegalTest()); + /* generator */ + TermDb* tdb = qe->getTermDatabase(); + CandidateGeneratorTheoryUfType cdtUfEq(pat.getType(),tdb); + typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryUfType, + TestMatcher > AuxMatcher1; + return new PatOfMatcher(AuxMatcher1(cdtUfEq,am2)); + } + } +}; + +ArithMatcher::ArithMatcher(Node pat, QuantifiersEngine* qe): d_pattern(pat){ + + if(Trigger::getPatternArithmetic(pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) ) + { + Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_pattern << std::endl; + Assert(false); + }else{ + Debug("matching-arith") << "Generated arithmetic pattern for " << d_pattern << ": " << std::endl; + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; + } + } + +}; + +bool ArithMatcher::reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ + Debug("matching-arith") << "Matching " << t << " " << d_pattern << std::endl; + d_binded.clear(); + if( !d_arith_coeffs.empty() ){ + NodeBuilder<> tb(kind::PLUS); + Node ic = Node::null(); + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << it->first << " -> " << it->second << std::endl; + if( !it->first.isNull() ){ + if( m.find( it->first )==m.end() ){ + //see if we can choose this to set + if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){ + ic = it->first; + } + }else{ + Debug("matching-arith") << "already set " << m.get( it->first ) << std::endl; + Node tm = m.get( it->first ); + if( !it->second.isNull() ){ + tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm ); + } + tb << tm; + } + }else{ + tb << it->second; + } + } + if( !ic.isNull() ){ + Node tm; + if( tb.getNumChildren()==0 ){ + tm = t; + }else{ + tm = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb; + tm = NodeManager::currentNM()->mkNode( MINUS, t, tm ); + } + if( !d_arith_coeffs[ ic ].isNull() ){ + Assert( !ic.getType().isInteger() ); + Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst() ); + tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm ); + } + m.set( ic, Rewriter::rewrite( tm )); + d_binded.push_back(ic); + //set the rest to zeros + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + if( !it->first.isNull() ){ + if( m.find( it->first )==m.end() ){ + m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) )); + d_binded.push_back(ic); + } + } + } + Debug("matching-arith") << "Setting " << ic << " to " << tm << std::endl; + return true; + }else{ + m.erase(d_binded.begin(), d_binded.end()); + return false; + } + }else{ + m.erase(d_binded.begin(), d_binded.end()); + return false; + } +}; + +bool ArithMatcher::getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + m.erase(d_binded.begin(), d_binded.end()); + return false; +}; + + +class MultiPatsMatcher: public PatsMatcher{ +private: + bool d_reset_done; + std::vector< PatMatcher* > d_patterns; + InstMatch d_im; + bool reset( QuantifiersEngine* qe ){ + d_im.clear(); + d_reset_done = true; + + return getNextMatch(qe,true); + }; + + bool getNextMatch(QuantifiersEngine* qe, bool reset){ + const size_t max = d_patterns.size() - 1; + size_t index = reset ? 0 : max; + while(true){ + Debug("matching") << "MultiPatsMatcher::index " << index << "/" + << max << (reset ? " reset_phase" : "") << std::endl; + if(reset ? + d_patterns[index]->reset( d_im, qe ) : + d_patterns[index]->getNextMatch( d_im, qe )){ + if(index==max) return true; + ++index; + reset=true; + }else{ + if(index==0) return false; + --index; + reset=false; + }; + } + } + +public: + MultiPatsMatcher(std::vector< Node > & pats, QuantifiersEngine* qe): + d_reset_done(false){ + Assert(pats.size() > 0); + for( size_t i=0; i< pats.size(); i++ ){ + d_patterns.push_back(mkPattern(pats[i],qe)); + }; + }; + void resetInstantiationRound( QuantifiersEngine* qe ){ + for( size_t i=0; i< d_patterns.size(); i++ ){ + d_patterns[i]->resetInstantiationRound( qe ); + }; + d_reset_done = false; + d_im.clear(); + }; + bool getNextMatch( QuantifiersEngine* qe ){ + Assert(d_patterns.size()>0); + if(d_reset_done) return getNextMatch(qe,false); + else return reset(qe); + } + const InstMatch& getInstMatch(){return d_im;}; + + int addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe); +}; + +enum EffiStep{ + ES_STOP, + ES_GET_MONO_CANDIDATE, + ES_GET_MULTI_CANDIDATE, + ES_RESET1, + ES_RESET2, + ES_NEXT1, + ES_NEXT2, + ES_RESET_OTHER, + ES_NEXT_OTHER, +}; +static inline std::ostream& operator<<(std::ostream& out, const EffiStep& step) { + switch(step){ + case ES_STOP: out << "STOP"; break; + case ES_GET_MONO_CANDIDATE: out << "GET_MONO_CANDIDATE"; break; + case ES_GET_MULTI_CANDIDATE: out << "GET_MULTI_CANDIDATE"; break; + case ES_RESET1: out << "RESET1"; break; + case ES_RESET2: out << "RESET2"; break; + case ES_NEXT1: out << "NEXT1"; break; + case ES_NEXT2: out << "NEXT2"; break; + case ES_RESET_OTHER: out << "RESET_OTHER"; break; + case ES_NEXT_OTHER: out << "NEXT_OTHER"; break; + } + return out; +} + + +int MultiPatsMatcher::addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe){ + //now, try to add instantiation for each match produced + int addedLemmas = 0; + resetInstantiationRound( qe ); + d_im.add( baseMatch ); + while( getNextMatch( qe ) ){ + InstMatch im_copy = getInstMatch(); + //m.makeInternal( d_quantEngine->getEqualityQuery() ); + if( qe->addInstantiation( quant, im_copy ) ){ + addedLemmas++; + } + } + //return number of lemmas added + return addedLemmas; +} + +PatsMatcher* mkPatterns( std::vector< Node > pat, QuantifiersEngine* qe ){ + return new MultiPatsMatcher( pat, qe); +} + +class MultiEfficientPatsMatcher: public PatsMatcher{ +private: + bool d_phase_mono; + bool d_phase_new_term; + std::vector< PatMatcher* > d_patterns; + std::vector< Matcher* > d_direct_patterns; + InstMatch d_im; + uf::EfficientHandler d_eh; + uf::EfficientHandler::MultiCandidate d_mc; + InstMatchTrie2Pairs d_cache; + std::vector d_pats; + // bool indexDone( size_t i){ + // return i == d_c.first.second || + // ( i == d_c.second.second && d_c.second.first.empty()); + // } + + + + static const EffiStep ES_START = ES_GET_MONO_CANDIDATE; + EffiStep d_step; + + //return true if it becomes bigger than d_patterns.size() - 1 + bool incrIndex(size_t & index){ + if(index == d_patterns.size() - 1) return true; + ++index; + if(index == d_mc.first.second + || (!d_phase_mono && index == d_mc.second.second)) + return incrIndex(index); + else return false; + } + + //return true if it becomes smaller than 0 + bool decrIndex(size_t & index){ + if(index == 0) return true; + --index; + if(index == d_mc.first.second + || (!d_phase_mono && index == d_mc.second.second)) + return decrIndex(index); + else return false; + } + + bool resetOther( QuantifiersEngine* qe ){ + return getNextMatchOther(qe,true); + }; + + + bool getNextMatchOther(QuantifiersEngine* qe, bool reset){ + size_t index = reset ? 0 : d_patterns.size(); + if(!reset && decrIndex(index)) return false; + if( reset && + (index == d_mc.first.second + || (!d_phase_mono && index == d_mc.second.second)) + && incrIndex(index)) return true; + while(true){ + Debug("matching") << "MultiEfficientPatsMatcher::index " << index << "/" + << d_patterns.size() - 1 << std::endl; + if(reset ? + d_patterns[index]->reset( d_im, qe ) : + d_patterns[index]->getNextMatch( d_im, qe )){ + if(incrIndex(index)) return true; + reset=true; + }else{ + if(decrIndex(index)) return false; + reset=false; + }; + } + } + + inline EffiStep TestMonoCache(QuantifiersEngine* qe){ + if( //!d_phase_new_term || + d_pats.size() == 1) return ES_RESET_OTHER; + if(d_cache.addInstMatch(d_mc.first.second,d_im)){ + Debug("inst-match::cache") << "Cache miss" << d_im << std::endl; + ++qe->d_statistics.d_mono_candidates_cache_miss; + return ES_RESET_OTHER; + } else { + Debug("inst-match::cache") << "Cache hit" << d_im << std::endl; + ++qe->d_statistics.d_mono_candidates_cache_hit; + return ES_NEXT1; + } + // ++qe->d_statistics.d_mono_candidates_cache_miss; + // return ES_RESET_OTHER; + } + + inline EffiStep TestMultiCache(QuantifiersEngine* qe){ + if(d_cache.addInstMatch(d_mc.first.second,d_mc.second.second,d_im)){ + ++qe->d_statistics.d_multi_candidates_cache_miss; + return ES_RESET_OTHER; + } else { + ++qe->d_statistics.d_multi_candidates_cache_hit; + return ES_NEXT2; + } + } + + +public: + + bool getNextMatch( QuantifiersEngine* qe ){ + Assert( d_step == ES_START || d_step == ES_NEXT_OTHER || d_step == ES_STOP ); + while(true){ + Debug("matching") << "d_step=" << d_step << " " + << "d_im=" << d_im << std::endl; + switch(d_step){ + case ES_GET_MONO_CANDIDATE: + Assert(d_im.empty()); + if(d_phase_new_term ? d_eh.getNextMonoCandidate(d_mc.first) : d_eh.getNextMonoCandidateNewTerm(d_mc.first)){ + if(d_phase_new_term) ++qe->d_statistics.d_num_mono_candidates_new_term; + else ++qe->d_statistics.d_num_mono_candidates; + d_phase_mono = true; + d_step = ES_RESET1; + } else if (!d_phase_new_term){ + d_phase_new_term = true; + d_step = ES_GET_MONO_CANDIDATE; + } else { + d_phase_new_term = false; + d_step = ES_GET_MULTI_CANDIDATE; + } + break; + case ES_GET_MULTI_CANDIDATE: + Assert(d_im.empty()); + if(d_eh.getNextMultiCandidate(d_mc)){ + ++qe->d_statistics.d_num_multi_candidates; + d_phase_mono = false; + d_step = ES_RESET1; + } else d_step = ES_STOP; + break; + case ES_RESET1: + if(d_direct_patterns[d_mc.first.second]->reset(d_mc.first.first,d_im,qe)) + d_step = d_phase_mono ? TestMonoCache(qe) : ES_RESET2; + else d_step = d_phase_mono ? ES_GET_MONO_CANDIDATE : ES_GET_MULTI_CANDIDATE; + break; + case ES_RESET2: + Assert(!d_phase_mono); + if(d_direct_patterns[d_mc.second.second]->reset(d_mc.second.first,d_im,qe)) + d_step = TestMultiCache(qe); + else d_step = ES_NEXT1; + break; + case ES_NEXT1: + if(d_direct_patterns[d_mc.first.second]->getNextMatch(d_im,qe)) + d_step = d_phase_mono ? TestMonoCache(qe) : ES_RESET2; + else d_step = d_phase_mono ? ES_GET_MONO_CANDIDATE : ES_GET_MULTI_CANDIDATE; + break; + case ES_NEXT2: + if(d_direct_patterns[d_mc.second.second]->getNextMatch(d_im,qe)) + d_step = TestMultiCache(qe); + else d_step = ES_NEXT1; + break; + case ES_RESET_OTHER: + if(resetOther(qe)){ + d_step = ES_NEXT_OTHER; + return true; + } else d_step = d_phase_mono ? ES_NEXT1 : ES_NEXT2; + break; + case ES_NEXT_OTHER: + { + if(!getNextMatchOther(qe,false)){ + d_step = d_phase_mono ? ES_NEXT1 : ES_NEXT2; + }else{ + d_step = ES_NEXT_OTHER; + return true; + } + } + break; + case ES_STOP: + Assert(d_im.empty()); + return false; + } + } + } + + MultiEfficientPatsMatcher(std::vector< Node > & pats, QuantifiersEngine* qe): + d_eh(qe->getTheoryEngine()->getSatContext()), + d_cache(qe->getTheoryEngine()->getSatContext(),qe,pats.size()), + d_pats(pats), d_step(ES_START) { + Assert(pats.size() > 0); + for( size_t i=0; i< pats.size(); i++ ){ + d_patterns.push_back(mkPattern(pats[i],qe)); + if(pats[i].getKind()==kind::INST_CONSTANT){ + d_direct_patterns.push_back(new VarMatcher(pats[i],qe)); + } else if( pats[i].getKind() == kind::NOT && pats[i][0].getKind() == kind::EQUAL){ + d_direct_patterns.push_back(new ApplyMatcher(pats[i][0],qe)); + } else { + d_direct_patterns.push_back(new ApplyMatcher(pats[i],qe)); + } + }; + Theory* th_uf = qe->getTheoryEngine()->getTheory( theory::THEORY_UF ); + uf::InstantiatorTheoryUf* ith = (uf::InstantiatorTheoryUf*)th_uf->getInstantiator(); + ith->registerEfficientHandler(d_eh, pats); + }; + void resetInstantiationRound( QuantifiersEngine* qe ){ + Assert(d_step == ES_START || d_step == ES_STOP); + for( size_t i=0; i< d_patterns.size(); i++ ){ + d_patterns[i]->resetInstantiationRound( qe ); + d_direct_patterns[i]->resetInstantiationRound( qe ); + }; + d_step = ES_START; + d_phase_new_term = false; + Assert(d_im.empty()); + }; + + const InstMatch& getInstMatch(){return d_im;}; + + int addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe); +}; + +int MultiEfficientPatsMatcher::addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe){ + //now, try to add instantiation for each match produced + int addedLemmas = 0; + Assert(baseMatch.empty()); + resetInstantiationRound( qe ); + while( getNextMatch( qe ) ){ + InstMatch im_copy = getInstMatch(); + //m.makeInternal( d_quantEngine->getEqualityQuery() ); + if( qe->addInstantiation( quant, im_copy ) ){ + addedLemmas++; + } + } + //return number of lemmas added + return addedLemmas; +}; + +PatsMatcher* mkPatternsEfficient( std::vector< Node > pat, QuantifiersEngine* qe ){ + return new MultiEfficientPatsMatcher( pat, qe); +} + +} /* CVC4::theory::rrinst */ +} /* CVC4::theory */ +} /* CVC4 */ diff --git a/src/theory/rr_inst_match.h b/src/theory/rr_inst_match.h new file mode 100644 index 000000000..d89b221bb --- /dev/null +++ b/src/theory/rr_inst_match.h @@ -0,0 +1,263 @@ +/********************* */ +/*! \file inst_match.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 inst match class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__RR_INST_MATCH_H +#define __CVC4__RR_INST_MATCH_H + +#include "theory/theory.h" +#include "util/hash.h" +#include "util/ntuple.h" + +#include +#include +#include + +#include "theory/uf/equality_engine.h" +#include "theory/uf/theory_uf.h" +#include "context/cdlist.h" + +#include "theory/inst_match.h" +#include "expr/node_manager.h" +#include "expr/node_builder.h" + +//#define USE_EFFICIENT_E_MATCHING + +namespace CVC4 { +namespace theory { + +namespace rrinst{ + +class CandidateGenerator +{ +public: + CandidateGenerator(){} + virtual ~CandidateGenerator(){}; + + /** Get candidates functions. These set up a context to get all match candidates. + cg->reset( eqc ); + do{ + Node cand = cg->getNextCandidate(); + //....... + }while( !cand.isNull() ); + + eqc is the equivalence class you are searching in + */ + virtual void reset( TNode eqc ) = 0; + virtual TNode getNextCandidate() = 0; + /** call this at the beginning of each instantiation round */ + virtual void resetInstantiationRound() = 0; +public: + /** legal candidate */ + static inline bool isLegalCandidate( TNode n ){ + return !n.getAttribute(NoMatchAttribute()) && + ( !Options::current()->cbqi || !n.hasAttribute(InstConstantAttribute())) && + ( !Options::current()->efficientEMatching || n.hasAttribute(AvailableInTermDb()) ); +} + +}; + + +inline std::ostream& operator<<(std::ostream& out, const InstMatch& m) { + m.toStream(out); + return out; +} + +template class InstMatchTrie2; +template class InstMatchTrie2Pairs; + +template +class InstMatchTrie2Gen +{ + friend class InstMatchTrie2; + friend class InstMatchTrie2Pairs; + +private: + + class Tree { + public: + typedef std::hash_map< Node, Tree *, NodeHashFunction > MLevel; + MLevel e; + const size_t level; //context level of creation + Tree() CVC4_UNDEFINED; + const Tree & operator =(const Tree & t){ + Assert(t.e.empty()); Assert(e.empty()); + Assert(t.level == level); + return t; + } + Tree(size_t l): level(l) {}; + ~Tree(){ + for(typename MLevel::iterator i = e.begin(); i!=e.end(); ++i) + delete(i->second); + }; + }; + + + typedef std::pair Mod; + + class CleanUp{ + public: + inline void operator()(Mod * m){ + typename Tree::MLevel::iterator i = m->first->e.find(m->second); + Assert (i != m->first->e.end()); //should not have been already removed + m->first->e.erase(i); + }; + }; + + EqualityQuery* d_eQ; + CandidateGenerator * d_cG; + + context::Context* d_context; + context::CDList > d_mods; + + + typedef std::map::const_iterator mapIter; + + /** add the substitution given by the iterator*/ + void addSubTree( Tree * root, mapIter current, mapIter end, size_t currLevel); + /** test if it exists match, modulo uf-equations if modEq is true if + * return false the deepest point of divergence is put in [e] and + * [diverge]. + */ + bool existsInstMatch( Tree * root, + mapIter & current, mapIter & end, + Tree * & e, mapIter & diverge) const; + + /** add match m in the trie root + return true if it was never seen */ + bool addInstMatch( InstMatch& m, Tree * root); + +public: + InstMatchTrie2Gen(context::Context* c, QuantifiersEngine* q); + InstMatchTrie2Gen(const InstMatchTrie2Gen &) CVC4_UNDEFINED; + const InstMatchTrie2Gen & operator =(const InstMatchTrie2Gen & e) CVC4_UNDEFINED; +}; + +template +class InstMatchTrie2 +{ + typename InstMatchTrie2Gen::Tree d_data; + InstMatchTrie2Gen d_backtrack; +public: + InstMatchTrie2(context::Context* c, QuantifiersEngine* q): d_data(0), + d_backtrack(c,q) {}; + InstMatchTrie2(const InstMatchTrie2 &) CVC4_UNDEFINED; + const InstMatchTrie2 & operator =(const InstMatchTrie2 & e) CVC4_UNDEFINED; + /** add match m in the trie, + return true if it was never seen */ + inline bool addInstMatch( InstMatch& m){ + return d_backtrack.addInstMatch(m,&d_data); + }; + +};/* class InstMatchTrie2 */ + +class Matcher +{ +public: + /** reset instantiation round (call this whenever equivalence classes have changed) */ + virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; + /** reset the term to match, return false if there is no such term */ + virtual bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ) = 0; + /** get the next match. If it return false once you shouldn't call + getNextMatch again before doing a reset */ + virtual bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) = 0; + /** If reset, or getNextMatch return false they remove from the + InstMatch the binding that they have previously created */ + + /** virtual Matcher in order to have definned behavior */ + virtual ~Matcher(){}; +}; + + +class ApplyMatcher: public Matcher{ +private: + /** What to check first: constant and variable */ + std::vector< triple< TNode,size_t,EqualityQuery* > > d_constants; + std::vector< triple< TNode,size_t,EqualityQuery* > > d_variables; + /** children generators, only the sub-pattern which are + neither a variable neither a constant appears */ + std::vector< triple< Matcher*, size_t, EqualityQuery* > > d_childrens; + /** the variable that have been set by this matcher (during its own reset) */ + std::vector< TNode > d_binded; /* TNode because the variable are already in d_pattern */ + /** the representant of the argument of the term given by the last reset */ + std::vector< Node > d_reps; +public: + /** The pattern we are producing matches for */ + Node d_pattern; +public: + /** constructors */ + ApplyMatcher( Node pat, QuantifiersEngine* qe); + /** destructor */ + ~ApplyMatcher(){/*TODO delete dandling pointers? */} + /** reset instantiation round (call this whenever equivalence classes have changed) */ + void resetInstantiationRound( QuantifiersEngine* qe ); + /** reset the term to match */ + bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ); + /** get the next match. */ + bool getNextMatch(InstMatch& m, QuantifiersEngine* qe); +private: + bool getNextMatch(InstMatch& m, QuantifiersEngine* qe, bool reset); +}; + + +/* Match literal so you don't choose the equivalence class( */ +class PatMatcher +{ +public: + /** reset instantiation round (call this whenever equivalence classes have changed) */ + virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; + /** reset the matcher, return false if there is no such term */ + virtual bool reset( InstMatch& m, QuantifiersEngine* qe ) = 0; + /** get the next match. If it return false once you shouldn't call + getNextMatch again before doing a reset */ + virtual bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) = 0; + /** If reset, or getNextMatch return false they remove from the + InstMatch the binding that they have previously created */ +}; + +Matcher* mkMatcher( Node pat, QuantifiersEngine* qe ); +PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe ); + +/* Match literal so you don't choose the equivalence class( */ +class PatsMatcher +{ +public: + /** reset instantiation round (call this whenever equivalence classes have changed) */ + virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; + /** reset the matcher, return false if there is no such term */ + virtual bool getNextMatch( QuantifiersEngine* qe ) = 0; + virtual const InstMatch& getInstMatch() = 0; + /** Add directly the instantiation to quantifiers engine */ + virtual int addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe) = 0; +}; + +PatsMatcher* mkPatterns( std::vector< Node > pat, QuantifiersEngine* qe ); +PatsMatcher* mkPatternsEfficient( std::vector< Node > pat, QuantifiersEngine* qe ); + +/** return true if whatever Node is subsituted for the variables the + given Node can't match the pattern */ +bool nonunifiable( TNode t, TNode pat, const std::vector & vars); + +class InstMatchGenerator; + +}/* CVC4::theory rrinst */ + +}/* CVC4::theory namespace */ + +}/* CVC4 namespace */ + +#endif /* __CVC4__RR_INST_MATCH_H */ diff --git a/src/theory/rr_inst_match_impl.h b/src/theory/rr_inst_match_impl.h new file mode 100644 index 000000000..04a15d41f --- /dev/null +++ b/src/theory/rr_inst_match_impl.h @@ -0,0 +1,128 @@ +/********************* */ +/*! \file inst_match_impl.h + ** \verbatim + ** Original author: bobot + ** Major contributors: none + ** Minor contributors (to current version): taking, mdeters + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009-2012 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 inst match class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__RR_INST_MATCH_IMPL_H +#define __CVC4__RR_INST_MATCH_IMPL_H + +#include "theory/rr_inst_match.h" +#include "theory/theory_engine.h" +#include "theory/quantifiers_engine.h" +#include "theory/uf/theory_uf_candidate_generator.h" +#include "theory/uf/equality_engine.h" + +namespace CVC4 { +namespace theory { +namespace rrinst { + +template +InstMatchTrie2Gen::InstMatchTrie2Gen(context::Context* c, QuantifiersEngine* qe): + d_context(c), d_mods(c) { + d_eQ = qe->getEqualityQuery(); + d_cG = qe->getRRCanGenClass(); +}; + +/** add match m for quantifier f starting at index, take into account equalities q, return true if successful */ +template +void InstMatchTrie2Gen::addSubTree( Tree * root, mapIter current, mapIter end, size_t currLevel ) { + if( current == end ) return; + + Assert(root->e.find(current->second) == root->e.end()); + Tree * root2 = new Tree(currLevel); + root->e.insert(std::make_pair(current->second, root2)); + addSubTree(root2, ++current, end, currLevel ); +} + +/** exists match */ +template +bool InstMatchTrie2Gen::existsInstMatch(InstMatchTrie2Gen::Tree * root, + mapIter & current, mapIter & end, + Tree * & e, mapIter & diverge) const{ + if( current == end ) { + Debug("Trie2") << "Trie2 Bottom " << std::endl; + --current; + return true; + }; //Already their + + if (current->first > diverge->first){ + // this point is the deepest point currently seen map are ordered + e = root; + diverge = current; + }; + + TNode n = current->second; + typename InstMatchTrie2Gen::Tree::MLevel::iterator it = + root->e.find( n ); + if( it!=root->e.end() && + existsInstMatch( (*it).second, ++current, end, e, diverge) ){ + Debug("Trie2") << "Trie2 Directly here " << n << std::endl; + --current; + return true; + } + Assert( it==root->e.end() || e != root ); + + // Even if n is in the trie others of the equivalence class + // can also be in it since the equality can have appeared + // after they have been added + if( modEq && d_eQ->hasTerm( n ) ){ + //check modulo equality if any other instantiation match exists + d_cG->reset( d_eQ->getRepresentative( n ) ); + for(TNode en = d_cG->getNextCandidate() ; !en.isNull() ; + en = d_cG->getNextCandidate() ){ + if( en == n ) continue; // already tested + typename InstMatchTrie2Gen::Tree::MLevel::iterator itc = + root->e.find( en ); + if( itc!=root->e.end() && + existsInstMatch( (*itc).second, ++current, end, e, diverge) ){ + Debug("Trie2") << "Trie2 Indirectly here by equality " << n << " = " << en << std::endl; + --current; + return true; + } + Assert( itc==root->e.end() || e != root ); + } + } + --current; + return false; +} + +template +bool InstMatchTrie2Gen:: +addInstMatch( InstMatch& m, InstMatchTrie2Gen::Tree* e ) { + d_cG->resetInstantiationRound(); + mapIter begin = m.begin(); + mapIter end = m.end(); + mapIter diverge = begin; + if( !existsInstMatch(e, begin, end, e, diverge ) ){ + Assert(!diverge->second.isNull()); + size_t currLevel = d_context->getLevel(); + addSubTree( e, diverge, end, currLevel ); + if(e->level != currLevel) + //If same level that e, will be removed at the same time than e + d_mods.push_back(std::make_pair(e,diverge->second)); + return true; + }else{ + return false; + } +} + +}/* CVC4::theory::rrinst namespace */ + +}/* CVC4::theory namespace */ + +}/* CVC4 namespace */ + +#endif /* __CVC4__RR_INST_MATCH_IMPL_H */ diff --git a/src/theory/rr_trigger.cpp b/src/theory/rr_trigger.cpp new file mode 100644 index 000000000..579608b59 --- /dev/null +++ b/src/theory/rr_trigger.cpp @@ -0,0 +1,523 @@ +/********************* */ +/*! \file trigger.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 trigger class + **/ + +#include "theory/rr_trigger.h" +#include "theory/theory_engine.h" +#include "theory/quantifiers_engine.h" +#include "theory/uf/theory_uf_instantiator.h" +#include "theory/uf/theory_uf_candidate_generator.h" +#include "theory/uf/equality_engine.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::rrinst; + +//#define NESTED_PATTERN_SELECTION + +Trigger* Trigger::TrTrie::getTrigger2( std::vector< Node >& nodes ){ + if( nodes.empty() ){ + return d_tr; + }else{ + Node n = nodes.back(); + nodes.pop_back(); + if( d_children.find( n )!=d_children.end() ){ + return d_children[n]->getTrigger2( nodes ); + }else{ + return NULL; + } + } +} +void Trigger::TrTrie::addTrigger2( std::vector< Node >& nodes, Trigger* t ){ + if( nodes.empty() ){ + d_tr = t; + }else{ + Node n = nodes.back(); + nodes.pop_back(); + if( d_children.find( n )==d_children.end() ){ + d_children[n] = new TrTrie; + } + d_children[n]->addTrigger2( nodes, t ); + } +} + +/** trigger static members */ +std::map< Node, std::vector< Node > > Trigger::d_var_contains; +int Trigger::trCount = 0; +Trigger::TrTrie Trigger::d_tr_trie; + +/** trigger class constructor */ +Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool smartTriggers ) : +d_quantEngine( qe ), d_f( f ){ + trCount++; + d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() ); + Debug("trigger") << "Trigger for " << f << ": " << d_nodes << std::endl; + if(matchOption == MATCH_GEN_DEFAULT) d_mg = mkPatterns( d_nodes, qe ); + else d_mg = mkPatternsEfficient( d_nodes, qe ); + if( d_nodes.size()==1 ){ + if( isSimpleTrigger( d_nodes[0] ) ){ + ++(qe->d_statistics.d_triggers); + }else{ + ++(qe->d_statistics.d_simple_triggers); + } + }else{ + Debug("multi-trigger") << "Multi-trigger " << (*this) << std::endl; + //std::cout << "Multi-trigger for " << f << " : " << std::endl; + //std::cout << " " << (*this) << std::endl; + ++(qe->d_statistics.d_multi_triggers); + } +} +void Trigger::computeVarContains( Node n ) { + if( d_var_contains.find( n )==d_var_contains.end() ){ + d_var_contains[n].clear(); + computeVarContains2( n, n ); + } +} + +void Trigger::computeVarContains2( Node n, Node parent ){ + if( n.getKind()==INST_CONSTANT ){ + if( std::find( d_var_contains[parent].begin(), d_var_contains[parent].end(), n )==d_var_contains[parent].end() ){ + d_var_contains[parent].push_back( n ); + } + }else{ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + computeVarContains2( n[i], parent ); + } + } +} + +void Trigger::resetInstantiationRound(){ + d_mg->resetInstantiationRound( d_quantEngine ); +} + + +bool Trigger::getNextMatch(){ + bool retVal = d_mg->getNextMatch( d_quantEngine ); + //m.makeInternal( d_quantEngine->getEqualityQuery() ); + return retVal; +} + +// bool Trigger::getMatch( Node t, InstMatch& m ){ +// //FIXME: this assumes d_mg is an inst match generator +// return ((InstMatchGenerator*)d_mg)->getMatch( t, m, d_quantEngine ); +// } + + +int Trigger::addInstantiations( InstMatch& baseMatch ){ + int addedLemmas = d_mg->addInstantiations( baseMatch, + d_nodes[0].getAttribute(InstConstantAttribute()), + d_quantEngine); + if( addedLemmas>0 ){ + Debug("inst-trigger") << "Added " << addedLemmas << " lemmas, trigger was "; + for( int i=0; i<(int)d_nodes.size(); i++ ){ + Debug("inst-trigger") << d_nodes[i] << " "; + } + Debug("inst-trigger") << std::endl; + } + return addedLemmas; +} + +Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool keepAll, int trOption, + bool smartTriggers ){ + std::vector< Node > trNodes; + if( !keepAll ){ + //only take nodes that contribute variables to the trigger when added + std::vector< Node > temp; + temp.insert( temp.begin(), nodes.begin(), nodes.end() ); + std::map< Node, bool > vars; + std::map< Node, std::vector< Node > > patterns; + for( int i=0; i<(int)temp.size(); i++ ){ + bool foundVar = false; + computeVarContains( temp[i] ); + for( int j=0; j<(int)d_var_contains[ temp[i] ].size(); j++ ){ + Node v = d_var_contains[ temp[i] ][j]; + if( v.getAttribute(InstConstantAttribute())==f ){ + if( vars.find( v )==vars.end() ){ + vars[ v ] = true; + foundVar = true; + } + } + } + if( foundVar ){ + trNodes.push_back( temp[i] ); + for( int j=0; j<(int)d_var_contains[ temp[i] ].size(); j++ ){ + Node v = d_var_contains[ temp[i] ][j]; + patterns[ v ].push_back( temp[i] ); + } + } + } + //now, minimalize the trigger + for( int i=0; i<(int)trNodes.size(); i++ ){ + bool keepPattern = false; + Node n = trNodes[i]; + for( int j=0; j<(int)d_var_contains[ n ].size(); j++ ){ + Node v = d_var_contains[ n ][j]; + if( patterns[v].size()==1 ){ + keepPattern = true; + break; + } + } + if( !keepPattern ){ + //remove from pattern vector + for( int j=0; j<(int)d_var_contains[ n ].size(); j++ ){ + Node v = d_var_contains[ n ][j]; + for( int k=0; k<(int)patterns[v].size(); k++ ){ + if( patterns[v][k]==n ){ + patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 ); + break; + } + } + } + //remove from trigger nodes + trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 ); + i--; + } + } + }else{ + trNodes.insert( trNodes.begin(), nodes.begin(), nodes.end() ); + } + + //check for duplicate? + if( trOption==TR_MAKE_NEW ){ + //static int trNew = 0; + //static int trOld = 0; + //Trigger* t = d_tr_trie.getTrigger( trNodes ); + //if( t ){ + // trOld++; + //}else{ + // trNew++; + //} + //if( (trNew+trOld)%100==0 ){ + // std::cout << "Trigger new old = " << trNew << " " << trOld << std::endl; + //} + }else{ + Trigger* t = d_tr_trie.getTrigger( trNodes ); + if( t ){ + if( trOption==TR_GET_OLD ){ + //just return old trigger + return t; + }else{ + return NULL; + } + } + } + Trigger* t = new Trigger( qe, f, trNodes, matchOption, smartTriggers ); + d_tr_trie.addTrigger( trNodes, t ); + return t; +} +Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption, bool smartTriggers ){ + std::vector< Node > nodes; + nodes.push_back( n ); + return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption, smartTriggers ); +} + +bool Trigger::isUsableTrigger( std::vector< Node >& nodes, Node f ){ + for( int i=0; i<(int)nodes.size(); i++ ){ + if( !isUsableTrigger( nodes[i], f ) ){ + return false; + } + } + return true; +} + +bool Trigger::isUsable( Node n, Node f ){ + if( n.getAttribute(InstConstantAttribute())==f ){ + if( !isAtomicTrigger( n ) && n.getKind()!=INST_CONSTANT ){ + std::map< Node, Node > coeffs; + return getPatternArithmetic( f, n, coeffs ); + }else{ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( !isUsable( n[i], f ) ){ + return false; + } + } + return true; + } + }else{ + return true; + } +} + +bool Trigger::isSimpleTrigger( Node n ){ + if( isAtomicTrigger( n ) ){ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){ + return false; + } + } + return true; + }else{ + return false; + } +} + +/** filter all nodes that have instances */ +void Trigger::filterInstances( std::vector< Node >& nodes ){ + std::vector< bool > active; + active.resize( nodes.size(), true ); + for( int i=0; i<(int)nodes.size(); i++ ){ + for( int j=i+1; j<(int)nodes.size(); j++ ){ + if( active[i] && active[j] ){ + int result = isInstanceOf( nodes[i], nodes[j] ); + if( result==1 ){ + active[j] = false; + }else if( result==-1 ){ + active[i] = false; + } + } + } + } + std::vector< Node > temp; + for( int i=0; i<(int)nodes.size(); i++ ){ + if( active[i] ){ + temp.push_back( nodes[i] ); + } + } + nodes.clear(); + nodes.insert( nodes.begin(), temp.begin(), temp.end() ); +} + + +bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ){ + if( patMap.find( n )==patMap.end() ){ + patMap[ n ] = false; + if( tstrt==TS_MIN_TRIGGER ){ + if( n.getKind()==FORALL ){ +#ifdef NESTED_PATTERN_SELECTION + //return collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ); + return collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ); +#else + return false; +#endif + }else{ + bool retVal = false; + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){ + retVal = true; + } + } + if( retVal ){ + return true; + }else if( isUsableTrigger( n, f ) ){ + patMap[ n ] = true; + return true; + }else{ + return false; + } + } + }else{ + bool retVal = false; + if( isUsableTrigger( n, f ) ){ + patMap[ n ] = true; + if( tstrt==TS_MAX_TRIGGER ){ + return true; + }else{ + retVal = true; + } + } + if( n.getKind()==FORALL ){ +#ifdef NESTED_PATTERN_SELECTION + //if( collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ) ){ + // retVal = true; + //} + if( collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ) ){ + retVal = true; + } +#endif + }else{ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){ + retVal = true; + } + } + } + return retVal; + } + }else{ + return patMap[ n ]; + } +} + +void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst ){ + std::map< Node, bool > patMap; + if( filterInst ){ + //immediately do not consider any term t for which another term is an instance of t + std::vector< Node > patTerms2; + collectPatTerms( qe, f, n, patTerms2, TS_ALL, false ); + std::vector< Node > temp; + temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() ); + filterInstances( temp ); + if( temp.size()!=patTerms2.size() ){ + Debug("trigger-filter-instance") << "Filtered an instance: " << std::endl; + Debug("trigger-filter-instance") << "Old: "; + for( int i=0; i<(int)patTerms2.size(); i++ ){ + Debug("trigger-filter-instance") << patTerms2[i] << " "; + } + Debug("trigger-filter-instance") << std::endl << "New: "; + for( int i=0; i<(int)temp.size(); i++ ){ + Debug("trigger-filter-instance") << temp[i] << " "; + } + Debug("trigger-filter-instance") << std::endl; + } + if( tstrt==TS_ALL ){ + patTerms.insert( patTerms.begin(), temp.begin(), temp.end() ); + return; + }else{ + //do not consider terms that have instances + for( int i=0; i<(int)patTerms2.size(); i++ ){ + if( std::find( temp.begin(), temp.end(), patTerms2[i] )==temp.end() ){ + patMap[ patTerms2[i] ] = false; + } + } + } + } + collectPatTerms2( qe, f, n, patMap, tstrt ); + for( std::map< Node, bool >::iterator it = patMap.begin(); it != patMap.end(); ++it ){ + if( it->second ){ + patTerms.push_back( it->first ); + } + } +} + +/** is n1 an instance of n2 or vice versa? */ +int Trigger::isInstanceOf( Node n1, Node n2 ){ + if( n1==n2 ){ + return 1; + }else if( n1.getKind()==n2.getKind() ){ + if( n1.getKind()==APPLY_UF ){ + if( n1.getOperator()==n2.getOperator() ){ + int result = 0; + for( int i=0; i<(int)n1.getNumChildren(); i++ ){ + if( n1[i]!=n2[i] ){ + int cResult = isInstanceOf( n1[i], n2[i] ); + if( cResult==0 ){ + return 0; + }else if( cResult!=result ){ + if( result!=0 ){ + return 0; + }else{ + result = cResult; + } + } + } + } + return result; + } + } + return 0; + }else if( n2.getKind()==INST_CONSTANT ){ + computeVarContains( n1 ); + //if( std::find( d_var_contains[ n1 ].begin(), d_var_contains[ n1 ].end(), n2 )!=d_var_contains[ n1 ].end() ){ + // return 1; + //} + if( d_var_contains[ n1 ].size()==1 && d_var_contains[ n1 ][ 0 ]==n2 ){ + return 1; + } + }else if( n1.getKind()==INST_CONSTANT ){ + computeVarContains( n2 ); + //if( std::find( d_var_contains[ n2 ].begin(), d_var_contains[ n2 ].end(), n1 )!=d_var_contains[ n2 ].end() ){ + // return -1; + //} + if( d_var_contains[ n2 ].size()==1 && d_var_contains[ n2 ][ 0 ]==n1 ){ + return 1; + } + } + return 0; +} + +bool Trigger::isVariableSubsume( Node n1, Node n2 ){ + if( n1==n2 ){ + return true; + }else{ + //std::cout << "is variable subsume ? " << n1 << " " << n2 << std::endl; + computeVarContains( n1 ); + computeVarContains( n2 ); + for( int i=0; i<(int)d_var_contains[n2].size(); i++ ){ + if( std::find( d_var_contains[n1].begin(), d_var_contains[n1].end(), d_var_contains[n2][i] )==d_var_contains[n1].end() ){ + //std::cout << "no" << std::endl; + return false; + } + } + //std::cout << "yes" << std::endl; + return true; + } +} + +void Trigger::getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ){ + for( int i=0; i<(int)pats.size(); i++ ){ + computeVarContains( pats[i] ); + varContains[ pats[i] ].clear(); + for( int j=0; j<(int)d_var_contains[pats[i]].size(); j++ ){ + if( d_var_contains[pats[i]][j].getAttribute(InstConstantAttribute())==f ){ + varContains[ pats[i] ].push_back( d_var_contains[pats[i]][j] ); + } + } + } +} + +void Trigger::getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ){ + computeVarContains( n ); + for( int j=0; j<(int)d_var_contains[n].size(); j++ ){ + if( d_var_contains[n][j].getAttribute(InstConstantAttribute())==f ){ + varContains.push_back( d_var_contains[n][j] ); + } + } +} + +bool Trigger::getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coeffs ){ + if( n.getKind()==PLUS ){ + Assert( coeffs.empty() ); + NodeBuilder<> t(kind::PLUS); + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( n[i].hasAttribute(InstConstantAttribute()) ){ + if( n[i].getKind()==INST_CONSTANT ){ + if( n[i].getAttribute(InstConstantAttribute())==f ){ + coeffs[ n[i] ] = Node::null(); + }else{ + coeffs.clear(); + return false; + } + }else if( !getPatternArithmetic( f, n[i], coeffs ) ){ + coeffs.clear(); + return false; + } + }else{ + t << n[i]; + } + } + if( t.getNumChildren()==0 ){ + coeffs[ Node::null() ] = NodeManager::currentNM()->mkConst( Rational(0) ); + }else if( t.getNumChildren()==1 ){ + coeffs[ Node::null() ] = t.getChild( 0 ); + }else{ + coeffs[ Node::null() ] = t; + } + return true; + }else if( n.getKind()==MULT ){ + if( n[0].getKind()==INST_CONSTANT && n[0].getAttribute(InstConstantAttribute())==f ){ + Assert( !n[1].hasAttribute(InstConstantAttribute()) ); + coeffs[ n[0] ] = n[1]; + return true; + }else if( n[1].getKind()==INST_CONSTANT && n[1].getAttribute(InstConstantAttribute())==f ){ + Assert( !n[0].hasAttribute(InstConstantAttribute()) ); + coeffs[ n[1] ] = n[0]; + return true; + } + } + return false; +} diff --git a/src/theory/rr_trigger.h b/src/theory/rr_trigger.h new file mode 100644 index 000000000..7ea4ee1a3 --- /dev/null +++ b/src/theory/rr_trigger.h @@ -0,0 +1,176 @@ +/********************* */ +/*! \file trigger.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 trigger class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__RR_TRIGGER_H +#define __CVC4__RR_TRIGGER_H + +#include "theory/rr_inst_match.h" + +namespace CVC4 { +namespace theory { +namespace rrinst { + +//a collect of nodes representing a trigger +class Trigger { +public: + static int trCount; +private: + /** computation of variable contains */ + static std::map< Node, std::vector< Node > > d_var_contains; + static void computeVarContains( Node n ); + static void computeVarContains2( Node n, Node parent ); +private: + /** the quantifiers engine */ + QuantifiersEngine* d_quantEngine; + /** the quantifier this trigger is for */ + Node d_f; + /** match generators */ + PatsMatcher * d_mg; +private: + /** a trie of triggers */ + class TrTrie + { + private: + Trigger* getTrigger2( std::vector< Node >& nodes ); + void addTrigger2( std::vector< Node >& nodes, Trigger* t ); + public: + TrTrie() : d_tr( NULL ){} + Trigger* d_tr; + std::map< Node, TrTrie* > d_children; + Trigger* getTrigger( std::vector< Node >& nodes ){ + std::vector< Node > temp; + temp.insert( temp.begin(), nodes.begin(), nodes.end() ); + std::sort( temp.begin(), temp.end() ); + return getTrigger2( temp ); + } + void addTrigger( std::vector< Node >& nodes, Trigger* t ){ + std::vector< Node > temp; + temp.insert( temp.begin(), nodes.begin(), nodes.end() ); + std::sort( temp.begin(), temp.end() ); + return addTrigger2( temp, t ); + } + }; + /** all triggers will be stored in this trie */ + static TrTrie d_tr_trie; +private: + /** trigger constructor */ + Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes, int matchOption = 0, bool smartTriggers = false ); +public: + ~Trigger(){} +public: + std::vector< Node > d_nodes; +public: + void debugPrint( const char* c ); + PatsMatcher* getGenerator() { return d_mg; } +public: + /** reset instantiation round (call this whenever equivalence classes have changed) */ + void resetInstantiationRound(); + /** get next match. must call reset( eqc ) once before this function. */ + bool getNextMatch(); + const InstMatch & getInstMatch(){return d_mg->getInstMatch();}; + /** return whether this is a multi-trigger */ + bool isMultiTrigger() { return d_nodes.size()>1; } +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); + /** mkTrigger method + ie : quantifier engine; + f : forall something .... + nodes : (multi-)trigger + matchOption : which policy to use for creating matches (one of InstMatchGenerator::MATCH_GEN_* ) + keepAll: don't remove unneeded patterns; + trOption : policy for dealing with triggers that already existed (see below) + */ + enum { + //options for producing matches + MATCH_GEN_DEFAULT = 0, + MATCH_GEN_EFFICIENT_E_MATCH, //generate matches via Efficient E + }; + enum{ + TR_MAKE_NEW, //make new trigger even if it already may exist + TR_GET_OLD, //return a previous trigger if it had already been created + TR_RETURN_NULL //return null if a duplicate is found + }; + static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, + int matchOption = 0, bool keepAll = true, int trOption = TR_MAKE_NEW, + bool smartTriggers = false ); + static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n, + int matchOption = 0, bool keepAll = true, int trOption = TR_MAKE_NEW, + bool smartTriggers = false ); +private: + /** is subterm of trigger usable */ + static bool isUsable( Node n, Node f ); + /** collect all APPLY_UF pattern terms for f in n */ + static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ); +public: + //different strategies for choosing trigger terms + enum { + TS_MAX_TRIGGER = 0, + TS_MIN_TRIGGER, + TS_ALL, + }; + static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst = false ); +public: + /** is usable trigger */ + static inline bool isUsableTrigger( TNode n, TNode f ){ + //return n.getAttribute(InstConstantAttribute())==f && n.getKind()==APPLY_UF; + return n.getAttribute(InstConstantAttribute())==f && isAtomicTrigger( n ) && isUsable( n, f ); + } + static inline bool isAtomicTrigger( TNode n ){ + return + n.getKind()==kind::APPLY_UF || + n.getKind()==kind::SELECT || + n.getKind()==kind::STORE; + } + static bool isUsableTrigger( std::vector< Node >& nodes, Node f ); + static bool isSimpleTrigger( Node n ); + /** filter all nodes that have instances */ + static void filterInstances( std::vector< Node >& nodes ); + /** -1: n1 is an instance of n2, 1: n1 is an instance of n2 */ + static int isInstanceOf( Node n1, Node n2 ); + /** variables subsume, return true if n1 contains all free variables in n2 */ + static bool isVariableSubsume( Node n1, Node n2 ); + /** get var contains */ + static void getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ); + static void getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ); + /** get pattern arithmetic */ + static bool getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coeffs ); + + inline void toStream(std::ostream& out) const { + out << "TRIGGER( "; + for( int i=0; i<(int)d_nodes.size(); i++ ){ + if( i>0 ){ out << ", "; } + out << d_nodes[i]; + } + out << " )"; + } +}; + +inline std::ostream& operator<<(std::ostream& out, const Trigger & tr) { + tr.toStream(out); + return out; +} + +}/* CVC4::theory::rrinst namespace */ + +}/* CVC4::theory namespace */ + +}/* CVC4 namespace */ + +#endif /* __CVC4__RR_TRIGGER_H */ diff --git a/src/theory/theory.h b/src/theory/theory.h index 7d003bf25..0cf7a8774 100644 --- a/src/theory/theory.h +++ b/src/theory/theory.h @@ -52,6 +52,10 @@ class InstStrategy; class QuantifiersEngine; class TheoryModel; +namespace rrinst{ +class CandidateGenerator; +} + /** * Information about an assertion for the theories. */ @@ -834,6 +838,12 @@ public: virtual bool areDisequal( Node a, Node b ) { return false; } virtual Node getRepresentative( Node a ) { return a; } virtual Node getInternalRepresentative( Node a ) { return getRepresentative( a ); } +public: + /** A Creator of CandidateGenerator for classes (one element in each + equivalence class) and class (every element of one equivalence + class) */ + virtual rrinst::CandidateGenerator* getRRCanGenClasses(){ return NULL; }; + virtual rrinst::CandidateGenerator* getRRCanGenClass(){ return NULL; }; };/* class Instantiator */ inline Assertion Theory::get() { diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h index f55c7c258..449f4adc3 100644 --- a/src/theory/theory_engine.h +++ b/src/theory/theory_engine.h @@ -449,6 +449,13 @@ public: return d_context; } + /** + * Get a pointer to the underlying user context. + */ + inline context::Context* getUserContext() const { + return d_userContext; + } + /** * Get a pointer to the underlying quantifiers engine. */ @@ -677,8 +684,8 @@ public: } /** Get the theory for id */ - theory::Theory* getTheory(int id) { - return d_theoryTable[id]; + theory::Theory* getTheory(theory::TheoryId theoryId) { + return d_theoryTable[theoryId]; } /** diff --git a/src/theory/trigger.cpp b/src/theory/trigger.cpp index 55ca07d77..14ba88ba1 100644 --- a/src/theory/trigger.cpp +++ b/src/theory/trigger.cpp @@ -26,6 +26,7 @@ using namespace CVC4; using namespace CVC4::kind; using namespace CVC4::context; using namespace CVC4::theory; +using namespace CVC4::theory::inst; //#define NESTED_PATTERN_SELECTION diff --git a/src/theory/trigger.h b/src/theory/trigger.h index 476ef392e..84bc7ac2e 100644 --- a/src/theory/trigger.h +++ b/src/theory/trigger.h @@ -23,6 +23,7 @@ namespace CVC4 { namespace theory { +namespace inst { //a collect of nodes representing a trigger class Trigger { @@ -163,6 +164,8 @@ inline std::ostream& operator<<(std::ostream& out, const Trigger & tr) { return out; } +}/* CVC4::theory::inst namespace */ + }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp index fe75b5f59..9376c858d 100644 --- a/src/theory/uf/equality_engine.cpp +++ b/src/theory/uf/equality_engine.cpp @@ -65,6 +65,10 @@ void EqualityEngine::init() { d_triggerDatabaseAllocatedSize = 100000; d_triggerDatabase = (char*) malloc(d_triggerDatabaseAllocatedSize); + //We can't notify during the initialization because it notifies + // QuantifiersEngine.AddTermToDatabase that try to access to the uf + // instantiator that currently doesn't exist. + ScopedBool sb(d_performNotify, false); addTerm(d_true); addTerm(d_false); diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h index 9228e29d4..0b461131e 100644 --- a/src/theory/uf/equality_engine.h +++ b/src/theory/uf/equality_engine.h @@ -794,7 +794,7 @@ class EqClassesIterator { public: - EqClassesIterator() { } + EqClassesIterator(): d_ee(NULL), d_it(0){ } EqClassesIterator(eq::EqualityEngine* ee) : d_ee(ee) { d_it = 0; if ( d_it < d_ee->d_nodesCount && @@ -840,7 +840,7 @@ class EqClassIterator { public: - EqClassIterator() { } + EqClassIterator(): d_ee(NULL){ } EqClassIterator(Node eqc, eq::EqualityEngine* ee) : d_ee(ee) { Assert( d_ee->getRepresentative(eqc) == eqc ); d_rep = eqc; diff --git a/src/theory/uf/inst_strategy.cpp b/src/theory/uf/inst_strategy.cpp index 669df055a..5696251ed 100644 --- a/src/theory/uf/inst_strategy.cpp +++ b/src/theory/uf/inst_strategy.cpp @@ -28,6 +28,7 @@ using namespace CVC4::kind; using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::uf; +using namespace CVC4::theory::inst; #define USE_SINGLE_TRIGGER_BEFORE_MULTI_TRIGGER //#define MULTI_TRIGGER_FULL_EFFORT_HALF @@ -83,7 +84,7 @@ void InstStrategyCheckCESolved::calcSolved( Node f ){ 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; + d_th->d_baseMatch[f].set(i,rep); }else{ d_solved[ f ] = false; } diff --git a/src/theory/uf/inst_strategy.h b/src/theory/uf/inst_strategy.h index 09b8087f2..a0091c4b4 100644 --- a/src/theory/uf/inst_strategy.h +++ b/src/theory/uf/inst_strategy.h @@ -20,6 +20,7 @@ #define __CVC4__INST_STRATEGY_H #include "theory/quantifiers_engine.h" +#include "theory/trigger.h" #include "context/context.h" #include "context/context_mm.h" @@ -59,7 +60,7 @@ private: /** InstantiatorTheoryUf class */ InstantiatorTheoryUf* d_th; /** explicitly provided patterns */ - std::map< Node, std::vector< Trigger* > > d_user_gen; + std::map< Node, std::vector< inst::Trigger* > > d_user_gen; /** counter for quantifiers */ std::map< Node, int > d_counter; /** process functions */ @@ -75,7 +76,7 @@ public: /** get num patterns */ int getNumUserGenerators( Node f ) { return (int)d_user_gen[f].size(); } /** get user pattern */ - Trigger* getUserGenerator( Node f, int i ) { return d_user_gen[f][ i ]; } + inst::Trigger* getUserGenerator( Node f, int i ) { return d_user_gen[f][ i ]; } /** identify */ std::string identify() const { return std::string("UserPatterns"); } };/* class InstStrategyUserPatterns */ @@ -99,7 +100,7 @@ private: /** generate additional triggers */ bool d_generate_additional; /** triggers for each quantifier */ - std::map< Node, std::map< Trigger*, bool > > d_auto_gen_trigger; + std::map< Node, std::map< inst::Trigger*, bool > > d_auto_gen_trigger; std::map< Node, int > d_counter; /** single, multi triggers for each quantifier */ std::map< Node, std::vector< Node > > d_patTerms[2]; @@ -120,7 +121,7 @@ public: ~InstStrategyAutoGenTriggers(){} public: /** get auto-generated trigger */ - Trigger* getAutoGenTrigger( Node f ); + inst::Trigger* getAutoGenTrigger( Node f ); /** identify */ std::string identify() const { return std::string("AutoGenTriggers"); } /** set regenerate frequency, if fr<0, turn off regenerate */ diff --git a/src/theory/uf/theory_uf_candidate_generator.cpp b/src/theory/uf/theory_uf_candidate_generator.cpp index 5342188f7..80151d1e1 100644 --- a/src/theory/uf/theory_uf_candidate_generator.cpp +++ b/src/theory/uf/theory_uf_candidate_generator.cpp @@ -26,6 +26,11 @@ using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::uf; +namespace CVC4{ +namespace theory{ +namespace uf{ +namespace inst{ + CandidateGeneratorTheoryUf::CandidateGeneratorTheoryUf( InstantiatorTheoryUf* ith, Node op ) : d_op( op ), d_ith( ith ), d_term_iter( -2 ){ Assert( !d_op.isNull() ); @@ -45,6 +50,7 @@ void CandidateGeneratorTheoryUf::reset( Node eqc ){ d_retNode = Node::null(); }else{ d_retNode = eqc; + } d_term_iter = -1; } @@ -169,3 +175,8 @@ Node CandidateGeneratorTheoryUfLitDeq::getNextCandidate(){ } return Node::null(); } + +} +} +} +} diff --git a/src/theory/uf/theory_uf_candidate_generator.h b/src/theory/uf/theory_uf_candidate_generator.h index 668d619db..a06f04f99 100644 --- a/src/theory/uf/theory_uf_candidate_generator.h +++ b/src/theory/uf/theory_uf_candidate_generator.h @@ -20,11 +20,155 @@ #define __CVC4__THEORY_UF_CANDIDATE_GENERATOR_H #include "theory/quantifiers_engine.h" +#include "theory/quantifiers/term_database.h" #include "theory/uf/theory_uf_instantiator.h" +#include "theory/rr_inst_match.h" + +using namespace CVC4::theory::quantifiers; namespace CVC4 { namespace theory { +namespace eq { + +namespace rrinst{ +typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator; + +//New CandidateGenerator. They have a simpler semantic than the old one + +// Just iterate amoung the equivalence classes +// node::Null() must be given to reset +class CandidateGeneratorTheoryEeClasses : public CandidateGenerator{ +private: + //the equality classes iterator + eq::EqClassesIterator d_eq; + //equalityengine pointer + EqualityEngine* d_ee; +public: + CandidateGeneratorTheoryEeClasses( EqualityEngine * ee): d_ee( ee ){} + ~CandidateGeneratorTheoryEeClasses(){} + void resetInstantiationRound(){}; + void reset( TNode eqc ){ + Assert(eqc.isNull()); + d_eq = eq::EqClassesIterator( d_ee ); + }; //* the argument is not used + TNode getNextCandidate(){ + if( !d_eq.isFinished() ) return (*(d_eq++)); + else return Node::null(); + }; +}; + +// Just iterate amoung the equivalence class of the given node +// node::Null() *can't* be given to reset +class CandidateGeneratorTheoryEeClass : public CandidateGenerator{ +private: + //instantiator pointer + EqualityEngine* d_ee; + //the equality class iterator + eq::EqClassIterator d_eqc; + /* For the case where the given term doesn't exists in uf */ + Node d_retNode; +public: + CandidateGeneratorTheoryEeClass( EqualityEngine* ee): d_ee( ee ){} + ~CandidateGeneratorTheoryEeClass(){} + void resetInstantiationRound(){}; + void reset( TNode eqc ){ + Assert(!eqc.isNull()); + if( d_ee->hasTerm( eqc ) ){ + /* eqc is in uf */ + eqc = d_ee->getRepresentative( eqc ); + d_eqc = eq::EqClassIterator( eqc, d_ee ); + d_retNode = Node::null(); + }else{ + /* If eqc if not a term known by uf, it is the only one in its + equivalence class. So we will return only it */ + d_retNode = eqc; + d_eqc = eq::EqClassIterator(); + } + }; //* the argument is not used + TNode getNextCandidate(){ + if(d_retNode.isNull()){ + if( !d_eqc.isFinished() ) return (*(d_eqc++)); + else return Node::null(); + }else{ + /* the case where eqc not in uf */ + Node ret = d_retNode; + d_retNode = Node::null(); /* d_eqc.isFinished() must be true */ + return ret; + } + }; +}; + + +} /* namespace rrinst */ +} /* namespace eq */ + namespace uf { +namespace rrinst { + +typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator; + +class CandidateGeneratorTheoryUfOp : public CandidateGenerator{ +private: + Node d_op; + //instantiator pointer + TermDb* d_tdb; + // Since new term can appears we restrict ourself to the one that + // exists at resetInstantiationRound + size_t d_term_iter_limit; + size_t d_term_iter; +public: + CandidateGeneratorTheoryUfOp(Node op, TermDb* tdb): d_op(op), d_tdb( tdb ){} + ~CandidateGeneratorTheoryUfOp(){} + void resetInstantiationRound(){ + d_term_iter_limit = d_tdb->d_op_map[d_op].size(); + }; + void reset( TNode eqc ){ + Assert(eqc.isNull()); + d_term_iter = 0; + }; //* the argument is not used + TNode getNextCandidate(){ + if( d_term_iterd_op_map[d_op][d_term_iter]; + ++d_term_iter; + return n; + } else return Node::null(); + }; +}; + +class CandidateGeneratorTheoryUfType : public CandidateGenerator{ +private: + TypeNode d_type; + //instantiator pointer + TermDb* d_tdb; + // Since new term can appears we restrict ourself to the one that + // exists at resetInstantiationRound + size_t d_term_iter_limit; + size_t d_term_iter; +public: + CandidateGeneratorTheoryUfType(TypeNode type, TermDb* tdb): d_type(type), d_tdb( tdb ){} + ~CandidateGeneratorTheoryUfType(){} + void resetInstantiationRound(){ + d_term_iter_limit = d_tdb->d_type_map[d_type].size(); + }; + void reset( TNode eqc ){ + Assert(eqc.isNull()); + d_term_iter = 0; + }; //* the argument is not used + TNode getNextCandidate(){ + if( d_term_iterd_type_map[d_type][d_term_iter]; + ++d_term_iter; + return n; + } else return Node::null(); + }; +}; + +} /* namespace rrinst */ + +namespace inst{ +typedef CVC4::theory::inst::CandidateGenerator CandidateGenerator; + +//Old CandidateGenerator class CandidateGeneratorTheoryUfDisequal; @@ -108,7 +252,8 @@ public: }; -} +}/* CVC4::theory::uf::inst namespace */ +}/* CVC4::theory::uf namespace */ }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/theory/uf/theory_uf_instantiator.cpp b/src/theory/uf/theory_uf_instantiator.cpp index e3999c163..257bed0a2 100644 --- a/src/theory/uf/theory_uf_instantiator.cpp +++ b/src/theory/uf/theory_uf_instantiator.cpp @@ -17,6 +17,7 @@ #include "theory/uf/theory_uf_instantiator.h" #include "theory/theory_engine.h" #include "theory/uf/theory_uf.h" +#include "theory/uf/theory_uf_candidate_generator.h" #include "theory/uf/equality_engine.h" #include "theory/quantifiers/term_database.h" @@ -26,6 +27,15 @@ using namespace CVC4::kind; using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::uf; +using namespace CVC4::theory::inst; + +namespace CVC4 { +namespace theory { +namespace uf { + +inline std::ostream& operator<<(std::ostream& out, const InstantiatorTheoryUf::Ips& ips) { + return out; +}; EqClassInfo::EqClassInfo( context::Context* c ) : d_funs( c ), d_pfuns( c ), d_disequal( c ){ @@ -33,13 +43,15 @@ EqClassInfo::EqClassInfo( context::Context* c ) : d_funs( c ), d_pfuns( c ), d_d //set member void EqClassInfo::setMember( Node n, quantifiers::TermDb* db ){ - if( n.getKind()==APPLY_UF ){ - d_funs[n.getOperator()] = true; + if( n.hasOperator() ){ + d_funs.insertAtContextLevelZero(n.getOperator(),true); } //add parent functions - for( std::map< Node, std::map< int, std::vector< Node > > >::iterator it = db->d_parents[n].begin(); + for( std::hash_map< Node, std::hash_map< int, std::vector< Node > >, NodeHashFunction >::iterator it = db->d_parents[n].begin(); it != db->d_parents[n].end(); ++it ){ - d_pfuns[ it->first ] = true; + //TODO Is it true to do it at level 0? That depend when SetMember is called + // At worst it is a good overapproximation + d_pfuns.insertAtContextLevelZero( it->first, true); } } @@ -62,6 +74,20 @@ void EqClassInfo::merge( EqClassInfo* eci ){ } } +inline void outputEqClassInfo( const char* c, const EqClassInfo* eci){ + Debug(c) << " funs:"; + for( EqClassInfo::BoolMap::iterator it = eci->d_funs.begin(); it != eci->d_funs.end(); it++ ) { + Debug(c) << (*it).first << ","; + } + Debug(c) << std::endl << "pfuns:"; + for( EqClassInfo::BoolMap::iterator it = eci->d_pfuns.begin(); it != eci->d_pfuns.end(); it++ ) { + Debug(c) << (*it).first << ","; + } + Debug(c) << std::endl; +} + + + InstantiatorTheoryUf::InstantiatorTheoryUf(context::Context* c, CVC4::theory::QuantifiersEngine* qe, Theory* th) : Instantiator( c, qe, th ) { @@ -221,21 +247,92 @@ void InstantiatorTheoryUf::newEqClass( TNode n ){ d_quantEngine->addTermToDatabase( n ); } +void InstantiatorTheoryUf::newTerms(SetNode& s){ + static NoMatchAttribute rewrittenNodeAttribute; + /* op -> nodes (if the set is empty, the op is not interesting) */ + std::hash_map< TNode, SetNode, TNodeHashFunction > h; + /* types -> nodes (if the set is empty, the type is not interesting) */ + std::hash_map< TypeNode, SetNode, TypeNodeHashFunction > tyh; + for(SetNode::iterator i=s.begin(), end=s.end(); i != end; ++i){ + if (i->getAttribute(rewrittenNodeAttribute)) continue; /* skip it */ + if( !d_cand_gens.empty() ){ + // op + TNode op = i->getOperator(); + std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator + is = h.find(op); + if(is == h.end()){ + std::pair::iterator,bool> + p = h.insert(make_pair(op,SetNode())); + is = p.first; + if(d_cand_gens.find(op) != d_cand_gens.end()){ + is->second.insert(*i); + } /* else we have inserted an empty set */ + }else if(!is->second.empty()){ + is->second.insert(*i); + } + } + if( !d_cand_gen_types.empty() ){ + //type + TypeNode ty = i->getType(); + std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator + is = tyh.find(ty); + if(is == tyh.end()){ + std::pair::iterator,bool> + p = tyh.insert(make_pair(ty,SetNode())); + is = p.first; + if(d_cand_gen_types.find(ty) != d_cand_gen_types.end()){ + is->second.insert(*i); + } /* else we have inserted an empty set */ + }else if(!is->second.empty()){ + is->second.insert(*i); + } + } + } + //op + for(std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator i=h.begin(), end=h.end(); + i != end; ++i){ + //new term, add n to candidate generators + if(i->second.empty()) continue; + std::map< Node, NodeNewTermDispatcher >::iterator + inpc = d_cand_gens.find(i->first); + //we know that this op exists + Assert(inpc != d_cand_gens.end()); + inpc->second.send(i->second); + } + //type + for(std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator i=tyh.begin(), end=tyh.end(); + i != end; ++i){ + //new term, add n to candidate generators + if(i->second.empty()) continue; + std::map< TypeNode, NodeNewTermDispatcher >::iterator + inpc = d_cand_gen_types.find(i->first); + //we know that this op exists + Assert(inpc != d_cand_gen_types.end()); + inpc->second.send(i->second); + } + +} + + /** merge */ void InstantiatorTheoryUf::merge( TNode a, TNode b ){ if( Options::current()->efficientEMatching ){ + //merge eqc_ops of b into a + EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a ); + EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( b ); + if( a.getKind()!=IFF && a.getKind()!=EQUAL && b.getKind()!=IFF && b.getKind()!=EQUAL ){ Debug("efficient-e-match") << "Merging " << a << " with " << b << std::endl; //determine new candidates for instantiation - computeCandidatesPcPairs( a, b ); - computeCandidatesPcPairs( b, a ); - computeCandidatesPpPairs( a, b ); - computeCandidatesPpPairs( b, a ); + computeCandidatesPcPairs( a, eci_a, b, eci_b ); + computeCandidatesPcPairs( b, eci_b, a, eci_a ); + computeCandidatesPpPairs( a, eci_a, b, eci_b ); + computeCandidatesPpPairs( b, eci_b, a, eci_a ); } - //merge eqc_ops of b into a - EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a ); - EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( b ); + computeCandidatesConstants( a, eci_a, b, eci_b); + computeCandidatesConstants( b, eci_b, a, eci_a); + eci_a->merge( eci_b ); } } @@ -258,97 +355,99 @@ EqClassInfo* InstantiatorTheoryUf::getOrCreateEquivalenceClassInfo( Node n ){ return d_eqc_ops[n]; } -void InstantiatorTheoryUf::computeCandidatesPcPairs( Node a, Node b ){ +void InstantiatorTheoryUf::computeCandidatesPcPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){ Debug("efficient-e-match") << "Compute candidates for pc pairs..." << std::endl; Debug("efficient-e-match") << " Eq class = ["; outputEqClass( "efficient-e-match", a); Debug("efficient-e-match") << "]" << std::endl; - EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a ); - EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( a ); + outputEqClassInfo("efficient-e-match",eci_a); for( BoolMap::iterator it = eci_a->d_funs.begin(); it != eci_a->d_funs.end(); it++ ) { //the child function: a member of eq_class( a ) has top symbol g, in other words g is in funs( a ) Node g = (*it).first; Debug("efficient-e-match") << " Checking application " << g << std::endl; //look at all parent/child pairs - for( std::map< Node, std::map< Node, std::vector< InvertedPathString > > >::iterator itf = d_pc_pairs[g].begin(); + for( std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > >::iterator itf = d_pc_pairs[g].begin(); itf != d_pc_pairs[g].end(); ++itf ){ //f/g is a parent/child pair Node f = itf->first; - if( eci_b->hasParent( f ) || true ){ + if( eci_b->hasParent( f ) ){ //DO_THIS: determine if f in pfuns( b ), only do the follow if so Debug("efficient-e-match") << " Checking parent application " << f << std::endl; //scan through the list of inverted path strings/candidate generators - for( std::map< Node, std::vector< InvertedPathString > >::iterator cit = itf->second.begin(); - cit != itf->second.end(); ++cit ){ - Node pat = cit->first; - Debug("efficient-e-match") << " Checking pattern " << pat << std::endl; - for( int c=0; c<(int)cit->second.size(); c++ ){ - Debug("efficient-e-match") << " Check inverted path string for pattern "; - outputInvertedPathString( "efficient-e-match", cit->second[c] ); - Debug("efficient-e-match") << std::endl; - - //collect all new relevant terms - std::vector< Node > terms; - terms.push_back( b ); - collectTermsIps( cit->second[c], terms ); - if( !terms.empty() ){ - Debug("efficient-e-match") << " -> Added terms (" << (int)terms.size() << "): "; - //add them as candidates to the candidate generator - for( int t=0; t<(int)terms.size(); t++ ){ - Debug("efficient-e-match") << terms[t] << " "; - //Notice() << "Add candidate (PC) " << terms[t] << std::endl; - for( int cg=0; cg<(int)d_pat_cand_gens[pat].size(); cg++ ){ - d_pat_cand_gens[pat][cg]->addCandidate( terms[t] ); - } - } - Debug("efficient-e-match") << std::endl; - } + for( std::vector< std::pair< NodePcDispatcher*, Ips > >::iterator cit = itf->second.begin(); + cit != itf->second.end(); ++cit ){ +#ifdef CVC4_DEBUG + Debug("efficient-e-match") << " Checking pattern " << cit->first->pat << std::endl; +#endif + Debug("efficient-e-match") << " Check inverted path string for pattern "; + outputIps( "efficient-e-match", cit->second ); + Debug("efficient-e-match") << std::endl; + + //collect all new relevant terms + SetNode terms; + terms.insert( b ); + collectTermsIps( cit->second, terms ); + if( terms.empty() ) continue; + Debug("efficient-e-match") << " -> Added terms (" << terms.size() << "): "; + for( SetNode::const_iterator t=terms.begin(), end=terms.end(); + t!=end; ++t ){ + Debug("efficient-e-match") << (*t) << " "; } + Debug("efficient-e-match") << std::endl; + //add them as candidates to the candidate generator + cit->first->send(terms); } } } } } -void InstantiatorTheoryUf::computeCandidatesPpPairs( Node a, Node b ){ +void InstantiatorTheoryUf::computeCandidatesPpPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){ Debug("efficient-e-match") << "Compute candidates for pp pairs..." << std::endl; - EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a ); - EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( a ); - for( std::map< Node, std::map< Node, std::map< Node, std::vector< IpsPair > > > >::iterator it = d_pp_pairs.begin(); + for( std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > >::iterator it = d_pp_pairs.begin(); it != d_pp_pairs.end(); ++it ){ Node f = it->first; if( eci_a->hasParent( f ) ){ Debug("efficient-e-match") << " Checking parent application " << f << std::endl; - for( std::map< Node, std::map< Node, std::vector< IpsPair > > >::iterator it2 = it->second.begin(); + for( std::map< Node, std::vector< triple > >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ Node g = it2->first; if( eci_b->hasParent( g ) ){ Debug("efficient-e-match") << " Checking parent application " << g << std::endl; //if f in pfuns( a ) and g is in pfuns( b ), only do the follow if so - for( std::map< Node, std::vector< IpsPair > >::iterator cit = it2->second.begin(); + for( std::vector< triple > ::iterator cit = it2->second.begin(); cit != it2->second.end(); ++cit ){ - Node pat = cit->first; - for( int c=0; c<(int)cit->second.size(); c++ ){ - std::vector< Node > a_terms; - a_terms.push_back( a ); - if( !a_terms.empty() ){ - collectTermsIps( cit->second[c].first, a_terms ); - std::vector< Node > b_terms; - b_terms.push_back( b ); - collectTermsIps( cit->second[c].first, b_terms ); - //take intersection - for( int t=0; t<(int)a_terms.size(); t++ ){ - if( std::find( b_terms.begin(), b_terms.end(), a_terms[t] )!=b_terms.end() ){ - //Notice() << "Add candidate (PP) " << a_terms[t] << std::endl; - Debug("efficient-e-match") << " -> Add term " << a_terms[t] << std::endl; - //add to all candidate generators having this term - for( int cg=0; cg<(int)d_pat_cand_gens[pat].size(); cg++ ){ - d_pat_cand_gens[pat][cg]->addCandidate( a_terms[t] ); - } - } - } - } +#ifdef CVC4_DEBUG + Debug("efficient-e-match") << " Checking pattern " << cit->first->pat1 << " and " << cit->first->pat2 << std::endl; +#endif + Debug("efficient-e-match") << " Check inverted path string "; + outputIps( "efficient-e-match", cit->second ); + SetNode a_terms; + a_terms.insert( a ); + collectTermsIps( cit->second, a_terms ); + if( a_terms.empty() ) continue; + Debug("efficient-e-match") << " And check inverted path string "; + outputIps( "efficient-e-match", cit->third ); + SetNode b_terms; + b_terms.insert( b ); + collectTermsIps( cit->third, b_terms ); + if( b_terms.empty() ) continue; + //Start debug + Debug("efficient-e-match") << " -> Possibly Added termsA (" << a_terms.size() << "): "; + for( SetNode::const_iterator t=a_terms.begin(), end=a_terms.end(); + t!=end; ++t ){ + Debug("efficient-e-match") << (*t) << " "; + } + Debug("efficient-e-match") << std::endl; + Debug("efficient-e-match") << " -> Possibly Added termsB (" << b_terms.size() << "): "; + for( SetNode::const_iterator t=b_terms.begin(), end=b_terms.end(); + t!=end; ++t ){ + Debug("efficient-e-match") << (*t) << " "; } + Debug("efficient-e-match") << std::endl; + //End debug + + cit->first->send(a_terms,b_terms); } } } @@ -356,39 +455,87 @@ void InstantiatorTheoryUf::computeCandidatesPpPairs( Node a, Node b ){ } } -void InstantiatorTheoryUf::collectTermsIps( InvertedPathString& ips, std::vector< Node >& terms, int index ){ - if( index<(int)ips.size() && !terms.empty() ){ + +void InstantiatorTheoryUf::computeCandidatesConstants( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){ + Debug("efficient-e-match") << "Compute candidates constants for cc pairs..." << std::endl; + Debug("efficient-e-match") << " Eq class = ["; + outputEqClass( "efficient-e-match", a); + Debug("efficient-e-match") << "]" << std::endl; + outputEqClassInfo("efficient-e-match",eci_a); + for( std::map< Node, std::map< Node, NodePcDispatcher* > >::iterator + it = d_cc_pairs.begin(), end = d_cc_pairs.end(); + it != end; ++it ) { + Debug("efficient-e-match") << " Checking application " << it->first << std::endl; + if( !eci_b->hasFunction(it->first) ) continue; + for( std::map< Node, NodePcDispatcher* >::iterator + itc = it->second.begin(), end = it->second.end(); + itc != end; ++itc ) { + //The constant + Debug("efficient-e-match") << " Checking constant " << a << std::endl; + if(getRepresentative(itc->first) != a) continue; + SetNode s; + eq::EqClassIterator eqc_iter( b, &((TheoryUF*)d_th)->d_equalityEngine ); + while( !eqc_iter.isFinished() ){ + Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter) + << std::endl; + if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == it->first ) s.insert(*eqc_iter); + eqc_iter++; + } + + if( s.empty() ) continue; + Debug("efficient-e-match") << " -> Added terms (" << s.size() << "): "; + for( SetNode::const_iterator t=s.begin(), end=s.end(); + t!=end; ++t ){ + Debug("efficient-e-match") << (*t) << " "; + } + Debug("efficient-e-match") << std::endl; + itc->second->send(s); + } + } +} + +void InstantiatorTheoryUf::collectTermsIps( Ips& ips, SetNode & terms ){ + Assert( ips.size() > 0); + return collectTermsIps( ips, terms, ips.size() - 1); +} + +void InstantiatorTheoryUf::collectTermsIps( Ips& ips, SetNode& terms, int index ){ + if( !terms.empty() ){ Debug("efficient-e-match-debug") << "> Process " << index << std::endl; Node f = ips[index].first; int arg = ips[index].second; //for each term in terms, determine if any term (modulo equality) has parent "f" from position "arg" - bool addRep = ( index!=(int)ips.size()-1 ); - std::vector< Node > newTerms; - for( int t=0; t<(int)terms.size(); t++ ){ - collectParentsTermsIps( terms[t], f, arg, newTerms, addRep ); + bool addRep = ( index!=0 ); // We want to keep the top symbol for the last + SetNode newTerms; + for( SetNode::const_iterator t=terms.begin(), end=terms.end(); + t!=end; ++t ){ + collectParentsTermsIps( *t, f, arg, newTerms, addRep ); } - terms.clear(); - terms.insert( terms.begin(), newTerms.begin(), newTerms.end() ); + terms.swap(newTerms); Debug("efficient-e-match-debug") << "> Terms are now: "; - for( int t=0; t<(int)terms.size(); t++ ){ - Debug("efficient-e-match-debug") << terms[t] << " "; + for( SetNode::const_iterator t=terms.begin(), end=terms.end(); + t!=end; ++t ){ + Debug("efficient-e-match-debug") << *t << " "; } Debug("efficient-e-match-debug") << std::endl; - collectTermsIps( ips, terms, index+1 ); + if(index!=0) collectTermsIps( ips, terms, index-1 ); } } -bool InstantiatorTheoryUf::collectParentsTermsIps( Node n, Node f, int arg, std::vector< Node >& terms, bool addRep, bool modEq ){ +bool InstantiatorTheoryUf::collectParentsTermsIps( Node n, Node f, int arg, SetNode & terms, bool addRep, bool modEq ){ //modEq default true bool addedTerm = false; - if( ((TheoryUF*)d_th)->d_equalityEngine.hasTerm( n ) && modEq ){ + + if( modEq && ((TheoryUF*)d_th)->d_equalityEngine.hasTerm( n )){ Assert( getRepresentative( n )==n ); //collect modulo equality //DO_THIS: this should (if necessary) compute a current set of (f, arg) parents for n and cache it - eq::EqClassIterator eqc_iter( getRepresentative( n ), &((TheoryUF*)d_th)->d_equalityEngine ); + eq::EqClassIterator eqc_iter( n, &((TheoryUF*)d_th)->d_equalityEngine ); while( !eqc_iter.isFinished() ){ + Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter) + << std::endl; if( collectParentsTermsIps( (*eqc_iter), f, arg, terms, addRep, false ) ){ //if only one argument, we know we can stop (since all others added will be congruent) if( f.getType().getNumChildren()==2 ){ @@ -401,90 +548,263 @@ bool InstantiatorTheoryUf::collectParentsTermsIps( Node n, Node f, int arg, std: }else{ 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() ){ - if( db->d_parents[n][f].find( arg )!=db->d_parents[n][f].end() ){ - for( int i=0; i<(int)db->d_parents[n][f][arg].size(); i++ ){ - Node t = db->d_parents[n][f][arg][i]; - if( addRep ){ - t = getRepresentative( t ); - } - if( std::find( terms.begin(), terms.end(), t )==terms.end() ){ - terms.push_back( t ); - } - addedTerm = true; - } - } - } + const std::vector & parents = db->getParents(n,f,arg); + for( size_t i=0; i > >& ips_map ){ - Assert( pat.getKind()==APPLY_UF ); +void InstantiatorTheoryUf::registerPatternElementPairs2( Node pat, Ips& ips, PpIpsMap & pp_ips_map, NodePcDispatcher* npc ){ + Assert( pat.hasOperator() ); //add information for possible pp-pair + ips.push_back( std::pair< Node, int >( pat.getOperator(), 0 ) ); //0 is just a dumb value + for( int i=0; i<(int)pat.getNumChildren(); i++ ){ if( pat[i].getKind()==INST_CONSTANT ){ - ips_map[ pat[i] ].push_back( std::pair< Node, InvertedPathString >( pat.getOperator(), InvertedPathString( ips ) ) ); + ips.back().second = i; + pp_ips_map[ pat[i] ].push_back( make_pair( pat.getOperator(), Ips( ips ) ) ); } } - ips.push_back( std::pair< Node, int >( pat.getOperator(), 0 ) ); + for( int i=0; i<(int)pat.getNumChildren(); i++ ){ if( pat[i].getKind()==APPLY_UF ){ ips.back().second = i; - registerPatternElementPairs2( opat, pat[i], ips, ips_map ); + registerPatternElementPairs2( pat[i], ips, pp_ips_map, npc ); Debug("pattern-element-opt") << "Found pc-pair ( " << pat.getOperator() << ", " << pat[i].getOperator() << " )" << std::endl; Debug("pattern-element-opt") << " Path = "; - outputInvertedPathString( "pattern-element-opt", ips ); + outputIps( "pattern-element-opt", ips ); Debug("pattern-element-opt") << std::endl; //pat.getOperator() and pat[i].getOperator() are a pc-pair - d_pc_pairs[ pat[i].getOperator() ][ pat.getOperator() ][opat].push_back( InvertedPathString( ips ) ); + d_pc_pairs[ pat[i].getOperator() ][ pat.getOperator() ] + .push_back( make_pair(npc,Ips(ips)) ); } } ips.pop_back(); } -void InstantiatorTheoryUf::registerPatternElementPairs( Node pat ){ - InvertedPathString ips; - std::map< Node, std::vector< std::pair< Node, InvertedPathString > > > ips_map; - registerPatternElementPairs2( pat, pat, ips, ips_map ); - for( std::map< Node, std::vector< std::pair< Node, InvertedPathString > > >::iterator it = ips_map.begin(); it != ips_map.end(); ++it ){ - for( int j=0; j<(int)it->second.size(); j++ ){ - for( int k=j+1; k<(int)it->second.size(); k++ ){ +void InstantiatorTheoryUf::registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map, + NodePcDispatcher* npc, + NodePpDispatcher* npp){ + Ips ips; + registerPatternElementPairs2( pat, ips, pp_ips_map, npc ); + for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){ + // for each variable construct all the pp-pair + for( size_t j=0; jsecond.size(); j++ ){ + for( size_t k=j+1; ksecond.size(); k++ ){ //found a pp-pair Debug("pattern-element-opt") << "Found pp-pair ( " << it->second[j].first << ", " << it->second[k].first << " )" << std::endl; Debug("pattern-element-opt") << " Paths = "; - outputInvertedPathString( "pattern-element-opt", it->second[j].second ); + outputIps( "pattern-element-opt", it->second[j].second ); Debug("pattern-element-opt") << " and "; - outputInvertedPathString( "pattern-element-opt", it->second[k].second ); + outputIps( "pattern-element-opt", it->second[k].second ); Debug("pattern-element-opt") << std::endl; - d_pp_pairs[ it->second[j].first ][ it->second[k].first ][pat].push_back( IpsPair( it->second[j].second, it->second[k].second ) ); + d_pp_pairs[ it->second[j].first ][ it->second[k].first ] + .push_back( make_triple( npp, it->second[j].second, it->second[k].second )); } } } +}; + +void findPpSite(Node pat, InstantiatorTheoryUf::Ips& ips, InstantiatorTheoryUf::PpIpsMap & pp_ips_map){ + Assert( pat.getKind()==APPLY_UF ); + //add information for possible pp-pair + + ips.push_back( make_pair( pat.getOperator(), 0) ); + for( size_t i=0; i & pats){ + hash_map npps; + for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){ + MultiPpIpsMap::iterator mit = multi_pp_ips_map.find(it->first); + if(mit == multi_pp_ips_map.end()) continue; + // for each variable construct all the pp-pair + // j the last pattern treated + for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ; + j != jend; ++j){ + // k one of the previous one + for( std::vector< triple< size_t, Node, Ips > >::iterator k=mit->second.begin(), kend = mit->second.end() ; + k != kend; ++k){ + //found a pp-pair + Debug("pattern-element-opt") << "Found multi-pp-pair ( " << j->first + << ", " << k->second << " in "<< k->first + << " )" << std::endl; + Debug("pattern-element-opt") << " Paths = "; + outputIps( "pattern-element-opt", j->second ); + Debug("pattern-element-opt") << " and "; + outputIps( "pattern-element-opt", k->third ); + Debug("pattern-element-opt") << std::endl; + NodePpDispatcher* dispatcher; + hash_map::iterator inpp = npps.find(k->first); + if( inpp != npps.end() ) dispatcher = inpp->second; + else{ + dispatcher = new NodePpDispatcher(); +#ifdef CVC4_DEBUG + dispatcher->pat1 = pats[index2]; + dispatcher->pat2 = pats[k->first]; +#endif + dispatcher->addPpDispatcher(&eh,index2,k->first); + }; + d_pp_pairs[ j->first ][ k->second ].push_back( make_triple( dispatcher, j->second, k->third )); + } + } } - d_pat_cand_gens[pat].push_back( cg ); - //take all terms from the uf term db and add to candidate generator - Node op = pat.getOperator(); - 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] ); + /** Put pp_ips_map to multi_pp_ips_map */ + for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){ + for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ; + j != jend; ++j){ + multi_pp_ips_map[it->first].push_back(make_triple(index2, j->first, j->second)); + } + } + +} + + +void InstantiatorTheoryUf::registerEfficientHandler( EfficientHandler& handler, + const std::vector< Node > & pats ){ + Assert(pats.size() > 0); + + MultiPpIpsMap multi_pp_ips_map; + PpIpsMap pp_ips_map; + //In a multi-pattern Pattern that is only a variable are specials, + //if the variable appears in another pattern, it can be discarded. + //Otherwise new term of this term can be candidate. So we stock them + //here before adding them. + std::vector< size_t > patVars; + + Debug("pattern-element-opt") << "Register patterns" << pats << std::endl; + for(size_t i = 0; i < pats.size(); ++i){ + if( pats[i].getKind() == kind::INST_CONSTANT){ + patVars.push_back(i); + continue; + } + //to complete + if( pats[i].getKind() == kind::NOT && pats[i][0].getKind() == kind::EQUAL){ + Node cst = NodeManager::currentNM()->mkConst(false); + TNode op = pats[i][0].getOperator(); + if(d_cc_pairs[op][cst] == NULL){ + d_cc_pairs[op][cst] = new NodePcDispatcher(); + } + d_cc_pairs[op][cst]->addPcDispatcher(&handler,i); + continue; + } + //end to complete + Debug("pattern-element-opt") << " Register candidate generator..." << pats[i] << std::endl; + /* Has the pattern already been seen */ + if( d_pat_cand_gens.find( pats[i] )==d_pat_cand_gens.end() ){ + NodePcDispatcher* npc = new NodePcDispatcher(); + NodePpDispatcher* npp = new NodePpDispatcher(); +#ifdef CVC4_DEBUG + npc->pat = pats[i]; + npp->pat1 = pats[i]; + npp->pat2 = pats[i]; +#endif + d_pat_cand_gens[pats[i]] = make_pair(npc,npp); + registerPatternElementPairs( pats[i], pp_ips_map, npc, npp ); + }else{ + Ips ips; + findPpSite(pats[i],ips,pp_ips_map); + } + //Has the top operator already been seen */ + TNode op = pats[i].getOperator(); + d_pat_cand_gens[pats[i]].first->addPcDispatcher(&handler,i); + d_pat_cand_gens[pats[i]].second->addPpDispatcher(&handler,i,i); + d_cand_gens[op].addNewTermDispatcher(&handler,i); + + combineMultiPpIpsMap(pp_ips_map,multi_pp_ips_map,handler,i,pats); + + pp_ips_map.clear(); + } + + for(size_t i = 0; i < patVars.size(); ++i){ + TNode var = pats[patVars[i]]; + Assert( var.getKind() == kind::INST_CONSTANT ); + if( multi_pp_ips_map.find(var) != multi_pp_ips_map.end() ){ + //The variable appear in another pattern, skip it + continue; + }; + d_cand_gen_types[var.getType()].addNewTermDispatcher(&handler,patVars[i]); } - d_cand_gens[op].push_back( cg ); + //take all terms from the uf term db and add to candidate generator + if( pats[0].getKind() == kind::INST_CONSTANT ){ + TypeNode ty = pats[0].getType(); + rrinst::CandidateGenerator* cg = d_quantEngine->getRRCanGenClasses(ty); + cg->reset(Node::null()); + TNode c; + SetNode ele; + while( !(c = cg->getNextCandidate()).isNull() ){ + if( c.getType() == ty ) ele.insert(c); + } + if( !ele.empty() ){ + // for(std::vector::iterator i = db->d_op_map[op].begin(), end = db->d_op_map[op].end(); i != end; ++i){ + // if(CandidateGenerator::isLegalCandidate(*i)) ele.insert(*i); + // } + if(Debug.isOn("efficient-e-match-stats")){ + Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl; + } + handler.addMonoCandidate(ele, 0); + } + + } else if( pats[0].getKind() == kind::NOT && pats[0][0].getKind() == kind::EQUAL){ + Node cst = NodeManager::currentNM()->mkConst(false); + TNode op = pats[0][0].getOperator(); + cst = getRepresentative(cst); + SetNode ele; + eq::EqClassIterator eqc_iter( cst, &((TheoryUF*)d_th)->d_equalityEngine ); + while( !eqc_iter.isFinished() ){ + Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter) + << std::endl; + if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == op ) ele.insert(*eqc_iter); + eqc_iter++; + } + if( !ele.empty() ){ + if(Debug.isOn("efficient-e-match-stats")){ + Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl; + } + handler.addMonoCandidate(ele, 0); + } + + } else { + Node op = pats[0].getOperator(); + TermDb* db = d_quantEngine->getTermDatabase(); + if(db->d_op_map[op].begin() != db->d_op_map[op].end()){ + SetNode ele; + // for(std::vector::iterator i = db->d_op_map[op].begin(), end = db->d_op_map[op].end(); i != end; ++i){ + // if(CandidateGenerator::isLegalCandidate(*i)) ele.insert(*i); + // } + ele.insert(db->d_op_map[op].begin(), db->d_op_map[op].end()); + if(Debug.isOn("efficient-e-match-stats")){ + Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl; + } + handler.addMonoCandidate(ele, 0); + } + } Debug("efficient-e-match") << "Done." << std::endl; } -void InstantiatorTheoryUf::registerTrigger( Trigger* tr, Node op ){ +void InstantiatorTheoryUf::registerTrigger( theory::inst::Trigger* tr, Node op ){ if( std::find( d_op_triggers[op].begin(), d_op_triggers[op].end(), tr )==d_op_triggers[op].end() ){ d_op_triggers[op].push_back( tr ); } @@ -506,9 +826,28 @@ void InstantiatorTheoryUf::outputEqClass( const char* c, Node n ){ } } -void InstantiatorTheoryUf::outputInvertedPathString( const char* c, InvertedPathString& ips ){ +void InstantiatorTheoryUf::outputIps( const char* c, Ips& ips ){ for( int i=0; i<(int)ips.size(); i++ ){ if( i>0 ){ Debug( c ) << "."; } Debug( c ) << ips[i].first << "." << ips[i].second; } } + +rrinst::CandidateGenerator* InstantiatorTheoryUf::getRRCanGenClasses(){ + uf::TheoryUF* uf = static_cast(getTheory()); + eq::EqualityEngine* ee = + static_cast(uf->getEqualityEngine()); + return new eq::rrinst::CandidateGeneratorTheoryEeClasses(ee); +} + +rrinst::CandidateGenerator* InstantiatorTheoryUf::getRRCanGenClass(){ + uf::TheoryUF* uf = static_cast(getTheory()); + eq::EqualityEngine* ee = + static_cast(uf->getEqualityEngine()); + return new eq::rrinst::CandidateGeneratorTheoryEeClass(ee); +} + + +} /* namespace uf */ +} /* namespace theory */ +} /* namespace cvc4 */ diff --git a/src/theory/uf/theory_uf_instantiator.h b/src/theory/uf/theory_uf_instantiator.h index 4ddc01986..3a2a5cc0e 100644 --- a/src/theory/uf/theory_uf_instantiator.h +++ b/src/theory/uf/theory_uf_instantiator.h @@ -27,6 +27,9 @@ #include "util/stats.h" #include "theory/uf/theory_uf.h" +#include "theory/trigger.h" +#include "util/ntuple.h" +#include "context/cdqueue.h" namespace CVC4 { namespace theory { @@ -38,6 +41,300 @@ namespace quantifiers{ namespace uf { class InstantiatorTheoryUf; +class HandlerPcDispatcher; +class HandlerPpDispatcher; + +typedef std::set SetNode; + +template +class CleanUpPointer{ +public: + inline void operator()(T** e){ + delete(*e); + }; +}; + +class EfficientHandler{ +public: + typedef std::pair< Node, size_t > MonoCandidate; + typedef std::pair< MonoCandidate, MonoCandidate > MultiCandidate; + typedef std::pair< SetNode, size_t > MonoCandidates; + typedef std::pair< MonoCandidates, MonoCandidates > MultiCandidates; +private: + /* Queue of candidates */ + typedef context::CDQueue< MonoCandidates *, CleanUpPointer > MonoCandidatesQueue; + typedef context::CDQueue< MultiCandidates *, CleanUpPointer > MultiCandidatesQueue; + MonoCandidatesQueue d_monoCandidates; + typedef uf::SetNode::iterator SetNodeIter; + context::CDO d_si; + context::CDO d_mono_not_first; + + MonoCandidatesQueue d_monoCandidatesNewTerm; + context::CDO d_si_new_term; + context::CDO d_mono_not_first_new_term; + + + MultiCandidatesQueue d_multiCandidates; + context::CDO d_si1; + context::CDO d_si2; + context::CDO d_multi_not_first; + + + friend class InstantiatorTheoryUf; + friend class HandlerPcDispatcher; + friend class HandlerPpDispatcher; + friend class HandlerNewTermDispatcher; +protected: + void addMonoCandidate(SetNode & s, size_t index){ + Assert(!s.empty()); + d_monoCandidates.push(new MonoCandidates(s,index)); + } + void addMonoCandidateNewTerm(SetNode & s, size_t index){ + Assert(!s.empty()); + d_monoCandidatesNewTerm.push(new MonoCandidates(s,index)); + } + void addMultiCandidate(SetNode & s1, size_t index1, SetNode & s2, size_t index2){ + Assert(!s1.empty() && !s2.empty()); + d_multiCandidates.push(new MultiCandidates(MonoCandidates(s1,index1), + MonoCandidates(s2,index2))); + } +public: + EfficientHandler(context::Context * c): + //false for d_mono_not_first beacause its the default constructor + d_monoCandidates(c), d_si(c), d_mono_not_first(c,false), + d_monoCandidatesNewTerm(c), d_si_new_term(c), + d_mono_not_first_new_term(c,false), + d_multiCandidates(c) , d_si1(c), d_si2(c), d_multi_not_first(c,false) {}; + + bool getNextMonoCandidate(MonoCandidate & candidate){ + if(d_monoCandidates.empty()) return false; + const MonoCandidates * front = d_monoCandidates.front(); + SetNodeIter si_tmp; + if(!d_mono_not_first){ + Assert(front->first.begin() != front->first.end()); + d_mono_not_first = true; + si_tmp=front->first.begin(); + }else{ + si_tmp = d_si; + ++si_tmp; + }; + if(si_tmp != front->first.end()){ + candidate.first = (*si_tmp); + candidate.second = front->second; + d_si = si_tmp; + Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl; + return true; + }; + d_monoCandidates.pop(); + d_mono_not_first = false; + return getNextMonoCandidate(candidate); + }; + + bool getNextMonoCandidateNewTerm(MonoCandidate & candidate){ + if(d_monoCandidatesNewTerm.empty()) return false; + const MonoCandidates * front = d_monoCandidatesNewTerm.front(); + SetNodeIter si_tmp; + if(!d_mono_not_first_new_term){ + Assert(front->first.begin() != front->first.end()); + d_mono_not_first_new_term = true; + si_tmp=front->first.begin(); + }else{ + si_tmp = d_si_new_term; + ++si_tmp; + }; + if(si_tmp != front->first.end()){ + candidate.first = (*si_tmp); + candidate.second = front->second; + d_si_new_term = si_tmp; + Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl; + return true; + }; + d_monoCandidatesNewTerm.pop(); + d_mono_not_first_new_term = false; + return getNextMonoCandidateNewTerm(candidate); + }; + + bool getNextMultiCandidate(MultiCandidate & candidate){ + if(d_multiCandidates.empty()) return false; + const MultiCandidates* front = d_multiCandidates.front(); + SetNodeIter si1_tmp; + SetNodeIter si2_tmp; + if(!d_multi_not_first){ + Assert(front->first.first.begin() != front->first.first.end()); + Assert(front->second.first.begin() != front->second.first.end()); + si1_tmp = front->first.first.begin(); + si2_tmp = front->second.first.begin(); + }else{ + si1_tmp = d_si1; + si2_tmp = d_si2; + ++si2_tmp; + }; + if(si2_tmp != front->second.first.end()){ + candidate.first.first = *si1_tmp; + candidate.first.second = front->first.second; + candidate.second.first = *si2_tmp; + candidate.second.second = front->second.second; + if(!d_multi_not_first){d_si1 = si1_tmp; d_multi_not_first = true; }; + d_si2 = si2_tmp; + Debug("efficienthandler") << "Multi1 produces " + << candidate.first.first << " for " + << candidate.first.second << " and " + << candidate.second.first << " for " + << candidate.second.second << " and " + << std::endl; + return true; + }; // end of the second set + si2_tmp = front->second.first.begin(); + ++si1_tmp; + if(si1_tmp != front->first.first.end()){ + candidate.first.first = *si1_tmp; + candidate.first.second = front->first.second; + candidate.second.first = *si2_tmp; + candidate.second.second = front->second.second; + d_si1 = si1_tmp; + d_si2 = si2_tmp; + Debug("efficienthandler") << "Multi2 produces " + << candidate.first.first << " for " + << candidate.first.second << " and " + << candidate.second.first << " for " + << candidate.second.second << " and " + << std::endl; + return true; + }; // end of the first set + d_multiCandidates.pop(); + d_multi_not_first = false; + return getNextMultiCandidate(candidate); + } +}; + +class PcDispatcher{ +public: + virtual ~PcDispatcher(){}; + /* Send the node to the dispatcher */ + virtual void send(SetNode & s) = 0; +}; + + +class HandlerPcDispatcher: public PcDispatcher{ + EfficientHandler* d_handler; + size_t d_index; +public: + HandlerPcDispatcher(EfficientHandler* handler, size_t index): + d_handler(handler), d_index(index) {}; + void send(SetNode & s){ + d_handler->addMonoCandidate(s,d_index); + } +}; + + +/** All the dispatcher that correspond to this node */ +class NodePcDispatcher: public PcDispatcher{ +#ifdef CVC4_DEBUG +public: + Node pat; +#endif/* CVC4_DEBUG*/ +private: + std::vector d_dis; +public: + void send(SetNode & s){ + Assert(!s.empty()); + for(std::vector::iterator i = d_dis.begin(), end = d_dis.end(); + i != end; ++i){ + (*i).send(s); + } + } + void addPcDispatcher(EfficientHandler* handler, size_t index){ + d_dis.push_back(HandlerPcDispatcher(handler,index)); + } +}; + + +class HandlerNewTermDispatcher: public PcDispatcher{ + EfficientHandler* d_handler; + size_t d_index; +public: + HandlerNewTermDispatcher(EfficientHandler* handler, size_t index): + d_handler(handler), d_index(index) {}; + void send(SetNode & s){ + d_handler->addMonoCandidateNewTerm(s,d_index); + } +}; + +/** All the dispatcher that correspond to this node */ +class NodeNewTermDispatcher: public PcDispatcher{ +#ifdef CVC4_DEBUG +public: + Node pat; +#endif/* CVC4_DEBUG*/ +private: + std::vector d_dis; +public: + void send(SetNode & s){ + Assert(!s.empty()); + for(std::vector::iterator i = d_dis.begin(), end = d_dis.end(); + i != end; ++i){ + (*i).send(s); + } + } + void addNewTermDispatcher(EfficientHandler* handler, size_t index){ + d_dis.push_back(HandlerNewTermDispatcher(handler,index)); + } +}; + +class PpDispatcher{ +public: + virtual ~PpDispatcher(){}; + /* Send the node to the dispatcher */ + virtual void send(SetNode & s1, SetNode & s2, SetNode & sinter) = 0; +}; + + +class HandlerPpDispatcher: public PpDispatcher{ + EfficientHandler* d_handler; + size_t d_index1; + size_t d_index2; +public: + HandlerPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2): + d_handler(handler), d_index1(index1), d_index2(index2) {}; + void send(SetNode & s1, SetNode & s2, SetNode & sinter){ + if(d_index1 == d_index2){ + if(!sinter.empty()) + d_handler->addMonoCandidate(sinter,d_index1); + }else{ + d_handler->addMultiCandidate(s1,d_index1,s2,d_index2); + } + } +}; + + +/** All the dispatcher that correspond to this node */ +class NodePpDispatcher: public PpDispatcher{ +#ifdef CVC4_DEBUG +public: + Node pat1; + Node pat2; +#endif/* CVC4_DEBUG */ +private: + std::vector d_dis; + void send(SetNode & s1, SetNode & s2, SetNode & inter){ + for(std::vector::iterator i = d_dis.begin(), end = d_dis.end(); + i != end; ++i){ + (*i).send(s1,s2,inter); + } + } +public: + void send(SetNode & s1, SetNode & s2){ + // can be done in HandlerPpDispatcher lazily + Assert(!s1.empty() && !s2.empty()); + SetNode inter; + std::set_intersection( s1.begin(), s1.end(), s2.begin(), s2.end(), + std::inserter( inter, inter.begin() ) ); + send(s1,s2,inter); + } + void addPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2){ + d_dis.push_back(HandlerPpDispatcher(handler,index1,index2)); + } +}; //equivalence class info class EqClassInfo @@ -68,7 +365,7 @@ public: }; class InstantiatorTheoryUf : public Instantiator{ - friend class ::CVC4::theory::InstMatchGenerator; + friend class ::CVC4::theory::inst::InstMatchGenerator; friend class ::CVC4::theory::quantifiers::TermDb; protected: typedef context::CDHashMap BoolMap; @@ -82,7 +379,14 @@ protected: InstStrategyUserPatterns* d_isup; public: InstantiatorTheoryUf(context::Context* c, CVC4::theory::QuantifiersEngine* qe, Theory* th); - ~InstantiatorTheoryUf() {} + ~InstantiatorTheoryUf() { + for(std::map< Node, std::pair >::iterator + i = d_pat_cand_gens.begin(), end = d_pat_cand_gens.end(); + i != end; i++){ + delete(i->second.first); + delete(i->second.second); + } + } /** assertNode method */ void assertNode( Node assertion ); /** Pre-register a term. Done one time for a Node, ever. */ @@ -127,6 +431,9 @@ public: bool areDisequal( Node a, Node b ); Node getRepresentative( Node a ); Node getInternalRepresentative( Node a ); + /** general creators of candidate generators */ + rrinst::CandidateGenerator* getRRCanGenClasses(); + rrinst::CandidateGenerator* getRRCanGenClass(); /** new node */ void newEqClass( TNode n ); /** merge */ @@ -136,47 +443,66 @@ public: /** get equivalence class info */ EqClassInfo* getEquivalenceClassInfo( Node n ); EqClassInfo* getOrCreateEquivalenceClassInfo( Node n ); + typedef std::vector< std::pair< Node, int > > Ips; + typedef std::map< Node, std::vector< std::pair< Node, Ips > > > PpIpsMap; + typedef std::map< Node, std::vector< triple< size_t, Node, Ips > > > MultiPpIpsMap; + private: - typedef std::vector< std::pair< Node, int > > InvertedPathString; - typedef std::pair< InvertedPathString, InvertedPathString > IpsPair; /** Parent/Child Pairs (for efficient E-matching) So, for example, if we have the pattern f( g( x ) ), then d_pc_pairs[g][f][f( g( x ) )] = { f.0 }. */ - std::map< Node, std::map< Node, std::map< Node, std::vector< InvertedPathString > > > > d_pc_pairs; + std::map< Node, std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > > > d_pc_pairs; /** Parent/Parent Pairs (for efficient E-matching) */ - std::map< Node, std::map< Node, std::map< Node, std::vector< IpsPair > > > > d_pp_pairs; + std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > > d_pp_pairs; + /** Constants/Child Pairs + So, for example, if we have the pattern f( x ) = c, then d_pc_pairs[f][c] = ..., pcdispatcher, ... + */ + //TODO constant in pattern can use the same thing just add an Ips + std::map< Node, std::map< Node, NodePcDispatcher* > > d_cc_pairs; /** list of all candidate generators for each operator */ - std::map< Node, std::vector< CandidateGenerator* > > d_cand_gens; + std::map< Node, NodeNewTermDispatcher > d_cand_gens; + /** list of all candidate generators for each type */ + std::map< TypeNode, NodeNewTermDispatcher > d_cand_gen_types; /** map from patterns to candidate generators */ - std::map< Node, std::vector< CandidateGenerator* > > d_pat_cand_gens; + std::map< Node, std::pair > d_pat_cand_gens; /** helper functions */ - void registerPatternElementPairs2( Node opat, Node pat, InvertedPathString& ips, - std::map< Node, std::vector< std::pair< Node, InvertedPathString > > >& ips_map ); - void registerPatternElementPairs( Node pat ); + void registerPatternElementPairs2( Node pat, Ips& ips, + PpIpsMap & pp_ips_map, NodePcDispatcher* npc); + void registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map, + NodePcDispatcher* npc, NodePpDispatcher* npp); + /** find the pp-pair between pattern inside multi-pattern*/ + void combineMultiPpIpsMap(PpIpsMap & pp_ips_map, MultiPpIpsMap & multi_pp_ips_map, + EfficientHandler& eh, size_t index2, + const std::vector & pats); //pats for debug /** compute candidates for pc pairs */ - void computeCandidatesPcPairs( Node a, Node b ); + void computeCandidatesPcPairs( Node a, EqClassInfo*, Node b, EqClassInfo* ); /** compute candidates for pp pairs */ - void computeCandidatesPpPairs( Node a, Node b ); + void computeCandidatesPpPairs( Node a, EqClassInfo*, Node b, EqClassInfo* ); + /** compute candidates for cc pairs */ + void computeCandidatesConstants( Node a, EqClassInfo*, Node b, EqClassInfo* ); /** collect terms based on inverted path string */ - void collectTermsIps( InvertedPathString& ips, std::vector< Node >& terms, int index = 0 ); - bool collectParentsTermsIps( Node n, Node f, int arg, std::vector< Node >& terms, bool addRep, bool modEq = true ); + void collectTermsIps( Ips& ips, SetNode& terms, int index); + bool collectParentsTermsIps( Node n, Node f, int arg, SetNode& terms, bool addRep, bool modEq = true ); public: + void collectTermsIps( Ips& ips, SetNode& terms); /** Register candidate generator cg for pattern pat. (for use with efficient e-matching) This request will ensure that calls will be made to cg->addCandidate( n ) for all ground terms n that are relevant for matching with pat. */ - void registerCandidateGenerator( CandidateGenerator* cg, Node pat ); private: /** triggers */ - std::map< Node, std::vector< Trigger* > > d_op_triggers; + std::map< Node, std::vector< inst::Trigger* > > d_op_triggers; public: /** register trigger (for eager quantifier instantiation) */ - void registerTrigger( Trigger* tr, Node op ); + void registerTrigger( inst::Trigger* tr, Node op ); + void registerEfficientHandler( EfficientHandler& eh, const std::vector & pat ); +public: + void newTerms(SetNode& s); public: /** output eq class */ void outputEqClass( const char* c, Node n ); /** output inverted path string */ - void outputInvertedPathString( const char* c, InvertedPathString& ips ); + void outputIps( const char* c, Ips& ips ); };/* class InstantiatorTheoryUf */ /** equality query object using instantiator theory uf */ diff --git a/src/util/options.cpp b/src/util/options.cpp index e9efab5dd..c2b632b32 100644 --- a/src/util/options.cpp +++ b/src/util/options.cpp @@ -161,6 +161,7 @@ Options::Options() : literalMatchMode(LITERAL_MATCH_NONE), cbqi(false), cbqiSetByUser(false), + rewriteRulesAsAxioms(false), userPatternsQuant(true), flipDecision(false), printInstEngine(false), @@ -294,12 +295,14 @@ Additional CVC4 options:\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\ - --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\ + REWRITERULES:\n\ + --efficient-e-matching use efficient E-matching (only for rewrite rules)\n\ + --rewrite-rules-as-axioms convert rewrite rules into usual axioms (for debugging only)\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\ @@ -642,6 +645,7 @@ enum OptionValue { DISABLE_CBQI, IGNORE_USER_PATTERNS, ENABLE_FLIP_DECISION, + REWRITE_RULES_AS_AXIOMS, PRINT_MODEL_ENGINE, PRINT_INST_ENGINE, PARALLEL_THREADS, @@ -779,6 +783,7 @@ static struct option cmdlineOptions[] = { { "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 }, + { "rewrite-rules-as-axioms", no_argument, NULL, REWRITE_RULES_AS_AXIOMS }, { "print-m-e", no_argument, NULL, PRINT_MODEL_ENGINE }, { "print-i-e", no_argument, NULL, PRINT_INST_ENGINE }, { "threads", required_argument, NULL, PARALLEL_THREADS }, @@ -1379,6 +1384,9 @@ throw(OptionException) { case ENABLE_FLIP_DECISION: flipDecision = true; break; + case REWRITE_RULES_AS_AXIOMS: + rewriteRulesAsAxioms = true; + break; case PRINT_MODEL_ENGINE: printModelEngine = true; break; diff --git a/src/util/options.h b/src/util/options.h index d89265b55..17d393e88 100644 --- a/src/util/options.h +++ b/src/util/options.h @@ -484,6 +484,11 @@ struct CVC4_PUBLIC Options { bool cbqiSetByUser; /** + * Whether to convert rewrite rules to usual axioms (for debugging only) + */ + bool rewriteRulesAsAxioms; + + /** * Whether to use user patterns for pattern-based instantiation */ bool userPatternsQuant; diff --git a/test/regress/regress0/Makefile.am b/test/regress/regress0/Makefile.am index 58788c194..c11d16729 100644 --- a/test/regress/regress0/Makefile.am +++ b/test/regress/regress0/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = . arith precedence uf uflra uflia bv arrays aufbv auflia datatypes quantifiers lemmas push-pop preprocess unconstrained decision +SUBDIRS = . arith precedence uf uflra uflia bv arrays aufbv auflia datatypes quantifiers rewriterules lemmas push-pop preprocess unconstrained decision DIST_SUBDIRS = . arith precedence uf uflra uflia bv arrays aufbv auflia datatypes quantifiers rewriterules lemmas push-pop preprocess unconstrained decision BINARY = cvc4 diff --git a/test/regress/regress0/quantifiers/Makefile.am b/test/regress/regress0/quantifiers/Makefile.am index 97675b111..38cc59125 100644 --- a/test/regress/regress0/quantifiers/Makefile.am +++ b/test/regress/regress0/quantifiers/Makefile.am @@ -50,8 +50,6 @@ TESTS = \ # javafe.ast.StmtVec.009.smt2 \ # javafe.ast.WhileStmt.447.smt2 \ # javafe.tc.CheckCompilationUnit.001.smt2 \ -# AdditiveMethods_AdditiveMethods..ctor.smt2 \ -# AdditiveMethods_OwnedResults.Mz.smt2 \ # javafe.tc.FlowInsensitiveChecks.682.smt2 \ # diff --git a/test/regress/regress0/rewriterules/Makefile.am b/test/regress/regress0/rewriterules/Makefile.am index 94b558675..c0a3fb934 100644 --- a/test/regress/regress0/rewriterules/Makefile.am +++ b/test/regress/regress0/rewriterules/Makefile.am @@ -1,4 +1,8 @@ BINARY = cvc4 + +CVC4_REGRESSION_ARGS ?= --efficient-e-matching +export CVC4_REGRESSION_ARGS + if PROOF_REGRESSIONS TESTS_ENVIRONMENT = LFSC="$(LFSC) $(LFSCARGS)" @srcdir@/../../run_regression $(RUN_REGRESSION_ARGS) --proof @top_builddir@/src/main/$(BINARY) else @@ -13,7 +17,8 @@ MAKEFLAGS = -k TESTS = \ length_trick.smt2 length_trick2.smt2 length_gen_020.smt2 \ datatypes.smt2 datatypes_sat.smt2 set_A_new_fast_tableau-base.smt2 \ - set_A_new_fast_tableau-base_sat.smt2 + set_A_new_fast_tableau-base_sat.smt2 relation.smt2 simulate_rewritting.smt2 \ + reachability_back_to_the_future.smt2 native_arrays.smt2 reachability_bbttf_eT_arrays.smt2 EXTRA_DIST = $(TESTS) diff --git a/test/regress/regress0/rewriterules/datatypes_clark.smt2 b/test/regress/regress0/rewriterules/datatypes_clark.smt2 index eacb5ff6a..f1e61a901 100644 --- a/test/regress/regress0/rewriterules/datatypes_clark.smt2 +++ b/test/regress/regress0/rewriterules/datatypes_clark.smt2 @@ -1,4 +1,4 @@ -(set-logic LRA) +(set-logic AUFLIRA) ;; DATATYPE ;; nat = succ(pred : nat) | zero, @@ -17,16 +17,14 @@ ;; injective (declare-fun inj1 (nat) nat) -(assert (forall ((?x1 nat)) - (! (! (=> true (=> true (= (inj1 (succ ?x1)) ?x1))) :pattern ((succ ?x1)) ) :rewrite-rule) )) - +(assert-propagation((?x1 nat)) + () () (= (inj1 (succ ?x1)) ?x1) (((succ ?x1))) ) ;;;;;;;;;;;;;;;;;;;; ;; projection (declare-fun pred (nat) nat) -(assert (forall ((?x1 nat)) - (! (= (pred (succ ?x1)) ?x1) :rewrite-rule) )) +(assert-rewrite ((?x1 nat)) () (pred (succ ?x1)) ?x1 () ) (assert (= (pred zero) zero)) @@ -34,45 +32,34 @@ ;; test (declare-fun is_succ (nat) Bool) (assert (= (is_succ zero) false)) -(assert (forall ((?x1 nat)) - (! (! (=> true (=> true (= (is_succ (succ ?x1)) true))) :pattern ((succ ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 nat)) () () (= (is_succ (succ ?x1)) true) (((succ ?x1))) ) -(assert (forall ((?x1 nat)) - (! (! (=> true (=> (is_succ ?x1) (= ?x1 (succ (pred ?x1))))) :pattern ((pred ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 nat)) () ((is_succ ?x1)) (= ?x1 (succ (pred ?x1))) (((pred ?x1)))) (declare-fun is_zero (nat) Bool) (assert (= (is_zero zero) true)) -(assert (forall ((?x1 nat)) - (! (=> true (=> (is_zero ?x1) (= ?x1 zero))) :rewrite-rule) )) +(assert-propagation ((?x1 nat)) () ((is_zero ?x1)) (= ?x1 zero) ()) ;;; directrr -(assert (forall ((?x1 nat)) - (! (= (is_succ (succ ?x1)) true) :rewrite-rule))) -(assert (forall ((?x1 nat)) - (! (= (is_zero (succ ?x1)) false) :rewrite-rule))) +(assert-rewrite ((?x1 nat)) () (is_succ (succ ?x1)) true () ) +(assert-rewrite ((?x1 nat)) () (is_zero (succ ?x1)) false () ) ;;;;;;;;;;;;;;;;;;;; ;; distinct -(assert (forall ((?x1 nat)) - (! (=> (is_zero ?x1) (not (is_succ ?x1)) ) :rewrite-rule) )) -(assert (forall ((?x1 nat)) - (! (=> (is_succ ?x1) (not (is_zero ?x1)) ) :rewrite-rule) )) -(assert (forall ((?x1 nat)) - (! (=> (not (is_zero ?x1)) (is_succ ?x1) ) :rewrite-rule) )) -(assert (forall ((?x1 nat)) - (! (=> (not (is_succ ?x1)) (is_zero ?x1) ) :rewrite-rule) )) +(assert-propagation ((?x1 nat)) () ((is_zero ?x1)) (not (is_succ ?x1)) () ) +(assert-propagation ((?x1 nat)) () ((is_succ ?x1)) (not (is_zero ?x1)) () ) +(assert-propagation ((?x1 nat)) () ((not (is_zero ?x1))) (is_succ ?x1) () ) +(assert-propagation ((?x1 nat)) () ((not (is_succ ?x1))) (is_zero ?x1) () ) ;;;;;;;;;;;;;;;;;;; ;; case-split -(assert (forall ((?x1 nat)) - (! (! (=> true (or (is_zero ?x1) (is_succ ?x1))) :pattern ((pred ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 nat)) () () (or (is_zero ?x1) (is_succ ?x1)) (((pred ?x1))) ) ;;;;;;;;;;;;;;;;;;; ;; non-cyclic (declare-fun size_nat (nat) Real) -(assert (forall ((?x1 nat)) - (! (! (=> true (> (size_nat (succ ?x1)) (size_nat ?x1))) :pattern ((succ ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 nat)) () () (> (size_nat (succ ?x1)) (size_nat ?x1)) (((succ ?x1))) ) @@ -96,26 +83,22 @@ ;; injective (declare-fun inj2 (list) tree) -(assert (forall ((?x1 tree) (?x2 list)) - (! (! (=> true (=> true (= (inj2 (cons ?x1 ?x2)) ?x1))) :pattern ((cons ?x1 ?x2)) ) :rewrite-rule) )) +(assert-propagation ((?x1 tree) (?x2 list)) () () (= (inj2 (cons ?x1 ?x2)) ?x1) (((cons ?x1 ?x2))) ) (declare-fun inj3 (list) list) -(assert (forall ((?x1 tree) (?x2 list)) - (! (! (=> true (=> true (= (inj3 (cons ?x1 ?x2)) ?x2))) :pattern ((cons ?x1 ?x2)) ) :rewrite-rule) )) +(assert-propagation ((?x1 tree) (?x2 list)) () () (= (inj3 (cons ?x1 ?x2)) ?x2) (((cons ?x1 ?x2))) ) ;;;;;;;;;;;;;;;;;;;; ;; projection (declare-fun car (list) tree) -(assert (forall ((?x1 tree) (?x2 list)) - (! (= (car (cons ?x1 ?x2)) ?x1) :rewrite-rule) )) +(assert-rewrite ((?x1 tree) (?x2 list)) () (car (cons ?x1 ?x2)) ?x1 ()) (assert (= (car null) (node null))) (declare-fun cdr (list) list) -(assert (forall ((?x1 tree) (?x2 list)) - (! (= (cdr (cons ?x1 ?x2)) ?x2) :rewrite-rule) )) +(assert-rewrite ((?x1 tree) (?x2 list)) () (cdr (cons ?x1 ?x2)) ?x2 ()) (assert (= (cdr null) null)) @@ -123,50 +106,36 @@ ;; test (declare-fun is_cons (list) Bool) (assert (= (is_cons null) false)) -(assert (forall ((?x1 tree) (?x2 list)) - (! (! (=> true (=> true (= (is_cons (cons ?x1 ?x2)) true))) :pattern ((cons ?x1 ?x2)) ) :rewrite-rule) )) +(assert-propagation ((?x1 tree) (?x2 list)) () () (= (is_cons (cons ?x1 ?x2)) true) (((cons ?x1 ?x2))) ) -(assert (forall ((?x1 list)) - (! (! (=> true (=> (is_cons ?x1) (= ?x1 (cons (car ?x1) (cdr ?x1))))) :pattern ((car ?x1)) ) :rewrite-rule) )) -(assert (forall ((?x1 list)) - (! (! (=> true (=> (is_cons ?x1) (= ?x1 (cons (car ?x1) (cdr ?x1))))) :pattern ((cdr ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 list)) () ((is_cons ?x1)) (= ?x1 (cons (car ?x1) (cdr ?x1))) (((car ?x1))) ) +(assert-propagation ((?x1 list)) () ((is_cons ?x1)) (= ?x1 (cons (car ?x1) (cdr ?x1))) (((cdr ?x1))) ) (declare-fun is_null (list) Bool) (assert (= (is_null null) true)) -(assert (forall ((?x1 list)) - (! (! (=> true (=> (is_null ?x1) (= (car ?x1) (node null)))) :pattern ((car ?x1)) ) :rewrite-rule) )) -(assert (forall ((?x1 list)) - (! (! (=> true (=> (is_null ?x1) (= (cdr ?x1) null))) :pattern ((cdr ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 list)) () ((is_null ?x1)) (= (car ?x1) (node null)) (((car ?x1))) ) +(assert-propagation ((?x1 list)) () ((is_null ?x1)) (= (cdr ?x1) null) (((cdr ?x1))) ) -(assert (forall ((?x1 list)) - (! (=> true (=> (is_null ?x1) (= ?x1 null))) :rewrite-rule) )) +(assert-propagation ((?x1 list)) () ((is_null ?x1)) (= ?x1 null) ()) ;;; directrr -(assert (forall ((?x1 tree) (?x2 list)) - (! (= (is_cons (cons ?x1 ?x2)) true) :rewrite-rule) )) -(assert (forall ((?x1 tree) (?x2 list)) - (! (= (is_null (cons ?x1 ?x2)) false) :rewrite-rule) )) +(assert-rewrite ((?x1 tree) (?x2 list)) () (is_cons (cons ?x1 ?x2)) true ()) +(assert-rewrite ((?x1 tree) (?x2 list)) () (is_null (cons ?x1 ?x2)) false ()) ;;;;;;;;;;;;;;;;;;;; ;; distinct -(assert (forall ((?x1 list)) - (! (=> (is_null ?x1) (not (is_cons ?x1)) ) :rewrite-rule) )) -(assert (forall ((?x1 list)) - (! (=> (is_cons ?x1) (not (is_null ?x1)) ) :rewrite-rule) )) -(assert (forall ((?x1 list)) - (! (=> (not (is_null ?x1)) (is_cons ?x1) ) :rewrite-rule) )) -(assert (forall ((?x1 list)) - (! (=> (not (is_cons ?x1)) (is_null ?x1) ) :rewrite-rule) )) +(assert-propagation ((?x1 list)) () ((is_null ?x1)) (not (is_cons ?x1)) () ) +(assert-propagation ((?x1 list)) () ((is_cons ?x1)) (not (is_null ?x1)) () ) +(assert-propagation ((?x1 list)) () ((not (is_null ?x1))) (is_cons ?x1) () ) +(assert-propagation ((?x1 list)) () ((not (is_cons ?x1))) (is_null ?x1) () ) ;;;;;;;;;;;;;;;;;;; ;; case-split -(assert (forall ((?x1 list)) - (! (! (=> true (or (is_null ?x1) (is_cons ?x1))) :pattern ((car ?x1)) ) :rewrite-rule) )) -(assert (forall ((?x1 list)) - (! (! (=> true (or (is_null ?x1) (is_cons ?x1))) :pattern ((cdr ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 list)) () () (or (is_null ?x1) (is_cons ?x1)) (((car ?x1))) ) +(assert-propagation ((?x1 list)) () () (or (is_null ?x1) (is_cons ?x1)) (((cdr ?x1))) ) ;;;;;;;;;;;;;;; ;; tree @@ -175,90 +144,61 @@ ;; injective (declare-fun inj4 (tree) list) -(assert (forall ((?x1 list)) - (! (! (=> true (=> true (= (inj4 (node ?x1)) ?x1))) :pattern ((node ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 list)) () () (= (inj4 (node ?x1)) ?x1) (((node ?x1))) ) (declare-fun inj5 (tree) nat) -(assert (forall ((?x1 nat)) - (! (! (=> true (=> true (= (inj5 (leaf ?x1)) ?x1))) :pattern ((leaf ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 nat)) () () (= (inj5 (leaf ?x1)) ?x1) (((leaf ?x1))) ) ;;;;;;;;;;;;;;;;;;;; ;; projection (declare-fun children (tree) list) -(assert (forall ((?x1 list)) - (! (= (children (node ?x1)) ?x1) :rewrite-rule) )) -(assert (forall ((?x1 nat)) - (! (= (children (leaf ?x1)) null) :rewrite-rule) )) - +(assert-rewrite ((?x1 list)) () (children (node ?x1)) ?x1 () ) +(assert-rewrite ((?x1 nat)) () (children (leaf ?x1)) null () ) (declare-fun data (tree) nat) -(assert (forall ((?x1 nat)) - (! (= (data (leaf ?x1)) ?x1) :rewrite-rule) )) -(assert (forall ((?x1 list)) - (! (= (data (node ?x1)) zero) :rewrite-rule) )) +(assert-rewrite ((?x1 nat)) () (data (leaf ?x1)) ?x1 () ) +(assert-rewrite ((?x1 list)) () (data (node ?x1)) zero () ) ;;;;;;;;;;;;;;;;;;; ;; test (declare-fun is_node (tree) Bool) -(assert (forall ((?x1 list)) - (! (! (=> true (=> true (= (is_node (node ?x1)) true))) :pattern ((node ?x1)) ) :rewrite-rule) )) - -(assert (forall ((?x1 tree)) - (! (! (=> true (=> (is_node ?x1) (= ?x1 (node (children ?x1))))) :pattern ((children ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 list)) () () (= (is_node (node ?x1)) true) (((node ?x1))) ) -(assert (forall ((?x1 tree)) - (! (! (=> true (=> (is_node ?x1) (= (data ?x1) zero))) :pattern ((data ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 tree)) () ((is_node ?x1)) (= ?x1 (node (children ?x1))) (((children ?x1))) ) +(assert-propagation ((?x1 tree)) () ((is_node ?x1)) (= (data ?x1) zero) (((data ?x1))) ) (declare-fun is_leaf (tree) Bool) -(assert (forall ((?x1 nat)) - (! (! (=> true (=> true (= (is_leaf (leaf ?x1)) true))) :pattern ((leaf ?x1)) ) :rewrite-rule) )) - -(assert (forall ((?x1 tree)) - (! (! (=> true (=> (is_leaf ?x1) (= ?x1 (leaf (data ?x1))))) :pattern ((data ?x1)) ) :rewrite-rule) )) -(assert (forall ((?x1 tree)) - (! (! (=> true (=> (is_leaf ?x1) (= (children ?x1) null))) :pattern ((children ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 nat)) () () (= (is_leaf (leaf ?x1)) true) (((leaf ?x1))) ) +(assert-propagation ((?x1 tree)) () ((is_leaf ?x1)) (= ?x1 (leaf (data ?x1))) (((data ?x1))) ) +(assert-propagation ((?x1 tree)) () ((is_leaf ?x1)) (= (children ?x1) null) (((children ?x1))) ) ;;; directrr -(assert (forall ((?x1 list)) - (! (= (is_node (node ?x1)) true) :rewrite-rule) )) -(assert (forall ((?x1 list)) - (! (= (is_leaf (node ?x1)) false) :rewrite-rule) )) -(assert (forall ((?x1 nat)) - (! (= (is_leaf (leaf ?x1)) true) :rewrite-rule) )) -(assert (forall ((?x1 nat)) - (! (= (is_node (leaf ?x1)) false) :rewrite-rule) )) +(assert-rewrite ((?x1 list)) () (is_node (node ?x1)) true () ) +(assert-rewrite ((?x1 list)) () (is_leaf (node ?x1)) false () ) +(assert-rewrite ((?x1 nat)) () (is_leaf (leaf ?x1)) true () ) +(assert-rewrite ((?x1 nat)) () (is_node (leaf ?x1)) false () ) ;;;;;;;;;;;;;;;;;;;; ;; distinct -(assert (forall ((?x1 tree)) - (! (=> (is_node ?x1) (not (is_leaf ?x1)) ) :rewrite-rule) )) -(assert (forall ((?x1 tree)) - (! (=> (is_leaf ?x1) (not (is_node ?x1)) ) :rewrite-rule) )) -(assert (forall ((?x1 tree)) - (! (=> (not (is_node ?x1)) (is_leaf ?x1) ) :rewrite-rule) )) -(assert (forall ((?x1 tree)) - (! (=> (not (is_leaf ?x1)) (is_node ?x1) ) :rewrite-rule) )) +(assert-propagation ((?x1 tree)) () ((is_node ?x1)) (not (is_leaf ?x1)) () ) +(assert-propagation ((?x1 tree)) () ((is_leaf ?x1)) (not (is_node ?x1)) () ) +(assert-propagation ((?x1 tree)) () ((not (is_node ?x1))) (is_leaf ?x1) () ) +(assert-propagation ((?x1 tree)) () ((not (is_leaf ?x1))) (is_node ?x1) () ) ;;;;;;;;;;;;;;;;;;; ;; case-split -(assert (forall ((?x1 tree)) - (! (! (=> true (or (is_node ?x1) (is_leaf ?x1))) :pattern ((children ?x1)) ) :rewrite-rule) )) - -(assert (forall ((?x1 tree)) - (! (! (=> true (or (is_node ?x1) (is_leaf ?x1))) :pattern ((data ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 tree)) () () (or (is_node ?x1) (is_leaf ?x1)) (((children ?x1))) ) +(assert-propagation ((?x1 tree)) () () (or (is_node ?x1) (is_leaf ?x1)) (((data ?x1))) ) ;;;;;;;;;;;;;;;;;; ;; non-cyclic (declare-fun size_list (list) Real) (declare-fun size_tree (tree) Real) -(assert (forall ((?x1 tree) (?x2 list)) - (! (! (=> true (and (> (size_list (cons ?x1 ?x2)) (size_tree ?x1)) (> (size_list (cons ?x1 ?x2)) (size_list ?x2)))) :pattern ((cons ?x1 ?x2)) ) :rewrite-rule) )) -(assert (forall ((?x1 list)) - (! (! (=> true (> (size_tree (node ?x1)) (size_list ?x1))) :pattern ((node ?x1)) ) :rewrite-rule) )) -(assert (forall ((?x1 nat)) - (! (! (=> true (> (size_tree (leaf ?x1)) (size_nat ?x1))) :pattern ((leaf ?x1)) ) :rewrite-rule) )) +(assert-propagation ((?x1 tree) (?x2 list)) () () (and (> (size_list (cons ?x1 ?x2)) (size_tree ?x1)) (> (size_list (cons ?x1 ?x2)) (size_list ?x2))) (((cons ?x1 ?x2))) ) +(assert-propagation ((?x1 list)) () () (> (size_tree (node ?x1)) (size_list ?x1)) (((node ?x1))) ) +(assert-propagation ((?x1 nat)) () () (> (size_tree (leaf ?x1)) (size_nat ?x1)) (((leaf ?x1))) ) diff --git a/test/regress/regress0/rewriterules/datatypes_clark_quantification.smt2 b/test/regress/regress0/rewriterules/datatypes_clark_quantification.smt2 new file mode 100644 index 000000000..6e22816d7 --- /dev/null +++ b/test/regress/regress0/rewriterules/datatypes_clark_quantification.smt2 @@ -0,0 +1,264 @@ +(set-logic AUFLIRA) + +;; DATATYPE +;; nat = succ(pred : nat) | zero, +;; list = cons(car : tree, cdr : list) | null, +;; tree = node(children : list) | leaf(data : nat) +;; END; + +;;;;;;;;;;; +;; nat ;; +;;;;;;;;;;; +(declare-sort nat 0) +(declare-fun zero () nat) +(declare-fun succ (nat) nat) + +;;;;;;;;;;;;;;;; +;; injective + +(declare-fun inj1 (nat) nat) +(assert (forall ((?x1 nat)) + (! (= (inj1 (succ ?x1)) ?x1) :pattern ((succ ?x1)) ) )) + + +;;;;;;;;;;;;;;;;;;;; +;; projection + +(declare-fun pred (nat) nat) +(assert (forall ((?x1 nat)) + (! (= (pred (succ ?x1)) ?x1) :pattern ((pred (succ ?x1))) ) )) + +(assert (= (pred zero) zero)) + +;;;;;;;;;;;;;;;;;;; +;; test +(declare-fun is_succ (nat) Bool) +(assert (= (is_succ zero) false)) +(assert (forall ((?x1 nat)) + (! (= (is_succ (succ ?x1)) true) :pattern ((succ ?x1)) ) )) + +(assert (forall ((?x1 nat)) + (! (=> (is_succ ?x1) (= ?x1 (succ (pred ?x1)))) :pattern ((is_succ ?x1) (pred ?x1)) ) )) + +(declare-fun is_zero (nat) Bool) +(assert (= (is_zero zero) true)) +(assert (forall ((?x1 nat)) + (! (=> (is_zero ?x1) (= ?x1 zero)) :pattern ((is_zero ?x1)) ) )) + +;;; directrr +(assert (forall ((?x1 nat)) + (! (= (is_succ (succ ?x1)) true) :pattern ((is_succ (succ ?x1))) ) )) +(assert (forall ((?x1 nat)) + (! (= (is_zero (succ ?x1)) false) :pattern ((is_zero (succ ?x1))) ))) + + +;;;;;;;;;;;;;;;;;;;; +;; distinct +(assert (forall ((?x1 nat)) + (! (=> (is_zero ?x1) (not (is_succ ?x1)) ) :pattern ((is_zero ?x1)) ) )) +(assert (forall ((?x1 nat)) + (! (=> (is_succ ?x1) (not (is_zero ?x1)) ) :pattern ((is_succ ?x1)) ) )) +(assert (forall ((?x1 nat)) + (! (=> (not (is_zero ?x1)) (is_succ ?x1) ) :pattern ((is_zero ?x1)) ) )) +(assert (forall ((?x1 nat)) + (! (=> (not (is_succ ?x1)) (is_zero ?x1) ) :pattern ((is_succ ?x1)) ) )) + +;;;;;;;;;;;;;;;;;;; +;; case-split +(assert (forall ((?x1 nat)) + (! (or (is_zero ?x1) (is_succ ?x1)) :pattern ((pred ?x1)) ) )) + +;;;;;;;;;;;;;;;;;;; +;; non-cyclic +(declare-fun size_nat (nat) Real) +(assert (forall ((?x1 nat)) + (! (> (size_nat (succ ?x1)) (size_nat ?x1)) :pattern ((succ ?x1)) ) )) + + + +;;;;;;;;;;;;;;;;;;;;; +;; list and tree + +(declare-sort list 0) +(declare-sort tree 0) + +;;;;;;;;;;; +;; list ;; +;;;;;;;;;;; + +(declare-fun null () list) +(declare-fun cons (tree list) list) + +(declare-fun node (list) tree) +(declare-fun leaf (nat) tree) + +;;;;;;;;;;;;;;;; +;; injective + +(declare-fun inj2 (list) tree) +(assert (forall ((?x1 tree) (?x2 list)) + (! (= (inj2 (cons ?x1 ?x2)) ?x1) :pattern ((cons ?x1 ?x2)) ) )) + +(declare-fun inj3 (list) list) +(assert (forall ((?x1 tree) (?x2 list)) + (! (= (inj3 (cons ?x1 ?x2)) ?x2) :pattern ((cons ?x1 ?x2)) ) )) + + +;;;;;;;;;;;;;;;;;;;; +;; projection + +(declare-fun car (list) tree) +(assert (forall ((?x1 tree) (?x2 list)) + (! (= (car (cons ?x1 ?x2)) ?x1) :pattern ((car (cons ?x1 ?x2))) ) )) + +(assert (= (car null) (node null))) + +(declare-fun cdr (list) list) +(assert (forall ((?x1 tree) (?x2 list)) + (! (= (cdr (cons ?x1 ?x2)) ?x2) :pattern ((cdr (cons ?x1 ?x2))) ) )) + +(assert (= (cdr null) null)) + +;;;;;;;;;;;;;;;;;;; +;; test +(declare-fun is_cons (list) Bool) +(assert (= (is_cons null) false)) +(assert (forall ((?x1 tree) (?x2 list)) + (! (= (is_cons (cons ?x1 ?x2)) true) :pattern ((cons ?x1 ?x2)) ) )) + +(assert (forall ((?x1 list)) + (! (=> (is_cons ?x1) (= ?x1 (cons (car ?x1) (cdr ?x1)))) :pattern ((is_cons ?x1)(car ?x1)) ) )) +(assert (forall ((?x1 list)) + (! (=> (is_cons ?x1) (= ?x1 (cons (car ?x1) (cdr ?x1)))) :pattern ((is_cons ?x1)(cdr ?x1)) ) )) + +(declare-fun is_null (list) Bool) +(assert (= (is_null null) true)) + +(assert (forall ((?x1 list)) + (! (=> (is_null ?x1) (= (car ?x1) (node null))) :pattern ((is_null ?x1)(car ?x1)) ) )) +(assert (forall ((?x1 list)) + (! (=> (is_null ?x1) (= (cdr ?x1) null)) :pattern ((is_null ?x1)(cdr ?x1)) ) )) + +(assert (forall ((?x1 list)) + (! (=> (is_null ?x1) (= ?x1 null)) :pattern ((is_null ?x1)) ) )) + +;;; directrr +(assert (forall ((?x1 tree) (?x2 list)) + (! (= (is_cons (cons ?x1 ?x2)) true) :pattern ((is_cons (cons ?x1 ?x2))) ) )) +(assert (forall ((?x1 tree) (?x2 list)) + (! (= (is_null (cons ?x1 ?x2)) false) :pattern ((is_null (cons ?x1 ?x2))) ) )) + + + +;;;;;;;;;;;;;;;;;;;; +;; distinct +(assert (forall ((?x1 list)) + (! (=> (is_null ?x1) (not (is_cons ?x1)) ) :pattern ((is_null ?x1)) ) )) +(assert (forall ((?x1 list)) + (! (=> (is_cons ?x1) (not (is_null ?x1)) ) :pattern ((is_cons ?x1)) ) )) +(assert (forall ((?x1 list)) + (! (=> (not (is_null ?x1)) (is_cons ?x1) ) :pattern ((is_null ?x1)) ) )) +(assert (forall ((?x1 list)) + (! (=> (not (is_cons ?x1)) (is_null ?x1) ) :pattern ((is_cons ?x1)) ) )) + +;;;;;;;;;;;;;;;;;;; +;; case-split +(assert (forall ((?x1 list)) + (! (or (is_null ?x1) (is_cons ?x1)) :pattern ((car ?x1)) ) )) +(assert (forall ((?x1 list)) + (! (or (is_null ?x1) (is_cons ?x1)) :pattern ((cdr ?x1)) ) )) + +;;;;;;;;;;;;;;; +;; tree + +;;;;;;;;;;;;;;;; +;; injective + +(declare-fun inj4 (tree) list) +(assert (forall ((?x1 list)) + (! (= (inj4 (node ?x1)) ?x1) :pattern ((node ?x1)) ) )) + +(declare-fun inj5 (tree) nat) +(assert (forall ((?x1 nat)) + (! (= (inj5 (leaf ?x1)) ?x1) :pattern ((leaf ?x1)) ) )) + + +;;;;;;;;;;;;;;;;;;;; +;; projection + +(declare-fun children (tree) list) +(assert (forall ((?x1 list)) + (! (= (children (node ?x1)) ?x1) :pattern ((children (node ?x1))) ) )) +(assert (forall ((?x1 nat)) + (! (= (children (leaf ?x1)) null) :pattern ((children (leaf ?x1))) ) )) + + +(declare-fun data (tree) nat) +(assert (forall ((?x1 nat)) + (! (= (data (leaf ?x1)) ?x1) :pattern ((data (leaf ?x1))) ) )) +(assert (forall ((?x1 list)) + (! (= (data (node ?x1)) zero) :pattern ((data (node ?x1))) ) )) + +;;;;;;;;;;;;;;;;;;; +;; test +(declare-fun is_node (tree) Bool) +(assert (forall ((?x1 list)) + (! (= (is_node (node ?x1)) true) :pattern ((node ?x1)) ) )) + +(assert (forall ((?x1 tree)) + (! (=> (is_node ?x1) (= ?x1 (node (children ?x1)))) :pattern ((is_node ?x1)(children ?x1)) ) )) + +(assert (forall ((?x1 tree)) + (! (=> (is_node ?x1) (= (data ?x1) zero)) :pattern ((is_node ?x1)(data ?x1)) ) )) + + +(declare-fun is_leaf (tree) Bool) +(assert (forall ((?x1 nat)) + (! (=> true (= (is_leaf (leaf ?x1)) true)) :pattern ((leaf ?x1)) ) )) + +(assert (forall ((?x1 tree)) + (! (=> (is_leaf ?x1) (= ?x1 (leaf (data ?x1)))) :pattern ((is_leaf ?x1)(data ?x1)) ) )) +(assert (forall ((?x1 tree)) + (! (=> (is_leaf ?x1) (= (children ?x1) null)) :pattern ((is_leaf ?x1)(children ?x1)) ) )) + +;;; directrr +(assert (forall ((?x1 list)) + (! (= (is_node (node ?x1)) true) :pattern ((is_node (node ?x1))) ) )) +(assert (forall ((?x1 list)) + (! (= (is_leaf (node ?x1)) false) :pattern ((is_leaf (node ?x1))) ) )) +(assert (forall ((?x1 nat)) + (! (= (is_leaf (leaf ?x1)) true) :pattern (is_leaf (leaf ?x1)) ) )) +(assert (forall ((?x1 nat)) + (! (= (is_node (leaf ?x1)) false) :pattern ((is_node (leaf ?x1))) ) )) + + +;;;;;;;;;;;;;;;;;;;; +;; distinct +(assert (forall ((?x1 tree)) + (! (=> (is_node ?x1) (not (is_leaf ?x1)) ) :pattern ((is_node ?x1)) ) )) +(assert (forall ((?x1 tree)) + (! (=> (is_leaf ?x1) (not (is_node ?x1)) ) :pattern ((is_leaf ?x1)) ) )) +(assert (forall ((?x1 tree)) + (! (=> (not (is_node ?x1)) (is_leaf ?x1) ) :pattern ((is_node ?x1)) ) )) +(assert (forall ((?x1 tree)) + (! (=> (not (is_leaf ?x1)) (is_node ?x1) ) :pattern ((is_leaf ?x1)) ) )) + +;;;;;;;;;;;;;;;;;;; +;; case-split +(assert (forall ((?x1 tree)) + (! (or (is_node ?x1) (is_leaf ?x1)) :pattern ((children ?x1)) ) )) + +(assert (forall ((?x1 tree)) + (! (or (is_node ?x1) (is_leaf ?x1)) :pattern ((data ?x1)) ) )) + + +;;;;;;;;;;;;;;;;;; +;; non-cyclic +(declare-fun size_list (list) Real) +(declare-fun size_tree (tree) Real) +(assert (forall ((?x1 tree) (?x2 list)) + (! (and (> (size_list (cons ?x1 ?x2)) (size_tree ?x1)) (> (size_list (cons ?x1 ?x2)) (size_list ?x2))) :pattern ((cons ?x1 ?x2)) ) )) +(assert (forall ((?x1 list)) + (! (> (size_tree (node ?x1)) (size_list ?x1)) :pattern ((node ?x1)) ) )) +(assert (forall ((?x1 nat)) + (! (> (size_tree (leaf ?x1)) (size_nat ?x1)) :pattern ((leaf ?x1)) ) )) diff --git a/test/regress/regress0/rewriterules/length_gen_010.smt2 b/test/regress/regress0/rewriterules/length_gen_010.smt2 index 7c7663b17..41cc61c9e 100644 --- a/test/regress/regress0/rewriterules/length_gen_010.smt2 +++ b/test/regress/regress0/rewriterules/length_gen_010.smt2 @@ -16,14 +16,16 @@ (assert (= (length nil) 0)) -(assert (forall ((?e Int) (?l list)) (! (= (length (cons ?e ?l)) (+ 1 (length ?l))) :rewrite-rule))) +;; (assert (forall ((?e Int) (?l list)) (! (= (length (cons ?e ?l)) (+ 1 (length ?l))) :rewrite-rule))) + +(assert-rewrite ((?e Int) (?l list)) () (length (cons ?e ?l)) (+ 1 (length ?l)) ()) (declare-fun gen_cons (Int list) list) -(assert (forall ((?n Int) (?l list)) (! (=> (= ?n 0) (= (gen_cons ?n ?l) ?l)) :rewrite-rule))) +(assert-rewrite ((?n Int) (?l list)) (= ?n 0) (gen_cons ?n ?l) (?l) ()) -(assert (forall ((?n Int) (?l list)) (! (=> (> ?n 0) (= (gen_cons ?n ?l) - (gen_cons (- ?n 1) (cons 1 ?l)))) :rewrite-rule))) +(assert-rewrite ((?n Int) (?l list)) (> ?n 0) (gen_cons ?n ?l) + (gen_cons (- ?n 1) (cons 1 ?l)) ()) (declare-fun n () Int) diff --git a/test/regress/regress0/rewriterules/native_arrays.smt2 b/test/regress/regress0/rewriterules/native_arrays.smt2 new file mode 100644 index 000000000..1be13167d --- /dev/null +++ b/test/regress/regress0/rewriterules/native_arrays.smt2 @@ -0,0 +1,34 @@ +;; This example can't be done if we don't access the EqualityEngine of +;; the theory of arrays + +(set-logic AUFLIA) +(set-info :status unsat) + +(declare-sort Index 0) +(declare-sort Element 0) + +;;A dumb predicate for a simple example +(declare-fun P (Element) Bool) + +(assert-rewrite ((?i1 Index) (?i2 Index) (?e Element) (?a (Array Index Element))) () + (P (select (store ?a ?i1 ?e) ?i2)) true () ) + +(declare-fun a1 () (Array Index Element)) +(declare-fun a2 () (Array Index Element)) +(declare-fun a3 () (Array Index Element)) +(declare-fun i1 () Index) +(declare-fun i2 () Index) +(declare-fun e1 () Element) + +(assert (not (=> (or (= a1 (store a2 i1 e1)) (= a1 (store a3 i1 e1))) (P (select a1 i2)) ))) +(check-sat) +(exit) + + +;; (declare-fun a1 () (Array Index Element)) +;; (declare-fun a2 () (Array Index Element)) +;; (declare-fun i1 () Index) +;; (assert (= (store a1 i1 (select a2 i1)) (store a2 i1 (select a1 i1)))) +;; (assert (not (= a1 a2))) +;; (check-sat) +;; (exit) diff --git a/test/regress/regress0/rewriterules/native_datatypes.smt2 b/test/regress/regress0/rewriterules/native_datatypes.smt2 new file mode 100644 index 000000000..f5d53e3d5 --- /dev/null +++ b/test/regress/regress0/rewriterules/native_datatypes.smt2 @@ -0,0 +1,33 @@ +;; Same than length.smt2 but the nil case is not a rewrite rule +;; So here the rewrite rules have no guards length + +(set-info :status unsat) + +(declare-datatypes ( +(nat (succ (pred nat)) (zero ) ) +(list (cons (car nat)(cdr list)) (nil ) ) + +)) + + +;;define length +(declare-fun length (list) nat) + +(assert (= (length nil) zero)) + +(assert (forall ((?e nat) (?l list)) (! (= (length (cons ?e ?l)) (succ (length ?l))) :rewrite-rule))) + +(declare-fun gen_cons (nat list) list) + +(assert (forall ((?l list)) (! (= (gen_cons zero ?l) ?l) :rewrite-rule))) + +(assert (forall ((?n nat) (?l list)) (! (= (gen_cons (succ ?n) ?l) + (gen_cons ?n (cons zero ?l))) :rewrite-rule))) + +(declare-fun n () nat) + +(assert (not (= (length (gen_cons (succ (succ zero)) nil)) (succ (succ zero))))) + +(check-sat) + +(exit) diff --git a/test/regress/regress0/rewriterules/native_datatypes2.smt2 b/test/regress/regress0/rewriterules/native_datatypes2.smt2 new file mode 100644 index 000000000..4a719fb85 --- /dev/null +++ b/test/regress/regress0/rewriterules/native_datatypes2.smt2 @@ -0,0 +1,35 @@ +;; Same than length.smt2 but the nil case is not a rewrite rule +;; So here the rewrite rules have no guards length + +(set-info :status unsat) + +(declare-datatypes ( +(nat (succ (pred nat)) (zero ) ) +(list (cons (car nat)(cdr list)) (nil ) ) + +)) + + +;;define length +(declare-fun length (list) nat) + +(assert (= (length nil) zero)) + +(assert-rewrite ((?e nat) (?l list)) () (length (cons ?e ?l)) (succ (length ?l)) () ) +(assert-propagation ((?l list)) ((= (length ?l) zero)) () (= ?l nil) (((length ?l))) ) +;(assert-propagation ((?l list)) () () (= ?l nil) (((= (length ?l) 0))) ) + +(declare-fun gen_cons (nat list) list) + +(assert-rewrite ((?l list)) () (gen_cons zero ?l) ?l () ) + +(assert-rewrite ((?n nat) (?l list)) () (gen_cons (succ ?n) ?l) (gen_cons ?n (cons zero ?l)) () ) + +(declare-fun l1 () list) +(declare-fun l2 () list) + +(assert (not (=> (= (length l1) zero) (= l1 nil)))) + +(check-sat) + +(exit) diff --git a/test/regress/regress0/rewriterules/reachability_back_to_the_future.smt2 b/test/regress/regress0/rewriterules/reachability_back_to_the_future.smt2 new file mode 100644 index 000000000..7cd61738b --- /dev/null +++ b/test/regress/regress0/rewriterules/reachability_back_to_the_future.smt2 @@ -0,0 +1,54 @@ +;; Back to the Future ... Shuvendu K.Lhiri, Shaz Qadeer +(set-logic AUFLIA) +(set-info :status unsat) + +(declare-sort elt 0) + +(declare-fun f (elt) elt) +(declare-fun Rf (elt elt elt) Bool) + +;;eq +(assert-propagation ((?x elt)) () () (or (= ?x ?x) (not (= ?x ?x))) ((?x)) ) +;; reflexive +(assert-propagation ((?x elt)) () () (Rf ?x ?x ?x) ((?x)) ) +;; step +(assert-propagation ((?x elt)) () () (Rf ?x (f ?x) (f ?x)) (((f ?x))) ) +;; reach +(assert-propagation ((?x1 elt)(?x2 elt)) () ((Rf ?x1 ?x2 ?x2)) (or (= ?x1 ?x2) (Rf ?x1 (f ?x1) ?x2)) (((f ?x1))) ) +;; cycle +(assert-propagation ((?x1 elt)(?x2 elt)) ((= (f ?x1) ?x1)) ((Rf ?x1 ?x2 ?x2)) (= ?x1 ?x2) (((f ?x1))) ) +;; sandwich +(assert-propagation ((?x1 elt)(?x2 elt)) () ((Rf ?x1 ?x2 ?x1)) (= ?x1 ?x2) () ) +;; order1 +(assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)) + (or (Rf ?x1 ?x2 ?x3) (Rf ?x1 ?x3 ?x2)) () ) +;; order2 +(assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x1 ?x2 ?x3)) + (and (Rf ?x1 ?x2 ?x2) (Rf ?x2 ?x3 ?x3)) () ) +;; transitive1 +(assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x1 ?x2 ?x2)(Rf ?x2 ?x3 ?x3)) + (Rf ?x1 ?x3 ?x3) () ) +;; transitive2 +(assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x0 ?x1 ?x2)(Rf ?x1 ?x3 ?x2)) + (and (Rf ?x0 ?x1 ?x3) (Rf ?x0 ?x3 ?x2)) () ) +;;transitive3 +(assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x0 ?x1 ?x2)(Rf ?x0 ?x3 ?x1)) + (and (Rf ?x0 ?x3 ?x2) (Rf ?x3 ?x1 ?x2)) () ) + +(declare-fun e1 () elt) +(declare-fun e2 () elt) +(declare-fun e3 () elt) +(declare-fun e4 () elt) + + +;; (assert (=> (Rf e1 e2 e3) (Rf e1 (f e1) (f e1)) )) + +;; (assert (=> (Rf e1 e2 e3) (Rf e1 e3 e3) )) + +;; (assert (=> (Rf e1 e2 e3) (or (= e1 e3) (Rf e1 (f e1) e3)) )) + +(assert (not (=> (and (not (= e1 e2)) (Rf e1 e2 e3)) (Rf e1 (f e1) e3) ))) + + +(check-sat) +(exit) \ No newline at end of file diff --git a/test/regress/regress0/rewriterules/reachability_back_to_the_future_extended.smt2 b/test/regress/regress0/rewriterules/reachability_back_to_the_future_extended.smt2 new file mode 100644 index 000000000..955c810aa --- /dev/null +++ b/test/regress/regress0/rewriterules/reachability_back_to_the_future_extended.smt2 @@ -0,0 +1,72 @@ +;; Back to the Future ... Shuvendu K.Lhiri, Shaz Qadeer +(set-logic AUFLIA) +(set-info :status unsat) + +(declare-sort elt 0) + +(declare-fun f (elt) elt) +(declare-fun Rf (elt elt elt) Bool) + +;;eq +(assert-propagation ((?x elt)) () () (or (= ?x ?x) (not (= ?x ?x))) ((?x)) ) +;; reflexive +(assert-propagation ((?x elt)) () () (Rf ?x ?x ?x) ((?x)) ) +;; step +(assert-propagation ((?x elt)) () () (Rf ?x (f ?x) (f ?x)) (((f ?x))) ) + +;; reach +(assert-propagation ((?x1 elt)(?x2 elt)) () ((Rf ?x1 ?x2 ?x2)) (or (= ?x1 ?x2) (Rf ?x1 (f ?x1) ?x2)) (((f ?x1))) ) +;; reach extended +(assert-propagation ((?x1 elt)(?x2 elt)) ((not (= ?x1 ?x2))(Rf ?x1 ?x2 ?x2)) () (Rf ?x1 (f ?x1) ?x2) (((Rf ?x1 (f ?x1) ?x2))) ) +;; reach extended +(assert-propagation ((?x1 elt)(?x2 elt)) ((not (Rf ?x1 (f ?x1) ?x2))(Rf ?x1 ?x2 ?x2)) () (= ?x1 ?x2) (((Rf ?x1 (f ?x1) ?x2))) ) + +;; cycle +(assert-propagation ((?x1 elt)(?x2 elt)) ((= (f ?x1) ?x1)) ((Rf ?x1 ?x2 ?x2)) (= ?x1 ?x2) (((f ?x1))) ) +;; sandwich +(assert-propagation ((?x1 elt)(?x2 elt)) () ((Rf ?x1 ?x2 ?x1)) (= ?x1 ?x2) () ) +;; order1 +(assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)) + (or (Rf ?x1 ?x2 ?x3) (Rf ?x1 ?x3 ?x2)) () ) +;; order1 extended +(assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x3 ?x2))) () + (Rf ?x1 ?x2 ?x3) (((Rf ?x1 ?x2 ?x3))) ) +;; order1 extended +(assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x2 ?x3))) () + (Rf ?x1 ?x3 ?x2) (((Rf ?x1 ?x3 ?x2))) ) + +;; order2 +(assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x1 ?x2 ?x3)) + (and (Rf ?x1 ?x2 ?x2) (Rf ?x2 ?x3 ?x3)) () ) +;; transitive1 +(assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x1 ?x2 ?x2)(Rf ?x2 ?x3 ?x3)) + (Rf ?x1 ?x3 ?x3) () ) +;; transitive2 +(assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x0 ?x1 ?x2)(Rf ?x1 ?x3 ?x2)) + (and (Rf ?x0 ?x1 ?x3) (Rf ?x0 ?x3 ?x2)) () ) +;;transitive3 +(assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x0 ?x1 ?x2)(Rf ?x0 ?x3 ?x1)) + (and (Rf ?x0 ?x3 ?x2) (Rf ?x3 ?x1 ?x2)) () ) + +(declare-fun e1 () elt) +(declare-fun e2 () elt) +(declare-fun e3 () elt) +(declare-fun e4 () elt) + + +(assert (and (hack e1) (hack e2) (hack e3) (hack e4) (hack (f e1)))) + + +;; (assert (=> (Rf e1 e2 e3) (Rf e1 (f e1) (f e1)) )) + +;; (assert (=> (Rf e1 e2 e3) (Rf e1 e3 e3) )) + +;; (assert (=> (Rf e1 e2 e3) (or (= e1 e3) (Rf e1 (f e1) e3)) )) + +;;(assert (not (=> (and (not (= e1 e2)) (Rf e1 e2 e3)) (Rf e1 (f e1) e3) ))) + +(assert (and (not (= e1 e2)) (Rf e1 e2 e3) (not (Rf e1 (f e1) e3)) )) + + +(check-sat) +(exit) \ No newline at end of file diff --git a/test/regress/regress0/rewriterules/reachability_bbttf_eT_arrays.smt2 b/test/regress/regress0/rewriterules/reachability_bbttf_eT_arrays.smt2 new file mode 100644 index 000000000..b7069536a --- /dev/null +++ b/test/regress/regress0/rewriterules/reachability_bbttf_eT_arrays.smt2 @@ -0,0 +1,332 @@ +;; Back to the Future ... Shuvendu K.Lhiri, Shaz Qadeer +(set-logic AUFLIA) +(set-info :status unsat) + +(declare-sort elt 0) +(define-sort mem () (Array elt elt)) + +(declare-fun R (mem elt elt elt) Bool) + +;; reflexive +(assert-propagation ((?m mem)(?x elt)) () () (R ?m ?x ?x ?x) ((?m ?x)) ) +;; step +(assert-propagation ((?m mem)(?x elt)) () () (R ?m ?x (select ?m ?x) (select ?m ?x)) (((select ?m ?x))) ) +;; (assert-propagation ((?x elt)) () () (Rf ?x (f ?x) (f ?x)) (((Rf ?x (f ?x) (f ?x)))) ) +;; (assert-propagation ((?x elt)) () () (=> true (Rf ?x (f ?x) (f ?x))) (((f ?x))) ) + +;; reach +(assert-propagation ((?m mem)(?x1 elt)(?x2 elt)) () ((R ?m ?x1 ?x2 ?x2)) (or (= ?x1 ?x2) (R ?m ?x1 (select ?m ?x1) ?x2)) (((select ?m ?x1))) ) +;; ;; reach extended +;; (assert-propagation ((?x1 elt)(?x2 elt)) ((not (= ?x1 ?x2))(Rf ?x1 ?x2 ?x2)) () (Rf ?x1 (f ?x1) ?x2) (((Rf ?x1 (f ?x1) ?x2))) ) +;; ;; reach extended +;; (assert-propagation ((?x1 elt)(?x2 elt)) ((not (Rf ?x1 (f ?x1) ?x2))(Rf ?x1 ?x2 ?x2)) () (= ?x1 ?x2) (((Rf ?x1 (f ?x1) ?x2))) ) + +;; cycle +(assert-propagation ((?m mem)(?x1 elt)(?x2 elt)) ((= (select ?m ?x1) ?x1)) ((R ?m ?x1 ?x2 ?x2)) (= ?x1 ?x2) (((select ?m ?x1))) ) +;; (assert-propagation ((?x1 elt)(?x2 elt)) ((= (f ?x1) ?x1)) ((Rf ?x1 ?x2 ?x2)) (= ?x1 ?x2) () ) + +;; (assert-propagation ((?x1 elt)(?x2 elt)) () () (=> (and (= (f ?x1) ?x1) (Rf ?x1 ?x2 ?x2)) (= ?x1 ?x2)) (((Rf ?x1 ?x2 ?x2)(f ?x1))) ) + +;; sandwich +(assert-propagation ((?m mem)(?x1 elt)(?x2 elt)) () ((R ?m ?x1 ?x2 ?x1)) (= ?x1 ?x2) () ) +;; (assert-propagation ((?x1 elt)(?x2 elt)) () () (=> (Rf ?x1 ?x2 ?x1) (= ?x1 ?x2)) (((Rf ?x1 ?x2 ?x1))) ) + +;; order1 +(assert-propagation ((?m mem)(?x1 elt)(?x2 elt)(?x3 elt)) () + ((R ?m ?x1 ?x2 ?x2)(R ?m ?x1 ?x3 ?x3)) (or (R ?m ?x1 ?x2 ?x3) (R ?m ?x1 ?x3 ?x2)) () ) + +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () () +;; (=> (and (Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)) (or (Rf ?x1 ?x2 ?x3) (Rf ?x1 ?x3 ?x2))) (((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3))) ) + +;; ;; order1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x3 ?x2))) () +;; (Rf ?x1 ?x2 ?x3) (((Rf ?x1 ?x2 ?x3))) ) +;; ;; order1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x2 ?x3))) () +;; (Rf ?x1 ?x3 ?x2) (((Rf ?x1 ?x3 ?x2))) ) +;; ;; order1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x3 ?x2))) () +;; (Rf ?x1 ?x2 ?x3) (((Rf ?x1 ?x3 ?x2))) ) +;; ;; order1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x2 ?x3))) () +;; (Rf ?x1 ?x3 ?x2) (((Rf ?x1 ?x2 ?x3))) ) +;; ;; order1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x3 ?x2))) () +;; (Rf ?x1 ?x2 ?x3) (((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3))) ) +;; ;; order1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x2 ?x3))) () +;; (Rf ?x1 ?x3 ?x2) (((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3))) ) + +;; order2 +(assert-propagation ((?m mem)(?x1 elt)(?x2 elt)(?x3 elt)) () ((R ?m ?x1 ?x2 ?x3)) + (and (R ?m ?x1 ?x2 ?x2) (R ?m ?x2 ?x3 ?x3)) () ) +;; transitive1 +(assert-propagation ((?m mem)(?x1 elt)(?x2 elt)(?x3 elt)) () ((R ?m ?x1 ?x2 ?x2)(R ?m ?x2 ?x3 ?x3)) + (R ?m ?x1 ?x3 ?x3) () ) +;; ;; transitive1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () ((not (Rf ?x1 ?x3 ?x3))(Rf ?x2 ?x3 ?x3)) +;; (not (Rf ?x1 ?x2 ?x2)) () ) +;; ;; transitive1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x1 ?x2 ?x2)(not (Rf ?x1 ?x3 ?x3))) +;; (not (Rf ?x2 ?x3 ?x3)) () ) + +;;transitive2 +(assert-propagation ((?m mem)(?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((R ?m ?x0 ?x1 ?x2)(R ?m ?x1 ?x3 ?x2)) + (and (R ?m ?x0 ?x1 ?x3) (R ?m ?x0 ?x3 ?x2)) () ) + +;; (assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () () +;; (=> (and (Rf ?x0 ?x1 ?x2)(Rf ?x1 ?x3 ?x2)) +;; (and (Rf ?x0 ?x1 ?x3) (Rf ?x0 ?x3 ?x2))) +;; (((Rf ?x0 ?x1 ?x2)(Rf ?x1 ?x3 ?x2))) ) + +;; ;; transitive2 extended +;; (assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((not (Rf ?x0 ?x1 ?x3))(Rf ?x1 ?x3 ?x2)) +;; (not (Rf ?x0 ?x1 ?x2)) (((Rf ?x0 ?x1 ?x2))) ) +;; ;; transitive2 extended +;; (assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x0 ?x1 ?x2)(not (Rf ?x0 ?x1 ?x3))) +;; (not (Rf ?x1 ?x3 ?x2)) (((Rf ?x1 ?x3 ?x2))) ) +;; ;; transitive2 extended +;; (assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((not (Rf ?x0 ?x3 ?x2))(Rf ?x1 ?x3 ?x2)) +;; (not (Rf ?x0 ?x1 ?x2)) (((Rf ?x0 ?x1 ?x2))) ) +;; ;; transitive2 extended +;; (assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x0 ?x1 ?x2)(not (Rf ?x0 ?x3 ?x2))) +;; (not (Rf ?x1 ?x3 ?x2)) (((Rf ?x1 ?x3 ?x2))) ) + +;; ;;transitive3 +(assert-propagation ((?m mem)(?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((R ?m ?x0 ?x1 ?x2)(R ?m ?x0 ?x3 ?x1)) + (and (R ?m ?x0 ?x3 ?x2) (R ?m ?x3 ?x1 ?x2)) () ) + +;; (assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () () +;; (=> (and (Rf ?x0 ?x1 ?x2)(Rf ?x0 ?x3 ?x1)) +;; (and (Rf ?x0 ?x3 ?x2) (Rf ?x3 ?x1 ?x2))) (((Rf ?x0 ?x1 ?x2)(Rf ?x0 ?x3 ?x1))) ) + + +(declare-fun next () mem) + +(declare-fun e1 () elt) +(declare-fun e2 () elt) +(declare-fun e3 () elt) +(declare-fun e4 () elt) + + + +(declare-fun R_avoid (mem elt elt elt) Bool) + +(assert-rewrite ((?m mem)(?x0 elt)(?x1 elt)(?exc elt)) () (R_avoid ?m ?x0 ?x1 ?exc) + (or (R ?m ?x0 ?x1 ?exc) (and (R ?m ?x0 ?x1 ?x1) (not (R ?m ?x0 ?exc ?exc)))) () ) + + +;; Identity of Back to the future p175 +(assert-rewrite ((?p elt)(?q elt)(?u elt)(?v elt)(?w elt)(?m mem)) () (R (store ?m ?p ?q) ?u ?v ?w) + (or (and (R ?m ?u ?v ?w) (R_avoid ?m ?u ?w ?p) ) + (and (not (= ?p ?w)) (R_avoid ?m ?u ?p ?w) (R ?m ?u ?v ?p) (R_avoid ?m ?q ?w ?p) ) + (and (not (= ?p ?w)) (R_avoid ?m ?u ?p ?w) (R ?m ?q ?v ?w) (R_avoid ?m ?q ?w ?p) ) ) + () +) + + + +(declare-fun join (mem elt elt) elt) + +(declare-fun null () elt) +(assert (= (select next null) null)) + +(assert-propagation ((?m mem)(?x elt)(?y elt)(?z elt)) () ((R ?m ?x ?z ?z)(R ?m ?y ?z ?z)) (R ?m ?x (join ?m ?x ?y) ?z) (((join ?m ?x ?y))) ) +(assert-propagation ((?m mem)(?x elt)(?y elt)) () () (or (and (R ?m ?x (join ?m ?x ?y) (join ?m ?x ?y)) (R ?m ?y (join ?m ?x ?y) (join ?m ?x ?y))) (= (join ?m ?x ?y) null)) (((join ?m ?x ?y))) ) + +;;extended join +(assert-propagation ((?m mem)(?x elt)(?y elt)(?z elt)) () ((R ?m ?x ?z (join ?m ?x ?y))(R ?m ?y ?z (join ?m ?x ?y))) (= ?z (join ?m ?x ?y)) () ) + + +(assert-propagation ((?p elt)(?q elt)(?m mem)(?u elt)(?v elt)) () () + (= (join (store ?m ?p ?q) ?u ?v) + (let ((jp (join ?m ?u ?v))) + ;; In ?m: ?u ?v have a nearest point of junction (join ?m ?u ?v) + (ite (and (R ?m ?u jp jp) (R ?m ?v jp jp)) + ;; The modification is in the ?u branch + (ite (R ?m ?u ?p jp) + ;; we can go by the new path and the new path doesn't cycle + (ite (and (R (store ?m ?p ?q) ?u ?p ?q) (R (store ?m ?p ?q) ?q (join ?m ?q ?v) (join ?m ?q ?v))) + (join ?m ?q ?v) + ;; we can't + null + ) + ;; The modification is in the ?v branch + (ite (R ?m ?v ?p jp) + ;; we can go by the new path and the new path doesn't cycle + (ite (and (R (store ?m ?p ?q) ?v ?p ?q) (R (store ?m ?p ?q) ?q (join ?m ?u ?q) (join ?m ?u ?q))) + (join ?m ?u ?q) + ;; we can't + null + ) + ;; The modification is not before the point of junction + (join ?m ?u ?v) + )) + ;; In ?m: ?u ?v doens't have a point of junction + ;;The modification is accesible from ?u + (ite (R ?m ?u ?p ?p) (join ?m ?q ?v) + ;;The modification is accesible from ?v + (ite (R ?m ?v ?p ?p) (join ?m ?u ?q) + ;;The modification is accesible neither from ?u neither from ?v + (join ?m ?u ?v) + ) + ) + ) + )) + (((join (store ?m ?p ?q) ?u ?v))) + ) + +(declare-fun next2 () mem) + +;; === Example 0 === +;; (assert (not (=> +;; (and (not (= e1 e2)) +;; (R next e1 e2 e3)) +;; (R next e1 (select next e1) e3)) +;; )) + +;;================ +;;Thomas' example1 x,e1 y,e2 z,e3 y',e4 +;;================ +;; (assert (not (=> +;; (and (R next e1 e2 e3) +;; (not (= e2 e3)) +;; (= e4 (select next e2))) +;; (R next e1 e4 e3)) +;; )) + + +;;=================== +;; ;;Thomas' example2 +;;=================== + +;; (assert (not (=> +;; (and (R next e1 null null) +;; (= (join next e1 e2) null) +;; (= next2 (store next e2 e1)) +;; ) +;; (R next2 e1 null null) +;; ) +;; ) +;; ) + + +;;================ +;;Thomas' example3 +;;================ +(assert (not (=> (and (= (join next e1 e2) null) + (R next e2 null null) + (not (= e2 null)) + (= next2 (store next e2 e1)) + (= e3 e2) + (= e4 (select next e2)) + ) + (= (join next2 e3 e4) null) + ) + ) + ) + +;; ==== for debugging example 3 ==== +;; ;;case to consider +;; ;;(assert (or (not (R next e1 null null)) (R next e1 null null))) + +;; ;;first case to consider +;; ;;(assert (R next e1 null null)) + +;; ;;second case to consider +;; ;; (assert (not (R next e1 null null))) + + +;; ;;hyp +;; (assert (= (join next e1 e2) null)) +;; (assert (R next e2 null null)) +;; (assert (not (= e2 null))) +;; (assert (= next2 (store next e2 e1))) +;; (assert (= e3 e2)) +;; (assert (= e4 (select next e2))) + +;; ;; help +;; ;; have a join point +;; ;; (assert (R next e2 e4 e4)) +;; ;; (assert (R next e4 e4 e4)) + +;; ;; (assert (R next e2 (join next e2 e4) e4)) +;; ;; (assert (not (R next e4 e2 e2))) + +;; ;; (assert (not (= e2 (join next e2 e4))));; slow with efficient (/axioms) + +;; ;; (assert (= e4 (join next e2 e4))) ;; unprovable with efficient (/axioms) +;; ;; in e2 branch +;; ;; (assert (not (R next e4 e2 null))) ;; +;; ;; the auxillary join +;; ;; (assert (= (join next2 e1 e4) null)) + + +;; ;;to prove +;; (assert (not (= (join next2 e3 e4) null))) + + +;;==================== +;; ;;Thomas' example wrong sat? +;;==================== + +;; (assert (not (=> (and +;; (= (join next e1 e2) null) +;; (R next e2 null null) +;; (not (= e2 null)) +;; (= next2 (store next e2 e1)) +;; ) +;; (= (join next2 e1 e2) null) +;; ) +;; ) +;; ) + +;;==================== +;; ;;example4 sat +;;==================== + +;; (assert (not (=> (and +;; (= (join next e1 e2) null) +;; (R next e2 null null) (not (= e2 null)) +;; ) +;; (not (R next e2 e2 e2)) +;; ))) + + +;;==================== +;;example5 unsat +;;==================== + +;; (assert (and +;; ;; (= (join e1 e2) null) +;; (= (select next (select next e1)) e1) +;; (R next e1 e2 e2) +;; (not (= e2 e1)) +;; (not (= e2 (select next e1))) +;; ) +;; ) + +;;==================== +;; ;; example 6 unsat +;;==================== + +;; ;; join is the nearest junction point +;; (assert (and (not (= e3 (join next e1 e2))) +;; (R next e1 e3 (join next e1 e2)) +;; (R next e2 e3 (join next e1 e2)) +;; )) + + +;;==================== +;; example7 unsat +;;==================== + +;; (assert (R next e1 e2 (select next e1))) +;; (assert (not (= e1 e2))) +;; (assert (not (= e2 (select next e1)))) + + + +(check-sat) +(exit) + diff --git a/test/regress/regress0/rewriterules/reachability_bttf_ext_Thomas.smt2 b/test/regress/regress0/rewriterules/reachability_bttf_ext_Thomas.smt2 new file mode 100644 index 000000000..92103238c --- /dev/null +++ b/test/regress/regress0/rewriterules/reachability_bttf_ext_Thomas.smt2 @@ -0,0 +1,211 @@ +;; Back to the Future ... Shuvendu K.Lhiri, Shaz Qadeer +(set-logic AUFLIA) +(set-info :status unsat) + +(declare-sort elt 0) + +(declare-fun f (elt) elt) +(declare-fun Rf (elt elt elt) Bool) + +;; reflexive +;;(assert-propagation ((?x elt)) () () (Rf ?x ?x ?x) ((?x)) ) +;; step +(assert-propagation ((?x elt)) () () (Rf ?x (f ?x) (f ?x)) (((f ?x))) ) +;; (assert-propagation ((?x elt)) () () (Rf ?x (f ?x) (f ?x)) (((Rf ?x (f ?x) (f ?x)))) ) +;; (assert-propagation ((?x elt)) () () (=> true (Rf ?x (f ?x) (f ?x))) (((f ?x))) ) + +;; reach +(assert-propagation ((?x1 elt)(?x2 elt)) () ((Rf ?x1 ?x2 ?x2)) (or (= ?x1 ?x2) (Rf ?x1 (f ?x1) ?x2)) (((f ?x1))) ) +;; ;; reach extended +;; (assert-propagation ((?x1 elt)(?x2 elt)) ((not (= ?x1 ?x2))(Rf ?x1 ?x2 ?x2)) () (Rf ?x1 (f ?x1) ?x2) (((Rf ?x1 (f ?x1) ?x2))) ) +;; ;; reach extended +;; (assert-propagation ((?x1 elt)(?x2 elt)) ((not (Rf ?x1 (f ?x1) ?x2))(Rf ?x1 ?x2 ?x2)) () (= ?x1 ?x2) (((Rf ?x1 (f ?x1) ?x2))) ) + +;; cycle +(assert-propagation ((?x1 elt)(?x2 elt)) ((= (f ?x1) ?x1)) ((Rf ?x1 ?x2 ?x2)) (= ?x1 ?x2) (((f ?x1))) ) +;; (assert-propagation ((?x1 elt)(?x2 elt)) ((= (f ?x1) ?x1)) ((Rf ?x1 ?x2 ?x2)) (= ?x1 ?x2) () ) + +;; (assert-propagation ((?x1 elt)(?x2 elt)) () () (=> (and (= (f ?x1) ?x1) (Rf ?x1 ?x2 ?x2)) (= ?x1 ?x2)) (((Rf ?x1 ?x2 ?x2)(f ?x1))) ) + +;; sandwich +(assert-propagation ((?x1 elt)(?x2 elt)) () ((Rf ?x1 ?x2 ?x1)) (= ?x1 ?x2) () ) +;; (assert-propagation ((?x1 elt)(?x2 elt)) () () (=> (Rf ?x1 ?x2 ?x1) (= ?x1 ?x2)) (((Rf ?x1 ?x2 ?x1))) ) + +;; order1 +(assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () + ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)) (or (Rf ?x1 ?x2 ?x3) (Rf ?x1 ?x3 ?x2)) () ) + +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () () +;; (=> (and (Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)) (or (Rf ?x1 ?x2 ?x3) (Rf ?x1 ?x3 ?x2))) (((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3))) ) + +;; ;; order1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x3 ?x2))) () +;; (Rf ?x1 ?x2 ?x3) (((Rf ?x1 ?x2 ?x3))) ) +;; ;; order1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x2 ?x3))) () +;; (Rf ?x1 ?x3 ?x2) (((Rf ?x1 ?x3 ?x2))) ) +;; ;; order1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x3 ?x2))) () +;; (Rf ?x1 ?x2 ?x3) (((Rf ?x1 ?x3 ?x2))) ) +;; ;; order1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x2 ?x3))) () +;; (Rf ?x1 ?x3 ?x2) (((Rf ?x1 ?x2 ?x3))) ) +;; ;; order1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x3 ?x2))) () +;; (Rf ?x1 ?x2 ?x3) (((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3))) ) +;; ;; order1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) ((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3)(not (Rf ?x1 ?x2 ?x3))) () +;; (Rf ?x1 ?x3 ?x2) (((Rf ?x1 ?x2 ?x2)(Rf ?x1 ?x3 ?x3))) ) + +;; order2 +(assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x1 ?x2 ?x3)) + (and (Rf ?x1 ?x2 ?x2) (Rf ?x2 ?x3 ?x3)) () ) +;; transitive1 +(assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x1 ?x2 ?x2)(Rf ?x2 ?x3 ?x3)) + (Rf ?x1 ?x3 ?x3) () ) +;; ;; transitive1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () ((not (Rf ?x1 ?x3 ?x3))(Rf ?x2 ?x3 ?x3)) +;; (not (Rf ?x1 ?x2 ?x2)) () ) +;; ;; transitive1 extended +;; (assert-propagation ((?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x1 ?x2 ?x2)(not (Rf ?x1 ?x3 ?x3))) +;; (not (Rf ?x2 ?x3 ?x3)) () ) + +;;transitive2 +(assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x0 ?x1 ?x2)(Rf ?x1 ?x3 ?x2)) + (and (Rf ?x0 ?x1 ?x3) (Rf ?x0 ?x3 ?x2)) () ) + +;; (assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () () +;; (=> (and (Rf ?x0 ?x1 ?x2)(Rf ?x1 ?x3 ?x2)) +;; (and (Rf ?x0 ?x1 ?x3) (Rf ?x0 ?x3 ?x2))) +;; (((Rf ?x0 ?x1 ?x2)(Rf ?x1 ?x3 ?x2))) ) + +;; ;; transitive2 extended +;; (assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((not (Rf ?x0 ?x1 ?x3))(Rf ?x1 ?x3 ?x2)) +;; (not (Rf ?x0 ?x1 ?x2)) (((Rf ?x0 ?x1 ?x2))) ) +;; ;; transitive2 extended +;; (assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x0 ?x1 ?x2)(not (Rf ?x0 ?x1 ?x3))) +;; (not (Rf ?x1 ?x3 ?x2)) (((Rf ?x1 ?x3 ?x2))) ) +;; ;; transitive2 extended +;; (assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((not (Rf ?x0 ?x3 ?x2))(Rf ?x1 ?x3 ?x2)) +;; (not (Rf ?x0 ?x1 ?x2)) (((Rf ?x0 ?x1 ?x2))) ) +;; ;; transitive2 extended +;; (assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x0 ?x1 ?x2)(not (Rf ?x0 ?x3 ?x2))) +;; (not (Rf ?x1 ?x3 ?x2)) (((Rf ?x1 ?x3 ?x2))) ) + +;; ;;transitive3 +(assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () ((Rf ?x0 ?x1 ?x2)(Rf ?x0 ?x3 ?x1)) + (and (Rf ?x0 ?x3 ?x2) (Rf ?x3 ?x1 ?x2)) () ) + +;; (assert-propagation ((?x0 elt)(?x1 elt)(?x2 elt)(?x3 elt)) () () +;; (=> (and (Rf ?x0 ?x1 ?x2)(Rf ?x0 ?x3 ?x1)) +;; (and (Rf ?x0 ?x3 ?x2) (Rf ?x3 ?x1 ?x2))) (((Rf ?x0 ?x1 ?x2)(Rf ?x0 ?x3 ?x1))) ) + + +(declare-fun e1 () elt) +(declare-fun e2 () elt) +(declare-fun e3 () elt) +(declare-fun e4 () elt) + + +;;Example0 +;;(assert (not (=> (and (not (= e1 e2)) (Rf e1 e2 e3)) (Rf e1 (f e1) e3))) ) + +;;Thomas' example1 x,e1 y,e2 z,e3 y',e4 +;;(assert (not (=> (and (Rf e1 e2 e3) (not (= e2 e3)) (= e4 (f e2))) (Rf e1 e4 e3)))) + +(declare-fun Rf_avoid (elt elt elt) Bool) + +;; (assert-rewrite ((?x0 elt)(?x1 elt)(?exc elt)) () (Rf_avoid ?x0 ?x1 ?exc) +;; (or (Rf ?x0 ?x1 ?exc) (and (Rf ?x0 ?x1 ?x1) (not (Rf ?x0 ?exc ?exc)))) () ) + +(declare-fun null () elt) +(assert (= (f null) null)) + +(declare-fun join (elt elt) elt) + +;; (assert-propagation ((?x elt)(?y elt)(?z elt)) () ((Rf ?x ?z ?z)(Rf ?y ?z ?z)) (Rf ?x (join ?x ?y) ?z) (((join ?x ?y))) ) +;; (assert-propagation ((?x elt)(?y elt)) () () (or (and (Rf ?x (join ?x ?y) (join ?x ?y)) (Rf ?y (join ?x ?y) (join ?x ?y))) (= (join ?x ?y) null)) (((join ?x ?y))) ) + +;;Thomas' example2 +;; (assert (not (=> (and (Rf e1 null null) (= (join e1 e2) null) +;; ;; (next' == upd(next, e, e1) +;; ) +;; ;; (reach(next', e1, null) ) +;; (or (and (Rf e1 null null) (Rf_avoid e1 null e2) ) +;; (and (not (= e2 null)) (Rf_avoid e1 e2 null) (Rf e1 null e2) (Rf_avoid e1 null e2) ) +;; (and (not (= e2 null)) (Rf_avoid e1 e2 null) (Rf e1 null null) (Rf_avoid e1 null e2) ) ) +;; ))) + + +;;Thomas' example3 +;; join(next, first, e) == null && +;; reach(next, e, null) && +;; e != null && +;; next' == upd(next, e, first) && +;; first' == e && +;; e' == sel (next, e) +;; ==> +;; join(next', first', e') == null + + +;;Thomas' example3 +(assert(not + (=> + (and + ;; (= (join e1 e2) null) + (Rf e2 null null) + (not (= e2 null))) + ;; (next' == upd(next, e2, e1) + ;;join(next',e1,e2) == null +(or (and (not (Rf (f e2) e2 e2)) (not (Rf e1 e2 e2) )) +;; (and (Rf (f e2) e2 e2) (not (Rf e1 e1 e1) )) + (and (Rf e1 e2 e2) (not (Rf (f e2) e1 e1)) ) +) +;; (or +;; (and (not (Rf e1 e2 e2)) (not (Rf e2 e2 e2))) +;; (and (Rf e1 e2 e2) (not (Rf e2 e1 e1))) +;; (and (Rf e2 e2 e2) (not (Rf e1 e1 e1))) +;; ) +))) + + + +;; ;;Thomas' example wrong sat? +;; (assert (not (=> (and +;; (= (join e1 e2) null) +;; (Rf e2 null null) (not (= e2 null))) +;; ;; (next' == upd(next, e2, e1) +;; ;;join(next',e1,e2) == null +;; (not (Rf e2 e2 e2)) +;; ;; (or +;; ;; (and (not (Rf e1 e2 e2)) (not (Rf e2 e2 e2))) +;; ;; (and (Rf e1 e2 e2) (not (Rf e2 e1 e1))) +;; ;; (and (Rf e2 e2 e2) (not (Rf e1 e1 e1))) +;; ;; ) +;; ))) + +;; ;;example4 +;; (assert (not (=> (and +;; (= (join e1 e2) null) +;; (Rf e2 null null) (not (= e2 null)) +;; ) +;; (not (Rf e2 e2 e2)) +;; ))) + + +;; ;;example5 +;; (assert (and +;; ;; (= (join e1 e2) null) +;; (= (f (f e1)) e1) +;; (Rf e1 e2 e2) +;; (not (= e2 e1)) +;; (not (= e2 (f e1))) +;; ) +;; ) + + + + +(check-sat) +(exit) + diff --git a/test/regress/regress0/rewriterules/relation.smt2 b/test/regress/regress0/rewriterules/relation.smt2 new file mode 100644 index 000000000..a327a90a4 --- /dev/null +++ b/test/regress/regress0/rewriterules/relation.smt2 @@ -0,0 +1,27 @@ +(set-logic AUFLIA) +(set-info :status unsat) + +;; don't use a datatypes for currently focusing in uf +(declare-sort elt 0) + +(declare-fun R (elt elt) Bool) + +;; reflexive +(assert-rewrite ((x elt)) () (R x x) true ()) + +;; transitive +(assert-propagation ((x elt) (y elt) (z elt)) () ((R x y) (R y z)) (R x z) ()) + +;; anti-symmetric +(assert-propagation ((x elt) (y elt)) () ((R x y) (R y x)) (= x y) ()) + +(declare-fun e1 () elt) +(declare-fun e2 () elt) +(declare-fun e3 () elt) +(declare-fun e4 () elt) + +(assert (not (=> (and (R e1 e2) (R e2 e3) (R e3 e4) (R e4 e1)) (= e1 e4)))) + +(check-sat) + +(exit) \ No newline at end of file diff --git a/test/regress/regress0/rewriterules/set_A_new_fast_tableau-base.smt2 b/test/regress/regress0/rewriterules/set_A_new_fast_tableau-base.smt2 index 65dc23a10..1b397ef5b 100644 --- a/test/regress/regress0/rewriterules/set_A_new_fast_tableau-base.smt2 +++ b/test/regress/regress0/rewriterules/set_A_new_fast_tableau-base.smt2 @@ -12,72 +12,98 @@ ;; inter (declare-fun inter (set set) set) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (in ?s (inter ?t1 ?t2)) (and (in ?s ?t1) (in ?s ?t2))) :rewrite-rule))) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) () + ((in ?s (inter ?t1 ?t2))) (and (in ?s ?t1) (in ?s ?t2)) ()) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (not (in ?s ?t1)) (not (in ?s (inter ?t1 ?t2)))) :pattern ((inter ?t1 ?t2)) ) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s ?t1))) (not (in ?s (inter ?t1 ?t2))) (((inter ?t1 ?t2))) ) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (not (in ?s ?t2)) (not (in ?s (inter ?t1 ?t2)))) :pattern ((inter ?t1 ?t2)) ) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s ?t2))) (not (in ?s (inter ?t1 ?t2))) (((inter ?t1 ?t2))) ) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (and (not (in ?s (inter ?t1 ?t2))) (in ?s ?t1)) (not (in ?s ?t2))) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s (inter ?t1 ?t2))) (in ?s ?t1)) (not (in ?s ?t2)) () ) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (and (not (in ?s (inter ?t1 ?t2))) (in ?s ?t2)) (not (in ?s ?t1))) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s (inter ?t1 ?t2))) (in ?s ?t2)) (not (in ?s ?t1)) ()) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (and (in ?s ?t1) (in ?s ?t2)) (in ?s (inter ?t1 ?t2))) :pattern ((inter ?t1 ?t2)) ) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s ?t1) (in ?s ?t2)) (in ?s (inter ?t1 ?t2)) (((inter ?t1 ?t2))) ) ;;;;;;;;;;;;;;;;; ;; union (declare-fun union (set set) set) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (not (in ?s (union ?t1 ?t2))) (and (not (in ?s ?t1)) (not (in ?s ?t2)))) :rewrite-rule))) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s (union ?t1 ?t2)))) (and (not (in ?s ?t1)) (not (in ?s ?t2))) ()) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s ?t1)) (in ?s (union ?t1 ?t2)) (((union ?t1 ?t2)))) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (in ?s ?t1) (in ?s (union ?t1 ?t2))) :pattern ((union ?t1 ?t2)) ) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s ?t2)) (in ?s (union ?t1 ?t2)) (((union ?t1 ?t2)))) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (in ?s ?t2) (in ?s (union ?t1 ?t2))) :pattern ((union ?t1 ?t2)) ) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s (union ?t1 ?t2)) (not (in ?s ?t1))) (in ?s ?t2) ()) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (and (in ?s (union ?t1 ?t2)) (not (in ?s ?t1))) (in ?s ?t2)) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s (union ?t1 ?t2)) (not (in ?s ?t2))) (in ?s ?t1) ()) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (and (in ?s (union ?t1 ?t2)) (not (in ?s ?t2))) (in ?s ?t1)) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s ?t1)) (not (in ?s ?t2))) (not (in ?s (union ?t1 ?t2))) (((union ?t1 ?t2)))) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (and (not (in ?s ?t1)) (not (in ?s ?t2))) (not (in ?s (union ?t1 ?t2)))) :pattern ((union ?t1 ?t2)) ) :rewrite-rule) )) +;;;;;;;;;;;;;;;;;;;; +;; diff + +(declare-fun diff (set set) set) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s (diff ?t1 ?t2))) (and (in ?s ?t1) (not (in ?s ?t2))) ()) + +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s ?t1))) (not (in ?s (diff ?t1 ?t2))) (((diff ?t1 ?t2))) ) + +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s ?t2)) (not (in ?s (diff ?t1 ?t2))) (((diff ?t1 ?t2)))) + +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s (diff ?t1 ?t2))) (in ?s ?t1)) (in ?s ?t2) ()) + +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s (diff ?t1 ?t2))) (not (in ?s ?t2))) (not (in ?s ?t1)) ()) + +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s ?t1) (not (in ?s ?t2))) (in ?s (diff ?t1 ?t2)) (((diff ?t1 ?t2))) ) ;;;;;;;;;;;;;;;; ;;sing (declare-fun sing (elt) set) -(assert (forall ((?s elt)) - (! (! (=> true (in ?s (sing ?s))) :pattern ((sing ?s)) ) :rewrite-rule) )) - -(assert (forall ((?s elt) (?t1 elt)) - (! (=> true (=> (in ?s (sing ?t1)) (= ?s ?t1))) :rewrite-rule) )) - -(assert (forall ((?s elt) (?t1 elt)) - (! (=> (not (in ?s (sing ?t1))) (not (= ?s ?t1))) :rewrite-rule) )) +(assert-propagation ((?s elt)) + () () (in ?s (sing ?s)) (((sing ?s))) ) +(assert-propagation ((?s elt) (?t1 elt)) + () ((in ?s (sing ?t1))) (= ?s ?t1) ()) +(assert-propagation ((?s elt) (?t1 elt)) + () ((not (in ?s (sing ?t1)))) (not (= ?s ?t1)) ()) ;;;;;;;;;;;;;;;;;;; -;; fullfiling -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (in ?s (union ?t1 ?t2)) (or (in ?s ?t1) (not (in ?s ?t1)))) :rewrite-rule))) +;; fullfiling runned at Full effort +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s (union ?t1 ?t2))) (or (in ?s ?t1) (not (in ?s ?t1))) ()) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (in ?s ?t1) (or (in ?s ?t2) (not (in ?s ?t2)))) :pattern ((inter ?t1 ?t2))) :rewrite-rule))) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s ?t1)) (or (in ?s ?t2) (not (in ?s ?t2))) (((inter ?t1 ?t2)))) -(assert (forall ((?t1 set) (?t2 set)) (! (=> (not (= ?t1 ?t2)) (exists ((?e elt)) (or (and (in ?e ?t1) (not (in ?e ?t2))) (and (not (in ?e ?t1)) (in ?e ?t2))))) :rewrite-rule))) +(assert-propagation ((?t1 set) (?t2 set)) + () ((not (= ?t1 ?t2))) (exists ((?e elt)) (or (and (in ?e ?t1) (not (in ?e ?t2))) (and (not (in ?e ?t1)) (in ?e ?t2)))) ()) + +;;;;;;;;;;;;;;;;;;; +;; shortcut +(declare-fun subset (set set) Bool) +(assert-reduction ((?t1 set) (?t2 set)) + () ((subset ?t1 ?t2)) (= (union ?t1 ?t2) ?t2) ()) (declare-fun e () elt) (declare-fun t1 () set) diff --git a/test/regress/regress0/rewriterules/set_A_new_fast_tableau-base_sat.smt2 b/test/regress/regress0/rewriterules/set_A_new_fast_tableau-base_sat.smt2 index 07e9f9643..55050ac1a 100644 --- a/test/regress/regress0/rewriterules/set_A_new_fast_tableau-base_sat.smt2 +++ b/test/regress/regress0/rewriterules/set_A_new_fast_tableau-base_sat.smt2 @@ -8,76 +8,103 @@ (declare-fun in (elt set) Bool) + ;;;;;;;;;;;;;;;;;;;; ;; inter (declare-fun inter (set set) set) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (in ?s (inter ?t1 ?t2)) (and (in ?s ?t1) (in ?s ?t2))) :rewrite-rule))) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) () + ((in ?s (inter ?t1 ?t2))) (and (in ?s ?t1) (in ?s ?t2)) ()) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (not (in ?s ?t1)) (not (in ?s (inter ?t1 ?t2)))) :pattern ((inter ?t1 ?t2)) ) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s ?t1))) (not (in ?s (inter ?t1 ?t2))) (((inter ?t1 ?t2))) ) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (not (in ?s ?t2)) (not (in ?s (inter ?t1 ?t2)))) :pattern ((inter ?t1 ?t2)) ) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s ?t2))) (not (in ?s (inter ?t1 ?t2))) (((inter ?t1 ?t2))) ) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (and (not (in ?s (inter ?t1 ?t2))) (in ?s ?t1)) (not (in ?s ?t2))) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s (inter ?t1 ?t2))) (in ?s ?t1)) (not (in ?s ?t2)) () ) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (and (not (in ?s (inter ?t1 ?t2))) (in ?s ?t2)) (not (in ?s ?t1))) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s (inter ?t1 ?t2))) (in ?s ?t2)) (not (in ?s ?t1)) ()) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (and (in ?s ?t1) (in ?s ?t2)) (in ?s (inter ?t1 ?t2))) :pattern ((inter ?t1 ?t2)) ) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s ?t1) (in ?s ?t2)) (in ?s (inter ?t1 ?t2)) (((inter ?t1 ?t2))) ) ;;;;;;;;;;;;;;;;; ;; union (declare-fun union (set set) set) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (not (in ?s (union ?t1 ?t2))) (and (not (in ?s ?t1)) (not (in ?s ?t2)))) :rewrite-rule))) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s (union ?t1 ?t2)))) (and (not (in ?s ?t1)) (not (in ?s ?t2))) ()) + +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s ?t1)) (in ?s (union ?t1 ?t2)) (((union ?t1 ?t2)))) + +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s ?t2)) (in ?s (union ?t1 ?t2)) (((union ?t1 ?t2)))) + +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s (union ?t1 ?t2)) (not (in ?s ?t1))) (in ?s ?t2) ()) + +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s (union ?t1 ?t2)) (not (in ?s ?t2))) (in ?s ?t1) ()) + +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s ?t1)) (not (in ?s ?t2))) (not (in ?s (union ?t1 ?t2))) (((union ?t1 ?t2)))) +;;;;;;;;;;;;;;;;;;;; +;; diff + +(declare-fun diff (set set) set) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s (diff ?t1 ?t2))) (and (in ?s ?t1) (not (in ?s ?t2))) ()) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (in ?s ?t1) (in ?s (union ?t1 ?t2))) :pattern ((union ?t1 ?t2)) ) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s ?t1))) (not (in ?s (diff ?t1 ?t2))) (((diff ?t1 ?t2))) ) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (in ?s ?t2) (in ?s (union ?t1 ?t2))) :pattern ((union ?t1 ?t2)) ) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s ?t2)) (not (in ?s (diff ?t1 ?t2))) (((diff ?t1 ?t2)))) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (and (in ?s (union ?t1 ?t2)) (not (in ?s ?t1))) (in ?s ?t2)) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s (diff ?t1 ?t2))) (in ?s ?t1)) (in ?s ?t2) ()) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (and (in ?s (union ?t1 ?t2)) (not (in ?s ?t2))) (in ?s ?t1)) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((not (in ?s (diff ?t1 ?t2))) (not (in ?s ?t2))) (not (in ?s ?t1)) ()) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (and (not (in ?s ?t1)) (not (in ?s ?t2))) (not (in ?s (union ?t1 ?t2)))) :pattern ((union ?t1 ?t2)) ) :rewrite-rule) )) +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s ?t1) (not (in ?s ?t2))) (in ?s (diff ?t1 ?t2)) (((diff ?t1 ?t2))) ) ;;;;;;;;;;;;;;;; ;;sing (declare-fun sing (elt) set) -(assert (forall ((?s elt)) - (! (! (=> true (in ?s (sing ?s))) :pattern ((sing ?s)) ) :rewrite-rule) )) - -(assert (forall ((?s elt) (?t1 elt)) - (! (=> true (=> (in ?s (sing ?t1)) (= ?s ?t1))) :rewrite-rule) )) - -(assert (forall ((?s elt) (?t1 elt)) - (! (=> (not (in ?s (sing ?t1))) (not (= ?s ?t1))) :rewrite-rule) )) +(assert-propagation ((?s elt)) + () () (in ?s (sing ?s)) (((sing ?s))) ) +(assert-propagation ((?s elt) (?t1 elt)) + () ((in ?s (sing ?t1))) (= ?s ?t1) ()) +(assert-propagation ((?s elt) (?t1 elt)) + () ((not (in ?s (sing ?t1)))) (not (= ?s ?t1)) ()) ;;;;;;;;;;;;;;;;;;; -;; fullfiling -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (=> (in ?s (union ?t1 ?t2)) (or (in ?s ?t1) (not (in ?s ?t1)))) :rewrite-rule))) +;; fullfiling runned at Full effort +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s (union ?t1 ?t2))) (or (in ?s ?t1) (not (in ?s ?t1))) ()) + +(assert-propagation ((?s elt) (?t1 set) (?t2 set)) + () ((in ?s ?t1)) (or (in ?s ?t2) (not (in ?s ?t2))) (((inter ?t1 ?t2)))) -(assert (forall ((?s elt) (?t1 set) (?t2 set)) - (! (! (=> (in ?s ?t1) (or (in ?s ?t2) (not (in ?s ?t2)))) :pattern ((inter ?t1 ?t2))) :rewrite-rule))) +(assert-propagation ((?t1 set) (?t2 set)) + () ((not (= ?t1 ?t2))) (exists ((?e elt)) (or (and (in ?e ?t1) (not (in ?e ?t2))) (and (not (in ?e ?t1)) (in ?e ?t2)))) ()) -;; (assert (forall ((?t1 set) (?t2 set)) (! (=> (not (= ?t1 ?t2)) (exists ((?e elt)) (or (and (in ?e ?t1) (not (in ?e ?t2))) (and (not (in ?e ?t1)) (in ?e ?t2))))) ))) +;;;;;;;;;;;;;;;;;;; +;; shortcut +(declare-fun subset (set set) Bool) +(assert-reduction ((?t1 set) (?t2 set)) + () ((subset ?t1 ?t2)) (= (union ?t1 ?t2) ?t2) ()) (declare-fun e () elt) (declare-fun t1 () set) diff --git a/test/regress/regress0/rewriterules/simulate_rewritting.smt2 b/test/regress/regress0/rewriterules/simulate_rewritting.smt2 new file mode 100644 index 000000000..d1d88a549 --- /dev/null +++ b/test/regress/regress0/rewriterules/simulate_rewritting.smt2 @@ -0,0 +1,24 @@ +;; A new fast tableau-base ... Domenico Cantone et Calogero G.Zarba +(set-logic AUFLIA) +(set-info :status sat) + +(declare-sort elt1 0) +(declare-sort elt2 0) + +(declare-fun g (elt2) Bool) + +(declare-fun p (elt1 elt1) Bool) +(declare-fun f (elt2) elt1) +(declare-fun c1 () elt1) +(declare-fun c2 () elt1) + +(assert (forall ((?e elt2)) (! (=> (g ?e) (= (f ?e) c2)) :rewrite-rule))) +(assert (forall ((?e elt2)) (! (=> (g ?e) (= (f ?e) c1)) :rewrite-rule))) + +(declare-fun e () elt2) + +(assert (not (=> (g e) (=> (p c1 c2) (p (f e) (f e)))) )) + +(check-sat) + +(exit) diff --git a/test/regress/regress0/rewriterules/test_efficient_ematching.smt2 b/test/regress/regress0/rewriterules/test_efficient_ematching.smt2 new file mode 100644 index 000000000..e91ef36c2 --- /dev/null +++ b/test/regress/regress0/rewriterules/test_efficient_ematching.smt2 @@ -0,0 +1,35 @@ +(set-logic AUFLIA) +(set-info :status unsat) + +;; don't use a datatypes for currently focusing in uf +(declare-sort elt 0) + +(declare-fun R (elt elt) Bool) + +;; reflexive +(assert-rewrite ((x elt)) () (R x x) true ()) + +;; transitive +(assert-propagation ((x elt) (y elt) (z elt)) () ((R x y) (R y z)) (R x z) ()) + +;; anti-symmetric +(assert-propagation ((x elt) (y elt)) () ((R x y) (R y x)) (= x y) ()) + +(declare-fun f (elt) elt) +(assert-propagation ((x elt)(y elt)) () ((R (f x) (f y))) (R x y) ()) + + +(declare-fun e1 () elt) +(declare-fun e2 () elt) +(declare-fun e3 () elt) +(declare-fun e4 () elt) +(declare-fun e5 () elt) + +(assert (not (=> (and (R e1 e2) (R e3 (f e4)) (R e4 e5) + (or (and (= e3 (f e2)) (= e4 e1)) + (and (= e4 e2) (= e5 e1)) ) + ) (= e1 e2)))) + +(check-sat) + +(exit) \ No newline at end of file -- 2.30.2