mirror of
https://github.com/Z3Prover/z3
synced 2025-05-07 15:55:46 +00:00
update proof formats for new core
- update proof format for quantifier instantiation to track original literals - update proof replay tools with ability to extract proof object The formats and features are subject to heavy revisions. Example ``` (set-option :sat.euf true) (set-option :sat.smt.proof eufproof.smt2) (declare-fun f (Int) Int) (declare-const x Int) (assert (or (= (f (f (f x))) x) (= (f (f x)) x))) (assert (not (= (f (f (f (f (f (f x)))))) x))) (check-sat) ``` eufproof.smt2 is: ``` (declare-fun x () Int) (declare-fun f (Int) Int) (define-const $24 Int (f x)) (define-const $25 Int (f $24)) (define-const $26 Int (f $25)) (define-const $27 Bool (= $26 x)) (define-const $28 Bool (= $25 x)) (assume $27 $28) (define-const $30 Int (f $26)) (define-const $31 Int (f $30)) (define-const $32 Int (f $31)) (define-const $33 Bool (= $32 x)) (assume (not $33)) (declare-fun rup () Proof) (infer (not $33) rup) (declare-fun euf (Bool Bool Proof Proof Proof Proof) Proof) (declare-fun cc (Bool) Proof) (define-const $42 Bool (= $32 $30)) (define-const $43 Proof (cc $42)) (define-const $40 Bool (= $31 $24)) (define-const $41 Proof (cc $40)) (define-const $38 Bool (= $30 $25)) (define-const $39 Proof (cc $38)) (define-const $36 Bool (= $24 $26)) (define-const $37 Proof (cc $36)) (define-const $34 Bool (not $33)) (define-const $44 Proof (euf $34 $28 $37 $39 $41 $43)) (infer (not $28) $33 $44) (infer (not $28) rup) (infer $27 rup) (declare-fun euf (Bool Bool Proof Proof Proof) Proof) (define-const $49 Bool (= $32 $26)) (define-const $50 Proof (cc $49)) (define-const $47 Bool (= $31 $25)) (define-const $48 Proof (cc $47)) (define-const $45 Bool (= $24 $30)) (define-const $46 Proof (cc $45)) (define-const $51 Proof (euf $34 $27 $46 $48 $50)) (infer $33 $51) (infer rup) ``` Example of inspecting proof from Python: ``` from z3 import * def parse(file): s = Solver() set_option("solver.proof.save", True) set_option("solver.proof.check", False) s.from_file(file) for step in s.proof().children(): print(step) parse("../eufproof.smt2") ``` Proof checking (self-validation) is on by default. Proof saving is off by default. You can use the proof logs and the proof terms to retrieve quantifier instantiations from the new core. The self-checker contains a few built-in tuned checkers but falls back to self-checking inferred clauses using SMT.
This commit is contained in:
parent
9782d4a730
commit
107981f099
40 changed files with 295 additions and 153 deletions
|
@ -177,10 +177,10 @@ ATOMIC_CMD(get_proof_cmd, "get-proof", "retrieve proof", {
|
|||
if (!ctx.has_manager())
|
||||
throw cmd_exception("proof is not available");
|
||||
|
||||
if (ctx.ignore_check())
|
||||
return;
|
||||
expr_ref pr(ctx.m());
|
||||
auto* chsr = ctx.get_check_sat_result();
|
||||
if (!chsr && ctx.ignore_check())
|
||||
return;
|
||||
if (!chsr)
|
||||
throw cmd_exception("proof is not available");
|
||||
pr = chsr->get_proof();
|
||||
|
|
|
@ -604,6 +604,8 @@ void cmd_context::global_params_updated() {
|
|||
if (m_opt) {
|
||||
get_opt()->updt_params(gparams::get_module("opt"));
|
||||
}
|
||||
if (m_proof_cmds)
|
||||
m_proof_cmds->updt_params(gparams::get_module("solver"));
|
||||
}
|
||||
|
||||
void cmd_context::set_produce_models(bool f) {
|
||||
|
|
|
@ -96,8 +96,9 @@ public:
|
|||
virtual ~proof_cmds() {}
|
||||
virtual void add_literal(expr* e) = 0;
|
||||
virtual void end_assumption() = 0;
|
||||
virtual void end_learned() = 0;
|
||||
virtual void end_infer() = 0;
|
||||
virtual void end_deleted() = 0;
|
||||
virtual void updt_params(params_ref const& p) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -159,6 +160,7 @@ struct builtin_decl {
|
|||
|
||||
class opt_wrapper : public check_sat_result {
|
||||
public:
|
||||
opt_wrapper(ast_manager& m): check_sat_result(m) {}
|
||||
virtual bool empty() = 0;
|
||||
virtual void push() = 0;
|
||||
virtual void pop(unsigned n) = 0;
|
||||
|
@ -411,6 +413,7 @@ public:
|
|||
sexpr_manager & sm() const { if (!m_sexpr_manager) const_cast<cmd_context*>(this)->m_sexpr_manager = alloc(sexpr_manager); return *m_sexpr_manager; }
|
||||
|
||||
proof_cmds* get_proof_cmds() { return m_proof_cmds.get(); }
|
||||
solver* get_solver() { return m_solver.get(); }
|
||||
void set_proof_cmds(proof_cmds* pc) { m_proof_cmds = pc; }
|
||||
|
||||
void set_solver_factory(solver_factory * s);
|
||||
|
|
|
@ -47,6 +47,7 @@ Proof checker for clauses created during search.
|
|||
#include "sat/sat_drat.h"
|
||||
#include "sat/smt/euf_proof_checker.h"
|
||||
#include "cmd_context/cmd_context.h"
|
||||
#include "params/solver_params.hpp"
|
||||
#include <iostream>
|
||||
|
||||
class smt_checker {
|
||||
|
@ -166,8 +167,6 @@ public:
|
|||
}
|
||||
m_solver->pop(1);
|
||||
std::cout << "(verified-smt)\n";
|
||||
if (proof_hint)
|
||||
std::cout << "(missed-hint " << mk_pp(proof_hint, m) << ")\n";
|
||||
add_clause(clause);
|
||||
}
|
||||
|
||||
|
@ -175,15 +174,59 @@ public:
|
|||
add_clause(clause);
|
||||
m_solver->assert_expr(mk_or(clause));
|
||||
}
|
||||
|
||||
void del(expr_ref_vector const& clause) {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class proof_saver {
|
||||
cmd_context& ctx;
|
||||
ast_manager& m;
|
||||
public:
|
||||
proof_saver(cmd_context& ctx):ctx(ctx), m(ctx.m()) {
|
||||
auto* s = ctx.get_solver();
|
||||
if (!s)
|
||||
ctx.set_solver_factory(mk_smt_strategic_solver_factory());
|
||||
if (!ctx.get_check_sat_result())
|
||||
ctx.set_check_sat_result(ctx.get_solver());
|
||||
}
|
||||
|
||||
void assume(expr_ref_vector const& clause) {
|
||||
ctx.get_solver()->log_inference(m.mk_assumption_add(nullptr, mk_or(clause)));
|
||||
}
|
||||
|
||||
void del(expr_ref_vector const& clause) {
|
||||
ctx.get_solver()->log_inference(m.mk_redundant_del(mk_or(clause)));
|
||||
}
|
||||
|
||||
void infer(expr_ref_vector const& clause, app* hint) {
|
||||
ctx.get_solver()->log_inference(m.mk_lemma_add(hint, mk_or(clause)));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class proof_cmds_imp : public proof_cmds {
|
||||
cmd_context& ctx;
|
||||
ast_manager& m;
|
||||
expr_ref_vector m_lits;
|
||||
app_ref m_proof_hint;
|
||||
smt_checker m_checker;
|
||||
bool m_check = true;
|
||||
bool m_save = false;
|
||||
bool m_trim = false;
|
||||
scoped_ptr<smt_checker> m_checker;
|
||||
scoped_ptr<proof_saver> m_saver;
|
||||
|
||||
smt_checker& checker() { if (!m_checker) m_checker = alloc(smt_checker, m); return *m_checker; }
|
||||
proof_saver& saver() { if (!m_saver) m_saver = alloc(proof_saver, ctx); return *m_saver; }
|
||||
|
||||
|
||||
public:
|
||||
proof_cmds_imp(ast_manager& m): m(m), m_lits(m), m_proof_hint(m), m_checker(m) {}
|
||||
proof_cmds_imp(cmd_context& ctx): ctx(ctx), m(ctx.m()), m_lits(m), m_proof_hint(m) {
|
||||
updt_params(gparams::get_module("solver"));
|
||||
}
|
||||
|
||||
void add_literal(expr* e) override {
|
||||
if (m.is_proof(e))
|
||||
|
@ -193,27 +236,43 @@ public:
|
|||
}
|
||||
|
||||
void end_assumption() override {
|
||||
m_checker.assume(m_lits);
|
||||
if (m_check)
|
||||
checker().assume(m_lits);
|
||||
if (m_save)
|
||||
saver().assume(m_lits);
|
||||
m_lits.reset();
|
||||
m_proof_hint.reset();
|
||||
}
|
||||
|
||||
void end_learned() override {
|
||||
m_checker.check(m_lits, m_proof_hint);
|
||||
void end_infer() override {
|
||||
if (m_check)
|
||||
checker().check(m_lits, m_proof_hint);
|
||||
if (m_save)
|
||||
saver().infer(m_lits, m_proof_hint);
|
||||
m_lits.reset();
|
||||
m_proof_hint.reset();
|
||||
}
|
||||
|
||||
void end_deleted() override {
|
||||
if (m_check)
|
||||
checker().del(m_lits);
|
||||
if (m_save)
|
||||
saver().del(m_lits);
|
||||
m_lits.reset();
|
||||
m_proof_hint.reset();
|
||||
}
|
||||
|
||||
void updt_params(params_ref const& p) {
|
||||
solver_params sp(p);
|
||||
m_check = sp.proof_check();
|
||||
m_save = sp.proof_save();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static proof_cmds& get(cmd_context& ctx) {
|
||||
if (!ctx.get_proof_cmds())
|
||||
ctx.set_proof_cmds(alloc(proof_cmds_imp, ctx.m()));
|
||||
ctx.set_proof_cmds(alloc(proof_cmds_imp, ctx));
|
||||
return *ctx.get_proof_cmds();
|
||||
}
|
||||
|
||||
|
@ -248,9 +307,9 @@ public:
|
|||
};
|
||||
|
||||
// learned/redundant clause
|
||||
class learn_cmd : public cmd {
|
||||
class infer_cmd : public cmd {
|
||||
public:
|
||||
learn_cmd():cmd("learn") {}
|
||||
infer_cmd():cmd("infer") {}
|
||||
char const* get_usage() const override { return "<expr>+"; }
|
||||
char const* get_descr(cmd_context& ctx) const override { return "proof command for learned (redundant) clauses"; }
|
||||
unsigned get_arity() const override { return VAR_ARITY; }
|
||||
|
@ -259,11 +318,11 @@ public:
|
|||
void failure_cleanup(cmd_context & ctx) override {}
|
||||
cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_EXPR; }
|
||||
void set_next_arg(cmd_context & ctx, expr * arg) override { get(ctx).add_literal(arg); }
|
||||
void execute(cmd_context& ctx) override { get(ctx).end_learned(); }
|
||||
void execute(cmd_context& ctx) override { get(ctx).end_infer(); }
|
||||
};
|
||||
|
||||
void install_proof_cmds(cmd_context & ctx) {
|
||||
ctx.insert(alloc(del_cmd));
|
||||
ctx.insert(alloc(learn_cmd));
|
||||
ctx.insert(alloc(infer_cmd));
|
||||
ctx.insert(alloc(assume_cmd));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue