/********************* */ /*! \file macros.cpp ** \verbatim ** Top contributors (to current version): ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS ** in the top-level source directory) and their institutional affiliations. ** All rights reserved. See the file COPYING in the top-level source ** directory for licensing information.\endverbatim ** ** \brief Sort inference module ** ** This class implements quantifiers macro definitions. **/ #include "theory/quantifiers/macros.h" #include #include "options/quantifiers_modes.h" #include "options/quantifiers_options.h" #include "proof/proof_manager.h" #include "smt/smt_engine.h" #include "smt/smt_engine_scope.h" #include "theory/quantifiers/term_database.h" #include "theory/quantifiers/term_util.h" #include "theory/quantifiers/ematching/trigger.h" #include "theory/rewriter.h" using namespace CVC4; using namespace std; using namespace CVC4::theory; using namespace CVC4::theory::quantifiers; using namespace CVC4::kind; QuantifierMacros::QuantifierMacros( QuantifiersEngine * qe ) : d_qe( qe ){ d_ground_macros = false; } bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite ){ unsigned rmax = options::macrosQuantMode()==MACROS_QUANT_MODE_ALL ? 2 : 1; for( unsigned r=0; r macro_assertions; for( int i=0; i<(int)assertions.size(); i++ ){ Trace("macros-debug") << " process assertion " << assertions[i] << std::endl; if( processAssertion( assertions[i] ) ){ PROOF( if( std::find( macro_assertions.begin(), macro_assertions.end(), assertions[i] )==macro_assertions.end() ){ macro_assertions.push_back( assertions[i] ); } ); //process this assertion again i--; } } Trace("macros") << "...finished process, #new def = " << d_macro_defs_new.size() << std::endl; if( doRewrite && !d_macro_defs_new.empty() ){ bool retVal = false; Trace("macros") << "Do simplifications..." << std::endl; //now, rewrite based on macro definitions for( unsigned i=0; iaddDependence(curr, assertions[i]); for( unsigned j=0; jaddDependence(curr,macro_assertions[j]); } } ); assertions[i] = curr; retVal = true; } } d_macro_defs_new.clear(); if( retVal ){ return true; } } } if( Trace.isOn("macros-warn") ){ for( unsigned i=0; i args; for( size_t j=0; j& opc, std::map< Node, bool >& visited ){ if( visited.find( n )==visited.end() ){ visited[n] = true; if( n.getKind()==APPLY_UF ){ Node nop = n.getOperator(); if( nop==op || d_macro_defs.find( nop )!=d_macro_defs.end() ){ return true; } if( std::find( opc.begin(), opc.end(), nop )==opc.end() ){ opc.push_back( nop ); } }else if( d_ground_macros && n.getKind()==FORALL ){ return true; } for( size_t i=0; igetTermUtil()->substituteBoundVariablesToInstConstants(n, f); Trace("macros-debug2") << "Get free variables in " << icn << std::endl; std::vector< Node > var; quantifiers::TermUtil::computeInstConstContainsForQuant(f, icn, var); Trace("macros-debug2") << "Get trigger variables for " << icn << std::endl; std::vector< Node > trigger_var; inst::Trigger::getTriggerVariables( icn, f, trigger_var ); Trace("macros-debug2") << "Done." << std::endl; //only if all variables are also trigger variables return trigger_var.size()>=var.size(); } bool QuantifierMacros::isBoundVarApplyUf( Node n ) { Assert( n.getKind()==APPLY_UF ); TypeNode tno = n.getOperator().getType(); std::map< Node, bool > vars; // allow if a vector of unique variables of the same type as UF arguments for( unsigned i=0; i& candidates, std::map< Node, bool >& visited ){ if( visited.find( n )==visited.end() ){ visited[n] = true; if( n.getKind()==APPLY_UF ){ if( isBoundVarApplyUf( n ) ){ 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 = plus_children.size()==1 ? plus_children[0] : 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::getFreeVariables( Node n, std::vector< Node >& v_quant, std::vector< Node >& vars, bool retOnly, std::map< Node, bool >& visited ){ if( visited.find( n )==visited.end() ){ visited[n] = true; 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 ){ Trace("macros-debug") << " process " << n << std::endl; if( n.getKind()==NOT ){ return process( n[0], !pol, args, f ); }else if( n.getKind()==AND || n.getKind()==OR ){ //bool favorPol = (n.getKind()==AND)==pol; //conditional? }else if( n.getKind()==ITE ){ //can not do anything }else if( n.getKind()==APPLY_UF ){ //predicate case if( isBoundVarApplyUf( n ) ){ Node op = n.getOperator(); if( d_macro_defs.find( op )==d_macro_defs.end() ){ Node n_def = NodeManager::currentNM()->mkConst( pol ); for( unsigned i=0; imkSkolem( ss.str(), n[i].getType(), "created during macro definition recognition" ); d_macro_basis[op].push_back( v ); } //contains no ops std::vector< Node > op_contains; //add the macro addMacro( op, n_def, op_contains ); return true; } } }else{ //literal case if( isMacroLiteral( n, pol ) ){ Trace("macros-debug") << "Check macro literal : " << n << std::endl; std::map< Node, bool > visited; std::vector< Node > candidates; for( size_t i=0; i fvs; visited.clear(); getFreeVariables( m, args, fvs, false, visited ); //get definition and condition Node n_def = solveInEquality( m, n ); //definition for the macro if( !n_def.isNull() ){ Trace("macros-debug") << m << " is possible macro in " << f << std::endl; Trace("macros-debug") << " corresponding definition is : " << n_def << std::endl; visited.clear(); //definition must exist and not contain any free variables apart from fvs if( !getFreeVariables( n_def, args, fvs, true, visited ) ){ Trace("macros-debug") << "...free variables are contained." << std::endl; visited.clear(); //cannot contain a defined operator, opc is list of functions it contains std::vector< Node > opc; if( !containsBadOp( n_def, op, opc, visited ) ){ Trace("macros-debug") << "...does not contain bad (recursive) operator." << std::endl; //must be ground UF term if mode is GROUND_UF if( options::macrosQuantMode()!=MACROS_QUANT_MODE_GROUND_UF || isGroundUfTerm( f, n_def ) ){ Trace("macros-debug") << "...respects ground-uf constraint." << 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::map< Node, Node > solved; for( size_t a=0; a vars; std::vector< Node > subs; if( getSubstitution( fvs, solved, vars, subs, true ) ){ n_def = n_def.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); addMacro( op, n_def, opc ); return true; } } } } } } } } } return false; } Node QuantifierMacros::simplify( Node n ){ if( n.getNumChildren()==0 ){ return n; }else{ std::map< Node, Node >::iterator itn = d_simplify_cache.find( n ); if( itn!=d_simplify_cache.end() ){ return itn->second; }else{ Node ret = n; Trace("macros-debug") << " simplify " << n << std::endl; std::vector< Node > children; bool childChanged = false; for( size_t i=0; i::iterator it = d_macro_defs.find( op ); if( it!=d_macro_defs.end() && !it->second.isNull() ){ //only apply if children are subtypes of arguments bool success = true; // FIXME : this can be eliminated when we have proper typing rules std::vector< Node > cond; TypeNode tno = op.getType(); for( unsigned i=0; isecond; std::map< Node, std::vector< Node > >::iterator itb = d_macro_basis.find( op ); if( itb!=d_macro_basis.end() ){ ret = ret.substitute( itb->second.begin(), itb->second.end(), children.begin(), children.end() ); } if( !cond.empty() ){ Node cc = cond.size()==1 ? cond[0] : NodeManager::currentNM()->mkNode( kind::AND, cond ); ret = NodeManager::currentNM()->mkNode( kind::ITE, cc, ret, n ); } retSet = true; } } } if( !retSet && childChanged ){ if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ children.insert( children.begin(), n.getOperator() ); } ret = NodeManager::currentNM()->mkNode( n.getKind(), children ); } d_simplify_cache[n] = ret; return ret; } } } void QuantifierMacros::debugMacroDefinition( Node oo, Node n ) { //for debugging, ensure that all previous definitions have been eliminated if( n.getKind()==APPLY_UF ){ Node op = n.getOperator(); if( d_macro_defs.find( op )!=d_macro_defs.end() ){ if( d_macro_defs.find( oo )!=d_macro_defs.end() ){ Trace("macros-warn") << "BAD DEFINITION for macro " << oo << " : " << d_macro_defs[oo] << std::endl; }else{ Trace("macros-warn") << "BAD ASSERTION " << oo << std::endl; } Trace("macros-warn") << " contains defined function " << op << "!!!" << std::endl; } } for( unsigned i=0; i::iterator it = d_macro_defs.begin(); it != d_macro_defs.end(); ++it ){ Trace("macros-def") << "Macro definition for " << it->first << " : " << it->second << std::endl; Trace("macros-def") << " basis is : "; std::vector< Node > nargs; std::vector< Expr > args; for( unsigned i=0; ifirst].size(); i++ ){ Node bv = NodeManager::currentNM()->mkBoundVar( d_macro_basis[it->first][i].getType() ); Trace("macros-def") << d_macro_basis[it->first][i] << " "; nargs.push_back( bv ); args.push_back( bv.toExpr() ); } Trace("macros-def") << std::endl; Node sbody = it->second.substitute( d_macro_basis[it->first].begin(), d_macro_basis[it->first].end(), nargs.begin(), nargs.end() ); smt::currentSmtEngine()->defineFunction( it->first.toExpr(), args, sbody.toExpr() ); if( Trace.isOn("macros-warn") ){ debugMacroDefinition( it->first, sbody ); } } Trace("macros") << "done." << std::endl; } } void QuantifierMacros::addMacro( Node op, Node n, std::vector< Node >& opc ) { Trace("macros") << "* " << n << " is a macro for " << op << ", #op contain = " << opc.size() << std::endl; d_simplify_cache.clear(); d_macro_defs[op] = n; d_macro_defs_new[op] = n; //substitute into all previous std::vector< Node > dep_ops; dep_ops.push_back( op ); Trace("macros-debug") << "...substitute into " << d_macro_def_contains[op].size() << " previous definitions." << std::endl; for( unsigned i=0; i