feat(library/blast/state): add methods for deleting hypotheses
This commit is contained in:
parent
0a25652885
commit
2889ec5870
3 changed files with 162 additions and 25 deletions
|
@ -25,7 +25,7 @@ using hypothesis_idx_map = typename lean::rb_map<unsigned, T, unsigned_cmp>;
|
|||
class hypothesis {
|
||||
friend class state;
|
||||
name m_name; // for pretty printing
|
||||
unsigned m_active:1;
|
||||
unsigned m_dead:1;
|
||||
unsigned m_dep_depth; // dependency depth
|
||||
unsigned m_proof_depth; // proof depth when the hypothesis was created
|
||||
hypothesis_idx_set m_deps; // hypotheses used by the type and/or value of this hypothesis.
|
||||
|
@ -34,9 +34,9 @@ class hypothesis {
|
|||
optional<expr> m_value; // justification for this object.
|
||||
// Remark: if blast::is_local(m_value) is true, then the hypothesis is an assumption
|
||||
public:
|
||||
hypothesis():m_active(false), m_dep_depth(0) {}
|
||||
hypothesis():m_dead(false), m_dep_depth(0) {}
|
||||
name const & get_name() const { return m_name; }
|
||||
bool is_active() const { return m_active; }
|
||||
bool is_dead() const { return m_dead; }
|
||||
unsigned get_dep_depth() const { return m_dep_depth; }
|
||||
unsigned get_proof_depth() const { return m_proof_depth; }
|
||||
hypothesis_idx_set const & get_backward_deps() const { return m_deps; }
|
||||
|
|
|
@ -299,7 +299,9 @@ bool state::check_hypothesis(expr const & e, unsigned hidx, hypothesis const & h
|
|||
}
|
||||
|
||||
bool state::check_hypothesis(unsigned hidx, hypothesis const & h) const {
|
||||
lean_assert(check_hypothesis(h.get_type(), hidx, h));
|
||||
if (!h.is_dead()) {
|
||||
lean_assert(check_hypothesis(h.get_type(), hidx, h));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -337,8 +339,9 @@ struct hypothesis_dep_depth_lt {
|
|||
};
|
||||
|
||||
void state::get_sorted_hypotheses(hypothesis_idx_buffer & r) const {
|
||||
m_branch.m_hyp_decls.for_each([&](unsigned hidx, hypothesis const &) {
|
||||
r.push_back(hidx);
|
||||
m_branch.m_hyp_decls.for_each([&](unsigned hidx, hypothesis const & h) {
|
||||
if (!h.is_dead())
|
||||
r.push_back(hidx);
|
||||
});
|
||||
std::sort(r.begin(), r.end(), hypothesis_dep_depth_lt(*this));
|
||||
}
|
||||
|
@ -357,7 +360,17 @@ void state::add_forward_dep(unsigned hidx_user, unsigned hidx_provider) {
|
|||
}
|
||||
}
|
||||
|
||||
void state::del_forward_dep(unsigned hidx_user, unsigned hidx_provider) {
|
||||
auto s = m_branch.m_forward_deps.find(hidx_provider);
|
||||
lean_assert(s);
|
||||
lean_assert(s->contains(hidx_user));
|
||||
hypothesis_idx_set new_s(*s);
|
||||
new_s.erase(hidx_user);
|
||||
m_branch.m_forward_deps.insert(hidx_provider, new_s);
|
||||
}
|
||||
|
||||
void state::add_deps(expr const & e, hypothesis & h_user, unsigned hidx_user) {
|
||||
lean_assert(!h_user.is_dead());
|
||||
if (!has_href(e) && !has_mref(e))
|
||||
return; // nothing to be done
|
||||
for_each(e, [&](expr const & l, unsigned) {
|
||||
|
@ -424,6 +437,99 @@ expr state::mk_hypothesis(expr const & type) {
|
|||
return mk_hypothesis(hidx, name(*g_prefix, hidx), type, none_expr());
|
||||
}
|
||||
|
||||
void state::del_hypotheses(buffer<hypothesis_idx> const & to_delete, hypothesis_idx_set const & to_delete_set) {
|
||||
for (hypothesis_idx h : to_delete) {
|
||||
hypothesis h_decl = *get_hypothesis_decl(h);
|
||||
if (m_branch.m_active.contains(h)) {
|
||||
m_branch.m_active.erase(h);
|
||||
remove_from_indices(h_decl, h);
|
||||
}
|
||||
m_branch.m_assumption.erase(h);
|
||||
m_branch.m_forward_deps.erase(h);
|
||||
h_decl.m_deps.for_each([&](hypothesis_idx h_dep) {
|
||||
if (to_delete_set.contains(h_dep)) {
|
||||
// we don't need to update forward deps for h_dep since
|
||||
// it will also be deleted.
|
||||
return;
|
||||
}
|
||||
del_forward_dep(h, h_dep);
|
||||
});
|
||||
h_decl.m_deps = hypothesis_idx_set();
|
||||
h_decl.m_dead = true;
|
||||
m_branch.m_hyp_decls.insert(h, h_decl);
|
||||
// Remark: we don't remove h from m_todo_queue. It is too expensive.
|
||||
// So, the method activate_hypothesis MUST check whether the candidate
|
||||
// hypothesis is dead or not.
|
||||
}
|
||||
}
|
||||
|
||||
void state::collect_forward_deps(hypothesis_idx hidx, buffer<hypothesis_idx> & result, hypothesis_idx_set & already_found) {
|
||||
unsigned qhead = result.size();
|
||||
while (true) {
|
||||
hypothesis_idx_set s = get_forward_deps(hidx);
|
||||
s.for_each([&](hypothesis_idx h_dep) {
|
||||
if (already_found.contains(h_dep))
|
||||
return;
|
||||
already_found.insert(h_dep);
|
||||
result.push_back(h_dep);
|
||||
});
|
||||
if (qhead == result.size())
|
||||
return;
|
||||
hidx = result[qhead];
|
||||
qhead++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return true iff the target type does not depend on any of the hypotheses in to_delete */
|
||||
bool state::safe_to_delete(buffer<hypothesis_idx> const & to_delete) {
|
||||
for (hypothesis_idx h : to_delete) {
|
||||
if (m_branch.m_target_deps.contains(h)) {
|
||||
// h cannot be deleted since the target type
|
||||
// depends on it.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void state::collect_forward_deps(hypothesis_idx hidx, buffer<hypothesis_idx> & result) {
|
||||
hypothesis_idx_set found;
|
||||
collect_forward_deps(hidx, result, found);
|
||||
}
|
||||
|
||||
bool state::del_hypotheses(buffer<hypothesis_idx> const & hs) {
|
||||
hypothesis_idx_set found;
|
||||
buffer<hypothesis_idx> to_delete;
|
||||
for (hypothesis_idx hidx : hs) {
|
||||
to_delete.push_back(hidx);
|
||||
found.insert(hidx);
|
||||
collect_forward_deps(hidx, to_delete, found);
|
||||
}
|
||||
if (!safe_to_delete(to_delete))
|
||||
return false;
|
||||
del_hypotheses(to_delete, found);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool state::del_hypothesis(hypothesis_idx hidx) {
|
||||
hypothesis_idx_set found;
|
||||
buffer<hypothesis_idx> to_delete;
|
||||
to_delete.push_back(hidx);
|
||||
found.insert(hidx);
|
||||
collect_forward_deps(hidx, to_delete, found);
|
||||
if (!safe_to_delete(to_delete))
|
||||
return false;
|
||||
del_hypotheses(to_delete, found);
|
||||
return true;
|
||||
}
|
||||
|
||||
hypothesis_idx_set state::get_forward_deps(hypothesis_idx hidx) const {
|
||||
if (auto r = m_branch.m_forward_deps.find(hidx))
|
||||
return *r;
|
||||
else
|
||||
return hypothesis_idx_set();
|
||||
}
|
||||
|
||||
static optional<head_index> to_head_index(expr type) {
|
||||
is_not(type, type);
|
||||
expr const & f = get_app_fn(type);
|
||||
|
@ -470,14 +576,22 @@ void state::update_indices(hypothesis_idx hidx) {
|
|||
/* TODO(Leo): update congruence closure indices */
|
||||
}
|
||||
|
||||
void state::remove_from_indices(hypothesis const & h, hypothesis_idx hidx) {
|
||||
if (auto i = to_head_index(h))
|
||||
m_branch.m_head_to_hyps.erase(*i, hidx);
|
||||
}
|
||||
|
||||
optional<unsigned> state::activate_hypothesis() {
|
||||
if (m_branch.m_todo_queue.empty()) {
|
||||
return optional<unsigned>();
|
||||
} else {
|
||||
unsigned hidx = m_branch.m_todo_queue.erase_min();
|
||||
m_branch.m_active.insert(hidx);
|
||||
update_indices(hidx);
|
||||
return optional<unsigned>(hidx);
|
||||
while (true) {
|
||||
if (m_branch.m_todo_queue.empty())
|
||||
return optional<unsigned>();
|
||||
unsigned hidx = m_branch.m_todo_queue.erase_min();
|
||||
hypothesis const * h_decl = get_hypothesis_decl(hidx);
|
||||
if (!h_decl->is_dead()) {
|
||||
m_branch.m_active.insert(hidx);
|
||||
update_indices(hidx);
|
||||
return optional<unsigned>(hidx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -103,12 +103,13 @@ class branch {
|
|||
typedef rb_map<double, hypothesis_idx, double_cmp> todo_queue;
|
||||
// Hypothesis/facts in the current state
|
||||
hypothesis_decls m_hyp_decls;
|
||||
// We break the set of hypotheses in m_context in 3 sets that are not necessarily disjoint:
|
||||
// We break the set of hypotheses in m_hyp_decls in 4 sets that are not necessarily disjoint:
|
||||
// - assumption
|
||||
// - active
|
||||
// - todo
|
||||
// - dead
|
||||
//
|
||||
// The sets active and todo are disjoint.
|
||||
// The sets active and todo are disjoint. The set dead is also disjoint from the other sets.
|
||||
//
|
||||
// A hypothesis is an "assumption" if it comes from the input goal,
|
||||
// "intros" proof step, or an assumption obtained when applying an elimination step.
|
||||
|
@ -142,15 +143,7 @@ class state {
|
|||
void add_forward_dep(hypothesis_idx hidx_user, hypothesis_idx hidx_provider);
|
||||
void add_deps(expr const & e, hypothesis & h_user, hypothesis_idx hidx_user);
|
||||
void add_deps(hypothesis & h_user, hypothesis_idx hidx_user);
|
||||
|
||||
/** \brief Compute the weight of a hypothesis with the given type
|
||||
We use this weight to update the todo_queue. */
|
||||
double compute_weight(hypothesis_idx hidx, expr const & type);
|
||||
|
||||
/** \brief This method is invoked when a hypothesis move from todo to active.
|
||||
|
||||
We will update indices and data-structures (e.g., congruence closure). */
|
||||
void update_indices(hypothesis_idx hidx);
|
||||
void del_forward_dep(unsigned hidx_user, unsigned hidx_provider);
|
||||
|
||||
expr mk_hypothesis(hypothesis_idx new_hidx, name const & n, expr const & type, optional<expr> const & value);
|
||||
|
||||
|
@ -159,6 +152,21 @@ class state {
|
|||
|
||||
expr mk_binding(bool is_lambda, unsigned num, expr const * hrefs, expr const & b) const;
|
||||
|
||||
/** \brief Compute the weight of a hypothesis with the given type
|
||||
We use this weight to update the todo_queue. */
|
||||
double compute_weight(hypothesis_idx hidx, expr const & type);
|
||||
|
||||
/** \brief This method is invoked when a hypothesis move from todo to active.
|
||||
We will update indices and data-structures (e.g., congruence closure). */
|
||||
void update_indices(hypothesis_idx hidx);
|
||||
|
||||
/** \brief Remove the given hypothesis from indexing data-structures */
|
||||
void remove_from_indices(hypothesis const & h, hypothesis_idx hidx);
|
||||
|
||||
void del_hypotheses(buffer<hypothesis_idx> const & to_delete, hypothesis_idx_set const & to_delete_set);
|
||||
void collect_forward_deps(hypothesis_idx hidx, buffer<hypothesis_idx> & result, hypothesis_idx_set & already_found);
|
||||
bool safe_to_delete(buffer<hypothesis_idx> const & to_delete);
|
||||
|
||||
#ifdef LEAN_DEBUG
|
||||
bool check_hypothesis(expr const & e, hypothesis_idx hidx, hypothesis const & h) const;
|
||||
bool check_hypothesis(hypothesis_idx hidx, hypothesis const & h) const;
|
||||
|
@ -191,12 +199,24 @@ public:
|
|||
/************************
|
||||
Hypotheses
|
||||
*************************/
|
||||
|
||||
expr mk_hypothesis(name const & n, expr const & type, expr const & value);
|
||||
expr mk_hypothesis(expr const & type, expr const & value);
|
||||
expr mk_hypothesis(name const & n, expr const & type);
|
||||
expr mk_hypothesis(expr const & type);
|
||||
|
||||
/** \brief Delete the given hypothesis and any other hypothesis that depends on it.
|
||||
The procedure is only performed if the target does not depend on the given hypothesis.
|
||||
Return true if success, and failure otherwise (target depends on hidx).
|
||||
|
||||
The hypothesese objects are not really deleted, we keep them at m_hyp_decls,
|
||||
but they are removed from all indexing data-structures.
|
||||
*/
|
||||
bool del_hypothesis(hypothesis_idx hidx);
|
||||
bool del_hypotheses(buffer<hypothesis_idx> const & hs);
|
||||
|
||||
/** \brief Collect all hypothesis in \c result that depend directly or indirectly on hidx */
|
||||
void collect_forward_deps(hypothesis_idx hidx, buffer<hypothesis_idx> & result);
|
||||
|
||||
/** \brief Return true iff the hypothesis with index \c hidx_user depends on the hypothesis with index
|
||||
\c hidx_provider. */
|
||||
bool hidx_depends_on(hypothesis_idx hidx_user, hypothesis_idx hidx_provider) const;
|
||||
|
@ -230,6 +250,9 @@ public:
|
|||
/** \brief Return (active) hypotheses whose head symbol is equal to target or it is the negation of */
|
||||
list<hypothesis_idx> get_head_related() const;
|
||||
|
||||
/** \brief Return the set of hypotheses that (directly) depend on the given one */
|
||||
hypothesis_idx_set get_forward_deps(hypothesis_idx hidx) const;
|
||||
|
||||
/************************
|
||||
Abstracting hypotheses
|
||||
*************************/
|
||||
|
|
Loading…
Reference in a new issue