Skip to content

Commit f6595c1

Browse files
add examples with proof replay
Signed-off-by: Nikolaj Bjorner <[email protected]>
1 parent 88d10f7 commit f6595c1

File tree

9 files changed

+166
-5
lines changed

9 files changed

+166
-5
lines changed

examples/python/proofreplay.py

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# This script illustrates uses of proof replay and proof logs over the Python interface.
2+
3+
from z3 import *
4+
5+
example1 = """
6+
(declare-sort T)
7+
8+
(declare-fun subtype (T T) Bool)
9+
10+
;; subtype is reflexive
11+
(assert (forall ((x T)) (subtype x x)))
12+
13+
;; subtype is antisymmetric
14+
(assert (forall ((x T) (y T)) (=> (and (subtype x y)
15+
(subtype y x))
16+
(= x y))))
17+
;; subtype is transitive
18+
(assert (forall ((x T) (y T) (z T)) (=> (and (subtype x y)
19+
(subtype y z))
20+
(subtype x z))))
21+
;; subtype has the tree-property
22+
(assert (forall ((x T) (y T) (z T)) (=> (and (subtype x z)
23+
(subtype y z))
24+
(or (subtype x y)
25+
(subtype y x)))))
26+
27+
;; now we define a simple example using the axiomatization above.
28+
(declare-const obj-type T)
29+
(declare-const int-type T)
30+
(declare-const real-type T)
31+
(declare-const complex-type T)
32+
(declare-const string-type T)
33+
34+
;; we have an additional axiom: every type is a subtype of obj-type
35+
(assert (forall ((x T)) (subtype x obj-type)))
36+
37+
(assert (subtype int-type real-type))
38+
(assert (subtype real-type complex-type))
39+
(assert (not (subtype string-type real-type)))
40+
(declare-const root-type T)
41+
(assert (subtype obj-type root-type))
42+
"""
43+
44+
if __name__ == "__main__":
45+
print("Solve and log inferences")
46+
print("--------------------------------------------------------")
47+
48+
# inference logging, replay, and checking is supported for
49+
# the core enabled by setting sat.euf = true.
50+
# setting the default tactic to 'sat' bypasses other tactics that could
51+
# end up using different solvers.
52+
set_param("sat.euf", True)
53+
set_param("tactic.default_tactic", "sat")
54+
55+
# Set a log file to trace inferences
56+
set_param("sat.smt.proof", "proof_log.smt2")
57+
s = Solver()
58+
s.from_string(example1)
59+
print(s.check())
60+
print(s.statistics())
61+
print("Parse the logged inferences and replay them")
62+
print("--------------------------------------------------------")
63+
64+
# Reset the log file to an invalid (empty) file name.
65+
set_param("sat.smt.proof", "")
66+
67+
# Turn off proof checking. It is on by default when parsing proof logs.
68+
set_param("solver.proof.check", False)
69+
s = Solver()
70+
onc = OnClause(s, lambda pr, clause : print(pr, clause))
71+
s.from_file("proof_log.smt2")
72+
73+
74+
print("Parse the logged inferences and check them")
75+
print("--------------------------------------------------------")
76+
s = Solver()
77+
78+
# Now turn on proof checking. It invokes the self-validator.
79+
# The self-validator produces log lines of the form:
80+
# (proofs +tseitin 60 +alldiff 8 +euf 3 +rup 5 +inst 6 -quant 3 -inst 2)
81+
# (verified-smt
82+
# (inst (forall (vars (x T) (y T) (z T)) (or (subtype (:var 2) (:var 1)) ...
83+
# The 'proofs' line summarizes inferences that were self-validated.
84+
# The pair +tseitin 60 indicates that 60 inferences were validated as Tseitin
85+
# encodings.
86+
# The pair -inst 2 indicates that two quantifier instantiations were not self-validated
87+
# They were instead validated using a call to SMT solving. A log for an smt invocation
88+
# is exemplified in the next line.
89+
# Note that the pair +inst 6 indicates that 6 quantifier instantations were validated
90+
# using a syntactic (cheap) check. Some quantifier instantiations based on quantifier elimination
91+
# are not simple substitutions and therefore a simple syntactic check does not suffice.
92+
set_param("solver.proof.check", True)
93+
s.from_file("proof_log.smt2")
94+
95+
print("Verify and self-validate on the fly")
96+
print("--------------------------------------------------------")
97+
set_param("sat.smt.proof.check", True)
98+
s = Solver()
99+
s.from_string(example1)
100+
print(s.check())
101+
print(s.statistics())
102+
103+
print("Verify and self-validate on the fly, but don't check rup")
104+
print("--------------------------------------------------------")
105+
set_param("sat.smt.proof.check", True)
106+
set_param("sat.smt.proof.check_rup", False)
107+
s = Solver()
108+
s.from_string(example1)
109+
print(s.check())
110+
print(s.statistics())
111+
112+
113+

