feat(library/blast/blast): use defeq_simplifier to normalize

This commit is contained in:
Daniel Selsam 2016-02-26 21:10:13 -08:00 committed by Leonardo de Moura
parent 20e7ff39cc
commit c23528b5d8
14 changed files with 260 additions and 79 deletions

View file

@ -53,6 +53,8 @@ false.rec c H
notation a = b := eq a b notation a = b := eq a b
definition rfl {A : Type} {a : A} : a = a := eq.refl a definition rfl {A : Type} {a : A} : a = a := eq.refl a
definition id.def [defeq] {A : Type} (a : A) : id a = a := rfl
-- proof irrelevance is built in -- proof irrelevance is built in
theorem proof_irrel {a : Prop} (H₁ H₂ : a) : H₁ = H₂ := theorem proof_irrel {a : Prop} (H₁ H₂ : a) : H₁ = H₂ :=
rfl rfl
@ -142,6 +144,7 @@ rfl
/- ne -/ /- ne -/
definition ne [reducible] {A : Type} (a b : A) := ¬(a = b) definition ne [reducible] {A : Type} (a b : A) := ¬(a = b)
definition ne.def [defeq] {A : Type} (a b : A) : ne a b = ¬ (a = b) := rfl
notation a ≠ b := ne a b notation a ≠ b := ne a b
namespace ne namespace ne

View file

