This PR adds the following features to `simp`: - A routine for simplifying `have` telescopes in a way that avoids quadratic complexity arising from locally nameless expression representations, like what #6220 did for `letFun` telescopes. Furthermore, simp converts `letFun`s into `have`s (nondependent lets), and we remove the #6220 routine since we are moving away from `letFun` encodings of nondependent lets. - A `+letToHave` configuration option (enabled by default) that converts lets into haves when possible, when `-zeta` is set. Previously Lean would need to do a full typecheck of the bodies of `let`s, but the `letToHave` procedure can skip checking some subexpressions, and it modifies the `let`s in an entire expression at once rather than one at a time. - A `+zetaHave` configuration option, to turn off zeta reduction of `have`s specifically. The motivation is that dependent `let`s can only be dsimped by let, so zeta reducing just the dependent lets is a reasonable way to make progress. The `+zetaHave` option is also added to the meta configuration. - When `simp` is zeta reducing, it now uses an algorithm that avoids complexity quadratic in the depth of the let telescope. - Additionally, the zeta reduction routines in `simp`, `whnf`, and `isDefEq` now all are consistent with how they apply the `zeta`, `zetaHave`, and `zetaUnused` configurations. The `letToFun` option is addressing a TODO in `getSimpLetCase` ("handle a block of nested let decls in a single pass if this becomes a performance problem"). Performance should be compared to before #8804, which temporarily disabled the #6220 optimizations for `letFun` telescopes. Good kernel performance depends on carefully handling the `have` encoding. Due to the way the kernel instantiates bvars (it does *not* beta reduce when instantiating), we cannot use congruence theorems of the form `(have x := v; f x) = (have x ;= v'; f' x)`, since the bodies of the `have`s will not be syntactically equal, which triggers zeta reduction in the kernel in `is_def_eq`. Instead, we work with `f v = f' v'`, where `f` and `f'` are lambda expressions. There is still zeta reduction, but only when converting between these two forms at the outset of the generated proof.
73 lines
2 KiB
Text
73 lines
2 KiB
Text
x : Nat
|
||
h : f (f x) = x
|
||
⊢ (have y := x * x;
|
||
if True then 1 else y + 1) =
|
||
1
|
||
theorem ex0 : ∀ (x : Nat),
|
||
f (f x) = x →
|
||
(have y := 0 + x * x;
|
||
if f (f x) = x then 1 else y + 1) =
|
||
1 :=
|
||
fun x h =>
|
||
Eq.mpr
|
||
(id
|
||
(congrArg (fun x => x = 1)
|
||
(id
|
||
(id
|
||
(have_congr' (Nat.zero_add (x * x)) fun y =>
|
||
ite_congr (Eq.trans (congrArg (fun x_1 => x_1 = x) h) (eq_self x)) (fun a => Eq.refl 1) fun a =>
|
||
Eq.refl (y + 1))))))
|
||
(of_eq_true (Eq.trans (congrArg (fun x => x = 1) (ite_cond_eq_true 1 (x * x + 1) (Eq.refl True))) (eq_self 1)))
|
||
x : Nat
|
||
h : f (f x) = x
|
||
⊢ (have y := x * x;
|
||
if True then 1 else y + 1) =
|
||
1
|
||
theorem ex1 : ∀ (x : Nat),
|
||
f (f x) = x →
|
||
(have y := x * x;
|
||
if f (f x) = x then 1 else y + 1) =
|
||
1 :=
|
||
fun x h =>
|
||
Eq.mpr
|
||
(id
|
||
(congrArg (fun x => x = 1)
|
||
(id
|
||
(id
|
||
(have_body_congr' (x * x) fun y =>
|
||
ite_congr (Eq.trans (congrArg (fun x_1 => x_1 = x) h) (eq_self x)) (fun a => Eq.refl 1) fun a =>
|
||
Eq.refl (y + 1))))))
|
||
(of_eq_true (Eq.trans (congrArg (fun x => x = 1) (ite_cond_eq_true 1 (x * x + 1) (Eq.refl True))) (eq_self 1)))
|
||
x z : Nat
|
||
h : f (f x) = x
|
||
h' : z = x
|
||
⊢ (have y := x;
|
||
y) =
|
||
z
|
||
theorem ex2 : ∀ (x z : Nat),
|
||
f (f x) = x →
|
||
z = x →
|
||
(have y := f (f x);
|
||
y) =
|
||
z :=
|
||
fun x z h h' =>
|
||
Eq.mpr (id (congrArg (fun x => x = z) (id (id (have_val_congr' h)))))
|
||
(of_eq_true (Eq.trans (congrArg (Eq x) h') (eq_self x)))
|
||
x z : Nat
|
||
⊢ (let α := Nat;
|
||
fun x => 0 + x) =
|
||
id
|
||
p : Prop
|
||
h : p
|
||
⊢ (have n := 10;
|
||
fun x => True) =
|
||
fun z => p
|
||
theorem ex4 : ∀ (p : Prop),
|
||
p →
|
||
(have n := 10;
|
||
fun x => x = x) =
|
||
fun z => p :=
|
||
fun p h =>
|
||
Eq.mpr
|
||
(id (congrArg (fun x => x = fun z => p) (id (id (have_body_congr_dep' 10 fun n => funext fun x => eq_self x)))))
|
||
(of_eq_true (Eq.trans (congrArg (Eq fun x => True) (funext fun z => eq_true h)) (eq_self fun x => True)))
|