src/api/api_solver.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,14 @@ extern "C" {
931931
on_clause_eh(user_ctx, of_expr(pr.get()), of_ast_vector(literals));
932932
};
933933
to_solver_ref(s)->register_on_clause(user_context, _on_clause);
934+
auto& solver = *to_solver(s);
935+
936+
if (!solver.m_cmd_context) {
937+
solver.m_cmd_context = alloc(cmd_context, false, &(mk_c(c)->m()));
938+
install_proof_cmds(*solver.m_cmd_context);
939+
init_proof_cmds(*solver.m_cmd_context);
940+
}
941+
solver.m_cmd_context->get_proof_cmds()->register_on_clause(user_context, _on_clause);
934942
Z3_CATCH;
935943
}
936944

src/cmd_context/cmd_context.h

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class proof_cmds {
9999
virtual void end_infer() = 0;
100100
virtual void end_deleted() = 0;
101101
virtual void updt_params(params_ref const& p) = 0;
102+
virtual void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) = 0;
102103
};
103104

104105

src/cmd_context/extra_cmds/proof_cmds.cpp

+38-1
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,34 @@ class proof_cmds_imp : public proof_cmds {
227227
scoped_ptr<euf::smt_proof_checker> m_checker;
228228
scoped_ptr<proof_saver> m_saver;
229229
scoped_ptr<proof_trim> m_trimmer;
230+
user_propagator::on_clause_eh_t m_on_clause_eh;
231+
void* m_on_clause_ctx = nullptr;
232+
expr_ref m_assumption, m_del;
230233

231234
euf::smt_proof_checker& checker() { params_ref p; if (!m_checker) m_checker = alloc(euf::smt_proof_checker, m, p); return *m_checker; }
232235
proof_saver& saver() { if (!m_saver) m_saver = alloc(proof_saver, ctx); return *m_saver; }
233236
proof_trim& trim() { if (!m_trimmer) m_trimmer = alloc(proof_trim, ctx); return *m_trimmer; }
237+
238+
expr_ref assumption() {
239+
if (!m_assumption)
240+
m_assumption = m.mk_app(symbol("assumption"), 0, nullptr, m.mk_proof_sort());
241+
return m_assumption;
242+
}
243+
244+
expr_ref del() {
245+
if (!m_del)
246+
m_del = m.mk_app(symbol("del"), 0, nullptr, m.mk_proof_sort());
247+
return m_del;
248+
}
234249

235250
public:
236-
proof_cmds_imp(cmd_context& ctx): ctx(ctx), m(ctx.m()), m_lits(m), m_proof_hint(m) {
251+
proof_cmds_imp(cmd_context& ctx):
252+
ctx(ctx),
253+
m(ctx.m()),
254+
m_lits(m),
255+
m_proof_hint(m),
256+
m_assumption(m),
257+
m_del(m) {
237258
updt_params(gparams::get_module("solver"));
238259
}
239260

@@ -251,6 +272,8 @@ class proof_cmds_imp : public proof_cmds {
251272
saver().assume(m_lits);
252273
if (m_trim)
253274
trim().assume(m_lits);
275+
if (m_on_clause_eh)
276+
m_on_clause_eh(m_on_clause_ctx, assumption(), m_lits.size(), m_lits.data());
254277
m_lits.reset();
255278
m_proof_hint.reset();
256279
}
@@ -262,6 +285,8 @@ class proof_cmds_imp : public proof_cmds {
262285
saver().infer(m_lits, m_proof_hint);
263286
if (m_trim)
264287
trim().infer(m_lits, m_proof_hint);
288+
if (m_on_clause_eh)
289+
m_on_clause_eh(m_on_clause_ctx, m_proof_hint, m_lits.size(), m_lits.data());
265290
m_lits.reset();
266291
m_proof_hint.reset();
267292
}
@@ -273,6 +298,8 @@ class proof_cmds_imp : public proof_cmds {
273298
saver().del(m_lits);
274299
if (m_trim)
275300
trim().del(m_lits);
301+
if (m_on_clause_eh)
302+
m_on_clause_eh(m_on_clause_ctx, del(), m_lits.size(), m_lits.data());
276303
m_lits.reset();
277304
m_proof_hint.reset();
278305
}
@@ -285,6 +312,12 @@ class proof_cmds_imp : public proof_cmds {
285312
if (m_trim)
286313
trim().updt_params(p);
287314
}
315+
316+
void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause_eh) override {
317+
m_on_clause_ctx = ctx;
318+
m_on_clause_eh = on_clause_eh;
319+
}
320+
288321
};
289322

