mirror of
https://github.com/Z3Prover/z3
synced 2025-04-15 13:28:47 +00:00
- add solver.axioms2files - prints negated theory axioms to files. Each file should be unsat - add solver.lemmas2console - prints lemmas to the console. - remove option smt.arith.dump_lemmas. It is replaced by solver.axioms2files
429 lines
15 KiB
C++
429 lines
15 KiB
C++
/*++
|
|
Copyright (c) 2006 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
smt_justification.h
|
|
|
|
Abstract:
|
|
|
|
Proof-like objects for tracking dependencies in the SMT engine, and generating proofs.
|
|
|
|
Author:
|
|
|
|
Leonardo de Moura (leonardo) 2008-02-18.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#pragma once
|
|
|
|
#include "ast/ast.h"
|
|
#include "smt/smt_types.h"
|
|
#include "smt/smt_literal.h"
|
|
#include "smt/smt_eq_justification.h"
|
|
|
|
namespace smt {
|
|
|
|
class conflict_resolution;
|
|
class context;
|
|
|
|
typedef ptr_vector<justification> justification_vector;
|
|
|
|
/**
|
|
\brief Pseudo-proof objects. They are mainly used to track dependencies.
|
|
When proof generation is enabled, they are also used to produce proofs.
|
|
|
|
Justification objects are allocated using a stack based policy.
|
|
Actually, there is one exception: justification of lemmas.
|
|
Lemmas created at scope level n may remain alive even after scope level n is backtracked.
|
|
Lemmas are deleted by a GC that runs from time to time. So, a justification attached
|
|
to a lemma will may remain alive after scope level n is backtracked.
|
|
|
|
So, I allow justification objects to be allocated in regions and
|
|
in the regular heap. The method in_region() should return true if the object is
|
|
allocated in a region.
|
|
*/
|
|
class justification {
|
|
unsigned m_mark:1;
|
|
unsigned m_in_region:1; // true if the object was allocated in a region.
|
|
public:
|
|
justification(bool in_region = true):m_mark(false), m_in_region(in_region) {}
|
|
virtual ~justification() = default;
|
|
|
|
/**
|
|
\brief This method should return true if the method del_eh needs to be invoked
|
|
to free resources.
|
|
*/
|
|
virtual bool has_del_eh() const {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
\brief Free the resources allocated by this object.
|
|
*/
|
|
virtual void del_eh(ast_manager & m) {
|
|
}
|
|
|
|
/**
|
|
\brief Mark the antecedents the justification object.
|
|
The antecedents are marked using the mark methods of the
|
|
conflict_resolution object.
|
|
*/
|
|
virtual void get_antecedents(conflict_resolution & cr){
|
|
}
|
|
|
|
/**
|
|
\brief Return the id of the theory that produced the proof object.
|
|
*/
|
|
virtual theory_id get_from_theory() const {
|
|
return null_theory_id;
|
|
}
|
|
|
|
void set_mark() { SASSERT(!m_mark); m_mark = true; }
|
|
|
|
void unset_mark() { SASSERT(m_mark); m_mark = false; }
|
|
|
|
bool is_marked() const { return m_mark; }
|
|
|
|
unsigned hash() const { return get_ptr_hash(this); }
|
|
|
|
virtual proof * mk_proof(conflict_resolution & cr) = 0;
|
|
|
|
bool in_region() const { return m_in_region; }
|
|
|
|
virtual char const * get_name() const { return "unknown"; }
|
|
|
|
virtual void display_debug_info(conflict_resolution & cr, std::ostream & out) { /* do nothing */ }
|
|
|
|
};
|
|
|
|
class justification_proof_wrapper : public justification {
|
|
proof * m_proof;
|
|
public:
|
|
justification_proof_wrapper(context & ctx, proof * pr, bool in_region = true);
|
|
|
|
bool has_del_eh() const override {
|
|
return true;
|
|
}
|
|
|
|
void del_eh(ast_manager & m) override;
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override;
|
|
|
|
char const * get_name() const override { return "proof-wrapper"; }
|
|
};
|
|
|
|
class unit_resolution_justification : public justification {
|
|
justification * m_antecedent;
|
|
unsigned m_num_literals;
|
|
literal * m_literals;
|
|
public:
|
|
unit_resolution_justification(context& ctx, justification * js, unsigned num_lits, literal const * lits);
|
|
|
|
unit_resolution_justification(justification * js, unsigned num_lits, literal const * lits);
|
|
|
|
~unit_resolution_justification() override;
|
|
|
|
bool has_del_eh() const override {
|
|
return !in_region() && m_antecedent && m_antecedent->has_del_eh();
|
|
}
|
|
|
|
void del_eh(ast_manager & m) override {
|
|
if (!in_region() && m_antecedent) m_antecedent->del_eh(m);
|
|
}
|
|
|
|
void get_antecedents(conflict_resolution & cr) override;
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override;
|
|
|
|
char const * get_name() const override { return "unit-resolution"; }
|
|
|
|
};
|
|
|
|
class eq_conflict_justification : public justification {
|
|
enode * m_node1;
|
|
enode * m_node2;
|
|
eq_justification m_js;
|
|
public:
|
|
eq_conflict_justification(enode * n1, enode * n2, eq_justification js):
|
|
m_node1(n1),
|
|
m_node2(n2),
|
|
m_js(js) {
|
|
}
|
|
|
|
void get_antecedents(conflict_resolution & cr) override;
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override;
|
|
|
|
char const * get_name() const override { return "eq-conflict"; }
|
|
};
|
|
|
|
/**
|
|
\brief Justification for m_node = root
|
|
*/
|
|
class eq_root_propagation_justification : public justification {
|
|
enode * m_node;
|
|
public:
|
|
eq_root_propagation_justification(enode * n):m_node(n) {
|
|
}
|
|
|
|
void get_antecedents(conflict_resolution & cr) override;
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override;
|
|
|
|
char const * get_name() const override { return "eq-root"; }
|
|
};
|
|
|
|
/**
|
|
\brief Justification for m_node1 = m_node2
|
|
*/
|
|
class eq_propagation_justification : public justification {
|
|
enode * m_node1;
|
|
enode * m_node2;
|
|
public:
|
|
eq_propagation_justification(enode * n1, enode * n2):m_node1(n1), m_node2(n2) {
|
|
}
|
|
|
|
void get_antecedents(conflict_resolution & cr) override;
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override;
|
|
|
|
char const * get_name() const override { return "eq-propagation"; }
|
|
};
|
|
|
|
/**
|
|
\brief Justification for p(x) <=> p(y), p(x) ===> p(y)
|
|
*/
|
|
class mp_iff_justification : public justification {
|
|
enode * m_node1; // p(x)
|
|
enode * m_node2; // p(y)
|
|
public:
|
|
mp_iff_justification(enode * n1, enode * n2):m_node1(n1), m_node2(n2) {
|
|
}
|
|
|
|
void get_antecedents(conflict_resolution & cr) override;
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override;
|
|
|
|
char const * get_name() const override { return "mp-iff"; }
|
|
};
|
|
|
|
/**
|
|
\brief Abstract class for justifications that contains set of literals.
|
|
*/
|
|
class simple_justification : public justification {
|
|
protected:
|
|
unsigned m_num_literals;
|
|
literal * m_literals;
|
|
|
|
bool antecedent2proof(conflict_resolution & cr, ptr_buffer<proof> & result);
|
|
|
|
public:
|
|
simple_justification(context& ctx, unsigned num_lits, literal const * lits);
|
|
|
|
void get_antecedents(conflict_resolution & cr) override;
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override = 0;
|
|
|
|
char const * get_name() const override { return "simple"; }
|
|
|
|
};
|
|
|
|
class simple_theory_justification : public simple_justification {
|
|
protected:
|
|
family_id m_th_id;
|
|
vector<parameter> m_params;
|
|
public:
|
|
simple_theory_justification(
|
|
family_id fid, context& ctx,
|
|
unsigned num_lits, literal const * lits,
|
|
unsigned num_params, parameter* params):
|
|
simple_justification(ctx, num_lits, lits),
|
|
m_th_id(fid), m_params(num_params, params) {}
|
|
|
|
bool has_del_eh() const override { return !m_params.empty(); }
|
|
|
|
void del_eh(ast_manager & m) override { m_params.reset(); }
|
|
|
|
theory_id get_from_theory() const override { return m_th_id; }
|
|
|
|
};
|
|
|
|
class theory_axiom_justification : public simple_theory_justification {
|
|
public:
|
|
|
|
theory_axiom_justification(family_id fid, context& ctx,
|
|
unsigned num_lits, literal const * lits,
|
|
unsigned num_params = 0, parameter* params = nullptr):
|
|
simple_theory_justification(fid, ctx, num_lits, lits, num_params, params) {}
|
|
|
|
void get_antecedents(conflict_resolution & cr) override {}
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override;
|
|
|
|
char const * get_name() const override { return "theory-axiom"; }
|
|
};
|
|
|
|
class theory_propagation_justification : public simple_theory_justification {
|
|
literal m_consequent;
|
|
void log(context& ctx);
|
|
public:
|
|
theory_propagation_justification(family_id fid, context& ctx, unsigned num_lits, literal const * lits, literal consequent,
|
|
unsigned num_params = 0, parameter* params = nullptr):
|
|
simple_theory_justification(fid, ctx, num_lits, lits, num_params, params), m_consequent(consequent) { log(ctx); }
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override;
|
|
|
|
|
|
char const * get_name() const override { return "theory-propagation"; }
|
|
|
|
};
|
|
|
|
class theory_conflict_justification : public simple_theory_justification {
|
|
void log(context& ctx);
|
|
public:
|
|
theory_conflict_justification(family_id fid, context& ctx, unsigned num_lits, literal const * lits,
|
|
unsigned num_params = 0, parameter* params = nullptr):
|
|
simple_theory_justification(fid, ctx, num_lits, lits, num_params, params) { log(ctx); }
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override;
|
|
|
|
char const * get_name() const override { return "theory-conflict"; }
|
|
};
|
|
|
|
/**
|
|
\brief Abstract class for justifications that contains set of literals and equalities.
|
|
*/
|
|
class ext_simple_justification : public simple_justification {
|
|
protected:
|
|
unsigned m_num_eqs;
|
|
enode_pair * m_eqs;
|
|
|
|
bool antecedent2proof(conflict_resolution & cr, ptr_buffer<proof> & result);
|
|
|
|
public:
|
|
ext_simple_justification(context& ctx, unsigned num_lits, literal const * lits,
|
|
unsigned num_eqs, enode_pair const * eqs);
|
|
|
|
void get_antecedents(conflict_resolution & cr) override;
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override = 0;
|
|
|
|
char const * get_name() const override { return "ext-simple"; }
|
|
};
|
|
|
|
/**
|
|
\brief Abstract class for justifications that contains set of literals and equalities.
|
|
*/
|
|
class ext_theory_simple_justification : public ext_simple_justification {
|
|
protected:
|
|
family_id m_th_id;
|
|
vector<parameter> m_params;
|
|
|
|
public:
|
|
ext_theory_simple_justification(family_id fid, context& ctx, unsigned num_lits, literal const * lits,
|
|
unsigned num_eqs, enode_pair const * eqs,
|
|
unsigned num_params = 0, parameter* params = nullptr):
|
|
ext_simple_justification(ctx, num_lits, lits, num_eqs, eqs), m_th_id(fid), m_params(num_params, params) {}
|
|
|
|
bool has_del_eh() const override { return !m_params.empty(); }
|
|
|
|
void del_eh(ast_manager & m) override { m_params.reset(); }
|
|
|
|
theory_id get_from_theory() const override { return m_th_id; }
|
|
};
|
|
|
|
class ext_theory_propagation_justification : public ext_theory_simple_justification {
|
|
literal m_consequent;
|
|
void log(context& ctx);
|
|
public:
|
|
ext_theory_propagation_justification(family_id fid, context & ctx,
|
|
unsigned num_lits, literal const * lits,
|
|
unsigned num_eqs, enode_pair const * eqs,
|
|
literal consequent,
|
|
unsigned num_params = 0, parameter* params = nullptr):
|
|
ext_theory_simple_justification(fid, ctx, num_lits, lits, num_eqs, eqs, num_params, params),
|
|
m_consequent(consequent) {
|
|
log(ctx);
|
|
}
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override;
|
|
|
|
char const * get_name() const override { return "ext-theory-propagation"; }
|
|
|
|
};
|
|
|
|
class ext_theory_conflict_justification : public ext_theory_simple_justification {
|
|
void log(context& ctx);
|
|
public:
|
|
ext_theory_conflict_justification(family_id fid, context& ctx, unsigned num_lits, literal const * lits,
|
|
unsigned num_eqs, enode_pair const * eqs,
|
|
unsigned num_params = 0, parameter* params = nullptr):
|
|
ext_theory_simple_justification(fid, ctx, num_lits, lits, num_eqs, eqs, num_params, params) {
|
|
log(ctx);
|
|
}
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override;
|
|
|
|
char const * get_name() const override { return "ext-theory-conflict"; }
|
|
};
|
|
|
|
class ext_theory_eq_propagation_justification : public ext_theory_simple_justification {
|
|
enode * m_lhs;
|
|
enode * m_rhs;
|
|
void log(context& ctx);
|
|
public:
|
|
ext_theory_eq_propagation_justification(
|
|
family_id fid, context& ctx,
|
|
unsigned num_lits, literal const * lits,
|
|
unsigned num_eqs, enode_pair const * eqs,
|
|
enode * lhs, enode * rhs,
|
|
unsigned num_params = 0, parameter* params = nullptr):
|
|
ext_theory_simple_justification(fid, ctx, num_lits, lits, num_eqs, eqs, num_params, params), m_lhs(lhs), m_rhs(rhs) { log(ctx); }
|
|
|
|
ext_theory_eq_propagation_justification(
|
|
family_id fid, context& ctx,
|
|
enode * lhs, enode * rhs):
|
|
ext_theory_simple_justification(fid, ctx, 0, nullptr, 0, nullptr, 0, nullptr), m_lhs(lhs), m_rhs(rhs) { log(ctx); }
|
|
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override;
|
|
|
|
char const * get_name() const override { return "ext-theory-eq-propagation"; }
|
|
};
|
|
|
|
/**
|
|
\brief A theory lemma is similar to a theory axiom, but it is attached to a CLS_AUX_LEMMA clause instead of CLS_AUX.
|
|
So, it cannot be stored in the heap, and it is unsafe to store literals, since it may be deleted during backtracking.
|
|
Instead, they store a set of pairs (sign, expr). This pair is represented as a tagged pointer.
|
|
*/
|
|
class theory_lemma_justification : public justification {
|
|
family_id m_th_id;
|
|
vector<parameter> m_params;
|
|
unsigned m_num_literals;
|
|
expr ** m_literals;
|
|
|
|
public:
|
|
theory_lemma_justification(family_id fid, context & ctx, unsigned num_lits, literal const * lits,
|
|
unsigned num_params = 0, parameter* params = nullptr);
|
|
|
|
~theory_lemma_justification() override;
|
|
|
|
bool has_del_eh() const override {
|
|
return true;
|
|
}
|
|
|
|
void del_eh(ast_manager & m) override;
|
|
|
|
void get_antecedents(conflict_resolution & cr) override {}
|
|
|
|
proof * mk_proof(conflict_resolution & cr) override;
|
|
|
|
char const * get_name() const override { return "theory-lemma"; }
|
|
};
|
|
|
|
};
|
|
|
|
|