bool reduce_eq(expr_mark& is_var, expr* l, expr* r, expr_ref& v, expr_ref& t) { if (is_var.is_marked(r)) { std::swap(l, r); } if (is_var.is_marked(l)) { contains_app cont(m, to_app(l)); if (!cont(r)) { v = to_app(l); t = r; return true; } } return false; }
bool arith_solver_plugin::solve(expr * lhs, expr * rhs, expr_mark const & forbidden, app_ref & var, expr_ref & subst) { rational k; if (!m_simplifier.is_numeral(rhs, k)) return false; bool _is_int = m_simplifier.is_int(lhs); ptr_buffer<expr> monomials; ptr_buffer<expr> todo; bool already_found = false; rational c; todo.push_back(lhs); while (!todo.empty()) { expr * curr = todo.back(); todo.pop_back(); rational coeff; if (m_simplifier.is_add(curr)) { SASSERT(to_app(curr)->get_num_args() == 2); todo.push_back(to_app(curr)->get_arg(1)); todo.push_back(to_app(curr)->get_arg(0)); } else { if (!already_found) { if (m_simplifier.is_mul(curr) && m_simplifier.is_numeral(to_app(curr)->get_arg(0), coeff) && !coeff.is_zero() && (!_is_int || coeff.is_minus_one()) && is_uninterp_const(to_app(curr)->get_arg(1)) && !forbidden.is_marked(to_app(curr)->get_arg(1))) { c = coeff; var = to_app(to_app(curr)->get_arg(1)); already_found = true; } else if (is_uninterp_const(curr) && !forbidden.is_marked(curr)) { c = rational::one(); var = to_app(curr); already_found = true; } else { monomials.push_back(curr); } } else { monomials.push_back(curr); } } } if (!already_found) return false; SASSERT(!c.is_zero()); k /= c; expr_ref_vector new_monomials(m_manager); if (!k.is_zero()) new_monomials.push_back(m_simplifier.mk_numeral(k, _is_int)); c.neg(); expr_ref inv_c(m_manager); if (!c.is_one()) { rational inv(1); inv /= c; inv_c = m_simplifier.mk_numeral(inv, _is_int); } // divide monomials by c unsigned sz = monomials.size(); for (unsigned i = 0; i < sz; i++) { expr * m = monomials[i]; expr_ref new_m(m_manager); if (!c.is_one()) m_simplifier.mk_mul(inv_c, m, new_m); else new_m = m; new_monomials.push_back(new_m); } if (new_monomials.empty()) subst = m_simplifier.mk_numeral(rational(0), _is_int); else m_simplifier.mk_add(new_monomials.size(), new_monomials.c_ptr(), subst); TRACE("arith_solver", tout << "solving:\n" << mk_pp(lhs, m_manager) << "\n" << mk_pp(rhs, m_manager) << "\nresult:\n" << mk_pp(var, m_manager) << "\n" << mk_pp(subst, m_manager) << "\n";);
virtual void operator()( goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; m_trail.reset(); m_fd.reset(); m_max.reset(); m_nonfd.reset(); m_bounds.reset(); ref<bvmc> mc1 = alloc(bvmc); tactic_report report("eq2bv", *g); m_bounds(*g); for (unsigned i = 0; i < g->size(); i++) { collect_fd(g->form(i)); } cleanup_fd(mc1); if (m_max.empty()) { result.push_back(g.get()); return; } for (unsigned i = 0; i < g->size(); i++) { expr_ref new_curr(m); proof_ref new_pr(m); if (is_bound(g->form(i))) { g->update(i, m.mk_true(), 0, 0); continue; } m_rw(g->form(i), new_curr, new_pr); if (m.proofs_enabled() && !new_pr) { new_pr = m.mk_rewrite(g->form(i), new_curr); new_pr = m.mk_modus_ponens(g->pr(i), new_pr); } g->update(i, new_curr, new_pr, g->dep(i)); } obj_map<expr, unsigned>::iterator it = m_max.begin(), end = m_max.end(); for (; it != end; ++it) { expr* c = it->m_key; bool strict; rational r; if (m_bounds.has_lower(c, r, strict)) { SASSERT(!strict); expr* d = m_fd.find(c); g->assert_expr(bv.mk_ule(bv.mk_numeral(r, m.get_sort(d)), d), m_bounds.lower_dep(c)); } if (m_bounds.has_upper(c, r, strict)) { SASSERT(!strict); expr* d = m_fd.find(c); g->assert_expr(bv.mk_ule(d, bv.mk_numeral(r, m.get_sort(d))), m_bounds.upper_dep(c)); } } g->inc_depth(); mc = mc1.get(); result.push_back(g.get()); TRACE("pb", g->display(tout););