Skip to content

Commit f6f3ca1

Browse files
adding SMT2 log file for solver interaction #867
Signed-off-by: Nikolaj Bjorner <[email protected]>
1 parent b6c1334 commit f6f3ca1

9 files changed

+159
-28
lines changed

src/api/api_solver.cpp

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,52 @@ Revision History:
4444

4545
extern "C" {
4646

47+
void solver2smt2_pp::assert_expr(expr* e) {
48+
m_pp_util.collect(e);
49+
m_pp_util.display_decls(m_out);
50+
m_pp_util.display_assert(m_out, e, true);
51+
}
52+
53+
void solver2smt2_pp::assert_expr(expr* e, expr* t) {
54+
m_pp_util.collect(e);
55+
m_pp_util.collect(t);
56+
m_pp_util.display_decls(m_out);
57+
m_pp_util.display_assert_and_track(m_out, e, t, true);
58+
}
59+
60+
void solver2smt2_pp::push() {
61+
m_out << "(push)\n";
62+
}
63+
64+
void solver2smt2_pp::pop(unsigned n) {
65+
m_out << "(pop " << n << ")\n";
66+
}
67+
68+
void solver2smt2_pp::check(unsigned n, expr* const* asms) {
69+
m_out << "(check-sat";
70+
for (unsigned i = 0; i < n; ++i) {
71+
m_out << "\n";
72+
m_pp_util.display_expr(m_out, asms[i]);
73+
}
74+
m_out << ")\n";
75+
}
76+
77+
solver2smt2_pp::solver2smt2_pp(ast_manager& m, char const* file): m_pp_util(m), m_out(file) {
78+
if (!m_out) {
79+
throw default_exception("could not open file for output");
80+
}
81+
}
82+
83+
void Z3_solver_ref::assert_expr(expr * e) {
84+
if (m_pp) m_pp->assert_expr(e);
85+
m_solver->assert_expr(e);
86+
}
87+
88+
void Z3_solver_ref::assert_expr(expr * e, expr* t) {
89+
if (m_pp) m_pp->assert_expr(e, t);
90+
m_solver->assert_expr(e, t);
91+
}
92+
4793
static void init_solver_core(Z3_context c, Z3_solver _s) {
4894
Z3_solver_ref * s = to_solver(_s);
4995
bool proofs_enabled, models_enabled, unsat_core_enabled;
@@ -85,6 +131,13 @@ extern "C" {
85131
Z3_CATCH_RETURN(nullptr);
86132
}
87133

134+
void Z3_API Z3_solver_open_smt2log(Z3_context c, Z3_solver s, Z3_string file) {
135+
Z3_TRY;
136+
LOG_Z3_solver_open_smt2log(c, s, file);
137+
to_solver(s)->m_pp = alloc(solver2smt2_pp, mk_c(c)->m(), file);
138+
Z3_CATCH;
139+
}
140+
88141
Z3_solver Z3_API Z3_mk_solver_for_logic(Z3_context c, Z3_symbol logic) {
89142
Z3_TRY;
90143
LOG_Z3_mk_solver_for_logic(c, logic);
@@ -154,7 +207,7 @@ extern "C" {
154207
if (!initialized)
155208
init_solver(c, s);
156209
for (expr * e : ctx->assertions()) {
157-
to_solver_ref(s)->assert_expr(e);
210+
to_solver(s)->assert_expr(e);
158211
}
159212
to_solver_ref(s)->set_model_converter(ctx->get_model_converter());
160213
}
@@ -177,7 +230,7 @@ extern "C" {
177230
goal g(m);
178231
s2g(solver, a2b, to_solver_ref(s)->get_params(), g, mc);
179232
for (unsigned i = 0; i < g.size(); ++i) {
180-
to_solver_ref(s)->assert_expr(g.form(i));
233+
to_solver(s)->assert_expr(g.form(i));
181234
}
182235
}
183236

@@ -302,6 +355,7 @@ extern "C" {
302355
RESET_ERROR_CODE();
303356
init_solver(c, s);
304357
to_solver_ref(s)->push();
358+
if (to_solver(s)->m_pp) to_solver(s)->m_pp->push();
305359
Z3_CATCH;
306360
}
307361

@@ -314,8 +368,10 @@ extern "C" {
314368
SET_ERROR_CODE(Z3_IOB, nullptr);
315369
return;
316370
}
317-
if (n > 0)
371+
if (n > 0) {
318372
to_solver_ref(s)->pop(n);
373+
if (to_solver(s)->m_pp) to_solver(s)->m_pp->pop(n);
374+
}
319375
Z3_CATCH;
320376
}
321377

@@ -342,7 +398,7 @@ extern "C" {
342398
RESET_ERROR_CODE();
343399
init_solver(c, s);
344400
CHECK_FORMULA(a,);
345-
to_solver_ref(s)->assert_expr(to_expr(a));
401+
to_solver(s)->assert_expr(to_expr(a));
346402
Z3_CATCH;
347403
}
348404

@@ -353,7 +409,7 @@ extern "C" {
353409
init_solver(c, s);
354410
CHECK_FORMULA(a,);
355411
CHECK_FORMULA(p,);
356-
to_solver_ref(s)->assert_expr(to_expr(a), to_expr(p));
412+
to_solver(s)->assert_expr(to_expr(a), to_expr(p));
357413
Z3_CATCH;
358414
}
359415

@@ -461,6 +517,7 @@ extern "C" {
461517
scoped_timer timer(timeout, &eh);
462518
scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit);
463519
try {
520+
if (to_solver(s)->m_pp) to_solver(s)->m_pp->check(num_assumptions, _assumptions);
464521
result = to_solver_ref(s)->check_sat(num_assumptions, _assumptions);
465522
}
466523
catch (z3_exception & ex) {

src/api/api_solver.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,28 @@ Revision History:
2121
#include "api/api_util.h"
2222
#include "solver/solver.h"
2323

24+
struct solver2smt2_pp {
25+
ast_pp_util m_pp_util;
26+
std::ofstream m_out;
27+
solver2smt2_pp(ast_manager& m, char const* file);
28+
void assert_expr(expr* e);
29+
void assert_expr(expr* e, expr* t);
30+
void push();
31+
void pop(unsigned n);
32+
void check(unsigned n, expr* const* asms);
33+
};
34+
2435
struct Z3_solver_ref : public api::object {
2536
scoped_ptr<solver_factory> m_solver_factory;
2637
ref<solver> m_solver;
2738
params_ref m_params;
2839
symbol m_logic;
40+
scoped_ptr<solver2smt2_pp> m_pp;
2941
Z3_solver_ref(api::context& c, solver_factory * f): api::object(c), m_solver_factory(f), m_solver(nullptr), m_logic(symbol::null) {}
3042
~Z3_solver_ref() override {}
43+
44+
void assert_expr(expr* e);
45+
void assert_expr(expr* e, expr* t);
3146
};
3247

3348
inline Z3_solver_ref * to_solver(Z3_solver s) { return reinterpret_cast<Z3_solver_ref *>(s); }

src/api/python/z3/z3.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6436,7 +6436,7 @@ def _repr_html_(self):
64366436
class Solver(Z3PPObject):
64376437
"""Solver API provides methods for implementing the main SMT 2.0 commands: push, pop, check, get-model, etc."""
64386438

6439-
def __init__(self, solver=None, ctx=None):
6439+
def __init__(self, solver=None, ctx=None, logFile=None):
64406440
assert solver is None or ctx is not None
64416441
self.ctx = _get_ctx(ctx)
64426442
self.backtrack_level = 4000000000
@@ -6446,6 +6446,8 @@ def __init__(self, solver=None, ctx=None):
64466446
else:
64476447
self.solver = solver
64486448
Z3_solver_inc_ref(self.ctx.ref(), self.solver)
6449+
if logFile is not None:
6450+
Z3_solver_open_smt2log(self.ctx.ref(), self.solver, logFile)
64496451

64506452
def __del__(self):
64516453
if self.solver is not None and self.ctx.ref() is not None:
@@ -6906,7 +6908,7 @@ def to_smt2(self):
69066908
e = BoolVal(True, self.ctx).as_ast()
69076909
return Z3_benchmark_to_smtlib_string(self.ctx.ref(), "benchmark generated from python API", "", "unknown", "", sz1, v, e)
69086910

6909-
def SolverFor(logic, ctx=None):
6911+
def SolverFor(logic, ctx=None, logFile=None):
69106912
"""Create a solver customized for the given logic.
69116913
69126914
The parameter `logic` is a string. It should be contains
@@ -6924,9 +6926,9 @@ def SolverFor(logic, ctx=None):
69246926
"""
69256927
ctx = _get_ctx(ctx)
69266928
logic = to_symbol(logic)
6927-
return Solver(Z3_mk_solver_for_logic(ctx.ref(), logic), ctx)
6929+
return Solver(Z3_mk_solver_for_logic(ctx.ref(), logic), ctx, logFile)
69286930

6929-
def SimpleSolver(ctx=None):
6931+
def SimpleSolver(ctx=None, logFile=None):
69306932
"""Return a simple general purpose solver with limited amount of preprocessing.
69316933
69326934
>>> s = SimpleSolver()
@@ -6936,7 +6938,7 @@ def SimpleSolver(ctx=None):
69366938
sat
69376939
"""
69386940
ctx = _get_ctx(ctx)
6939-
return Solver(Z3_mk_simple_solver(ctx.ref()), ctx)
6941+
return Solver(Z3_mk_simple_solver(ctx.ref()), ctx, logFile)
69406942

69416943
#########################################
69426944
#
@@ -7662,7 +7664,7 @@ def __del__(self):
76627664
if self.tactic is not None and self.ctx.ref() is not None:
76637665
Z3_tactic_dec_ref(self.ctx.ref(), self.tactic)
76647666

7665-
def solver(self):
7667+
def solver(self, logFile=None):
76667668
"""Create a solver using the tactic `self`.
76677669
76687670
The solver supports the methods `push()` and `pop()`, but it
@@ -7677,7 +7679,7 @@ def solver(self):
76777679
>>> s.model()
76787680
[x = 1.4142135623?]
76797681
"""
7680-
return Solver(Z3_mk_solver_from_tactic(self.ctx.ref(), self.tactic), self.ctx)
7682+
return Solver(Z3_mk_solver_from_tactic(self.ctx.ref(), self.tactic), self.ctx, logFile)
76817683

76827684
def apply(self, goal, *arguments, **keywords):
76837685
"""Apply tactic `self` to the given goal or Z3 Boolean expression using the given options.

src/api/z3_api.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6332,6 +6332,21 @@ extern "C" {
63326332
*/
63336333
void Z3_API Z3_solver_dec_ref(Z3_context c, Z3_solver s);
63346334

6335+
/**
6336+
\brief Log solver interactions into an SMT2 file.
6337+
The tracked interactions are:
6338+
- Z3_solver_assert
6339+
- Z3_solver_assert_and_track
6340+
- Z3_solver_push
6341+
- Z3_solver_pop
6342+
- Z3_solver_check
6343+
- Z3_solver_check_assumptions
6344+
Assertions that are loaded from a file are also going to be tracked.
6345+
6346+
def_API('Z3_solver_open_smt2log', VOID, (_in(CONTEXT), _in(SOLVER), _in(STRING)))
6347+
*/
6348+
void Z3_API Z3_solver_open_smt2log(Z3_context c, Z3_solver s, Z3_string file);
6349+
63356350
/**
63366351
\brief Create a backtracking point.
63376352

src/ast/ast_pp_util.cpp

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,32 +38,63 @@ void ast_pp_util::collect(expr_ref_vector const& es) {
3838

3939
void ast_pp_util::display_decls(std::ostream& out) {
4040
ast_smt_pp pp(m);
41-
coll.order_deps();
41+
bool first = m_num_decls == 0;
42+
coll.order_deps(m_num_sorts);
4243
unsigned n = coll.get_num_sorts();
43-
for (unsigned i = 0; i < n; ++i) {
44+
for (unsigned i = m_num_sorts; i < n; ++i) {
4445
pp.display_ast_smt2(out, coll.get_sorts()[i], 0, 0, nullptr);
4546
}
47+
m_num_sorts = n;
4648
n = coll.get_num_decls();
47-
for (unsigned i = 0; i < n; ++i) {
49+
for (unsigned i = m_num_decls; i < n; ++i) {
4850
func_decl* f = coll.get_func_decls()[i];
4951
if (f->get_family_id() == null_family_id && !m_removed.contains(f)) {
5052
ast_smt2_pp(out, f, m_env) << "\n";
5153
}
5254
}
53-
vector<std::pair<func_decl*, expr*>> recfuns;
54-
recfun::util u(m);
55-
func_decl_ref_vector funs = u.get_rec_funs();
56-
if (funs.empty()) return;
57-
for (func_decl * f : funs) {
58-
recfuns.push_back(std::make_pair(f, u.get_def(f).get_rhs()));
55+
m_num_decls = n;
56+
if (first) {
57+
vector<std::pair<func_decl*, expr*>> recfuns;
58+
recfun::util u(m);
59+
func_decl_ref_vector funs = u.get_rec_funs();
60+
if (funs.empty()) return;
61+
for (func_decl * f : funs) {
62+
recfuns.push_back(std::make_pair(f, u.get_def(f).get_rhs()));
63+
}
64+
ast_smt2_pp_recdefs(out, recfuns, m_env);
5965
}
60-
ast_smt2_pp_recdefs(out, recfuns, m_env);
6166
}
6267

6368
void ast_pp_util::remove_decl(func_decl* f) {
6469
m_removed.insert(f);
6570
}
6671

72+
std::ostream& ast_pp_util::display_expr(std::ostream& out, expr* f, bool neat) {
73+
if (neat) {
74+
ast_smt2_pp(out, f, m_env);
75+
}
76+
else {
77+
ast_smt_pp ll_smt2_pp(m);
78+
ll_smt2_pp.display_expr_smt2(out, f);
79+
}
80+
return out;
81+
}
82+
83+
void ast_pp_util::display_assert(std::ostream& out, expr* f, bool neat) {
84+
display_expr(out << "(assert ", f, neat) << ")\n";
85+
}
86+
87+
void ast_pp_util::display_assert_and_track(std::ostream& out, expr* f, expr* t, bool neat) {
88+
if (neat) {
89+
ast_smt2_pp(out << "(assert (=> ", t, m_env) << " ";
90+
ast_smt2_pp(out, f, m_env) << "))\n";
91+
}
92+
else {
93+
ast_smt_pp ll_smt2_pp(m);
94+
ll_smt2_pp.display_expr_smt2(out << "(assert (=> ", t); out << " ";
95+
ll_smt2_pp.display_expr_smt2(out, f); out << "))\n";
96+
}
97+
}
6798

6899
void ast_pp_util::display_asserts(std::ostream& out, expr_ref_vector const& fmls, bool neat) {
69100
if (neat) {

src/ast/ast_pp_util.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ class ast_pp_util {
2727
ast_manager& m;
2828
obj_hashtable<func_decl> m_removed;
2929
smt2_pp_environment_dbg m_env;
30+
unsigned m_num_sorts, m_num_decls;
31+
3032
public:
3133

3234
decl_collector coll;
3335

34-
ast_pp_util(ast_manager& m): m(m), m_env(m), coll(m) {}
36+
ast_pp_util(ast_manager& m): m(m), m_env(m), coll(m), m_num_sorts(0), m_num_decls(0) {}
3537

3638
void collect(expr* e);
3739

@@ -45,6 +47,12 @@ class ast_pp_util {
4547

4648
void display_asserts(std::ostream& out, expr_ref_vector const& fmls, bool neat = true);
4749

50+
void display_assert(std::ostream& out, expr* f, bool neat = true);
51+
52+
void display_assert_and_track(std::ostream& out, expr* f, expr* t, bool neat = true);
53+
54+
std::ostream& display_expr(std::ostream& out, expr* f, bool neat = true);
55+
4856
smt2_pp_environment& env() { return m_env; }
4957
};
5058

src/ast/ast_smt_pp.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
957957
#if 0
958958
decls.display_decls(strm);
959959
#else
960-
decls.order_deps();
960+
decls.order_deps(0);
961961
ast_mark sort_mark;
962962
for (sort* s : decls.get_sorts()) {
963963
if (!(*m_is_declared)(s)) {

src/ast/decl_collector.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,14 @@ void decl_collector::visit(ast* n) {
113113
}
114114
}
115115

116-
void decl_collector::order_deps() {
116+
void decl_collector::order_deps(unsigned n) {
117117
top_sort<sort> st;
118-
for (sort * s : m_sorts) st.insert(s, collect_deps(s));
118+
for (unsigned i = n; i < m_sorts.size(); ++i) {
119+
sort* s = m_sorts.get(i);
120+
st.insert(s, collect_deps(s));
121+
}
119122
st.topological_sort();
120-
m_sorts.reset();
123+
m_sorts.shrink(n);
121124
for (sort* s : st.top_sorted()) m_sorts.push_back(s);
122125
}
123126

src/ast/decl_collector.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class decl_collector {
5252
void visit(unsigned n, expr* const* es);
5353
void visit(expr_ref_vector const& es);
5454

55-
void order_deps();
55+
void order_deps(unsigned n);
5656

5757
unsigned get_num_sorts() const { return m_sorts.size(); }
5858
unsigned get_num_decls() const { return m_decls.size(); }

0 commit comments

Comments
 (0)