3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-30 04:15:51 +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:
Nikolaj Bjorner 2022-09-28 10:40:43 -07:00
parent 9782d4a730
commit 107981f099
40 changed files with 295 additions and 153 deletions

View file

@ -20,6 +20,7 @@ Author:
#include "ast/ast_ll_pp.h"
#include "sat/smt/euf_proof_checker.h"
#include "sat/smt/arith_proof_checker.h"
#include <iostream>
namespace euf {
@ -57,6 +58,7 @@ namespace euf {
ast_manager& m;
basic_union_find m_uf;
svector<std::pair<unsigned, unsigned>> m_expr2id;
ptr_vector<expr> m_id2expr;
svector<std::pair<expr*,expr*>> m_diseqs;
unsigned m_ts = 0;
@ -108,10 +110,10 @@ namespace euf {
if (ts != m_ts) {
id = m_uf.mk_var();
m_expr2id.setx(e->get_id(), {m_ts, id}, {0,0});
m_id2expr.setx(id, e, nullptr);
}
return id;
}
}
public:
eq_proof_checker(ast_manager& m): m(m) {}
@ -149,15 +151,17 @@ namespace euf {
if (!is_app(arg))
return false;
app* a = to_app(arg);
if (a->get_num_args() != 2)
if (a->get_num_args() != 1)
return false;
if (a->get_name() != symbol("cc"))
if (!m.is_eq(a->get_arg(0), x, y))
return false;
if (!m.is_eq(a->get_arg(1), x, y))
bool is_cc = a->get_name() == symbol("cc");
bool is_comm = a->get_name() == symbol("comm");
if (!is_cc && !is_comm)
return false;
if (!is_app(x) || !is_app(y))
return false;
if (!congruence(m.is_true(a->get_arg(0)), to_app(x), to_app(y))) {
if (!congruence(!is_cc, to_app(x), to_app(y))) {
IF_VERBOSE(0, verbose_stream() << "not congruent " << mk_pp(a, m) << "\n");
return false;
}
@ -167,9 +171,27 @@ namespace euf {
return false;
}
}
// check if a disequality is violated.
for (auto const& [a, b] : m_diseqs)
if (are_equal(a, b))
return true;
return true;
// check if some equivalence class contains two distinct values.
for (unsigned v = 0; v < m_uf.get_num_vars(); ++v) {
if (v != m_uf.find(v))
continue;
unsigned r = v;
expr* val = nullptr;
do {
expr* e = m_id2expr[v];
if (val && m.are_distinct(e, val))
return true;
if (m.is_value(e))
val = e;
v = m_uf.next(v);
}
while (r != v);
}
return false;
}
@ -201,8 +223,12 @@ namespace euf {
units.reset();
app* a = to_app(e);
proof_checker_plugin* p = nullptr;
if (m_map.find(a->get_decl()->get_name(), p))
return p->check(clause, a, units);
if (!m_map.find(a->get_decl()->get_name(), p))
return false;
if (p->check(clause, a, units))
return true;
std::cout << "(missed-hint " << mk_pp(e, m) << ")\n";
return false;
}