290323

@@ -344,3 +377,7 @@ void install_proof_cmds(cmd_context & ctx) {
344377
ctx.insert(alloc(infer_cmd));
345378
ctx.insert(alloc(assume_cmd));
346379
}
380+
381+
void init_proof_cmds(cmd_context& ctx) {
382+
get(ctx);
383+
}

src/cmd_context/extra_cmds/proof_cmds.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ Module Name:
3333

3434
class cmd_context;
3535
void install_proof_cmds(cmd_context & ctx);
36-
36+
void init_proof_cmds(cmd_context& ctx);

src/sat/sat_config.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,9 @@ namespace sat {
200200
m_smt_proof = p.smt_proof();
201201
m_smt_proof_check = p.smt_proof_check();
202202
m_smt_proof_check_rup = p.smt_proof_check_rup();
203+
m_drat_disable = p.drat_disable();
203204
m_drat =
204-
!p.drat_disable() && p.threads() == 1 &&
205+
!m_drat_disable && p.threads() == 1 &&
205206
(sp.lemmas2console() ||
206207
m_drat_check_unsat ||
207208
m_drat_file.is_non_empty_string() ||

src/sat/sat_config.h

+1
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ namespace sat {
175175

176176
// drat proofs
177177
bool m_drat;
178+
bool m_drat_disable;
178179
bool m_drat_binary;
179180
symbol m_drat_file;
180181
symbol m_smt_proof;

src/sat/smt/euf_proof.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ namespace euf {
2525
if (m_proof_initialized)
2626
return;
2727

28-
if (m_on_clause)
28+
if (m_on_clause && !s().get_config().m_drat_disable)
2929
s().set_drat(true);
3030

3131
if (!s().get_config().m_drat)
@@ -39,7 +39,6 @@ namespace euf {
3939

4040
get_drat().add_theory(get_id(), symbol("euf"));
4141
get_drat().add_theory(m.get_basic_family_id(), symbol("bool"));
42-
4342
if (s().get_config().m_smt_proof.is_non_empty_string())
4443
m_proof_out = alloc(std::ofstream, s().get_config().m_smt_proof.str(), std::ios_base::out);
4544
get_drat().set_clause_eh(*this);

src/sat/smt/euf_proof_checker.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ namespace euf {
372372
void smt_theory_checker_plugin::register_plugins(theory_checker& pc) {
373373
pc.register_plugin(symbol("datatype"), this);
374374
pc.register_plugin(symbol("array"), this);
375+
pc.register_plugin(symbol("quant"), this);
375376
pc.register_plugin(symbol("fpa"), this);
376377
}
377378

0 commit comments

Comments
 (0)