z3-z3-4.13.0.src.smt.smt_justification.h Maven / Gradle / Ivy
The newest version!
/*++
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_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 & 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 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 & 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 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 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"; }
};
};