Node CandidateGeneratorQEAll::getNextCandidate() { while( !d_eq.isFinished() ){ TNode n = (*d_eq); ++d_eq; if( n.getType().isSubtypeOf( d_match_pattern_type ) ){ TNode nh = d_qe->getTermDatabase()->getEligibleTermInEqc( n ); if( !nh.isNull() ){ if( options::instMaxLevel()!=-1 || options::lteRestrictInstClosure() ){ nh = d_qe->getEqualityQuery()->getInternalRepresentative( nh, d_f, d_index ); //don't consider this if already the instantiation is ineligible if( !d_qe->getTermDatabase()->isTermEligibleForInstantiation( nh, d_f, false ) ){ nh = Node::null(); } } if( !nh.isNull() ){ d_firstTime = false; //an equivalence class with the same type as the pattern, return it return nh; } } } } if( d_firstTime ){ Assert( d_qe->getTermDatabase()->d_type_map[d_match_pattern_type].empty() ); //must return something d_firstTime = false; return d_qe->getTermDatabase()->getModelBasisTerm( d_match_pattern_type ); } return Node::null(); }
TNode EqualityQueryInstProp::getCongruentTerm( Node f, std::vector< TNode >& args ) { TNode t = d_qe->getTermDatabase()->getCongruentTerm( f, args ); if( !t.isNull() ){ return t; }else{ //TODO? return TNode::null(); } }
void AbsDef::construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth ) { d_value = v; if( depth<n.getNumChildren() ){ TypeNode tn = q.isNull() ? n[depth].getType() : m->getVariable( q, depth ).getType(); unsigned dom = m->d_domain[tn] ; d_def[dom].construct_def_entry( m, q, n, v, depth+1 ); d_default = dom; } }
SatLiteral TheoryProxy::getNextTheoryDecisionRequest() { TNode n = d_theoryEngine->getNextDecisionRequest(); return n.isNull() ? undefSatLiteral : d_cnfStream->getLiteral(n); }
//this is identical to TermDb::evaluateTerm2, but tracks more information Node EqualityQueryInstProp::evaluateTermExp( Node n, std::vector< Node >& exp, std::map< Node, Node >& visited, bool hasPol, bool pol, std::map< Node, bool >& watch_list_out, std::vector< Node >& props ) { std::map< Node, Node >::iterator itv = visited.find( n ); if( itv != visited.end() ){ return itv->second; }else{ visited[n] = n; Trace("qip-eval") << "evaluate term : " << n << std::endl; std::vector< Node > exp_n; Node ret = getRepresentativeExp( n, exp_n ); if( ret.isNull() ){ //term is not known to be equal to a representative in equality engine, evaluate it Kind k = n.getKind(); if( k==FORALL ){ ret = Node::null(); }else{ std::map< Node, bool > watch_list_out_curr; TNode f = d_qe->getTermDatabase()->getMatchOperator( n ); std::vector< Node > args; bool ret_set = false; bool childChanged = false; int abort_i = -1; //get the child entailed polarity Assert( n.getKind()!=IMPLIES ); bool newHasPol, newPol; QuantPhaseReq::getEntailPolarity( n, 0, hasPol, pol, newHasPol, newPol ); //for each child for( unsigned i=0; i<n.getNumChildren(); i++ ){ Node c = evaluateTermExp( n[i], exp, visited, newHasPol, newPol, watch_list_out_curr, props ); if( c.isNull() ){ ret = Node::null(); ret_set = true; break; }else if( c==d_true || c==d_false ){ //short-circuiting if( k==kind::AND || k==kind::OR ){ if( (k==kind::AND)==(c==d_false) ){ ret = c; ret_set = true; break; }else{ //redundant c = Node::null(); childChanged = true; } }else if( k==kind::ITE && i==0 ){ Assert( watch_list_out_curr.empty() ); ret = evaluateTermExp( n[ c==d_true ? 1 : 2], exp, visited, hasPol, pol, watch_list_out_curr, props ); ret_set = true; break; }else if( k==kind::NOT ){ ret = c==d_true ? d_false : d_true; ret_set = true; break; } } if( !c.isNull() ){ childChanged = childChanged || n[i]!=c; if( !f.isNull() && !watch_list_out_curr.empty() ){ // we are done if this is an UF application and an argument is unevaluated args.push_back( c ); abort_i = i; break; }else if( ( k==kind::AND || k==kind::OR ) ){ if( c.getKind()==k ){ //flatten for( unsigned j=0; j<c.getNumChildren(); j++ ){ addArgument( args, props, c[j], newHasPol, newPol ); } }else{ addArgument( args, props, c, newHasPol, newPol ); } //if we are in a branching position if( hasPol && !newHasPol && args.size()>=2 ){ //we are done if at least two args are unevaluated abort_i = i; break; } }else if( k==kind::ITE ){ //we are done if we are ITE and condition is unevaluated Assert( i==0 ); args.push_back( c ); abort_i = i; break; }else{ args.push_back( c ); } } } //add remaining children if we aborted if( abort_i!=-1 ){ for( int i=(abort_i+1); i<(int)n.getNumChildren(); i++ ){ args.push_back( n[i] ); } } //copy over the watch list for( std::map< Node, bool >::iterator itc = watch_list_out_curr.begin(); itc != watch_list_out_curr.end(); ++itc ){ watch_list_out[itc->first] = itc->second; } //if we have not short-circuited evaluation if( !ret_set ){ //if it is an indexed term, return the congruent term if( !f.isNull() && watch_list_out.empty() ){ std::vector< TNode > t_args; for( unsigned i=0; i<args.size(); i++ ) { t_args.push_back( args[i] ); } Assert( args.size()==n.getNumChildren() ); //args contains terms known by the equality engine TNode nn = getCongruentTerm( f, t_args ); Trace("qip-eval") << " got congruent term " << nn << " from DB for " << n << std::endl; if( !nn.isNull() ){ //successfully constructed representative in EE Assert( exp_n.empty() ); ret = getRepresentativeExp( nn, exp_n ); Trace("qip-eval") << "return rep, exp size = " << exp_n.size() << std::endl; merge_exp( exp, exp_n ); ret_set = true; Assert( !ret.isNull() ); } } if( !ret_set ){ if( childChanged ){ Trace("qip-eval") << "return rewrite" << std::endl; if( ( k==kind::AND || k==kind::OR ) ){ if( args.empty() ){ ret = k==kind::AND ? d_true : d_false; ret_set = true; }else if( args.size()==1 ){ ret = args[0]; ret_set = true; } }else{ Assert( args.size()==n.getNumChildren() ); } if( !ret_set ){ if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ args.insert( args.begin(), n.getOperator() ); } ret = NodeManager::currentNM()->mkNode( k, args ); ret = Rewriter::rewrite( ret ); //re-evaluate Node ret_eval = getRepresentativeExp( ret, exp_n ); if( !ret_eval.isNull() ){ ret = ret_eval; watch_list_out.clear(); }else{ watch_list_out[ret] = true; } } }else{ ret = n; watch_list_out[ret] = true; } } } } }else{ Trace("qip-eval") << "...exists in ee, return rep, exp size = " << exp_n.size() << std::endl; merge_exp( exp, exp_n ); } Trace("qip-eval") << "evaluated term : " << n << ", got : " << ret << ", exp size = " << exp.size() << std::endl; visited[n] = ret; return ret; } }
void UnconstrainedSimplifier::processUnconstrained() { TNodeSet::iterator it = d_unconstrained.begin(), iend = d_unconstrained.end(); vector<TNode> workList; for ( ; it != iend; ++it) { workList.push_back(*it); } Node currentSub; TNode parent; bool swap; bool isSigned; bool strict; vector<TNode> delayQueueLeft; vector<Node> delayQueueRight; TNode current = workList.back(); workList.pop_back(); for (;;) { Assert(d_visitedOnce.find(current) != d_visitedOnce.end()); parent = d_visitedOnce[current]; if (!parent.isNull()) { swap = isSigned = strict = false; switch (parent.getKind()) { // If-then-else operator - any two unconstrained children makes the parent unconstrained case kind::ITE: { Assert(parent[0] == current || parent[1] == current || parent[2] == current); bool uCond = parent[0] == current || d_unconstrained.find(parent[0]) != d_unconstrained.end(); bool uThen = parent[1] == current || d_unconstrained.find(parent[1]) != d_unconstrained.end(); bool uElse = parent[2] == current || d_unconstrained.find(parent[2]) != d_unconstrained.end(); if ((uCond && uThen) || (uCond && uElse) || (uThen && uElse)) { if (d_unconstrained.find(parent) == d_unconstrained.end() && !d_substitutions.hasSubstitution(parent)) { ++d_numUnconstrainedElim; if (uThen) { if (parent[1] != current) { if (parent[1].isVar()) { currentSub = parent[1]; } else { Assert(d_substitutions.hasSubstitution(parent[1])); currentSub = d_substitutions.apply(parent[1]); } } else if (currentSub.isNull()) { currentSub = current; } } else if (parent[2] != current) { if (parent[2].isVar()) { currentSub = parent[2]; } else { Assert(d_substitutions.hasSubstitution(parent[2])); currentSub = d_substitutions.apply(parent[2]); } } else if (currentSub.isNull()) { currentSub = current; } current = parent; } else { currentSub = Node(); } } else if (uCond) { Cardinality card = parent.getType().getCardinality(); if (card.isFinite() && !card.isLargeFinite() && card.getFiniteCardinality() == 2) { // Special case: condition is unconstrained, then and else are different, and total cardinality of the type is 2, then the result // is unconstrained Node test; if (parent.getType().isBoolean()) { test = Rewriter::rewrite(parent[1].iffNode(parent[2])); } else { test = Rewriter::rewrite(parent[1].eqNode(parent[2])); } if (test == NodeManager::currentNM()->mkConst<bool>(false)) { ++d_numUnconstrainedElim; if (currentSub.isNull()) { currentSub = current; } currentSub = newUnconstrainedVar(parent.getType(), currentSub); current = parent; } } } break; } // Comparisons that return a different type - assuming domains are larger than 1, any // unconstrained child makes parent unconstrained as well case kind::EQUAL: if (parent[0].getType() != parent[1].getType()) { TNode other = (parent[0] == current) ? parent[1] : parent[0]; if (current.getType().isSubtypeOf(other.getType())) { break; } } if( parent[0].getType().isDatatype() ){ TypeNode tn = parent[0].getType(); const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); if( dt.isRecursiveSingleton( tn.toType() ) ){ //domain size may be 1 break; } } case kind::BITVECTOR_COMP: case kind::LT: case kind::LEQ: case kind::GT: case kind::GEQ: { if (d_unconstrained.find(parent) == d_unconstrained.end() && !d_substitutions.hasSubstitution(parent)) { ++d_numUnconstrainedElim; Assert(parent[0] != parent[1] && (parent[0] == current || parent[1] == current)); if (currentSub.isNull()) { currentSub = current; } currentSub = newUnconstrainedVar(parent.getType(), currentSub); current = parent; } else { currentSub = Node(); } break; } // Unary operators that propagate unconstrainedness case kind::NOT: case kind::BITVECTOR_NOT: case kind::BITVECTOR_NEG: case kind::UMINUS: ++d_numUnconstrainedElim; Assert(parent[0] == current); if (currentSub.isNull()) { currentSub = current; } current = parent; break; // Unary operators that propagate unconstrainedness and return a different type case kind::BITVECTOR_EXTRACT: ++d_numUnconstrainedElim; Assert(parent[0] == current); if (currentSub.isNull()) { currentSub = current; } currentSub = newUnconstrainedVar(parent.getType(), currentSub); current = parent; break; // Operators returning same type requiring all children to be unconstrained case kind::AND: case kind::OR: case kind::IMPLIES: case kind::BITVECTOR_AND: case kind::BITVECTOR_OR: case kind::BITVECTOR_NAND: case kind::BITVECTOR_NOR: { bool allUnconstrained = true; for(TNode::iterator child_it = parent.begin(); child_it != parent.end(); ++child_it) { if (d_unconstrained.find(*child_it) == d_unconstrained.end()) { allUnconstrained = false; break; } } if (allUnconstrained) { if (d_unconstrained.find(parent) == d_unconstrained.end() && !d_substitutions.hasSubstitution(parent)) { ++d_numUnconstrainedElim; if (currentSub.isNull()) { currentSub = current; } current = parent; } else { currentSub = Node(); } } } break; // Require all children to be unconstrained and different case kind::BITVECTOR_SHL: case kind::BITVECTOR_LSHR: case kind::BITVECTOR_ASHR: case kind::BITVECTOR_UDIV_TOTAL: case kind::BITVECTOR_UREM_TOTAL: case kind::BITVECTOR_SDIV: case kind::BITVECTOR_SREM: case kind::BITVECTOR_SMOD: { bool allUnconstrained = true; bool allDifferent = true; for(TNode::iterator child_it = parent.begin(); child_it != parent.end(); ++child_it) { if (d_unconstrained.find(*child_it) == d_unconstrained.end()) { allUnconstrained = false; break; } for(TNode::iterator child_it2 = child_it + 1; child_it2 != parent.end(); ++child_it2) { if (*child_it == *child_it2) { allDifferent = false; break; } } } if (allUnconstrained && allDifferent) { if (d_unconstrained.find(parent) == d_unconstrained.end() && !d_substitutions.hasSubstitution(parent)) { ++d_numUnconstrainedElim; if (currentSub.isNull()) { currentSub = current; } current = parent; } else { currentSub = Node(); } } break; } // Requires all children to be unconstrained and different, and returns a different type case kind::BITVECTOR_CONCAT: { bool allUnconstrained = true; bool allDifferent = true; for(TNode::iterator child_it = parent.begin(); child_it != parent.end(); ++child_it) { if (d_unconstrained.find(*child_it) == d_unconstrained.end()) { allUnconstrained = false; break; } for(TNode::iterator child_it2 = child_it + 1; child_it2 != parent.end(); ++child_it2) { if (*child_it == *child_it2) { allDifferent = false; break; } } } if (allUnconstrained && allDifferent) { if (d_unconstrained.find(parent) == d_unconstrained.end() && !d_substitutions.hasSubstitution(parent)) { ++d_numUnconstrainedElim; if (currentSub.isNull()) { currentSub = current; } currentSub = newUnconstrainedVar(parent.getType(), currentSub); current = parent; } else { currentSub = Node(); } } } break; // N-ary operators returning same type requiring at least one child to be unconstrained case kind::PLUS: case kind::MINUS: if (current.getType().isInteger() && !parent.getType().isInteger()) { break; } case kind::IFF: case kind::XOR: case kind::BITVECTOR_XOR: case kind::BITVECTOR_XNOR: case kind::BITVECTOR_PLUS: case kind::BITVECTOR_SUB: if (d_unconstrained.find(parent) == d_unconstrained.end() && !d_substitutions.hasSubstitution(parent)) { ++d_numUnconstrainedElim; if (currentSub.isNull()) { currentSub = current; } current = parent; } else { currentSub = Node(); } break; // Multiplication/division: must be non-integer and other operand must be non-zero case kind::MULT: { case kind::DIVISION: Assert(parent.getNumChildren() == 2); TNode other; if (parent[0] == current) { other = parent[1]; } else { Assert(parent[1] == current); other = parent[0]; } if (d_unconstrained.find(other) != d_unconstrained.end()) { if (d_unconstrained.find(parent) == d_unconstrained.end() && !d_substitutions.hasSubstitution(parent)) { if (current.getType().isInteger() && other.getType().isInteger()) { Assert(parent.getKind() == kind::DIVISION || parent.getType().isInteger()); if (parent.getKind() == kind::DIVISION) { break; } } ++d_numUnconstrainedElim; if (currentSub.isNull()) { currentSub = current; } current = parent; } else { currentSub = Node(); } } else { // if only the denominator of a division is unconstrained, can't set it to 0 so the result is not unconstrained if (parent.getKind() == kind::DIVISION && current == parent[1]) { break; } NodeManager* nm = NodeManager::currentNM(); // if we are an integer, the only way we are unconstrained is if we are a MULT by -1 if (current.getType().isInteger()) { // div/mult by 1 should have been simplified Assert(other != nm->mkConst<Rational>(1)); if (other == nm->mkConst<Rational>(-1)) { // div by -1 should have been simplified Assert(parent.getKind() == kind::MULT); Assert(parent.getType().isInteger()); } else { break; } } else { // TODO: could build ITE here Node test = other.eqNode(nm->mkConst<Rational>(0)); if (Rewriter::rewrite(test) != nm->mkConst<bool>(false)) { break; } } ++d_numUnconstrainedElim; if (currentSub.isNull()) { currentSub = current; } current = parent; } break; } // Bitvector MULT - current must only appear once in the children: // all other children must be unconstrained or odd case kind::BITVECTOR_MULT: { bool found = false; bool done = false; for(TNode::iterator child_it = parent.begin(); child_it != parent.end(); ++child_it) { if ((*child_it) == current) { if (found) { done = true; break; } found = true; continue; } else if (d_unconstrained.find(*child_it) != d_unconstrained.end()) { continue; } else { NodeManager* nm = NodeManager::currentNM(); Node extractOp = nm->mkConst<BitVectorExtract>(BitVectorExtract(0,0)); vector<Node> children; children.push_back(*child_it); Node test = nm->mkNode(extractOp, children); BitVector one(1,unsigned(1)); test = test.eqNode(nm->mkConst<BitVector>(one)); if (Rewriter::rewrite(test) != nm->mkConst<bool>(true)) { done = true; break; } } } if (done) { break; } if (d_unconstrained.find(parent) == d_unconstrained.end() && !d_substitutions.hasSubstitution(parent)) { ++d_numUnconstrainedElim; if (currentSub.isNull()) { currentSub = current; } current = parent; } else { currentSub = Node(); } break; } // Uninterpreted function - if domain is infinite, no quantifiers are used, and any child is unconstrained, result is unconstrained case kind::APPLY_UF: if (d_logicInfo.isQuantified() || !current.getType().getCardinality().isInfinite()) { break; } if (d_unconstrained.find(parent) == d_unconstrained.end() && !d_substitutions.hasSubstitution(parent)) { ++d_numUnconstrainedElim; if (currentSub.isNull()) { currentSub = current; } if (parent.getType() != current.getType()) { currentSub = newUnconstrainedVar(parent.getType(), currentSub); } current = parent; } else { currentSub = Node(); } break; // Array select - if array is unconstrained, so is result case kind::SELECT: if (parent[0] == current) { ++d_numUnconstrainedElim; Assert(current.getType().isArray()); if (currentSub.isNull()) { currentSub = current; } currentSub = newUnconstrainedVar(current.getType().getArrayConstituentType(), currentSub); current = parent; } break; // Array store - if both store and value are unconstrained, so is resulting store case kind::STORE: if (((parent[0] == current && d_unconstrained.find(parent[2]) != d_unconstrained.end()) || (parent[2] == current && d_unconstrained.find(parent[0]) != d_unconstrained.end()))) { if (d_unconstrained.find(parent) == d_unconstrained.end() && !d_substitutions.hasSubstitution(parent)) { ++d_numUnconstrainedElim; if (parent[0] != current) { if (parent[0].isVar()) { currentSub = parent[0]; } else { Assert(d_substitutions.hasSubstitution(parent[0])); currentSub = d_substitutions.apply(parent[0]); } } else if (currentSub.isNull()) { currentSub = current; } current = parent; } else { currentSub = Node(); } } break; // Bit-vector comparisons: replace with new Boolean variable, but have // to also conjoin with a side condition as there is always one case // when the comparison is forced to be false case kind::BITVECTOR_ULT: case kind::BITVECTOR_UGE: case kind::BITVECTOR_UGT: case kind::BITVECTOR_ULE: case kind::BITVECTOR_SLT: case kind::BITVECTOR_SGE: case kind::BITVECTOR_SGT: case kind::BITVECTOR_SLE: { // Tuples over (signed, swap, strict). switch (parent.getKind()) { case kind::BITVECTOR_UGE: break; case kind::BITVECTOR_ULT: strict = true; break; case kind::BITVECTOR_ULE: swap = true; break; case kind::BITVECTOR_UGT: swap = true; strict = true; break; case kind::BITVECTOR_SGE: isSigned = true; break; case kind::BITVECTOR_SLT: isSigned = true; strict = true; break; case kind::BITVECTOR_SLE: isSigned = true; swap = true; break; case kind::BITVECTOR_SGT: isSigned = true; swap = true; strict = true; break; default: Unreachable(); } TNode other; bool left = false; if (parent[0] == current) { other = parent[1]; left = true; } else { Assert(parent[1] == current); other = parent[0]; } if (d_unconstrained.find(other) != d_unconstrained.end()) { if (d_unconstrained.find(parent) == d_unconstrained.end() && !d_substitutions.hasSubstitution(parent)) { ++d_numUnconstrainedElim; if (currentSub.isNull()) { currentSub = current; } currentSub = newUnconstrainedVar(parent.getType(), currentSub); current = parent; } else { currentSub = Node(); } } else { unsigned size = current.getType().getBitVectorSize(); BitVector bv = isSigned ? BitVector(size, Integer(1).multiplyByPow2(size - 1)) : BitVector(size, unsigned(0)); if (swap == left) { bv = ~bv; } if (currentSub.isNull()) { currentSub = current; } currentSub = newUnconstrainedVar(parent.getType(), currentSub); current = parent; NodeManager* nm = NodeManager::currentNM(); Node test = Rewriter::rewrite(other.eqNode(nm->mkConst<BitVector>(bv))); if (test == nm->mkConst<bool>(false)) { break; } if (strict) { currentSub = currentSub.andNode(test.notNode()); } else { currentSub = currentSub.orNode(test); } // Delay adding this substitution - see comment at end of function delayQueueLeft.push_back(current); delayQueueRight.push_back(currentSub); currentSub = Node(); parent = TNode(); } break; } // Do nothing case kind::BITVECTOR_SIGN_EXTEND: case kind::BITVECTOR_ZERO_EXTEND: case kind::BITVECTOR_REPEAT: case kind::BITVECTOR_ROTATE_LEFT: case kind::BITVECTOR_ROTATE_RIGHT: default: break; } if (current == parent && d_visited[parent] == 1) { d_unconstrained.insert(parent); continue; } } if (!currentSub.isNull()) { Assert(currentSub.isVar()); d_substitutions.addSubstitution(current, currentSub, false); } if (workList.empty()) { break; } current = workList.back(); currentSub = Node(); workList.pop_back(); } TNode left; Node right; // All substitutions except those arising from bitvector comparisons are // substitutions t -> x where x is a variable. This allows us to build the // substitution very quickly (never invalidating the substitution cache). // Bitvector comparisons are more complicated and may require // back-substitution and cache-invalidation. So we do these last. while (!delayQueueLeft.empty()) { left = delayQueueLeft.back(); if (!d_substitutions.hasSubstitution(left)) { right = d_substitutions.apply(delayQueueRight.back()); d_substitutions.addSubstitution(delayQueueLeft.back(), right); } delayQueueLeft.pop_back(); delayQueueRight.pop_back(); } }