@@ -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
273273Whenever 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