/********************* */ /*! \file quantifiers_rewriter.cpp ** \verbatim ** Original author: Morgan Deters ** Major contributors: Andrew Reynolds ** Minor contributors (to current version): Tim King ** This file is part of the CVC4 project. ** Copyright (c) 2009-2014 New York University and The University of Iowa ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** ** \brief Implementation of QuantifiersRewriter class **/ #include "theory/quantifiers/quantifiers_rewriter.h" #include "options/quantifiers_options.h" #include "theory/datatypes/datatypes_rewriter.h" #include "theory/quantifiers/term_database.h" #include "theory/quantifiers/trigger.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 QuantifiersRewriter::isClause( Node n ){ if( isLiteral( n ) ){ return true; }else if( n.getKind()==NOT ){ return isCube( n[0] ); }else if( n.getKind()==OR ){ for( int i=0; i<(int)n.getNumChildren(); i++ ){ if( !isClause( n[i] ) ){ return false; } } return true; }else if( n.getKind()==IMPLIES ){ return isCube( n[0] ) && isClause( n[1] ); }else{ return false; } } bool QuantifiersRewriter::isLiteral( Node n ){ switch( n.getKind() ){ case NOT: return isLiteral( n[0] ); break; case OR: case AND: case IMPLIES: case XOR: case ITE: case IFF: return false; break; case EQUAL: return n[0].getType()!=NodeManager::currentNM()->booleanType(); break; default: break; } return true; } bool QuantifiersRewriter::isCube( Node n ){ if( isLiteral( n ) ){ return true; }else if( n.getKind()==NOT ){ return isClause( n[0] ); }else if( n.getKind()==AND ){ for( int i=0; i<(int)n.getNumChildren(); i++ ){ if( !isCube( n[i] ) ){ return false; } } return true; }else{ return false; } } int QuantifiersRewriter::getPurifyId( Node n ){ if( !TermDb::hasBoundVarAttr( n ) ){ return 0; }else if( inst::Trigger::isAtomicTriggerKind( n.getKind() ) ){ return 1; }else if( TermDb::isBoolConnective( n.getKind() ) || n.getKind()==EQUAL || n.getKind()==BOUND_VARIABLE ){ return 0; }else{ return -1; } } int QuantifiersRewriter::getPurifyIdLit2( Node n, std::map< Node, int >& visited ) { std::map< Node, int >::iterator it = visited.find( n ); if( visited.find( n )==visited.end() ){ int ret = 0; if( TermDb::hasBoundVarAttr( n ) ){ ret = getPurifyId( n ); for( unsigned i=0; isecond; } } int QuantifiersRewriter::getPurifyIdLit( Node n ) { std::map< Node, int > visited; return getPurifyIdLit2( n, visited ); } void QuantifiersRewriter::addNodeToOrBuilder( Node n, NodeBuilder<>& t ){ if( n.getKind()==OR ){ for( int i=0; i<(int)n.getNumChildren(); i++ ){ t << n[i]; } }else{ t << n; } } void QuantifiersRewriter::computeArgs( std::vector< Node >& args, std::map< Node, bool >& activeMap, Node n, std::map< Node, bool >& visited ){ if( visited.find( n )==visited.end() ){ visited[n] = true; if( n.getKind()==BOUND_VARIABLE ){ if( std::find( args.begin(), args.end(), n )!=args.end() ){ activeMap[ n ] = true; } }else{ for( int i=0; i<(int)n.getNumChildren(); i++ ){ computeArgs( args, activeMap, n[i], visited ); } } } } void QuantifiersRewriter::computeArgVec( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n ) { Assert( activeArgs.empty() ); std::map< Node, bool > activeMap; std::map< Node, bool > visited; computeArgs( args, activeMap, n, visited ); if( !activeMap.empty() ){ for( unsigned i=0; i& args, std::vector< Node >& activeArgs, Node n, Node ipl ) { Assert( activeArgs.empty() ); std::map< Node, bool > activeMap; std::map< Node, bool > visited; computeArgs( args, activeMap, n, visited ); if( !activeMap.empty() ){ //collect variables in inst pattern list only if we cannot eliminate quantifier computeArgs( args, activeMap, ipl, visited ); for( unsigned i=0; i args; for( int i=0; i<(int)in[0].getNumChildren(); i++ ){ args.push_back( in[0][i] ); } Node body = in[1]; bool doRewrite = false; std::vector< Node > ipl; while( body.getNumChildren()>=2 && body.getKind()==in.getKind() ){ if( body.getNumChildren()==3 ){ for( unsigned i=0; i children; children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST,args) ); children.push_back( body ); if( in.getNumChildren()==3 ){ for( unsigned i=0; imkNode( INST_PATTERN_LIST, ipl ) ); } Node n = NodeManager::currentNM()->mkNode( in.getKind(), children ); if( in!=n ){ Trace("quantifiers-pre-rewrite") << "*** pre-rewrite " << in << std::endl; Trace("quantifiers-pre-rewrite") << " to " << std::endl; Trace("quantifiers-pre-rewrite") << n << std::endl; } return RewriteResponse(REWRITE_DONE, n); } } return RewriteResponse(REWRITE_DONE, in); } RewriteResponse QuantifiersRewriter::postRewrite(TNode in) { Trace("quantifiers-rewrite-debug") << "post-rewriting " << in << std::endl; RewriteStatus status = REWRITE_DONE; Node ret = in; //get the body if( in.getKind()==EXISTS ){ std::vector< Node > children; children.push_back( in[0] ); children.push_back( in[1].negate() ); if( in.getNumChildren()==3 ){ children.push_back( in[2] ); } ret = NodeManager::currentNM()->mkNode( FORALL, children ); ret = ret.negate(); status = REWRITE_AGAIN_FULL; }else if( in.getKind()==FORALL ){ //compute attributes QAttributes qa; TermDb::computeQuantAttributes( in, qa ); if( !qa.isRewriteRule() ){ for( int op=0; op children; std::map< Node, bool > lit_pol; for( unsigned i=0; i::iterator it = lit_pol.find( lit ); if( it==lit_pol.end() ){ lit_pol[lit] = pol; children.push_back( c ); }else{ childrenChanged = true; if( it->second!=pol ){ return NodeManager::currentNM()->mkConst( k==OR ); } } }else{ children.push_back( c ); } childrenChanged = childrenChanged || c!=body[i]; } //if( body.getKind()==ITE && isLiteral( body[0] ) ){ // ret = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, body[0].negate(), body[1] ), // NodeManager::currentNM()->mkNode( OR, body[0], body[2] ) ); //} if( childrenChanged ){ return ( children.size()==1 && k!=NOT ) ? children[0] : NodeManager::currentNM()->mkNode( k, children ); }else{ return body; } } } Node QuantifiersRewriter::computeNNF( Node body ){ if( body.getKind()==NOT ){ if( body[0].getKind()==NOT ){ return computeNNF( body[0][0] ); }else if( isLiteral( body[0] ) ){ return body; }else{ std::vector< Node > children; Kind k = body[0].getKind(); if( body[0].getKind()==OR || body[0].getKind()==AND ){ k = body[0].getKind()==AND ? OR : AND; for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ Node nc = computeNNF( body[0][i].notNode() ); if( nc.getKind()==k ){ for( unsigned j=0; jmkNode( k, children ); } }else if( isLiteral( body ) ){ return body; }else{ std::vector< Node > children; bool childrenChanged = false; bool isAssoc = body.getKind()==AND || body.getKind()==OR; for( int i=0; i<(int)body.getNumChildren(); i++ ){ Node nc = computeNNF( body[i] ); if( isAssoc && nc.getKind()==body.getKind() ){ for( unsigned j=0; jmkNode( body.getKind(), children ); }else{ return body; } } } void QuantifiersRewriter::computeDtTesterIteSplit( Node n, std::map< Node, Node >& pcons, std::map< Node, std::map< int, Node > >& ncons, std::vector< Node >& conj ){ if( n.getKind()==ITE && n[0].getKind()==APPLY_TESTER && n[1].getType().isBoolean() ){ Trace("quantifiers-rewrite-ite-debug") << "Split tester condition : " << n << std::endl; Node x = n[0][0]; std::map< Node, Node >::iterator itp = pcons.find( x ); if( itp!=pcons.end() ){ Trace("quantifiers-rewrite-ite-debug") << "...condition already set " << itp->second << std::endl; computeDtTesterIteSplit( n[ itp->second==n[0] ? 1 : 2 ], pcons, ncons, conj ); }else{ Expr testerExpr = n[0].getOperator().toExpr(); int index = Datatype::indexOf( testerExpr ); std::map< int, Node >::iterator itn = ncons[x].find( index ); if( itn!=ncons[x].end() ){ Trace("quantifiers-rewrite-ite-debug") << "...condition negated " << itn->second << std::endl; computeDtTesterIteSplit( n[ 2 ], pcons, ncons, conj ); }else{ for( unsigned i=0; i<2; i++ ){ if( i==0 ){ pcons[x] = n[0]; }else{ pcons.erase( x ); ncons[x][index] = n[0].negate(); } computeDtTesterIteSplit( n[i+1], pcons, ncons, conj ); } ncons[x].erase( index ); } } }else{ Trace("quantifiers-rewrite-ite-debug") << "Return value : " << n << std::endl; std::vector< Node > children; children.push_back( n ); std::vector< Node > vars; //add all positive testers for( std::map< Node, Node >::iterator it = pcons.begin(); it != pcons.end(); ++it ){ children.push_back( it->second.negate() ); vars.push_back( it->first ); } //add all negative testers for( std::map< Node, std::map< int, Node > >::iterator it = ncons.begin(); it != ncons.end(); ++it ){ Node x = it->first; //only if we haven't settled on a positive tester if( std::find( vars.begin(), vars.end(), x )==vars.end() ){ //check if we have exhausted all options but one const Datatype& dt = DatatypeType(x.getType().toType()).getDatatype(); std::vector< Node > nchildren; int pos_cons = -1; for( int i=0; i<(int)dt.getNumConstructors(); i++ ){ std::map< int, Node >::iterator itt = it->second.find( i ); if( itt==it->second.end() ){ pos_cons = pos_cons==-1 ? i : -2; }else{ nchildren.push_back( itt->second.negate() ); } } if( pos_cons>=0 ){ const DatatypeConstructor& c = dt[pos_cons]; Expr tester = c.getTester(); children.push_back( NodeManager::currentNM()->mkNode( kind::APPLY_TESTER, Node::fromExpr( tester ), x ).negate() ); }else{ children.insert( children.end(), nchildren.begin(), nchildren.end() ); } } } //make condition/output pair Node c = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( OR, children ); conj.push_back( c ); } } int getEntailedCond( Node n, std::map< Node, bool >& currCond ){ std::map< Node, bool >::iterator it = currCond.find( n ); if( it!=currCond.end() ){ return it->second ? 1 : -1; }else if( n.getKind()==AND || n.getKind()==OR ){ bool hasZero = false; for( unsigned i=0; i& currCond, std::vector< Node >& new_cond, bool& conflict ) { std::map< Node, bool >::iterator it = currCond.find( n ); if( it==currCond.end() ){ Trace("quantifiers-rewrite-term-debug") << "cond : " << n << " -> " << pol << std::endl; new_cond.push_back( n ); currCond[n] = pol; return true; }else{ if( it->second!=pol ){ Trace("quantifiers-rewrite-term-debug") << "CONFLICTING cond : " << n << " -> " << pol << std::endl; conflict = true; } return false; } } void setEntailedCond( Node n, bool pol, std::map< Node, bool >& currCond, std::vector< Node >& new_cond, bool& conflict ) { if( ( n.getKind()==AND && pol ) || ( n.getKind()==OR && !pol ) ){ for( unsigned i=0; i1 ); if( pol ){ for( unsigned i=0; imkNode( APPLY_TESTER, Node::fromExpr( dt[i].getTester() ), n[0] ); addEntailedCond( t, false, currCond, new_cond, conflict ); } } }else{ if( dt.getNumConstructors()==2 ){ int oindex = 1-index; Node t = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[oindex].getTester() ), n[0] ); addEntailedCond( t, true, currCond, new_cond, conflict ); } } } } } void removeEntailedCond( std::map< Node, bool >& currCond, std::vector< Node >& new_cond, std::map< Node, Node >& cache ) { if( !new_cond.empty() ){ for( unsigned j=0; j& new_vars, std::vector< Node >& new_conds, Node q, QAttributes& qa ){ std::map< Node, bool > curr_cond; std::map< Node, Node > cache; std::map< Node, Node > icache; if( qa.isFunDef() ){ Node h = TermDb::getFunDefHead( q ); Assert( !h.isNull() ); // if it is a function definition, rewrite the body independently Node fbody = TermDb::getFunDefBody( q ); Assert( !body.isNull() ); Trace("quantifiers-rewrite-debug") << "Decompose " << h << " / " << fbody << " as function definition for " << q << "." << std::endl; Node r = computeProcessTerms2( fbody, true, true, curr_cond, 0, cache, icache, new_vars, new_conds ); return Rewriter::rewrite( NodeManager::currentNM()->mkNode( h.getType().isBoolean() ? IFF : EQUAL, h, r ) ); }else{ return computeProcessTerms2( body, true, true, curr_cond, 0, cache, icache, new_vars, new_conds ); } } Node QuantifiersRewriter::computeProcessTerms2( Node body, bool hasPol, bool pol, std::map< Node, bool >& currCond, int nCurrCond, std::map< Node, Node >& cache, std::map< Node, Node >& icache, std::vector< Node >& new_vars, std::vector< Node >& new_conds ) { Trace("quantifiers-rewrite-term-debug2") << "computeProcessTerms " << body << " " << hasPol << " " << pol << std::endl; Node ret; std::map< Node, Node >::iterator iti = cache.find( body ); if( iti!=cache.end() ){ ret = iti->second; Trace("quantifiers-rewrite-term-debug2") << "Return (cached) " << ret << " for " << body << std::endl; }else{ //only do context dependent processing up to depth 8 bool doCD = nCurrCond<8; bool changed = false; std::vector< Node > children; //set entailed conditions based on OR/AND std::map< int, std::vector< Node > > new_cond_children; if( doCD && ( body.getKind()==OR || body.getKind()==AND ) ){ nCurrCond = nCurrCond + 1; bool conflict = false; bool use_pol = body.getKind()==AND; for( unsigned j=0; jmkConst( !use_pol ); } } if( ret.isNull() ){ for( size_t i=0; i new_cond; bool conflict = false; if( doCD ){ if( Trace.isOn("quantifiers-rewrite-term-debug") ){ if( ( body.getKind()==ITE && i>0 ) || body.getKind()==OR || body.getKind()==AND ){ Trace("quantifiers-rewrite-term-debug") << "---rewrite " << body[i] << " under conditions:----" << std::endl; } } if( body.getKind()==ITE && i>0 ){ if( i==1 ){ nCurrCond = nCurrCond + 1; } setEntailedCond( children[0], i==1, currCond, new_cond, conflict ); //should not conflict (entailment check failed) Assert( !conflict ); } if( body.getKind()==OR || body.getKind()==AND ){ bool use_pol = body.getKind()==AND; //remove the current condition removeEntailedCond( currCond, new_cond_children[i], cache ); if( i>0 ){ //add the previous condition setEntailedCond( children[i-1], use_pol, currCond, new_cond_children[i-1], conflict ); } if( conflict ){ Trace("quantifiers-rewrite-term-debug") << "-------conflict, return " << !use_pol << std::endl; ret = NodeManager::currentNM()->mkConst( !use_pol ); } } if( !new_cond.empty() ){ cache.clear(); } if( Trace.isOn("quantifiers-rewrite-term-debug") ){ if( ( body.getKind()==ITE && i>0 ) || body.getKind()==OR || body.getKind()==AND ){ Trace("quantifiers-rewrite-term-debug") << "-------" << std::endl; } } } //do the recursive call on children if( !conflict ){ bool newHasPol; bool newPol; QuantPhaseReq::getPolarity( body, i, hasPol, pol, newHasPol, newPol ); Node nn = computeProcessTerms2( body[i], newHasPol, newPol, currCond, nCurrCond, cache, icache, new_vars, new_conds ); if( body.getKind()==ITE && i==0 ){ int res = getEntailedCond( nn, currCond ); Trace("quantifiers-rewrite-term-debug") << "Condition for " << body << " is " << nn << ", entailment check=" << res << std::endl; if( res==1 ){ ret = computeProcessTerms2( body[1], hasPol, pol, currCond, nCurrCond, cache, icache, new_vars, new_conds ); }else if( res==-1 ){ ret = computeProcessTerms2( body[2], hasPol, pol, currCond, nCurrCond, cache, icache, new_vars, new_conds ); } } children.push_back( nn ); changed = changed || nn!=body[i]; } //clean up entailed conditions removeEntailedCond( currCond, new_cond, cache ); if( !ret.isNull() ){ break; } } //make return value if( ret.isNull() ){ if( changed ){ if( body.getMetaKind() == kind::metakind::PARAMETERIZED ){ children.insert( children.begin(), body.getOperator() ); } ret = NodeManager::currentNM()->mkNode( body.getKind(), children ); }else{ ret = body; } } } //clean up entailed conditions if( body.getKind()==OR || body.getKind()==AND ){ for( unsigned j=0; jsecond; }else{ Node prev = ret; if( ret.getKind()==EQUAL && options::iteLiftQuant()!=ITE_LIFT_QUANT_MODE_NONE ){ for( size_t i=0; i<2; i++ ){ if( ret[i].getKind()==ITE ){ Node no = i==0 ? ret[1] : ret[0]; if( no.getKind()!=ITE ){ bool doRewrite = options::iteLiftQuant()==ITE_LIFT_QUANT_MODE_ALL; std::vector< Node > children; children.push_back( ret[i][0] ); for( size_t j=1; j<=2; j++ ){ //check if it rewrites to a constant Node nn = NodeManager::currentNM()->mkNode( EQUAL, no, ret[i][j] ); nn = Rewriter::rewrite( nn ); children.push_back( nn ); if( nn.isConst() ){ doRewrite = true; } } if( doRewrite ){ ret = NodeManager::currentNM()->mkNode( ITE, children ); break; } } } } /* ITE lifting if( ret.getKind()==ITE ){ TypeNode ite_t = ret[1].getType(); if( !ite_t.isBoolean() ){ ite_t = TypeNode::leastCommonTypeNode( ite_t, ret[2].getType() ); Node ite_v = NodeManager::currentNM()->mkBoundVar(ite_t); new_vars.push_back( ite_v ); Node cond = NodeManager::currentNM()->mkNode(kind::ITE, ret[0], ite_v.eqNode( ret[1] ), ite_v.eqNode( ret[2] ) ); new_conds.push_back( cond.negate() ); ret = ite_v; } */ }else if( options::elimExtArithQuant() ){ if( ret.getKind()==INTS_DIVISION_TOTAL || ret.getKind()==INTS_MODULUS_TOTAL ){ Node num = ret[0]; Node den = ret[1]; if(den.isConst()) { const Rational& rat = den.getConst(); Assert(!num.isConst()); if(rat != 0) { Node intVar = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType()); new_vars.push_back( intVar ); Node cond; if(rat > 0) { cond = NodeManager::currentNM()->mkNode(kind::AND, NodeManager::currentNM()->mkNode(kind::LEQ, NodeManager::currentNM()->mkNode(kind::MULT, den, intVar), num), NodeManager::currentNM()->mkNode(kind::LT, num, NodeManager::currentNM()->mkNode(kind::MULT, den, NodeManager::currentNM()->mkNode(kind::PLUS, intVar, NodeManager::currentNM()->mkConst(Rational(1)))))); } else { cond = NodeManager::currentNM()->mkNode(kind::AND, NodeManager::currentNM()->mkNode(kind::LEQ, NodeManager::currentNM()->mkNode(kind::MULT, den, intVar), num), NodeManager::currentNM()->mkNode(kind::LT, num, NodeManager::currentNM()->mkNode(kind::MULT, den, NodeManager::currentNM()->mkNode(kind::PLUS, intVar, NodeManager::currentNM()->mkConst(Rational(-1)))))); } new_conds.push_back( cond.negate() ); if( ret.getKind()==INTS_DIVISION_TOTAL ){ ret = intVar; }else{ ret = NodeManager::currentNM()->mkNode(kind::MINUS, num, NodeManager::currentNM()->mkNode(kind::MULT, den, intVar)); } } } }else if( ret.getKind()==TO_INTEGER || ret.getKind()==IS_INTEGER ){ Node intVar = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType()); new_vars.push_back( intVar ); new_conds.push_back(NodeManager::currentNM()->mkNode(kind::AND, NodeManager::currentNM()->mkNode(kind::LT, NodeManager::currentNM()->mkNode(kind::MINUS, ret[0], NodeManager::currentNM()->mkConst(Rational(1))), intVar), NodeManager::currentNM()->mkNode(kind::LEQ, intVar, ret[0])).negate()); if( ret.getKind()==TO_INTEGER ){ ret = intVar; }else{ ret = ret[0].eqNode( intVar ); } } } icache[prev] = ret; return ret; } } bool QuantifiersRewriter::isConditionalVariableElim( Node n, int pol ){ if( n.getKind()==NOT ){ return isConditionalVariableElim( n[0], -pol ); }else if( ( n.getKind()==AND && pol>=0 ) || ( n.getKind()==OR && pol<=0 ) ){ pol = n.getKind()==AND ? 1 : -1; for( unsigned i=0; i pcons; std::map< Node, std::map< int, Node > > ncons; std::vector< Node > conj; computeDtTesterIteSplit( body, pcons, ncons, conj ); Assert( !conj.empty() ); if( conj.size()>1 ){ Trace("quantifiers-rewrite-ite") << "*** Split ITE (datatype tester) " << body << " into : " << std::endl; for( unsigned i=0; imkNode( AND, conj ); } } if( options::condVarSplitQuant() ){ if( body.getKind()==ITE || ( body.getKind()==IFF && options::condVarSplitQuantAgg() ) ){ Assert( !qa.isFunDef() ); Trace("quantifiers-rewrite-debug") << "Conditional var elim split " << body << "?" << std::endl; bool do_split = false; unsigned index_max = body.getKind()==ITE ? 0 : 1; for( unsigned index=0; index<=index_max; index++ ){ if( isConditionalVariableElim( body[index] ) ){ do_split = true; break; } } if( do_split ){ Node pos; Node neg; if( body.getKind()==ITE ){ pos = NodeManager::currentNM()->mkNode( OR, body[0].negate(), body[1] ); neg = NodeManager::currentNM()->mkNode( OR, body[0], body[2] ); }else{ pos = NodeManager::currentNM()->mkNode( OR, body[0].negate(), body[1] ); neg = NodeManager::currentNM()->mkNode( OR, body[0], body[1].negate() ); } Trace("quantifiers-rewrite-debug") << "*** Split (conditional variable eq) " << body << " into : " << std::endl; Trace("quantifiers-rewrite-debug") << " " << pos << std::endl; Trace("quantifiers-rewrite-debug") << " " << neg << std::endl; return NodeManager::currentNM()->mkNode( AND, pos, neg ); } }else if( body.getKind()==OR && options::condVarSplitQuantAgg() ){ std::vector< Node > bchildren; std::vector< Node > nchildren; for( unsigned i=0; i children; for( unsigned j=0; jmkNode( AND, children ) ); } split = true; } } } if( !split ){ bchildren.push_back( body[i] ); } } if( !nchildren.empty() ){ Trace("quantifiers-rewrite-debug") << "*** Split (conditional variable eq) " << body << " into : " << std::endl; for( unsigned i=0; imkNode( OR, bchildren ); Trace("quantifiers-rewrite-debug") << " " << nchildren[i] << std::endl; bchildren.pop_back(); } return NodeManager::currentNM()->mkNode( AND, nchildren ); } } } return body; } bool QuantifiersRewriter::isVariableElim( Node v, Node s, std::map< Node, std::vector< int > >& var_parent ) { if( TermDb::containsTerm( s, v ) || !s.getType().isSubtypeOf( v.getType() ) ){ return false; }else{ if( !var_parent.empty() ){ std::map< Node, std::vector< int > >::iterator it = var_parent.find( v ); if( it!=var_parent.end() ){ Assert( !it->second.empty() ); int id = getPurifyId( s ); return it->second.size()==1 && it->second[0]==id; } } return true; } } bool QuantifiersRewriter::computeVariableElimLit( Node lit, bool pol, std::vector< Node >& args, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< int > >& var_parent ) { if( lit.getKind()==EQUAL && pol ){ for( unsigned i=0; i<2; i++ ){ std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), lit[i] ); if( ita!=args.end() ){ if( isVariableElim( lit[i], lit[1-i], var_parent ) ){ Trace("var-elim-quant") << "Variable eliminate based on equality : " << lit[i] << " -> " << lit[1-i] << std::endl; vars.push_back( lit[i] ); subs.push_back( lit[1-i] ); args.erase( ita ); return true; } } } //for arithmetic, solve the equality if( lit[0].getType().isReal() ){ std::map< Node, Node > msum; if( QuantArith::getMonomialSumLit( lit, msum ) ){ for( std::map< Node, Node >::iterator itm = msum.begin(); itm != msum.end(); ++itm ){ std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), itm->first ); if( ita!=args.end() ){ Node veq_c; Node val; int ires = QuantArith::isolate( itm->first, msum, veq_c, val, EQUAL ); if( ires!=0 && veq_c.isNull() && isVariableElim( itm->first, val, var_parent ) ){ Trace("var-elim-quant") << "Variable eliminate based on solved equality : " << itm->first << " -> " << val << std::endl; vars.push_back( itm->first ); subs.push_back( val ); args.erase( ita ); return true; } } } } } }else if( lit.getKind()==APPLY_TESTER && pol && lit[0].getKind()==BOUND_VARIABLE ){ Trace("var-elim-dt") << "Expand datatype variable based on : " << lit << std::endl; std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), lit[0] ); if( ita!=args.end() ){ vars.push_back( lit[0] ); Expr testerExpr = lit.getOperator().toExpr(); int index = Datatype::indexOf( testerExpr ); const Datatype& dt = Datatype::datatypeOf(testerExpr); const DatatypeConstructor& c = dt[index]; std::vector< Node > newChildren; newChildren.push_back( Node::fromExpr( c.getConstructor() ) ); std::vector< Node > newVars; for( unsigned j=0; jmkBoundVar( tn ); newChildren.push_back( v ); newVars.push_back( v ); } subs.push_back( NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, newChildren ) ); Trace("var-elim-dt") << "...apply substitution " << subs[0] << "/" << vars[0] << std::endl; args.erase( ita ); args.insert( args.end(), newVars.begin(), newVars.end() ); return true; } }else if( lit.getKind()==BOUND_VARIABLE ){ std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), lit ); if( ita!=args.end() ){ Trace("var-elim-bool") << "Variable eliminate : " << lit << std::endl; vars.push_back( lit ); subs.push_back( NodeManager::currentNM()->mkConst( pol ) ); args.erase( ita ); return true; } } return false; } Node QuantifiersRewriter::computeVarElimination2( Node body, std::vector< Node >& args, QAttributes& qa, std::map< Node, std::vector< int > >& var_parent ){ Trace("var-elim-quant-debug") << "Compute var elimination for " << body << std::endl; QuantPhaseReq qpr( body ); std::vector< Node > vars; std::vector< Node > subs; for( std::map< Node, bool >::iterator it = qpr.d_phase_reqs.begin(); it != qpr.d_phase_reqs.end(); ++it ){ //Notice() << " " << it->first << " -> " << ( it->second ? "true" : "false" ) << std::endl; if( ( it->first.getKind()==EQUAL && it->second && options::varElimQuant() ) || ( it->first.getKind()==APPLY_TESTER && it->second && it->first[0].getKind()==BOUND_VARIABLE && options::dtVarExpandQuant() ) || ( it->first.getKind()==BOUND_VARIABLE && options::varElimQuant() ) ){ if( computeVariableElimLit( it->first, it->second, args, vars, subs, var_parent ) ){ break; } } } if( !vars.empty() ){ Trace("var-elim-quant-debug") << "VE " << vars.size() << "/" << args.size() << std::endl; //remake with eliminated nodes body = body.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); body = Rewriter::rewrite( body ); if( !qa.d_ipl.isNull() ){ qa.d_ipl = qa.d_ipl.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); } Trace("var-elim-quant") << "Return " << body << std::endl; } return body; } Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& args, QAttributes& qa ){ //the parent id's for each variable, if using purifyQuant std::map< Node, std::vector< int > > var_parent; if( options::purifyQuant() ){ body = computePurify( body, args, var_parent ); } if( options::varElimQuant() || options::dtVarExpandQuant() ){ Node prev; do{ prev = body; body = computeVarElimination2( body, args, qa, var_parent ); }while( prev!=body && !args.empty() ); } return body; } Node QuantifiersRewriter::computeClause( Node n ){ Assert( isClause( n ) ); if( isLiteral( n ) ){ return n; }else{ NodeBuilder<> t(OR); if( n.getKind()==NOT ){ if( n[0].getKind()==NOT ){ return computeClause( n[0][0] ); }else{ //De-Morgan's law Assert( n[0].getKind()==AND ); for( int i=0; i<(int)n[0].getNumChildren(); i++ ){ Node nn = computeClause( n[0][i].notNode() ); addNodeToOrBuilder( nn, t ); } } }else{ for( int i=0; i<(int)n.getNumChildren(); i++ ){ Node nn = computeClause( n[i] ); addNodeToOrBuilder( nn, t ); } } return t.constructNode(); } } Node QuantifiersRewriter::computeCNF( Node n, std::vector< Node >& args, NodeBuilder<>& defs, bool forcePred ){ if( isLiteral( n ) ){ return n; }else if( !forcePred && isClause( n ) ){ return computeClause( n ); }else{ Kind k = n.getKind(); NodeBuilder<> t(k); for( int i=0; i<(int)n.getNumChildren(); i++ ){ Node nc = n[i]; Node ncnf = computeCNF( nc, args, defs, k!=OR ); if( k==OR ){ addNodeToOrBuilder( ncnf, t ); }else{ t << ncnf; } } if( !forcePred && k==OR ){ return t.constructNode(); }else{ //compute the free variables Node nt = t; std::vector< Node > activeArgs; computeArgVec( args, activeArgs, nt ); std::vector< TypeNode > argTypes; for( int i=0; i<(int)activeArgs.size(); i++ ){ argTypes.push_back( activeArgs[i].getType() ); } //create the predicate Assert( argTypes.size()>0 ); TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, NodeManager::currentNM()->booleanType() ); std::stringstream ss; ss << "cnf_" << n.getKind() << "_" << n.getId(); Node op = NodeManager::currentNM()->mkSkolem( ss.str(), typ, "was created by the quantifiers rewriter" ); std::vector< Node > predArgs; predArgs.push_back( op ); predArgs.insert( predArgs.end(), activeArgs.begin(), activeArgs.end() ); Node pred = NodeManager::currentNM()->mkNode( APPLY_UF, predArgs ); Trace("quantifiers-rewrite-cnf-debug") << "Made predicate " << pred << " for " << nt << std::endl; //create the bound var list Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, activeArgs ); //now, look at the structure of nt if( nt.getKind()==NOT ){ //case for NOT for( int i=0; i<2; i++ ){ NodeBuilder<> tt(OR); tt << ( i==0 ? nt[0].notNode() : nt[0] ); tt << ( i==0 ? pred.notNode() : pred ); defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); } }else if( nt.getKind()==OR ){ //case for OR for( int i=0; i<(int)nt.getNumChildren(); i++ ){ NodeBuilder<> tt(OR); tt << nt[i].notNode() << pred; defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); } NodeBuilder<> tt(OR); for( int i=0; i<(int)nt.getNumChildren(); i++ ){ tt << nt[i]; } tt << pred.notNode(); defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); }else if( nt.getKind()==AND ){ //case for AND for( int i=0; i<(int)nt.getNumChildren(); i++ ){ NodeBuilder<> tt(OR); tt << nt[i] << pred.notNode(); defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); } NodeBuilder<> tt(OR); for( int i=0; i<(int)nt.getNumChildren(); i++ ){ tt << nt[i].notNode(); } tt << pred; defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); }else if( nt.getKind()==IFF ){ //case for IFF for( int i=0; i<4; i++ ){ NodeBuilder<> tt(OR); tt << ( ( i==0 || i==3 ) ? nt[0].notNode() : nt[0] ); tt << ( ( i==1 || i==3 ) ? nt[1].notNode() : nt[1] ); tt << ( ( i==0 || i==1 ) ? pred.notNode() : pred ); defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); } }else if( nt.getKind()==ITE ){ //case for ITE for( int j=1; j<=2; j++ ){ for( int i=0; i<2; i++ ){ NodeBuilder<> tt(OR); tt << ( ( j==1 ) ? nt[0].notNode() : nt[0] ); tt << ( ( i==1 ) ? nt[j].notNode() : nt[j] ); tt << ( ( i==0 ) ? pred.notNode() : pred ); defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); } } for( int i=0; i<2; i++ ){ NodeBuilder<> tt(OR); tt << ( i==0 ? nt[1].notNode() : nt[1] ); tt << ( i==0 ? nt[2].notNode() : nt[2] ); tt << ( i==1 ? pred.notNode() : pred ); defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); } }else{ Notice() << "Unhandled Quantifiers CNF: " << nt << std::endl; } return pred; } } } Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, bool pol ){ if( body.getKind()==FORALL ){ if( pol && ( options::prenexQuant()==PRENEX_ALL || body.getNumChildren()==2 ) ){ std::vector< Node > terms; std::vector< Node > subs; //for doing prenexing of same-signed quantifiers //must rename each variable that already exists for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ //if( std::find( args.begin(), args.end(), body[0][i] )!=args.end() ){ terms.push_back( body[0][i] ); subs.push_back( NodeManager::currentNM()->mkBoundVar( body[0][i].getType() ) ); } args.insert( args.end(), subs.begin(), subs.end() ); Node newBody = body[1]; newBody = newBody.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() ); Debug("quantifiers-substitute-debug") << "Did substitute have an effect" << (body[1] != newBody) << body[1] << " became " << newBody << endl; return newBody; }else{ return body; } }else{ Assert( body.getKind()!=EXISTS ); bool childrenChanged = false; std::vector< Node > newChildren; for( int i=0; i<(int)body.getNumChildren(); i++ ){ bool newHasPol; bool newPol; QuantPhaseReq::getPolarity( body, i, true, pol, newHasPol, newPol ); if( newHasPol ){ Node n = computePrenex( body[i], args, newPol ); newChildren.push_back( n ); if( n!=body[i] ){ childrenChanged = true; } }else{ newChildren.push_back( body[i] ); } } if( childrenChanged ){ if( body.getKind()==NOT && newChildren[0].getKind()==NOT ){ return newChildren[0][0]; }else{ return NodeManager::currentNM()->mkNode( body.getKind(), newChildren ); } }else{ return body; } } } Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node body ) { Assert( body.getKind()==OR ); size_t var_found_count = 0; size_t eqc_count = 0; size_t eqc_active = 0; std::map< Node, int > var_to_eqc; std::map< int, std::vector< Node > > eqc_to_var; std::map< int, std::vector< Node > > eqc_to_lit; std::vector lits; for( unsigned i=0; i lit_args; computeArgVec( args, lit_args, n ); if (lit_args.empty()) { lits.push_back(n); }else { //collect the equivalence classes this literal belongs to, and the new variables it contributes std::vector< int > eqcs; std::vector< Node > lit_new_args; //for each variable in literal for( unsigned j=0; j1 || !lits.empty() ){ Trace("clause-split-debug") << "Split clause " << f << std::endl; Trace("clause-split-debug") << " Ground literals: " << std::endl; for( size_t i=0; i >::iterator it = eqc_to_lit.begin(); it != eqc_to_lit.end(); ++it ){ Trace("clause-split-debug") << " Literals: " << std::endl; for (size_t i=0; isecond.size(); i++) { Trace("clause-split-debug") << " " << it->second[i] << std::endl; } int eqc = it->first; Trace("clause-split-debug") << " Variables: " << std::endl; for (size_t i=0; imkNode( BOUND_VAR_LIST, eqc_to_var[eqc]); Node body = it->second.size()==1 ? it->second[0] : NodeManager::currentNM()->mkNode( OR, it->second ); Node fa = NodeManager::currentNM()->mkNode( FORALL, bvl, body ); lits.push_back(fa); } Assert( lits.size()>1 ); Node nf = NodeManager::currentNM()->mkNode(OR,lits); Trace("clause-split-debug") << "Made node : " << nf << std::endl; return nf; } return f; } Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, QAttributes& qa ){ std::vector< Node > activeArgs; //if cegqi is on, may be synthesis conjecture, in which case we want to keep all variables if( options::ceGuidedInst() && qa.d_sygus ){ activeArgs.insert( activeArgs.end(), args.begin(), args.end() ); }else{ computeArgVec2( args, activeArgs, body, qa.d_ipl ); } if( activeArgs.empty() ){ return body; }else{ std::vector< Node > children; children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, activeArgs ) ); children.push_back( body ); if( !qa.d_ipl.isNull() ){ children.push_back( qa.d_ipl ); } return NodeManager::currentNM()->mkNode( kind::FORALL, children ); } } Node QuantifiersRewriter::computeMiniscoping( Node f, std::vector< Node >& args, Node body, QAttributes& qa ){ if( body.getKind()==FORALL ){ //combine arguments std::vector< Node > newArgs; for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ newArgs.push_back( body[0][i] ); } newArgs.insert( newArgs.end(), args.begin(), args.end() ); return mkForAll( newArgs, body[ 1 ], qa ); }else{ if( body.getKind()==NOT ){ //push not downwards if( body[0].getKind()==NOT ){ return computeMiniscoping( f, args, body[0][0], qa ); }else if( body[0].getKind()==AND ){ if( options::miniscopeQuantFreeVar() ){ NodeBuilder<> t(kind::OR); for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ t << ( body[0][i].getKind()==NOT ? body[0][i][0] : body[0][i].notNode() ); } return computeMiniscoping( f, args, t.constructNode(), qa ); } }else if( body[0].getKind()==OR ){ if( options::miniscopeQuant() ){ NodeBuilder<> t(kind::AND); for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ Node trm = body[0][i].negate(); t << computeMiniscoping( f, args, trm, qa ); } return t.constructNode(); } } }else if( body.getKind()==AND ){ if( options::miniscopeQuant() ){ //break apart NodeBuilder<> t(kind::AND); for( unsigned i=0; i body_split(kind::OR); NodeBuilder<> tb(kind::OR); for( unsigned i=0; i0 ){ newBody = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb; body_split << mkForAll( args, newBody, qa ); return body_split.getNumChildren()==1 ? body_split.getChild( 0 ) : body_split; } } } } //if( body==f[1] ){ // return f; //}else{ return mkForAll( args, body, qa ); //} } Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& args, Node body ){ std::map< Node, std::vector< Node > > varLits; std::map< Node, std::vector< Node > > litVars; if( body.getKind()==OR ){ Trace("ag-miniscope") << "compute aggressive miniscoping on " << body << std::endl; for( size_t i=0; i activeArgs; computeArgVec( args, activeArgs, body[i] ); for (unsigned j=0; j >::iterator it = varLits.begin(); it != varLits.end(); ++it ){ if( bestVar.isNull() || varLits[bestVar].size()>it->second.size() ){ bestVar = it->first; } } Trace("ag-miniscope-debug") << "Best variable " << bestVar << " occurs in " << varLits[bestVar].size() << "/ " << body.getNumChildren() << " literals." << std::endl; if( !bestVar.isNull() && varLits[bestVar].size() qlit1; qlit1.insert( qlit1.begin(), varLits[bestVar].begin(), varLits[bestVar].end() ); std::vector< Node > qlitt; //for all literals not containing bestVar for( size_t i=0; i qvl1; std::vector< Node > qvl2; std::vector< Node > qvsh; for( unsigned i=0; i qlitsh; std::vector< Node > qlit2; for( size_t i=0; imkNode( OR, qlit1 ); n1 = computeAggressiveMiniscoping( qvl1, n1 ); qlitsh.push_back( n1 ); if( !qlit2.empty() ){ Node n2 = qlit2.size()==1 ? qlit2[0] : NodeManager::currentNM()->mkNode( OR, qlit2 ); n2 = computeAggressiveMiniscoping( qvl2, n2 ); qlitsh.push_back( n2 ); } Node n = NodeManager::currentNM()->mkNode( OR, qlitsh ); if( !qvsh.empty() ){ Node bvl = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, qvsh); n = NodeManager::currentNM()->mkNode( FORALL, bvl, n ); } Trace("ag-miniscope") << "Return " << n << " for " << body << std::endl; return n; } } QAttributes qa; return mkForAll( args, body, qa ); } bool QuantifiersRewriter::doOperation( Node f, int computeOption, QAttributes& qa ){ bool is_std = !qa.d_sygus && !qa.d_quant_elim && !qa.isFunDef(); if( computeOption==COMPUTE_ELIM_SYMBOLS ){ return true; }else if( computeOption==COMPUTE_MINISCOPING ){ return is_std; }else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){ return options::aggressiveMiniscopeQuant() && is_std; }else if( computeOption==COMPUTE_NNF ){ return options::nnfQuant(); }else if( computeOption==COMPUTE_PROCESS_TERMS ){ return true; //return options::iteLiftQuant()!=ITE_LIFT_QUANT_MODE_NONE || options::iteCondVarSplitQuant(); }else if( computeOption==COMPUTE_COND_SPLIT ){ return ( options::iteDtTesterSplitQuant() || options::condVarSplitQuant() ) && is_std; }else if( computeOption==COMPUTE_PRENEX ){ return options::prenexQuant()!=PRENEX_NONE && !options::aggressiveMiniscopeQuant(); }else if( computeOption==COMPUTE_VAR_ELIMINATION ){ return ( options::varElimQuant() || options::dtVarExpandQuant() || options::purifyQuant() ) && is_std; //}else if( computeOption==COMPUTE_CNF ){ // return options::cnfQuant(); }else if( computeOption==COMPUTE_PURIFY_EXPAND ){ return options::purifyQuant(); }else{ return false; } } //general method for computing various rewrites Node QuantifiersRewriter::computeOperation( Node f, int computeOption, QAttributes& qa ){ Trace("quantifiers-rewrite-debug") << "Compute operation " << computeOption << " on " << f << std::endl; std::vector< Node > args; for( unsigned i=0; i new_conds; n = computeProcessTerms( n, args, new_conds, f, qa ); if( !new_conds.empty() ){ new_conds.push_back( n ); n = NodeManager::currentNM()->mkNode( OR, new_conds ); } }else if( computeOption==COMPUTE_COND_SPLIT ){ n = computeCondSplit( n, qa ); }else if( computeOption==COMPUTE_PRENEX ){ n = computePrenex( n, args, true ); }else if( computeOption==COMPUTE_VAR_ELIMINATION ){ n = computeVarElimination( n, args, qa ); //}else if( computeOption==COMPUTE_CNF ){ //n = computeCNF( n, args, defs, false ); //ipl = Node::null(); }else if( computeOption==COMPUTE_PURIFY_EXPAND ){ std::vector< Node > conj; computePurifyExpand( n, conj, args, qa ); if( !conj.empty() ){ return conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( AND, conj ); }else{ return f; } } Trace("quantifiers-rewrite-debug") << "Compute Operation: return " << n << ", " << args.size() << std::endl; if( f[1]==n && args.size()==f[0].getNumChildren() ){ return f; }else{ if( args.empty() ){ return n; }else{ std::vector< Node > children; children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args ) ); children.push_back( n ); if( !qa.d_ipl.isNull() ){ children.push_back( qa.d_ipl ); } return NodeManager::currentNM()->mkNode(kind::FORALL, children ); } } } Node QuantifiersRewriter::rewriteRewriteRule( Node r ) { Kind rrkind = r[2].getKind(); //guards, pattern, body // Replace variables by Inst_* variable and tag the terms that contain them std::vector vars; vars.reserve(r[0].getNumChildren()); for( Node::const_iterator v = r[0].begin(); v != r[0].end(); ++v ){ vars.push_back(*v); }; // Body/Remove_term/Guards/Triggers Node body = r[2][1]; TNode new_terms = r[2][1]; std::vector guards; std::vector pattern; Node true_node = NodeManager::currentNM()->mkConst(true); // shortcut TNode head = r[2][0]; switch(rrkind){ case kind::RR_REWRITE: // Equality pattern.push_back( head ); if( head.getType().isBoolean() ){ body = head.iffNode(body); }else{ body = head.eqNode(body); } break; case kind::RR_REDUCTION: case kind::RR_DEDUCTION: // Add head to guards and pattern switch(head.getKind()){ case kind::AND: for( unsigned i = 0; i= 3 ){ for( unsigned i=0; i forallB(kind::FORALL); forallB << r[0]; Node gg = guards.size()==0 ? true_node : ( guards.size()==1 ? guards[0] : NodeManager::currentNM()->mkNode( AND, guards ) ); gg = NodeManager::currentNM()->mkNode( OR, gg.negate(), body ); gg = Rewriter::rewrite( gg ); forallB << gg; NodeBuilder<> patternB(kind::INST_PATTERN); patternB.append(pattern); NodeBuilder<> patternListB(kind::INST_PATTERN_LIST); //the entire rewrite rule is the first pattern if( options::quantRewriteRules() ){ patternListB << NodeManager::currentNM()->mkNode( INST_ATTRIBUTE, r ); } patternListB << static_cast(patternB); forallB << static_cast(patternListB); Node rn = (Node) forallB; return rn; } struct ContainsQuantAttributeId {}; typedef expr::Attribute ContainsQuantAttribute; // check if the given node contains a universal quantifier bool QuantifiersRewriter::containsQuantifiers(Node n) { if( n.hasAttribute(ContainsQuantAttribute()) ){ return n.getAttribute(ContainsQuantAttribute())==1; } else if(n.getKind() == kind::FORALL) { return true; } else { bool cq = false; for( unsigned i = 0; i < n.getNumChildren(); ++i ){ if( containsQuantifiers(n[i]) ){ cq = true; break; } } ContainsQuantAttribute cqa; n.setAttribute(cqa, cq ? 1 : 0); return cq; } } Node QuantifiersRewriter::preSkolemizeQuantifiers( Node n, bool polarity, std::vector< TypeNode >& fvTypes, std::vector< TNode >& fvs ){ Trace("pre-sk") << "Pre-skolem " << n << " " << polarity << " " << fvs.size() << endl; if( n.getKind()==kind::NOT ){ Node nn = preSkolemizeQuantifiers( n[0], !polarity, fvTypes, fvs ); return nn.negate(); }else if( n.getKind()==kind::FORALL ){ if( polarity ){ if( options::preSkolemQuant() && options::preSkolemQuantNested() ){ vector< Node > children; children.push_back( n[0] ); //add children to current scope std::vector< TypeNode > fvt; std::vector< TNode > fvss; fvt.insert( fvt.begin(), fvTypes.begin(), fvTypes.end() ); fvss.insert( fvss.begin(), fvs.begin(), fvs.end() ); for( int i=0; i<(int)n[0].getNumChildren(); i++ ){ fvt.push_back( n[0][i].getType() ); fvss.push_back( n[0][i] ); } //process body children.push_back( preSkolemizeQuantifiers( n[1], polarity, fvt, fvss ) ); if( n.getNumChildren()==3 ){ children.push_back( n[2] ); } //return processed quantifier return NodeManager::currentNM()->mkNode( kind::FORALL, children ); } }else{ //process body Node nn = preSkolemizeQuantifiers( n[1], polarity, fvTypes, fvs ); std::vector< Node > sk; Node sub; std::vector< unsigned > sub_vars; //return skolemized body return TermDb::mkSkolemizedBody( n, nn, fvTypes, fvs, sk, sub, sub_vars ); } }else{ //check if it contains a quantifier as a subterm //if so, we will write this node if( containsQuantifiers( n ) ){ if( ( n.getKind()==kind::ITE && n.getType().isBoolean() ) || n.getKind()==kind::IFF ){ if( options::preSkolemQuantAgg() ){ Node nn; //must remove structure if( n.getKind()==kind::ITE ){ nn = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n[1] ), NodeManager::currentNM()->mkNode( kind::OR, n[0], n[2] ) ); }else if( n.getKind()==kind::IFF || n.getKind()==kind::XOR ){ nn = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n.getKind()==kind::XOR ? n[1].notNode() : n[1] ), NodeManager::currentNM()->mkNode( kind::OR, n[0], n.getKind()==kind::XOR ? n[1] : n[1].notNode() ) ); }else if( n.getKind()==kind::IMPLIES ){ nn = NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n[1] ); } return preSkolemizeQuantifiers( nn, polarity, fvTypes, fvs ); } }else if( n.getKind()==kind::AND || n.getKind()==kind::OR ){ vector< Node > children; for( int i=0; i<(int)n.getNumChildren(); i++ ){ children.push_back( preSkolemizeQuantifiers( n[i], polarity, fvTypes, fvs ) ); } return NodeManager::currentNM()->mkNode( n.getKind(), children ); } } } return n; } Node QuantifiersRewriter::preprocess( Node n, bool isInst ) { Node prev = n; if( options::preSkolemQuant() ){ if( !isInst || !options::preSkolemQuantNested() ){ Trace("quantifiers-preprocess-debug") << "Pre-skolemize " << n << "..." << std::endl; //apply pre-skolemization to existential quantifiers std::vector< TypeNode > fvTypes; std::vector< TNode > fvs; n = quantifiers::QuantifiersRewriter::preSkolemizeQuantifiers( prev, true, fvTypes, fvs ); } } if( n!=prev ){ Trace("quantifiers-preprocess") << "Preprocess " << prev<< std::endl; Trace("quantifiers-preprocess") << "..returned " << n << std::endl; } return n; } Node QuantifiersRewriter::computePurify2( Node body, std::vector< Node >& args, std::map< Node, Node >& visited, std::map< Node, Node >& var_to_term, std::map< Node, std::vector< int > >& var_parent, int parentId ){ std::map< Node, Node >::iterator it = visited.find( body ); if( it!=visited.end() ){ return it->second; }else{ Node ret = body; if( body.getNumChildren()>0 && body.getKind()!=FORALL && TermDb::hasBoundVarAttr( ret ) ){ std::vector< Node > children; bool childrenChanged = false; int id = getPurifyId( body ); for( unsigned i=0; imkNode( body.getKind(), children ); } if( parentId!=0 && parentId!=id ){ Node v = NodeManager::currentNM()->mkBoundVar( ret.getType() ); var_to_term[v] = Rewriter::rewrite( v.eqNode( ret ) ); ret = v; args.push_back( v ); } } visited[body] = ret; return ret; } } Node QuantifiersRewriter::computePurify( Node body, std::vector< Node >& args, std::map< Node, std::vector< int > >& var_parent ) { std::map< Node, Node > visited; std::map< Node, Node > var_to_term; Node pbody = computePurify2( body, args, visited, var_to_term, var_parent, 0 ); if( pbody==body ){ return body; }else{ Trace("quantifiers-rewrite-purify") << "Purify : " << body << std::endl; Trace("quantifiers-rewrite-purify") << " Got : " << pbody << std::endl; for( std::map< Node, Node >::iterator it = var_to_term.begin(); it != var_to_term.end(); ++it ){ Trace("quantifiers-rewrite-purify") << " " << it->first << " : " << it->second << std::endl; } Trace("quantifiers-rewrite-purify") << "Variable parents : " << std::endl; for( std::map< Node, std::vector< int > >::iterator it = var_parent.begin(); it != var_parent.end(); ++it ){ Trace("quantifiers-rewrite-purify") << " " << it->first << " -> "; for( unsigned i=0; isecond.size(); i++ ){ Trace("quantifiers-rewrite-purify") << it->second[i] << " "; } Trace("quantifiers-rewrite-purify") << std::endl; } Trace("quantifiers-rewrite-purify") << std::endl; std::vector< Node > disj; for( std::map< Node, Node >::iterator it = var_to_term.begin(); it != var_to_term.end(); ++it ){ disj.push_back( it->second.negate() ); } Node res; if( disj.empty() ){ res = pbody; }else{ disj.push_back( pbody ); res = NodeManager::currentNM()->mkNode( OR, disj ); } Trace("quantifiers-rewrite-purify") << "Constructed : " << res << std::endl << std::endl; return res; } } void QuantifiersRewriter::computePurifyExpand( Node body, std::vector< Node >& conj, std::vector< Node >& args, QAttributes& qa ) { if( body.getKind()==OR ){ Trace("quantifiers-rewrite-purify-exp") << "Purify expansion : " << body << std::endl; std::map< int, std::vector< Node > > disj; std::map< int, std::vector< Node > > fvs; for( unsigned i=0; imkNode( INST_ATTRIBUTE, body ); } }