void collectAtoms(TNode node, CVC4::NodeSet& seen) { if (seen.find(node) != seen.end()) return; if (theory::Theory::theoryOf(node) != theory::THEORY_BOOL || node.isVar()) { seen.insert(node); return; } for (unsigned i = 0; i < node.getNumChildren(); ++i) { collectAtoms(node[i], seen); } }
void EagerBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) { TNodeSet::iterator it = d_variables.begin(); for (; it!= d_variables.end(); ++it) { TNode var = *it; if (d_bv->isLeaf(var) || isSharedTerm(var) || (var.isVar() && var.getType().isBoolean())) { // only shared terms could not have been bit-blasted Assert (hasBBTerm(var) || isSharedTerm(var)); Node const_value = getModelFromSatSolver(var, fullModel); if(const_value != Node()) { Debug("bitvector-model") << "EagerBitblaster::collectModelInfo (assert (= " << var << " " << const_value << "))\n"; m->assertEquality(var, const_value, true); } } } }
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 UnconstrainedSimplifier::visitAll(TNode assertion) { // Do a topological sort of the subexpressions and substitute them vector<unc_preprocess_stack_element> toVisit; toVisit.push_back(assertion); while (!toVisit.empty()) { // The current node we are processing TNode current = toVisit.back().node; TNode parent = toVisit.back().parent; toVisit.pop_back(); TNodeCountMap::iterator find = d_visited.find(current); if (find != d_visited.end()) { if (find->second == 1) { d_visitedOnce.erase(current); if (current.isVar()) { d_unconstrained.erase(current); } } ++find->second; continue; } d_visited[current] = 1; d_visitedOnce[current] = parent; if (current.getNumChildren() == 0) { if (current.getKind()==kind::VARIABLE || current.getKind()==kind::SKOLEM) { d_unconstrained.insert(current); } } else { for(TNode::iterator child_it = current.begin(); child_it != current.end(); ++ child_it) { TNode childNode = *child_it; toVisit.push_back(unc_preprocess_stack_element(childNode, current)); } } } }
bool TheoryEngineModelBuilder::isAssignable(TNode n) { return (n.isVar() || n.getKind() == kind::APPLY_UF || n.getKind() == kind::SELECT || n.getKind() == kind::APPLY_SELECTOR); }
PreprocessingPassResult SynthRewRulesPass::applyInternal( AssertionPipeline* assertionsToPreprocess) { Trace("synth-rr-pass") << "Synthesize rewrite rules from assertions..." << std::endl; std::vector<Node>& assertions = assertionsToPreprocess->ref(); // compute the variables we will be sampling std::vector<Node> vars; unsigned nsamples = options::sygusSamples(); Options& nodeManagerOptions = NodeManager::currentNM()->getOptions(); // attribute to mark processed terms SynthRrComputedAttribute srrca; // initialize the candidate rewrite std::unique_ptr<theory::quantifiers::CandidateRewriteDatabaseGen> crdg; std::unordered_map<TNode, bool, TNodeHashFunction> visited; std::unordered_map<TNode, bool, TNodeHashFunction>::iterator it; std::vector<TNode> visit; // two passes: the first collects the variables, the second registers the // terms for (unsigned r = 0; r < 2; r++) { visited.clear(); visit.clear(); TNode cur; for (const Node& a : assertions) { visit.push_back(a); do { cur = visit.back(); visit.pop_back(); it = visited.find(cur); // if already processed, ignore if (cur.getAttribute(SynthRrComputedAttribute())) { Trace("synth-rr-pass-debug") << "...already processed " << cur << std::endl; } else if (it == visited.end()) { Trace("synth-rr-pass-debug") << "...preprocess " << cur << std::endl; visited[cur] = false; Kind k = cur.getKind(); bool isQuant = k == kind::FORALL || k == kind::EXISTS || k == kind::LAMBDA || k == kind::CHOICE; // we recurse on this node if it is not a quantified formula if (!isQuant) { visit.push_back(cur); for (const Node& cc : cur) { visit.push_back(cc); } } } else if (!it->second) { Trace("synth-rr-pass-debug") << "...postprocess " << cur << std::endl; // check if all of the children are valid // this ensures we do not register terms that have e.g. quantified // formulas as subterms bool childrenValid = true; for (const Node& cc : cur) { Assert(visited.find(cc) != visited.end()); if (!visited[cc]) { childrenValid = false; } } if (childrenValid) { Trace("synth-rr-pass-debug") << "...children are valid, check rewrites..." << std::endl; if (r == 0) { if (cur.isVar()) { vars.push_back(cur); } } else { Trace("synth-rr-pass-debug") << "Add term " << cur << std::endl; // mark as processed cur.setAttribute(srrca, true); bool ret = crdg->addTerm(cur, *nodeManagerOptions.getOut()); Trace("synth-rr-pass-debug") << "...return " << ret << std::endl; // if we want only rewrites of minimal size terms, we would set // childrenValid to false if ret is false here. } } visited[cur] = childrenValid; } } while (!visit.empty()); } if (r == 0) { Trace("synth-rr-pass-debug") << "Initialize with " << nsamples << " samples and variables : " << vars << std::endl; crdg = std::unique_ptr<theory::quantifiers::CandidateRewriteDatabaseGen>( new theory::quantifiers::CandidateRewriteDatabaseGen(vars, nsamples)); } } Trace("synth-rr-pass") << "...finished " << std::endl; return PreprocessingPassResult::NO_CONFLICT; }
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; }
void CoreSolver::buildModel() { Debug("bv-core") << "CoreSolver::buildModel() \n"; NodeManager* nm = NodeManager::currentNM(); d_modelValues.clear(); TNodeSet constants; TNodeSet constants_in_eq_engine; // collect constants in equality engine eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(&d_equalityEngine); while (!eqcs_i.isFinished()) { TNode repr = *eqcs_i; if (repr.getKind() == kind::CONST_BITVECTOR) { // must check if it's just the constant eq::EqClassIterator it(repr, &d_equalityEngine); if (!(++it).isFinished() || true) { constants.insert(repr); constants_in_eq_engine.insert(repr); } } ++eqcs_i; } // build repr to value map eqcs_i = eq::EqClassesIterator(&d_equalityEngine); while (!eqcs_i.isFinished()) { TNode repr = *eqcs_i; ++eqcs_i; if (!repr.isVar() && repr.getKind() != kind::CONST_BITVECTOR && !d_bv->isSharedTerm(repr)) { continue; } TypeNode type = repr.getType(); if (type.isBitVector() && repr.getKind() != kind::CONST_BITVECTOR) { Debug("bv-core-model") << " processing " << repr << "\n"; // we need to assign a value for it TypeEnumerator te(type); Node val; do { val = *te; ++te; // Debug("bv-core-model") << " trying value " << val << "\n"; // Debug("bv-core-model") << " is in set? " << constants.count(val) << // "\n"; Debug("bv-core-model") << " enumerator done? " << // te.isFinished() << "\n"; } while (constants.count(val) != 0 && !(te.isFinished())); if (te.isFinished() && constants.count(val) != 0) { // if we cannot enumerate anymore values we just return the lemma // stating that at least two of the representatives are equal. std::vector<TNode> representatives; representatives.push_back(repr); for (TNodeSet::const_iterator it = constants_in_eq_engine.begin(); it != constants_in_eq_engine.end(); ++it) { TNode constant = *it; if (utils::getSize(constant) == utils::getSize(repr)) { representatives.push_back(constant); } } for (ModelValue::const_iterator it = d_modelValues.begin(); it != d_modelValues.end(); ++it) { representatives.push_back(it->first); } std::vector<Node> equalities; for (unsigned i = 0; i < representatives.size(); ++i) { for (unsigned j = i + 1; j < representatives.size(); ++j) { TNode a = representatives[i]; TNode b = representatives[j]; if (a.getKind() == kind::CONST_BITVECTOR && b.getKind() == kind::CONST_BITVECTOR) { Assert(a != b); continue; } if (utils::getSize(a) == utils::getSize(b)) { equalities.push_back(nm->mkNode(kind::EQUAL, a, b)); } } } // better off letting the SAT solver split on values if (equalities.size() > d_lemmaThreshold) { d_isComplete = false; return; } if (equalities.size() == 0) { Debug("bv-core") << " lemma: true (no equalities)" << std::endl; } else { Node lemma = utils::mkOr(equalities); d_bv->lemma(lemma); Debug("bv-core") << " lemma: " << lemma << std::endl; } return; } Debug("bv-core-model") << " " << repr << " => " << val << "\n"; constants.insert(val); d_modelValues[repr] = val; } } }
TheoryId Theory::theoryOf(TheoryOfMode mode, TNode node) { TheoryId tid = THEORY_BUILTIN; switch(mode) { case THEORY_OF_TYPE_BASED: // Constants, variables, 0-ary constructors if (node.isVar() || node.isConst()) { tid = Theory::theoryOf(node.getType()); } else if (node.getKind() == kind::EQUAL) { // Equality is owned by the theory that owns the domain tid = Theory::theoryOf(node[0].getType()); } else { // Regular nodes are owned by the kind tid = kindToTheoryId(node.getKind()); } break; case THEORY_OF_TERM_BASED: // Variables if (node.isVar()) { if (Theory::theoryOf(node.getType()) != theory::THEORY_BOOL) { // We treat the variables as uninterpreted tid = s_uninterpretedSortOwner; } else { // Except for the Boolean ones, which we just ignore anyhow tid = theory::THEORY_BOOL; } } else if (node.isConst()) { // Constants go to the theory of the type tid = Theory::theoryOf(node.getType()); } else if (node.getKind() == kind::EQUAL) { // Equality // If one of them is an ITE, it's irelevant, since they will get replaced out anyhow if (node[0].getKind() == kind::ITE) { tid = Theory::theoryOf(node[0].getType()); } else if (node[1].getKind() == kind::ITE) { tid = Theory::theoryOf(node[1].getType()); } else { TNode l = node[0]; TNode r = node[1]; TypeNode ltype = l.getType(); TypeNode rtype = r.getType(); if( ltype != rtype ){ tid = Theory::theoryOf(l.getType()); }else { // If both sides belong to the same theory the choice is easy TheoryId T1 = Theory::theoryOf(l); TheoryId T2 = Theory::theoryOf(r); if (T1 == T2) { tid = T1; } else { TheoryId T3 = Theory::theoryOf(ltype); // This is a case of // * x*y = f(z) -> UF // * x = c -> UF // * f(x) = read(a, y) -> either UF or ARRAY // at least one of the theories has to be parametric, i.e. theory of the type is different // from the theory of the term if (T1 == T3) { tid = T2; } else if (T2 == T3) { tid = T1; } else { // If both are parametric, we take the smaller one (arbitrary) tid = T1 < T2 ? T1 : T2; } } } } } else { // Regular nodes are owned by the kind tid = kindToTheoryId(node.getKind()); } break; default: Unreachable(); } Trace("theory::internal") << "theoryOf(" << mode << ", " << node << ") -> " << tid << std::endl; return tid; }