diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 330d0f2bc..8be818e5e 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -386,7 +386,7 @@ extern "C" { init_solver(c, s); Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); - expr_ref_vector fmls = to_solver_ref(s)->get_units(mk_c(c)->m()); + expr_ref_vector fmls = to_solver_ref(s)->get_units(); for (expr* f : fmls) { v->m_ast_vector.push_back(f); } @@ -401,7 +401,7 @@ extern "C" { init_solver(c, s); Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); - expr_ref_vector fmls = to_solver_ref(s)->get_non_units(mk_c(c)->m()); + expr_ref_vector fmls = to_solver_ref(s)->get_non_units(); for (expr* f : fmls) { v->m_ast_vector.push_back(f); } @@ -409,6 +409,40 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } + void Z3_API Z3_solver_get_levels(Z3_context c, Z3_solver s, unsigned sz, Z3_ast literals[], unsigned levels[]) { + Z3_TRY; + LOG_Z3_solver_get_levels(c, s, sz, literals, levels); + RESET_ERROR_CODE(); + init_solver(c, s); + ptr_vector _vars; + for (unsigned i = 0; i < sz; ++i) { + expr* e = to_expr(literals[i]); + mk_c(c)->m().is_not(e, e); + _vars.push_back(e); + } + unsigned_vector _levels(sz); + to_solver_ref(s)->get_levels(_vars, _levels); + for (unsigned i = 0; i < sz; ++i) { + levels[i] = _levels[i]; + } + Z3_CATCH; + } + + Z3_ast_vector Z3_API Z3_solver_get_trail(Z3_context c, Z3_solver s) { + Z3_TRY; + LOG_Z3_solver_get_trail(c, s); + RESET_ERROR_CODE(); + init_solver(c, s); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); + mk_c(c)->save_object(v); + expr_ref_vector trail = to_solver_ref(s)->get_trail(); + for (expr* f : trail) { + v->m_ast_vector.push_back(f); + } + RETURN_Z3(of_ast_vector(v)); + Z3_CATCH_RETURN(nullptr); + } + static Z3_lbool _solver_check(Z3_context c, Z3_solver s, unsigned num_assumptions, Z3_ast const assumptions[]) { for (unsigned i = 0; i < num_assumptions; i++) { if (!is_expr(to_ast(assumptions[i]))) { diff --git a/src/api/z3_api.h b/src/api/z3_api.h index cd52d2d86..b7e043f00 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6213,6 +6213,13 @@ extern "C" { */ Z3_ast_vector Z3_API Z3_solver_get_units(Z3_context c, Z3_solver s); + /** + \brief Return the trail modulo model conversion, in order of decision level + The decision level can be retrieved using \c Z3_solver_get_level based on the trail. + + def_API('Z3_solver_get_trail', AST_VECTOR, (_in(CONTEXT), _in(SOLVER))) + */ + Z3_ast_vector Z3_API Z3_solver_get_trail(Z3_context c, Z3_solver s); /** \brief Return the set of non units in the solver state. @@ -6221,6 +6228,15 @@ extern "C" { */ Z3_ast_vector Z3_API Z3_solver_get_non_units(Z3_context c, Z3_solver s); + /** + \brief retrieve the decision depth of Boolean literals (variables or their negations). + Assumes a check-sat call and no other calls (to extract models) have been invoked. + + def_API('Z3_solver_get_levels', VOID, (_in(CONTEXT), _in(SOLVER), _in(UINT), _in_array(2, AST), _in_array(2, UINT))) + */ + void Z3_API Z3_solver_get_levels(Z3_context c, Z3_solver s, unsigned sz, Z3_ast literals[], unsigned levels[]); + + /** \brief Check whether the assertions in a given solver are consistent or not. diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index a51bfbef9..67fdc0fc3 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -122,6 +122,8 @@ public: void assert_expr_core(expr *t) override { m_solver.assert_expr(t); } void assert_expr_core2(expr *t, expr *a) override { NOT_IMPLEMENTED_YET(); } expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); } + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { m_solver.get_levels(vars, depth); } + expr_ref_vector get_trail() { return m_solver.get_trail(); } void push() override; void pop(unsigned n) override; diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 78851f5cb..80a81ba3a 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -208,6 +208,9 @@ namespace opt { return m_context.preferred_sat(asms, cores); } + void opt_solver::get_levels(ptr_vector const& vars, unsigned_vector& depth) { + return m_context.get_levels(vars, depth); + } /** diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 8d2abdb93..9eda063e9 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -108,6 +108,8 @@ namespace opt { ast_manager& get_manager() const override { return m; } lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override; lbool preferred_sat(expr_ref_vector const& asms, vector& cores) override; + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override; + expr_ref_vector get_trail() override { return m_context.get_trail(); } expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); } void set_logic(symbol const& logic); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 96cc53b4a..dd81bac2e 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -300,6 +300,7 @@ namespace sat { unsigned lvl(bool_var v) const { return m_level[v]; } unsigned lvl(literal l) const { return m_level[l.var()]; } unsigned init_trail_size() const { return at_base_lvl() ? m_trail.size() : m_scopes[0].m_trail_lim; } + unsigned trail_size() const { return m_trail.size(); } literal trail_literal(unsigned i) const { return m_trail[i]; } literal scope_literal(unsigned n) const { return m_trail[m_scopes[n].m_trail_lim]; } void assign(literal l, justification j) { diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 34348f0fc..fd795dbc7 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -318,6 +318,29 @@ public: r.reset(); r.append(m_core.size(), m_core.c_ptr()); } + + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { + unsigned sz = vars.size(); + depth.resize(sz); + for (unsigned i = 0; i < sz; ++i) { + auto bv = m_map.to_bool_var(vars[i]); + depth = bv == sat::null_bool_var ? UINT_MAX : m_solver.lvl(bv); + } + } + + expr_ref_vector get_trail() override { + expr_ref_vector result(m); + unsigned sz = m_solver.trail_size(); + expr_ref_vector lit2expr(m); + lit2expr.resize(m_solver.num_vars() * 2); + m_map.mk_inv(lit2expr); + for (unsigned i = 0; i < sz; ++i) { + sat::literal lit = m_solver.trail_literal(i); + result.push_back(lit2expr[lit.index()].get()); + } + return result; + } + proof * get_proof() override { UNREACHABLE(); return nullptr; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 9d4c9f852..86b3374fc 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4423,6 +4423,22 @@ namespace smt { m = const_cast(m_model.get()); } + void context::get_levels(ptr_vector const& vars, unsigned_vector& depth) { + unsigned sz = vars.size(); + depth.resize(sz); + for (unsigned i = 0; i < sz; ++i) { + expr* v = vars[i]; + bool_var bv = m_expr2bool_var.get(v->get_id(), null_bool_var); + depth[i] = bv == null_bool_var ? UINT_MAX : get_assign_level(bv); + } + } + + expr_ref_vector context::get_trail() { + expr_ref_vector result(get_manager()); + get_assignments(result); + return result; + } + void context::get_proto_model(proto_model_ref & m) const { m = const_cast(m_proto_model.get()); } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index ef018b895..d935bf53e 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1575,6 +1575,10 @@ namespace smt { return m_unsat_core.get(idx); } + void get_levels(ptr_vector const& vars, unsigned_vector& depth); + + expr_ref_vector get_trail(); + void get_model(model_ref & m) const; bool update_model(bool refinalize); diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 4a6cd086c..1cf816d55 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -196,7 +196,7 @@ namespace smt { TRACE("incompleteness_bug", tout << "[internalize-assertion]: #" << n->get_id() << "\n";); flet l(m_generation, generation); m_stats.m_max_generation = std::max(m_generation, m_stats.m_max_generation); - if (get_depth(n) > DEEP_EXPR_THRESHOLD) { + if (::get_depth(n) > DEEP_EXPR_THRESHOLD) { // if the expression is deep, then execute topological sort to avoid // stack overflow. // a caveat is that theory internalizers do rely on recursive descent so diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index b03604b5b..f2f17321c 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -146,6 +146,14 @@ namespace smt { expr * get_unsat_core_expr(unsigned idx) const { return m_kernel.get_unsat_core_expr(idx); } + + void get_levels(ptr_vector const& vars, unsigned_vector& depth) { + m_kernel.get_levels(vars, depth); + } + + expr_ref_vector get_trail() { + return m_kernel.get_trail(); + } failure last_failure() const { return m_kernel.get_last_search_failure(); @@ -396,4 +404,13 @@ namespace smt { return m_imp->m_kernel; } + void kernel::get_levels(ptr_vector const& vars, unsigned_vector& depth) { + m_imp->get_levels(vars, depth); + } + + expr_ref_vector kernel::get_trail() { + return m_imp->get_trail(); + } + + }; diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index d78f71e20..6eeb8d728 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -219,6 +219,16 @@ namespace smt { */ expr* next_decision(); + /** + \brief retrieve depth of variables from decision stack. + */ + void get_levels(ptr_vector const& vars, unsigned_vector& depth); + + /** + \brief retrieve trail of assignment stack. + */ + expr_ref_vector get_trail(); + /** \brief (For debubbing purposes) Prints the state of the kernel */ diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 5d32d1bed..e36858b06 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -195,6 +195,14 @@ namespace smt { return m_context.check(cube, clauses); } + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { + m_context.get_levels(vars, depth); + } + + expr_ref_vector get_trail() override { + return m_context.get_trail(); + } + struct scoped_minimize_core { smt_solver& s; expr_ref_vector m_assumptions; diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 813b2be18..b602fe6e1 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -314,6 +314,20 @@ public: m_solver2->get_model(m); } + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { + if (m_use_solver1_results) + m_solver1->get_levels(vars, depth); + else + m_solver2->get_levels(vars, depth); + } + + expr_ref_vector get_trail() override { + if (m_use_solver1_results) + return m_solver1->get_trail(); + else + return m_solver2->get_trail(); + } + proof * get_proof() override { if (m_use_solver1_results) return m_solver1->get_proof(); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 9126ab1a2..89421f079 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -251,7 +251,8 @@ void solver::updt_params(params_ref const & p) { } -expr_ref_vector solver::get_units(ast_manager& m) { +expr_ref_vector solver::get_units() { + ast_manager& m = get_manager(); expr_ref_vector fmls(m), result(m), tmp(m); get_assertions(fmls); obj_map units; @@ -284,7 +285,8 @@ expr_ref_vector solver::get_units(ast_manager& m) { } -expr_ref_vector solver::get_non_units(ast_manager& m) { +expr_ref_vector solver::get_non_units() { + ast_manager& m = get_manager(); expr_ref_vector result(m), fmls(m); get_assertions(fmls); family_id bfid = m.get_basic_family_id(); @@ -320,6 +322,7 @@ expr_ref_vector solver::get_non_units(ast_manager& m) { return result; } + lbool solver::check_sat(unsigned num_assumptions, expr * const * assumptions) { lbool r = l_undef; try { diff --git a/src/solver/solver.h b/src/solver/solver.h index 161677cb5..0c509b8c7 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -243,9 +243,13 @@ public: /** \brief extract units from solver. */ - expr_ref_vector get_units(ast_manager& m); + expr_ref_vector get_units(); - expr_ref_vector get_non_units(ast_manager& m); + expr_ref_vector get_non_units(); + + virtual expr_ref_vector get_trail() = 0; // { return expr_ref_vector(get_manager()); } + + virtual void get_levels(ptr_vector const& vars, unsigned_vector& depth) = 0; class scoped_push { solver& s; diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 0495e8a3d..7f3882447 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -119,6 +119,14 @@ public: } } + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { + m_base->get_levels(vars, depth); + } + + expr_ref_vector get_trail() override { + return m_base->get_trail(); + } + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { SASSERT(!m_pushed || get_scope_level() > 0); m_proof.reset(); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 298ed9bc5..8721e106b 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -85,6 +85,14 @@ public: model_converter_ref get_model_converter() const override { return m_mc; } + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { + throw default_exception("cannot retrieve depth from solvers created using tactics"); + } + + expr_ref_vector get_trail() override { + throw default_exception("cannot retrieve trail from solvers created using tactcis"); + } + }; ast_manager& tactic2solver::get_manager() const { return m_assertions.get_manager(); } diff --git a/src/tactic/fd_solver/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp index 45d1344ba..b19875737 100644 --- a/src/tactic/fd_solver/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -155,6 +155,12 @@ public: if (mc) (*mc)(mdl); } } + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { + m_solver->get_levels(vars, depth); + } + expr_ref_vector get_trail() override { + return m_solver->get_trail(); + } model_converter* external_model_converter() const { return concat(mc0(), local_model_converter()); } diff --git a/src/tactic/fd_solver/enum2bv_solver.cpp b/src/tactic/fd_solver/enum2bv_solver.cpp index b9a564542..d8119ddfd 100644 --- a/src/tactic/fd_solver/enum2bv_solver.cpp +++ b/src/tactic/fd_solver/enum2bv_solver.cpp @@ -178,7 +178,13 @@ public: return r; } + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { + m_solver->get_levels(vars, depth); + } + expr_ref_vector get_trail() override { + return m_solver->get_trail(); + } unsigned get_num_assertions() const override { return m_solver->get_num_assertions(); diff --git a/src/tactic/fd_solver/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp index b3620c8ec..29aa573e3 100644 --- a/src/tactic/fd_solver/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -96,6 +96,13 @@ public: if (mc) (*mc)(mdl); } } + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { + m_solver->get_levels(vars, depth); + } + + expr_ref_vector get_trail() override { + return m_solver->get_trail(); + } model_converter* external_model_converter() const{ return concat(mc0(), local_model_converter());