tactic * mk_qflra_tactic(ast_manager & m, params_ref const & p) { params_ref pivot_p; pivot_p.set_bool("arith.greatest_error_pivot", true); params_ref main_p = p; main_p.set_bool("elim_and", true); main_p.set_bool("som", true); main_p.set_bool("blast_distinct", true); params_ref ctx_simp_p; ctx_simp_p.set_uint("max_depth", 30); ctx_simp_p.set_uint("max_steps", 5000000); params_ref lhs_p; lhs_p.set_bool("arith_lhs", true); lhs_p.set_bool("eq2ineq", true); params_ref elim_to_real_p; elim_to_real_p.set_bool("elim_to_real", true); #if 0 tactic * mip = and_then(fail_if(mk_produce_proofs_probe()), fail_if(mk_produce_unsat_cores_probe()), using_params(and_then(and_then(mk_simplify_tactic(m), mk_recover_01_tactic(m), using_params(mk_simplify_tactic(m), elim_to_real_p), mk_propagate_values_tactic(m)), using_params(mk_ctx_simplify_tactic(m), ctx_simp_p), mk_elim_uncnstr_tactic(m), mk_solve_eqs_tactic(m), using_params(mk_simplify_tactic(m), lhs_p), using_params(mk_simplify_tactic(m), elim_to_real_p) ), main_p), fail_if(mk_not(mk_is_mip_probe())), try_for(mk_mip_tactic(m), 30000), mk_fail_if_undecided_tactic()); #endif // return using_params(or_else(mip, // using_params(mk_smt_tactic(m), pivot_p)), // p); #if 0 params_ref simplex_0, simplex_1, simplex_2; simplex_0.set_uint("lp.simplex_strategy", 0); simplex_1.set_uint("lp.simplex_strategy", 1); simplex_2.set_uint("lp.simplex_strategy", 2); return par(using_params(mk_smt_tactic(), simplex_0), using_params(mk_smt_tactic(), simplex_1), using_params(mk_smt_tactic(), simplex_2)); #else return using_params(using_params(mk_smt_tactic(m), pivot_p), p); #endif }
static tactic * mk_quant_preprocessor(ast_manager & m, bool disable_gaussian = false) { params_ref pull_ite_p; pull_ite_p.set_bool(":pull-cheap-ite", true); pull_ite_p.set_bool(":local-ctx", true); pull_ite_p.set_uint(":local-ctx-limit", 10000000); params_ref ctx_simp_p; ctx_simp_p.set_uint(":max-depth", 30); ctx_simp_p.set_uint(":max-steps", 5000000); tactic * solve_eqs; if (disable_gaussian) solve_eqs = mk_skip_tactic(); else solve_eqs = when(mk_not(mk_has_pattern_probe()), mk_solve_eqs_tactic(m)); // remark: investigate if gaussian elimination is useful when patterns are not provided. return and_then(mk_simplify_tactic(m), mk_propagate_values_tactic(m), using_params(mk_ctx_simplify_tactic(m), ctx_simp_p), using_params(mk_simplify_tactic(m), pull_ite_p), solve_eqs, mk_elim_uncnstr_tactic(m), mk_simplify_tactic(m)); }
void asserted_formulas::push_assertion(expr * e, proof * pr, vector<justified_expr>& result) { if (inconsistent()) { return; } expr* e1 = nullptr; if (m.is_false(e)) { result.push_back(justified_expr(m, e, pr)); m_inconsistent = true; } else if (m.is_true(e)) { // skip } else if (m.is_and(e)) { for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { expr* arg = to_app(e)->get_arg(i); proof_ref _pr(m.proofs_enabled() ? m.mk_and_elim(pr, i) : nullptr, m); push_assertion(arg, _pr, result); } } else if (m.is_not(e, e1) && m.is_or(e1)) { for (unsigned i = 0; i < to_app(e1)->get_num_args(); ++i) { expr* arg = to_app(e1)->get_arg(i); proof_ref _pr(m.proofs_enabled() ? m.mk_not_or_elim(pr, i) : nullptr, m); expr_ref narg(mk_not(m, arg), m); push_assertion(narg, _pr, result); } } else { result.push_back(justified_expr(m, e, pr)); } }
Z3_probe Z3_API Z3_probe_not(Z3_context c, Z3_probe p) { Z3_TRY; LOG_Z3_probe_not(c, p); RESET_ERROR_CODE(); probe * new_p = mk_not(to_probe_ref(p)); RETURN_PROBE(new_p); Z3_CATCH_RETURN(0); }
// If restricted is true, we don't use (e <-> true) rewrite list<expr_pair> apply(expr const & e, expr const & H, bool restrited) { expr c, Hdec, A, arg1, arg2; if (is_relation(e)) { return mk_singleton(e, H); } else if (is_standard(m_env) && is_not(m_env, e, arg1)) { expr new_e = mk_iff(arg1, mk_false()); expr new_H = mk_app(mk_constant(get_iff_false_intro_name()), arg1, H); return mk_singleton(new_e, new_H); } else if (is_standard(m_env) && is_and(e, arg1, arg2)) { // TODO(Leo): we can extend this trick to any type that has only one constructor expr H1 = mk_app(mk_constant(get_and_elim_left_name()), arg1, arg2, H); expr H2 = mk_app(mk_constant(get_and_elim_right_name()), arg1, arg2, H); auto r1 = apply(arg1, H1, restrited); auto r2 = apply(arg2, H2, restrited); return append(r1, r2); } else if (is_pi(e)) { expr local = mk_local(m_tc.mk_fresh_name(), binding_name(e), binding_domain(e), binding_info(e)); expr new_e = instantiate(binding_body(e), local); expr new_H = mk_app(H, local); auto r = apply(new_e, new_H, restrited); unsigned len = length(r); if (len == 0) { return r; } else if (len == 1 && head(r).first == new_e && head(r).second == new_H) { return mk_singleton(e, H); } else { return lift(local, r); } } else if (is_standard(m_env) && is_ite(e, c, Hdec, A, arg1, arg2) && is_prop(e)) { // TODO(Leo): support HoTT mode if users request expr not_c = mk_not(m_tc, c); expr Hc = mk_local(m_tc.mk_fresh_name(), c); expr Hnc = mk_local(m_tc.mk_fresh_name(), not_c); expr H1 = mk_app({mk_constant(get_implies_of_if_pos_name()), c, arg1, arg2, Hdec, e, Hc}); expr H2 = mk_app({mk_constant(get_implies_of_if_neg_name()), c, arg1, arg2, Hdec, e, Hnc}); auto r1 = lift(Hc, apply(arg1, H1, restrited)); auto r2 = lift(Hnc, apply(arg2, H2, restrited)); return append(r1, r2); } else if (!restrited) { constraint_seq cs; expr new_e = m_tc.whnf(e, cs); if (new_e != e && !cs) { if (auto r = apply(new_e, H, true)) return r; } if (is_standard(m_env) && is_prop(e)) { expr new_e = mk_iff(e, mk_true()); expr new_H = mk_app(mk_constant(get_iff_true_intro_name()), arg1, H); return mk_singleton(new_e, new_H); } else { return list<expr_pair>(); } } else { return list<expr_pair>(); } }
// ax + by < k // <=> // -ax - by >= -k + 1 // <=> // a(1-x) + b(1-y) >= -k + a + b + 1 app * pb_util::mk_lt(unsigned num_args, rational const * _coeffs, expr * const * _args, rational const& _k) { normalize(num_args, _coeffs, _k); expr_ref_vector args(m); for (unsigned i = 0; i < num_args; ++i) { args.push_back(mk_not(m, _args[i])); } m_k = floor(m_k); m_k.neg(); m_k += rational::one(); for (unsigned i = 0; i < num_args; ++i) { m_k += m_coeffs[i]; } return mk_ge(num_args, m_coeffs.c_ptr(), args.c_ptr(), m_k); }
bool bool_rewriter::simp_nested_eq_ite(expr * t, expr_fast_mark1 & neg_lits, expr_fast_mark2 & pos_lits, expr_ref & result) { bool neg = false; m_local_ctx_cost += 3; if (m().is_not(t)) { neg = true; t = to_app(t)->get_arg(0); } if (m().is_iff(t) || m().is_eq(t)) { bool modified = false; expr * new_lhs = simp_arg(to_app(t)->get_arg(0), neg_lits, pos_lits, modified); expr * new_rhs = simp_arg(to_app(t)->get_arg(1), neg_lits, pos_lits, modified); if (!modified) return false; mk_eq(new_lhs, new_rhs, result); if (neg) mk_not(result, result); return true; } if (m().is_ite(t)) { bool modified = false; expr * new_c = simp_arg(to_app(t)->get_arg(0), neg_lits, pos_lits, modified); expr * new_t = simp_arg(to_app(t)->get_arg(1), neg_lits, pos_lits, modified); expr * new_e = simp_arg(to_app(t)->get_arg(2), neg_lits, pos_lits, modified); if (!modified) return false; // It is not safe to invoke mk_ite here, since it can recursively call // local_ctx_simp by // - transforming the ITE into an OR // - and invoked mk_or, that will invoke local_ctx_simp // mk_ite(new_c, new_t, new_e, result); mk_nested_ite(new_c, new_t, new_e, result); if (neg) mk_not(result, result); return true; } return false; }
/** \brief Auxiliary method for local_ctx_simp. Replace args[i] by true if marked in neg_lits. Replace args[i] by false if marked in pos_lits. */ bool bool_rewriter::simp_nested_not_or(unsigned num_args, expr * const * args, expr_fast_mark1 & neg_lits, expr_fast_mark2 & pos_lits, expr_ref & result) { ptr_buffer<expr> new_args; bool simp = false; m_local_ctx_cost += num_args; for (unsigned i = 0; i < num_args; i++) { expr * arg = args[i]; if (neg_lits.is_marked(arg)) { result = m().mk_false(); return true; } if (pos_lits.is_marked(arg)) { simp = true; continue; } if (m().is_not(arg)) { expr * atom = to_app(arg)->get_arg(0); if (neg_lits.is_marked(atom)) { simp = true; continue; } if (pos_lits.is_marked(atom)) { result = m().mk_false(); return true; } } new_args.push_back(arg); } if (simp) { switch(new_args.size()) { case 0: result = m().mk_true(); return true; case 1: mk_not(new_args[0], result); return true; default: result = m().mk_not(m().mk_or(new_args.size(), new_args.c_ptr())); return true; } } return false; }
bool basic_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { set_reduce_invoked(); SASSERT(f->get_family_id() == m_manager.get_basic_family_id()); basic_op_kind k = static_cast<basic_op_kind>(f->get_decl_kind()); switch (k) { case OP_FALSE: case OP_TRUE: return false; case OP_EQ: SASSERT(num_args == 2); mk_eq(args[0], args[1], result); return true; case OP_DISTINCT: mk_distinct(num_args, args, result); return true; case OP_ITE: SASSERT(num_args == 3); mk_ite(args[0], args[1], args[2], result); return true; case OP_AND: mk_and(num_args, args, result); return true; case OP_OR: mk_or(num_args, args, result); return true; case OP_IMPLIES: mk_implies(args[0], args[1], result); return true; case OP_IFF: mk_iff(args[0], args[1], result); return true; case OP_XOR: mk_xor(args[0], args[1], result); return true; case OP_NOT: SASSERT(num_args == 1); mk_not(args[0], result); return true; default: UNREACHABLE(); return false; } }
/** \brief Simpler version of mk_ite, that will not invoke mk_or/mk_and. It is used byt local_ctx_simp to prevent a recursive call to local_ctx_simp. See comment at simp_nested_eq_ite. */ void bool_rewriter::mk_nested_ite(expr * c, expr * t, expr * e, expr_ref & result) { if (m().is_true(c)) { result = t; return; } if (m().is_false(c)) { result = e; return; } if (t == e) { result = t; return; } if (m().is_bool(t)) { if (m().is_true(t)) { if (m().is_false(e)) { result = c; return; } result = m().mk_or(c, e); return; } if (m().is_false(t)) { if (m().is_true(e)) { mk_not(c, result); return; } expr_ref tmp(m()); mk_not(e, tmp); result = m().mk_not(m().mk_or(c, tmp)); return; } if (m().is_true(e)) { expr_ref tmp(m()); mk_not(c, tmp); result = m().mk_or(tmp, t); return; } if (m().is_false(e) || c == e) { expr_ref tmp1(m()); expr_ref tmp2(m()); mk_not(c, tmp1); mk_not(t, tmp2); result = m().mk_not(m().mk_or(tmp1, tmp2)); return; } if (c == t) { result = m().mk_or(c, e); return; } if (m().is_complement_core(t, e)) { // t = not(e) mk_eq(c, t, result); return; } if (m().is_complement_core(e, t)) { // e = not(t) mk_eq(c, t, result); return; } } result = m().mk_ite(c, t, e); }
void prop_mbi_plugin::block(expr_ref_vector const& lits) { m_solver->assert_expr(mk_not(mk_and(lits))); }
probe * mk_quasi_pb_probe() { return mk_and(mk_not(mk_is_unbounded_probe()), alloc(quasi_pb_probe)); }
tactic * mk_qfidl_tactic(ast_manager & m, params_ref const & p) { params_ref main_p; main_p.set_bool("elim_and", true); main_p.set_bool("blast_distinct", true); main_p.set_bool("som", true); params_ref lhs_p; lhs_p.set_bool("arith_lhs", true); params_ref lia2pb_p; lia2pb_p.set_uint("lia2pb_max_bits", 4); params_ref pb2bv_p; pb2bv_p.set_uint("pb2bv_all_clauses_limit", 8); params_ref pull_ite_p; pull_ite_p.set_bool("pull_cheap_ite", true); pull_ite_p.set_bool("local_ctx", true); pull_ite_p.set_uint("local_ctx_limit", 10000000); tactic * preamble_st = and_then(and_then(mk_simplify_tactic(m), mk_fix_dl_var_tactic(m), mk_propagate_values_tactic(m), mk_elim_uncnstr_tactic(m) ), and_then(mk_solve_eqs_tactic(m), using_params(mk_simplify_tactic(m), lhs_p), mk_propagate_values_tactic(m), mk_normalize_bounds_tactic(m), mk_solve_eqs_tactic(m))); params_ref bv_solver_p; // The cardinality constraint encoding generates a lot of shared if-then-else's that can be flattened. // Several of them are simplified to and/or. If we flat them, we increase a lot the memory consumption. bv_solver_p.set_bool("flat", false); bv_solver_p.set_bool("som", false); // dynamic psm seems to work well. bv_solver_p.set_sym("gc", symbol("dyn_psm")); tactic * bv_solver = using_params(and_then(mk_simplify_tactic(m), mk_propagate_values_tactic(m), mk_solve_eqs_tactic(m), mk_max_bv_sharing_tactic(m), mk_bit_blaster_tactic(m), mk_aig_tactic(), mk_sat_tactic(m)), bv_solver_p); tactic * try2bv = and_then(using_params(mk_lia2pb_tactic(m), lia2pb_p), mk_propagate_ineqs_tactic(m), using_params(mk_pb2bv_tactic(m), pb2bv_p), fail_if(mk_not(mk_is_qfbv_probe())), bv_solver); params_ref diff_neq_p; diff_neq_p.set_uint("diff_neq_max_k", 25); tactic * st = cond(mk_and(mk_lt(mk_num_consts_probe(), mk_const_probe(static_cast<double>(BIG_PROBLEM))), mk_and(mk_not(mk_produce_proofs_probe()), mk_not(mk_produce_unsat_cores_probe()))), using_params(and_then(preamble_st, or_else(using_params(mk_diff_neq_tactic(m), diff_neq_p), try2bv, mk_smt_tactic())), main_p), mk_smt_tactic()); st->updt_params(p); return st; }
probe * mk_lt(probe * p1, probe * p2) { return mk_not(mk_ge(p1, p2)); }
probe * mk_neq(probe * p1, probe * p2) { return mk_not(mk_eq(p1, p2)); }
probe * mk_implies(probe * p1, probe * p2) { return mk_or(mk_not(p1), p2); }