bool InequalitySolver::isInequalityOnly(TNode node) { if (node.getKind() == kind::NOT) { node = node[0]; } if (node.getAttribute(IneqOnlyComputedAttribute())) { return node.getAttribute(IneqOnlyAttribute()); } if (node.getKind() != kind::EQUAL && node.getKind() != kind::BITVECTOR_ULT && node.getKind() != kind::BITVECTOR_ULE && node.getKind() != kind::CONST_BITVECTOR && node.getKind() != kind::SELECT && node.getKind() != kind::STORE && node.getMetaKind() != kind::metakind::VARIABLE) { // not worth caching return false; } bool res = true; for (unsigned i = 0; res && i < node.getNumChildren(); ++i) { res = res && isInequalityOnly(node[i]); } node.setAttribute(IneqOnlyComputedAttribute(), true); node.setAttribute(IneqOnlyAttribute(), res); return res; }
Node RePairAssocCommutativeOperators::case_assoccomm(TNode n){ Kind k = n.getKind(); Assert(isAssociateCommutative(k)); Assert(n.getMetaKind() != kind::metakind::PARAMETERIZED); unsigned N = n.getNumChildren(); Assert(N >= 2); Node last = rePairAssocCommutativeOperators( n[N-1]); Node nextToLast = rePairAssocCommutativeOperators(n[N-2]); NodeManager* nm = NodeManager::currentNM(); Node last2 = nm->mkNode(k, nextToLast, last); if(N <= 2){ return last2; } else{ Assert(N > 2); Node prevRound = last2; for(unsigned prevPos = N-2; prevPos > 0; --prevPos){ unsigned currPos = prevPos-1; Node curr = rePairAssocCommutativeOperators(n[currPos]); Node round = nm->mkNode(k, curr, prevRound); prevRound = round; } return prevRound; } }
Node BvToBoolPreprocessor::liftNode(TNode current) { Node result; if (hasLiftCache(current)) { result = getLiftCache(current); }else if (isConvertibleBvAtom(current)) { result = convertBvAtom(current); addToLiftCache(current, result); } else { if (current.getNumChildren() == 0) { result = current; } else { NodeBuilder<> builder(current.getKind()); if (current.getMetaKind() == kind::metakind::PARAMETERIZED) { builder << current.getOperator(); } for (unsigned i = 0; i < current.getNumChildren(); ++i) { Node converted = liftNode(current[i]); Assert (converted.getType() == current[i].getType()); builder << converted; } result = builder; addToLiftCache(current, result); } } Assert (result != Node()); Assert(result.getType() == current.getType()); Debug("bv-to-bool") << "BvToBoolPreprocessor::liftNode " << current << " => \n" << result << "\n"; return result; }
Node AbstractionModule::substituteArguments(TNode signature, TNode apply, unsigned& index, TNodeTNodeMap& seen) { if (seen.find(signature) != seen.end()) { return seen[signature]; } if (signature.getKind() == kind::SKOLEM) { // return corresponding argument and increment counter seen[signature] = apply[index]; return apply[index++]; } if (signature.getNumChildren() == 0) { Assert (signature.getKind() != kind::VARIABLE && signature.getKind() != kind::SKOLEM); seen[signature] = signature; return signature; } NodeBuilder<> builder(signature.getKind()); if (signature.getMetaKind() == kind::metakind::PARAMETERIZED) { builder << signature.getOperator(); } for (unsigned i = 0; i < signature.getNumChildren(); ++i) { Node child = substituteArguments(signature[i], apply, index, seen); builder << child; } Node result = builder; seen[signature]= result; return result; }
bool CVC4::theory::bv::utils::isEqualityTerm(TNode term, TNodeBoolMap& cache) { term = term.getKind() == kind::NOT ? term[0] : term; TNodeBoolMap::const_iterator it = cache.find(term); if (it != cache.end()) { return it->second; } if (term.getNumChildren() == 0) return true; if (theory::Theory::theoryOf(theory::THEORY_OF_TERM_BASED, term) == THEORY_BV) { Kind k = term.getKind(); if (k != kind::CONST_BITVECTOR && k != kind::EQUAL && term.getMetaKind() != kind::metakind::VARIABLE) { cache[term] = false; return false; } } for (unsigned i = 0; i < term.getNumChildren(); ++i) { if (!isEqualityTerm(term[i], cache)) { cache[term] = false; return false; } } cache[term]= true; return true; }
Node AbstractionModule::computeSignatureRec(TNode node, NodeNodeMap& cache) { if (cache.find(node) != cache.end()) { return cache.find(node)->second; } if (node.getNumChildren() == 0) { if (node.getKind() == kind::CONST_BITVECTOR) return node; Node sig = getSignatureSkolem(node); cache[node] = sig; return sig; } NodeBuilder<> builder(node.getKind()); if (node.getMetaKind() == kind::metakind::PARAMETERIZED) { builder << node.getOperator(); } for (unsigned i = 0; i < node.getNumChildren(); ++i) { Node converted = computeSignatureRec(node[i], cache); builder << converted; } Node result = builder; cache[node] = result; return result; }
bool InequalitySolver::isInequalityOnly(TNode node) { if (d_ineqOnlyCache.find(node) != d_ineqOnlyCache.end()) { return d_ineqOnlyCache[node]; } if (node.getKind() == kind::NOT) { node = node[0]; } if (node.getKind() != kind::EQUAL && node.getKind() != kind::BITVECTOR_ULT && node.getKind() != kind::BITVECTOR_ULE && node.getKind() != kind::CONST_BITVECTOR && node.getKind() != kind::SELECT && node.getKind() != kind::STORE && node.getMetaKind() != kind::metakind::VARIABLE) { return false; } bool res = true; for (unsigned i = 0; i < node.getNumChildren(); ++i) { res = res && isInequalityOnly(node[i]); } d_ineqOnlyCache[node] = res; return res; }
void AlgebraicSolver::collectModelInfo(TheoryModel* model, bool fullModel) { Debug("bitvector-model") << "AlgebraicSolver::collectModelInfo\n"; AlwaysAssert (!d_quickSolver->inConflict()); set<Node> termSet; d_bv->computeRelevantTerms(termSet); // collect relevant terms that the bv theory abstracts to variables // (variables and parametric terms such as select apply_uf) std::vector<TNode> variables; std::vector<Node> values; for (set<Node>::const_iterator it = termSet.begin(); it != termSet.end(); ++it) { TNode term = *it; if (term.getType().isBitVector() && (term.getMetaKind() == kind::metakind::VARIABLE || Theory::theoryOf(term) != THEORY_BV)) { variables.push_back(term); values.push_back(term); } } NodeSet leaf_vars; Debug("bitvector-model") << "Substitutions:\n"; for (unsigned i = 0; i < variables.size(); ++i) { TNode current = variables[i]; TNode subst = Rewriter::rewrite(d_modelMap->apply(current)); Debug("bitvector-model") << " " << current << " => " << subst << "\n"; values[i] = subst; utils::collectVariables(subst, leaf_vars); } Debug("bitvector-model") << "Model:\n"; for (NodeSet::const_iterator it = leaf_vars.begin(); it != leaf_vars.end(); ++it) { TNode var = *it; Node value = d_quickSolver->getVarValue(var, true); Assert (!value.isNull() || !fullModel); // may be a shared term that did not appear in the current assertions if (!value.isNull()) { Debug("bitvector-model") << " " << var << " => " << value << "\n"; Assert (value.getKind() == kind::CONST_BITVECTOR); d_modelMap->addSubstitution(var, value); } } Debug("bitvector-model") << "Final Model:\n"; for (unsigned i = 0; i < variables.size(); ++i) { TNode current = values[i]; TNode subst = Rewriter::rewrite(d_modelMap->apply(current)); Debug("bitvector-model") << "AlgebraicSolver: " << variables[i] << " => " << subst << "\n"; // Doesn't have to be constant as it may be irrelevant Assert (subst.getKind() == kind::CONST_BITVECTOR); model->assertEquality(variables[i], subst, true); } }
void ExtractSkolemizer::storeExtract(TNode var, unsigned high, unsigned low) { Assert (var.getMetaKind() == kind::metakind::VARIABLE); if (d_varToExtract.find(var) == d_varToExtract.end()) { d_varToExtract[var] = ExtractList(utils::getSize(var)); } VarExtractMap::iterator it = d_varToExtract.find(var); ExtractList& el = it->second; Extract e(high, low); el.addExtract(e); }
Node TheoryEngineModelBuilder::normalize(TheoryModel* m, TNode r, std::map< Node, Node >& constantReps, bool evalOnly) { std::map<Node, Node>::iterator itMap = constantReps.find(r); if (itMap != constantReps.end()) { return (*itMap).second; } NodeMap::iterator it = d_normalizedCache.find(r); if (it != d_normalizedCache.end()) { return (*it).second; } Node retNode = r; if (r.getNumChildren() > 0) { std::vector<Node> children; if (r.getMetaKind() == kind::metakind::PARAMETERIZED) { children.push_back(r.getOperator()); } bool childrenConst = true; for (size_t i=0; i < r.getNumChildren(); ++i) { Node ri = r[i]; if (!ri.isConst()) { if (m->d_equalityEngine.hasTerm(ri)) { ri = m->d_equalityEngine.getRepresentative(ri); itMap = constantReps.find(ri); if (itMap != constantReps.end()) { ri = (*itMap).second; } else if (evalOnly) { ri = normalize(m, r[i], constantReps, evalOnly); } } else { ri = normalize(m, ri, constantReps, evalOnly); } if (!ri.isConst()) { childrenConst = false; } } children.push_back(ri); } retNode = NodeManager::currentNM()->mkNode( r.getKind(), children ); if (childrenConst) { retNode = Rewriter::rewrite(retNode); Assert(retNode.getKind() == kind::APPLY_UF || retNode.isConst()); } } d_normalizedCache[r] = retNode; return retNode; }
void AbstractionModule::makeFreshSkolems(TNode node, SubstitutionMap& map, SubstitutionMap& reverse_map) { if (map.hasSubstitution(node)) { return; } if (node.getMetaKind() == kind::metakind::VARIABLE) { Node skolem = utils::mkVar(utils::getSize(node)); map.addSubstitution(node, skolem); reverse_map.addSubstitution(skolem, node); return; } if (node.isConst()) return; for (unsigned i = 0; i < node.getNumChildren(); ++i) { makeFreshSkolems(node[i], map, reverse_map); } }
Node ITESimplifier::createSimpContext(TNode c, Node& iteNode, Node& simpVar) { NodeMap::iterator it; it = d_simpContextCache.find(c); if (it != d_simpContextCache.end()) { return (*it).second; } if (!containsTermITE(c)) { d_simpContextCache[c] = c; return c; } if (c.getKind() == kind::ITE && !c.getType().isBoolean()) { // Currently only support one ite node in a simp context // Return Null if more than one is found if (!iteNode.isNull()) { return Node(); } simpVar = getSimpVar(c.getType()); if (simpVar.isNull()) { return Node(); } d_simpContextCache[c] = simpVar; iteNode = c; return simpVar; } NodeBuilder<> builder(c.getKind()); if (c.getMetaKind() == kind::metakind::PARAMETERIZED) { builder << c.getOperator(); } unsigned i = 0; for (; i < c.getNumChildren(); ++ i) { Node newChild = createSimpContext(c[i], iteNode, simpVar); if (newChild.isNull()) { return newChild; } builder << newChild; } // Mark the substitution and continue Node result = builder; d_simpContextCache[c] = result; return result; }
Node RePairAssocCommutativeOperators::case_other(TNode n){ if(n.isConst() || n.isVar()){ return n; } NodeBuilder<> nb(n.getKind()); if(n.getMetaKind() == kind::metakind::PARAMETERIZED) { nb << n.getOperator(); } // Remove the ITEs from the children for(TNode::const_iterator i = n.begin(), end = n.end(); i != end; ++i) { Node newChild = rePairAssocCommutativeOperators(*i); nb << newChild; } Node result = (Node)nb; return result; }
void AbstractionModule::makeFreshArgs(TNode func, std::vector<Node>& fresh_args) { Assert (fresh_args.size() == 0); Assert (func.getKind() == kind::APPLY_UF); TNodeNodeMap d_map; for (unsigned i = 0; i < func.getNumChildren(); ++i) { TNode arg = func[i]; if (arg.isConst()) { fresh_args.push_back(arg); continue; } Assert (arg.getMetaKind() == kind::metakind::VARIABLE); TNodeNodeMap::iterator it = d_map.find(arg); if (it != d_map.end()) { fresh_args.push_back(it->second); } else { Node skolem = utils::mkVar(utils::getSize(arg)); d_map[arg] = skolem; fresh_args.push_back(skolem); } } Assert (fresh_args.size() == func.getNumChildren()); }
Node ITESimplifier::substitute(TNode e, TNodeMap& substTable, TNodeMap& cache) { TNodeMap::iterator it = cache.find(e), iend = cache.end(); if (it != iend) { return it->second; } // do substitution? it = substTable.find(e); iend = substTable.end(); if (it != iend) { Node result = substitute(it->second, substTable, cache); cache[e] = result; return result; } size_t sz = e.getNumChildren(); if (sz == 0) { cache[e] = e; return e; } NodeBuilder<> builder(e.getKind()); if (e.getMetaKind() == kind::metakind::PARAMETERIZED) { builder << e.getOperator(); } for (unsigned i = 0; i < e.getNumChildren(); ++ i) { builder << substitute(e[i], substTable, cache); } Node result = builder; // it = substTable.find(result); // if (it != iend) { // result = substitute(it->second, substTable, cache); // } cache[e] = result; return result; }
bool AlgebraicSolver::isSubstitutableIn(TNode node, TNode in) { if (node.getMetaKind() == kind::metakind::VARIABLE && !in.hasSubterm(node)) return true; return false; }
Node RemoveITE::run(TNode node, std::vector<Node>& output, IteSkolemMap& iteSkolemMap) { // Current node Debug("ite") << "removeITEs(" << node << ")" << endl; // The result may be cached already NodeManager *nodeManager = NodeManager::currentNM(); ITECache::iterator i = d_iteCache.find(node); if(i != d_iteCache.end()) { Node cachedRewrite = (*i).second; Debug("ite") << "removeITEs: in-cache: " << cachedRewrite << endl; return cachedRewrite.isNull() ? Node(node) : cachedRewrite; } // If an ITE replace it if(node.getKind() == kind::ITE) { TypeNode nodeType = node.getType(); if(!nodeType.isBoolean()) { // Make the skolem to represent the ITE Node skolem = nodeManager->mkSkolem("termITE_$$", nodeType, "a variable introduced due to term-level ITE removal"); // The new assertion Node newAssertion = nodeManager->mkNode(kind::ITE, node[0], skolem.eqNode(node[1]), skolem.eqNode(node[2])); Debug("ite") << "removeITEs(" << node << ") => " << newAssertion << endl; // Attach the skolem d_iteCache[node] = skolem; // Remove ITEs from the new assertion, rewrite it and push it to the output newAssertion = run(newAssertion, output, iteSkolemMap); iteSkolemMap[skolem] = output.size(); output.push_back(newAssertion); // The representation is now the skolem return skolem; } } // If not an ITE, go deep if( node.getKind() != kind::FORALL && node.getKind() != kind::EXISTS && node.getKind() != kind::REWRITE_RULE ) { vector<Node> newChildren; bool somethingChanged = false; if(node.getMetaKind() == kind::metakind::PARAMETERIZED) { newChildren.push_back(node.getOperator()); } // Remove the ITEs from the children for(TNode::const_iterator it = node.begin(), end = node.end(); it != end; ++it) { Node newChild = run(*it, output, iteSkolemMap); somethingChanged |= (newChild != *it); newChildren.push_back(newChild); } // If changes, we rewrite if(somethingChanged) { Node cachedRewrite = nodeManager->mkNode(node.getKind(), newChildren); d_iteCache[node] = cachedRewrite; return cachedRewrite; } else { d_iteCache[node] = Node::null(); return node; } } else { d_iteCache[node] = Node::null(); return node; } }
bool AlgebraicSolver::solve(TNode fact, TNode reason, SubstitutionEx& subst) { if (fact.getKind() != kind::EQUAL) return false; TNode left = fact[0]; TNode right = fact[1]; if (left.isVar() && !right.hasSubterm(left)) { bool changed = subst.addSubstitution(left, right, reason); return changed; } if (right.isVar() && !left.hasSubterm(right)) { bool changed = subst.addSubstitution(right, left, reason); return changed; } // xor simplification if (right.getKind() == kind::BITVECTOR_XOR && left.getKind() == kind::BITVECTOR_XOR) { TNode var = left[0]; if (var.getMetaKind() != kind::metakind::VARIABLE) return false; // simplify xor with same variable on both sides if (right.hasSubterm(var)) { std::vector<Node> right_children; for (unsigned i = 0; i < right.getNumChildren(); ++i) { if (right[i] != var) right_children.push_back(right[i]); } Assert (right_children.size()); Node new_right = right_children.size() > 1 ? utils::mkNode(kind::BITVECTOR_XOR, right_children) : right_children[0]; std::vector<Node> left_children; for (unsigned i = 1; i < left.getNumChildren(); ++i) { left_children.push_back(left[i]); } Node new_left = left_children.size() > 1 ? utils::mkNode(kind::BITVECTOR_XOR, left_children) : left_children[0]; Node new_fact = utils::mkNode(kind::EQUAL, new_left, new_right); bool changed = subst.addSubstitution(fact, new_fact, reason); return changed; } NodeBuilder<> nb(kind::BITVECTOR_XOR); for (unsigned i = 1; i < left.getNumChildren(); ++i) { nb << left[i]; } Node inverse = left.getNumChildren() == 2? (Node)left[1] : (Node)nb; Node new_right = utils::mkNode(kind::BITVECTOR_XOR, right, inverse); bool changed = subst.addSubstitution(var, new_right, reason); if (Dump.isOn("bv-algebraic")) { Node query = utils::mkNot(utils::mkNode(kind::IFF, fact, utils::mkNode(kind::EQUAL, var, new_right))); Dump("bv-algebraic") << EchoCommand("ThoeryBV::AlgebraicSolver::substitution explanation"); Dump("bv-algebraic") << PushCommand(); Dump("bv-algebraic") << AssertCommand(query.toExpr()); Dump("bv-algebraic") << CheckSatCommand(); Dump("bv-algebraic") << PopCommand(); } return changed; } // (a xor t = a) <=> (t = 0) if (left.getKind() == kind::BITVECTOR_XOR && right.getMetaKind() == kind::metakind::VARIABLE && left.hasSubterm(right)) { TNode var = right; Node new_left = utils::mkNode(kind::BITVECTOR_XOR, var, left); Node zero = utils::mkConst(utils::getSize(var), 0u); Node new_fact = utils::mkNode(kind::EQUAL, zero, new_left); bool changed = subst.addSubstitution(fact, new_fact, reason); return changed; } if (right.getKind() == kind::BITVECTOR_XOR && left.getMetaKind() == kind::metakind::VARIABLE && right.hasSubterm(left)) { TNode var = left; Node new_right = utils::mkNode(kind::BITVECTOR_XOR, var, right); Node zero = utils::mkConst(utils::getSize(var), 0u); Node new_fact = utils::mkNode(kind::EQUAL, zero, new_right); bool changed = subst.addSubstitution(fact, new_fact, reason); return changed; } // (a xor b = 0) <=> (a = b) if (left.getKind() == kind::BITVECTOR_XOR && left.getNumChildren() == 2 && right.getKind() == kind::CONST_BITVECTOR && right.getConst<BitVector>() == BitVector(utils::getSize(left), 0u)) { Node new_fact = utils::mkNode(kind::EQUAL, left[0], left[1]); bool changed = subst.addSubstitution(fact, new_fact, reason); return changed; } return false; }
Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const { Assert(n.getKind() != kind::FORALL && n.getKind() != kind::EXISTS); if(n.getKind() == kind::LAMBDA) { NodeManager* nm = NodeManager::currentNM(); Node body = getModelValue(n[1], true); // This is a bit ugly, but cache inside simplifier can change, so can't be const // The ite simplifier is needed to get rid of artifacts created by Boolean terms body = const_cast<ITESimplifier*>(&d_iteSimp)->simpITE(body); body = Rewriter::rewrite(body); return nm->mkNode(kind::LAMBDA, n[0], body); } if(n.isConst() || (hasBoundVars && n.getKind() == kind::BOUND_VARIABLE)) { return n; } TypeNode t = n.getType(); if (t.isFunction() || t.isPredicate()) { if (d_enableFuncModels) { std::map< Node, Node >::const_iterator it = d_uf_models.find(n); if (it != d_uf_models.end()) { // Existing function return it->second; } // Unknown function symbol: return LAMBDA x. c, where c is the first constant in the enumeration of the range type vector<TypeNode> argTypes = t.getArgTypes(); vector<Node> args; NodeManager* nm = NodeManager::currentNM(); for (unsigned i = 0; i < argTypes.size(); ++i) { args.push_back(nm->mkBoundVar(argTypes[i])); } Node boundVarList = nm->mkNode(kind::BOUND_VAR_LIST, args); TypeEnumerator te(t.getRangeType()); return nm->mkNode(kind::LAMBDA, boundVarList, *te); } // TODO: if func models not enabled, throw an error? Unreachable(); } if (n.getNumChildren() > 0) { std::vector<Node> children; if (n.getKind() == APPLY_UF) { Node op = getModelValue(n.getOperator(), hasBoundVars); children.push_back(op); } else if (n.getMetaKind() == kind::metakind::PARAMETERIZED) { children.push_back(n.getOperator()); } //evaluate the children for (unsigned i = 0; i < n.getNumChildren(); ++i) { Node val = getModelValue(n[i], hasBoundVars); children.push_back(val); } Node val = Rewriter::rewrite(NodeManager::currentNM()->mkNode(n.getKind(), children)); Assert(hasBoundVars || val.isConst()); return val; } if (!d_equalityEngine.hasTerm(n)) { // Unknown term - return first enumerated value for this type TypeEnumerator te(n.getType()); return *te; } Node val = d_equalityEngine.getRepresentative(n); Assert(d_reps.find(val) != d_reps.end()); std::map< Node, Node >::const_iterator it = d_reps.find( val ); if( it!=d_reps.end() ){ return it->second; }else{ return Node::null(); } }
Node ITESimplifier::simpITE(TNode assertion) { // Do a topological sort of the subexpressions and substitute them vector<preprocess_stack_element> toVisit; toVisit.push_back(assertion); while (!toVisit.empty()) { // The current node we are processing preprocess_stack_element& stackHead = toVisit.back(); TNode current = stackHead.node; // If node has no ITE's or already in the cache we're done, pop from the stack if (current.getNumChildren() == 0 || (Theory::theoryOf(current) != THEORY_BOOL && !containsTermITE(current))) { d_simpITECache[current] = current; toVisit.pop_back(); continue; } NodeMap::iterator find = d_simpITECache.find(current); if (find != d_simpITECache.end()) { toVisit.pop_back(); continue; } // Not yet substituted, so process if (stackHead.children_added) { // Children have been processed, so substitute NodeBuilder<> builder(current.getKind()); if (current.getMetaKind() == kind::metakind::PARAMETERIZED) { builder << current.getOperator(); } for (unsigned i = 0; i < current.getNumChildren(); ++ i) { Assert(d_simpITECache.find(current[i]) != d_simpITECache.end()); builder << d_simpITECache[current[i]]; } // Mark the substitution and continue Node result = builder; // If this is an atom, we process it if (Theory::theoryOf(result) != THEORY_BOOL && result.getType().isBoolean()) { result = simpITEAtom(result); } result = Rewriter::rewrite(result); d_simpITECache[current] = result; toVisit.pop_back(); } else { // Mark that we have added the children if any if (current.getNumChildren() > 0) { stackHead.children_added = true; // We need to add the children for(TNode::iterator child_it = current.begin(); child_it != current.end(); ++ child_it) { TNode childNode = *child_it; NodeMap::iterator childFind = d_simpITECache.find(childNode); if (childFind == d_simpITECache.end()) { toVisit.push_back(childNode); } } } else { // No children, so we're done d_simpITECache[current] = current; toVisit.pop_back(); } } } return d_simpITECache[assertion]; }
Node SubstitutionEx::internalApply(TNode node) { if (d_substitutions.empty()) return node; vector<SubstitutionStackElement> stack; stack.push_back(SubstitutionStackElement(node)); while (!stack.empty()) { SubstitutionStackElement head = stack.back(); stack.pop_back(); TNode current = head.node; if (hasCache(current)) { continue; } // check if it has substitution Substitutions::const_iterator it = d_substitutions.find(current); if (it != d_substitutions.end()) { vector<Node> reasons; TNode to = it->second.to; reasons.push_back(it->second.reason); // check if the thing we subsituted to has substitutions TNode res = internalApply(to); // update reasons reasons.push_back(getReason(to)); Node reason = mergeExplanations(reasons); storeCache(current, res, reason); continue; } // if no children then just continue if(current.getNumChildren() == 0) { storeCache(current, current, utils::mkTrue()); continue; } // children already processed if (head.childrenAdded) { NodeBuilder<> nb(current.getKind()); std::vector<Node> reasons; if (current.getMetaKind() == kind::metakind::PARAMETERIZED) { TNode op = current.getOperator(); Assert (hasCache(op)); nb << getCache(op); reasons.push_back(getReason(op)); } for (unsigned i = 0; i < current.getNumChildren(); ++i) { Assert (hasCache(current[i])); nb << getCache(current[i]); reasons.push_back(getReason(current[i])); } Node result = nb; // if the node is new apply substitutions to it Node subst_result = result; if (result != current) { subst_result = result!= current? internalApply(result) : result; reasons.push_back(getReason(result)); } Node reason = mergeExplanations(reasons); storeCache(current, subst_result, reason); continue; } else { // add children to stack stack.push_back(SubstitutionStackElement(current, true)); if (current.getMetaKind() == kind::metakind::PARAMETERIZED) { stack.push_back(SubstitutionStackElement(current.getOperator())); } for (unsigned i = 0; i < current.getNumChildren(); ++i) { stack.push_back(SubstitutionStackElement(current[i])); } } } Assert(hasCache(node)); return getCache(node); }