feat(library/simplifier): simplification sets for hypothesis and conclusion

This commit is contained in:
Leonardo de Moura 2015-07-27 14:47:41 -07:00
parent 966e0109ff
commit b2bd6b1ff8
6 changed files with 100 additions and 26 deletions

View file

@ -225,6 +225,7 @@ struct app_builder::imp {
};
app_builder::app_builder(type_checker & tc):m_ptr(new imp(tc)) {}
app_builder::~app_builder() {}
optional<expr> app_builder::mk_app(declaration const & d, unsigned nargs, expr const * args, bool use_cache) {
return m_ptr->mk_app(d, nargs, args, use_cache);
}

View file

@ -28,6 +28,7 @@ class app_builder {
std::unique_ptr<imp> m_ptr;
public:
app_builder(type_checker & tc);
~app_builder();
/** \brief Create an application (d.{_ ... _} _ ... _ args[0] ... args[nargs-1]).
The missing arguments and universes levels are inferred using type inference.

View file

@ -70,6 +70,7 @@ optional<trans_info> get_trans_extra_info(environment const & env, name const &
optional<name> get_refl_info(environment const & env, name const & op);
optional<name> get_symm_info(environment const & env, name const & op);
optional<name> get_trans_info(environment const & env, name const & op);
bool is_subst_relation(environment const & env, name const & op);
inline bool is_trans_relation(environment const & env, name const & op) { return static_cast<bool>(get_trans_info(env, op)); }
inline bool is_symm_relation(environment const & env, name const & op) { return static_cast<bool>(get_symm_info(env, op)); }

View file

@ -9,7 +9,6 @@ Author: Leonardo de Moura
#include "kernel/instantiate.h"
#include "kernel/for_each_fn.h"
#include "library/constants.h"
#include "library/expr_pair.h"
#include "library/util.h"
#include "library/relation_manager.h"
#include "library/occurs.h"

View file

@ -6,6 +6,7 @@ Author: Leonardo de Moura
*/
#pragma once
#include "kernel/type_checker.h"
#include "library/expr_pair.h"
namespace lean {
bool is_simp_relation(environment const & env, expr const & e, expr & rel, expr & lhs, expr & rhs);

View file

@ -5,9 +5,13 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include "util/sexpr/option_declarations.h"
#include "kernel/instantiate.h"
#include "library/constants.h"
#include "library/util.h"
#include "library/app_builder.h"
#include "library/relation_manager.h"
#include "library/tactic/expr_to_tactic.h"
#include "library/simplifier/ceqv.h"
#include "library/simplifier/simp_tactic.h"
#include "library/simplifier/simp_rule_set.h"
@ -129,14 +133,23 @@ private:
environment m_env;
io_state m_ios;
name_generator m_ngen;
elaborate_fn m_elab;
optional<tactic> m_tactic;
type_checker m_elab_tc;
app_builder m_app_builder;
// transient state
unsigned m_steps;
goal m_g;
substitution m_subst;
// Remark: the following buffer contains pre-terms that need to be elaborated.
// The 'simp at *' is not very efficient in the current implementation.
// If we have N hypotheses, then m_lemmas_to_process will be processed N+1 times.
buffer<expr> m_lemmas_to_process;
simp_rule_sets m_simp_set;
simp_rule_sets m_simp_sets;
// configuration options
bool m_single_pass;
@ -174,33 +187,101 @@ private:
}
}
res_kind simp_goal() {
// Add lemmas and assumptions to m_simp_set.
// If hidx is none, then we are elaborating the conclusion, otherwise we are elaborating hypothesis hidx.
// This method destructively updates m_simp_set
void elaborate_lemmas(optional<unsigned> hidx) {
name user("user");
for (expr const & l : m_lemmas_to_process) {
try {
expr new_l; constraints cs;
bool report_unassigned = true;
std::tie(new_l, m_subst, cs) = m_elab(m_g, m_ngen.mk_child(), l, none_expr(), m_subst, report_unassigned);
if (cs)
throw tactic_exception("invalid 'simp' tactic, fail to resolve generated constraints");
expr new_e = head_beta_reduce(m_elab_tc.infer(new_l).first);
m_simp_sets = add(m_elab_tc, m_simp_sets, user, new_e, new_l);
} catch (exception &) {
if (!hidx) {
// processing conclusion, then report the error
throw;
}
}
}
if (m_assumptions) {
name assump("assumption");
buffer<expr> hyps;
m_g.get_hyps(hyps);
unsigned end = hidx ? *hidx : hyps.size();
for (unsigned i = 0; i < end; i++) {
expr H = hyps[i];
expr H_type = mlocal_type(H);
expr rel, lhs, rhs;
if (is_simp_relation(m_env, H_type, rel, lhs, rhs)) {
// TODO(Leo): we are currently flipping equations when lhs < rhs.
// Should we remove this automatic flipping?
if (get_weight(lhs) >= get_weight(rhs)) {
m_simp_sets = add(m_elab_tc, m_simp_sets, assump, H_type, H);
} else {
// lhs is "smaller" than rhs
// so we try to apply symmetry if available
if (!is_constant(rel))
continue;
name op = const_name(rel);
auto rel_info = get_relation_info(m_env, op);
auto info = get_symm_extra_info(m_env, op);
if (!info || !rel_info)
continue; // relation is not symmetric
buffer<expr> args;
get_app_args(H_type, args);
expr tmp = args[rel_info->get_lhs_pos()];
args[rel_info->get_lhs_pos()] = args[rel_info->get_rhs_pos()];
args[rel_info->get_rhs_pos()] = tmp;
H_type = mk_app(rel, args);
if (auto new_H = m_app_builder.mk_app(info->m_name, H)) {
H = *new_H;
m_simp_sets = add(m_elab_tc, m_simp_sets, assump, H_type, H);
}
}
}
}
}
}
res_kind simp_conclusion() {
elaborate_lemmas(optional<unsigned>());
if (m_trace) {
out() << m_simp_sets;
}
// TODO(Leo)
return DidNothing;
}
bool simp_hyp(unsigned hidx) {
flet<simp_rule_sets> save(m_simp_sets, m_simp_sets);
elaborate_lemmas(optional<unsigned>(hidx));
// TODO(Leo)
return false;
}
// Initialize m_simp_set with information that is context independent
void init_simp_set(buffer<name> const & ns, buffer<name> const & ex) {
m_simp_set = get_simp_rule_sets(m_env);
// Remark: we cannot initialize explicitly provided lemmas here
// since some of them may depend on hypotheses.
m_simp_sets = get_simp_rule_sets(m_env);
for (name const & n : ns) {
simp_rule_sets tmp_simp_set = get_simp_rule_sets(m_env, n);
m_simp_set = join(m_simp_set, tmp_simp_set);
}
m_simp_set.erase_simp(ex);
if (m_trace) {
out() << m_simp_set;
m_simp_sets = join(m_simp_sets, tmp_simp_set);
}
m_simp_sets.erase_simp(ex);
}
public:
simp_tactic_fn(environment const & env, io_state const & ios, name_generator && ngen,
buffer<expr> const & /* ls */, buffer<name> const & ns, buffer<name> const & ex,
optional<tactic> const & tac):m_env(env), m_ios(ios), m_ngen(ngen), m_tactic(tac) {
simp_tactic_fn(environment const & env, io_state const & ios, name_generator && ngen, elaborate_fn const & elab,
buffer<expr> const & ls, buffer<name> const & ns, buffer<name> const & ex,
optional<tactic> const & tac):
m_env(env), m_ios(ios), m_ngen(ngen), m_elab(elab), m_tactic(tac), m_elab_tc(m_env), m_app_builder(m_elab_tc),
m_lemmas_to_process(ls) {
set_options(env, m_ios.get_options());
init_simp_set(ns, ex);
}
@ -209,7 +290,7 @@ public:
m_g = g;
m_subst = s;
if (loc.is_goal_only()) {
res_kind k = simp_goal();
res_kind k = simp_conclusion();
return std::make_tuple(k, m_g, m_subst);
} else {
buffer<expr> hyps;
@ -224,7 +305,7 @@ public:
hidx++;
}
if (loc.includes_goal()) {
res_kind k = simp_goal();
res_kind k = simp_conclusion();
if (k == DidNothing && progress)
k = Simplified;
return std::make_tuple(k, m_g, m_subst);
@ -245,18 +326,8 @@ tactic mk_simp_tactic(elaborate_fn const & elab, buffer<expr> const & ls, buffer
}
goal const & g = head(gs);
name_generator new_ngen = s.get_ngen();
substitution new_subst = s.get_subst();
buffer<expr> new_ls;
for (expr const & l : ls) {
expr new_l; constraints cs;
bool report_unassigned = true;
std::tie(new_l, new_subst, cs) = elab(g, new_ngen.mk_child(), l, none_expr(), new_subst, report_unassigned);
if (cs)
throw_tactic_exception_if_enabled(s, "invalid 'simp' tactic, fail to resolve generated constraints");
new_ls.push_back(new_l);
}
simp_tactic_fn simp(env, ios, new_ngen.mk_child(), new_ls, ns, ex, tac);
goal new_g; simp_tactic_fn::res_kind k;
simp_tactic_fn simp(env, ios, new_ngen.mk_child(), elab, ls, ns, ex, tac);
goal new_g; simp_tactic_fn::res_kind k; substitution new_subst = s.get_subst();
std::tie(k, new_g, new_subst) = simp(g, loc, new_subst);
switch (k) {
case simp_tactic_fn::Simplified: {