3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-22 16:45:31 +00:00

proof-checker: replace match_negated with ast_manager::is_complement

is_complement matches true and false, while match_negated does not

Necessary to handle uses of true-axiom
This commit is contained in:
Arie Gurfinkel 2018-05-21 10:45:07 -07:00
parent 9550fd1ec4
commit 6514741e3f

View file

@ -1,4 +1,3 @@
/*++
Copyright (c) 2015 Microsoft Corporation
@ -16,7 +15,7 @@ Copyright (c) 2015 Microsoft Corporation
#define SAME_OP(_d1_, _d2_) ((_d1_ == _d2_) || (IS_EQUIV(_d1_) && IS_EQUIV(_d2_)))
proof_checker::hyp_decl_plugin::hyp_decl_plugin() :
proof_checker::hyp_decl_plugin::hyp_decl_plugin() :
m_cons(nullptr),
m_atom(nullptr),
m_nil(nullptr),
@ -59,13 +58,13 @@ func_decl * proof_checker::hyp_decl_plugin::mk_func_decl(decl_kind k) {
}
func_decl * proof_checker::hyp_decl_plugin::mk_func_decl(
decl_kind k, unsigned num_parameters, parameter const * parameters,
decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
return mk_func_decl(k);
}
func_decl * proof_checker::hyp_decl_plugin::mk_func_decl(
decl_kind k, unsigned num_parameters, parameter const * parameters,
decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned num_args, expr * const * args, sort * range) {
return mk_func_decl(k);
}
@ -84,7 +83,7 @@ void proof_checker::hyp_decl_plugin::get_sort_names(svector<builtin_name> & sort
}
}
proof_checker::proof_checker(ast_manager& m) : m(m), m_todo(m), m_marked(), m_pinned(m), m_nil(m),
proof_checker::proof_checker(ast_manager& m) : m(m), m_todo(m), m_marked(), m_pinned(m), m_nil(m),
m_dump_lemmas(false), m_logic("AUFLIA"), m_proof_lemma_id(0) {
symbol fam_name("proof_hypothesis");
if (!m.has_plugin(fam_name)) {
@ -98,16 +97,16 @@ proof_checker::proof_checker(ast_manager& m) : m(m), m_todo(m), m_marked(), m_pi
bool proof_checker::check(proof* p, expr_ref_vector& side_conditions) {
proof_ref curr(m);
m_todo.push_back(p);
bool result = true;
while (result && !m_todo.empty()) {
curr = m_todo.back();
m_todo.pop_back();
result = check1(curr.get(), side_conditions);
if (!result) {
IF_VERBOSE(0, ast_ll_pp(verbose_stream() << "Proof check failed\n", m, curr.get()););
IF_VERBOSE(0, ast_ll_pp(verbose_stream() << "Proof check failed\n", m, curr.get()););
UNREACHABLE();
}
}
}
m_hypotheses.reset();
@ -157,10 +156,10 @@ bool proof_checker::check1_spc(proof* p, expr_ref_vector& side_conditions) {
}
return false;
}
case PR_SPC_REWRITE:
case PR_SUPERPOSITION:
case PR_SPC_REWRITE:
case PR_SUPERPOSITION:
case PR_EQUALITY_RESOLUTION:
case PR_SPC_RESOLUTION:
case PR_SPC_RESOLUTION:
case PR_FACTORING:
case PR_SPC_DER: {
if (match_fact(p, fact)) {
@ -176,7 +175,7 @@ bool proof_checker::check1_spc(proof* p, expr_ref_vector& side_conditions) {
side_conditions.push_back(rewrite_cond.get());
return true;
}
return false;
return false;
}
default:
UNREACHABLE();
@ -201,7 +200,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
func_decl_ref f1(m), f2(m);
expr_ref_vector terms1(m), terms2(m), terms(m);
sort_ref_vector decls1(m), decls2(m);
if (match_proof(p, proofs)) {
for (unsigned i = 0; i < proofs.size(); ++i) {
add_premise(proofs.get(i));
@ -231,8 +230,8 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
return false;
}
case PR_REFLEXIVITY: {
if (match_fact(p, fact) &&
match_proof(p) &&
if (match_fact(p, fact) &&
match_proof(p) &&
(match_equiv(fact, t1, t2) || match_oeq(fact, t1, t2)) &&
(t1.get() == t2.get())) {
return true;
@ -245,7 +244,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
match_proof(p, p1) &&
match_fact(p1.get(), fml) &&
match_binary(fact.get(), d1, l1, r1) &&
match_binary(fml.get(), d2, l2, r2) &&
match_binary(fml.get(), d2, l2, r2) &&
SAME_OP(d1.get(), d2.get()) &&
l1.get() == r2.get() &&
r1.get() == l2.get()) {
@ -273,7 +272,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
}
UNREACHABLE();
return false;
}
}
case PR_TRANSITIVITY_STAR: {
if (match_fact(p, fact) &&
match_binary(fact.get(), d1, t1, t2)) {
@ -294,14 +293,14 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
return false;
}
}
return
return
vertices.size() == 2 &&
vertices.contains(t1->get_id()) &&
vertices.contains(t2->get_id());
}
UNREACHABLE();
return false;
}
}
case PR_MONOTONICITY: {
TRACE("proof_checker", tout << mk_bounded_pp(p, m, 3) << "\n";);
if (match_fact(p, fact) &&
@ -317,7 +316,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
if (term1 != term2) {
bool found = false;
for(unsigned j = 0; j < proofs.size() && !found; ++j) {
found =
found =
match_fact(proofs[j].get(), fml) &&
match_binary(fml.get(), d2, s1, s2) &&
SAME_OP(d1.get(), d2.get()) &&
@ -353,7 +352,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
for (unsigned i = 0; i < q1->get_num_decls(); ++i) {
if (q1->get_decl_sort(i) != q2->get_decl_sort(i)) {
// term is not well-typed.
UNREACHABLE();
UNREACHABLE();
return false;
}
}
@ -410,7 +409,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
side_conditions.push_back(fact.get());
return true;
}
IF_VERBOSE(0, verbose_stream() << "Expected proof of equality:\n" << mk_bounded_pp(p, m););
IF_VERBOSE(0, verbose_stream() << "Expected proof of equality:\n" << mk_bounded_pp(p, m););
return false;
}
case PR_REWRITE_STAR: {
@ -428,8 +427,8 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
side_conditions.push_back(rewrite_cond.get());
return true;
}
IF_VERBOSE(0, verbose_stream() << "Expected proof of equality:\n" << mk_bounded_pp(p, m););
return false;
IF_VERBOSE(0, verbose_stream() << "Expected proof of equality:\n" << mk_bounded_pp(p, m););
return false;
}
case PR_PULL_QUANT: {
if (match_proof(p) &&
@ -439,7 +438,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
// TBD: check the enchilada.
return true;
}
IF_VERBOSE(0, verbose_stream() << "Expected proof of equivalence with a quantifier:\n" << mk_bounded_pp(p, m););
IF_VERBOSE(0, verbose_stream() << "Expected proof of equivalence with a quantifier:\n" << mk_bounded_pp(p, m););
return false;
}
case PR_PUSH_QUANT: {
@ -459,7 +458,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
}
else {
return false;
}
}
}
}
UNREACHABLE();
@ -470,7 +469,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
match_fact(p, fact) &&
match_iff(fact.get(), t1, t2)) {
// TBD:
// match_quantifier(t1.get(), is_forall1, decls1, body1)
// match_quantifier(t1.get(), is_forall1, decls1, body1)
// filter out decls1 that occur in body1.
// if list is empty, then t2 could be just body1.
// otherwise t2 is also a quantifier.
@ -489,7 +488,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
// TBD: check that terms are set of equalities.
// t2 is an instance of a predicate in terms1
return true;
}
}
IF_VERBOSE(0, verbose_stream() << "does not match last rule: " << mk_pp(p, m) << "\n";);
return false;
}
@ -511,7 +510,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
get_hypotheses(p1.get(), hypotheses);
if (hypotheses.size() == 1 && match_negated(hypotheses.get(0), fact)) {
// Suppose fact is (or a b c) and hypothesis is (not (or a b c))
// That is, (or a b c) should be viewed as a 'quoted expression' and a unary clause,
// That is, (or a b c) should be viewed as a 'quoted expression' and a unary clause,
// instead of a clause with three literals.
return true;
}
@ -535,7 +534,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
});
UNREACHABLE();
return false;
}
}
TRACE("proof_checker", tout << "Matched:\n";
ast_ll_pp(tout, m, hypotheses[i].get());
ast_ll_pp(tout, m, ors[j-1].get()););
@ -550,7 +549,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
proofs.size() == 2 &&
match_fact(proofs[0].get(), fml1) &&
match_fact(proofs[1].get(), fml2) &&
match_negated(fml1.get(), fml2.get()) &&
m.is_complement(fml1.get(), fml2.get()) &&
m.is_false(fact.get())) {
return true;
}
@ -564,7 +563,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
}
bool found = false;
for (unsigned j = 0; !found && j < terms1.size(); ++j) {
if (match_negated(terms1.get(j), fml2)) {
if (m.is_complement(terms1.get(j), fml2)) {
found = true;
if (j + 1 < terms1.size()) {
terms1[j] = terms1.get(terms1.size()-1);
@ -573,7 +572,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
}
}
if (!found) {
TRACE("pr_unit_bug",
TRACE("pr_unit_bug",
tout << "Parents:\n";
for (unsigned i = 0; i < proofs.size(); i++) {
expr_ref p(m);
@ -592,9 +591,9 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
}
}
switch(terms1.size()) {
case 0:
case 0:
return m.is_false(fact.get());
case 1:
case 1:
return fact.get() == terms1[0].get();
default: {
if (match_or(fact.get(), terms2)) {
@ -617,7 +616,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
return false;
}
}
}
UNREACHABLE();
@ -635,7 +634,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
}
UNREACHABLE();
return false;
}
}
case PR_IFF_FALSE: {
// iff_false(?rule(?p1, (not ?fml)), (iff ?fml false))
if (match_proof(p, p1) &&
@ -678,11 +677,11 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
}
case PR_DEF_INTRO: {
// def_intro(?fml)
//
//
// ?fml: forall x . ~p(x) or e(x) and forall x . ~e(x) or p(x)
// : forall x . ~cond(x) or f(x) = then(x) and forall x . cond(x) or f(x) = else(x)
// : forall x . f(x) = e(x)
//
//
if (match_fact(p, fact) &&
match_proof(p) &&
m.is_bool(fact.get())) {
@ -712,7 +711,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
return true;
}
UNREACHABLE();
return false;
return false;
}
case PR_NNF_POS: {
// TBD:
@ -735,9 +734,9 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
is_forall = true;
}
if (is_quantifier(e)) {
q = to_quantifier(e);
q = to_quantifier(e);
// TBD check that quantifier is properly instantiated
return is_forall == q->is_forall();
return is_forall == q->is_forall();
}
}
UNREACHABLE();
@ -788,7 +787,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
vs(premise, sub.size(), sub.c_ptr(), premise);
}
fmls.push_back(premise.get());
TRACE("proof_checker",
TRACE("proof_checker",
tout << mk_pp(premise.get(), m) << "\n";
for (unsigned j = 0; j < sub.size(); ++j) {
tout << mk_pp(sub[j], m) << " ";
@ -810,7 +809,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
// ok
}
else {
IF_VERBOSE(0, verbose_stream() << "Could not establish complementarity for:\n" <<
IF_VERBOSE(0, verbose_stream() << "Could not establish complementarity for:\n" <<
mk_pp(lit1, m) << "\n" << mk_pp(lit2, m) << "\n" << mk_pp(p, m) << "\n";);
}
fmls[i] = premise1;
@ -825,7 +824,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
else {
premise0 = m.mk_iff(premise0, conclusion);
}
side_conditions.push_back(premise0);
side_conditions.push_back(premise0);
return true;
}
default:
@ -841,7 +840,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
(=> (and ln+1 ln+2 .. ln+m) l0)
or in the most general (ground) form:
(=> (and ln+1 ln+2 .. ln+m) (or l0 l1 .. ln-1))
In other words we use the following (Prolog style) convention for Horn
In other words we use the following (Prolog style) convention for Horn
implications:
The head of a Horn implication is position 0,
the first conjunct in the body of an implication is position 1
@ -853,7 +852,7 @@ void proof_checker::set_false(expr_ref& e, unsigned position, expr_ref& lit) {
app* a = to_app(e);
expr* head, *body;
expr_ref_vector args(m);
if (m.is_or(e)) {
if (m.is_or(e)) {
SASSERT(position < a->get_num_args());
args.append(a->get_num_args(), a->get_args());
lit = args[position].get();
@ -865,13 +864,13 @@ void proof_checker::set_false(expr_ref& e, unsigned position, expr_ref& lit) {
unsigned num_heads = 1;
if (m.is_or(head)) {
num_heads = to_app(head)->get_num_args();
heads = to_app(head)->get_args();
heads = to_app(head)->get_args();
}
expr*const* bodies = &body;
unsigned num_bodies = 1;
if (m.is_and(body)) {
num_bodies = to_app(body)->get_num_args();
bodies = to_app(body)->get_args();
bodies = to_app(body)->get_args();
}
if (position < num_heads) {
args.append(num_heads, heads);
@ -884,7 +883,7 @@ void proof_checker::set_false(expr_ref& e, unsigned position, expr_ref& lit) {
args.append(num_bodies, bodies);
lit = m.mk_not(args[position].get());
args[position] = m.mk_true();
e = m.mk_implies(m.mk_and(args.size(), args.c_ptr()), head);
e = m.mk_implies(m.mk_and(args.size(), args.c_ptr()), head);
}
}
else if (position == 0) {
@ -914,7 +913,7 @@ void proof_checker::add_premise(proof* p) {
}
bool proof_checker::match_proof(proof const* p) const {
return
return
m.is_proof(p) &&
m.get_num_parents(p) == 0;
}
@ -927,7 +926,7 @@ bool proof_checker::match_proof(proof const* p, proof_ref& p0) const {
}
return false;
}
bool proof_checker::match_proof(proof const* p, proof_ref& p0, proof_ref& p1) const {
if (m.is_proof(p) &&
m.get_num_parents(p) == 2) {
@ -1055,7 +1054,7 @@ bool proof_checker::match_oeq(expr const* e, expr_ref& t1, expr_ref& t2) const {
bool proof_checker::match_negated(expr const* a, expr* b) const {
expr_ref t(m);
return
return
(match_not(a, t) && t.get() == b) ||
(match_not(b, t) && t.get() == a);
}
@ -1082,7 +1081,7 @@ void proof_checker::get_hypotheses(proof* p, expr_ref_vector& ante) {
p = stack.back();
SASSERT(m.is_proof(p));
if (m_hypotheses.contains(p)) {
stack.pop_back();
stack.pop_back();
continue;
}
if (is_hypothesis(p) && match_fact(p, hyp)) {
@ -1124,13 +1123,13 @@ void proof_checker::get_hypotheses(proof* p, expr_ref_vector& ante) {
if (!m_hypotheses.find(p, h)) {
UNREACHABLE();
}
ptr_buffer<expr> hyps;
ptr_buffer<expr> todo;
expr_mark mark;
todo.push_back(h);
expr_ref a(m), b(m);
while (!todo.empty()) {
h = todo.back();
@ -1155,14 +1154,14 @@ void proof_checker::get_hypotheses(proof* p, expr_ref_vector& ante) {
ast_ll_pp(tout << "Getting hypotheses from: ", m, p);
tout << "Found hypotheses:\n";
for (unsigned i = 0; i < ante.size(); ++i) {
ast_ll_pp(tout, m, ante[i].get());
ast_ll_pp(tout, m, ante[i].get());
}
});
}
bool proof_checker::match_nil(expr const* e) const {
return
return
is_app(e) &&
to_app(e)->get_family_id() == m_hyp_fid &&
to_app(e)->get_decl_kind() == OP_NIL;
@ -1203,7 +1202,7 @@ expr* proof_checker::mk_nil() {
}
bool proof_checker::is_hypothesis(proof const* p) const {
return
return
m.is_proof(p) &&
p->get_decl_kind() == PR_HYPOTHESIS;
}
@ -1225,7 +1224,7 @@ expr* proof_checker::mk_hyp(unsigned num_hyps, expr * const * hyps) {
}
else {
return result;
}
}
}
void proof_checker::dump_proof(proof const* pr) {
@ -1267,7 +1266,7 @@ void proof_checker::dump_proof(unsigned num_antecedents, expr * const * antecede
bool proof_checker::check_arith_literal(bool is_pos, app* lit0, rational const& coeff, expr_ref& sum, bool& is_strict) {
arith_util a(m);
app* lit = lit0;
if (m.is_not(lit)) {
lit = to_app(lit->get_arg(0));
is_pos = !is_pos;
@ -1307,25 +1306,25 @@ bool proof_checker::check_arith_literal(bool is_pos, app* lit0, rational const&
}
//
// Multiplying by coefficients over strict
// Multiplying by coefficients over strict
// and non-strict inequalities:
//
// (a <= b) * 2
// (a - b <= 0) * 2
// (2a - 2b <= 0)
// (a < b) * 2 <=>
// (a +1 <= b) * 2 <=>
// 2a + 2 <= 2b <=>
// 2a+2-2b <= 0
bool strict_ineq =
is_pos?(a.is_gt(lit) || a.is_lt(lit)):(a.is_ge(lit) || a.is_le(lit));
if (is_int && strict_ineq) {
sum = a.mk_add(sum, sign1);
}
term = a.mk_mul(sign1, a0);
sum = a.mk_add(sum, term);
term = a.mk_mul(sign2, a1);
@ -1357,7 +1356,7 @@ bool proof_checker::check_arith_proof(proof* p) {
}
expr_ref fact(m);
proof_ref_vector proofs(m);
if (!match_fact(p, fact)) {
UNREACHABLE();
return false;
@ -1386,7 +1385,7 @@ bool proof_checker::check_arith_proof(proof* p) {
coeffs[i] = lc*coeffs[i];
}
}
unsigned num_parents = m.get_num_parents(p);
for (unsigned i = 0; i < num_parents; i++) {
proof * a = m.get_parent(p, i);
@ -1395,11 +1394,11 @@ bool proof_checker::check_arith_proof(proof* p) {
return false;
}
}
if (m.is_or(fact)) {
if (m.is_or(fact)) {
app* disj = to_app(fact);
unsigned num_args = disj->get_num_args();
for (unsigned i = 0; i < num_args; ++i) {
for (unsigned i = 0; i < num_args; ++i) {
app* lit = to_app(disj->get_arg(i));
if (!check_arith_literal(false, lit, coeffs[offset++], sum, is_strict)) {
return false;
@ -1411,13 +1410,13 @@ bool proof_checker::check_arith_proof(proof* p) {
return false;
}
}
if (!sum.get()) {
return false;
}
sort* s = m.get_sort(sum);
if (is_strict) {
sum = autil.mk_lt(sum, autil.mk_numeral(rational(0), s));
@ -1435,6 +1434,6 @@ bool proof_checker::check_arith_proof(proof* p) {
dump_proof(p);
return false;
}
return true;
}