Skip to content

Commit ca19f8f

Browse files
chore: update complicated proofs in the PR guide
This includes the changes from leanprover-community/mathlib4#31124. The proof of banach_steinhaus has changed and is now only 3 lines with no comments, so is no longer a suitable example.
1 parent e5db044 commit ca19f8f

File tree

1 file changed

+96
-115
lines changed

1 file changed

+96
-115
lines changed

templates/contribute/pr-review.md

Lines changed: 96 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -266,142 +266,123 @@ See the previous example, where a cross reference was requested for a related de
266266

267267
#### Do complicated proofs have a sketch in comments interspersed throughout?
268268

269-
In this example, we just show an existing example of how interspersed comments can
270-
significantly add to the value of a proof in Lean. This is copied directly from the
271-
source for [Gromov_Hausdorff.GH_space.topological_space.second_countable_topology](https://leanprover-community.github.io/mathlib_docs/topology/metric_space/gromov_hausdorff.html#Gromov_Hausdorff.GH_space.topological_space.second_countable_topology).
269+
In this example, we just show an existing example of how interspersed comments can
270+
significantly add to the value of a proof in Lean. This is copied directly from the
271+
source for [GromovHausdorff.instSecondCountableTopologyGHSpace](https://leanprover-community.github.io/mathlib4_docs/Mathlib/Topology/MetricSpace/GromovHausdorff.html#GromovHausdorff.instSecondCountableTopologyGHSpace).
272272

273273
Whenever a complicated proof isn't documented like this, please encourage the PR
274-
author to do so. You can point them to this code. Another suitable and less complicated
275-
example can be found in the source for
276-
[banach_steinhaus](https://leanprover-community.github.io/mathlib_docs/analysis/normed_space/banach_steinhaus.html#banach_steinhaus).
274+
author to do so. You can point them to this code.
277275

278276
```
279277
/-- The Gromov-Hausdorff space is second countable. -/
280-
instance : second_countable_topology GH_space :=
281-
begin
282-
refine second_countable_of_countable_discretization (λ δ δpos, _),
283-
let ε := (2/5) * δ,
284-
have εpos : 0 < ε := mul_pos (by norm_num) δpos,
285-
have : ∀ p:GH_space, ∃ s : set p.rep, s.finite ∧ (univ ⊆ (⋃x∈s, ball x ε)) :=
286-
λ p, by simpa only [subset_univ, exists_true_left]
287-
using finite_cover_balls_of_compact is_compact_univ εpos,
278+
instance : SecondCountableTopology GHSpace := by
279+
refine secondCountable_of_countable_discretization fun δ δpos => ?_
280+
let ε := 2 / 5 * δ
281+
have εpos : 0 < ε := mul_pos (by simp) δpos
282+
have (p : GHSpace) : ∃ s : Set p.Rep, s.Finite ∧ univ ⊆ ⋃ x ∈ s, ball x ε := by
283+
simpa only [subset_univ, true_and] using
284+
finite_cover_balls_of_compact (X := p.Rep) isCompact_univ εpos
288285
-- for each `p`, `s p` is a finite `ε`-dense subset of `p` (or rather the metric space
289-
-- `p.rep` representing `p`)
290-
choose s hs using this,
291-
have : ∀ p:GH_space, ∀ t:set p.rep, t.finite → ∃ n:ℕ, ∃ e:equiv t (fin n), true,
292-
{ assume p t ht,
293-
letI : fintype t := finite.fintype ht,
294-
exact ⟨fintype.card t, fintype.equiv_fin t, trivial⟩ },
295-
choose N e hne using this,
296-
-- cardinality of the nice finite subset `s p` of `p.rep`, called `N p`
297-
let N := λ p:GH_space, N p (s p) (hs p).1,
298-
-- equiv from `s p`, a nice finite subset of `p.rep`, to `fin (N p)`, called `E p`
299-
let E := λ p:GH_space, e p (s p) (hs p).1,
300-
-- A function `F` associating to `p : GH_space` the data of all distances between points
286+
-- `p.Rep` representing `p`)
287+
choose s hs using this
288+
-- cardinality of the nice finite subset `s p` of `p.Rep`, called `N p`
289+
let N := fun p : GHSpace => Nat.card (s p)
290+
-- equiv from `s p`, a nice finite subset of `p.Rep`, to `Fin (N p)`, called `E p`
291+
let E := fun p : GHSpace => (hs p).1.equivFin
292+
-- A function `F` associating to `p : GHSpace` the data of all distances between points
301293
-- in the `ε`-dense set `s p`.
302-
let F : GH_spaceΣn:ℕ, (fin n → fin n → ℤ) :=
303-
λp, ⟨N p, λa b, ⌊ε⁻¹ * dist ((E p).symm a) ((E p).symm b)⌋⟩,
304-
refine ⟨Σ n, fin n → fin n → ℤ, by apply_instance, F, λp q hpq, _⟩,
294+
let F : GHSpaceΣ n : ℕ, Fin n → Fin n → ℤ := fun p =>
295+
⟨N p, fun a b => ⌊ε⁻¹ * dist ((E p).symm a) ((E p).symm b)⌋⟩
296+
refine ⟨Σ n, Fin n → Fin n → ℤ, inferInstance, F, fun p q hpq => ?_⟩
305297
/- As the target space of F is countable, it suffices to show that two points
306298
`p` and `q` with `F p = F q` are at distance `≤ δ`.
307-
For this, we construct a map `Φ` from `s p ⊆ p.rep` (representing `p`)
308-
to `q.rep` (representing `q`) which is almost an isometry on `s p`, and
309-
with image `s q`. For this, we compose the identification of `s p` with `fin (N p)`
310-
and the inverse of the identification of `s q` with `fin (N q)`. Together with
299+
For this, we construct a map `Φ` from `s p ⊆ p.Rep` (representing `p`)
300+
to `q.Rep` (representing `q`) which is almost an isometry on `s p`, and
301+
with image `s q`. For this, we compose the identification of `s p` with `Fin (N p)`
302+
and the inverse of the identification of `s q` with `Fin (N q)`. Together with
311303
the fact that `N p = N q`, this constructs `Ψ` between `s p` and `s q`, and then
312304
composing with the canonical inclusion we get `Φ`. -/
313-
have Npq : N p = N q := (sigma.mk.inj_iff.1 hpq).1,
314-
let Ψ : s p → s q := λ x, (E q).symm (fin.cast Npq ((E p) x)),
315-
let Φ : s p → q.rep := λ x, Ψ x,
316-
-- Use the almost isometry `Φ` to show that `p.rep` and `q.rep`
305+
have Npq : N p = N q := (Sigma.mk.inj_iff.1 hpq).1
306+
let Ψ : s p → s q := fun x => (E q).symm (Fin.cast Npq ((E p) x))
307+
let Φ : s p → q.Rep := fun x => Ψ x
308+
-- Use the almost isometry `Φ` to show that `p.Rep` and `q.Rep`
317309
-- are within controlled Gromov-Hausdorff distance.
318-
have main : GH_dist p.rep q.rep ≤ ε + ε/2 + ε,
319-
{ refine GH_dist_le_of_approx_subsets Φ _ _ _,
320-
show ∀ x : p.rep, ∃ (y : p.rep) (H : y ∈ s p), dist x y ≤ ε,
321-
{ -- by construction, `s p` is `ε`-dense
322-
assume x,
323-
have : x ∈ ⋃y∈(s p), ball y ε := (hs p).2 (mem_univ _),
324-
rcases mem_Union₂.1 this with ⟨y, ys, hy⟩,
325-
exact ⟨y, ys, le_of_lt hy⟩ },
326-
show ∀ x : q.rep, ∃ (z : s p), dist x (Φ z) ≤ ε,
327-
{ -- by construction, `s q` is `ε`-dense, and it is the range of `Φ`
328-
assume x,
329-
have : x ∈ ⋃y∈(s q), ball y ε := (hs q).2 (mem_univ _),
330-
rcases mem_Union₂.1 this with ⟨y, ys, hy⟩,
331-
let i : ℕ := E q ⟨y, ys⟩,
332-
let hi := ((E q) ⟨y, ys⟩).is_lt,
333-
have ihi_eq : (⟨i, hi⟩ : fin (N q)) = (E q) ⟨y, ys⟩, by rw [fin.ext_iff, fin.coe_mk],
334-
have hiq : i < N q := hi,
335-
have hip : i < N p, { rwa Npq.symm at hiq },
336-
let z := (E p).symm ⟨i, hip⟩,
337-
use z,
338-
have C1 : (E p) z = ⟨i, hip⟩ := (E p).apply_symm_apply ⟨i, hip⟩,
339-
have C2 : fin.cast Npq ⟨i, hip⟩ = ⟨i, hi⟩ := rfl,
340-
have C3 : (E q).symm ⟨i, hi⟩ = ⟨y, ys⟩,
341-
{ rw ihi_eq, exact (E q).symm_apply_apply ⟨y, ys⟩ },
342-
have : Φ z = y,
343-
{ simp only [Φ, Ψ], rw [C1, C2, C3], refl },
344-
rw this,
345-
exact le_of_lt hy },
346-
show ∀ x y : s p, |dist x y - dist (Φ x) (Φ y)| ≤ ε,
347-
{ /- the distance between `x` and `y` is encoded in `F p`, and the distance between
310+
have main : ghDist p.Rep q.Rep ≤ ε + ε / 2 + ε := by
311+
refine ghDist_le_of_approx_subsets Φ ?_ ?_ ?_
312+
· show ∀ x : p.Rep, ∃ y ∈ s p, dist x y ≤ ε
313+
-- by construction, `s p` is `ε`-dense
314+
intro x
315+
have : x ∈ ⋃ y ∈ s p, ball y ε := (hs p).2 (mem_univ _)
316+
obtain ⟨y, ys, hy⟩ := mem_iUnion₂.1 this
317+
exact ⟨y, ys, hy.le⟩
318+
· show ∀ x : q.Rep, ∃ z : s p, dist x (Φ z) ≤ ε
319+
-- by construction, `s q` is `ε`-dense, and it is the range of `Φ`
320+
intro x
321+
have : x ∈ ⋃ y ∈ s q, ball y ε := (hs q).2 (mem_univ _)
322+
obtain ⟨y, ys, hy⟩ := mem_iUnion₂.1 this
323+
let i : ℕ := E q ⟨y, ys⟩
324+
let hi := ((E q) ⟨y, ys⟩).is_lt
325+
have ihi_eq : (⟨i, hi⟩ : Fin (N q)) = (E q) ⟨y, ys⟩ := by rw [Fin.ext_iff, Fin.val_mk]
326+
have hiq : i < N q := hi
327+
have hip : i < N p := by rwa [Npq.symm] at hiq
328+
let z := (E p).symm ⟨i, hip⟩
329+
use z
330+
have C1 : (E p) z = ⟨i, hip⟩ := (E p).apply_symm_apply ⟨i, hip⟩
331+
have C2 : Fin.cast Npq ⟨i, hip⟩ = ⟨i, hi⟩ := rfl
332+
have C3 : (E q).symm ⟨i, hi⟩ = ⟨y, ys⟩ := by
333+
rw [ihi_eq]; exact (E q).symm_apply_apply ⟨y, ys⟩
334+
have : Φ z = y := by simp only [Φ, Ψ]; rw [C1, C2, C3]
335+
rw [this]
336+
exact hy.le
337+
· show ∀ x y : s p, |dist x y - dist (Φ x) (Φ y)| ≤ ε
338+
/- the distance between `x` and `y` is encoded in `F p`, and the distance between
348339
`Φ x` and `Φ y` (two points of `s q`) is encoded in `F q`, all this up to `ε`.
349340
As `F p = F q`, the distances are almost equal. -/
350-
assume x y,
351-
have : dist (Φ x) (Φ y) = dist (Ψ x) (Ψ y) := rfl,
352-
rw this,
353-
-- introduce `i`, that codes both `x` and `Φ x` in `fin (N p) = fin (N q)`
354-
let i : ℕ := E p x,
355-
have hip : i < N p := ((E p) x).2,
356-
have hiq : i < N q, by rwa Npq at hip,
357-
have i' : i = ((E q) (Ψ x)), by { simp only [equiv.apply_symm_apply, fin.coe_cast] },
358-
-- introduce `j`, that codes both `y` and `Φ y` in `fin (N p) = fin (N q)`
359-
let j : ℕ := E p y,
360-
have hjp : j < N p := ((E p) y).2,
361-
have hjq : j < N q, by rwa Npq at hjp,
362-
have j' : j = ((E q) (Ψ y)).1,
363-
{ simp only [equiv.apply_symm_apply, fin.val_eq_coe, fin.coe_cast] },
341+
intro x y
342+
-- introduce `i`, that codes both `x` and `Φ x` in `Fin (N p) = Fin (N q)`
343+
let i : ℕ := E p x
344+
have hip : i < N p := ((E p) x).2
345+
have hiq : i < N q := by rwa [Npq] at hip
346+
have i' : i = (E q) (Ψ x) := by simp only [i, Ψ, Equiv.apply_symm_apply, Fin.coe_cast]
347+
-- introduce `j`, that codes both `y` and `Φ y` in `Fin (N p) = Fin (N q)`
348+
let j : ℕ := E p y
349+
have hjp : j < N p := ((E p) y).2
350+
have hjq : j < N q := by rwa [Npq] at hjp
351+
have j' : j = ((E q) (Ψ y)).1 := by
352+
simp only [j, Ψ, Equiv.apply_symm_apply, Fin.coe_cast]
364353
-- Express `dist x y` in terms of `F p`
365-
have : (F p).2 ((E p) x) ((E p) y) = floor (ε⁻¹ * dist x y),
366-
by simp only [F, (E p).symm_apply_apply],
367-
have Ap : (F p).2 ⟨i, hip⟩ ⟨j, hjp⟩ = floor (ε⁻¹ * dist x y),
368-
by { rw ← this, congr; apply fin.ext_iff.2; refl },
354+
have : (F p).2 ((E p) x) ((E p) y) = ⌊ε⁻¹ * dist x y⌋ := by
355+
simp only [F, (E p).symm_apply_apply]
356+
have Ap : (F p).2 ⟨i, hip⟩ ⟨j, hjp⟩ = ⌊ε⁻¹ * dist x y⌋ := by rw [← this]
369357
-- Express `dist (Φ x) (Φ y)` in terms of `F q`
370-
have : (F q).2 ((E q) (Ψ x)) ((E q) (Ψ y)) = floor (ε⁻¹ * dist (Ψ x) (Ψ y)),
371-
by simp only [F, (E q).symm_apply_apply],
372-
have Aq : (F q).2 ⟨i, hiq⟩ ⟨j, hjq⟩ = floor (ε⁻¹ * dist (Ψ x) (Ψ y)),
373-
by { rw ← this, congr; apply fin.ext_iff.2; [exact i', exact j'] },
358+
have : (F q).2 ((E q) (Ψ x)) ((E q) (Ψ y)) = ε⁻¹ * dist (Ψ x) (Ψ y)⌋ := by
359+
simp only [F, (E q).symm_apply_apply]
360+
have Aq : (F q).2 ⟨i, hiq⟩ ⟨j, hjq⟩ = ε⁻¹ * dist (Ψ x) (Ψ y)⌋ := by
361+
simp [← this, *]
374362
-- use the equality between `F p` and `F q` to deduce that the distances have equal
375363
-- integer parts
376-
have : (F p).2 ⟨i, hip⟩ ⟨j, hjp⟩ = (F q).2 ⟨i, hiq⟩ ⟨j, hjq⟩,
377-
{ -- we want to `subst hpq` where `hpq : F p = F q`, except that `subst` only works
378-
-- with a constant, so replace `F q` (and everything that depends on it) by a constant `f`
379-
-- then `subst`
380-
revert hiq hjq,
381-
change N q with (F q).1,
382-
generalize_hyp : F q = f at hpq ⊢,
383-
subst hpq,
384-
intros,
385-
refl },
386-
rw [Ap, Aq] at this,
364+
have : (F p).2 ⟨i, hip⟩ ⟨j, hjp⟩ = (F q).2 ⟨i, hiq⟩ ⟨j, hjq⟩ := by
365+
have hpq' : (F p).snd ≍ (F q).snd := (Sigma.mk.inj_iff.1 hpq).2
366+
rw [Fin.heq_fun₂_iff Npq Npq] at hpq'
367+
rw [← hpq']
368+
rw [Ap, Aq] at this
387369
-- deduce that the distances coincide up to `ε`, by a straightforward computation
388370
-- that should be automated
389-
have I := calc
390-
|ε⁻¹| * |dist x y - dist (Ψ x) (Ψ y)| =
391-
|ε⁻¹ * (dist x y - dist (Ψ x) (Ψ y))| : (abs_mul _ _).symm
392-
... = |(ε⁻¹ * dist x y) - (ε⁻¹ * dist (Ψ x) (Ψ y))| : by { congr, ring }
393-
... ≤ 1 : le_of_lt (abs_sub_lt_one_of_floor_eq_floor this),
371+
have I :=
372+
calc
373+
ε⁻¹ * |dist x y - dist (Ψ x) (Ψ y)| = |ε⁻¹ * (dist x y - dist (Ψ x) (Ψ y))| := by
374+
rw [abs_mul, abs_of_nonneg (inv_pos.2 εpos).le]
375+
_ = |ε⁻¹ * dist x y - ε⁻¹ * dist (Ψ x) (Ψ y)| := by congr; ring
376+
_ ≤ 1 := le_of_lt (abs_sub_lt_one_of_floor_eq_floor this)
394377
calc
395-
|dist x y - dist (Ψ x) (Ψ y)| = (ε * ε⁻¹) * |dist x y - dist (Ψ x) (Ψ y)| :
396-
by rw [mul_inv_cancel (ne_of_gt εpos), one_mul]
397-
... = ε * (|ε⁻¹| * |dist x y - dist (Ψ x) (Ψ y)|) :
398-
by rw [abs_of_nonneg (le_of_lt (inv_pos.2 εpos)), mul_assoc]
399-
... ≤ ε * 1 : mul_le_mul_of_nonneg_left I (le_of_lt εpos)
400-
... = ε : mul_one _ } },
401-
calc dist p q = GH_dist p.rep (q.rep) : dist_GH_dist p q
402-
... ≤ ε + ε/2 + ε : main
403-
... = δ : by { simp only [ε], ring }
404-
end
378+
|dist x y - dist (Ψ x) (Ψ y)|
379+
_ = ε * (ε⁻¹ * |dist x y - dist (Ψ x) (Ψ y)|) := by grind
380+
_ ≤ ε * 1 := by gcongr
381+
_ = ε := mul_one _
382+
calc
383+
dist p q = ghDist p.Rep q.Rep := dist_ghDist p q
384+
_ ≤ ε + ε / 2 + ε := main
385+
_ = δ := by ring
405386
```
406387

407388
#### Are there warnings to the user when code should only be used in certain ways?

0 commit comments

Comments
 (0)