feat(library/unifier): when unifier.expensive == true, then use only restrict higher-order unification (a fragment slightly more general than higher-order pattern matching) for solving class-instance constraints

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2014-08-02 14:30:25 -07:00
parent 5e2185cfbe
commit fbc4a7af3b
2 changed files with 45 additions and 7 deletions

View file

@ -257,6 +257,7 @@ struct unifier_fn {
unsigned m_max_steps; unsigned m_max_steps;
unsigned m_num_steps; unsigned m_num_steps;
bool m_expensive; bool m_expensive;
bool m_pattern; //!< If true, then only higher-order (pattern) matching is used
bool m_first; //!< True if we still have to generate the first solution. bool m_first; //!< True if we still have to generate the first solution.
unsigned m_next_assumption_idx; //!< Next assumption index. unsigned m_next_assumption_idx; //!< Next assumption index.
unsigned m_next_cidx; //!< Next constraint index. unsigned m_next_cidx; //!< Next constraint index.
@ -299,11 +300,12 @@ struct unifier_fn {
cnstr_set m_cnstrs; cnstr_set m_cnstrs;
name_to_cnstrs m_mvar_occs; name_to_cnstrs m_mvar_occs;
owned_map m_owned_map; owned_map m_owned_map;
bool m_pattern;
/** \brief Save unifier's state */ /** \brief Save unifier's state */
case_split(unifier_fn & u, justification const & j): case_split(unifier_fn & u, justification const & j):
m_assumption_idx(u.m_next_assumption_idx), m_jst(j), m_subst(u.m_subst), m_cnstrs(u.m_cnstrs), m_assumption_idx(u.m_next_assumption_idx), m_jst(j), m_subst(u.m_subst), m_cnstrs(u.m_cnstrs),
m_mvar_occs(u.m_mvar_occs), m_owned_map(u.m_owned_map) { m_mvar_occs(u.m_mvar_occs), m_owned_map(u.m_owned_map), m_pattern(u.m_pattern) {
u.m_next_assumption_idx++; u.m_next_assumption_idx++;
u.m_tc[0]->push(); u.m_tc[0]->push();
u.m_tc[1]->push(); u.m_tc[1]->push();
@ -320,6 +322,7 @@ struct unifier_fn {
u.m_cnstrs = m_cnstrs; u.m_cnstrs = m_cnstrs;
u.m_mvar_occs = m_mvar_occs; u.m_mvar_occs = m_mvar_occs;
u.m_owned_map = m_owned_map; u.m_owned_map = m_owned_map;
u.m_pattern = m_pattern;
m_assumption_idx = u.m_next_assumption_idx; m_assumption_idx = u.m_next_assumption_idx;
m_failed_justifications = mk_composite1(m_failed_justifications, *u.m_conflict); m_failed_justifications = mk_composite1(m_failed_justifications, *u.m_conflict);
u.m_next_assumption_idx++; u.m_next_assumption_idx++;
@ -350,7 +353,7 @@ struct unifier_fn {
name_generator const & ngen, substitution const & s, name_generator const & ngen, substitution const & s,
bool use_exception, unsigned max_steps, bool expensive): bool use_exception, unsigned max_steps, bool expensive):
m_env(env), m_ngen(ngen), m_subst(s), m_plugin(get_unifier_plugin(env)), m_env(env), m_ngen(ngen), m_subst(s), m_plugin(get_unifier_plugin(env)),
m_use_exception(use_exception), m_max_steps(max_steps), m_num_steps(0), m_expensive(expensive) { m_use_exception(use_exception), m_max_steps(max_steps), m_num_steps(0), m_expensive(expensive), m_pattern(false) {
m_tc[0] = mk_type_checker_with_hints(env, m_ngen.mk_child(), false); m_tc[0] = mk_type_checker_with_hints(env, m_ngen.mk_child(), false);
m_tc[1] = mk_type_checker_with_hints(env, m_ngen.mk_child(), true); m_tc[1] = mk_type_checker_with_hints(env, m_ngen.mk_child(), true);
m_next_assumption_idx = 0; m_next_assumption_idx = 0;
@ -1395,15 +1398,18 @@ struct unifier_fn {
mk_simple_projections(m, margs, rhs, j, alts, relax); mk_simple_projections(m, margs, rhs, j, alts, relax);
break; break;
case expr_kind::Sort: case expr_kind::Constant: case expr_kind::Sort: case expr_kind::Constant:
mk_simple_projections(m, margs, rhs, j, alts, relax); if (!m_pattern)
mk_simple_projections(m, margs, rhs, j, alts, relax);
mk_simple_imitation(m, rhs, j, alts, relax); mk_simple_imitation(m, rhs, j, alts, relax);
break; break;
case expr_kind::Pi: case expr_kind::Lambda: case expr_kind::Pi: case expr_kind::Lambda:
mk_simple_projections(m, margs, rhs, j, alts, relax); if (!m_pattern)
mk_simple_projections(m, margs, rhs, j, alts, relax);
mk_bindings_imitation(m, margs, rhs, j, alts, relax); mk_bindings_imitation(m, margs, rhs, j, alts, relax);
break; break;
case expr_kind::Macro: case expr_kind::Macro:
mk_simple_projections(m, margs, rhs, j, alts, relax); if (!m_pattern)
mk_simple_projections(m, margs, rhs, j, alts, relax);
mk_macro_imitation(m, margs, rhs, j, alts, relax); mk_macro_imitation(m, margs, rhs, j, alts, relax);
break; break;
case expr_kind::App: { case expr_kind::App: {
@ -1416,12 +1422,13 @@ struct unifier_fn {
expr const & marg = margs[i]; expr const & marg = margs[i];
if (is_local(marg) && mlocal_name(marg) == mlocal_name(f)) if (is_local(marg) && mlocal_name(marg) == mlocal_name(f))
mk_flex_rigid_app_cnstrs(m, margs, mk_var(vidx), rhs, j, alts, relax); mk_flex_rigid_app_cnstrs(m, margs, mk_var(vidx), rhs, j, alts, relax);
else else if (!m_pattern)
mk_simple_nonlocal_projection(m, margs, i, rhs, j, alts, relax); mk_simple_nonlocal_projection(m, margs, i, rhs, j, alts, relax);
} }
} else { } else {
lean_assert(is_constant(f)); lean_assert(is_constant(f));
mk_simple_projections(m, margs, rhs, j, alts, relax); if (!m_pattern)
mk_simple_projections(m, margs, rhs, j, alts, relax);
mk_flex_rigid_app_cnstrs(m, margs, f, rhs, j, alts, relax); mk_flex_rigid_app_cnstrs(m, margs, f, rhs, j, alts, relax);
} }
break; break;
@ -1625,6 +1632,8 @@ struct unifier_fn {
lean_assert(!m_tc[1]->next_cnstr()); lean_assert(!m_tc[1]->next_cnstr());
auto const * p = m_cnstrs.min(); auto const * p = m_cnstrs.min();
unsigned cidx = p->second; unsigned cidx = p->second;
if (!m_expensive && cidx > get_group_first_index(cnstr_group::MaxDelayed))
m_pattern = true; // use only higher-order (pattern) matching after we start processing MaxDelayed (aka class-instance constraints)
constraint c = p->first; constraint c = p->first;
m_cnstrs.erase_min(); m_cnstrs.erase_min();
if (is_choice_cnstr(c)) { if (is_choice_cnstr(c)) {

View file

@ -0,0 +1,29 @@
----------------------------------------------------------------------------------------------------
--- Copyright (c) 2014 Microsoft Corporation. All rights reserved.
--- Released under Apache 2.0 license as described in the file LICENSE.
--- Author: Jeremy Avigad
----------------------------------------------------------------------------------------------------
import logic data.nat
using nat
namespace simp
-- first define a class of homogeneous equality
inductive simplifies_to {T : Type} (t1 t2 : T) : Prop :=
| mk : t1 = t2 → simplifies_to t1 t2
theorem get_eq {T : Type} {t1 t2 : T} (C : simplifies_to t1 t2) : t1 = t2 :=
simplifies_to_rec (λx, x) C
theorem infer_eq {T : Type} (t1 t2 : T) {C : simplifies_to t1 t2} : t1 = t2 :=
simplifies_to_rec (λx, x) C
theorem simp_app [instance] (S : Type) (T : Type) (f1 f2 : S → T) (s1 s2 : S)
(C1 : simplifies_to f1 f2) (C2 : simplifies_to s1 s2) : simplifies_to (f1 s1) (f2 s2) :=
mk (congr (get_eq C1) (get_eq C2))
theorem test1 (S : Type) (T : Type) (f1 f2 : S → T) (s1 s2 : S) (Hf : f1 = f2) (Hs : s1 = s2) :
f1 s1 = f2 s2 :=
have Rs [fact] : simplifies_to f1 f2, from mk Hf,
have Cs [fact] : simplifies_to s1 s2, from mk Hs,
infer_eq _ _