@ -574,8 +574,8 @@ static environment defeq_simplify_cmd(parser & p) {
std::tie(e, ls) = parse_local_expr(p); std::tie(e, ls) = parse_local_expr(p);
auto tc = mk_type_checker(p.env()); auto tc = mk_type_checker(p.env());
default_tmp_type_context_pool pool(p.env(), p.get_options());
expr e_simp = defeq_simplify(env, p.get_options(), sls, e); expr e_simp = defeq_simplify(pool, p.get_options(), sls, e);
if (!tc->is_def_eq(e, e_simp).first) { if (!tc->is_def_eq(e, e_simp).first) {
throw parser_error("defeq_simplify result not definitionally equal to input expression", pos); throw parser_error("defeq_simplify result not definitionally equal to input expression", pos);
} }

View file

@ -10,9 +10,13 @@ Author: Leonardo de Moura
#include "kernel/for_each_fn.h" #include "kernel/for_each_fn.h"
#include "kernel/find_fn.h" #include "kernel/find_fn.h"
#include "kernel/replace_fn.h" #include "kernel/replace_fn.h"
#include "kernel/instantiate.h"
#include "kernel/abstract.h"
#include "kernel/type_checker.h" #include "kernel/type_checker.h"
#include "library/replace_visitor.h" #include "library/replace_visitor.h"
#include "library/util.h" #include "library/util.h"
#include "library/defeq_simp_lemmas.h"
#include "library/defeq_simplifier.h"
#include "library/trace.h" #include "library/trace.h"
#include "library/reducible.h" #include "library/reducible.h"
#include "library/class.h" #include "library/class.h"
@ -21,6 +25,7 @@ Author: Leonardo de Moura
#include "library/relation_manager.h" #include "library/relation_manager.h"
#include "library/congr_lemma_manager.h" #include "library/congr_lemma_manager.h"
#include "library/abstract_expr_manager.h" #include "library/abstract_expr_manager.h"
#include "library/proof_irrel_expr_manager.h"
#include "library/light_lt_manager.h" #include "library/light_lt_manager.h"
#include "library/projection.h" #include "library/projection.h"
#include "library/scoped_ext.h" #include "library/scoped_ext.h"
@ -67,6 +72,15 @@ struct imp_extension_entry {
m_ext_state(ext_state), m_ext_id(ext_id), m_ext_of_ext_state(ext_of_ext_state) {} m_ext_state(ext_state), m_ext_id(ext_id), m_ext_of_ext_state(ext_of_ext_state) {}
}; };
unsigned proof_irrel_hash(expr const & e);
bool proof_irrel_is_equal(expr const & e1, expr const & e2);
class tmp_tctx_pool : public tmp_type_context_pool {
public:
virtual tmp_type_context * mk_tmp_type_context() override;
virtual void recycle_tmp_type_context(tmp_type_context * tmp_tctx) override;
};
class blastenv { class blastenv {
friend class scope_assignment; friend class scope_assignment;
friend class scope_unfold_macro_pred; friend class scope_unfold_macro_pred;
@ -103,6 +117,7 @@ class blastenv {
fun_info_manager m_fun_info_manager; fun_info_manager m_fun_info_manager;
congr_lemma_manager m_congr_lemma_manager; congr_lemma_manager m_congr_lemma_manager;
abstract_expr_manager m_abstract_expr_manager; abstract_expr_manager m_abstract_expr_manager;
proof_irrel_expr_manager m_proof_irrel_expr_manager;
light_lt_manager m_light_lt_manager; light_lt_manager m_light_lt_manager;
imp_extension_entries m_imp_extension_entries; imp_extension_entries m_imp_extension_entries;
relation_info_getter m_rel_getter; relation_info_getter m_rel_getter;
@ -517,8 +532,34 @@ class blastenv {
} }
tctx m_tctx; tctx m_tctx;
/* Normalizing instances */
normalizer m_normalizer; normalizer m_normalizer;
expr_map<expr> m_norm_cache; // normalization cache
struct inst_key {
expr m_e;
unsigned m_hash;
inst_key(expr const & e):
m_e(e), m_hash(blast::proof_irrel_hash(e)) { }
};
struct inst_key_hash_fn {
unsigned operator()(inst_key const & k) const { return k.m_hash; }
};
struct inst_key_eq_fn {
bool operator()(inst_key const & k1, inst_key const & k2) const {
return blast::proof_irrel_is_equal(k1.m_e, k2.m_e);
}
};
typedef std::unordered_map<inst_key, expr, inst_key_hash_fn, inst_key_eq_fn> inst_cache;
inst_cache m_inst_nf_to_cf;
expr_map<expr> m_inst_to_nf;
expr_map<expr> m_norm_cache; // normalization cache
void save_initial_context() { void save_initial_context() {
hypothesis_idx_buffer hidxs; hypothesis_idx_buffer hidxs;
@ -528,6 +569,8 @@ class blastenv {
ctx.push_back(mk_href(hidx)); ctx.push_back(mk_href(hidx));
} }
m_initial_context = to_list(ctx); m_initial_context = to_list(ctx);
for (auto ctx : m_tmp_ctx_pool) delete ctx;
m_tmp_ctx_pool.clear();
} }
name_map<level> mk_uref2uvar() const { name_map<level> mk_uref2uvar() const {
@ -636,6 +679,7 @@ public:
m_fun_info_manager(*m_tmp_ctx), m_fun_info_manager(*m_tmp_ctx),
m_congr_lemma_manager(m_app_builder, m_fun_info_manager), m_congr_lemma_manager(m_app_builder, m_fun_info_manager),
m_abstract_expr_manager(m_congr_lemma_manager), m_abstract_expr_manager(m_congr_lemma_manager),
m_proof_irrel_expr_manager(m_fun_info_manager),
m_light_lt_manager(env), m_light_lt_manager(env),
m_rel_getter(mk_relation_info_getter(env)), m_rel_getter(mk_relation_info_getter(env)),
m_refl_getter(mk_refl_info_getter(env)), m_refl_getter(mk_refl_info_getter(env)),
@ -709,6 +753,10 @@ public:
return m_projection_info.find(n); return m_projection_info.find(n);
} }
unfold_macro_pred get_unfold_macro_pred() const {
return m_unfold_macro_pred;
}
expr mk_fresh_local(expr const & type, binder_info const & bi) { expr mk_fresh_local(expr const & type, binder_info const & bi) {
return m_tctx.mk_tmp_local(type, bi); return m_tctx.mk_tmp_local(type, bi);
} }
@ -793,6 +841,10 @@ public:
return m_abstract_expr_manager.hash(e); return m_abstract_expr_manager.hash(e);
} }
unsigned proof_irrel_hash(expr const & e) {
return m_proof_irrel_expr_manager.hash(e);
}
void init_imp_extension_entries() { void init_imp_extension_entries() {
for (auto & p : get_imp_extension_manager().get_entries()) { for (auto & p : get_imp_extension_manager().get_entries()) {
branch_extension & b_ext = curr_state().get_extension(p.second); branch_extension & b_ext = curr_state().get_extension(p.second);
@ -849,6 +901,10 @@ public:
return m_abstract_expr_manager.is_equal(e1, e2); return m_abstract_expr_manager.is_equal(e1, e2);
} }
bool proof_irrel_is_equal(expr const & e1, expr const & e2) {
return m_proof_irrel_expr_manager.is_equal(e1, e2);
}
bool is_light_lt(expr const & e1, expr const & e2) { bool is_light_lt(expr const & e1, expr const & e2) {
return m_light_lt_manager.is_lt(e1, e2); return m_light_lt_manager.is_lt(e1, e2);
} }
@ -870,11 +926,74 @@ public:
return m_tctx; return m_tctx;
} }
expr normalize_instance(expr const & inst) {
auto it1 = m_inst_to_nf.find(inst);
expr inst_nf;
if (it1 != m_inst_to_nf.end()) {
inst_nf = it1->second;
} else {
inst_nf = m_normalizer(inst);
m_inst_to_nf.insert(mk_pair(inst, inst_nf));
}
auto it2 = m_inst_nf_to_cf.find(inst_nf);
expr inst_cf;
if (it2 != m_inst_nf_to_cf.end()) {
inst_cf = it2->second;
} else {
inst_cf = inst;
m_inst_nf_to_cf.insert(mk_pair(inst_nf, inst_cf));
}
lean_trace(name({"debug", "blast", "inst_cache"}),
tout() << "\n" << inst << "\n==>\n" << inst_nf << "\n==>\n" << inst_cf << "\n";);
return inst_cf;
}
expr normalize_instances(expr const & e) {
expr b, l, d;
switch (e.kind()) {
case expr_kind::Constant:
case expr_kind::Local:
case expr_kind::Meta:
case expr_kind::Sort:
case expr_kind::Var:
case expr_kind::Macro:
return e;
case expr_kind::Lambda:
case expr_kind::Pi:
d = normalize_instances(binding_domain(e));
l = mk_fresh_local(d, binding_info(e));
b = abstract(normalize_instances(instantiate(binding_body(e), l)), l);
return update_binding(e, d, b);
case expr_kind::App:
buffer<expr> args;
expr const & f = get_app_args(e, args);
unsigned prefix_sz = get_specialization_prefix_size(f, args.size());
expr new_f = e;
unsigned rest_sz = args.size() - prefix_sz;
for (unsigned i = 0; i < rest_sz; i++)
new_f = app_fn(new_f);
fun_info info = get_fun_info(new_f, rest_sz);
lean_assert(length(info.get_params_info()) == rest_sz);
unsigned i = prefix_sz;
for_each(info.get_params_info(), [&](param_info const & p_info) {
if (p_info.is_inst_implicit()) {
args[i] = normalize_instance(args[i]);
} else {
args[i] = normalize_instances(args[i]);
}
i++;
});
return mk_app(f, args);
}
lean_unreachable();
}
expr normalize(expr const & e) { expr normalize(expr const & e) {
auto it = m_norm_cache.find(e); auto it = m_norm_cache.find(e);
if (it != m_norm_cache.end()) if (it != m_norm_cache.end()) return it->second;
return it->second; tmp_tctx_pool pool;
expr r = m_normalizer(e); expr r = normalize_instances(defeq_simplify(pool, m_ios.get_options(), get_defeq_simp_lemmas(m_env), e));
m_norm_cache.insert(mk_pair(e, r)); m_norm_cache.insert(mk_pair(e, r));
return r; return r;
} }
@ -1114,6 +1233,11 @@ optional<expr> mk_subsingleton_instance(expr const & type) {
return g_blastenv->mk_subsingleton_instance(type); return g_blastenv->mk_subsingleton_instance(type);
} }
unfold_macro_pred get_unfold_macro_pred() {
lean_assert(g_blastenv);
return g_blastenv->get_unfold_macro_pred();
}
expr mk_fresh_local(expr const & type, binder_info const & bi) { expr mk_fresh_local(expr const & type, binder_info const & bi) {
lean_assert(g_blastenv); lean_assert(g_blastenv);
return g_blastenv->mk_fresh_local(type, bi); return g_blastenv->mk_fresh_local(type, bi);
@ -1194,6 +1318,11 @@ unsigned abstract_hash(expr const & e) {
return g_blastenv->abstract_hash(e); return g_blastenv->abstract_hash(e);
} }
unsigned proof_irrel_hash(expr const & e) {
lean_assert(g_blastenv);
return g_blastenv->proof_irrel_hash(e);
}
unsigned register_imp_extension(std::function<imp_extension_state*()> & ext_state_maker) { unsigned register_imp_extension(std::function<imp_extension_state*()> & ext_state_maker) {
return get_imp_extension_manager().register_imp_extension(ext_state_maker); return get_imp_extension_manager().register_imp_extension(ext_state_maker);
} }
@ -1208,6 +1337,11 @@ bool abstract_is_equal(expr const & e1, expr const & e2) {
return g_blastenv->abstract_is_equal(e1, e2); return g_blastenv->abstract_is_equal(e1, e2);
} }
bool proof_irrel_is_equal(expr const & e1, expr const & e2) {
lean_assert(g_blastenv);
return g_blastenv->proof_irrel_is_equal(e1, e2);
}
bool is_light_lt(expr const & e1, expr const & e2) { bool is_light_lt(expr const & e1, expr const & e2) {
lean_assert(g_blastenv); lean_assert(g_blastenv);
return g_blastenv->is_light_lt(e1, e2); return g_blastenv->is_light_lt(e1, e2);
@ -1313,6 +1447,10 @@ public:
tmp_tctx(environment const & env, options const & o): tmp_tctx(environment const & env, options const & o):
tmp_type_context(env, o) {} tmp_type_context(env, o) {}
virtual bool should_unfold_macro(expr const & e) const override {
return get_unfold_macro_pred()(e);
}
/** \brief Return the type of a local constant (local or not). /** \brief Return the type of a local constant (local or not).
\remark This method allows the customer to store the type of local constants \remark This method allows the customer to store the type of local constants
in a different place. */ in a different place. */
@ -1358,6 +1496,16 @@ tmp_type_context * blastenv::mk_tmp_type_context() {
return r; return r;
} }
tmp_type_context * tmp_tctx_pool::mk_tmp_type_context() {
lean_assert(g_blastenv);
return g_blastenv->mk_tmp_type_context();
}
void tmp_tctx_pool::recycle_tmp_type_context(tmp_type_context * tmp_tctx) {
lean_assert(g_blastenv);
g_blastenv->recycle_tmp_type_context(tmp_tctx);
}
blast_tmp_type_context::blast_tmp_type_context(unsigned num_umeta, unsigned num_emeta) { blast_tmp_type_context::blast_tmp_type_context(unsigned num_umeta, unsigned num_emeta) {
lean_assert(g_blastenv); lean_assert(g_blastenv);
m_ctx = g_blastenv->mk_tmp_type_context(); m_ctx = g_blastenv->mk_tmp_type_context();
@ -1400,6 +1548,7 @@ void initialize_blast() {
register_trace_class(name{"blast", "search"}); register_trace_class(name{"blast", "search"});
register_trace_class(name{"blast", "deadend"}); register_trace_class(name{"blast", "deadend"});
register_trace_class(name{"debug", "blast"}); register_trace_class(name{"debug", "blast"});
register_trace_class(name{"debug", "blast", "inst_cache"});
register_trace_class_alias("app_builder", name({"blast", "event"})); register_trace_class_alias("app_builder", name({"blast", "event"}));
register_trace_class_alias(name({"simplifier", "failure"}), name({"blast", "event"})); register_trace_class_alias(name({"simplifier", "failure"}), name({"blast", "event"}));

View file

@ -168,10 +168,14 @@ fun_info get_specialized_fun_info(expr const & a);
/** \brief Return the given function specialization prefix size. */ /** \brief Return the given function specialization prefix size. */
unsigned get_specialization_prefix_size(expr const & fn, unsigned nargs); unsigned get_specialization_prefix_size(expr const & fn, unsigned nargs);
/** \brief Hash and equality test for abstract expressions */ /** \brief Hash and equality test that ignore subsingleton arguments */
unsigned abstract_hash(expr const & e); unsigned abstract_hash(expr const & e);
bool abstract_is_equal(expr const & e1, expr const & e2); bool abstract_is_equal(expr const & e1, expr const & e2);
/** \brief Hash and equality test that ignore arguments that are proofs */
unsigned proof_irrel_hash(expr const & e);
bool proof_irrel_is_equal(expr const & e1, expr const & e2);
/** \brief Order on expressions that supports the "light" annotation */ /** \brief Order on expressions that supports the "light" annotation */
bool is_light_lt(expr const & e1, expr const & e2); bool is_light_lt(expr const & e1, expr const & e2);

View file

@ -129,10 +129,11 @@ defeq_simp_lemmas get_defeq_simp_lemmas(environment const & env) {
} }
defeq_simp_lemmas get_defeq_simp_lemmas(environment const & env, name const & ns) { defeq_simp_lemmas get_defeq_simp_lemmas(environment const & env, name const & ns) {
list<defeq_simp_lemmas_entry> const * entries = defeq_simp_lemmas_ext::get_entries(env, ns); list<defeq_simp_lemmas_entry> const * _entries = defeq_simp_lemmas_ext::get_entries(env, ns);
defeq_simp_lemmas_state s; defeq_simp_lemmas_state s;
if (entries) { if (_entries) {
for (auto const & e : *entries) { list<defeq_simp_lemmas_entry> entries = reverse(*_entries);
for (auto const & e : entries) {
tmp_type_context tctx(env, get_dummy_ios().get_options()); tmp_type_context tctx(env, get_dummy_ios().get_options());
s.register_defeq_simp_lemma(tctx, e.m_decl_name, e.m_priority); s.register_defeq_simp_lemma(tctx, e.m_decl_name, e.m_priority);
} }

View file

@ -15,10 +15,10 @@ Author: Daniel Selsam
#include "library/normalize.h" #include "library/normalize.h"
#ifndef LEAN_DEFAULT_DEFEQ_SIMPLIFY_MAX_SIMP_ROUNDS #ifndef LEAN_DEFAULT_DEFEQ_SIMPLIFY_MAX_SIMP_ROUNDS
#define LEAN_DEFAULT_DEFEQ_SIMPLIFY_MAX_SIMP_ROUNDS 1000 #define LEAN_DEFAULT_DEFEQ_SIMPLIFY_MAX_SIMP_ROUNDS 5000
#endif #endif
#ifndef LEAN_DEFAULT_DEFEQ_SIMPLIFY_MAX_REWRITE_ROUNDS #ifndef LEAN_DEFAULT_DEFEQ_SIMPLIFY_MAX_REWRITE_ROUNDS
#define LEAN_DEFAULT_DEFEQ_SIMPLIFY_MAX_REWRITE_ROUNDS 1000 #define LEAN_DEFAULT_DEFEQ_SIMPLIFY_MAX_REWRITE_ROUNDS 5000
#endif #endif
#ifndef LEAN_DEFAULT_DEFEQ_SIMPLIFY_TOP_DOWN #ifndef LEAN_DEFAULT_DEFEQ_SIMPLIFY_TOP_DOWN
#define LEAN_DEFAULT_DEFEQ_SIMPLIFY_TOP_DOWN false #define LEAN_DEFAULT_DEFEQ_SIMPLIFY_TOP_DOWN false
@ -29,9 +29,6 @@ Author: Daniel Selsam
#ifndef LEAN_DEFAULT_DEFEQ_SIMPLIFY_MEMOIZE #ifndef LEAN_DEFAULT_DEFEQ_SIMPLIFY_MEMOIZE
#define LEAN_DEFAULT_DEFEQ_SIMPLIFY_MEMOIZE true #define LEAN_DEFAULT_DEFEQ_SIMPLIFY_MEMOIZE true
#endif #endif
#ifndef LEAN_DEFAULT_DEFEQ_SIMPLIFY_EXPAND_MACROS
#define LEAN_DEFAULT_DEFEQ_SIMPLIFY_EXPAND_MACROS false
#endif
namespace lean { namespace lean {
@ -42,7 +39,6 @@ static name * g_simplify_max_rewrite_rounds = nullptr;
static name * g_simplify_top_down = nullptr; static name * g_simplify_top_down = nullptr;
static name * g_simplify_exhaustive = nullptr; static name * g_simplify_exhaustive = nullptr;
static name * g_simplify_memoize = nullptr; static name * g_simplify_memoize = nullptr;
static name * g_simplify_expand_macros = nullptr;
static unsigned get_simplify_max_simp_rounds(options const & o) { static unsigned get_simplify_max_simp_rounds(options const & o) {
return o.get_unsigned(*g_simplify_max_simp_rounds, LEAN_DEFAULT_DEFEQ_SIMPLIFY_MAX_SIMP_ROUNDS); return o.get_unsigned(*g_simplify_max_simp_rounds, LEAN_DEFAULT_DEFEQ_SIMPLIFY_MAX_SIMP_ROUNDS);
@ -64,29 +60,23 @@ static bool get_simplify_memoize(options const & o) {
return o.get_bool(*g_simplify_memoize, LEAN_DEFAULT_DEFEQ_SIMPLIFY_MEMOIZE); return o.get_bool(*g_simplify_memoize, LEAN_DEFAULT_DEFEQ_SIMPLIFY_MEMOIZE);
} }
static bool get_simplify_expand_macros(options const & o) {
return o.get_bool(*g_simplify_expand_macros, LEAN_DEFAULT_DEFEQ_SIMPLIFY_EXPAND_MACROS);
}
/* Main simplifier class */ /* Main simplifier class */
class defeq_simplify_fn { class defeq_simplify_fn {
tmp_type_context m_tmp_tctx; tmp_type_context_pool & m_tmp_tctx_pool;
normalizer m_normalizer; tmp_type_context * m_tmp_tctx;
defeq_simp_lemmas m_simp_lemmas; defeq_simp_lemmas m_simp_lemmas;
unsigned m_num_simp_rounds{0}; unsigned m_num_simp_rounds{0};
unsigned m_num_rewrite_rounds{0}; unsigned m_num_rewrite_rounds{0};
options const & m_options;
/* Options */ /* Options */
unsigned m_max_simp_rounds; unsigned m_max_simp_rounds;
unsigned m_max_rewrite_rounds; unsigned m_max_rewrite_rounds;
bool m_top_down; bool m_top_down;
bool m_exhaustive; bool m_exhaustive;
bool m_memoize; bool m_memoize;
bool m_expand_macros;
/* Cache */ /* Cache */
expr_struct_map<expr> m_cache; expr_struct_map<expr> m_cache;
@ -131,9 +121,7 @@ class defeq_simplify_fn {
case expr_kind::Var: case expr_kind::Var:
lean_unreachable(); lean_unreachable();
case expr_kind::Macro: case expr_kind::Macro:
if (m_expand_macros) { e = defeq_simplify_macro(e);
if (auto m = m_tmp_tctx.expand_macro(e)) e = defeq_simplify(whnf_eta(*m));
}
break; break;
case expr_kind::Lambda: case expr_kind::Lambda:
e = try_eta(defeq_simplify_binding(e)); e = try_eta(defeq_simplify_binding(e));
@ -152,12 +140,20 @@ class defeq_simplify_fn {
if (!m_exhaustive || e == e_start) break; if (!m_exhaustive || e == e_start) break;
} }
if (m_memoize) cache_save(_e, e); if (m_memoize) cache_save(_e, e);
lean_assert(m_tmp_tctx->is_def_eq(_e, e));
return e; return e;
} }
expr defeq_simplify_macro(expr const & e) {
buffer<expr> new_args;
for (unsigned i = 0; i < macro_num_args(e); i++)
new_args.push_back(defeq_simplify(macro_arg(e, i)));
return update_macro(e, new_args.size(), new_args.data());
}
expr defeq_simplify_binding(expr const & e) { expr defeq_simplify_binding(expr const & e) {
expr d = defeq_simplify(binding_domain(e)); expr d = defeq_simplify(binding_domain(e));
expr l = m_tmp_tctx.mk_tmp_local(binding_name(e), d, binding_info(e)); expr l = m_tmp_tctx->mk_tmp_local(binding_name(e), d, binding_info(e));
expr b = abstract(defeq_simplify(instantiate(binding_body(e), l)), l); expr b = abstract(defeq_simplify(instantiate(binding_body(e), l)), l);
return update_binding(e, d, b); return update_binding(e, d, b);
} }
@ -168,7 +164,7 @@ class defeq_simplify_fn {
expr f = get_app_rev_args(e, args); expr f = get_app_rev_args(e, args);
for (expr & a : args) { for (expr & a : args) {
expr new_a = a; expr new_a = a;
if (!m_tmp_tctx.is_prop(m_tmp_tctx.infer(a))) if (!m_tmp_tctx->is_prop(m_tmp_tctx->infer(a)))
new_a = defeq_simplify(a); new_a = defeq_simplify(a);
if (new_a != a) if (new_a != a)
modified = true; modified = true;
@ -176,15 +172,18 @@ class defeq_simplify_fn {
} }
if (is_constant(f)) { if (is_constant(f)) {
if (auto idx = inductive::get_elim_major_idx(m_tmp_tctx.env(), const_name(f))) { if (auto idx = inductive::get_elim_major_idx(m_tmp_tctx->env(), const_name(f))) {
if (auto r = m_normalizer.unfold_recursor_major(f, *idx, args)) if (auto r = normalizer(*m_tmp_tctx).unfold_recursor_major(f, *idx, args))
return *r; return *r;
} }
} }
if (!modified) if (!modified)
return e; return e;
expr r = mk_rev_app(f, args); expr r = mk_rev_app(f, args);
if (is_constant(f) && m_tmp_tctx.env().is_recursor(const_name(f))) {
if (is_constant(f) && m_tmp_tctx->env().is_recursor(const_name(f))) {
return defeq_simplify(r); return defeq_simplify(r);
} else { } else {
return r; return r;
@ -214,31 +213,32 @@ class defeq_simplify_fn {
} }
expr rewrite(expr const & e, defeq_simp_lemma const & sl) { expr rewrite(expr const & e, defeq_simp_lemma const & sl) {
tmp_type_context tmp_tctx(m_tmp_tctx.env(), m_options); tmp_type_context * tmp_tctx = m_tmp_tctx_pool.mk_tmp_type_context();
tmp_tctx.clear(); tmp_tctx->clear();
tmp_tctx.set_next_uvar_idx(sl.get_num_umeta()); tmp_tctx->set_next_uvar_idx(sl.get_num_umeta());
tmp_tctx.set_next_mvar_idx(sl.get_num_emeta()); tmp_tctx->set_next_mvar_idx(sl.get_num_emeta());
if (!tmp_tctx.is_def_eq(e, sl.get_lhs())) return e; if (!tmp_tctx->is_def_eq(e, sl.get_lhs())) return e;
lean_trace(name({"defeq_simplifier", "rewrite"}), lean_trace(name({"defeq_simplifier", "rewrite"}),
expr new_lhs = tmp_tctx.instantiate_uvars_mvars(sl.get_lhs()); expr new_lhs = tmp_tctx->instantiate_uvars_mvars(sl.get_lhs());
expr new_rhs = tmp_tctx.instantiate_uvars_mvars(sl.get_rhs()); expr new_rhs = tmp_tctx->instantiate_uvars_mvars(sl.get_rhs());
tout() << "(" << sl.get_id() << ") " tout() << "(" << sl.get_id() << ") "
<< "[" << new_lhs << " --> " << new_rhs << "]\n";); << "[" << new_lhs << " --> " << new_rhs << "]\n";);
if (!instantiate_emetas(tmp_tctx, sl.get_emetas(), sl.get_instances())) return e; if (!instantiate_emetas(tmp_tctx, sl.get_emetas(), sl.get_instances())) return e;
for (unsigned i = 0; i < sl.get_num_umeta(); i++) { for (unsigned i = 0; i < sl.get_num_umeta(); i++) {
if (!tmp_tctx.is_uvar_assigned(i)) return e; if (!tmp_tctx->is_uvar_assigned(i)) return e;
} }
expr new_rhs = tmp_tctx.instantiate_uvars_mvars(sl.get_rhs()); expr new_rhs = tmp_tctx->instantiate_uvars_mvars(sl.get_rhs());
m_tmp_tctx_pool.recycle_tmp_type_context(tmp_tctx);
return new_rhs; return new_rhs;
} }
bool instantiate_emetas(tmp_type_context & tmp_tctx, list<expr> const & _emetas, list<bool> const & _instances) { bool instantiate_emetas(tmp_type_context * tmp_tctx, list<expr> const & _emetas, list<bool> const & _instances) {
buffer<expr> emetas; buffer<expr> emetas;
buffer<bool> instances; buffer<bool> instances;
to_buffer(_emetas, emetas); to_buffer(_emetas, emetas);
@ -248,17 +248,17 @@ class defeq_simplify_fn {
for (unsigned i = 0; i < emetas.size(); ++i) { for (unsigned i = 0; i < emetas.size(); ++i) {
expr m = emetas[i]; expr m = emetas[i];
unsigned mvar_idx = emetas.size() - 1 - i; unsigned mvar_idx = emetas.size() - 1 - i;
expr m_type = tmp_tctx.instantiate_uvars_mvars(tmp_tctx.infer(m)); expr m_type = tmp_tctx->instantiate_uvars_mvars(tmp_tctx->infer(m));
lean_assert(!has_metavar(m_type)); lean_assert(!has_metavar(m_type));
if (tmp_tctx.is_mvar_assigned(mvar_idx)) continue; if (tmp_tctx->is_mvar_assigned(mvar_idx)) continue;
if (instances[i]) { if (instances[i]) {
if (auto v = tmp_tctx.mk_class_instance(m_type)) { if (auto v = tmp_tctx->mk_class_instance(m_type)) {
if (!tmp_tctx.assign(m, *v)) { if (!tmp_tctx->assign(m, *v)) {
lean_trace(name({"defeq_simplifier", "failure"}), lean_trace(name({"defeq_simplifier", "failure"}),
tout() << "unable to assign instance for: " << m_type << "\n";); tout() << "unable to assign instance for: " << m_type << "\n";);
return false; return false;
} else { } else {
lean_assert(tmp_tctx.is_mvar_assigned(mvar_idx)); lean_assert(tmp_tctx->is_mvar_assigned(mvar_idx));
continue; continue;
} }
} else { } else {
@ -276,22 +276,24 @@ class defeq_simplify_fn {
} }
expr whnf_eta(expr const & e) { expr whnf_eta(expr const & e) {
return try_eta(m_tmp_tctx.whnf(e)); return try_eta(m_tmp_tctx->whnf(e));
} }
public: public:
defeq_simplify_fn(environment const & env, options const & o, defeq_simp_lemmas const & simp_lemmas): defeq_simplify_fn(tmp_type_context_pool & tmp_tctx_pool, options const & o, defeq_simp_lemmas const & simp_lemmas):
m_tmp_tctx(env, o), m_tmp_tctx_pool(tmp_tctx_pool),
m_normalizer(m_tmp_tctx), m_tmp_tctx(m_tmp_tctx_pool.mk_tmp_type_context()),
m_simp_lemmas(simp_lemmas), m_simp_lemmas(simp_lemmas),
m_options(o),
m_max_simp_rounds(get_simplify_max_simp_rounds(o)), m_max_simp_rounds(get_simplify_max_simp_rounds(o)),
m_max_rewrite_rounds(get_simplify_max_rewrite_rounds(o)), m_max_rewrite_rounds(get_simplify_max_rewrite_rounds(o)),
m_top_down(get_simplify_top_down(o)), m_top_down(get_simplify_top_down(o)),
m_exhaustive(get_simplify_exhaustive(o)), m_exhaustive(get_simplify_exhaustive(o)),
m_memoize(get_simplify_memoize(o)), m_memoize(get_simplify_memoize(o))
m_expand_macros(get_simplify_expand_macros(o)) {} { }
~defeq_simplify_fn() {
m_tmp_tctx_pool.recycle_tmp_type_context(m_tmp_tctx);
}
expr operator()(expr const & e) { return defeq_simplify(e); } expr operator()(expr const & e) { return defeq_simplify(e); }
}; };
@ -307,7 +309,6 @@ void initialize_defeq_simplifier() {
g_simplify_top_down = new name{"defeq_simplify", "top_down"}; g_simplify_top_down = new name{"defeq_simplify", "top_down"};
g_simplify_exhaustive = new name{"defeq_simplify", "exhaustive"}; g_simplify_exhaustive = new name{"defeq_simplify", "exhaustive"};
g_simplify_memoize = new name{"defeq_simplify", "memoize"}; g_simplify_memoize = new name{"defeq_simplify", "memoize"};
g_simplify_expand_macros = new name{"defeq_simplify", "expand_macros"};
register_unsigned_option(*g_simplify_max_simp_rounds, LEAN_DEFAULT_DEFEQ_SIMPLIFY_MAX_SIMP_ROUNDS, register_unsigned_option(*g_simplify_max_simp_rounds, LEAN_DEFAULT_DEFEQ_SIMPLIFY_MAX_SIMP_ROUNDS,
"(defeq_simplify) max allowed simplification rounds"); "(defeq_simplify) max allowed simplification rounds");
@ -319,12 +320,9 @@ void initialize_defeq_simplifier() {
"(defeq_simplify) simplify exhaustively"); "(defeq_simplify) simplify exhaustively");
register_bool_option(*g_simplify_memoize, LEAN_DEFAULT_DEFEQ_SIMPLIFY_MEMOIZE, register_bool_option(*g_simplify_memoize, LEAN_DEFAULT_DEFEQ_SIMPLIFY_MEMOIZE,
"(defeq_simplify) memoize simplifications"); "(defeq_simplify) memoize simplifications");
register_bool_option(*g_simplify_expand_macros, LEAN_DEFAULT_DEFEQ_SIMPLIFY_EXPAND_MACROS,
"(defeq_simplify) expand macros");
} }
void finalize_defeq_simplifier() { void finalize_defeq_simplifier() {
delete g_simplify_expand_macros;
delete g_simplify_memoize; delete g_simplify_memoize;
delete g_simplify_exhaustive; delete g_simplify_exhaustive;
delete g_simplify_top_down; delete g_simplify_top_down;
@ -333,9 +331,8 @@ void finalize_defeq_simplifier() {
} }
/* Entry point */ /* Entry point */
expr defeq_simplify(environment const & env, options const & o, defeq_simp_lemmas const & simp_lemmas, expr const & e) { expr defeq_simplify(tmp_type_context_pool & tmp_tctx_pool, options const & o, defeq_simp_lemmas const & simp_lemmas, expr const & e) {
return defeq_simplify_fn(env, o, simp_lemmas)(e); return defeq_simplify_fn(tmp_tctx_pool, o, simp_lemmas)(e);
} }
} }

View file

@ -5,11 +5,12 @@ Author: Daniel Selsam
*/ */
#pragma once #pragma once
#include "kernel/expr.h" #include "kernel/expr.h"
#include "library/tmp_type_context.h"
#include "library/defeq_simp_lemmas.h" #include "library/defeq_simp_lemmas.h"
namespace lean { namespace lean {
expr defeq_simplify(environment const & env, options const & o, defeq_simp_lemmas const & simp_lemmas, expr const & e); expr defeq_simplify(tmp_type_context_pool & tmp_tctx_pool, options const & o, defeq_simp_lemmas const & simp_lemmas, expr const & e);
void initialize_defeq_simplifier(); void initialize_defeq_simplifier();
void finalize_defeq_simplifier(); void finalize_defeq_simplifier();

View file

@ -90,4 +90,24 @@ public:
return static_cast<bool>(m_eassignment[idx]); return static_cast<bool>(m_eassignment[idx]);
} }
}; };
class tmp_type_context_pool {
public:
virtual tmp_type_context * mk_tmp_type_context() =0;
virtual void recycle_tmp_type_context(tmp_type_context * tmp_tctx) =0;
virtual ~tmp_type_context_pool() {}
};
class default_tmp_type_context_pool : public tmp_type_context_pool {
environment m_env;
options m_options;
public:
default_tmp_type_context_pool(environment const & env, options const & o):
m_env(env), m_options(o) {}
virtual tmp_type_context * mk_tmp_type_context() override { return new tmp_type_context(m_env, m_options); }
virtual void recycle_tmp_type_context(tmp_type_context * tmp_tctx) override { delete tmp_tctx; }
};
} }

View file

@ -170,7 +170,7 @@ optional<declaration> type_context::is_transparent(name const & n) {
optional<expr> type_context::expand_macro(expr const & m) { optional<expr> type_context::expand_macro(expr const & m) {
lean_assert(is_macro(m)); lean_assert(is_macro(m));
if (should_unfold_macro(m)) if (m_in_is_def_eq || should_unfold_macro(m))
return macro_def(m).expand(m, *m_ext_ctx); return macro_def(m).expand(m, *m_ext_ctx);
else else
return none_expr(); return none_expr();
@ -1064,6 +1064,7 @@ bool type_context::process_postponed(unsigned old_sz) {
bool type_context::is_def_eq(expr const & e1, expr const & e2) { bool type_context::is_def_eq(expr const & e1, expr const & e2) {
scope s(*this); scope s(*this);
flet<bool> in_is_def_eq(m_in_is_def_eq, true);
unsigned psz = m_postponed.size(); unsigned psz = m_postponed.size();
if (!is_def_eq_core(e1, e2)) { if (!is_def_eq_core(e1, e2)) {
return false; return false;

View file

@ -116,6 +116,7 @@ class type_context : public abstract_type_context {
// postponed universe constraints // postponed universe constraints
std::vector<pair<level, level>> m_postponed; std::vector<pair<level, level>> m_postponed;
name_map<projection_info> m_proj_info; name_map<projection_info> m_proj_info;
bool m_in_is_def_eq{false};
// Internal (configuration) options for customers // Internal (configuration) options for customers

View file

@ -1,3 +1,4 @@
namespace foo
universe l universe l
constants (A : Type.{l}) constants (A : Type.{l})
@ -12,4 +13,5 @@ definition g.def [defeq] (x y : A) : g x y = h y := rfl
definition f.def [defeq] (x y z : A) : f x y z = g (g x y) z := rfl definition f.def [defeq] (x y z : A) : f x y z = g (g x y) z := rfl
definition d.def [defeq] (x y z w : A) : d x y z w = f (f x y z) (f y z w) (f x w z) := rfl definition d.def [defeq] (x y z w : A) : d x y z w = f (f x y z) (f y z w) (f x w z) := rfl
print [defeq] print [defeq] foo
end foo

View file

@ -1,5 +1,5 @@
defeq simp lemmas: defeq simp lemmas at namespace 'foo':
#2, g ?M_1 ?M_2 ↦ h ?M_2
#4, d ?M_1 ?M_2 ?M_3 ?M_4 ↦ f (f ?M_1 ?M_2 ?M_3) (f ?M_2 ?M_3 ?M_4) (f ?M_1 ?M_4 ?M_3) #4, d ?M_1 ?M_2 ?M_3 ?M_4 ↦ f (f ?M_1 ?M_2 ?M_3) (f ?M_2 ?M_3 ?M_4) (f ?M_1 ?M_4 ?M_3)
#3, f ?M_1 ?M_2 ?M_3 ↦ g (g ?M_1 ?M_2) ?M_3 #3, f ?M_1 ?M_2 ?M_3 ↦ g (g ?M_1 ?M_2) ?M_3
#2, g ?M_1 ?M_2 ↦ h ?M_2
#1, h ?M_1 ↦ q ?M_1 #1, h ?M_1 ↦ q ?M_1

View file

@ -1,3 +1,4 @@
namespace foo
universe l universe l
constants (A : Type.{l}) constants (A : Type.{l})
@ -18,7 +19,7 @@ definition f.def [defeq] (x y z : A) : f x y z = g (g x y) z := rfl
definition d.def [defeq] (x y z w : A) : d x y z w = f (f x y z) (f y z w) (f x w z) := rfl definition d.def [defeq] (x y z w : A) : d x y z w = f (f x y z) (f y z w) (f x w z) := rfl
-- Confirm that more recent annotations get priority -- Confirm that more recent annotations get priority
print [defeq] print [defeq] foo
attribute h.rfl [defeq] [priority 1001] attribute h.rfl [defeq] [priority 1001]
attribute g.rfl [defeq] [priority 1001] attribute g.rfl [defeq] [priority 1001]
@ -26,7 +27,7 @@ attribute f.rfl [defeq] [priority 1001]
attribute d.rfl [defeq] [priority 1001] attribute d.rfl [defeq] [priority 1001]
-- Confirm that priority annotations override -- Confirm that priority annotations override
print [defeq] print [defeq] foo
attribute h.def [defeq] [priority 1001] attribute h.def [defeq] [priority 1001]
attribute g.def [defeq] [priority 1001] attribute g.def [defeq] [priority 1001]
@ -34,4 +35,5 @@ attribute f.def [defeq] [priority 1001]
attribute d.def [defeq] [priority 1001] attribute d.def [defeq] [priority 1001]
-- Confirm that most recent annotations get priority to break explicit priority ties -- Confirm that most recent annotations get priority to break explicit priority ties
print [defeq] print [defeq] foo
end foo

View file

@ -1,27 +1,27 @@
defeq simp lemmas: defeq simp lemmas at namespace 'foo':
#2, g ?M_1 ?M_2 ↦ h ?M_2
#2, g ?M_1 ?M_2 ↦ ?M_2
#4, d ?M_1 ?M_2 ?M_3 ?M_4 ↦ f (f ?M_1 ?M_2 ?M_3) (f ?M_2 ?M_3 ?M_4) (f ?M_1 ?M_4 ?M_3) #4, d ?M_1 ?M_2 ?M_3 ?M_4 ↦ f (f ?M_1 ?M_2 ?M_3) (f ?M_2 ?M_3 ?M_4) (f ?M_1 ?M_4 ?M_3)
#4, d ?M_1 ?M_2 ?M_3 ?M_4 ↦ ?M_3 #4, d ?M_1 ?M_2 ?M_3 ?M_4 ↦ ?M_3
#3, f ?M_1 ?M_2 ?M_3 ↦ g (g ?M_1 ?M_2) ?M_3 #3, f ?M_1 ?M_2 ?M_3 ↦ g (g ?M_1 ?M_2) ?M_3
#3, f ?M_1 ?M_2 ?M_3 ↦ ?M_3 #3, f ?M_1 ?M_2 ?M_3 ↦ ?M_3
#2, g ?M_1 ?M_2 ↦ h ?M_2
#2, g ?M_1 ?M_2 ↦ ?M_2
#1, h ?M_1 ↦ q ?M_1 #1, h ?M_1 ↦ q ?M_1
#1, h ?M_1 ↦ ?M_1 #1, h ?M_1 ↦ ?M_1
defeq simp lemmas: defeq simp lemmas at namespace 'foo':
#2 (1001), g ?M_1 ?M_2 ↦ ?M_2
#2, g ?M_1 ?M_2 ↦ h ?M_2
#4 (1001), d ?M_1 ?M_2 ?M_3 ?M_4 ↦ ?M_3 #4 (1001), d ?M_1 ?M_2 ?M_3 ?M_4 ↦ ?M_3
#4, d ?M_1 ?M_2 ?M_3 ?M_4 ↦ f (f ?M_1 ?M_2 ?M_3) (f ?M_2 ?M_3 ?M_4) (f ?M_1 ?M_4 ?M_3) #4, d ?M_1 ?M_2 ?M_3 ?M_4 ↦ f (f ?M_1 ?M_2 ?M_3) (f ?M_2 ?M_3 ?M_4) (f ?M_1 ?M_4 ?M_3)
#3 (1001), f ?M_1 ?M_2 ?M_3 ↦ ?M_3 #3 (1001), f ?M_1 ?M_2 ?M_3 ↦ ?M_3
#3, f ?M_1 ?M_2 ?M_3 ↦ g (g ?M_1 ?M_2) ?M_3 #3, f ?M_1 ?M_2 ?M_3 ↦ g (g ?M_1 ?M_2) ?M_3
#2 (1001), g ?M_1 ?M_2 ↦ ?M_2
#2, g ?M_1 ?M_2 ↦ h ?M_2
#1 (1001), h ?M_1 ↦ ?M_1 #1 (1001), h ?M_1 ↦ ?M_1
#1, h ?M_1 ↦ q ?M_1 #1, h ?M_1 ↦ q ?M_1
defeq simp lemmas: defeq simp lemmas at namespace 'foo':
#2 (1001), g ?M_1 ?M_2 ↦ h ?M_2
#2 (1001), g ?M_1 ?M_2 ↦ ?M_2
#4 (1001), d ?M_1 ?M_2 ?M_3 ?M_4 ↦ f (f ?M_1 ?M_2 ?M_3) (f ?M_2 ?M_3 ?M_4) (f ?M_1 ?M_4 ?M_3) #4 (1001), d ?M_1 ?M_2 ?M_3 ?M_4 ↦ f (f ?M_1 ?M_2 ?M_3) (f ?M_2 ?M_3 ?M_4) (f ?M_1 ?M_4 ?M_3)
#4 (1001), d ?M_1 ?M_2 ?M_3 ?M_4 ↦ ?M_3 #4 (1001), d ?M_1 ?M_2 ?M_3 ?M_4 ↦ ?M_3
#3 (1001), f ?M_1 ?M_2 ?M_3 ↦ g (g ?M_1 ?M_2) ?M_3 #3 (1001), f ?M_1 ?M_2 ?M_3 ↦ g (g ?M_1 ?M_2) ?M_3
#3 (1001), f ?M_1 ?M_2 ?M_3 ↦ ?M_3 #3 (1001), f ?M_1 ?M_2 ?M_3 ↦ ?M_3
#2 (1001), g ?M_1 ?M_2 ↦ h ?M_2
#2 (1001), g ?M_1 ?M_2 ↦ ?M_2
#1 (1001), h ?M_1 ↦ q ?M_1 #1 (1001), h ?M_1 ↦ q ?M_1
#1 (1001), h ?M_1 ↦ ?M_1 #1 (1001), h ?M_1 ↦ ?M_1