Zulip Chat Archive
Stream: mathlib4
Topic: Shrinking epsilon in analysis proofs
Winston Yin (尹維晨) (Dec 14 2023 at 03:24):
I'd like to suggest, if it doesn't already exist, an API/tactic for writing analysis proofs.
A standard proof procedure in real analysis is show ∃ ε > 0, P ε
. So you first obtain some ε
and hε : 0 < ε
from, say, an open ball inside a neighbourhood set, and you do refine ⟨ε, hε, ?_⟩
, hoping that P ε
follows.
Halfway through the proof of P ε
, you realise you actually needed ε / 2
, or maybe min ε ε'
, where ε' > 0
has to be obtained from, say, the continuity of some function. In informal mathematics, you just say "shrink ε
to ε / 2
" or "let εmin
be the smallest out of ε1, ε2, ε3
". The statements P1 ε1, P2 ε2, P3 ε3
that held before are presumed to still hold for εmin
.
In Lean, you have to go back and rewrite refine ⟨min ε ε', ?_, ?_⟩
, and then you need all these code blocks that show that the statements that held for ε
now still hold for ε / 2
or εmin
. Every time such shrinkage of ε
happens, you need to tediously modify all the previous code by adding a bunch of half_pos
or min_le_[left|right]
. I'm hoping that Lean has a better way to handle this sort of proofs.
You may argue that any good proof formaliser should first write the proof down nicely on paper, figure out that the correct ε
you need is εmin = min (ε1 / 2) (min (ε2 / 4) (min ε3 ε4))
, and then get it right in Lean the first time. One, this still invovles a lot of tedious nesting of min_le_[left|right]
that clutter the overall argument. Two, you still need to show that if Pi εmin
holds for every i
; more clutter. Three, this doesn't correspond to how one actually thinks through a proof in real analysis, even when one already knows the proof by heart.
I faced this problem in #8886, where I needed to get εmin
as the min of SIX different ε
s extracted from various conditions. I experimented with the following design, which you can see in action in IntegralCurve.lean
. I introduced a Prop
called Shrinkable
(for lack of a better name), which takes in p : ℝ → Prop
. Shrinkable p
basically says that if p ε
holds, then p ε'
also holds for a smaller ε'
.
In the actual proof, you first show that h1 : p1 ε1
holds for some ε1
. Later on you have another ε2
for which h2 : p2 ε2
holds. You then show that hp1 : Shrinkable p1
and hp2 : Shrinkable p2
, which are lemmas tucked elsewhere (can instance synthesis help?). Now, hp1 h1 (min_le_left ε1 ε2) : p1 (min ε1 ε2)
can be directly used in the grand finale, after refine ⟨min ε1 ε2, ?_, ?_⟩
is invoked.
I hope what I'm describing is clear! What do you think?
Mario Carneiro (Dec 14 2023 at 03:24):
I think the clean way to do this kind of proof is using the filter_upwards
tactic
Winston Yin (尹維晨) (Dec 14 2023 at 03:24):
Oh so an easy way already exists?
Winston Yin (尹維晨) (Dec 14 2023 at 03:25):
Let me read into it and not reinvent the wheel!
Mario Carneiro (Dec 14 2023 at 03:25):
it will handle min
reasoning but not / 2
reasoning
Mario Carneiro (Dec 14 2023 at 03:25):
although I suppose you can do / 2
reasoning using the uniformity filter
Patrick Massot (Dec 14 2023 at 03:36):
Winston Yin (尹維晨) (Dec 14 2023 at 03:45):
It's not immediately clear to me how to use filter_upwards
for the proof in #8886 in a clean way :neutral:
Patrick Massot (Dec 14 2023 at 03:48):
Could you tell me where precisely you have this issue?
Winston Yin (尹維晨) (Dec 14 2023 at 03:52):
I'll think a little harder first :)
Winston Yin (尹維晨) (Dec 14 2023 at 03:53):
I'm guessing the idiomatic way with filter_upwards
is not to reason with ε
so soon
Winston Yin (尹維晨) (Dec 14 2023 at 03:53):
Reason with sets in the neighbourhood filter first
Patrick Massot (Dec 14 2023 at 03:56):
The way filters are meant to handle this is as follows.
have F₁ : ∀ᶠ ε in 𝓝 (0 : ℝ), P₁ ε := sorry
have F₂ : ∀ᶠ ε in 𝓝 (0 : ℝ), P₂ ε := sorry
have F₃ : ∀ᶠ ε in 𝓝 (0 : ℝ), P₃ ε := sorry
have : ∀ᶠ ε in 𝓝 (0 : ℝ), P₁ ε ∧ P₂ ε ∧ P₃ ε := F₁.and (F₂.and F₃)
Patrick Massot (Dec 14 2023 at 03:56):
And you can use docs#Metric.eventually_nhds_iff_ball to get out of filter world.
Patrick Massot (Dec 14 2023 at 03:57):
There is probably an even more specialized version for real numbers.
Patrick Massot (Dec 14 2023 at 03:59):
You can at least do something like simp [Metric.eventually_nhds_iff_ball, Real.dist_0_eq_abs] at this
to turn this
into ∃ ε, 0 < ε ∧ ∀ t : ℝ, |t| < ε → P₁ t ∧ P₂ t ∧ P₃ t
.
Winston Yin (尹維晨) (Dec 14 2023 at 03:59):
Very helpful. Thank you!
Patrick Massot (Dec 14 2023 at 04:00):
And really ∀ᶠ ε in 𝓝 (0 : ℝ), P₁ ε
reads as "for every ε close to 0, P₁ ε".
Junyan Xu (Dec 14 2023 at 04:00):
The appropriate filter might be nhdsWithin 0 (Set.Ioi 0)
which for example appears in this file.
Patrick Massot (Dec 14 2023 at 04:01):
Also known as the much friendlier looking 𝓝[>] 0
.
Junyan Xu (Dec 14 2023 at 04:01):
Yeah the notation is used in the code but I don't know where it's introduced ...
Patrick Massot (Dec 14 2023 at 04:03):
Winston Yin (尹維晨) (Dec 14 2023 at 04:06):
It's great to know this standard way using filters. Does Mathematics in Lean have examples of a translation of standard epsilon-delta proofs using filters?
Patrick Massot (Dec 14 2023 at 04:10):
Section 9.1 contains quite a bit about that.
Patrick Massot (Dec 14 2023 at 04:10):
I don't remember the exact details because I wrote that more than one year ago.
Patrick Massot (Dec 14 2023 at 04:10):
https://leanprover-community.github.io/mathematics_in_lean/C09_Topology.html
Patrick Massot (Dec 14 2023 at 04:12):
You should start with the introduction to Chapter 9, even before 9.1
Winston Yin (尹維晨) (Dec 14 2023 at 04:27):
I think I'm understanding how Eventually
works now. Thank you all!
Winston Yin (尹維晨) (Dec 14 2023 at 06:59):
Filters are maybe not quite as intuitive, but I managed to refactor #8886 using filters. Filter.Eventually.and
really helped me extract a clean, smallest, neighbourhood at the end. No more min
s or going back to rewrite previous code!
Patrick Massot (Dec 14 2023 at 15:15):
Don't worry, you will soon find filters much more intuitive than epsilon-wrangling, starting here.
Last updated: Dec 20 2023 at 11:08 UTC