feat(library/blast/forward/ematch): add option 'blast.ematch.max_instances'

This commit is contained in:
Leonardo de Moura 2015-12-29 20:36:11 -08:00
parent 0148bb08fd
commit 41a01bb606
3 changed files with 69 additions and 11 deletions

View file

@ -325,9 +325,7 @@ section add_group
by msimp
theorem neg.inj {a b : A} (H : -a = -b) : a = b :=
calc
a = -(-a) : by simp_nohyps
... = b : begin apply neg_eq_of_add_eq_zero, simp end
by msimp
theorem neg_eq_neg_iff_eq (a b : A) : -a = -b ↔ a = b :=
iff.intro (assume H, neg.inj H) (by simp)

View file

@ -6,6 +6,7 @@ Author: Leonardo de Moura
*/
#include <algorithm>
#include "util/interrupt.h"
#include "util/sexpr/option_declarations.h"
#include "library/constants.h"
#include "library/idx_metavar.h"
#include "library/head_map.h"
@ -17,22 +18,45 @@ Author: Leonardo de Moura
#include "library/blast/forward/forward_lemmas.h"
#include "library/blast/simplifier/simp_lemmas.h"
// TODO(Leo, Daniel): should we store all options at blast/options.cpp?
// Leo: I think we should only put the main options there, i.e.,
// the ones that are accessed/checked all the time. The config structure
// provides fast access to these options, and allows us to update them without
// using the expensive options object methods.
// Alternative design: each main module (forward/backward/simplifier/...) maintains
// its own config object.
#ifndef LEAN_DEFAULT_BLAST_EMATCH_MAX_INSTANCES
#define LEAN_DEFAULT_BLAST_EMATCH_MAX_INSTANCES 1000
#endif
namespace lean {
namespace blast {
#define lean_trace_ematch(Code) lean_trace(name({"blast", "ematch"}), Code)
static name * g_blast_ematch_max_instances = nullptr;
unsigned get_blast_ematch_max_instances(options const & o) {
return o.get_unsigned(*g_blast_ematch_max_instances, LEAN_DEFAULT_BLAST_EMATCH_MAX_INSTANCES);
}
typedef rb_tree<expr, expr_quick_cmp> expr_set;
/* Branch extension for supporting heuristic instantiations methods.
It contains
1- mapping functions to its applications.
2- set of lemmas that have been instantiated. */
struct instances_branch_extension : public branch_extension {
class instances_branch_extension : public branch_extension {
rb_map<head_index, expr_set, head_index::cmp> m_apps;
expr_set m_instances;
unsigned m_num_instances{0};
unsigned m_max_instances{0};
bool m_max_instances_exceeded{false};
public:
instances_branch_extension() {}
instances_branch_extension(instances_branch_extension const & src):
m_apps(src.m_apps), m_instances(src.m_instances) {}
m_apps(src.m_apps), m_instances(src.m_instances),
m_num_instances(src.m_num_instances), m_max_instances(src.m_max_instances),
m_max_instances_exceeded(src.m_max_instances_exceeded) {}
void collect_apps(expr const & e) {
switch (e.kind()) {
@ -68,6 +92,10 @@ struct instances_branch_extension : public branch_extension {
}}
}
virtual void initialized() override {
m_max_instances = get_blast_ematch_max_instances(ios().get_options());
}
virtual void hypothesis_activated(hypothesis const & h, hypothesis_idx) override {
collect_apps(h.get_type());
}
@ -75,6 +103,30 @@ struct instances_branch_extension : public branch_extension {
virtual void target_updated() override { collect_apps(curr_state().get_target()); }
virtual branch_extension * clone() override { return new instances_branch_extension(*this); }
bool max_instances_exceeded() const { return m_max_instances_exceeded; }
bool save_instance(expr const & i) {
if (m_num_instances >= m_max_instances) {
if (!m_max_instances_exceeded) {
lean_trace_event(tout() << "maximum number of ematching instances (" << m_max_instances << ") has been reached, "
<< "set option blast.ematch.max_instances to increase limit\n";);
}
m_max_instances_exceeded = true;
return false;
}
if (m_instances.contains(i)) {
return false;
} else {
m_num_instances++;
m_instances.insert(i);
return true;
}
}
rb_map<head_index, expr_set, head_index::cmp> const & get_apps() const {
return m_apps;
}
};
static unsigned g_inst_ext_id = 0;
@ -181,6 +233,11 @@ void initialize_ematch() {
g_ematch_ext_id = register_branch_extension(new ematch_branch_extension());
g_ematch_simp_ext_id = register_branch_extension(new ematch_simp_branch_extension());
register_trace_class(name{"blast", "ematch"});
g_blast_ematch_max_instances = new name{"blast", "ematch", "max_instances"};
register_unsigned_option(*g_blast_ematch_max_instances, LEAN_DEFAULT_BLAST_EMATCH_MAX_INSTANCES,
"(blast.ematch) max number of instances created by ematching based procedures");
}
void finalize_ematch() {}
@ -287,7 +344,7 @@ struct ematch_fn {
buffer<expr> p_args;
expr const & f = get_app_args(p, p_args);
buffer<state> new_states;
if (auto s = m_inst_ext.m_apps.find(head_index(f))) {
if (auto s = m_inst_ext.get_apps().find(head_index(f))) {
s->for_each([&](expr const & t) {
if (m_cc.is_congr_root(R, t)) {
state new_state = m_state;
@ -360,7 +417,7 @@ struct ematch_fn {
expr new_inst = normalize(m_ctx->instantiate_uvars_mvars(lemma.m_prop));
if (has_idx_metavar(new_inst))
return; // result contains temporary metavariables
if (m_inst_ext.m_instances.contains(new_inst))
if (!m_inst_ext.save_instance(new_inst))
return; // already added this instance
if (!m_new_instances) {
trace_action("ematch");
@ -368,7 +425,6 @@ struct ematch_fn {
lean_trace_ematch(tout() << "instance: " << ppb(new_inst) << "\n";);
m_new_instances = true;
expr new_proof = m_ctx->instantiate_uvars_mvars(lemma.m_proof);
m_inst_ext.m_instances.insert(new_inst);
curr_state().mk_hypothesis(new_inst, new_proof);
}
@ -393,7 +449,7 @@ struct ematch_fn {
expr const & f = get_app_args(p0, p0_args);
name const & R = is_prop(p0) ? get_iff_name() : get_eq_name();
unsigned gmt = m_cc.get_gmt();
if (auto s = m_inst_ext.m_apps.find(head_index(f))) {
if (auto s = m_inst_ext.get_apps().find(head_index(f))) {
s->for_each([&](expr const & t) {
if (m_cc.is_congr_root(R, t) && (!filter || m_cc.get_mt(R, t) == gmt)) {
m_ctx->clear();
@ -438,11 +494,14 @@ struct ematch_fn {
/* (Try to) instantiate lemmas in \c s. If \c filter is true, then use gmt optimization. */
void instantiate_lemmas(hi_lemma_set const & s, bool filter) {
s.for_each([&](hi_lemma const & l) {
instantiate_lemma(l, filter);
if (!m_inst_ext.max_instances_exceeded())
instantiate_lemma(l, filter);
});
}
action_result operator()() {
if (m_inst_ext.max_instances_exceeded())
return action_result::failed();
instantiate_lemmas(m_ext.m_new_lemmas, false);
instantiate_lemmas(m_ext.m_lemmas, true);
m_ext.m_lemmas.merge(m_ext.m_new_lemmas);

View file

@ -19,6 +19,7 @@ void trace_action(char const * a);
void trace_curr_state_if(action_result r);
#define lean_trace_action(Code) lean_trace(name({"blast", "action"}), Code)
#define lean_trace_event(Code) lean_trace(name({"blast", "event"}), Code)
#define lean_trace_search(Code) lean_trace(name({"blast", "search"}), Code)
#define lean_trace_deadend(Code) lean_trace(name({"blast", "deadend"}), Code)