From a441252481616ff4851f208caffce826a026ae30 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Sun, 18 Nov 2012 17:34:00 +0000 Subject: [PATCH] support for quantifiers macros, bug fix for bug 454 involving E-matching Array select terms (thanks for the bug report Francois) --- src/smt/smt_engine.cpp | 7 +- src/theory/quantifiers/inst_match.cpp | 12 + src/theory/quantifiers/inst_match.h | 9 +- .../quantifiers/inst_match_generator.cpp | 2 +- src/theory/quantifiers/macros.cpp | 323 +++++++++++++++--- src/theory/quantifiers/macros.h | 21 +- 6 files changed, 320 insertions(+), 54 deletions(-) diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp index e4d21c72e..b9025a2ce 100644 --- a/src/smt/smt_engine.cpp +++ b/src/smt/smt_engine.cpp @@ -2109,8 +2109,11 @@ void SmtEnginePrivate::processAssertions() { if( options::macrosQuant() ){ //quantifiers macro expansion - QuantifierMacros qm; - qm.simplify( d_assertionsToPreprocess ); + bool success; + do{ + QuantifierMacros qm; + success = qm.simplify( d_assertionsToPreprocess, true ); + }while( success ); } if( options::sortInference() ){ diff --git a/src/theory/quantifiers/inst_match.cpp b/src/theory/quantifiers/inst_match.cpp index 16f06017e..1a48ec161 100644 --- a/src/theory/quantifiers/inst_match.cpp +++ b/src/theory/quantifiers/inst_match.cpp @@ -134,6 +134,18 @@ Node InstMatch::getValue( Node var ) const{ } } +void InstMatch::set(TNode var, TNode n){ + Assert( !var.isNull() ); + if( !n.isNull() &&// For a strange use in inst_match.cpp InstMatchGeneratorSimple::addInstantiations + //var.getType() == n.getType() + !n.getType().isSubtypeOf( var.getType() ) ){ + Trace("inst-match-warn") << var.getAttribute(InstConstantAttribute()) << std::endl; + Trace("inst-match-warn") << var << " " << var.getType() << n << " " << n.getType() << std::endl ; + Assert(false); + } + d_map[var] = n; +} + /** add match m for quantifier f starting at index, take into account equalities q, return true if successful */ void InstMatchTrie::addInstMatch2( QuantifiersEngine* qe, Node f, InstMatch& m, int index, ImtIndexOrder* imtio ){ if( long(index)d_order.size()) ) ){ diff --git a/src/theory/quantifiers/inst_match.h b/src/theory/quantifiers/inst_match.h index 41ebb63d2..c8f843c90 100644 --- a/src/theory/quantifiers/inst_match.h +++ b/src/theory/quantifiers/inst_match.h @@ -92,14 +92,7 @@ public: /** get */ Node get( TNode var ) { return d_map[var]; } /** 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() - n.getType().isSubtypeOf( var.getType() ) ); - d_map[var] = n; - } + void set(TNode var, TNode n); size_t size(){ return d_map.size(); } /* iterator */ std::map< Node, Node >::iterator begin(){ return d_map.begin(); }; diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp index a70fd9d7e..3b5e594fb 100755 --- a/src/theory/quantifiers/inst_match_generator.cpp +++ b/src/theory/quantifiers/inst_match_generator.cpp @@ -629,7 +629,7 @@ 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.get( ic ).isNull() || m.get( ic )==t ){ + if( ( m.get( ic ).isNull() || m.get( ic )==t ) && ic.getType()==t.getType() ){ Node prev = m.get( ic ); m.set( ic, t); addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); diff --git a/src/theory/quantifiers/macros.cpp b/src/theory/quantifiers/macros.cpp index 10db57184..c116b73f5 100755 --- a/src/theory/quantifiers/macros.cpp +++ b/src/theory/quantifiers/macros.cpp @@ -17,6 +17,7 @@ #include #include "theory/quantifiers/macros.h" +#include "theory/rewriter.h" using namespace CVC4; using namespace std; @@ -25,7 +26,7 @@ using namespace CVC4::theory::quantifiers; using namespace CVC4::kind; using namespace CVC4::context; -void QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite ){ +bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite ){ //first, collect macro definitions for( size_t i=0; i& assertions, bool doRewrite process( assertions[i][1], true, args, assertions[i] ); } } - //now, rewrite based on macro definitions - for( size_t i=0; i > >::iterator it = d_macro_def_cases.begin(); + it != d_macro_def_cases.end(); ++it ){ + //create ite based on case definitions + Node val; + for( size_t i=0; isecond.size(); ++i ){ + if( it->second[i].first.isNull() ){ + Assert( i==0 ); + val = it->second[i].second; + }else{ + //if value is null, must generate it + if( val.isNull() ){ + std::stringstream ss; + ss << "mdo_" << it->first << "_$$"; + Node op = NodeManager::currentNM()->mkSkolem( ss.str(), it->first.getType(), "op created during macro definitions" ); + //will be defined in terms of fresh operator + std::vector< Node > children; + children.push_back( op ); + children.insert( children.end(), d_macro_basis[ it->first ].begin(), d_macro_basis[ it->first ].end() ); + val = NodeManager::currentNM()->mkNode( APPLY_UF, children ); + } + val = NodeManager::currentNM()->mkNode( ITE, it->second[i].first, it->second[i].second, val ); + } + } + d_macro_defs[ it->first ] = val; + Trace("macros-def") << "* " << val << " is a macro for " << it->first << std::endl; + } + //now simplify bodies + for( std::map< Node, Node >::iterator it = d_macro_defs.begin(); it != d_macro_defs.end(); ++it ){ + d_macro_defs[ it->first ] = Rewriter::rewrite( simplify( it->second ) ); + } + bool retVal = false; + if( doRewrite && !d_macro_defs.empty() ){ + //now, rewrite based on macro definitions + for( size_t i=0; i& candidates ){ if( n.getKind()==APPLY_UF ){ - if( n.getOperator()==op ){ - return true; + candidates.push_back( n ); + }else if( n.getKind()==PLUS ){ + for( size_t i=0; i plus_children; + //find monomial with n + for( size_t j=0; jmkConst( Rational(1) ); + }else if( lit[1][j].getKind()==MULT && lit[1][j][1]==n ){ + Assert( coeff.isNull() ); + Assert( lit[1][j][0].isConst() ); + coeff = lit[1][j][0]; + }else{ + plus_children.push_back( lit[1][j] ); + } + } + if( !coeff.isNull() ){ + term = NodeManager::currentNM()->mkNode( PLUS, plus_children ); + term = NodeManager::currentNM()->mkNode( MINUS, lit[0], term ); + } + } + if( !coeff.isNull() ){ + coeff = NodeManager::currentNM()->mkConst( Rational(1) / coeff.getConst() ); + term = NodeManager::currentNM()->mkNode( MULT, coeff, term ); + term = Rewriter::rewrite( term ); + return term; + } + } + } + Trace("macros-debug") << "Cannot find for " << lit << " " << n << std::endl; + return Node::null(); +} + +bool QuantifierMacros::isConsistentDefinition( Node op, Node cond, Node def ){ + if( d_macro_def_cases[op].empty() || ( cond.isNull() && !d_macro_def_cases[op][0].first.isNull() ) ){ + return true; + }else{ + return false; + } +} + +bool QuantifierMacros::getFreeVariables( Node n, std::vector< Node >& v_quant, std::vector< Node >& vars, bool retOnly ){ + if( std::find( v_quant.begin(), v_quant.end(), n )!=v_quant.end() ){ + if( std::find( vars.begin(), vars.end(), n )==vars.end() ){ + if( retOnly ){ + return true; + }else{ + vars.push_back( n ); + } } } for( size_t i=0; i& v_quant, std::map< Node, Node >& solved, + std::vector< Node >& vars, std::vector< Node >& subs, bool reqComplete ){ + bool success = true; + for( size_t a=0; a& args, Node f ){ @@ -71,20 +240,105 @@ void QuantifierMacros::process( Node n, bool pol, std::vector< Node >& args, Nod //can not do anything }else{ //literal case - //only care about literals in form of (basis, definition) - if( isMacroKind( n, pol ) ){ - for( int i=0; i<2; i++ ){ - int j = i==0 ? 1 : 0; - //check if n[i] is the basis for a macro - if( n[i].getKind()==APPLY_UF ){ - //make sure it doesn't occur in the potential definition - if( !containsOp( n[j], n[i].getOperator() ) ){ - //bool usable = true; - //for( size_j a=0; a candidates; + for( size_t i=0; i fvs; + getFreeVariables( m, args, fvs, false ); + //get definition and condition + Node n_def = solveInEquality( m, n ); //definition for the macro + //definition must exist and not contain any free variables apart from fvs + if( !n_def.isNull() && !getFreeVariables( n_def, args, fvs, true ) ){ + Node n_cond; //condition when this definition holds + //conditional must not contain any free variables apart from fvs + if( n_cond.isNull() || !getFreeVariables( n_cond, args, fvs, true ) ){ + Trace("macros") << m << " is possible macro in " << f << std::endl; + //now we must rewrite candidates[i] to a term of form g( x1, ..., xn ) where + // x1 ... xn are distinct variables + if( d_macro_basis[op].empty() ){ + for( size_t a=0; amkSkolem( ss.str(), m[a].getType(), "created during macro definition recognition" ); + d_macro_basis[op].push_back( v ); + } + } + std::vector< Node > eq; + for( size_t a=0; a solved; + //solve obvious cases first + for( size_t a=0; a vars; + std::vector< Node > subs; + getSubstitution( fvs, solved, vars, subs, false ); + for( size_t a=0; a conds; + if( !n_cond.isNull() ){ + //must apply substitution obtained from solving system of equations to original condition + n_cond = n_cond.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); + conds.push_back( n_cond ); + } + for( size_t a=0; amkNode( eq[a].getType().isBoolean() ? IFF : EQUAL, d_macro_basis[op][a], eq[a] ) ); + } + } + //build the condition + if( !conds.empty() ){ + n_cond = conds.size()==1 ? conds[0] : NodeManager::currentNM()->mkNode( AND, conds ); + } + //apply the substitution to the + n_def = n_def.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); + //now see if definition is consistent with others + if( isConsistentDefinition( op, n_cond, n_def ) ){ + //must clear if it is a base definition + if( n_cond.isNull() ){ + d_macro_def_cases[ op ].clear(); + } + d_macro_def_cases[ op ].push_back( std::pair< Node, Node >( n_cond, n_def ) ); + } + } + } } } } @@ -93,7 +347,7 @@ void QuantifierMacros::process( Node n, bool pol, std::vector< Node >& args, Nod } Node QuantifierMacros::simplify( Node n ){ -#if 0 + Trace("macros-debug") << "simplify " << n << std::endl; std::vector< Node > children; bool childChanged = false; for( size_t i=0; i vars; - for( size_t i = 0; imkNode( n.getKind(), children ); }else{ return n; } -#else - return n; -#endif } diff --git a/src/theory/quantifiers/macros.h b/src/theory/quantifiers/macros.h index d93070481..b1fbb3e68 100755 --- a/src/theory/quantifiers/macros.h +++ b/src/theory/quantifiers/macros.h @@ -31,17 +31,28 @@ namespace quantifiers { class QuantifierMacros{ private: void process( Node n, bool pol, std::vector< Node >& args, Node f ); - bool containsOp( Node n, Node op ); - bool isMacroKind( Node n, bool pol ); - //map from operators to macro definition ( basis, definition ) - std::map< Node, std::pair< Node, Node > > d_macro_defs; + bool contains( Node n, Node n_s ); + bool containsBadOp( Node n, Node n_op ); + bool isMacroLiteral( Node n, bool pol ); + void getMacroCandidates( Node n, std::vector< Node >& candidates ); + Node solveInEquality( Node n, Node lit ); + bool isConsistentDefinition( Node op, Node cond, Node def ); + bool getFreeVariables( Node n, std::vector< Node >& v_quant, std::vector< Node >& vars, bool retOnly ); + bool getSubstitution( std::vector< Node >& v_quant, std::map< Node, Node >& solved, + std::vector< Node >& vars, std::vector< Node >& subs, bool reqComplete ); + //map from operators to macro basis terms + std::map< Node, std::vector< Node > > d_macro_basis; + //map from operators to map from conditions to definition cases + std::map< Node, std::vector< std::pair< Node, Node > > > d_macro_def_cases; + //map from operators to macro definition + std::map< Node, Node > d_macro_defs; private: Node simplify( Node n ); public: QuantifierMacros(){} ~QuantifierMacros(){} - void simplify( std::vector< Node >& assertions, bool doRewrite = false ); + bool simplify( std::vector< Node >& assertions, bool doRewrite = false ); }; } -- 2.30.2