feat(library/blast): add basic support for non-recursive recursors/eliminators in the simple_strategy, fix bug at recursor_action

This commit is contained in:
Leonardo de Moura 2015-11-15 18:39:12 -08:00
parent a545860aa1
commit db59c6829c
6 changed files with 48 additions and 5 deletions

View file

@ -456,6 +456,9 @@ public:
expr mk_fresh_local(expr const & type, binder_info const & bi) { expr mk_fresh_local(expr const & type, binder_info const & bi) {
return m_tmp_local_generator.mk_tmp_local(type, bi); return m_tmp_local_generator.mk_tmp_local(type, bi);
} }
bool is_fresh_local(expr const & e) const {
return m_tmp_local_generator.is_tmp_local(e);
}
expr whnf(expr const & e) { return m_tctx.whnf(e); } expr whnf(expr const & e) { return m_tctx.whnf(e); }
expr relaxed_whnf(expr const & e) { return m_tctx.relaxed_whnf(e); } expr relaxed_whnf(expr const & e) { return m_tctx.relaxed_whnf(e); }
expr infer_type(expr const & e) { return m_tctx.infer(e); } expr infer_type(expr const & e) { return m_tctx.infer(e); }
@ -611,6 +614,11 @@ expr mk_fresh_local(expr const & type, binder_info const & bi) {
return g_blastenv->mk_fresh_local(type, bi); return g_blastenv->mk_fresh_local(type, bi);
} }
bool is_fresh_local(expr const & e) {
lean_assert(g_blastenv);
return g_blastenv->is_fresh_local(e);
}
optional<congr_lemma> mk_congr_lemma_for_simp(expr const & fn, unsigned num_args) { optional<congr_lemma> mk_congr_lemma_for_simp(expr const & fn, unsigned num_args) {
lean_assert(g_blastenv); lean_assert(g_blastenv);
return g_blastenv->mk_congr_lemma_for_simp(fn, num_args); return g_blastenv->mk_congr_lemma_for_simp(fn, num_args);

View file

@ -30,6 +30,7 @@ type_context & get_type_context();
state & curr_state(); state & curr_state();
/** \brief Return a thread local fresh local constant. */ /** \brief Return a thread local fresh local constant. */
expr mk_fresh_local(expr const & type, binder_info const & bi = binder_info()); expr mk_fresh_local(expr const & type, binder_info const & bi = binder_info());
bool is_fresh_local(expr const & e);
/** \brief Return true iff the given constant name is marked as reducible in env() */ /** \brief Return true iff the given constant name is marked as reducible in env() */
bool is_reducible(name const & n); bool is_reducible(name const & n);
/** \brief Return a nonnull projection_info object if \c n is the name of a projection in env() */ /** \brief Return a nonnull projection_info object if \c n is the name of a projection in env() */

View file

@ -94,20 +94,19 @@ struct recursor_proof_step_cell : public proof_step_cell {
list<expr> new_prs = cons(pr, m_goal_proofs); list<expr> new_prs = cons(pr, m_goal_proofs);
if (empty(new_goals)) { if (empty(new_goals)) {
buffer<expr> proof_args; buffer<expr> proof_args;
buffer<expr> gs;
to_buffer(m_goals, gs);
expr const & rec = get_app_args(m_proof, proof_args); expr const & rec = get_app_args(m_proof, proof_args);
// update proof_args that are goals with their proofs // update proof_args that are goals with their proofs
unsigned i = proof_args.size(); unsigned i = proof_args.size();
while (i > 0) { while (i > 0) {
--i; --i;
if (!gs.empty() && proof_args[i] == gs.back()) { if (is_fresh_local(proof_args[i])) {
lean_assert(new_prs); lean_assert(new_prs);
proof_args[i] = head(new_prs); proof_args[i] = head(new_prs);
new_prs = tail(new_prs); new_prs = tail(new_prs);
} }
} }
return action_result::solved(mk_app(rec, proof_args)); expr result = mk_app(rec, proof_args);
return action_result::solved(result);
} else { } else {
s.pop_proof_step(); s.pop_proof_step();
s.push_proof_step(new recursor_proof_step_cell(m_dep, m_branch, m_proof, new_goals, new_prs)); s.push_proof_step(new recursor_proof_step_cell(m_dep, m_branch, m_proof, new_goals, new_prs));

View file

@ -14,6 +14,7 @@ optional<name> is_recursor_action_target(hypothesis_idx hidx);
/** \brief Return the number of minor premises of the given recursor */ /** \brief Return the number of minor premises of the given recursor */
unsigned get_num_minor_premises(name const & R); unsigned get_num_minor_premises(name const & R);
bool is_recursive_recursor(name const & R);
action_result recursor_action(hypothesis_idx hidx, name const & R); action_result recursor_action(hypothesis_idx hidx, name const & R);
action_result recursor_action(hypothesis_idx hidx); action_result recursor_action(hypothesis_idx hidx);

View file

@ -45,12 +45,25 @@ class simple_strategy : public strategy {
} }
if (optional<name> R = is_recursor_action_target(*hidx)) { if (optional<name> R = is_recursor_action_target(*hidx)) {
if (get_num_minor_premises(*R) == 1) { unsigned num_minor = get_num_minor_premises(*R);
if (num_minor == 1) {
action_result r = recursor_action(*hidx, *R); action_result r = recursor_action(*hidx, *R);
if (!failed(r)) { if (!failed(r)) {
if (!preprocess) display_action("recursor"); if (!preprocess) display_action("recursor");
return r; return r;
} }
} else {
// If the hypothesis recursor has more than 1 minor premise, we
// put it in a priority queue.
// TODO(Leo): refine
// TODO(Leo): the following weight computation is too simple...
double w = 1.0 / (static_cast<double>(*hidx) + 1.0);
if (!is_recursive_recursor(*R)) {
// TODO(Leo): we need a better strategy for handling recursive recursors...
w += static_cast<double>(num_minor);
curr_state().add_to_rec_queue(*hidx, w);
}
} }
} }
@ -95,6 +108,16 @@ class simple_strategy : public strategy {
return action_result::solved(*pr); return action_result::solved(*pr);
} }
while (auto hidx = curr_state().select_rec_hypothesis()) {
if (optional<name> R = is_recursor_action_target(*hidx)) {
r = recursor_action(*hidx, *R);
if (!failed(r)) {
display_action("recursor");
return r;
}
}
}
r = constructor_action(); r = constructor_action();
if (!failed(r)) { if (!failed(r)) {
display_action("constructor"); display_action("constructor");

View file

@ -0,0 +1,11 @@
set_option blast.init_depth 10
set_option blast.inc_depth 100
set_option blast.trace true
example (p q : Prop) : p q → q p :=
by blast
definition lemma1 (p q r s : Prop) (a b : nat) : r s → p q → a = b → q p :=
by blast
print lemma1