/*++ Copyright (c) 2012 Microsoft Corporation Module Name: nlsat_tactic.cpp Abstract: Tactic for using nonlinear procedure. Author: Leonardo (leonardo) 2012-01-02 Notes: --*/ #include"tactical.h" #include"goal2nlsat.h" #include"nlsat_solver.h" #include"model.h" #include"expr2var.h" #include"arith_decl_plugin.h" #include"ast_smt2_pp.h" #include"z3_exception.h" #include"algebraic_numbers.h" class nlsat_tactic : public tactic { struct expr_display_var_proc : public nlsat::display_var_proc { ast_manager & m; expr_ref_vector m_var2expr; expr_display_var_proc(ast_manager & _m):m(_m), m_var2expr(_m) {} virtual void operator()(std::ostream & out, nlsat::var x) const { if (x < m_var2expr.size()) out << mk_ismt2_pp(m_var2expr.get(x), m); else out << "x!" << x; } }; struct imp { ast_manager & m; params_ref m_params; expr_display_var_proc m_display_var; nlsat::solver m_solver; goal2nlsat m_g2nl; imp(ast_manager & _m, params_ref const & p): m(_m), m_params(p), m_display_var(_m), m_solver(p) { } void updt_params(params_ref const & p) { m_params = p; m_solver.updt_params(p); } void set_cancel(bool f) { m_solver.set_cancel(f); m_g2nl.set_cancel(f); } bool contains_unsupported(expr_ref_vector & b2a, expr_ref_vector & x2t) { for (unsigned x = 0; x < x2t.size(); x++) { if (!is_uninterp_const(x2t.get(x))) { TRACE("unsupported", tout << "unsupported atom:\n" << mk_ismt2_pp(x2t.get(x), m) << "\n";); return true; } } for (unsigned b = 0; b < b2a.size(); b++) { expr * a = b2a.get(b); if (a == 0) continue; if (is_uninterp_const(a)) continue; if (m_solver.is_interpreted(b)) continue; // arithmetic atom TRACE("unsupported", tout << "unsupported atom:\n" << mk_ismt2_pp(a, m) << "\n";); return true; // unsupported } return false; } // Return false if nlsat assigned noninteger value to an integer variable. bool mk_model(expr_ref_vector & b2a, expr_ref_vector & x2t, model_converter_ref & mc) { bool ok = true; model_ref md = alloc(model, m); arith_util util(m); for (unsigned x = 0; x < x2t.size(); x++) { expr * t = x2t.get(x); if (!is_uninterp_const(t)) continue; expr * v; try { v = util.mk_numeral(m_solver.value(x), util.is_int(t)); } catch (z3_error & ex) { throw ex; } catch (z3_exception &) { v = util.mk_to_int(util.mk_numeral(m_solver.value(x), false)); ok = false; } md->register_decl(to_app(t)->get_decl(), v); } for (unsigned b = 0; b < b2a.size(); b++) { expr * a = b2a.get(b); if (a == 0 || !is_uninterp_const(a)) continue; lbool val = m_solver.bvalue(b); if (val == l_undef) continue; // don't care md->register_decl(to_app(a)->get_decl(), val == l_true ? m.mk_true() : m.mk_false()); } mc = model2model_converter(md.get()); return ok; } 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; tactic_report report("nlsat", *g); if (g->is_decided()) { result.push_back(g.get()); return; } fail_if_proof_generation("nlsat", g); expr2var a2b(m); expr2var t2x(m); m_g2nl(*g, m_params, m_solver, a2b, t2x); m_display_var.m_var2expr.reset(); t2x.mk_inv(m_display_var.m_var2expr); m_solver.set_display_var(m_display_var); lbool st = m_solver.check(); if (st == l_undef) { } else if (st == l_true) { expr_ref_vector x2t(m); expr_ref_vector b2a(m); a2b.mk_inv(b2a); t2x.mk_inv(x2t); if (!contains_unsupported(b2a, x2t)) { // If mk_model is false it means that the model produced by nlsat // assigns noninteger values to integer variables if (mk_model(b2a, x2t, mc)) { // result goal is trivially SAT g->reset(); } } } else { // TODO: extract unsat core g->assert_expr(m.mk_false(), 0, 0); } g->inc_depth(); result.push_back(g.get()); TRACE("nlsat", g->display(tout);); SASSERT(g->is_well_sorted()); } }; imp * m_imp; params_ref m_params; statistics m_stats; struct scoped_set_imp { nlsat_tactic & m_owner; scoped_set_imp(nlsat_tactic & o, imp & i):m_owner(o) { #pragma omp critical (tactic_cancel) { m_owner.m_imp = &i; } } ~scoped_set_imp() { m_owner.m_imp->m_solver.collect_statistics(m_owner.m_stats); #pragma omp critical (tactic_cancel) { m_owner.m_imp = 0; } } }; public: nlsat_tactic(params_ref const & p): m_params(p) { m_imp = 0; } virtual tactic * translate(ast_manager & m) { return alloc(nlsat_tactic, m_params); } virtual ~nlsat_tactic() { SASSERT(m_imp == 0); } virtual void updt_params(params_ref const & p) { m_params = p; } virtual void collect_param_descrs(param_descrs & r) { goal2nlsat::collect_param_descrs(r); nlsat::solver::collect_param_descrs(r); algebraic_numbers::manager::collect_param_descrs(r); } virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { try { imp local_imp(in->m(), m_params); scoped_set_imp setter(*this, local_imp); local_imp(in, result, mc, pc, core); } catch (z3_error & ex) { throw ex; } catch (z3_exception & ex) { throw tactic_exception(ex.msg()); } } virtual void cleanup() {} virtual void set_cancel(bool f) { if (m_imp) m_imp->set_cancel(f); } virtual void collect_statistics(statistics & st) const { st.copy(m_stats); } virtual void reset_statistics() { m_stats.reset(); } }; tactic * mk_nlsat_tactic(ast_manager & m, params_ref const & p) { return clean(alloc(nlsat_tactic, p)); }