void context::display_subexprs_info(std::ostream & out, expr * n) const { ptr_buffer<expr> todo; todo.push_back(n); while (!todo.empty()) { expr * n = todo.back(); todo.pop_back(); out << "#"; out.width(6); out << std::left << n->get_id(); out << ", relevant: " << is_relevant(n); if (m_manager.is_bool(n)) { out << ", val: "; out.width(7); out << std::right; if (lit_internalized(n)) out << get_assignment(n); else out << "l_undef"; } if (e_internalized(n)) { enode * e = get_enode(n); out << ", root: #" << e->get_root()->get_owner_id(); } out << "\n"; if (is_app(n)) { for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) todo.push_back(to_app(n)->get_arg(i)); } } }
bool quasi_macros::depends_on(expr * e, func_decl * f) const { ptr_vector<expr> todo; expr_mark visited; todo.push_back(e); while(!todo.empty()) { expr * cur = todo.back(); todo.pop_back(); if (visited.is_marked(cur)) continue; if (is_app(cur)) { app * a = to_app(cur); if (a->get_decl() == f) return true; unsigned j = a->get_num_args(); while (j>0) todo.push_back(a->get_arg(--j)); } visited.mark(cur, true); } return false; }
void save_candidate(expr * t, bool form_ctx) { if (!form_ctx) return; if (!m.is_bool(t)) return; if (!m_has_term_ite.is_marked(t)) return; if (!is_app(t)) return; if (to_app(t)->get_family_id() == m.get_basic_family_id()) { switch (to_app(t)->get_decl_kind()) { case OP_OR: case OP_AND: case OP_NOT: case OP_XOR: case OP_IMPLIES: case OP_TRUE: case OP_FALSE: case OP_ITE: return; case OP_EQ: case OP_DISTINCT: if (m.is_bool(to_app(t)->get_arg(0))) return; break; default: break; } } // it is an atom in a formula context (i.e., it is not nested inside a term), // and it contains a term if-then-else. m_candidates.insert(t); }
void mk_interp_tail_simplifier::rule_substitution::apply(app * a, app_ref& res) { SASSERT(m_rule); expr_ref res_e(m); m_subst.apply(a, res_e); SASSERT(is_app(res_e.get())); res = to_app(res_e.get()); }
void process(expr * f) { if (fvisited.is_marked(f)) return; fvisited.mark(f); todo.push_back(f); while (!todo.empty()) { expr * t = todo.back(); todo.pop_back(); if (is_uninterp_const(t)) continue; if (is_app(t) && to_app(t)->get_family_id() == m.get_basic_family_id() && to_app(t)->get_num_args() > 0) { decl_kind k = to_app(t)->get_decl_kind(); if (k == OP_OR || k == OP_NOT || k == OP_IFF || ((k == OP_EQ || k == OP_ITE) && m.is_bool(to_app(t)->get_arg(1)))) { unsigned num = to_app(t)->get_num_args(); for (unsigned i = 0; i < num; i++) { expr * arg = to_app(t)->get_arg(i); if (fvisited.is_marked(arg)) continue; fvisited.mark(arg); todo.push_back(arg); } } } else { quick_for_each_expr(proc, tvisited, t); } } }
void variable_intersection::populate_self(const app * a) { SASSERT(is_uninterp(a)); //TODO: optimize quadratic complexity //TODO: optimize number of checks when variable occurs multiple times unsigned arity = a->get_num_args(); for(unsigned i1=0; i1<arity; i1++) { expr * e1=a->get_arg(i1); if(is_var(e1)) { var* v1=to_var(e1); for(unsigned i2=i1+1; i2<arity; i2++) { expr * e2=a->get_arg(i2); if(!is_var(e2)) { continue; } var* v2=to_var(e2); if(v1->get_idx()==v2->get_idx()) { add_pair(i1, i2); } } } else { SASSERT(is_app(e1)); app * c1 = to_app(e1); SASSERT(c1->get_num_args()==0); //c1 must be a constant m_const_indexes.push_back(i1); m_consts.push_back(c1); SASSERT(m_const_indexes.size()==m_consts.size()); } } }
void mk_array_instantiation::retrieve_selects(expr* e) { //If the expression is not a function application, we ignore it if (!is_app(e)) { return; } app*f=to_app(e); //Call the function recursively on all arguments unsigned nbargs = f->get_num_args(); for(unsigned i=0;i<nbargs;i++) { retrieve_selects(f->get_arg(i)); } //If it is a select, then add it to selects if(m_a.is_select(f)) { SASSERT(!m_a.is_array(get_sort(e))); selects.insert_if_not_there(f->get_arg(0), ptr_vector<expr>()); selects[f->get_arg(0)].push_back(e); } //If it is a condition between arrays, for example the result of a store, then add it to the equiv_classes if(m_a.is_store(f)) { eq_classes.merge(e, f->get_arg(0)); } else if(m.is_eq(f) && m_a.is_array(get_sort(f->get_arg(0)))) { eq_classes.merge(f->get_arg(0), f->get_arg(1)); } }
bool expr_delta::delta_dfs(unsigned& n, expr* e, expr_ref& result) { ast_manager& m = m_manager; if (m.is_true(e) || m.is_false(e)) { return false; } if (n == 0 && m.is_bool(e)) { result = m.mk_true(); return true; } else if (n == 1 && m.is_bool(e)) { result = m.mk_false(); return true; } else if (is_app(e)) { if (m.is_bool(e)) { SASSERT(n >= 2); n -= 2; } return delta_dfs(n, to_app(e), result); } else if (is_quantifier(e)) { SASSERT(n >= 2); n -= 2; quantifier* q = to_quantifier(e); if (delta_dfs(n, q->get_expr(), result)) { result = m.update_quantifier(q, result.get()); return true; } else { return false; } } return false; }
void expr_context_simplifier::reduce_rec(expr * m, expr_ref & result) { // // reduce expr in context evaluation. // bool polarity; if (m_context.find(m, polarity)) { result = polarity ? m_manager.mk_true() : m_manager.mk_false(); } else if (m_mark.is_marked(m) && !m_manager.is_not(m)) { result = m; } else if (is_quantifier(m)) { reduce_rec(to_quantifier(m), result); m_mark.mark(m, true); } else if (is_app(m)) { reduce_rec(to_app(m), result); m_mark.mark(m, true); } else if (is_var(m)) { result = m; m_mark.mark(m, true); } else { UNREACHABLE(); result = m; } }
expr const & get_app_rev_args(expr const & e, buffer<expr> & args) { expr const * it = &e; while (is_app(*it)) { args.push_back(app_arg(*it)); it = &(app_fn(*it)); } return *it; }
void visit_args(expr * t, expr_fast_mark1 & visited) { if (is_app(t)) { for (expr * arg : *to_app(t)) { save_degree(arg, m_one); visit(arg, visited); } } }
unsigned get_app_num_args(expr const & e) { expr const * it = &e; unsigned n = 0; while (is_app(*it)) { it = &(app_fn(*it)); n++; } return n; }
static bool to_apps(unsigned n, Z3_app const es[], app_ref_vector& result) { for (unsigned i = 0; i < n; ++i) { if (!is_app(to_app(es[i]))) { return false; } result.push_back (to_app (es [i])); } return true; }
br_status pull_ite(expr_ref & result) { expr * t = result.get(); if (is_app(t)) { br_status st = pull_ite(to_app(t)->get_decl(), to_app(t)->get_num_args(), to_app(t)->get_args(), result); if (st != BR_FAILED) return st; } return BR_DONE; }
void visit_args(expr * t, expr_fast_mark1 & visited) { if (is_app(t)) { unsigned num_args = to_app(t)->get_num_args(); for (unsigned i = 0; i < num_args; i++) { expr * arg = to_app(t)->get_arg(i); save_degree(arg, m_one); visit(arg, visited); } } }
expr const & get_app_args(expr const & e, buffer<expr> & args) { unsigned sz = args.size(); expr const * it = &e; while (is_app(*it)) { args.push_back(app_arg(*it)); it = &(app_fn(*it)); } std::reverse(args.begin() + sz, args.end()); return *it; }
br_status datatype_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { if (!is_app(lhs) || !is_app(rhs) || !m_util.is_constructor(to_app(lhs)) || !m_util.is_constructor(to_app(rhs))) return BR_FAILED; if (to_app(lhs)->get_decl() != to_app(rhs)->get_decl()) { result = m().mk_false(); return BR_DONE; } // Remark: In datatype_simplifier_plugin, we used // m_basic_simplifier to create '=' and 'and' applications in the // following code. This trick not guarantee that the final expression // will be fully simplified. // // Example: // The assertion // (assert (= (cons a1 (cons a2 (cons a3 (cons (+ a4 1) (cons (+ a5 c5) (cons a6 nil)))))) // (cons b1 (cons b2 (cons b3 (cons b4 (cons b5 (cons b6 nil)))))))) // // After applying asserted_formulas::reduce(), the following formula was generated. // // (= a1 b1) // (= a2 b2) // (= a3 b3) // (= (+ a4 (* (- 1) b4)) (- 1)) // (= (+ c5 a5) b5) <<< NOT SIMPLIFIED WITH RESPECT TO ARITHMETIC // (= (cons a6 nil) (cons b6 nil))) <<< NOT SIMPLIFIED WITH RESPECT TO DATATYPE theory // // Note that asserted_formulas::reduce() applied the simplier many times. // After the first simplification step we had: // (= a1 b1) // (= (cons a2 (cons a3 (cons (+ a4 1) (cons (+ a5 c5) (cons a6 nil)))))) // (cons b2 (cons b3 (cons b4 (cons b5 (cons b6 nil)))))) ptr_buffer<expr> eqs; unsigned num = to_app(lhs)->get_num_args(); SASSERT(num == to_app(rhs)->get_num_args()); for (unsigned i = 0; i < num; ++i) { eqs.push_back(m().mk_eq(to_app(lhs)->get_arg(i), to_app(rhs)->get_arg(i))); } result = m().mk_and(eqs.size(), eqs.c_ptr()); return BR_REWRITE2; }
/** \brief Return true if s >_{lpo} t_i forall children t_i of t. */ bool lpo::dominates_args(expr_offset s, expr_offset t, unsigned depth) { SASSERT(is_app(t.get_expr())); unsigned num_args = to_app(t.get_expr())->get_num_args(); unsigned off = t.get_offset(); for (unsigned i = 0; i < num_args; i++) { expr * t_i = to_app(t.get_expr())->get_arg(i); if (!greater(s, expr_offset(t_i, off), depth+1)) return false; } return true; }
expr* apply_accessor( ptr_vector<func_decl> const& acc, unsigned j, func_decl* f, expr* c) { if (is_app(c) && to_app(c)->get_decl() == f) { return to_app(c)->get_arg(j); } else { return m.mk_app(acc[j], c); } }
bool is_atom(ast_manager & m, expr * n) { if (is_quantifier(n) || !m.is_bool(n)) return false; if (is_var(n)) return true; SASSERT(is_app(n)); if (to_app(n)->get_family_id() != m.get_basic_family_id()) { return true; } // the other operators of the basic family are not considered atomic: distinct, ite, and, or, iff, xor, not, implies. return (m.is_eq(n) && !m.is_bool(to_app(n)->get_arg(0))) || m.is_true(n) || m.is_false(n); }
static optional<pair<expr, unsigned>> find_hyp_core(expr const & meta, F && pred) { expr const * it = &meta; unsigned i = 0; while (is_app(*it)) { expr const & h = app_arg(*it); if (pred(h)) return some(mk_pair(h, i)); i++; it = &app_fn(*it); } return optional<pair<expr, unsigned>>(); }
/** \brief Return true if s_i >=_{lpo} t for some arg s_i of s. */ bool lpo::arg_dominates_expr(expr_offset s, expr_offset t, unsigned depth) { SASSERT(is_app(s.get_expr())); unsigned num_args = to_app(s.get_expr())->get_num_args(); unsigned off = s.get_offset(); for (unsigned i = 0; i < num_args; i++) { expr * s_i = to_app(s.get_expr())->get_arg(i); result r = compare(expr_offset(s_i, off), t, depth+1); if (r == EQUAL || r == GREATER) return true; } return false; }
bool reduce_arg(expr* a, expr_ref& result) { sort* s = get_sort(a); if (!m_imp.is_fd(s)) { return false; } unsigned bv_size = get_bv_size(s); if (is_var(a)) { result = m.mk_var(to_var(a)->get_idx(), m_bv.mk_sort(bv_size)); return true; } SASSERT(is_app(a)); func_decl* f = to_app(a)->get_decl(); if (m_dt.is_constructor(f)) { unsigned idx = m_dt.get_constructor_idx(f); result = m_bv.mk_numeral(idx, bv_size); } else if (is_uninterp_const(a)) { func_decl* f_fresh; if (m_imp.m_enum2bv.find(f, f_fresh)) { result = m.mk_const(f_fresh); return true; } // create a fresh variable, add bounds constraints for it. unsigned nc = m_dt.get_datatype_num_constructors(s); result = m.mk_fresh_const(f->get_name().str().c_str(), m_bv.mk_sort(bv_size)); f_fresh = to_app(result)->get_decl(); if (!is_power_of_two(nc) || nc == 1) { m_imp.m_bounds.push_back(m_bv.mk_ule(result, m_bv.mk_numeral(nc-1, bv_size))); } expr_ref f_def(m); ptr_vector<func_decl> const& cs = *m_dt.get_datatype_constructors(s); f_def = m.mk_const(cs[nc-1]); for (unsigned i = nc - 1; i > 0; ) { --i; f_def = m.mk_ite(m.mk_eq(result, m_bv.mk_numeral(i,bv_size)), m.mk_const(cs[i]), f_def); } m_imp.m_enum2def.insert(f, f_def); m_imp.m_enum2bv.insert(f, f_fresh); m_imp.m_bv2enum.insert(f_fresh, f); m_imp.m_enum_consts.push_back(f); m_imp.m_enum_bvs.push_back(f_fresh); m_imp.m_enum_defs.push_back(f_def); } else { throw_non_fd(a); } ++m_imp.m_num_translated; return true; }
void operator()(expr * t) { SASSERT(m.is_bool(t)); push_frame(t, true); SASSERT(!m_frame_stack.empty()); while (!m_frame_stack.empty()) { frame & fr = m_frame_stack.back(); expr * t = fr.m_t; bool form_ctx = fr.m_form_ctx; TRACE("cofactor", tout << "processing, form_ctx: " << form_ctx << "\n" << mk_bounded_pp(t, m) << "\n";); m_owner.checkpoint(); if (m_processed.is_marked(t)) { save_candidate(t, form_ctx); m_frame_stack.pop_back(); continue; } if (m.is_term_ite(t)) { m_has_term_ite.mark(t); m_processed.mark(t); m_frame_stack.pop_back(); continue; } if (fr.m_first) { fr.m_first = false; bool visited = true; if (is_app(t)) { unsigned num_args = to_app(t)->get_num_args(); for (unsigned i = 0; i < num_args; i++) visit(to_app(t)->get_arg(i), form_ctx, visited); } // ignoring quantifiers if (!visited) continue; } if (is_app(t)) { unsigned num_args = to_app(t)->get_num_args(); unsigned i; for (i = 0; i < num_args; i++) { if (m_has_term_ite.is_marked(to_app(t)->get_arg(i))) break; } if (i < num_args) { m_has_term_ite.mark(t); TRACE("cofactor", tout << "saving candidate: " << form_ctx << "\n" << mk_bounded_pp(t, m) << "\n";); save_candidate(t, form_ctx); }
expr const & get_app_args_at_most(expr const & e, unsigned num, buffer<expr> & args) { unsigned sz = args.size(); expr const * it = &e; unsigned i = 0; while (is_app(*it)) { if (i == num) break; args.push_back(app_arg(*it)); it = &(app_fn(*it)); i++; } std::reverse(args.begin() + sz, args.end()); return *it; }
void fixedpoint_context::simplify_rules( unsigned num_rules, expr* const* rules, unsigned num_outputs, func_decl* const* outputs, expr_ref_vector& result) { ast_manager& m = m_context.get_manager(); datalog::context ctx(m, m_context.get_fparams()); datalog::rule_manager& rm = ctx.get_rule_manager(); for (unsigned i = 0; i < num_rules; ++i) { expr* rule = rules[i], *body, *head; while (true) { if (is_quantifier(rule)) { rule = to_quantifier(rule)->get_expr(); } else if (m.is_implies(rule, body, head)) { rule = head; } else { break; } } if (is_app(rule)) { func_decl* r = to_app(rule)->get_decl(); if (!ctx.is_predicate(r)) { ctx.register_predicate(r); if (num_outputs == 0) { ctx.set_output_predicate(r); } } } } for (unsigned i = 0; i < num_outputs; ++i) { ctx.set_output_predicate(outputs[i]); } for (unsigned i = 0; i < num_rules; ++i) { expr* rule = rules[i]; ctx.add_rule(rule, symbol::null); } model_converter_ref mc; // not exposed. proof_converter_ref pc; // not exposed. ctx.apply_default_transformation(mc, pc); datalog::rule_set const& new_rules = ctx.get_rules(); datalog::rule_set::iterator it = new_rules.begin(), end = new_rules.end(); for (; it != end; ++it) { datalog::rule* r = *it; expr_ref fml(m); r->to_formula(fml); result.push_back(fml); } }
void mk_coalesce::merge_rules(rule_ref& tgt, rule const& src) { SASSERT(same_body(*tgt.get(), src)); m_sub1.reset(); m_sub2.reset(); m_idx = 0; app_ref pred(m), head(m); expr_ref fml1(m), fml2(m), fml(m); app_ref_vector tail(m); ptr_vector<sort> sorts1, sorts2; expr_ref_vector conjs1(m), conjs(m); rule_ref res(rm); bool_rewriter bwr(m); svector<bool> is_neg; tgt->get_vars(sorts1); src.get_vars(sorts2); mk_pred(head, src.get_head(), tgt->get_head()); for (unsigned i = 0; i < src.get_uninterpreted_tail_size(); ++i) { mk_pred(pred, src.get_tail(i), tgt->get_tail(i)); tail.push_back(pred); is_neg.push_back(src.is_neg_tail(i)); } extract_conjs(m_sub1, src, fml1); extract_conjs(m_sub2, *tgt.get(), fml2); bwr.mk_or(fml1, fml2, fml); SASSERT(is_app(fml)); tail.push_back(to_app(fml)); is_neg.push_back(false); res = rm.mk(head, tail.size(), tail.c_ptr(), is_neg.c_ptr(), tgt->name()); if (m_ctx.generate_proof_trace()) { src.to_formula(fml1); tgt->to_formula(fml2); res->to_formula(fml); #if 0 sort* ps = m.mk_proof_sort(); sort* domain[3] = { ps, ps, m.mk_bool_sort() }; func_decl* merge = m.mk_func_decl(symbol("merge-clauses"), 3, domain, ps); // TBD: ad-hoc proof rule expr* args[3] = { m.mk_asserted(fml1), m.mk_asserted(fml2), fml }; // ...m_pc->insert(m.mk_app(merge, 3, args)); #else svector<std::pair<unsigned, unsigned> > pos; vector<expr_ref_vector> substs; proof* p = src.get_proof(); p = m.mk_hyper_resolve(1, &p, fml, pos, substs); res->set_proof(m, p); #endif } tgt = res; }
order::result lpo::lex_compare(expr_offset s, expr_offset t, unsigned depth) { SASSERT(is_app(s.get_expr())); SASSERT(is_app(t.get_expr())); app * _s = to_app(s.get_expr()); app * _t = to_app(t.get_expr()); unsigned num_args1 = _s->get_num_args(); unsigned num_args2 = _t->get_num_args(); unsigned num_args = std::min(num_args1, num_args2); unsigned off1 = s.get_offset(); unsigned off2 = t.get_offset(); result r = EQUAL; for (unsigned i = 0; i < num_args; i++) { r = compare(expr_offset(_s->get_arg(i), off1), expr_offset(_t->get_arg(i), off2), depth+1); if (r != EQUAL) break; } if (r == EQUAL) { if (num_args1 > num_args2) return GREATER; if (num_args1 < num_args2) return NOT_GTEQ; } return r; }
void superposition::insert_r(clause * cls, expr * n, unsigned i, bool lhs) { if (is_app(n)) { unsigned idx = (i << 1) | static_cast<unsigned>(lhs); clause_pos_pair new_pair(cls, idx); SASSERT(m_todo.empty()); m_todo.push_back(to_app(n)); while (!m_todo.empty()) { app * n = m_todo.back(); m_todo.pop_back(); clause_pos_set * s = m_r2clause_set.get_parents(n); if (s == 0 || !s->contains(new_pair)) { m_r.insert(n); m_r2clause_set.insert(new_pair, n); unsigned num_args = n->get_num_args(); for (unsigned i = 0; i < num_args; i++) { expr * c = n->get_arg(i); if (is_app(c)) m_todo.push_back(to_app(c)); } } } } }
Z3_pattern Z3_API Z3_mk_pattern(Z3_context c, unsigned num_patterns, Z3_ast const terms[]) { Z3_TRY; LOG_Z3_mk_pattern(c, num_patterns, terms); RESET_ERROR_CODE(); for (unsigned i = 0; i < num_patterns; ++i) { if (!is_app(to_expr(terms[i]))) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } } app* a = mk_c(c)->m().mk_pattern(num_patterns, reinterpret_cast<app*const*>(to_exprs(terms))); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_pattern(a)); Z3_CATCH_RETURN(0); }