From 28c58edf3f6436442c35802c8e88a1dffaa7d1bd Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Mon, 21 Sep 2026 18:02:37 +0000 Subject: [PATCH 01/16] Import complete 1mfld proof development --- LeanPool.lean | 1 + LeanPool/OneManifold.lean | 44 + LeanPool/OneManifold/OneMfld.lean | 7 + LeanPool/OneManifold/OneMfld/Charts.lean | 94 ++ .../OneManifold/OneMfld/CircleBlocks.lean | 292 ++++ LeanPool/OneManifold/OneMfld/CircleGlue.lean | 852 ++++++++++ .../OneManifold/OneMfld/Classification.lean | 414 +++++ .../OneManifold/OneMfld/ClassifyInterval.lean | 1380 +++++++++++++++++ .../OneManifold/OneMfld/ClassifyOverlaps.lean | 452 ++++++ .../OneManifold/OneMfld/ClosureOverlap.lean | 79 + LeanPool/OneManifold/OneMfld/Compactness.lean | 101 ++ .../OneMfld/FiniteIntervalCharts.lean | 29 + .../OneManifold/OneMfld/FinitelyCharted.lean | 61 + LeanPool/OneManifold/OneMfld/GlueBlocks.lean | 210 +++ LeanPool/OneManifold/OneMfld/GlueCore.lean | 267 ++++ LeanPool/OneManifold/OneMfld/GlueNNReal.lean | 208 +++ LeanPool/OneManifold/OneMfld/GlueUI.lean | 308 ++++ .../OneManifold/OneMfld/IntervalCharts.lean | 56 + .../OneManifold/OneMfld/LocallyConnected.lean | 165 ++ LeanPool/OneManifold/OneMfld/NiceCharts.lean | 202 +++ LeanPool/OneManifold/OneMfld/Noncompact.lean | 89 ++ LeanPool/OneManifold/OneMfld/Normalize.lean | 182 +++ LeanPool/OneManifold/OneMfld/Outer.lean | 364 +++++ .../OneMfld/PartialHomeomorphHelpers.lean | 48 + .../OneManifold/OneMfld/RealIntervals.lean | 486 ++++++ .../OneManifold/OneMfld/TransitionMono.lean | 49 + .../OneManifold/OneMfld/TwoComponents.lean | 443 ++++++ .../OneManifold/OneMfld/UnitInterval.lean | 22 + LeanPool/OneManifold/Solution.lean | 25 + LeanPool/projects.yml | 33 + 30 files changed, 6963 insertions(+) create mode 100644 LeanPool/OneManifold.lean create mode 100644 LeanPool/OneManifold/OneMfld.lean create mode 100644 LeanPool/OneManifold/OneMfld/Charts.lean create mode 100644 LeanPool/OneManifold/OneMfld/CircleBlocks.lean create mode 100644 LeanPool/OneManifold/OneMfld/CircleGlue.lean create mode 100644 LeanPool/OneManifold/OneMfld/Classification.lean create mode 100644 LeanPool/OneManifold/OneMfld/ClassifyInterval.lean create mode 100644 LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean create mode 100644 LeanPool/OneManifold/OneMfld/ClosureOverlap.lean create mode 100644 LeanPool/OneManifold/OneMfld/Compactness.lean create mode 100644 LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean create mode 100644 LeanPool/OneManifold/OneMfld/FinitelyCharted.lean create mode 100644 LeanPool/OneManifold/OneMfld/GlueBlocks.lean create mode 100644 LeanPool/OneManifold/OneMfld/GlueCore.lean create mode 100644 LeanPool/OneManifold/OneMfld/GlueNNReal.lean create mode 100644 LeanPool/OneManifold/OneMfld/GlueUI.lean create mode 100644 LeanPool/OneManifold/OneMfld/IntervalCharts.lean create mode 100644 LeanPool/OneManifold/OneMfld/LocallyConnected.lean create mode 100644 LeanPool/OneManifold/OneMfld/NiceCharts.lean create mode 100644 LeanPool/OneManifold/OneMfld/Noncompact.lean create mode 100644 LeanPool/OneManifold/OneMfld/Normalize.lean create mode 100644 LeanPool/OneManifold/OneMfld/Outer.lean create mode 100644 LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean create mode 100644 LeanPool/OneManifold/OneMfld/RealIntervals.lean create mode 100644 LeanPool/OneManifold/OneMfld/TransitionMono.lean create mode 100644 LeanPool/OneManifold/OneMfld/TwoComponents.lean create mode 100644 LeanPool/OneManifold/OneMfld/UnitInterval.lean create mode 100644 LeanPool/OneManifold/Solution.lean diff --git a/LeanPool.lean b/LeanPool.lean index 50fa6e5b30..2092a32a2d 100644 --- a/LeanPool.lean +++ b/LeanPool.lean @@ -5667,6 +5667,7 @@ import LeanPool.Odlyzko.TestFunction.TaylorBound import LeanPool.Odlyzko.Theta.PoissonSummation import LeanPool.Odlyzko.Theta.TraceDualIdeal import LeanPool.Odlyzko.Theta.TraceDualLattice +import LeanPool.OneManifold import LeanPool.OrderPQ import LeanPool.OrderPQ.Basic import LeanPool.OrderPQ.IsCyclic diff --git a/LeanPool/OneManifold.lean b/LeanPool/OneManifold.lean new file mode 100644 index 0000000000..ad174814ae --- /dev/null +++ b/LeanPool/OneManifold.lean @@ -0,0 +1,44 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ + +import LeanPool.OneManifold.OneMfld +import LeanPool.OneManifold.OneMfld.Charts +import LeanPool.OneManifold.OneMfld.CircleBlocks +import LeanPool.OneManifold.OneMfld.CircleGlue +import LeanPool.OneManifold.OneMfld.Classification +import LeanPool.OneManifold.OneMfld.ClassifyInterval +import LeanPool.OneManifold.OneMfld.ClassifyOverlaps +import LeanPool.OneManifold.OneMfld.ClosureOverlap +import LeanPool.OneManifold.OneMfld.Compactness +import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts +import LeanPool.OneManifold.OneMfld.FinitelyCharted +import LeanPool.OneManifold.OneMfld.GlueBlocks +import LeanPool.OneManifold.OneMfld.GlueCore +import LeanPool.OneManifold.OneMfld.GlueNNReal +import LeanPool.OneManifold.OneMfld.GlueUI +import LeanPool.OneManifold.OneMfld.IntervalCharts +import LeanPool.OneManifold.OneMfld.LocallyConnected +import LeanPool.OneManifold.OneMfld.NiceCharts +import LeanPool.OneManifold.OneMfld.Noncompact +import LeanPool.OneManifold.OneMfld.Normalize +import LeanPool.OneManifold.OneMfld.Outer +import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers +import LeanPool.OneManifold.OneMfld.RealIntervals +import LeanPool.OneManifold.OneMfld.TransitionMono +import LeanPool.OneManifold.OneMfld.TwoComponents +import LeanPool.OneManifold.OneMfld.UnitInterval +import LeanPool.OneManifold.Solution + +/-! +# The classification of compact 1-manifolds + +Source: url:https://github.com/sweeneyde/1mfld +Authors: Jim Fowler, Dennis Sweeney +Status: verified +Main declarations: `OneMfld.homeomorph_circle_or_unitInterval` +Tags: topology +MSC: 57N99, 54F65, 68V20 +-/ diff --git a/LeanPool/OneManifold/OneMfld.lean b/LeanPool/OneManifold/OneMfld.lean new file mode 100644 index 0000000000..1750f08943 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld.lean @@ -0,0 +1,7 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import LeanPool.OneManifold.OneMfld.Classification + diff --git a/LeanPool/OneManifold/OneMfld/Charts.lean b/LeanPool/OneManifold/OneMfld/Charts.lean new file mode 100644 index 0000000000..d052fb421d --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/Charts.lean @@ -0,0 +1,94 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers + +/-! Interval charts on a 1-manifold charted on `ℝ≥0`, and the `Overlap` relation. + +An `OChart` has an open-interval target `Ioo x y` (an interior chart); an `HChart` has a +half-open target `Iio x` (a boundary chart); an `IChart` is either. +-/ + +structure OChart (M : Type*) [TopologicalSpace M] + extends OpenPartialHomeomorph M NNReal where + target_ioo : (∃ x y, (Set.Ioo x y = target)) + +structure HChart (M : Type*) [TopologicalSpace M] + extends OpenPartialHomeomorph M NNReal where + target_iio : (∃ x, (Set.Iio x = target)) + +structure IChart (M : Type*) [TopologicalSpace M] + extends OpenPartialHomeomorph M NNReal where + is_interval : (∃ x y, (Set.Ioo x y = target)) ∨ (∃ x, (Set.Iio x = target)) + +variable + {M : Type*} + [TopologicalSpace M] + +def OChart.toIChart (a : OChart M) : IChart M := + { a with is_interval := Or.inl a.target_ioo } + +def HChart.toIChart (a : HChart M) : IChart M := + { a with is_interval := Or.inr a.target_iio } + +def Overlap (U : Set α) (V : Set α) : Prop := + (U ∩ V).Nonempty ∧ (U \ V).Nonempty ∧ (V \ U).Nonempty + +theorem does_overlap' (U : Set α) (V : Set α) (hu : ¬ U ⊆ V) + : (U \ V).Nonempty := Set.sdiff_nonempty.mpr hu + +theorem does_overlap (U : Set α) (V : Set α) (h : (U ∩ V).Nonempty) (hu : ¬ U ⊆ V) (hv : ¬ V ⊆ U) + : Overlap U V := by + apply And.intro + · exact h + · apply And.intro + · exact does_overlap' U V hu + · exact does_overlap' V U hv + +theorem overlap_symm {U : Set α} {V : Set α} (h : Overlap U V) : Overlap V U := by + dsimp [Overlap] at h + apply And.intro + · exact Set.inter_nonempty_iff_exists_right.mpr h.1 + · apply And.intro + · exact h.2.2 + · exact h.2.1 + +lemma Overlap.nonempty {U : Set α} {V : Set α} (h : Overlap U V) : (Nonempty U) ∧ (Nonempty V) := by + have nonempty : (U ∩ V).Nonempty := h.1 + apply And.intro + · exact Set.Nonempty.to_subtype (Set.Nonempty.left nonempty) + · exact Set.Nonempty.to_subtype (Set.Nonempty.right nonempty) + +lemma chart_target_nonempty (φ : OpenPartialHomeomorph M NNReal) (h : φ.source.Nonempty) : + φ.target.Nonempty := by + rw [← PartialEquiv.image_source_eq_target φ.toPartialEquiv] + exact h.image _ + +lemma OChart.connected_source (a : OChart M) (h : a.source.Nonempty) : + IsConnected a.source := by + apply (partial_homeo_source_connected_iff_target_connected a.toOpenPartialHomeomorph).mpr + obtain ⟨x, y, hxy⟩ := a.target_ioo + have hne : a.target.Nonempty := chart_target_nonempty _ h + rw [←hxy] at hne ⊢ + exact isConnected_Ioo (Set.nonempty_Ioo.mp hne) + +lemma HChart.connected_source (a : HChart M) (h : a.source.Nonempty) : + IsConnected a.source := by + apply (partial_homeo_source_connected_iff_target_connected a.toOpenPartialHomeomorph).mpr + obtain ⟨x, hx⟩ := a.target_iio + have hne : a.target.Nonempty := chart_target_nonempty _ h + rw [←hx] at hne ⊢ + exact ⟨hne, isPreconnected_Iio⟩ + +lemma IChart.connected_source (a : IChart M) (h : a.source.Nonempty) : + IsConnected a.source := by + apply (partial_homeo_source_connected_iff_target_connected a.toOpenPartialHomeomorph).mpr + have hne : a.target.Nonempty := chart_target_nonempty _ h + rcases a.is_interval with (⟨x, y, hxy⟩ | ⟨x, hx⟩) + · rw [←hxy] at hne ⊢ + exact isConnected_Ioo (Set.nonempty_Ioo.mp hne) + · rw [←hx] at hne ⊢ + exact ⟨hne, isPreconnected_Iio⟩ diff --git a/LeanPool/OneManifold/OneMfld/CircleBlocks.lean b/LeanPool/OneManifold/OneMfld/CircleBlocks.lean new file mode 100644 index 0000000000..1d1db78a2e --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/CircleBlocks.lean @@ -0,0 +1,292 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib + +/-! # Building blocks for the circle case + +* `mobiusFun c` — the Möbius reparametrization `x ↦ x / (x + c(1-x))` of the unit + interval in `ℝ≥0`, packaged as an `OpenPartialHomeomorph` with its image lemmas: it + lets us shrink the lower overlap component of a chart to sit below any `ε > 0` while + preserving the end-segment structure of images. +* `affineNNRealOPH k d` — the affine chart `x ↦ k·x + d` from `Ioo 0 1 ⊆ ℝ≥0` onto + `Ioo d (d + k) ⊆ ℝ`. +* Arithmetic for arcs in `AddCircle 1`: injectivity of the quotient map on short + windows, period-shift identities, the frontier of a closed arc, and the covering of + the circle by a closed arc and its complementary open arc. +-/ + +open Set + +noncomputable section + +/-- The Möbius reparametrization of the unit interval of `ℝ≥0`. -/ +def mobiusFun (c x : NNReal) : NNReal := x / (x + c * (1 - x)) + +/-- `mobiusFun c` can push any interior point below any positive level, for large `c`. -/ +lemma exists_mobiusFun_lt {r ε : NNReal} (hr0 : 0 < r) (hr1 : r < 1) (hε : 0 < ε) : + ∃ c : NNReal, 0 < c ∧ mobiusFun c r < ε := by + have h1r : 0 < 1 - r := tsub_pos_of_lt hr1 + have hden : 0 < ε * (1 - r) := mul_pos hε h1r + refine ⟨r / (ε * (1 - r)), div_pos hr0 hden, ?_⟩ + rw [mobiusFun, div_lt_iff₀ (lt_of_lt_of_le hr0 le_self_add)] + have hkey : r / (ε * (1 - r)) * (1 - r) = r / ε := by + rw [div_mul_eq_mul_div, mul_comm ε (1 - r), ← div_div, + mul_div_cancel_right₀ _ h1r.ne'] + rw [mul_add, hkey, ← mul_div_assoc, mul_div_cancel_left₀ _ hε.ne'] + exact lt_add_of_pos_left r (mul_pos hε hr0) + +lemma mobiusFun_strictMonoOn (c : NNReal) (hc : 0 < c) : + StrictMonoOn (mobiusFun c) (Ioo 0 1) := by + intro x hx y hy hxy + have hdx : 0 < x + c * (1 - x) := lt_of_lt_of_le hx.1 le_self_add + have hdy : 0 < y + c * (1 - y) := lt_of_lt_of_le hy.1 le_self_add + rw [mobiusFun, mobiusFun, div_lt_div_iff₀ hdx hdy] + rw [← NNReal.coe_lt_coe] + push_cast [NNReal.coe_sub hx.2.le, NNReal.coe_sub hy.2.le] + have hc' : (0:ℝ) < c := hc + have hxy' : (x:ℝ) < y := hxy + nlinarith [mul_pos hc' (sub_pos.mpr hxy')] + +lemma mobiusFun_mem (c : NNReal) (hc : 0 < c) {t : NNReal} (ht : t ∈ Ioo (0:NNReal) 1) : + mobiusFun c t ∈ Ioo (0:NNReal) 1 := by + have hden : 0 < t + c * (1 - t) := lt_of_lt_of_le ht.1 le_self_add + refine ⟨div_pos ht.1 hden, ?_⟩ + rw [mobiusFun, div_lt_one hden] + exact lt_add_of_pos_right t (mul_pos hc (tsub_pos_of_lt ht.2)) + +/-- The Möbius reparametrization as a partial homeomorphism of `Ioo 0 1 ⊆ ℝ≥0`, with +its action on lower and upper end-segments. -/ +def mobiusOPH' (c : NNReal) (hc : 0 < c) : + { e : OpenPartialHomeomorph NNReal NNReal // + e.source = Ioo 0 1 ∧ e.target = Ioo 0 1 ∧ + (∀ x : NNReal, e.toFun x = mobiusFun c x) ∧ + (∀ t ∈ Ioo (0:NNReal) 1, e.toFun '' (Ioo 0 t) = Ioo 0 (mobiusFun c t)) ∧ + (∀ t ∈ Ioo (0:NNReal) 1, e.toFun '' (Ioo t 1) = Ioo (mobiusFun c t) 1) } := by + have hc' : (0:ℝ) < c := hc + -- the inverse function + have hgmem : ∀ y ∈ Ioo (0:NNReal) 1, c * y / ((1 - y) + c * y) ∈ Ioo (0:NNReal) 1 := by + intro y hy + have hden : 0 < (1 - y) + c * y := + lt_of_lt_of_le (tsub_pos_of_lt hy.2) le_self_add + exact ⟨div_pos (mul_pos hc hy.1) hden, + (div_lt_one hden).mpr (lt_add_of_pos_left _ (tsub_pos_of_lt hy.2))⟩ + have hcoe_mobius : ∀ x : NNReal, x ≤ 1 → + ((mobiusFun c x : NNReal) : ℝ) = (x:ℝ) / ((x:ℝ) + c * (1 - (x:ℝ))) := by + intro x hx1 + rw [mobiusFun] + push_cast [NNReal.coe_sub hx1] + ring + have hleft : ∀ x ∈ Ioo (0:NNReal) 1, + c * mobiusFun c x / ((1 - mobiusFun c x) + c * mobiusFun c x) = x := by + intro x hx + have hfx := mobiusFun_mem c hc hx + have hX0 : (0:ℝ) < x := hx.1 + have hX1 : (x:ℝ) < 1 := hx.2 + have hD : (0:ℝ) < (x:ℝ) + c * (1 - (x:ℝ)) := by nlinarith + apply NNReal.coe_injective + push_cast [NNReal.coe_sub hfx.2.le, hcoe_mobius x hx.2.le] + have hkey : (1 - (x:ℝ) / ((x:ℝ) + c * (1 - (x:ℝ)))) + + c * ((x:ℝ) / ((x:ℝ) + c * (1 - (x:ℝ)))) = c / ((x:ℝ) + c * (1 - (x:ℝ))) := by + field_simp + ring + rw [hkey] + field_simp + have hright : ∀ y ∈ Ioo (0:NNReal) 1, + mobiusFun c (c * y / ((1 - y) + c * y)) = y := by + intro y hy + have hgy := hgmem y hy + have hY0 : (0:ℝ) < y := hy.1 + have hY1 : (y:ℝ) < 1 := hy.2 + have hE : (0:ℝ) < (1 - (y:ℝ)) + c * (y:ℝ) := by nlinarith + have hgy_coe : ((c * y / ((1 - y) + c * y) : NNReal) : ℝ) + = c * (y:ℝ) / ((1 - (y:ℝ)) + c * (y:ℝ)) := by + push_cast [NNReal.coe_sub hy.2.le] + ring + apply NNReal.coe_injective + rw [hcoe_mobius _ hgy.2.le, hgy_coe] + have hkey : c * (y:ℝ) / ((1 - (y:ℝ)) + c * (y:ℝ)) + + c * (1 - c * (y:ℝ) / ((1 - (y:ℝ)) + c * (y:ℝ))) + = c / ((1 - (y:ℝ)) + c * (y:ℝ)) := by + field_simp + ring + rw [hkey] + field_simp + refine ⟨{ toFun := mobiusFun c + invFun := fun y => c * y / ((1 - y) + c * y) + source := Ioo 0 1 + target := Ioo 0 1 + map_source' := fun x hx => mobiusFun_mem c hc hx + map_target' := hgmem + left_inv' := fun x hx => hleft x hx + right_inv' := fun y hy => hright y hy + open_source := isOpen_Ioo + open_target := isOpen_Ioo + continuousOn_toFun := ?_ + continuousOn_invFun := ?_ }, + rfl, rfl, fun x => rfl, ?_, ?_⟩ + · show ContinuousOn (fun x : NNReal => x / (x + c * (1 - x))) (Ioo 0 1) + exact ContinuousOn.div continuousOn_id + ((continuous_id.add (continuous_const.mul (continuous_const.sub continuous_id))).continuousOn) + (fun x hx => (lt_of_lt_of_le hx.1 le_self_add).ne') + · exact ContinuousOn.div (continuous_const.mul continuous_id).continuousOn + (((continuous_const.sub continuous_id).add + (continuous_const.mul continuous_id)).continuousOn) + (fun y hy => (lt_of_lt_of_le (tsub_pos_of_lt hy.2) le_self_add).ne') + · -- lower end-segment + intro t ht + ext z + constructor + · rintro ⟨x, hx, rfl⟩ + have hx1 : x ∈ Ioo (0:NNReal) 1 := ⟨hx.1, hx.2.trans ht.2⟩ + exact ⟨(mobiusFun_mem c hc hx1).1, mobiusFun_strictMonoOn c hc hx1 ht hx.2⟩ + · intro hz + have hz1 : z ∈ Ioo (0:NNReal) 1 := ⟨hz.1, hz.2.trans (mobiusFun_mem c hc ht).2⟩ + have hmem := hgmem z hz1 + refine ⟨c * z / ((1 - z) + c * z), ⟨hmem.1, ?_⟩, hright z hz1⟩ + by_contra hcon + rw [not_lt] at hcon + have := (mobiusFun_strictMonoOn c hc).monotoneOn ht hmem hcon + rw [hright z hz1] at this + exact absurd hz.2 (not_lt.mpr this) + · -- upper end-segment + intro t ht + ext z + constructor + · rintro ⟨x, hx, rfl⟩ + have hx1 : x ∈ Ioo (0:NNReal) 1 := ⟨ht.1.trans hx.1, hx.2⟩ + exact ⟨mobiusFun_strictMonoOn c hc ht hx1 hx.1, (mobiusFun_mem c hc hx1).2⟩ + · intro hz + have hz1 : z ∈ Ioo (0:NNReal) 1 := ⟨lt_trans (mobiusFun_mem c hc ht).1 hz.1, hz.2⟩ + have hmem := hgmem z hz1 + refine ⟨c * z / ((1 - z) + c * z), ⟨?_, hmem.2⟩, hright z hz1⟩ + by_contra hcon + rw [not_lt] at hcon + have := (mobiusFun_strictMonoOn c hc).monotoneOn hmem ht hcon + rw [hright z hz1] at this + exact absurd hz.1 (not_lt.mpr this) + +/-- The affine map `x ↦ k·x + d` as a chart from `Ioo 0 1 ⊆ ℝ≥0` onto +`Ioo d (d + k) ⊆ ℝ`. -/ +def affineNNRealOPH (k d : ℝ) (hk : 0 < k) : + { e : OpenPartialHomeomorph NNReal ℝ // + e.source = Ioo 0 1 ∧ e.target = Ioo d (d + k) ∧ + ∀ x : NNReal, e.toFun x = k * (x : ℝ) + d } := by + refine ⟨{ toFun := fun x => k * (x : ℝ) + d + invFun := fun y => Real.toNNReal ((y - d) / k) + source := Ioo 0 1 + target := Ioo d (d + k) + map_source' := ?_ + map_target' := ?_ + left_inv' := ?_ + right_inv' := ?_ + open_source := isOpen_Ioo + open_target := isOpen_Ioo + continuousOn_toFun := + ((continuous_const.mul NNReal.continuous_coe).add continuous_const).continuousOn + continuousOn_invFun := + (continuous_real_toNNReal.comp + ((continuous_id.sub continuous_const).div_const k)).continuousOn }, + rfl, rfl, fun x => rfl⟩ + · intro x hx + have hx0 : (0:ℝ) < x := hx.1 + have hx1 : (x:ℝ) < 1 := hx.2 + constructor + · nlinarith + · nlinarith + · intro y hy + exact ⟨Real.toNNReal_pos.mpr (div_pos (sub_pos.mpr hy.1) hk), + Real.toNNReal_lt_one.mpr ((div_lt_one hk).mpr (by linarith [hy.2]))⟩ + · intro x _ + show Real.toNNReal ((k * (x:ℝ) + d - d) / k) = x + have h : (k * (x:ℝ) + d - d) / k = (x:ℝ) := by + field_simp + ring + rw [h, Real.toNNReal_coe] + · intro y hy + show k * ((Real.toNNReal ((y - d) / k) : NNReal) : ℝ) + d = y + rw [Real.coe_toNNReal _ (div_nonneg (sub_nonneg.mpr hy.1.le) hk.le)] + field_simp + ring + +section AddCircleArith + +/-- Two reals with the same image in `AddCircle 1` and distance less than `1` are +equal. -/ +lemma addCircle_coe_inj {x y : ℝ} (h : (x : AddCircle (1:ℝ)) = (y : AddCircle (1:ℝ))) + (hxy : |x - y| < 1) : x = y := by + have h0 : ((x - y : ℝ) : AddCircle (1:ℝ)) = 0 := by + rw [AddCircle.coe_sub, h, sub_self] + obtain ⟨n, hn⟩ := (AddCircle.coe_eq_zero_iff _).mp h0 + rw [zsmul_one] at hn + have h1 : |(n:ℝ)| < 1 := by rw [hn]; exact hxy + have h2 : |n| < 1 := by exact_mod_cast h1 + have h3 : n = 0 := Int.abs_lt_one_iff.mp h2 + rw [h3] at hn + simp only [Int.cast_zero] at hn + linarith + +/-- Shifting a real by the period `1` does not change its image in `AddCircle 1`. -/ +lemma addCircle_coe_add_one (x : ℝ) : + ((x + 1 : ℝ) : AddCircle (1:ℝ)) = (x : AddCircle (1:ℝ)) := + AddCircle.coe_add_period 1 x + +/-- The closed arc `coe '' Icc c d` is closed in `AddCircle 1`. -/ +lemma addCircle_arc_isClosed (c d : ℝ) : + IsClosed (((↑) : ℝ → AddCircle (1:ℝ)) '' Icc c d) := by + have : Fact ((0:ℝ) < 1) := ⟨one_pos⟩ + exact (isCompact_Icc.image (AddCircle.continuous_mk' 1)).isClosed + +/-- The open arc `coe '' Ioo c d` is open in `AddCircle 1`. -/ +lemma addCircle_arc_isOpen (c d : ℝ) : + IsOpen (((↑) : ℝ → AddCircle (1:ℝ)) '' Ioo c d) := + QuotientAddGroup.isOpenMap_coe _ isOpen_Ioo + +/-- The frontier of a closed arc is contained in its two endpoints. -/ +lemma addCircle_frontier_arc_subset {c d : ℝ} (hcd : c ≤ d) : + frontier (((↑) : ℝ → AddCircle (1:ℝ)) '' Icc c d) ⊆ + {((c : ℝ) : AddCircle (1:ℝ)), ((d : ℝ) : AddCircle (1:ℝ))} := by + have hclosed := addCircle_arc_isClosed c d + have hopen := addCircle_arc_isOpen c d + have hint : ((↑) : ℝ → AddCircle (1:ℝ)) '' Ioo c d ⊆ + interior (((↑) : ℝ → AddCircle (1:ℝ)) '' Icc c d) := + interior_maximal (image_mono Ioo_subset_Icc_self) hopen + intro z hz + rw [hclosed.frontier_eq] at hz + obtain ⟨⟨y, hy, rfl⟩, hz2⟩ := hz + have hnot : y ∉ Ioo c d := fun hy' => hz2 (hint ⟨y, hy', rfl⟩) + have hy' : y = c ∨ y = d := by + rcases lt_or_eq_of_le hy.1 with h1 | h1 + · rcases lt_or_eq_of_le hy.2 with h2 | h2 + · exact absurd ⟨h1, h2⟩ hnot + · exact Or.inr h2 + · exact Or.inl h1.symm + rcases hy' with rfl | rfl + · exact mem_insert _ _ + · exact mem_insert_of_mem _ (mem_singleton _) + +/-- A closed arc and the complementary open arc cover the circle. -/ +lemma addCircle_arc_union_covers {c d : ℝ} (hcd : c ≤ d) (hlen : d < c + 1) : + (((↑) : ℝ → AddCircle (1:ℝ)) '' Icc c d) ∪ + (((↑) : ℝ → AddCircle (1:ℝ)) '' Ioo d (c + 1)) = univ := by + have : Fact ((0:ℝ) < 1) := ⟨one_pos⟩ + rw [← image_union] + have hsets : Icc c d ∪ Ioo d (c + 1) = Ico c (c + 1) := by + ext x + simp only [mem_union, mem_Icc, mem_Ioo, mem_Ico] + constructor + · rintro (⟨h1, h2⟩ | ⟨h1, h2⟩) + · exact ⟨h1, lt_of_le_of_lt h2 hlen⟩ + · exact ⟨hcd.trans h1.le, h2⟩ + · rintro ⟨h1, h2⟩ + rcases le_or_gt x d with h | h + · exact Or.inl ⟨h1, h⟩ + · exact Or.inr ⟨h, h2⟩ + rw [hsets] + exact AddCircle.coe_image_Ico_eq 1 c + +end AddCircleArith + +end diff --git a/LeanPool/OneManifold/OneMfld/CircleGlue.lean b/LeanPool/OneManifold/OneMfld/CircleGlue.lean new file mode 100644 index 0000000000..a12c42fb21 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/CircleGlue.lean @@ -0,0 +1,852 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.Charts +import LeanPool.OneManifold.OneMfld.Normalize +import LeanPool.OneManifold.OneMfld.GlueBlocks +import LeanPool.OneManifold.OneMfld.TwoComponents +import LeanPool.OneManifold.OneMfld.CircleBlocks + +/-! # The circle chart + +Two interior charts whose overlap is disconnected wrap around and close `M` into a +circle: after normalizing, the overlap has exactly two components, one at each end of +each chart. We shrink the charts' coordinates (Möbius) into a controlled numeric regime, +choose a split point in each component, and glue the two charts — each embedded as an +arc of `AddCircle 1` — with `OpenPartialHomeomorph.piecewise` along a closed sub-arc +whose frontier is the two split points. The result is a chart of `M` onto the whole of +`AddCircle 1` with source `a.source ∪ b.source`. +-/ + +open Set + +/-! ### Small helpers -/ + +/-- Two reals with the same image in `AddCircle 1` differ by an integer. -/ +private lemma addCircle_coe_eq_iff_int {x y : ℝ} : + (x : AddCircle (1:ℝ)) = (y : AddCircle (1:ℝ)) ↔ ∃ n : ℤ, x - y = (n : ℝ) := by + rw [QuotientAddGroup.eq_iff_sub_mem] + constructor + · intro h + obtain ⟨n, hn⟩ := AddSubgroup.mem_zmultiples_iff.mp h + exact ⟨n, by rw [← hn, zsmul_eq_mul, mul_one]⟩ + · rintro ⟨n, hn⟩ + exact AddSubgroup.mem_zmultiples_iff.mpr ⟨n, by rw [zsmul_eq_mul, mul_one, hn]⟩ + +/-- Window analysis: two reals with the same circle image and difference in `(-1, 2)` +are equal or differ by exactly one period. -/ +private lemma addCircle_eq_or_eq_add_one {x y : ℝ} + (h : (x : AddCircle (1:ℝ)) = (y : AddCircle (1:ℝ))) + (h1 : -1 < x - y) (h2 : x - y < 2) : x = y ∨ x = y + 1 := by + obtain ⟨n, hn⟩ := addCircle_coe_eq_iff_int.mp h + have hn1 : (-1 : ℝ) < (n : ℝ) := hn ▸ h1 + have hn2 : ((n : ℤ) : ℝ) < 2 := hn ▸ h2 + have hn1' : (-1 : ℤ) < n := by exact_mod_cast hn1 + have hn2' : n < 2 := by exact_mod_cast hn2 + interval_cases n + · left + have : x - y = 0 := by rw [hn]; norm_num + linarith + · right + have : x - y = 1 := by rw [hn]; norm_num + linarith + +/-- Pull membership in a chart image back to membership in the set, using injectivity. -/ +private lemma mem_of_image_mem {M : Type*} [TopologicalSpace M] + (e : OpenPartialHomeomorph M NNReal) {W : Set M} {I : Set NNReal} + (hW : W ⊆ e.source) (himg : e '' W = I) {x : M} (hx : x ∈ e.source) + (hval : e x ∈ I) : x ∈ W := by + rw [← himg] at hval + obtain ⟨w, hw, hvw⟩ := hval + rwa [← e.injOn (hW hw) hx hvw] + +/-- A strictly increasing correspondence on `W` matches lower cuts at a point of `W`. -/ +private lemma mono_key_le {M : Type*} [TopologicalSpace M] + (A B : OpenPartialHomeomorph M NNReal) + {W : Set M} (hWA : W ⊆ A.source) + (mono : ∀ x ∈ W, ∀ y ∈ W, A x < A y → B x < B y) + {m : M} (hm : m ∈ W) : + ∀ x ∈ W, (A m ≤ A x ↔ B m ≤ B x) := by + intro x hx + constructor + · intro hle + rcases eq_or_lt_of_le hle with heq | hlt + · rw [A.injOn (hWA hm) (hWA hx) heq] + · exact (mono m hm x hx hlt).le + · intro hle + by_contra hgt + rw [not_le] at hgt + exact absurd hle (not_le.2 (mono x hx m hm hgt)) + +/-- A strictly increasing correspondence on `W` matches upper cuts at a point of `W`. -/ +private lemma mono_key_ge {M : Type*} [TopologicalSpace M] + (A B : OpenPartialHomeomorph M NNReal) + {W : Set M} (hWA : W ⊆ A.source) + (mono : ∀ x ∈ W, ∀ y ∈ W, A x < A y → B x < B y) + {m : M} (hm : m ∈ W) : + ∀ x ∈ W, (A x ≤ A m ↔ B x ≤ B m) := by + intro x hx + constructor + · intro hle + rcases eq_or_lt_of_le hle with heq | hlt + · rw [A.injOn (hWA hx) (hWA hm) heq] + · exact (mono x hx m hm hlt).le + · intro hle + by_contra hgt + rw [not_le] at hgt + exact absurd hle (not_le.2 (mono m hm x hx hgt)) + +/-- The real parameters of the circle gluing: slopes `kα`, `kg` and offset `g0` with the +matching identities and strict separation inequalities. -/ +private lemma circle_params {ρ ν σ μ : ℝ} + (hρ0 : 0 < ρ) (hρ4 : ρ < 1/4) (hν3 : 3/4 < ν) (hν1 : ν < 1) + (hσ0 : 0 < σ) (hσ4 : σ < 1/4) (hμ3 : 3/4 < μ) (hμ1 : μ < 1) : + ∃ kα kg g0 : ℝ, 0 < kα ∧ kα < 1 ∧ 0 < kg ∧ kg < 1 ∧ + kg * σ + g0 = kα * ν ∧ + kg * μ + g0 = 1 + kα * ρ ∧ + kα * ρ < g0 ∧ + g0 < kα * ν ∧ + 1 + kα * ρ < g0 + kg ∧ + g0 + kg < 1 + kα * ν := by + have hνρ : 1/2 < ν - ρ := by linarith + have hμσ0 : 0 < μ - σ := by linarith + have hd1 : (1 - μ + σ)/(ν - ρ) < 1 := by + rw [div_lt_one (by linarith)] + linarith + have h23 : (2/3 : ℝ) < 1 := by norm_num + obtain ⟨kα, hkα1, hkα2⟩ := exists_between (max_lt hd1 h23) + have hkα23 : (2/3 : ℝ) < kα := lt_of_le_of_lt (le_max_right _ _) hkα1 + have hkαd : (1 - μ + σ)/(ν - ρ) < kα := lt_of_le_of_lt (le_max_left _ _) hkα1 + have hkα0 : (0:ℝ) < kα := by linarith + have hnum : 0 < 1 - kα * (ν - ρ) := by + nlinarith [mul_pos (show (0:ℝ) < 1 - kα by linarith) (show (0:ℝ) < ν - ρ by linarith)] + set kg := (1 - kα * (ν - ρ)) / (μ - σ) with hkgdef + have hkg0 : 0 < kg := div_pos hnum hμσ0 + have hkgden : kg * (μ - σ) = 1 - kα * (ν - ρ) := div_mul_cancel₀ _ hμσ0.ne' + have hkg1 : kg < 1 := by + rw [hkgdef, div_lt_one hμσ0] + have := (div_lt_iff₀ (show (0:ℝ) < ν - ρ by linarith)).mp hkαd + linarith + set g0 := kα * ν - kg * σ with hg0def + have hid1 : kg * σ + g0 = kα * ν := by rw [hg0def]; ring + have hid2 : kg * μ + g0 = 1 + kα * ρ := by + rw [hg0def]; linear_combination hkgden + have hP1 : (1/3 : ℝ) < kα * (ν - ρ) := by nlinarith + have hP2 : (1/4 : ℝ) < kα * (ν - ρ) * μ := by nlinarith + have hkey : σ < kα * (ν - ρ) * μ := by linarith + have hc₁g0 : kα * ρ < g0 := by + have h2 : kg * σ * (μ - σ) = σ * (1 - kα * (ν - ρ)) := by + rw [← hkgden]; ring + have h3 : kg * σ * (μ - σ) < kα * (ν - ρ) * (μ - σ) := by + rw [h2]; nlinarith + have h4 : kg * σ < kα * (ν - ρ) := lt_of_mul_lt_mul_right h3 hμσ0.le + rw [hg0def]; nlinarith + have hg0d : g0 < kα * ν := by + rw [hg0def] + nlinarith [mul_pos hkg0 hσ0] + have h1c : 1 + kα * ρ < g0 + kg := by + nlinarith [hid2, mul_pos hkg0 (show (0:ℝ) < 1 - μ by linarith)] + have hg1d : g0 + kg < 1 + kα * ν := by + nlinarith [hid1, mul_pos hkg0 hσ0] + exact ⟨kα, kg, g0, hkα0, hkα2, hkg0, hkg1, hid1, hid2, hc₁g0, hg0d, h1c, hg1d⟩ + +/-- The target of a chart of the form `x ↦ coe (k * X x + d)` (with `X` landing onto +`Ioo 0 1`) is the arc `coe '' Ioo d (d + k)`. -/ +private lemma affine_circle_target {M : Type*} [TopologicalSpace M] + (X : OpenPartialHomeomorph M NNReal) (hXt : X.target = Ioo 0 1) + (E : OpenPartialHomeomorph M (AddCircle (1:ℝ))) + (hEs : E.source = X.source) {k d : ℝ} (hk : 0 < k) + (hEval : ∀ x ∈ X.source, E x = ((k * ((X x : NNReal) : ℝ) + d : ℝ) : AddCircle (1:ℝ))) : + E.target = ((↑) : ℝ → AddCircle (1:ℝ)) '' (Ioo d (d + k)) := by + rw [← E.image_source_eq_target, hEs] + ext z + constructor + · rintro ⟨x, hx, rfl⟩ + rw [hEval x hx] + have hXx : X x ∈ Ioo (0:NNReal) 1 := hXt ▸ X.map_source hx + have h0 : (0:ℝ) < ((X x : NNReal) : ℝ) := by exact_mod_cast hXx.1 + have h1 : ((X x : NNReal) : ℝ) < 1 := by exact_mod_cast hXx.2 + exact mem_image_of_mem _ ⟨by nlinarith, by nlinarith⟩ + · rintro ⟨u, hu, rfl⟩ + have h0 : 0 < (u - d)/k := div_pos (by linarith [hu.1]) hk + have h1 : (u - d)/k < 1 := (div_lt_one hk).mpr (by linarith [hu.2]) + set t := Real.toNNReal ((u - d)/k) with htdef + have htc : (t : ℝ) = (u - d)/k := Real.coe_toNNReal _ h0.le + have ht : t ∈ Ioo (0:NNReal) 1 := by + constructor + · rw [← NNReal.coe_lt_coe, NNReal.coe_zero, htc]; exact h0 + · rw [← NNReal.coe_lt_coe, NNReal.coe_one, htc]; exact h1 + have htT : t ∈ X.target := hXt ▸ ht + refine ⟨X.symm t, X.map_target htT, ?_⟩ + rw [hEval _ (X.map_target htT), X.right_inv htT, htc] + congr 1 + field_simp + ring + +/-- Normalize both charts to target `Ioo 0 1`, split the overlap into its two +components, orient the second chart so the component lower in `a` is upper in `b`, and +Möbius-shrink both charts so the lower end-segments sit below `1/4`. -/ +private lemma exists_normalized_charts {M : Type*} [TopologicalSpace M] [T2Space M] + (a b : OChart M) (h : Overlap a.source b.source) + (hdisc : ¬ IsConnected (a.source ∩ b.source)) : + ∃ (A B : OpenPartialHomeomorph M NNReal) (W₀ W₁ : Set M) (r p s q : NNReal), + A.source = a.source ∧ B.source = b.source ∧ + A.target = Ioo 0 1 ∧ B.target = Ioo 0 1 ∧ + A.source ∩ B.source = W₀ ∪ W₁ ∧ + A '' W₀ = Ioo 0 r ∧ A '' W₁ = Ioo p 1 ∧ + B '' W₀ = Ioo q 1 ∧ B '' W₁ = Ioo 0 s ∧ + 0 < r ∧ r ≤ p ∧ p < 1 ∧ r < 1/4 ∧ + 0 < s ∧ s ≤ q ∧ q < 1 ∧ s < 1/4 := by + have hane : a.source.Nonempty := h.1.mono inter_subset_left + have hbne : b.source.Nonempty := h.1.mono inter_subset_right + obtain ⟨a₀, ha₀s, ha₀t, -⟩ := a.rescale hane + obtain ⟨b₀, hb₀s, hb₀t, -⟩ := b.rescale hbne + have hab : (a₀.source \ b₀.source).Nonempty := by rw [ha₀s, hb₀s]; exact h.2.1 + have hba : (b₀.source \ a₀.source).Nonempty := by rw [ha₀s, hb₀s]; exact h.2.2 + have hne : (a₀.source ∩ b₀.source).Nonempty := by rw [ha₀s, hb₀s]; exact h.1 + have hdisc' : ¬ IsConnected (a₀.source ∩ b₀.source) := by rw [ha₀s, hb₀s]; exact hdisc + have hbconn : IsConnected b₀.source := b₀.connected_source (hb₀s ▸ hbne) + obtain ⟨W₀, W₁, r₀, p₁, hunion, hcomp₀, hcomp₁, hdisj, himgA₀, himgA₁, hr₀0, hr₀p, hp₁1⟩ := + two_components_structure a₀.toOpenPartialHomeomorph b₀.toOpenPartialHomeomorph + ha₀t hbconn hab hba hne hdisc' + have hW₀S : W₀ ⊆ a₀.source ∩ b₀.source := by rw [hunion]; exact subset_union_left + have hW₁S : W₁ ⊆ a₀.source ∩ b₀.source := by rw [hunion]; exact subset_union_right + have hne₀ : W₀.Nonempty := by + have himg : (a₀.toOpenPartialHomeomorph '' W₀).Nonempty := by + rw [himgA₀]; exact nonempty_Ioo.2 hr₀0 + exact himg.of_image + have hne₁ : W₁.Nonempty := by + have himg : (a₀.toOpenPartialHomeomorph '' W₁).Nonempty := by + rw [himgA₁]; exact nonempty_Ioo.2 hp₁1 + exact himg.of_image + have haconn : IsConnected a₀.source := a₀.connected_source (ha₀s ▸ hane) + obtain ⟨s₁, q₀, hs₁0, hs₁q₀, hq₀1, harr⟩ := + two_components_other_chart a₀.toOpenPartialHomeomorph b₀.toOpenPartialHomeomorph + hb₀t haconn hab hcomp₀ hcomp₁ hne₀ hne₁ hdisj + -- Orient the `b`-side chart so that `W₀` is upper and `W₁` is lower. + have hBpick : ∃ B₁ : OpenPartialHomeomorph M NNReal, + B₁.source = b.source ∧ B₁.target = Ioo 0 1 ∧ + ∃ s₂ q₂ : NNReal, 0 < s₂ ∧ s₂ ≤ q₂ ∧ q₂ < 1 ∧ + B₁ '' W₀ = Ioo q₂ 1 ∧ B₁ '' W₁ = Ioo 0 s₂ := by + rcases harr with ⟨h₀, h₁⟩ | ⟨h₀, h₁⟩ + · exact ⟨b₀.toOpenPartialHomeomorph, hb₀s, hb₀t, s₁, q₀, hs₁0, hs₁q₀, hq₀1, h₀, h₁⟩ + · obtain ⟨b₁, hb₁s, hb₁t, hb₁f⟩ := b₀.flip hb₀t + have himg₀ : b₁.toOpenPartialHomeomorph '' W₀ + = (fun y => 1 - y) '' (b₀.toOpenPartialHomeomorph '' W₀) := by + rw [← image_comp] + exact image_congr (fun x hx => hb₁f x (hW₀S hx).2) + have himg₁ : b₁.toOpenPartialHomeomorph '' W₁ + = (fun y => 1 - y) '' (b₀.toOpenPartialHomeomorph '' W₁) := by + rw [← image_comp] + exact image_congr (fun x hx => hb₁f x (hW₁S hx).2) + rw [h₀, reflect_image_Ioo_lower hs₁0 (hs₁q₀.trans hq₀1.le)] at himg₀ + rw [h₁, reflect_image_Ioo_upper hq₀1] at himg₁ + exact ⟨b₁.toOpenPartialHomeomorph, hb₁s.trans hb₀s, hb₁t, 1 - q₀, 1 - s₁, + tsub_pos_of_lt hq₀1, tsub_le_tsub_left hs₁q₀ 1, tsub_lt_self one_pos hs₁0, + himg₀, himg₁⟩ + obtain ⟨B₁, hB₁s, hB₁t, s₂, q₂, hs₂0, hs₂q, hq₂1, himgB₀, himgB₁⟩ := hBpick + -- Möbius-shrink the `a`-side chart. + have hr₀1 : r₀ < 1 := lt_of_le_of_lt hr₀p hp₁1 + have hquarter : (0:NNReal) < 1/4 := by norm_num + obtain ⟨cA, hcA0, hcA⟩ := exists_mobiusFun_lt hr₀0 hr₀1 hquarter + obtain ⟨mA, hmAs, hmAt, hmAf, hmAlo, hmAhi⟩ := mobiusOPH' cA hcA0 + set A := a₀.toOpenPartialHomeomorph.trans mA with hAdef + have hAs : A.source = a.source := by + rw [hAdef, OpenPartialHomeomorph.trans_source, hmAs, ← ha₀s] + refine inter_eq_left.mpr fun x hx => ?_ + rw [mem_preimage, ← ha₀t] + exact a₀.toOpenPartialHomeomorph.map_source hx + have hAt : A.target = Ioo 0 1 := by + rw [hAdef, OpenPartialHomeomorph.trans_target, hmAt] + refine inter_eq_left.mpr fun y hy => ?_ + rw [mem_preimage, ha₀t, ← hmAs] + exact mA.map_target (by rw [hmAt]; exact hy) + have hr₀mem : r₀ ∈ Ioo (0:NNReal) 1 := ⟨hr₀0, hr₀1⟩ + have hp₁mem : p₁ ∈ Ioo (0:NNReal) 1 := ⟨lt_of_lt_of_le hr₀0 hr₀p, hp₁1⟩ + have himA₀ : A '' W₀ = Ioo 0 (mobiusFun cA r₀) := by + rw [hAdef, OpenPartialHomeomorph.coe_trans, image_comp, himgA₀] + exact hmAlo r₀ hr₀mem + have himA₁ : A '' W₁ = Ioo (mobiusFun cA p₁) 1 := by + rw [hAdef, OpenPartialHomeomorph.coe_trans, image_comp, himgA₁] + exact hmAhi p₁ hp₁mem + have hmonoA := mobiusFun_strictMonoOn cA hcA0 + have hrp' : mobiusFun cA r₀ ≤ mobiusFun cA p₁ := by + rcases eq_or_lt_of_le hr₀p with heq | hlt + · rw [heq] + · exact (hmonoA hr₀mem hp₁mem hlt).le + have hr'mem := mobiusFun_mem cA hcA0 hr₀mem + have hp'mem := mobiusFun_mem cA hcA0 hp₁mem + -- Möbius-shrink the `b`-side chart. + have hs₂1 : s₂ < 1 := lt_of_le_of_lt hs₂q hq₂1 + obtain ⟨cB, hcB0, hcB⟩ := exists_mobiusFun_lt hs₂0 hs₂1 hquarter + obtain ⟨mB, hmBs, hmBt, hmBf, hmBlo, hmBhi⟩ := mobiusOPH' cB hcB0 + set B := B₁.trans mB with hBdef + have hBs : B.source = b.source := by + rw [hBdef, OpenPartialHomeomorph.trans_source, hmBs, ← hB₁s] + refine inter_eq_left.mpr fun x hx => ?_ + rw [mem_preimage, ← hB₁t] + exact B₁.map_source hx + have hBt : B.target = Ioo 0 1 := by + rw [hBdef, OpenPartialHomeomorph.trans_target, hmBt] + refine inter_eq_left.mpr fun y hy => ?_ + rw [mem_preimage, hB₁t, ← hmBs] + exact mB.map_target (by rw [hmBt]; exact hy) + have hs₂mem : s₂ ∈ Ioo (0:NNReal) 1 := ⟨hs₂0, hs₂1⟩ + have hq₂mem : q₂ ∈ Ioo (0:NNReal) 1 := ⟨lt_of_lt_of_le hs₂0 hs₂q, hq₂1⟩ + have himB₀ : B '' W₀ = Ioo (mobiusFun cB q₂) 1 := by + rw [hBdef, OpenPartialHomeomorph.coe_trans, image_comp, himgB₀] + exact hmBhi q₂ hq₂mem + have himB₁ : B '' W₁ = Ioo 0 (mobiusFun cB s₂) := by + rw [hBdef, OpenPartialHomeomorph.coe_trans, image_comp, himgB₁] + exact hmBlo s₂ hs₂mem + have hmonoB := mobiusFun_strictMonoOn cB hcB0 + have hsq' : mobiusFun cB s₂ ≤ mobiusFun cB q₂ := by + rcases eq_or_lt_of_le hs₂q with heq | hlt + · rw [heq] + · exact (hmonoB hs₂mem hq₂mem hlt).le + have hs'mem := mobiusFun_mem cB hcB0 hs₂mem + have hq'mem := mobiusFun_mem cB hcB0 hq₂mem + have hunion' : A.source ∩ B.source = W₀ ∪ W₁ := by + rw [hAs, hBs, ← ha₀s, ← hb₀s] + exact hunion + exact ⟨A, B, W₀, W₁, mobiusFun cA r₀, mobiusFun cA p₁, mobiusFun cB s₂, mobiusFun cB q₂, + hAs, hBs, hAt, hBt, hunion', himA₀, himA₁, himB₀, himB₁, + hr'mem.1, hrp', hp'mem.2, hcA, hs'mem.1, hsq', hq'mem.2, hcB⟩ + +/-- Assemble the circle chart from the normalized data: embed each chart as an arc of +`AddCircle 1` and glue along a closed sub-arc via `piecewise`. -/ +private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Space M] + (A B : OpenPartialHomeomorph M NNReal) (W₀ W₁ : Set M) (r p s q : NNReal) + (hAt : A.target = Ioo 0 1) (hBt : B.target = Ioo 0 1) + (hunion : A.source ∩ B.source = W₀ ∪ W₁) + (himgA₀ : A '' W₀ = Ioo 0 r) (himgA₁ : A '' W₁ = Ioo p 1) + (himgB₀ : B '' W₀ = Ioo q 1) (himgB₁ : B '' W₁ = Ioo 0 s) + (hr0 : 0 < r) (hrp : r ≤ p) (hp1 : p < 1) (hr4 : r < 1/4) + (hs0 : 0 < s) (hsq : s ≤ q) (hq1 : q < 1) (hs4 : s < 1/4) : + ∃ f : OpenPartialHomeomorph M (AddCircle (1:ℝ)), + f.source = A.source ∪ B.source ∧ f.target = univ := by + classical + have hfact : Fact ((0:ℝ) < 1) := ⟨one_pos⟩ + -- Subset bookkeeping. + have hW₀S : W₀ ⊆ A.source ∩ B.source := by rw [hunion]; exact subset_union_left + have hW₁S : W₁ ⊆ A.source ∩ B.source := by rw [hunion]; exact subset_union_right + have hW₀A : W₀ ⊆ A.source := fun z hz => (hW₀S hz).1 + have hW₀B : W₀ ⊆ B.source := fun z hz => (hW₀S hz).2 + have hW₁A : W₁ ⊆ A.source := fun z hz => (hW₁S hz).1 + have hW₁B : W₁ ⊆ B.source := fun z hz => (hW₁S hz).2 + -- Numeric NNReal facts. + have hp0 : (0:NNReal) < p := lt_of_lt_of_le hr0 hrp + have hq0 : (0:NNReal) < q := lt_of_lt_of_le hs0 hsq + have hr1 : r < 1 := hr4.trans (by norm_num) + have hs1 : s < 1 := hs4.trans (by norm_num) + -- Image of the full overlap. + have himgS : A '' (A.source ∩ B.source) = Ioo 0 r ∪ Ioo p 1 := by + rw [hunion, image_union, himgA₀, himgA₁] + -- Monotone correspondences on both components. + have mono₀ : ∀ x ∈ W₀, ∀ y ∈ W₀, A x < A y → B x < B y := by + apply overlap_mono_on A B hW₀S himgA₀ himgB₀ + · rw [hAt]; exact ⟨hr0, hr1⟩ + · rw [hBt]; exact ⟨hq0, hq1⟩ + · rw [himgS] + rintro (⟨-, h2⟩ | ⟨h1, -⟩) + · exact absurd h2 (lt_irrefl r) + · exact absurd h1 (not_lt.2 hrp) + have mono₁ : ∀ x ∈ W₁, ∀ y ∈ W₁, A x < A y → B x < B y := by + apply overlap_mono_on' A B hW₁S himgA₁ himgB₁ + · rw [hAt]; exact ⟨hp0, hp1⟩ + · rw [hBt]; exact ⟨hs0, hs1⟩ + · rw [himgS] + rintro (⟨-, h2⟩ | ⟨h1, -⟩) + · exact absurd h2 (not_lt.2 hrp) + · exact absurd h1 (lt_irrefl p) + -- Split points. + have h34lt1 : (3/4 : NNReal) < 1 := by norm_num + obtain ⟨ν, hν1', hν2⟩ := exists_between (max_lt hp1 h34lt1) + have hpν : p < ν := lt_of_le_of_lt (le_max_left _ _) hν1' + have h34ν : (3/4:NNReal) < ν := lt_of_le_of_lt (le_max_right _ _) hν1' + obtain ⟨m₁, hm₁W, hm₁ν⟩ : ∃ m₁ ∈ W₁, A m₁ = ν := by + have hmem : ν ∈ A '' W₁ := by rw [himgA₁]; exact ⟨hpν, hν2⟩ + obtain ⟨m₁, hm₁, he⟩ := hmem + exact ⟨m₁, hm₁, he⟩ + obtain ⟨μ, hμ1', hμ2⟩ := exists_between (max_lt hq1 h34lt1) + have hqμ : q < μ := lt_of_le_of_lt (le_max_left _ _) hμ1' + have h34μ : (3/4:NNReal) < μ := lt_of_le_of_lt (le_max_right _ _) hμ1' + obtain ⟨m₀, hm₀W, hm₀μ⟩ : ∃ m₀ ∈ W₀, B m₀ = μ := by + have hmem : μ ∈ B '' W₀ := by rw [himgB₀]; exact ⟨hqμ, hμ2⟩ + obtain ⟨m₀, hm₀, he⟩ := hmem + exact ⟨m₀, hm₀, he⟩ + have hm₀A : m₀ ∈ A.source := hW₀A hm₀W + have hm₀B : m₀ ∈ B.source := hW₀B hm₀W + have hm₁A : m₁ ∈ A.source := hW₁A hm₁W + have hm₁B : m₁ ∈ B.source := hW₁B hm₁W + have hρmem : A m₀ ∈ Ioo 0 r := by rw [← himgA₀]; exact mem_image_of_mem _ hm₀W + have hσmem : B m₁ ∈ Ioo 0 s := by rw [← himgB₁]; exact mem_image_of_mem _ hm₁W + -- Key monotone-correspondence facts. + have K₀ := mono_key_le A B hW₀A mono₀ hm₀W + have K₁ := mono_key_ge A B hW₁A mono₁ hm₁W + -- Real versions of the split data. + have hρ'0 : (0:ℝ) < ((A m₀ : NNReal) : ℝ) := by exact_mod_cast hρmem.1 + have hρ'4 : ((A m₀ : NNReal) : ℝ) < 1/4 := by exact_mod_cast hρmem.2.trans hr4 + have hν'3 : (3/4:ℝ) < ((ν : NNReal) : ℝ) := by exact_mod_cast h34ν + have hν'1 : ((ν : NNReal) : ℝ) < 1 := by exact_mod_cast hν2 + have hσ'0 : (0:ℝ) < ((B m₁ : NNReal) : ℝ) := by exact_mod_cast hσmem.1 + have hσ'4 : ((B m₁ : NNReal) : ℝ) < 1/4 := by exact_mod_cast hσmem.2.trans hs4 + have hμ'3 : (3/4:ℝ) < ((μ : NNReal) : ℝ) := by exact_mod_cast h34μ + have hμ'1 : ((μ : NNReal) : ℝ) < 1 := by exact_mod_cast hμ2 + obtain ⟨kα, kg, g0, hkα0, hkα1, hkg0, hkg1, hid1, hid2, hcg0, hg0d, h1c, hg1d⟩ := + circle_params hρ'0 hρ'4 hν'3 hν'1 hσ'0 hσ'4 hμ'3 hμ'1 + -- Derived real facts. + have hc₁0 : (0:ℝ) < kα * ((A m₀ : NNReal) : ℝ) := mul_pos hkα0 hρ'0 + have hd₁kα : kα * ((ν : NNReal) : ℝ) < kα := by + have hh : kα * ((ν : NNReal) : ℝ) < kα * 1 := mul_lt_mul_of_pos_left hν'1 hkα0 + rwa [mul_one] at hh + have hd₁1 : kα * ((ν : NNReal) : ℝ) < 1 := hd₁kα.trans hkα1 + have hc₁1 : kα * ((A m₀ : NNReal) : ℝ) < 1 := by linarith + have hg00 : (0:ℝ) < g0 := lt_trans hc₁0 hcg0 + have hc₁d₁ : kα * ((A m₀ : NNReal) : ℝ) ≤ kα * ((ν : NNReal) : ℝ) := by linarith + -- The circle charts. + obtain ⟨eA, heAs, heAt, heAf⟩ := affineNNRealOPH kα 0 hkα0 + obtain ⟨eB, heBs, heBt, heBf⟩ := affineNNRealOPH kg g0 hkg0 + have heAf' : ∀ x : NNReal, eA x = kα * (x:ℝ) + 0 := heAf + have heBf' : ∀ x : NNReal, eB x = kg * (x:ℝ) + g0 := heBf + set CA := AddCircle.openPartialHomeomorphCoe (1:ℝ) (0:ℝ) with hCAdef + set CB := AddCircle.openPartialHomeomorphCoe (1:ℝ) (g0 + kg - 1) with hCBdef + have hCAs : CA.source = Ioo (0:ℝ) (0+1) := rfl + have hCBs : CB.source = Ioo (g0 + kg - 1) (g0 + kg - 1 + 1) := rfl + set e := (A.trans eA).trans CA with hedef + set e' := (B.trans eB).trans CB with he'def + -- Sources and pointwise formulas. + have hAeAs : (A.trans eA).source = A.source := by + rw [OpenPartialHomeomorph.trans_source, heAs] + refine inter_eq_left.mpr fun x hx => ?_ + rw [mem_preimage, ← hAt] + exact A.map_source hx + have hBeBs : (B.trans eB).source = B.source := by + rw [OpenPartialHomeomorph.trans_source, heBs] + refine inter_eq_left.mpr fun x hx => ?_ + rw [mem_preimage, ← hBt] + exact B.map_source hx + have hAeAval : ∀ x, (A.trans eA) x = kα * ((A x : NNReal):ℝ) + 0 := fun x => by + rw [OpenPartialHomeomorph.trans_apply, heAf'] + have hBeBval : ∀ x, (B.trans eB) x = kg * ((B x : NNReal):ℝ) + g0 := fun x => by + rw [OpenPartialHomeomorph.trans_apply, heBf'] + have heval : ∀ x, e x = ((kα * ((A x : NNReal) : ℝ) : ℝ) : AddCircle (1:ℝ)) := by + intro x + rw [hedef, OpenPartialHomeomorph.trans_apply, hAeAval, add_zero] + rfl + have he'val : ∀ x, e' x = ((kg * ((B x : NNReal) : ℝ) + g0 : ℝ) : AddCircle (1:ℝ)) := by + intro x + rw [he'def, OpenPartialHomeomorph.trans_apply, hBeBval] + rfl + have hbounds : ∀ x ∈ A.source, + 0 < kα * ((A x : NNReal):ℝ) ∧ kα * ((A x : NNReal):ℝ) < kα := by + intro x hx + have hAx : A x ∈ Ioo (0:NNReal) 1 := hAt ▸ A.map_source hx + have h0 : (0:ℝ) < ((A x : NNReal):ℝ) := by exact_mod_cast hAx.1 + have h1 : ((A x : NNReal):ℝ) < 1 := by exact_mod_cast hAx.2 + have hh : kα * ((A x : NNReal):ℝ) < kα * 1 := mul_lt_mul_of_pos_left h1 hkα0 + rw [mul_one] at hh + exact ⟨mul_pos hkα0 h0, hh⟩ + have hb'bounds : ∀ x ∈ B.source, + g0 < kg * ((B x : NNReal):ℝ) + g0 ∧ kg * ((B x : NNReal):ℝ) + g0 < g0 + kg := by + intro x hx + have hBx : B x ∈ Ioo (0:NNReal) 1 := hBt ▸ B.map_source hx + have h0 : (0:ℝ) < ((B x : NNReal):ℝ) := by exact_mod_cast hBx.1 + have h1 : ((B x : NNReal):ℝ) < 1 := by exact_mod_cast hBx.2 + have hh : kg * ((B x : NNReal):ℝ) < kg * 1 := mul_lt_mul_of_pos_left h1 hkg0 + rw [mul_one] at hh + exact ⟨by linarith [mul_pos hkg0 h0], by linarith⟩ + have hes : e.source = A.source := by + rw [hedef, OpenPartialHomeomorph.trans_source, hAeAs] + refine inter_eq_left.mpr fun x hx => ?_ + rw [mem_preimage, hAeAval, hCAs] + obtain ⟨hb0, hb1⟩ := hbounds x hx + exact ⟨by linarith, by linarith⟩ + have he's : e'.source = B.source := by + rw [he'def, OpenPartialHomeomorph.trans_source, hBeBs] + refine inter_eq_left.mpr fun x hx => ?_ + rw [mem_preimage, hBeBval, hCBs] + obtain ⟨hb0, hb1⟩ := hb'bounds x hx + exact ⟨by linarith, by linarith⟩ + -- Targets. + have htargetE : e.target = ((↑) : ℝ → AddCircle (1:ℝ)) '' (Ioo 0 kα) := by + have hgen := affine_circle_target A hAt e hes hkα0 + (fun x _ => by rw [heval x, add_zero]) + rw [hgen, zero_add] + have htargetE' : e'.target = ((↑) : ℝ → AddCircle (1:ℝ)) '' (Ioo g0 (g0 + kg)) := + affine_circle_target B hBt e' he's hkg0 (fun x _ => he'val x) + -- The gluing sets. + set sset := A.source ∩ A ⁻¹' (Icc (A m₀) ν) with hssetdef + set tset := ((↑) : ℝ → AddCircle (1:ℝ)) '' + (Icc (kα * ((A m₀ : NNReal):ℝ)) (kα * ((ν : NNReal):ℝ))) with htsetdef + have hssub : sset ⊆ A.source := by rw [hssetdef]; exact inter_subset_left + -- `e` maps `sset` to `tset`. + have H : e.IsImage sset tset := by + intro x hx + rw [hes] at hx + rw [heval x] + obtain ⟨hb0, hb1⟩ := hbounds x hx + constructor + · rintro ⟨y, hy, hye⟩ + have hyeq : y = kα * ((A x : NNReal):ℝ) := by + apply addCircle_coe_inj hye + rw [abs_lt] + constructor + · linarith [hy.1] + · linarith [hy.2] + rw [hyeq] at hy + have hxle : ((A m₀ : NNReal):ℝ) ≤ ((A x : NNReal):ℝ) := le_of_mul_le_mul_left hy.1 hkα0 + have hxge : ((A x : NNReal):ℝ) ≤ ((ν : NNReal):ℝ) := le_of_mul_le_mul_left hy.2 hkα0 + rw [hssetdef] + refine ⟨hx, ?_⟩ + rw [mem_preimage] + exact ⟨by exact_mod_cast hxle, by exact_mod_cast hxge⟩ + · intro hmem + rw [hssetdef] at hmem + obtain ⟨-, hmem2⟩ := hmem + rw [mem_preimage] at hmem2 + have h1' : ((A m₀ : NNReal):ℝ) ≤ ((A x : NNReal):ℝ) := by exact_mod_cast hmem2.1 + have h2' : ((A x : NNReal):ℝ) ≤ ((ν : NNReal):ℝ) := by exact_mod_cast hmem2.2 + rw [htsetdef] + exact mem_image_of_mem _ ⟨mul_le_mul_of_nonneg_left h1' hkα0.le, + mul_le_mul_of_nonneg_left h2' hkα0.le⟩ + -- Windows: membership of a point of the `e'`-arc in `tset`. + have claim1 : ∀ v : ℝ, v ∈ Ioo g0 (g0 + kg) → + (((v : ℝ) : AddCircle (1:ℝ)) ∈ tset ↔ + v ∈ Icc (kα * ((A m₀ : NNReal):ℝ)) (kα * ((ν : NNReal):ℝ)) ∨ + v ∈ Icc (1 + kα * ((A m₀ : NNReal):ℝ)) (1 + kα * ((ν : NNReal):ℝ))) := by + intro v hv + rw [htsetdef] + constructor + · rintro ⟨z, hz, hze⟩ + have h1 : -1 < v - z := by linarith [hz.2, hv.1] + have h2 : v - z < 2 := by linarith [hz.1, hv.2] + rcases addCircle_eq_or_eq_add_one hze.symm h1 h2 with heq | heq + · left; rw [heq]; exact hz + · right; rw [heq]; exact ⟨by linarith [hz.1], by linarith [hz.2]⟩ + · rintro (hv1 | hv2) + · exact mem_image_of_mem _ hv1 + · refine ⟨v - 1, ⟨by linarith [hv2.1], by linarith [hv2.2]⟩, ?_⟩ + rw [← addCircle_coe_add_one (v - 1), sub_add_cancel] + -- Translation of the window membership into `B`-coordinate inequalities. + have claim2 : ∀ y ∈ B.source, + ((kg * ((B y : NNReal):ℝ) + g0 ∈ + Icc (kα * ((A m₀ : NNReal):ℝ)) (kα * ((ν : NNReal):ℝ)) ∨ + kg * ((B y : NNReal):ℝ) + g0 ∈ + Icc (1 + kα * ((A m₀ : NNReal):ℝ)) (1 + kα * ((ν : NNReal):ℝ))) + ↔ (B y ≤ B m₁ ∨ B m₀ ≤ B y)) := by + intro y hy + obtain ⟨hb0, hb1⟩ := hb'bounds y hy + constructor + · rintro (hc | hc) + · left + have h' : kg * ((B y : NNReal):ℝ) + g0 ≤ kg * ((B m₁ : NNReal):ℝ) + g0 := by + rw [hid1]; exact hc.2 + have hby : ((B y : NNReal):ℝ) ≤ ((B m₁ : NNReal):ℝ) := + le_of_mul_le_mul_left (by linarith) hkg0 + exact_mod_cast hby + · right + have h' : kg * ((μ : NNReal):ℝ) + g0 ≤ kg * ((B y : NNReal):ℝ) + g0 := by + rw [hid2]; exact hc.1 + have hby : ((μ : NNReal):ℝ) ≤ ((B y : NNReal):ℝ) := + le_of_mul_le_mul_left (by linarith) hkg0 + rw [hm₀μ] + exact_mod_cast hby + · rintro (hc | hc) + · left + have hby : ((B y : NNReal):ℝ) ≤ ((B m₁ : NNReal):ℝ) := by exact_mod_cast hc + constructor + · linarith + · rw [← hid1] + have := mul_le_mul_of_nonneg_left hby hkg0.le + linarith + · right + rw [hm₀μ] at hc + have hby : ((μ : NNReal):ℝ) ≤ ((B y : NNReal):ℝ) := by exact_mod_cast hc + constructor + · rw [← hid2] + have := mul_le_mul_of_nonneg_left hby hkg0.le + linarith + · linarith + -- The `B`-coordinate inequalities describe exactly `sset`. + have claim3 : ∀ y ∈ B.source, ((B y ≤ B m₁ ∨ B m₀ ≤ B y) ↔ y ∈ sset) := by + intro y hy + rw [hssetdef] + by_cases hyA : y ∈ A.source + · have hyS : y ∈ W₀ ∪ W₁ := by rw [← hunion]; exact ⟨hyA, hy⟩ + rcases hyS with hyW | hyW + · have hAy : A y ∈ Ioo 0 r := by rw [← himgA₀]; exact mem_image_of_mem _ hyW + have hBy : B y ∈ Ioo q 1 := by rw [← himgB₀]; exact mem_image_of_mem _ hyW + have hnots : ¬ (B y ≤ B m₁) := by + rw [not_le] + exact lt_trans (lt_of_lt_of_le hσmem.2 hsq) hBy.1 + have hK := K₀ y hyW + constructor + · rintro (hc | hc) + · exact absurd hc hnots + · refine ⟨hyA, ?_⟩ + rw [mem_preimage] + exact ⟨hK.mpr hc, le_of_lt (lt_of_lt_of_le hAy.2 (hrp.trans hpν.le))⟩ + · rintro ⟨-, hmem⟩ + rw [mem_preimage] at hmem + exact Or.inr (hK.mp hmem.1) + · have hAy : A y ∈ Ioo p 1 := by rw [← himgA₁]; exact mem_image_of_mem _ hyW + have hBy : B y ∈ Ioo 0 s := by rw [← himgB₁]; exact mem_image_of_mem _ hyW + have hnots : ¬ (B m₀ ≤ B y) := by + rw [not_le, hm₀μ] + exact lt_trans (lt_of_lt_of_le hBy.2 hsq) hqμ + have hK := K₁ y hyW + constructor + · rintro (hc | hc) + · refine ⟨hyA, ?_⟩ + rw [mem_preimage] + refine ⟨le_of_lt (lt_trans (lt_of_lt_of_le hρmem.2 hrp) hAy.1), ?_⟩ + rw [← hm₁ν] + exact hK.mpr hc + · exact absurd hc hnots + · rintro ⟨-, hmem⟩ + rw [mem_preimage] at hmem + refine Or.inl (hK.mp ?_) + rw [hm₁ν] + exact hmem.2 + · constructor + · rintro (hc | hc) + · exfalso + have hBy0 : (0:NNReal) < B y := by + have hmem := B.map_source hy + rw [hBt] at hmem + exact hmem.1 + have hmem : B y ∈ Ioo 0 s := ⟨hBy0, lt_of_le_of_lt hc hσmem.2⟩ + have hyW : y ∈ W₁ := mem_of_image_mem B hW₁B himgB₁ hy hmem + exact hyA (hW₁A hyW) + · exfalso + have hBy1 : B y < 1 := by + have hmem := B.map_source hy + rw [hBt] at hmem + exact hmem.2 + rw [hm₀μ] at hc + have hmem : B y ∈ Ioo q 1 := ⟨lt_of_lt_of_le hqμ hc, hBy1⟩ + have hyW : y ∈ W₀ := mem_of_image_mem B hW₀B himgB₀ hy hmem + exact hyA (hW₀A hyW) + · rintro ⟨hyA', -⟩ + exact absurd hyA' hyA + -- `e'` also maps `sset` to `tset`. + have H' : e'.IsImage sset tset := by + intro y hy + rw [he's] at hy + rw [he'val y] + obtain ⟨hb0, hb1⟩ := hb'bounds y hy + rw [claim1 _ ⟨hb0, hb1⟩, claim2 y hy] + exact claim3 y hy + -- The frontier of the closed arc consists of at most the two endpoint classes. + have hfrontier : frontier tset ⊆ + {((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1:ℝ)), + ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1:ℝ))} := by + rw [htsetdef] + exact addCircle_frontier_arc_subset hc₁d₁ + -- The endpoint classes are attained only at the split points. + have Pce : ∀ x ∈ A.source, + (e x = ((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1:ℝ)) ↔ x = m₀) := by + intro x hx + obtain ⟨hb0, hb1⟩ := hbounds x hx + constructor + · intro hcoe + rw [heval x] at hcoe + have heq : kα * ((A x : NNReal):ℝ) = kα * ((A m₀ : NNReal):ℝ) := by + apply addCircle_coe_inj hcoe + rw [abs_lt] + exact ⟨by linarith, by linarith⟩ + have hAeq : A x = A m₀ := + NNReal.coe_injective (mul_left_cancel₀ hkα0.ne' heq) + exact A.injOn hx hm₀A hAeq + · rintro rfl + rw [heval x] + have Pde : ∀ x ∈ A.source, + (e x = ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1:ℝ)) ↔ x = m₁) := by + intro x hx + obtain ⟨hb0, hb1⟩ := hbounds x hx + have hd₁0 : (0:ℝ) < kα * ((ν : NNReal):ℝ) := by linarith + constructor + · intro hcoe + rw [heval x] at hcoe + have heq : kα * ((A x : NNReal):ℝ) = kα * ((ν : NNReal):ℝ) := by + apply addCircle_coe_inj hcoe + rw [abs_lt] + exact ⟨by linarith, by linarith⟩ + have hAeq : A x = ν := + NNReal.coe_injective (mul_left_cancel₀ hkα0.ne' heq) + rw [← hm₁ν] at hAeq + exact A.injOn hx hm₁A hAeq + · rintro rfl + rw [heval x, hm₁ν] + have Pce' : ∀ y ∈ B.source, + (e' y = ((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1:ℝ)) ↔ y = m₀) := by + intro y hy + obtain ⟨hb0, hb1⟩ := hb'bounds y hy + constructor + · intro hcoe + rw [he'val y] at hcoe + rcases addCircle_eq_or_eq_add_one hcoe (by linarith) (by linarith) with heq | heq + · exfalso; linarith + · have h' : kg * ((B y : NNReal):ℝ) + g0 = kg * ((μ : NNReal):ℝ) + g0 := by + rw [hid2]; linarith + have hBeq : B y = μ := + NNReal.coe_injective (mul_left_cancel₀ hkg0.ne' (by linarith)) + rw [← hm₀μ] at hBeq + exact B.injOn hy hm₀B hBeq + · rintro rfl + rw [he'val y, hm₀μ, hid2, add_comm 1 (kα * ((A y : NNReal):ℝ))] + exact addCircle_coe_add_one _ + have Pde' : ∀ y ∈ B.source, + (e' y = ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1:ℝ)) ↔ y = m₁) := by + intro y hy + obtain ⟨hb0, hb1⟩ := hb'bounds y hy + constructor + · intro hcoe + rw [he'val y] at hcoe + rcases addCircle_eq_or_eq_add_one hcoe (by linarith) (by linarith) with heq | heq + · have h' : kg * ((B y : NNReal):ℝ) + g0 = kg * ((B m₁ : NNReal):ℝ) + g0 := by + rw [hid1]; linarith + have hBeq : B y = B m₁ := + NNReal.coe_injective (mul_left_cancel₀ hkg0.ne' (by linarith)) + exact B.injOn hy hm₁B hBeq + · exfalso; linarith + · rintro rfl + rw [he'val y, hid1] + -- Frontier agreement and equality on the frontier. + have hpre := H.frontier.preimage_eq + have hpre' := H'.frontier.preimage_eq + have Hs : e.source ∩ frontier sset = e'.source ∩ frontier sset := by + rw [← hpre, ← hpre'] + ext x + simp only [mem_inter_iff, mem_preimage] + constructor + · rintro ⟨hx, hfx⟩ + have hx' : x ∈ A.source := by rwa [hes] at hx + have hex := hfrontier hfx + simp only [mem_insert_iff, mem_singleton_iff] at hex + rcases hex with hcx | hdx + · have hxm : x = m₀ := (Pce x hx').mp hcx + subst hxm + refine ⟨by rw [he's]; exact hm₀B, ?_⟩ + rw [(Pce' x hm₀B).mpr rfl, ← hcx] + exact hfx + · have hxm : x = m₁ := (Pde x hx').mp hdx + subst hxm + refine ⟨by rw [he's]; exact hm₁B, ?_⟩ + rw [(Pde' x hm₁B).mpr rfl, ← hdx] + exact hfx + · rintro ⟨hx, hfx⟩ + have hx' : x ∈ B.source := by rwa [he's] at hx + have hex := hfrontier hfx + simp only [mem_insert_iff, mem_singleton_iff] at hex + rcases hex with hcx | hdx + · have hxm : x = m₀ := (Pce' x hx').mp hcx + subst hxm + refine ⟨by rw [hes]; exact hm₀A, ?_⟩ + rw [(Pce x hm₀A).mpr rfl, ← hcx] + exact hfx + · have hxm : x = m₁ := (Pde' x hx').mp hdx + subst hxm + refine ⟨by rw [hes]; exact hm₁A, ?_⟩ + rw [(Pde x hm₁A).mpr rfl, ← hdx] + exact hfx + have Heq : Set.EqOn e e' (e.source ∩ frontier sset) := by + rw [← hpre] + rintro x ⟨hx, hfx⟩ + rw [mem_preimage] at hfx + have hx' : x ∈ A.source := by rwa [hes] at hx + have hex := hfrontier hfx + simp only [mem_insert_iff, mem_singleton_iff] at hex + rcases hex with hcx | hdx + · have hxm : x = m₀ := (Pce x hx').mp hcx + subst hxm + rw [hcx, (Pce' x hm₀B).mpr rfl] + · have hxm : x = m₁ := (Pde x hx').mp hdx + subst hxm + rw [hdx, (Pde' x hm₁B).mpr rfl] + -- Glue. + refine ⟨e.piecewise e' sset tset H H' Hs Heq, ?_, ?_⟩ + · show Set.ite sset e.source e'.source = A.source ∪ B.source + have hite : Set.ite sset e.source e'.source + = (e.source ∩ sset) ∪ (e'.source \ sset) := rfl + rw [hite, hes, he's] + apply Subset.antisymm + · rintro x (⟨hx, -⟩ | ⟨hx, -⟩) + · exact Or.inl hx + · exact Or.inr hx + · rintro x hx + by_cases hxs : x ∈ sset + · exact Or.inl ⟨hssub hxs, hxs⟩ + · rcases hx with hxa | hxb + · have hxB : x ∈ B.source := by + have hAx : A x ∈ Ioo (0:NNReal) 1 := hAt ▸ A.map_source hxa + have hnot : A x ∉ Icc (A m₀) ν := by + intro hmem + exact hxs (by rw [hssetdef]; exact ⟨hxa, hmem⟩) + rcases lt_or_ge (A x) (A m₀) with hlt | hge + · have hmem : A x ∈ Ioo 0 r := ⟨hAx.1, lt_trans hlt hρmem.2⟩ + exact hW₀B (mem_of_image_mem A hW₀A himgA₀ hxa hmem) + · rcases le_or_gt (A x) ν with hle | hgt + · exact absurd ⟨hge, hle⟩ hnot + · have hmem : A x ∈ Ioo p 1 := ⟨lt_trans hpν hgt, hAx.2⟩ + exact hW₁B (mem_of_image_mem A hW₁A himgA₁ hxa hmem) + exact Or.inr ⟨hxB, hxs⟩ + · exact Or.inr ⟨hxb, hxs⟩ + · show Set.ite tset e.target e'.target = univ + have hite : Set.ite tset e.target e'.target + = (e.target ∩ tset) ∪ (e'.target \ tset) := rfl + rw [hite] + have h1 : e.target ∩ tset = tset := by + apply inter_eq_right.mpr + rw [htargetE, htsetdef] + exact image_mono + (fun u hu => ⟨lt_of_lt_of_le hc₁0 hu.1, lt_of_le_of_lt hu.2 hd₁kα⟩) + have h2 : e'.target \ tset = ((↑) : ℝ → AddCircle (1:ℝ)) '' + (Ioo (kα * ((ν : NNReal):ℝ)) (kα * ((A m₀ : NNReal):ℝ) + 1)) := by + rw [htargetE'] + ext z + constructor + · rintro ⟨⟨v, hv, rfl⟩, hnt⟩ + have hnor : ¬(v ∈ Icc (kα * ((A m₀ : NNReal):ℝ)) (kα * ((ν : NNReal):ℝ)) ∨ + v ∈ Icc (1 + kα * ((A m₀ : NNReal):ℝ)) (1 + kα * ((ν : NNReal):ℝ))) := + fun hor => hnt ((claim1 v hv).mpr hor) + push Not at hnor + obtain ⟨hn1, hn2⟩ := hnor + rw [mem_Icc] at hn1 hn2 + push Not at hn1 hn2 + refine mem_image_of_mem _ ⟨?_, ?_⟩ + · exact hn1 (by linarith [hv.1]) + · by_contra hge + push Not at hge + have := hn2 (by linarith) + linarith [hv.2] + · rintro ⟨u, hu, rfl⟩ + have huv : u ∈ Ioo g0 (g0 + kg) := + ⟨lt_trans hg0d hu.1, by linarith [hu.2]⟩ + refine ⟨mem_image_of_mem _ huv, ?_⟩ + intro ht + rcases (claim1 u huv).mp ht with hin | hin + · rw [mem_Icc] at hin + linarith [hu.1, hin.2] + · rw [mem_Icc] at hin + linarith [hu.2, hin.1] + rw [h1, h2, htsetdef] + exact addCircle_arc_union_covers hc₁d₁ (by linarith) + +/-- **The circle chart.** Two O-charts with `Overlap` and a disconnected overlap glue to +a chart of `M` onto the whole of `AddCircle 1`. -/ +theorem exists_circle_chart {M : Type*} [TopologicalSpace M] [T2Space M] + (a b : OChart M) (h : Overlap a.source b.source) + (hdisc : ¬ IsConnected (a.source ∩ b.source)) : + ∃ f : OpenPartialHomeomorph M (AddCircle (1:ℝ)), + f.source = a.source ∪ b.source ∧ f.target = univ := by + obtain ⟨A, B, W₀, W₁, r, p, s, q, hAs, hBs, hAt, hBt, hunion, + himgA₀, himgA₁, himgB₀, himgB₁, hr0, hrp, hp1, hr4, hs0, hsq, hq1, hs4⟩ := + exists_normalized_charts a b h hdisc + obtain ⟨f, hfs, hft⟩ := circle_chart_of_normalized A B W₀ W₁ r p s q hAt hBt hunion + himgA₀ himgA₁ himgB₀ himgB₁ hr0 hrp hp1 hr4 hs0 hsq hq1 hs4 + exact ⟨f, by rw [hfs, hAs, hBs], hft⟩ diff --git a/LeanPool/OneManifold/OneMfld/Classification.lean b/LeanPool/OneManifold/OneMfld/Classification.lean new file mode 100644 index 0000000000..83c1817588 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/Classification.lean @@ -0,0 +1,414 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.UnitInterval +import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts +import LeanPool.OneManifold.OneMfld.IntervalCharts +import LeanPool.OneManifold.OneMfld.NiceCharts +import LeanPool.OneManifold.OneMfld.ClassifyOverlaps +import LeanPool.OneManifold.OneMfld.Compactness + +variable + {M : Type*} + [TopologicalSpace M] + [ConnectedSpace M] + +noncomputable def subsume_charts (ht : FinitelyIntervalChartedSpace M) + {a : OpenPartialHomeomorph M NNReal} (ha : a ∈ ht.atlas) + {b : OpenPartialHomeomorph M NNReal} (hb : b ∈ ht.atlas) + (hs : a.source ⊆ b.source) (hab : a ≠ b): + { ht' : FinitelyIntervalChartedSpace M | Nat.card ht'.atlas = Nat.card ht.atlas - 1 } := by + let ht' : FinitelyIntervalChartedSpace M := + { chartAt := by + intro x + by_cases h : a = ht.chartAt x + · exact b + · exact ht.chartAt x + , atlas := ht.atlas \ { a } + , chart_mem_atlas := by + intro x + split_ifs with h + · apply Set.mem_sdiff_singleton.mpr + apply And.intro + · exact hb + · exact id (Ne.symm hab) + · apply Set.mem_sdiff_singleton.mpr + apply And.intro + · exact ChartedSpace.chart_mem_atlas x + · exact fun a_1 => h (id (Eq.symm a_1)) + , mem_chart_source := by + intro x + split_ifs with h + · rw [h] at hs + apply hs + exact ChartedSpace.mem_chart_source x + · exact ChartedSpace.mem_chart_source x + , is_finite := Set.Finite.subset ht.is_finite Set.sdiff_subset + , is_interval := by + intro φ hφ + apply ht.is_interval + exact Set.mem_of_mem_sdiff hφ + } + + use ht' + exact Set.ncard_sdiff_singleton_of_mem ha + + +noncomputable def replace_charts (ht : FinitelyIntervalChartedSpace M) + {a : OpenPartialHomeomorph M NNReal} (ha : a ∈ ht.atlas) + {b : OpenPartialHomeomorph M NNReal} (hb : b ∈ ht.atlas) + (ho : Overlap a.source b.source) + (f : IChart M) (hf : f.source = a.source ∪ b.source ) : + { ht' : FinitelyIntervalChartedSpace M | Nat.card ht'.atlas ≤ Nat.card ht.atlas - 1 } := by + + let hab : a ≠ b := by + by_contra hab + rw [hab] at ho + let ho1 := ho.2.1 + simp only [sdiff_self, Set.bot_eq_empty, Set.not_nonempty_empty] at ho1 + + let ht' : FinitelyIntervalChartedSpace M := + { chartAt := by + intro x + by_cases h : a = ht.chartAt x + · exact f.toOpenPartialHomeomorph + · by_cases h : b = ht.chartAt x + · exact f.toOpenPartialHomeomorph + · exact ht.chartAt x + , atlas := (ht.atlas \ { a, b }) ∪ ({ f.toOpenPartialHomeomorph } : Set _) + , chart_mem_atlas := by + intro x + split_ifs with h h' + · simp only [Set.union_singleton, Set.mem_insert_iff, Set.mem_sdiff, Set.mem_singleton_iff, + not_or, true_or] + · simp only [Set.union_singleton, Set.mem_insert_iff, Set.mem_sdiff, Set.mem_singleton_iff, + not_or, true_or] + · simp only [Set.union_singleton, Set.mem_insert_iff, Set.mem_sdiff, chart_mem_atlas, + Set.mem_singleton_iff, not_or, true_and] + right + exact ⟨fun a_1 => h (id (Eq.symm a_1)), fun a => h' (id (Eq.symm a))⟩ + , mem_chart_source := by + intro x + split_ifs with h h' + · rw [hf] + simp only [Set.mem_union] + left + rw [h] + exact ChartedSpace.mem_chart_source x + · rw [hf] + simp only [Set.mem_union] + right + rw [h'] + exact ChartedSpace.mem_chart_source x + · exact ChartedSpace.mem_chart_source x + , is_finite := by + have : Finite ht.atlas := ht.is_finite + simp only [Set.union_singleton] + exact Finite.Set.finite_insert f.toOpenPartialHomeomorph (ChartedSpace.atlas \ {a, b}) + , is_interval := by + intro x hx + simp only [Set.union_singleton, Set.mem_insert_iff, Set.mem_sdiff, Set.mem_singleton_iff, + not_or] at hx + + rcases hx with (hx|hx) + · rw [hx] + apply f.is_interval + · apply ht.is_interval + exact hx.1 + } + + use ht' + + have pair : ( { a, b } : Set (OpenPartialHomeomorph M NNReal) ).ncard = 2 := Set.ncard_pair hab + + have equal : ht.atlas \ {a, b} ∪ {a, b} = ht.atlas := Set.sdiff_union_of_subset (Set.pair_subset ha hb) + + have union : ((ht.atlas \ { a, b } : Set _) ∪ {a, b} : Set _).ncard = (ht.atlas \ { a, b } : Set _).ncard + ( { a, b } : Set _ ).ncard := by + apply Set.ncard_union_eq + exact Set.disjoint_sdiff_left + apply Set.Finite.sdiff + exact ht.is_finite + exact Set.toFinite {a, b} + + rw [pair] at union + rw [equal] at union + + dsimp [ht'] + + have : (ht.atlas \ { a, b } : Set _).ncard = (ht.atlas).ncard - 2 := by + rw [union] + exact rfl + + have t : (ht.atlas \ {a, b} ∪ {f.toOpenPartialHomeomorph}).ncard ≤ (ht.atlas \ { a, b } : Set _).ncard + ({f.toOpenPartialHomeomorph} : Set _).ncard := by + apply Set.ncard_union_le + + rw [this] at t + simp only [Set.ncard_singleton] at t + + have t' : ht.atlas.ncard - 2 + 1 ≤ ht.atlas.ncard - 1 := by + have nonzero : ht.atlas.ncard ≥ 2 := by + rw [←pair] + apply Set.ncard_le_ncard + exact Set.pair_subset ha hb + exact ht.is_finite + + ring_nf + apply Nat.one_add_le_iff.mpr + exact Nat.sub_succ_lt_self ht.atlas.ncard 1 nonzero + exact Nat.le_trans t t' + +lemma nonempty_atlas (ht : FinitelyIntervalChartedSpace M) : ht.atlas.Nonempty := by + by_contra nonempty + have he : Nonempty M := ConnectedSpace.toNonempty + have x := he.some + let chart := ht.chartAt x + have hc : chart ∈ ht.atlas := ht.chart_mem_atlas x + exfalso + exact nonempty (Set.nonempty_of_mem hc) + +lemma more_than_one_chart [CompactSpace M] (ht : FinitelyIntervalChartedSpace M) : Nat.card ht.atlas > 1 := by + have z := (ConnectedSpace.toNonempty : Nonempty M).some + let φ := ht.chartAt z + + have nonempty := nonempty_atlas ht + + have hzero : Nat.card ht.atlas > 0 := by + refine (Set.natCard_pos ?_).mpr nonempty + exact ht.is_finite + by_contra htwo + have hone : Nat.card ht.atlas = 1 := by linarith + + have he : ∃ (a : OpenPartialHomeomorph M NNReal), ht.atlas = { a } := Set.ncard_eq_one.mp hone + rcases he with ⟨a,ha⟩ + + have : φ ∈ ht.atlas := ChartedSpace.chart_mem_atlas z + rw [ha] at this + have hφa : φ = a := by exact this + + have h : a.source = Set.univ := by + ext x + apply Iff.intro + · exact fun _ => trivial + · intro hx + let c := ht.chartAt x + + have : c ∈ ht.atlas := ht.chart_mem_atlas x + have : c = a := by + rw [ha] at this + exact this + rw [←this] + exact ht.mem_chart_source x + + -- a.source is homeo to a.target which is not compact + have notcompactφ : ¬ CompactSpace (φ.target) := by + apply noncompact_target + exact ChartedSpace.chart_mem_atlas z + exact ChartedSpace.mem_chart_source z + have notcompact : ¬ CompactSpace (a.target) := by + rwa [←hφa] + + exfalso + apply notcompact + refine isCompact_iff_compactSpace.mp ?_ + have : a.target = a.toFun '' a.source := Eq.symm (PartialEquiv.image_source_eq_target a.toPartialEquiv) + rw [this] + apply IsCompact.image_of_continuousOn + · rw [h] + exact CompactSpace.isCompact_univ + · exact a.continuousOn_toFun + +lemma find_overlap [CompactSpace M] (ht : FinitelyIntervalChartedSpace M) {a : OpenPartialHomeomorph M NNReal} + (ha : a ∈ ht.atlas) {x : M} (hx : x ∈ a.source) + (contains : ∀ c ∈ ChartedSpace.atlas \ {a}, ¬ a.source ⊆ c.source) : + ∃ (b : OpenPartialHomeomorph M NNReal), (b ∈ ht.atlas \ {a}) ∧ (Overlap a.source b.source) := by + by_contra h + push Not at h + + have ho : IsOpen a.source := a.open_source + have hc : IsClosed a.source := by + have comp : a.sourceᶜ = ⋃ (b ∈ { c ∈ ChartedSpace.atlas \ {a} | ¬ (c.source ⊆ a.source) }), b.source := by + ext z + apply Iff.intro + · intro hz + simp only [Set.mem_sdiff, Set.mem_singleton_iff, Set.mem_ofPred_eq, Set.mem_iUnion, + exists_prop] + use ChartedSpace.chartAt z + simp only [chart_mem_atlas, true_and, mem_chart_source, and_true] + by_contra hza + push Not at hza + + apply hz + apply hza + by_contra hc + rw [←hc] at hz + simp only [Set.mem_compl_iff, mem_chart_source, not_true_eq_false] at hz + exact ChartedSpace.mem_chart_source z + · intro hz + simp only [Set.mem_compl_iff] + by_contra hza + simp only [Set.mem_sdiff, Set.mem_singleton_iff, Set.mem_iUnion, exists_prop] at hz + rcases hz with ⟨ i, ⟨ ⟨ hia, hia' ⟩, his ⟩, hzi ⟩ + specialize h i + + have hic : i ∈ ChartedSpace.atlas \ {a} := Set.mem_sdiff_of_mem hia hia' + specialize h hic + + apply h + apply does_overlap + · use z + simp only [Set.mem_inter_iff] + tauto + · exact contains i hic + · exact his + + refine { isOpen_compl := ?_ } + rw [comp] + apply isOpen_biUnion + exact fun i a => i.open_source + + have hco : IsClopen a.source := ⟨hc, ho⟩ + have he : IsPreconnected (Set.univ : Set M) := isPreconnected_univ + + have he' := he.subset_isClopen hco + + have hn : (Set.univ ∩ a.source).Nonempty := by + apply Set.inter_nonempty.mpr + use x + exact (Set.mem_ite_empty_right (x ∈ Set.univ) a.source x).mp hx + have h' := he' hn + + have hs : a.source ⊆ Set.univ := by exact fun ⦃a_1⦄ a => trivial + + have he : a.source = Set.univ := Set.eq_univ_of_univ_subset (he' hn) + + have hcpct : ¬ CompactSpace a.target := by + apply noncompact_target + exact ha + exact hx + + apply hcpct + + refine isCompact_iff_compactSpace.mp ?_ + have : a.target = a.toFun '' a.source := Eq.symm (PartialEquiv.image_source_eq_target a.toPartialEquiv) + rw [this] + rw [he] + + have hcpctM : IsCompact (Set.univ : Set M) := CompactSpace.isCompact_univ + refine IsCompact.image_of_continuousOn hcpctM ?_ + rw [←he] + exact a.continuousOn_toFun + +noncomputable def classification' [T2Space M] [CompactSpace M] (ht : FinitelyIntervalChartedSpace M) : (Homeomorph M Circle) ⊕ (Homeomorph M UnitInterval) := by + -- instead, use the fact that M is nonempty and then use chartat + have x := (ConnectedSpace.toNonempty : Nonempty M).some + let φ := ht.chartAt x + + have nonempty := nonempty_atlas ht + --let φ := nonempty.some + by_cases nonempty' : (ht.atlas \ {φ}).Nonempty + · by_cases contains : ∃ (ψ : OpenPartialHomeomorph M NNReal), (ψ ∈ ht.atlas \ {φ}) ∧ (φ.source ⊆ ψ.source) + · let ψ := contains.choose + let hψ := contains.choose_spec + have hψ' : ψ ∈ ht.atlas := by + have : ht.atlas \ { φ } ⊆ ht.atlas := Set.sdiff_subset + apply this + exact hψ.1 + have : φ.source ⊆ ψ.source := hψ.2 + have hd : φ ≠ ψ := by + have : ψ ∈ ChartedSpace.atlas \ {φ} := hψ.1 + by_contra hd + rw [←hd] at this + have this' : φ ∉ ChartedSpace.atlas \ {φ} := by exact Set.notMem_sdiff_of_mem rfl + exact this' this + have ⟨ ht', ht'' ⟩ := subsume_charts ht (ChartedSpace.chart_mem_atlas x) hψ' this hd + exact classification' ht' + · have : ∃ (ψ : OpenPartialHomeomorph M NNReal), (ψ ∈ ht.atlas \ {φ}) ∧ (Overlap φ.source ψ.source) := by + simp only [not_exists, not_and] at contains + exact find_overlap ht (ChartedSpace.chart_mem_atlas x) (ChartedSpace.mem_chart_source x) contains + let ψ := this.choose + let ⟨ hψ, overlap ⟩ := this.choose_spec + have hφ := ht.is_interval φ (ChartedSpace.chart_mem_atlas x) + by_cases hφIoo : ∃ x y, Set.Ioo x y = φ.target + · have hψ'' := ht.is_interval ψ (Set.mem_of_mem_sdiff hψ) + by_cases hψIoo : ∃ x y, Set.Ioo x y = ψ.target + · -- the O O case + let a : OChart M := { φ with target_ioo := hφIoo } + let b : OChart M := { ψ with target_ioo := hψIoo } + let result := handle_o_o a b overlap + rcases result with (result|result) + · left + exact result + · rcases result with ⟨ f, hf ⟩ + let f := f.toIChart + have ⟨ ht', ht'' ⟩ := replace_charts ht (ChartedSpace.chart_mem_atlas x) (Set.mem_of_mem_sdiff hψ) overlap f hf + simp only [Set.mem_ofPred_eq] at ht'' + exact classification' ht' + · have hψIio : ∃ x, Set.Iio x = ψ.target := Or.elim hψ'' (fun x => False.elim (hψIoo x)) id + -- an O H case + let a : OChart M := { φ with target_ioo := hφIoo } + let b : HChart M := { ψ with target_iio := hψIio } + let result := handle_o_h a b overlap + + rcases result with ⟨ f, hf ⟩ + let f := f.toIChart + have ⟨ ht', ht'' ⟩ := replace_charts ht (ChartedSpace.chart_mem_atlas x) (Set.mem_of_mem_sdiff hψ) overlap f hf + simp only [Set.mem_ofPred_eq] at ht'' + exact classification' ht' + + · have hφIio : ∃ x, Set.Iio x = φ.target := Or.elim hφ (fun x => False.elim (hφIoo x)) id + have hψ'' := ht.is_interval ψ (Set.mem_of_mem_sdiff hψ) + by_cases hψIoo : ∃ x y, Set.Ioo x y = ψ.target + · -- an H O case + let a : HChart M := { φ with target_iio := hφIio } + let b : OChart M := { ψ with target_ioo := hψIoo } + let result := handle_o_h b a (overlap_symm overlap) + + rcases result with ⟨ f, hf ⟩ + let f := f.toIChart + have ⟨ ht', ht'' ⟩ := replace_charts ht (Set.mem_of_mem_sdiff hψ) (ChartedSpace.chart_mem_atlas x) (overlap_symm overlap) f hf + simp only [Set.mem_ofPred_eq] at ht'' + exact classification' ht' + + · have hψIio : ∃ x, Set.Iio x = ψ.target := Or.elim hψ'' (fun x => False.elim (hψIoo x)) id + -- the H H case + right + let a : HChart M := { φ with target_iio := hφIio } + let b : HChart M := { ψ with target_iio := hψIio } + exact handle_h_h a b overlap + · -- A compact manifold must have more than one chart + exfalso + apply nonempty' + push Not at nonempty' + have : ht.atlas ⊆ {φ} := Set.sdiff_eq_empty.mp nonempty' + have hone : Nat.card ({φ} : Set _) = 1 := by exact Nat.card_unique + have : Nat.card (ht.atlas) ≤ Nat.card ({φ} : Set _) := by + refine Nat.card_mono ?_ this + exact Set.finite_singleton φ + have t' := more_than_one_chart ht + linarith + +termination_by Set.ncard ht.atlas +decreasing_by · simp at ht'' + rw [ht''] + simp only [tsub_lt_self_iff, zero_lt_one, and_true] + exact (Set.natCard_pos (ht.is_finite)).mpr (nonempty_atlas ht) + · simp at ht'' + refine Nat.lt_of_le_pred ?_ ht'' + refine (Set.natCard_pos ?_).mpr nonempty + exact ht.is_finite + · simp at ht'' + refine Nat.lt_of_le_pred ?_ ht'' + refine (Set.natCard_pos ?_).mpr nonempty + exact ht.is_finite + · simp at ht'' + refine Nat.lt_of_le_pred ?_ ht'' + refine (Set.natCard_pos ?_).mpr nonempty + exact ht.is_finite + +noncomputable def classification [T2Space M] [CompactSpace M] (ht : ChartedSpace NNReal M) : (Homeomorph M Circle) ⊕ (Homeomorph M UnitInterval) := + let ht' := nicely_charted ht + let ht'' := interval_charted ht' + classification' (finitely_interval_charted ht'') diff --git a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean new file mode 100644 index 0000000000..20dac5747e --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean @@ -0,0 +1,1380 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib + +open Function +open Set + +theorem ici_cap_iio_empty (y : Real) : (Ici y ∩ Iio y) = ∅ := by + have h' : Ici y ∩ Iio y = Ico y y := rfl + rw [h'] + simp only [lt_self_iff_false, not_false_eq_true, Ico_eq_empty] + +theorem iic_cap_ioi_empty (y : Real) : (Iic y ∩ Ioi y) = ∅ := by + have h' : Iic y ∩ Ioi y = Ioc y y := Iic_inter_Ioi + rw [h'] + simp only [lt_self_iff_false, not_false_eq_true, Ioc_eq_empty] + +theorem not_ici (U : Set Real) (y : Real) (hu : IsOpen U) : (Ici y ≠ U) := by + by_contra h + rw [←h] at hu + + have h''' : IsClosed (Ici y) := by + apply isClosed_Ici + have ho : IsOpen (Ici y)ᶜ + exact IsClosed.isOpen_compl + have hr : IsPreconnected (univ : Set Real) := isPreconnected_univ + let hr' := hr (Ici y) ((Ici y)ᶜ) hu ho + have huniv : Ici y ∪ (Ici y)ᶜ = univ := union_compl_self (Ici y) + rw [huniv] at hr' + simp only [subset_refl, univ_inter, nonempty_Ici, compl_Ici, nonempty_Iio, forall_const] at hr' + rw [ici_cap_iio_empty] at hr' + apply Set.not_nonempty_empty + exact hr' + +theorem not_iic (U : Set Real) (y : Real) (hu : IsOpen U) : (Iic y ≠ U) := by + by_contra h + rw [←h] at hu + + have h''' : IsClosed (Iic y) := by + apply isClosed_Iic + have ho : IsOpen (Iic y)ᶜ + exact IsClosed.isOpen_compl + have hr : IsPreconnected (univ : Set Real) := isPreconnected_univ + let hr' := hr (Iic y) ((Iic y)ᶜ) hu ho + have huniv : Iic y ∪ (Iic y)ᶜ = univ := union_compl_self (Iic y) + rw [huniv] at hr' + simp only [subset_refl, univ_inter, nonempty_Iic, compl_Iic, nonempty_Ioi, forall_const] at hr' + rw [iic_cap_ioi_empty] at hr' + apply Set.not_nonempty_empty + exact hr' + +lemma ioc_not_open (x y : Real) (hxy : x < y) : ¬ IsOpen (Ioc x y) := by + have hu : (Ioc x y) ∪ (Iio y) = (Iic y) + ext p + simp only [mem_union, mem_Ioc, mem_Iio, mem_Iic] + apply Iff.intro + intro h + rcases h with (h1|h2) + tauto + exact le_of_lt h2 + by_cases hp : p = y + intro h + rw [hp] + simp only [le_refl, and_true, lt_self_iff_false, or_false] + exact hxy + intro h + right + exact lt_of_le_of_ne h hp + + by_contra hopen + have hopen' : IsOpen (Iio y) := isOpen_Iio + have hopen'' : IsOpen (Iic y) + rw [←hu] + exact IsOpen.union hopen hopen' + + have hc : IsOpen ((Iic y)ᶜ) + simp only [compl_Iic] + exact isOpen_Ioi + + have hcon := isPreconnected_univ (Iic y) ((Iic y)ᶜ) hopen'' hc + (by simp only [compl_Iic, Iic_union_Ioi, subset_refl]) + (by simp only [univ_inter, nonempty_Iic]) + (by simp only [compl_Iic, univ_inter, nonempty_Ioi]) + simp only [compl_Iic, univ_inter] at hcon + rcases hcon with ⟨x,hx⟩ + simp at hx + linarith + +lemma ico_not_open (x y : Real) (hxy : x < y) : ¬ IsOpen (Ico x y) := by + have hxy' : -y < -x := neg_lt_neg_iff.mpr hxy + have hn := ioc_not_open (-y) (-x) hxy' + + let f : Real → Real := fun x => - x + let fb : Bijective f := ⟨ neg_injective, neg_surjective ⟩ + let fe := Equiv.ofBijective f fb + have fc : Continuous fe := continuous_neg + have fo : IsOpenMap fe := isOpenMap_neg ℝ + have fh : Homeomorph Real Real + apply Equiv.toHomeomorphOfContinuousOpen + exact fc + exact fo + + by_contra h + + have p := fo (Ico x y) h + have he : fe '' (Ico x y) = Ioc (-y) (-x) + · ext t + + have ht : ∀ s : Real, fe.symm (-s) = s := fun s => Equiv.ofBijective_symm_apply_apply f fb s + have ht' := ht (-t) + simp only [neg_neg] at ht' + + simp only [mem_image_equiv, mem_Ico, mem_Ioc] + apply Iff.intro + simp only [and_imp] + intro h1 + intro h2 + constructor + rw [ht'] at h1 + rw [ht'] at h2 + linarith + + rw [ht'] at h1 + rw [ht'] at h2 + linarith + + simp only [and_imp] + intro h1 h2 + rw [ht'] + constructor + linarith + linarith + · rw [he] at p + exact hn p + +lemma icc_not_open (x y : Real) (hxy : x < y) : ¬ IsOpen (Icc x y) := by + by_contra h + have hc : IsClosed (Icc x y) := isClosed_Icc + have hc'' : IsOpen ((Icc x y)ᶜ) := IsClosed.isOpen_compl + + have hcon := isPreconnected_univ (Icc x y) ((Icc x y)ᶜ) h hc'' + (by simp only [union_compl_self, subset_refl]) + (by simp only [univ_inter, nonempty_Icc] + linarith) + (by simp only [univ_inter] + have hy : ((y + 1) ∈ (Icc x y)ᶜ) + simp only [mem_compl_iff, mem_Icc, add_le_iff_nonpos_right, not_and, not_le, + zero_lt_one, implies_true] + exact nonempty_of_mem hy) + simp only [inter_compl_self, inter_empty, Set.not_nonempty_empty] at hcon + +lemma not_ioc (U : Set Real) (x y : Real) (hu : IsOpen U) (h : Ioc x y = U) : (U = ∅) := by + by_cases hxy : (x < y) + · have h' : ¬ IsOpen (Ioc x y) + apply ioc_not_open x y + exact hxy + exfalso + apply h' + rw [h] + tauto + · have h' : Ioc x y = ∅ + exact Ioc_eq_empty hxy + rw [h] at h' + tauto + +theorem not_ico (U : Set Real) (x y : Real) (hu : IsOpen U) (h : Ico x y = U) : (U = ∅) := by + by_cases hxy : (x < y) + · have h' : ¬ IsOpen (Ico x y) + apply ico_not_open x y + exact hxy + exfalso + apply h' + rw [h] + tauto + · have h' : Ico x y = ∅ + exact Ico_eq_empty hxy + rw [h] at h' + tauto + +theorem not_icc (U : Set Real) (x y : Real) (hu : IsOpen U) (h : Icc x y = U) : (U = ∅) := by + by_cases hxy : (x < y) + · have h' : ¬ IsOpen (Icc x y) + apply icc_not_open x y + exact hxy + exfalso + apply h' + rw [h] + tauto + · by_cases hyx : (x > y) + · have h' : Icc x y = ∅ + exact Icc_eq_empty_of_lt hyx + rw [h] at h' + exact h' + · have hxy' : x ≥ y := le_of_not_gt hxy + have hyx' : x ≤ y := by exact le_of_not_gt hyx + have hxx : x = y + have hxy'' : (x = y) ∨ (y < x) := eq_or_gt_of_not_lt hxy + have hyx'' : (x = y) ∨ (x < y) := by exact Or.symm (Decidable.lt_or_eq_of_le hyx') + rcases hyx'' with (h|h) + exact h + tauto + rw [←hxx] at h + simp only [Icc_self] at h + rw [←h] at hu + exfalso + have c : ¬ IsOpen {x} := not_isOpen_singleton x + tauto + +theorem classify_intervals (U : Set Real) (hu : IsOpen U) (hc : IsPreconnected U) : + (∃ x y, (Set.Ioo x y = U)) ∨ + (∃ (x : Real), (U = Set.Iio x)) ∨ + (∃ (x : Real), (Set.Ioi x = U)) ∨ + (U = univ) ∨ (U = ∅) := by + have h : U ∈ (range (uncurry Icc)) ∪ range (uncurry Ico) ∪ range (uncurry Ioc) ∪ range (uncurry Ioo) ∪ (range Ici ∪ range Ioi ∪ range Iic ∪ range Iio ∪ {univ, ∅}) + rw [←setOfPred_isPreconnected_eq_of_ordered] + simp + exact hc + simp only [union_insert, union_singleton, mem_insert_iff, mem_union, mem_range, Prod.exists, + uncurry_apply_pair] at h + cases h + case inl h => tauto + case inr h => + cases h + case inl h => tauto + case inr h => + cases h + case inr h => + cases h + case inl h => + cases h + case inr h => by_contra + rcases h with ⟨ x', hx ⟩ + apply not_iic + exact hu + exact hx + case inl h => + cases h + case inr h => right ; right ; left ; assumption + case inl h => by_contra + rcases h with ⟨ x', hx ⟩ + apply not_ici + exact hu + exact hx + case inr h => tauto + case inl h => + cases h + case inr h => left ; tauto + case inl h => + cases h + case inl h => + cases h + case inl h => rcases h with ⟨ x, y, hx ⟩ + right ; right ; right ; right + apply not_icc + exact hu + exact hx + case inr h => rcases h with ⟨ x, y, hx ⟩ + right ; right ; right ; right + apply not_ico + exact hu + exact hx + case inr h => rcases h with ⟨ x, y, hx ⟩ + right + right + right + right + apply not_ioc + exact hu + exact hx + +macro "solve_disj" : tactic => `(tactic| repeat (apply Or.inl <|> apply Or.inr)) + +theorem classify_connected_interval (U : Set Real) (hu : IsOpen U) (hc : IsConnected U) : + (∃ x y, (Set.Ioo x y = U)) ∨ + (∃ (x : Real), (U = Set.Iio x)) ∨ + (∃ (x : Real), (Set.Ioi x = U)) ∨ + (U = univ) := by + have hpc : IsPreconnected U := by exact IsConnected.isPreconnected hc + have hi := classify_intervals U hu hpc + have ho : ¬ (U = ∅) := by + by_contra hn + rw [hn] at hc + have he : (∅ : Set Real).Nonempty := IsConnected.nonempty hc + exact Set.not_nonempty_empty he + rcases hi with (h|h|h|h|h) + left ; assumption + right ; left ; assumption + right ; right ; left ; assumption + right ; right ; right ; assumption + exfalso + exact ho h + +noncomputable def homeo_nnreal_real : (Set.Ioi 0 : Set NNReal) ≃ₜ (Set.univ : Set Real) where + toFun := fun ⟨x,_⟩ => ⟨ Real.log x, trivial ⟩ + invFun := fun ⟨x,_⟩ => ⟨ NNReal.mk (Real.exp x) (Real.exp_nonneg x), Real.exp_pos x ⟩ + left_inv := fun ⟨ ⟨ x, nn ⟩, p ⟩ => by + ext + simp only [NNReal.coe_mk] + exact Real.exp_log p + right_inv := fun x => by + simp only [NNReal.coe_mk, Real.log_exp, Subtype.coe_eta] + continuous_toFun := by + simp only + refine Continuous.subtype_mk ?_ fun x => trivial + refine Continuous.log ?_ ?_ + exact Isometry.continuous fun x1 => congrFun rfl + intro x + rcases x with ⟨x,hx⟩ + simp only [ne_eq, NNReal.coe_eq_zero] + exact pos_iff_ne_zero.mp hx + continuous_invFun := by + simp only + apply Continuous.subtype_mk + apply Continuous.subtype_mk + apply Continuous.rexp + exact continuous_subtype_val + +def relu (x : ℝ) : NNReal := + NNReal.mk (max x 0) (by simp) + +lemma relu_zero : (relu 0 = 0) := by + have : max (0 : Real) (0 : Real) = (0 : Real) := by exact max_self 0 + dsimp [relu] + simp only [max_self, NNReal.mk_zero] + +theorem continuous_relu : Continuous relu := by + apply Continuous.subtype_mk + apply Continuous.max + exact continuous_id' + exact continuous_const + + +lemma proj_relu {x : ℝ} (h : x > 0) : (relu x).toReal = x := by + have : max x 0 = x := max_eq_left_of_lt h + exact this + +lemma proj_relu' {x : ℝ} (h : x <= 0) : (relu x).toReal = 0 := by + have : 0 = max x 0 := right_eq_sup.mpr h + dsimp [relu] + rw [←this] + +lemma relu_proj {x : NNReal} : (relu x.toReal) = x := by + by_cases h0 : x = 0 + · rw [h0] + simp only [NNReal.coe_zero] + rw [relu_zero] + · have : x > 0 := by exact pos_iff_ne_zero.mpr h0 + refine NNReal.eq ?_ + rw [proj_relu] + exact this + +lemma relu_mono : StrictMonoOn relu (Set.Ici 0) := by + intro x hx y hy h + simp only [mem_Ici] at hx + simp only [mem_Ici] at hy + apply NNReal.coe_lt_coe.mp + + by_cases hx0 : x = 0 + · rw [hx0] + simp only [NNReal.coe_lt_coe] + by_cases hy0 : y = 0 + · rw [hy0] + simp only [lt_self_iff_false] + linarith + · have hy' : y > 0 := by linarith + apply NNReal.coe_lt_coe.mp + rw [proj_relu hy'] + rw [relu_zero] + simp only [NNReal.coe_zero] + assumption + · have hx' : x > 0 := by exact lt_of_le_of_ne hx fun a => hx0 (id (Eq.symm a)) + rw [proj_relu hx'] + by_cases hy0 : y = 0 + · rw [hy0] + rw [relu_zero] + simp only [NNReal.coe_zero, gt_iff_lt] + linarith + · have hy' : y > 0 := by linarith + rw [proj_relu hy'] + assumption + +lemma relu_interval_ioo {U : Set NNReal} {a b : Real} (h : Ioo a b = relu ⁻¹' U) : + (relu '' (Set.Ioo a b) = U) := by + ext x + simp only [mem_image, mem_Ioo] + constructor + · intro ⟨y,⟨ hya, hyb ⟩,hy'⟩ + have : y ∈ Set.Ioo a b := by + apply mem_Ioo.mpr + exact ⟨ hya, hyb ⟩ + rw [h] at this + simp only [mem_preimage] at this + rw [hy'] at this + assumption + · intro hx + use x.1 + simp only [NNReal.val_eq_coe] + rw [relu_proj] + simp only [and_true] + + by_cases h0 : 0 ∈ U + · have hneg : ¬ BddBelow (relu ⁻¹' U) := by + by_contra hneg + rcases hneg with ⟨ c, hc ⟩ + have hn : Set.Iio 0 ⊆ relu ⁻¹' U := by + intro z + simp only [mem_Iio, mem_preimage] + intro hz + have : (relu z) = 0 := by + apply NNReal.coe_eq_zero.mp + rw [proj_relu'] + linarith + rw [this] + assumption + dsimp [lowerBounds] at hc + have : - 2 ∈ relu ⁻¹' U := by + apply hn + simp only [mem_Iio] + simp only [Left.neg_neg_iff] + linarith + have c2 := hc this + have : c - 1 ∈ relu ⁻¹' U := by + apply hn + simp only [mem_Iio, sub_neg] + linarith + specialize hc this + linarith + rw [←h] at hneg + exfalso + exact hneg bddBelow_Ioo + · have hpos : x > 0 := by + have hnonneg : x ≥ 0 := by exact zero_le + have hzero : x ≠ 0 := by exact ne_of_mem_of_not_mem hx h0 + exact pos_iff_ne_zero.mpr hzero + have : relu (NNReal.toReal x) = x := by exact relu_proj + rw [←this] at hx + have : ↑x ∈ relu ⁻¹' U := by exact hx + rw [←h] at this + exact this + +theorem StrictMonoOn.injOn_Ioo {α : Type u_1} {β : Type u_2} {f : α → β} + [LinearOrder α] [LinearOrder β] {a : α} {b : α} (h : StrictMonoOn f (Set.Icc a b)) : + InjOn f (Set.Ioo a b) := by + intro x hx y hy hf + have hx' : x ∈ Set.Icc a b := by exact mem_Icc_of_Ioo hx + have hy' : y ∈ Set.Icc a b := by exact mem_Icc_of_Ioo hy + by_cases hxy : x < y + · have : f x < f y := by + exact h hx' hy' (hxy) + exfalso + rw [hf] at this + exact (lt_self_iff_false (f y)).mp this + · by_cases hyx : y < x + · have : f y < f x := by + exact h hy' hx' hyx + exfalso + rw [hf] at this + exact (lt_self_iff_false (f y)).mp this + · have hyx' : x ≤ y := le_of_not_gt hyx + have hxy' : y ≤ x := le_of_not_gt hxy + apply le_antisymm + assumption + assumption + +lemma relu_ioo (a b : Real) : + (relu '' (Set.Ioo a b) = Set.Ioo (relu a) (relu b)) ∨ + (relu '' (Set.Ioo a b) = Set.Ico 0 (relu b)) ∨ + (relu '' (Set.Ioo a b) = { 0 }) ∨ + (relu '' (Set.Ioo a b) = ∅) := by + by_cases ha : a > 0 + · by_cases hb : b > 0 + · left + ext z + simp only [mem_image, mem_Ioo] + constructor + · intro ⟨ x, ⟨ hx, hxz ⟩ ⟩ + have hax : relu a < relu x := by + apply NNReal.coe_lt_coe.mp + rw [proj_relu] + rw [proj_relu] + exact hx.1 + linarith + linarith + have hxb : relu x < relu b := by + apply NNReal.coe_lt_coe.mp + rw [proj_relu] + rw [proj_relu] + exact hx.2 + linarith + linarith + rw [hxz] at hax + rw [hxz] at hxb + exact ⟨hax, hxb⟩ + · intro ⟨ haz, hzb ⟩ + use z + rw [relu_proj] + simp only [and_true] + have haz' : NNReal.toReal (relu a) < NNReal.toReal z := by exact haz + have hzb' : NNReal.toReal z < NNReal.toReal (relu b) := by exact hzb + rw [proj_relu] at hzb' + rw [proj_relu] at haz' + exact ⟨haz', hzb'⟩ + exact ha + exact hb + · have : Ioo a b = ∅ := by + ext z + simp only [mem_Ioo, mem_empty_iff_false, iff_false, not_and, not_lt] + intro ha + linarith + rw [this] + simp only [image_empty] + simp only [or_true] + · by_cases hb : b > 0 + · by_cases ha0 : a = 0 + · rw [ha0] + left + ext z + simp only [mem_image, mem_Ioo] + apply Iff.intro + · intro ⟨ y, ⟨ h0y, hyb ⟩, hyz ⟩ + rw [←hyz] + apply And.intro + · rw [relu_zero] + have : 0 < NNReal.toReal (relu y) := by + rw [proj_relu] + assumption + linarith + simp only [gt_iff_lt] + exact this + · have : NNReal.toReal (relu y) < NNReal.toReal (relu b) := by + rw [proj_relu] + rw [proj_relu] + assumption + linarith + linarith + exact this + · intro ⟨ h0z, hzb ⟩ + use z.toReal + apply And.intro + · apply And.intro + · simp only [NNReal.coe_pos] + exact pos_of_gt h0z + · have : NNReal.toReal z < NNReal.toReal (relu b) := by exact hzb + exact Real.lt_toNNReal_iff_coe_lt.mp hzb + · exact relu_proj + · right ; left + ext z + simp only [mem_image, mem_Ioo, mem_Ico, zero_le, true_and] + apply Iff.intro + · intro ⟨ y, ⟨ hay, hyb ⟩ , hyz ⟩ + rw [←hyz] + dsimp [relu] + simp only [gt_iff_lt] + refine NNReal.coe_lt_coe.mp ?_ + simp only [NNReal.coe_mk, lt_sup_iff, sup_lt_iff, lt_self_iff_false, and_false, or_false] + apply And.intro <;> linarith + · intro hzb + use NNReal.toReal z + apply And.intro + · apply And.intro + · have ha0' : a < 0 := by + simp only [gt_iff_lt, not_lt] at ha + exact lt_of_le_of_ne ha ha0 + have h0z : 0 ≤ (relu z) := by exact zero_le + have h0z' : a < relu z := by exact lt_of_le_of_lt' h0z ha0' + rw [relu_proj] at h0z' + assumption + · have : NNReal.toReal z < NNReal.toReal (relu b) := by exact hzb + rw [proj_relu] at this + assumption + assumption + · rw [relu_proj] + · by_cases hab : a ≥ b + · have : Ioo a b = ∅ := by + exact Ioo_eq_empty_of_le hab + rw [this] + simp only [image_empty, or_true] + · right ; right ; left + ext z + simp only [mem_image, mem_Ioo, mem_singleton_iff] + constructor + · rintro ⟨ y, hy, hyz ⟩ + have : y ≤ 0 := by linarith + have h' := proj_relu' this + rw [hyz] at h' + exact NNReal.coe_eq_zero.mp h' + · intro hz + have hab' : a < b := by linarith + use (a + b) / 2 + apply And.intro + · apply And.intro + · exact left_lt_add_div_two.mpr hab' + · exact add_div_two_lt_right.mpr hab' + · have hn : (a + b) / 2 ≤ 0 := by linarith + rw [hz] + apply NNReal.coe_eq_zero.mp + exact proj_relu' hn + +lemma relu_iio (b : Real) : + ((relu '' (Set.Iio b) = Set.Ico 0 (relu b)) ∨ + (relu '' (Set.Iio b) = { 0 })) := by + by_cases hb : b > 0 + · left + ext z + simp only [mem_image, mem_Iio, mem_Ico, zero_le, true_and] + apply Iff.intro + · intro ⟨ x, ⟨ hxb, hxz ⟩ ⟩ + rw [←hxz] + simp only [gt_iff_lt] + dsimp [relu] + apply NNReal.coe_lt_coe.mp + simp only [NNReal.coe_mk, lt_sup_iff, sup_lt_iff, lt_self_iff_false, and_false, or_false] + apply And.intro + · assumption + · assumption + · intro hzb + use z.1 + apply And.intro + · exact Nonneg.toNonneg_lt.mp hzb + · have : z ≥ 0 := by exact zero_le + simp only [NNReal.val_eq_coe] + exact relu_proj + · right + ext z + simp only [mem_image, mem_Iio, mem_singleton_iff] + apply Iff.intro + · intro ⟨ x, ⟨ hxb, hxz ⟩ ⟩ + have : x ≤ 0 := by linarith + have hn := proj_relu' this + rw [hxz] at hn + exact NNReal.coe_eq_zero.mp hn + · intro hz + use b - 1 + simp only [sub_lt_self_iff, zero_lt_one, true_and] + have : b - 1 ≤ 0 := by linarith + have hn := proj_relu' this + rw [hz] + simp only [NNReal.coe_eq_zero] at hn + assumption + +lemma relu_univ : (relu '' univ = univ) := by + ext z + simp only [image_univ, mem_range, mem_univ, iff_true] + use z.1 + apply relu_proj + +lemma relu_ioi (b : Real) : + ((relu '' (Set.Ioi b) = Set.Ioi (relu b)) ∨ + (relu '' (Set.Ioi b) = univ)) := by + by_cases hb : b > 0 + · left + ext z + simp only [mem_image, mem_Ioi] + apply Iff.intro + · intro ⟨ x, ⟨ hbx, hxz ⟩ ⟩ + rw [←hxz] + apply NNReal.coe_lt_coe.mp + rw [proj_relu, proj_relu] + linarith + linarith + linarith + · intro hbz + use z.1 + apply And.intro + · simp only [NNReal.val_eq_coe] + refine (Real.toNNReal_lt_iff_lt_coe ?_).mp hbz + linarith + · apply relu_proj + · by_cases hb' : b = 0 + · left + rw [hb'] + ext z + simp only [mem_image, mem_Ioi] + apply Iff.intro + · intro ⟨ x, ⟨ hbx, hxz ⟩ ⟩ + rw [relu_zero] + rw [←hxz] + apply NNReal.coe_pos.mp + rw [proj_relu] + assumption + assumption + · intro hz + use z.1 + apply And.intro + rw [relu_zero] at hz + exact hz + apply relu_proj + · right + ext z + simp only [mem_image, mem_Ioi, mem_univ, iff_true] + use z.1 + simp only [NNReal.val_eq_coe] + apply And.intro + · have : 0 ≤ NNReal.toReal z := by exact NNReal.zero_le_coe + have this' : b < 0 := by + simp only [gt_iff_lt, not_lt] at hb + exact lt_of_le_of_ne hb hb' + exact lt_of_le_of_lt' this this' + · exact relu_proj + +lemma a_and_b (U : Set NNReal) (ε : Real) (εpos : ε > 0) (A : Set NNReal) (B : Set NNReal) (openA : IsOpen A) (openB : IsOpen B) + (hp : IsPreconnected U) + (interval : Set NNReal) + (interval_def : interval = Set.Ioo (0 : NNReal) (NNReal.mk ε (by linarith))) + (h1' : interval ⊆ A ∪ B) + (empty : ¬ (interval ∩ B).Nonempty) + (hA : (U \ {0} ∩ A).Nonempty) (hB : (U \ {0} ∩ B).Nonempty) + (hAB : U \ {0} ⊆ A ∪ B) : (U \ {0} ∩ (A ∩ B)).Nonempty := by + + let interval' := Set.Iio (NNReal.mk ε (by linarith)) + let A' := A ∪ interval' + have openA' : IsOpen A' := by + apply IsOpen.union openA + exact isOpen_Iio + let B' := B ∩ Set.Ioi 0 + have openB' : IsOpen B' := by + exact IsOpen.inter openB isOpen_Ioi + specialize hp A' B' openA' openB' + have h1 : U ⊆ A' ∪ B' := by + intro x hx + by_cases h0' : x = 0 + · rw [h0'] + simp only [mem_union] + left + exact mem_union_right A εpos + · have : x ∈ U \ { 0 } := by exact mem_sdiff_of_mem hx h0' + specialize hAB this + simp only [mem_union] + rcases hAB with (hAB|hAB) + · left + exact mem_union_left interval' hAB + · right + apply (mem_inter_iff x B (Ioi 0)).mpr + apply And.intro + · assumption + · apply mem_Ioi.mpr + exact pos_iff_ne_zero.mpr h0' + have h2 : (U ∩ A').Nonempty := by + rcases hA with ⟨ x, hx ⟩ + use x + simp only [mem_inter_iff] + apply And.intro + · have : x ∈ U \ {0} := by exact mem_of_mem_inter_left hx + exact mem_of_mem_sdiff this + · apply (mem_union x A interval').mpr + left + exact mem_of_mem_inter_right hx + have h3 : (U ∩ B').Nonempty := by + rcases hB with ⟨ x, hx ⟩ + use x + simp only [mem_inter_iff] + apply And.intro + · have : x ∈ U \ { 0 } := by exact mem_of_mem_inter_left hx + exact mem_of_mem_sdiff this + · apply (mem_inter_iff x B (Ioi 0)).mpr + apply And.intro + · exact mem_of_mem_inter_right hx + · apply mem_Ioi.mpr + have : x ∈ U \ { 0 } := by exact mem_of_mem_inter_left hx + have this' : x ∉ ({ 0 } : Set NNReal) := by exact notMem_of_mem_sdiff this + exact pos_iff_ne_zero.mpr this' + + specialize hp h1 h2 h3 + rcases hp with ⟨ x, hx ⟩ + use x + simp only [mem_inter_iff, mem_sdiff, mem_singleton_iff] + + have hn0 : x ≠ 0 := by + have : x ∈ A' ∩ B' := by exact mem_of_mem_inter_right hx + have : x ∈ B' := by exact mem_of_mem_inter_right this + have : x ∈ Set.Ioi 0 := by exact mem_of_mem_inter_right this + exact pos_iff_ne_zero.mp this + + apply And.intro + · apply And.intro + · exact mem_of_mem_inter_left hx + · exact hn0 + · apply And.intro + · have : x ∈ A' ∩ B' := by exact mem_of_mem_inter_right hx + have : x ∈ A' := by exact mem_of_mem_inter_left this + simp only [A'] at this + rcases this with (this|this) + · assumption + · have hi : x ∈ interval := by + rw [interval_def] + simp only [mem_Ioo] + dsimp [interval'] at this + simp only [mem_Iio] at this + apply And.intro + · exact pos_iff_ne_zero.mpr hn0 + · exact this + have this' := h1' hi + rcases this' with (this'|this') + · assumption + · exfalso + apply empty + use x + exact mem_inter hi this' + · have : x ∈ A' ∩ B' := by exact mem_of_mem_inter_right hx + have : x ∈ B' := by exact mem_of_mem_inter_right this + exact mem_of_mem_inter_left this + +lemma remove_zero_connected (U : Set NNReal) (h0 : 0 ∈ U) (hu : IsOpen U) (hc : IsConnected U) : + IsConnected (U \ {0}) := by + rcases Metric.isOpen_iff.mp hu 0 h0 with ⟨ ε, εpos, hε ⟩ + dsimp [IsConnected] + apply And.intro + · let ε' : NNReal := NNReal.mk (ε/2) (by linarith) + have : ε' ∈ Metric.ball 0 ε := by + simp only [Metric.mem_ball] + dsimp [ε'] + have hd : dist ε' 0 = ε/2 := by + rw [NNReal.dist_eq] + simp only [ε', NNReal.coe_mk, NNReal.coe_zero, sub_zero] + exact abs_of_nonneg (by linarith) + rw [hd] + simp only [half_lt_self_iff, gt_iff_lt] + linarith + use ε' + apply mem_sdiff_singleton.mpr + apply And.intro + · exact hε this + · apply NNReal.coe_ne_zero.mp + simp only [ne_eq, NNReal.coe_eq_zero] + dsimp [ε'] + apply NNReal.coe_ne_zero.mp + simp only [NNReal.coe_mk, ne_eq, div_eq_zero_iff, OfNat.ofNat_ne_zero, or_false] + exact ne_of_gt εpos + · dsimp [IsPreconnected] + by_contra h + simp only [not_forall] at h + rcases h with ⟨ A, B, openA, openB, hAB, hA, hB, hn ⟩ + have hp : IsPreconnected U := IsConnected.isPreconnected hc + + let interval := Set.Ioo (0 : NNReal) (NNReal.mk ε (by linarith)) + have h1' : interval ⊆ A ∪ B := by + intro x hx + apply hAB + simp only [mem_sdiff, mem_singleton_iff] + apply And.intro + · apply hε + simp only [Metric.mem_ball] + simp only [interval, mem_Ioo] at hx + rw [NNReal.dist_eq] + simp only [NNReal.coe_zero, sub_zero, NNReal.abs_eq] + exact hx.right + · by_contra h0 + rw [h0] at hx + simp only [interval, mem_Ioo, lt_self_iff_false, false_and] at hx + + have cb : IsPreconnected interval := isPreconnected_Ioo + specialize cb A B openA openB h1' + + have iu : interval ⊆ U := by + intro x hx + simp only [interval, mem_Ioo] at hx + apply hε + simp only [Metric.mem_ball] + rw [NNReal.dist_eq] + simp only [NNReal.coe_zero, sub_zero, NNReal.abs_eq] + exact hx.right + + have hn' : ¬ (interval ∩ (A ∩ B)).Nonempty := by + by_contra hn'' + rcases hn'' with ⟨ x, hn'' ⟩ + apply hn + use x + apply (mem_inter_iff x (U \ {0}) (A ∩ B)).mpr + apply And.intro + · apply mem_sdiff_singleton.mpr + apply And.intro + · have : x ∈ interval := by exact mem_of_mem_inter_left hn'' + apply iu + assumption + · have : x ∈ interval := by exact mem_of_mem_inter_left hn'' + by_contra x0 + rw [x0] at this + simp only [interval, mem_Ioo, lt_self_iff_false, false_and] at this + · exact mem_of_mem_inter_right hn'' + + have empty : (¬ (interval ∩ A).Nonempty ∨ ¬ (interval ∩ B).Nonempty) := by tauto + apply hn + rcases empty with (empty|empty) + · have h1'' : interval ⊆ B ∪ A := by + intro x hx + simp only [mem_union] + specialize h1' hx + simp only [mem_union] at h1' + tauto + have hBA : U \ {0} ⊆ B ∪ A := by + intro x hx + simp only [mem_union] + specialize hAB hx + simp only [mem_union] at hAB + tauto + have := a_and_b U ε εpos B A openB openA hp interval (by exact rfl) h1'' empty hB hA hBA + rcases this with ⟨ x, hx ⟩ + use x + simp only [mem_inter_iff] + simp only [mem_inter_iff] at hx + tauto + · exact a_and_b U ε εpos A B openA openB hp interval (by exact rfl) h1' empty hA hB hAB + +lemma zero_in_open (a b : NNReal) (h : IsOpen ((Ioo a b) ∪ {0})) : a ≤ 0 ∧ 0 < b := by + by_contra h' + simp only [nonpos_iff_eq_zero, not_and, not_lt] at h' + by_cases ha : a = 0 + · specialize h' ha + rw [ha] at h + rw [h'] at h + simp only [lt_self_iff_false, not_false_eq_true, Ioo_eq_empty, union_singleton, + insert_empty_eq] at h + have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 + apply this + assumption + · let U := Set.Iio (a / 2) + have openU : IsOpen U := by exact isOpen_Iio + let U' := U ∩ (Ioo a b ∪ {0}) + let openU' : IsOpen U' := by exact IsOpen.inter openU h + have U0 : U' = { 0 } := by + ext x + simp only [mem_singleton_iff] + apply Iff.intro + · intro hx + dsimp [U, U'] at hx + simp only [union_singleton, mem_inter_iff, mem_Iio, mem_insert_iff, mem_Ioo] at hx + have hx1 := hx.1 + have hx2 := hx.2 + rcases hx2 with (hx2|hx2) + · exact hx2 + · have : a < x := hx2.1 + exfalso + have this' : a < a / 2 := by exact gt_trans hx1 this + have this'' : a.toReal < a.toReal / 2 := by exact this' + have this3 : 0 ≤ a.toReal := by exact NNReal.zero_le_coe + linarith + · intro hx + dsimp [U, U'] + simp only [union_singleton, mem_inter_iff, mem_Iio, mem_insert_iff, mem_Ioo] + apply And.intro + · rw [hx] + have : 0 < a := by exact pos_iff_ne_zero.mpr ha + exact half_pos this + · left ; assumption + have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 + apply this + rwa [U0] at openU' + +theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc : IsConnected U) : + (∃ x y, (Set.Ioo x y = U)) ∨ + (∃ (x : NNReal), (Set.Iio x = U)) ∨ + (∃ (x : NNReal), (Set.Ioi x = U)) ∨ + (U = univ) := by + let U0 := U ∩ (Set.Ioi 0) + have hu0 : IsOpen U0 := IsOpen.inter hu isOpen_Ioi + + let U' := relu ⁻¹' U0 + + have hr : (relu ⁻¹' U0) = (Set.Ioi (0 : Real)) ∩ (NNReal.toReal '' U) := by + ext x + simp only [mem_preimage, mem_inter_iff, mem_Ioi, mem_image] + constructor + · intro h + have : U0 ⊆ Set.Ioi 0 := inter_subset_right + have hr : relu x ∈ Set.Ioi 0 := this h + simp at hr + have hr' : 0 < x := Real.toNNReal_pos.mp (this h) + constructor + · exact hr' + · use relu x + constructor + · have : U0 ⊆ U := by exact inter_subset_left + exact this h + · have hf : (relu x).1 = x := by + apply proj_relu + assumption + assumption + · rintro ⟨h1,⟨y,⟨hu,hy⟩⟩⟩ + rw [←hy] + rw [relu_proj] + apply mem_inter hu + rw [←hy] at h1 + exact h1 + + have hu' : IsOpen U' := Continuous.isOpen_preimage continuous_relu U0 hu0 + + have hc' : IsConnected U' := by + by_cases h0 : 0 ∈ U + · dsimp [U'] + rw [hr] + have hs0 : IsConnected (U \ {0}) := by exact remove_zero_connected U h0 hu hc + have he : (Ioi 0 ∩ NNReal.toReal '' U) = NNReal.toReal '' (U \ {0}) := by + ext z + simp only [mem_inter_iff, mem_Ioi, mem_image, mem_sdiff, mem_singleton_iff] + apply Iff.intro + · intro ⟨ zpos, ⟨ x, ⟨ hx, hx' ⟩ ⟩ ⟩ + use x + apply And.intro + · apply And.intro + · assumption + · by_contra h' + rw [h'] at hx' + simp only [NNReal.coe_zero] at hx' + rw [←hx'] at zpos + exact (lt_self_iff_false 0).mp zpos + · assumption + · intro ⟨ x, ⟨ ⟨ h1, h2 ⟩, h3 ⟩ ⟩ + apply And.intro + · rw [←h3] + simp only [NNReal.coe_pos] + exact pos_iff_ne_zero.mpr h2 + · use x + rw [he] + have : Continuous NNReal.toReal := by exact NNReal.continuous_coe + apply IsConnected.image hs0 NNReal.toReal + apply Continuous.continuousOn + exact this + · have he : U' = NNReal.toReal '' U := by + ext z + simp only [mem_image] + apply Iff.intro + · intro hz + dsimp [U'] at hz + rw [hr] at hz + simp only [mem_inter_iff, mem_Ioi, mem_image] at hz + rcases hz with ⟨ hzpos, hz ⟩ + assumption + · rintro ⟨ x, ⟨ hx, hz ⟩ ⟩ + apply mem_preimage.mpr + rw [←hz] + rw [relu_proj] + dsimp [U0] + simp only [mem_inter_iff, mem_Ioi] + apply And.intro + · assumption + · have : x ≥ 0 := by exact zero_le + have this' : x ≠ 0 := by exact ne_of_mem_of_not_mem hx h0 + exact pos_iff_ne_zero.mpr this' + rw [he] + apply IsConnected.image hc NNReal.toReal + have : Continuous NNReal.toReal := by exact NNReal.continuous_coe + apply Continuous.continuousOn + assumption + + let c := classify_connected_interval U' hu' hc' + + have h0u0 : 0 ∉ U0 := by + apply zero_notMem_iff.mpr + intro z hz + have : z ∈ Set.Ioi (0 : NNReal) := mem_of_mem_inter_right hz + exact this + + have h0u' : 0 ∉ U' := by + dsimp [U'] + simp only [mem_preimage] + rw [relu_zero] + assumption + + rcases c with (c|c|c|c) + · rcases c with ⟨ a, b, c ⟩ + have c' := relu_ioo a b + have hc := relu_interval_ioo c + rw [hc] at c' + by_cases hu0' : 0 ∈ U + · have uu0 : U = U0 ∪ { 0 } := by + ext x + simp only [union_singleton, mem_insert_iff] + apply Iff.intro + · intro hx + dsimp [U0] + simp only [mem_inter_iff, mem_Ioi] + by_cases h : x = 0 + · left ; exact h + · right ; apply And.intro + · assumption + · exact pos_iff_ne_zero.mpr h + · intro hx + rcases hx with (hx|hx) + · rw [hx] + assumption + · dsimp [U0] at hx + simp only [mem_inter_iff, mem_Ioi] at hx + exact hx.1 + rw [uu0] + rcases c' with (c'|c'|c'|c') + · right + left + rw [c'] + rw [c'] at uu0 + rw [uu0] at hu + have hz := zero_in_open (relu a) (relu b) hu + use relu b + ext x + simp only [mem_Iio, union_singleton, mem_insert_iff, mem_Ioo] + apply Iff.intro + · intro hx + by_cases h0 : x = 0 + · left ; exact h0 + · right + apply And.intro + · have : 0 < x := by exact pos_iff_ne_zero.mpr h0 + exact lt_of_le_of_lt hz.1 this + · assumption + · intro hx + rcases hx with (hx|hx) + · rw [hx] + exact hz.2 + · exact hx.2 + · by_cases hb : relu b = 0 + · rw [hb] at c' + simp only [lt_self_iff_false, not_false_eq_true, Ico_eq_empty] at c' + rw [c'] at uu0 + simp only [union_singleton, insert_empty_eq] at uu0 + rw [uu0] at hu + have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 + exfalso + exact this hu + · right + left + use relu b + rw [c'] + ext x + simp only [mem_Iio, union_singleton, mem_insert_iff, mem_Ico, zero_le, true_and, + iff_or_self] + intro hx + rw [hx] + exact pos_iff_ne_zero.mpr hb + · rw [c'] at hu0 + exfalso + have this' : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 + exact this' hu0 + · rw [c'] at uu0 + simp only [union_singleton, insert_empty_eq] at uu0 + have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 + rw [uu0] at hu + exfalso + exact this hu + · have uu0 : U = U0 := by + dsimp [U0] + simp only [left_eq_inter] + intro x hx + simp only [mem_Ioi] + have : x ≠ 0 := by exact ne_of_mem_of_not_mem hx hu0' + exact pos_iff_ne_zero.mpr this + rw [←uu0] at c' + rcases c' with (c'|c'|c'|c') + · left + use relu a + use relu b + rw [c'] + · right + left + use (relu b) + rw [c'] + ext x + simp only [mem_Iio, mem_Ico, zero_le, true_and] + · rw [c'] at hu + exfalso + have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 + apply this + exact hu + · left + use 0 + use 0 + rw [c'] + simp only [lt_self_iff_false, not_false_eq_true, Ioo_eq_empty] + · rcases c with ⟨ x, hx ⟩ + rw [hx] at h0u' + simp only [mem_Iio, not_lt] at h0u' + dsimp [U'] at hx + rw [hr] at hx + have hxi : x - 1 ∈ Set.Iio x := by + apply mem_Iio.mpr + linarith + rw [←hx] at hxi + have hc : x - 1 ∈ Set.Ioi 0 := by exact mem_of_mem_inter_left hxi + simp only [mem_Ioi, sub_pos] at hc + linarith + · rcases c with ⟨ x, c ⟩ + by_cases h0 : x = 0 + · by_cases hu0 : 0 ∈ U + · right ; right ; right + rw [h0] at c + dsimp [U'] at c + ext z + simp only [mem_univ, iff_true] + by_cases hz0 : z = 0 + · rw [hz0] + assumption + · have zpos : z > 0 := by + exact pos_iff_ne_zero.mpr hz0 + have zi : z ∈ Set.Ioi 0 := by exact zpos + have zi' : NNReal.toReal z ∈ relu ⁻¹' U0 := by + rw [←c] + simp only [mem_Ioi, NNReal.coe_pos] + assumption + simp only [mem_preimage] at zi' + rw [relu_proj] at zi' + exact mem_of_mem_inter_left zi' + · right ; right ; left + use 0 + have uu0 : U = U0 := by + ext z + apply Iff.intro + · intro hz + dsimp [U0] + simp only [mem_inter_iff, mem_Ioi] + apply And.intro + · exact hz + · have : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 + exact pos_iff_ne_zero.mpr this + · intro hz + exact mem_of_mem_inter_left hz + rw [uu0] + rw [h0] at c + ext z + simp only [mem_Ioi] + apply Iff.intro + · intro hz + have : NNReal.toReal z > 0 := by exact hz + have this' : NNReal.toReal z ∈ U' := by + rw [←c] + simp only [mem_Ioi, NNReal.coe_pos] + assumption + dsimp [U'] at this' + simp only [mem_preimage] at this' + rw [relu_proj] at this' + assumption + · intro hz + rw [←uu0] at hz + have : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 + exact pos_iff_ne_zero.mpr this + · by_cases hx : x < 0 + · have : 0 ∈ U' := by + have this' : 0 ∈ Set.Ioi x := by exact hx + rw [c] at this' + assumption + exfalso + exact h0u' this + · right ; right ; left + by_cases hu0 : 0 ∈ U + · have : U = U0 ∪ {0} := by + ext z + simp only [union_singleton, mem_insert_iff] + apply Iff.intro + · intro hz + by_cases hz' : z = 0 + · left ; assumption + · right + dsimp [U0] + refine (mem_inter_iff z U (Ioi 0)).mpr ?_ + apply And.intro + · assumption + · simp only [mem_Ioi] + exact pos_iff_ne_zero.mpr hz' + · intro hz + rcases hz with (hz|hz) + · rw [hz] + assumption + · exact mem_of_mem_inter_left hz + dsimp [U'] at c + rw [hr] at c + + have contra : ¬ IsConnected U := by + dsimp [IsConnected] + simp only [not_and] + intro hn + dsimp [IsPreconnected] + simp only [not_forall] + have xpos : x ≥ 0 := by linarith + use Set.Iio (NNReal.mk x xpos) + use Set.Ioi (NNReal.mk x xpos) + simp only [exists_prop, Iio_union_Ioi, subset_compl_singleton_iff] + apply And.intro + · exact isOpen_Iio + · apply And.intro + · exact isOpen_Ioi + · apply And.intro + · by_contra h + have h' : NNReal.toReal (NNReal.mk x xpos) ∈ NNReal.toReal '' U := + mem_image_of_mem NNReal.toReal h + have h'' : NNReal.toReal (NNReal.mk x xpos) ∈ Set.Ioi 0 := by + apply mem_Ioi.mpr + exact lt_of_le_of_ne xpos fun a => h0 (id (Eq.symm a)) + have h3 : NNReal.toReal (NNReal.mk x xpos) ∈ Set.Ioi x := by + rw [c] + exact mem_inter h'' h' + simp only [NNReal.coe_mk, mem_Ioi, lt_self_iff_false] at h3 + · apply And.intro + · use 0 + simp only [mem_inter_iff, mem_Iio] + apply And.intro + · assumption + · apply NNReal.coe_pos.mp + simp only [NNReal.coe_mk] + exact lt_of_le_of_ne xpos fun a => h0 (id (Eq.symm a)) + · apply And.intro + · apply inter_nonempty.mpr + use (1 : NNReal) + (NNReal.mk x xpos) + apply And.intro + · have : 1 + x ∈ Set.Ioi x := by + apply mem_Ioi.mpr + exact lt_one_add x + rw [c] at this + simp only [mem_inter_iff, mem_Ioi, mem_image] at this + rcases this with ⟨ tpos, ⟨ t, ⟨ tu, ht ⟩ ⟩ ⟩ + have ht2 : t = 1 + (NNReal.mk x xpos) := by + exact NNReal.eq ht + rw [←ht2] + assumption + · apply mem_Ioi.mpr + exact lt_one_add ((NNReal.mk x xpos) : NNReal) + · refine not_nonempty_iff_eq_empty.mpr ?_ + let x' : NNReal := (NNReal.mk x xpos) + have : (Set.Iio x' ∩ Set.Ioi x') = ∅ := by + ext z + simp only [mem_inter_iff, mem_Iio, mem_Ioi, mem_empty_iff_false, + iff_false, not_and, not_lt] + intro hz + exact le_of_lt hz + rw [this] + simp only [inter_empty] + exfalso + exact contra hc + · have h0' : 0 ∉ Set.Ioi x := by exact Eq.mpr_not (congrFun c 0) h0u' + simp only [mem_Ioi, not_lt] at h0' + use (NNReal.mk x h0') + ext z + simp only [mem_Ioi] + apply Iff.intro + · intro hxz + have hu' : NNReal.toReal z ∈ U' := by + rw [←c] + simp only [mem_Ioi] + exact hxz + have : NNReal.toReal z ∈ Ioi 0 ∩ NNReal.toReal '' U := by + rw [←hr] + exact hu' + have this' : NNReal.toReal z ∈ NNReal.toReal '' U := mem_of_mem_inter_right this + simp only [mem_image, NNReal.coe_inj, exists_eq_right] at this' + assumption + · intro hz + apply NNReal.coe_lt_coe.mp + simp only [NNReal.coe_mk] + dsimp [U'] at c + have z0 : z ∈ U0 := by + refine (mem_inter_iff z U (Ioi 0)).mpr ?_ + apply And.intro + · exact hz + · refine mem_Ioi.mpr ?_ + refine NNReal.coe_pos.mp ?_ + simp only [NNReal.coe_pos] + have hz0 : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 + exact pos_iff_ne_zero.mpr hz0 + have : NNReal.toReal z ∈ Set.Ioi 0 ∩ NNReal.toReal '' U := by + simp only [mem_inter_iff, mem_Ioi, NNReal.coe_pos, mem_image, NNReal.coe_inj, + exists_eq_right] + apply And.intro + · have : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 + have this' : z ≥ 0 := by exact zero_le + exact pos_iff_ne_zero.mpr this + assumption + rw [←hr] at this + rw [←c] at this + simp only [mem_Ioi] at this + assumption + · exfalso + have h0i : 0 ∉ Set.Ioi (0 : NNReal) := self_notMem_Ioi + have this' : 0 ∈ U0 := by + have : 0 ∈ U' := by + rw [c] + exact trivial + dsimp [U'] at this + simp only [mem_preimage] at this + rw [relu_zero] at this + assumption + exact h0u0 this' diff --git a/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean b/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean new file mode 100644 index 0000000000..170bbebfb4 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean @@ -0,0 +1,452 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.UnitInterval +import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts +import LeanPool.OneManifold.OneMfld.IntervalCharts +import LeanPool.OneManifold.OneMfld.NiceCharts +import LeanPool.OneManifold.OneMfld.ClosureOverlap +import LeanPool.OneManifold.OneMfld.RealIntervals +import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers +import LeanPool.OneManifold.OneMfld.Charts +import LeanPool.OneManifold.OneMfld.Outer +import LeanPool.OneManifold.OneMfld.TransitionMono +import LeanPool.OneManifold.OneMfld.Normalize +import LeanPool.OneManifold.OneMfld.GlueCore +import LeanPool.OneManifold.OneMfld.GlueBlocks +import LeanPool.OneManifold.OneMfld.GlueNNReal +import LeanPool.OneManifold.OneMfld.GlueUI +import LeanPool.OneManifold.OneMfld.TwoComponents +import LeanPool.OneManifold.OneMfld.CircleBlocks +import LeanPool.OneManifold.OneMfld.CircleGlue + +open Set + +variable + {M : Type*} + [TopologicalSpace M] + [ConnectedSpace M] + [T2Space M] + +open Classical in +/-- Turn a homeomorphism of open subtypes `A ≃ₜ B` into a partial homeomorphism `X ⇀ Y`. + +The `Nonempty` hypotheses are needed, and are not an artefact of the proof: a +`PartialEquiv X Y` carries a *total* `toFun : X → Y`, so `OpenPartialHomeomorph Unit Empty` +is an empty type even though `(∅ : Set Unit) ≃ₜ (∅ : Set Empty)` with both sets open. -/ +noncomputable def Homeomorph.toOpenPartialHomeomorphOnOpens + {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] [Nonempty X] [Nonempty Y] + {A : Set X} {B : Set Y} (h : A ≃ₜ B) (hA : IsOpen A) (hB : IsOpen B) : + OpenPartialHomeomorph X Y where + toFun x := if hx : x ∈ A then (h ⟨x, hx⟩ : Y) else Classical.arbitrary Y + invFun y := if hy : y ∈ B then (h.symm ⟨y, hy⟩ : X) else Classical.arbitrary X + source := A + target := B + map_source' x hx := by simp only [dif_pos hx]; exact (h ⟨x, hx⟩).2 + map_target' y hy := by simp only [dif_pos hy]; exact (h.symm ⟨y, hy⟩).2 + left_inv' x hx := by + simp only [dif_pos hx, dif_pos (h ⟨x, hx⟩).2] + have : (⟨(h ⟨x, hx⟩ : Y), (h ⟨x, hx⟩).2⟩ : B) = h ⟨x, hx⟩ := rfl + rw [this, Homeomorph.symm_apply_apply] + right_inv' y hy := by + simp only [dif_pos hy, dif_pos (h.symm ⟨y, hy⟩).2] + have : (⟨(h.symm ⟨y, hy⟩ : X), (h.symm ⟨y, hy⟩).2⟩ : A) = h.symm ⟨y, hy⟩ := rfl + rw [this, Homeomorph.apply_symm_apply] + open_source := hA + open_target := hB + continuousOn_toFun := by + rw [continuousOn_iff_continuous_domRestrict] + have : (A.domRestrict fun x => if hx : x ∈ A then (h ⟨x, hx⟩ : Y) else Classical.arbitrary Y) + = fun x : A => ((h x : B) : Y) := by + funext x; simp only [Set.domRestrict_apply, dif_pos x.2] + rw [this] + exact continuous_subtype_val.comp h.continuous + continuousOn_invFun := by + rw [continuousOn_iff_continuous_domRestrict] + have : (B.domRestrict fun y => if hy : y ∈ B then (h.symm ⟨y, hy⟩ : X) else Classical.arbitrary X) + = fun y : B => ((h.symm y : A) : X) := by + funext y; simp only [Set.domRestrict_apply, dif_pos y.2] + rw [this] + exact continuous_subtype_val.comp h.symm.continuous + +/-- An `OpenPartialHomeomorph` from a preconnected Hausdorff space onto the whole of a +compact space, with nonempty source, is a global homeomorphism: its source is compact +(hence closed) as well as open, so it is clopen and equals `univ`. -/ +noncomputable def OpenPartialHomeomorph.toHomeomorphOfCompactTarget + {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] + [PreconnectedSpace X] [T2Space X] [CompactSpace Y] + (φ : OpenPartialHomeomorph X Y) + (hne : φ.source.Nonempty) + (ht : φ.target = Set.univ) : + Homeomorph X Y := by + have ho : IsOpen φ.source := φ.open_source + have hc : IsClosed φ.source := by + have cpct' : CompactSpace φ.target := by + rw [ht] + exact (Homeomorph.Set.univ Y).symm.compactSpace + have h : Homeomorph φ.target φ.source := φ.toHomeomorphSourceTarget.symm + have hcs : CompactSpace φ.source := h.compactSpace + have cpct : IsCompact φ.source := isCompact_iff_isCompact_univ.mpr CompactSpace.isCompact_univ + exact cpct.isClosed + have hs : φ.source = Set.univ := by + have hco : IsClopen φ.source := ⟨hc, ho⟩ + have he' := isPreconnected_univ.subset_isClopen hco (by simpa using hne) + exact Set.eq_univ_of_univ_subset he' + exact φ.toHomeomorphOfSourceEqUnivTargetEqUniv hs ht + +section OverlapHelpers + +omit [ConnectedSpace M] [T2Space M] in +/-- The chart image of the overlap is never the whole target (since `U.source` is not +contained in `V.source`). -/ +lemma overlap_image_ne_target (U V : OpenPartialHomeomorph M NNReal) + (hUV : (U.source \ V.source).Nonempty) : + U '' (U.source ∩ V.source) ≠ U.target := by + intro heq + obtain ⟨y, hyU, hyV⟩ := hUV + have hy : U y ∈ U '' (U.source ∩ V.source) := heq ▸ U.map_source hyU + obtain ⟨w, hwS, hwy⟩ := hy + have hw : w = y := U.injOn hwS.1 hyU hwy + exact hyV (hw ▸ hwS.2) + +omit [ConnectedSpace M] in +/-- The outer-overlap lemma for a boundary chart, specialized to a connected overlap. -/ +lemma overlap_image_Iio (U V : OpenPartialHomeomorph M NNReal) {v : NNReal} + (hUt : U.target = Iio v) + (hV : IsConnected V.source) + (hUV : (U.source \ V.source).Nonempty) + (hVU : (V.source \ U.source).Nonempty) + (hc : IsConnected (U.source ∩ V.source)) : + ∃ p, p < v ∧ U '' (U.source ∩ V.source) = Ioo p v := by + obtain ⟨x, hx⟩ := hc.nonempty + obtain ⟨p, hp, himg⟩ := overlap_component_outer_Iio U V hUt hV hUV hVU hx + have hcomp : connectedComponentIn (U.source ∩ V.source) x = U.source ∩ V.source := + subset_antisymm (connectedComponentIn_subset _ _) + (hc.isPreconnected.subset_connectedComponentIn hx subset_rfl) + rw [hcomp] at himg + exact ⟨p, hp, himg⟩ + +omit [ConnectedSpace M] in +/-- The outer-overlap lemma for an interior chart, specialized to a connected overlap. -/ +lemma overlap_image_Ioo (U V : OpenPartialHomeomorph M NNReal) {u v : NNReal} + (hUt : U.target = Ioo u v) + (hV : IsConnected V.source) + (hVU : (V.source \ U.source).Nonempty) + (hc : IsConnected (U.source ∩ V.source)) : + (∃ p, u ≤ p ∧ p < v ∧ U '' (U.source ∩ V.source) = Ioo p v) ∨ + (∃ q, u < q ∧ q ≤ v ∧ U '' (U.source ∩ V.source) = Ioo u q) := by + obtain ⟨x, hx⟩ := hc.nonempty + have hcomp : connectedComponentIn (U.source ∩ V.source) x = U.source ∩ V.source := + subset_antisymm (connectedComponentIn_subset _ _) + (hc.isPreconnected.subset_connectedComponentIn hx subset_rfl) + rcases overlap_component_outer_Ioo U V hUt hV hVU hx with ⟨p, h1, h2, himg⟩ | ⟨q, h1, h2, himg⟩ + · rw [hcomp] at himg + exact Or.inl ⟨p, h1, h2, himg⟩ + · rw [hcomp] at himg + exact Or.inr ⟨q, h1, h2, himg⟩ + +omit [ConnectedSpace M] in +/-- The overlap of a boundary chart with a connected chart is connected. -/ +lemma hchart_overlap_connected (b : HChart M) (V : OpenPartialHomeomorph M NNReal) + (hV : IsConnected V.source) + (hbV : (b.source \ V.source).Nonempty) + (hVb : (V.source \ b.source).Nonempty) + (hne : (b.source ∩ V.source).Nonempty) : + IsConnected (b.source ∩ V.source) := by + obtain ⟨v, hv⟩ := b.target_iio + exact overlap_connected b.toOpenPartialHomeomorph V hv.symm hV hbV hVb hne + +lemma Ioc_union_Ioo_eq_Ioo {μ ν : NNReal} (hμν : μ < ν) : + Ioc 0 μ ∪ Ioo μ ν = Ioo 0 ν := by + ext y + simp only [mem_union, mem_Ioc, mem_Ioo] + constructor + · rintro (⟨hy0, hy⟩ | ⟨hy, hy'⟩) + · exact ⟨hy0, lt_of_le_of_lt hy hμν⟩ + · exact ⟨lt_of_le_of_lt (zero_le : (0 : NNReal) ≤ μ) hy, hy'⟩ + · rintro ⟨hy0, hy⟩ + rcases le_or_gt y μ with hle | hgt + · exact Or.inl ⟨hy0, hle⟩ + · exact Or.inr ⟨hgt, hy⟩ + +lemma lt_div_self_of_lt_one {μ ρ : NNReal} (hμ0 : 0 < μ) (hρ0 : 0 < ρ) (hρ1 : ρ < 1) : + μ < μ / ρ := by + rw [lt_div_iff₀ hρ0] + exact mul_lt_of_lt_one_right hμ0 hρ1 + +end OverlapHelpers + +section Orient + +omit [ConnectedSpace M] in +/-- Re-orient an `OChart` with target `Ioo 0 1` (flipping if necessary) so that its image +of the overlap with `V.source` is the *lower* end-segment `Ioo 0 r` with `0 < r < 1`. +The source is unchanged. -/ +lemma OChart.exists_orient_lower (a : OChart M) (V : OpenPartialHomeomorph M NNReal) + (hat : a.target = Ioo 0 1) + (hV : IsConnected V.source) + (haV : (a.source \ V.source).Nonempty) + (hVa : (V.source \ a.source).Nonempty) + (hc : IsConnected (a.source ∩ V.source)) : + ∃ (a' : OChart M) (r : NNReal), a'.source = a.source ∧ a'.target = Ioo 0 1 ∧ + 0 < r ∧ r < 1 ∧ + a'.toOpenPartialHomeomorph '' (a.source ∩ V.source) = Ioo 0 r := by + have hne := overlap_image_ne_target a.toOpenPartialHomeomorph V haV + rcases overlap_image_Ioo a.toOpenPartialHomeomorph V hat hV hVa hc with + ⟨p, -, hp1, himg⟩ | ⟨r, hr0, hr1, himg⟩ + · -- upper case: flip + have hp0 : 0 < p := by + rcases eq_or_lt_of_le (zero_le : (0 : NNReal) ≤ p) with heq | hlt + · exfalso + apply hne + rw [himg, hat, ← heq] + · exact hlt + obtain ⟨a', ha's, ha't, ha'f⟩ := a.flip hat + have himg' : a'.toOpenPartialHomeomorph '' (a.source ∩ V.source) + = (fun y => 1 - y) '' (a.toOpenPartialHomeomorph '' (a.source ∩ V.source)) := by + rw [← image_comp] + exact image_congr (fun x hx => ha'f x hx.1) + rw [himg, reflect_image_Ioo_upper hp1] at himg' + exact ⟨a', 1 - p, ha's, ha't, tsub_pos_of_lt hp1, tsub_lt_self one_pos hp0, himg'⟩ + · -- lower case: already oriented + have hr1' : r < 1 := by + rcases eq_or_lt_of_le hr1 with heq | hlt + · exfalso + apply hne + rw [himg, hat, heq] + · exact hlt + exact ⟨a, r, rfl, hat, hr0, hr1', himg⟩ + +omit [ConnectedSpace M] in +/-- Re-orient an `OChart` with target `Ioo 0 1` (flipping if necessary) so that its image +of the overlap with `V.source` is the *upper* end-segment `Ioo q 1` with `0 < q < 1`. +The source is unchanged. -/ +lemma OChart.exists_orient_upper (a : OChart M) (V : OpenPartialHomeomorph M NNReal) + (hat : a.target = Ioo 0 1) + (hV : IsConnected V.source) + (haV : (a.source \ V.source).Nonempty) + (hVa : (V.source \ a.source).Nonempty) + (hc : IsConnected (a.source ∩ V.source)) : + ∃ (a' : OChart M) (q : NNReal), a'.source = a.source ∧ a'.target = Ioo 0 1 ∧ + 0 < q ∧ q < 1 ∧ + a'.toOpenPartialHomeomorph '' (a.source ∩ V.source) = Ioo q 1 := by + have hne := overlap_image_ne_target a.toOpenPartialHomeomorph V haV + rcases overlap_image_Ioo a.toOpenPartialHomeomorph V hat hV hVa hc with + ⟨q, hq0, hq1, himg⟩ | ⟨w, hw0, hw1, himg⟩ + · -- upper case: already oriented + have hq0' : 0 < q := by + rcases eq_or_lt_of_le hq0 with heq | hlt + · exfalso + apply hne + rw [himg, hat, ← heq] + · exact hlt + exact ⟨a, q, rfl, hat, hq0', hq1, himg⟩ + · -- lower case: flip + have hw1' : w < 1 := by + rcases eq_or_lt_of_le hw1 with heq | hlt + · exfalso + apply hne + rw [himg, hat, heq] + · exact hlt + obtain ⟨a', ha's, ha't, ha'f⟩ := a.flip hat + have himg' : a'.toOpenPartialHomeomorph '' (a.source ∩ V.source) + = (fun y => 1 - y) '' (a.toOpenPartialHomeomorph '' (a.source ∩ V.source)) := by + rw [← image_comp] + exact image_congr (fun x hx => ha'f x hx.1) + rw [himg, reflect_image_Ioo_lower hw0 hw1] at himg' + exact ⟨a', 1 - w, ha's, ha't, tsub_pos_of_lt hw1', tsub_lt_self one_pos hw0, himg'⟩ + +end Orient + +omit [ConnectedSpace M] in +/-- Two overlapping H-charts glue to a chart of `M` onto the unit interval: rescale both +to target `Iio 1`, note the overlap is connected and appears as an upper end-segment in +each chart (outer-overlap lemma), and apply the unit-interval gluing. -/ +lemma exists_glue_h_h (a : HChart M) (b : HChart M) (h : Overlap a.source b.source) : + ∃ φ : OpenPartialHomeomorph M UnitInterval, + φ.source = a.source ∪ b.source ∧ φ.target = Set.univ := by + have hane : a.source.Nonempty := h.1.mono inter_subset_left + have hbne : b.source.Nonempty := h.1.mono inter_subset_right + obtain ⟨a', ha's, ha't, -⟩ := a.rescale hane + obtain ⟨b', hb's, hb't, -⟩ := b.rescale hbne + -- the overlap is connected + have hc : IsConnected (a'.source ∩ b'.source) := by + rw [ha's, hb's, inter_comm] + exact hchart_overlap_connected b a.toOpenPartialHomeomorph + (a.connected_source hane) h.2.2 h.2.1 (inter_comm a.source b.source ▸ h.1) + -- each chart sees the overlap as an upper end-segment + have hb'conn : IsConnected b'.source := b'.connected_source (hb's ▸ hbne) + have ha'conn : IsConnected a'.source := a'.connected_source (ha's ▸ hane) + obtain ⟨p, hp1, haimg⟩ := overlap_image_Iio a'.toOpenPartialHomeomorph + b'.toOpenPartialHomeomorph ha't hb'conn + (by rw [ha's, hb's]; exact h.2.1) (by rw [ha's, hb's]; exact h.2.2) hc + obtain ⟨q, hq1, hbimg⟩ := overlap_image_Iio b'.toOpenPartialHomeomorph + a'.toOpenPartialHomeomorph hb't ha'conn + (by rw [ha's, hb's]; exact h.2.2) (by rw [ha's, hb's]; exact h.2.1) + (inter_comm a'.source b'.source ▸ hc) + rw [inter_comm] at hbimg + -- glue + obtain ⟨f, hfs, hft⟩ := glue_hh_ui a'.toOpenPartialHomeomorph b'.toOpenPartialHomeomorph + ha't hb't haimg hp1 hbimg + refine ⟨f, ?_, hft⟩ + rw [hfs, ha's, hb's] + +/-- Glue two overlapping H-charts into a single chart of `M` onto the unit interval. -/ +noncomputable def glue_h_h (a : HChart M) (b : HChart M) (h : Overlap a.source b.source) : + { φ : OpenPartialHomeomorph M UnitInterval | φ.source = a.source ∪ b.source ∧ φ.target = Set.univ } := + ⟨(exists_glue_h_h a b h).choose, (exists_glue_h_h a b h).choose_spec⟩ + +noncomputable def handle_h_h (a : HChart M) (b : HChart M) (h : Overlap a.source b.source) : + Homeomorph M UnitInterval := by + obtain ⟨φ, hφ, hs⟩ := glue_h_h a b h + have hne : φ.source.Nonempty := by + rw [hφ] + exact Set.Nonempty.inl (h.1.mono Set.inter_subset_left) + exact φ.toHomeomorphOfCompactTarget hne hs + +omit [ConnectedSpace M] in +/-- An O-chart and an H-chart with connected overlap glue to an H-chart on the union: +rescale both, orient the O-chart so the overlap sits at its lower end, and apply the +`ℝ≥0` gluing. -/ +lemma exists_glue_o_h (a : OChart M) (b : HChart M) (h : Overlap a.source b.source) + (hc : IsConnected (a.source ∩ b.source)) : + ∃ f : HChart M, f.source = a.source ∪ b.source := by + have hane : a.source.Nonempty := h.1.mono inter_subset_left + have hbne : b.source.Nonempty := h.1.mono inter_subset_right + obtain ⟨a₀, ha₀s, ha₀t, -⟩ := a.rescale hane + obtain ⟨b', hb's, hb't, -⟩ := b.rescale hbne + have hb'conn : IsConnected b'.source := b'.connected_source (hb's ▸ hbne) + -- orient the O-chart so the overlap is its lower end-segment + obtain ⟨a', r, ha's, ha't, hr0, hr1, haimg⟩ := + a₀.exists_orient_lower b'.toOpenPartialHomeomorph ha₀t hb'conn + (by rw [ha₀s, hb's]; exact h.2.1) (by rw [ha₀s, hb's]; exact h.2.2) + (by rw [ha₀s, hb's]; exact hc) + have ha's' : a'.source = a.source := ha's.trans ha₀s + have ha'conn : IsConnected a'.source := a'.connected_source (ha's' ▸ hane) + -- the H-chart sees the overlap as an upper end-segment + obtain ⟨q, hq1, hbimg⟩ := overlap_image_Iio b'.toOpenPartialHomeomorph + a'.toOpenPartialHomeomorph hb't ha'conn + (by rw [ha's', hb's]; exact h.2.2) (by rw [ha's', hb's]; exact h.2.1) + (by rw [ha's', hb's, inter_comm]; exact hc) + rw [inter_comm] at hbimg + -- adjust the O-chart image statement to the primed sources + have haimg' : a'.toOpenPartialHomeomorph '' (a'.source ∩ b'.source) = Ioo 0 r := by + rw [ha's] + exact haimg + -- glue + obtain ⟨f, hfs, μ, ρ, hqμ, hμ1, hρ0, hρ1, hft⟩ := + glue_nnreal a'.toOpenPartialHomeomorph b'.toOpenPartialHomeomorph ha't + (by rw [hb't]) haimg' hr0 hr1 hbimg (by rw [hb't]; exact hq1) + -- the glued target is `Iio (μ/ρ)` + have hμ0 : 0 < μ := lt_of_le_of_lt zero_le hqμ + have hμν : μ < μ / ρ := lt_div_self_of_lt_one hμ0 hρ0 hρ1 + have htarget : f.target = Iio (μ / ρ) := by + rw [hft, hb't] + have h1 : Iio 1 ∩ Iic μ = Iic μ := + inter_eq_right.mpr (fun y hy => lt_of_le_of_lt hy hμ1) + rw [h1, Iic_union_Ioo_eq_Iio hμν] + refine ⟨⟨f, ⟨μ / ρ, htarget.symm⟩⟩, ?_⟩ + show f.source = a.source ∪ b.source + rw [hfs, ha's', hb's] + +/-- Glue an O-chart and an H-chart with connected overlap into an H-chart on the union. -/ +noncomputable def handle_o_h' (a : OChart M) (b : HChart M) (h : Overlap a.source b.source) + (hc : IsConnected (a.source ∩ b.source)) : + { f : HChart M | f.source = a.source ∪ b.source } := + ⟨(exists_glue_o_h a b h hc).choose, (exists_glue_o_h a b h hc).choose_spec⟩ + +/-- Glue an O-chart and an H-chart: the overlap with an H-chart is automatically +connected. -/ +noncomputable def handle_o_h (a : OChart M) (b : HChart M) (h : Overlap a.source b.source) : + { f : HChart M | f.source = a.source ∪ b.source } := by + have hane : a.source.Nonempty := h.1.mono inter_subset_left + have hc : IsConnected (a.source ∩ b.source) := by + rw [inter_comm] + exact hchart_overlap_connected b a.toOpenPartialHomeomorph + (a.connected_source hane) h.2.2 h.2.1 (inter_comm a.source b.source ▸ h.1) + exact handle_o_h' a b h hc + +omit [ConnectedSpace M] in +/-- Two O-charts with connected overlap glue to an O-chart on the union: rescale both, +orient the first chart's overlap low and the second's high, and apply the `ℝ≥0` +gluing. -/ +lemma exists_glue_o_o (a : OChart M) (b : OChart M) (h : Overlap a.source b.source) + (hc : IsConnected (a.source ∩ b.source)) : + ∃ f : OChart M, f.source = a.source ∪ b.source := by + have hane : a.source.Nonempty := h.1.mono inter_subset_left + have hbne : b.source.Nonempty := h.1.mono inter_subset_right + obtain ⟨a₀, ha₀s, ha₀t, -⟩ := a.rescale hane + obtain ⟨b₀, hb₀s, hb₀t, -⟩ := b.rescale hbne + have hb₀conn : IsConnected b₀.source := b₀.connected_source (hb₀s ▸ hbne) + -- orient the first chart's overlap low + obtain ⟨a', r, ha's, ha't, hr0, hr1, haimg⟩ := + a₀.exists_orient_lower b₀.toOpenPartialHomeomorph ha₀t hb₀conn + (by rw [ha₀s, hb₀s]; exact h.2.1) (by rw [ha₀s, hb₀s]; exact h.2.2) + (by rw [ha₀s, hb₀s]; exact hc) + have ha's' : a'.source = a.source := ha's.trans ha₀s + have ha'conn : IsConnected a'.source := a'.connected_source (ha's' ▸ hane) + -- orient the second chart's overlap high + obtain ⟨b', q, hb's, hb't, hq0, hq1, hbimg⟩ := + b₀.exists_orient_upper a'.toOpenPartialHomeomorph hb₀t ha'conn + (by rw [ha's', hb₀s]; exact h.2.2) (by rw [ha's', hb₀s]; exact h.2.1) + (by rw [ha's', hb₀s, inter_comm]; exact hc) + have hb's' : b'.source = b.source := hb's.trans hb₀s + -- adjust both image statements to the primed sources + have haimg' : a'.toOpenPartialHomeomorph '' (a'.source ∩ b'.source) = Ioo 0 r := by + rw [ha's, hb's] + exact haimg + have hbimg' : b'.toOpenPartialHomeomorph '' (a'.source ∩ b'.source) = Ioo q 1 := by + rw [hb's, inter_comm] + exact hbimg + -- glue + obtain ⟨f, hfs, μ, ρ, hqμ, hμ1, hρ0, hρ1, hft⟩ := + glue_nnreal a'.toOpenPartialHomeomorph b'.toOpenPartialHomeomorph ha't + (by rw [hb't]; exact Ioo_subset_Iio_self) haimg' hr0 hr1 hbimg' + (by rw [hb't]; exact ⟨hq0, hq1⟩) + -- the glued target is `Ioo 0 (μ/ρ)` + have hμ0 : 0 < μ := lt_of_le_of_lt zero_le hqμ + have hμν : μ < μ / ρ := lt_div_self_of_lt_one hμ0 hρ0 hρ1 + have htarget : f.target = Ioo 0 (μ / ρ) := by + rw [hft, hb't] + have h1 : Ioo 0 1 ∩ Iic μ = Ioc 0 μ := by + ext y + simp only [mem_inter_iff, mem_Ioo, mem_Iic, mem_Ioc] + constructor + · rintro ⟨⟨hy0, -⟩, hy⟩ + exact ⟨hy0, hy⟩ + · rintro ⟨hy0, hy⟩ + exact ⟨⟨hy0, lt_of_le_of_lt hy hμ1⟩, hy⟩ + rw [h1, Ioc_union_Ioo_eq_Ioo hμν] + refine ⟨⟨f, ⟨0, μ / ρ, htarget.symm⟩⟩, ?_⟩ + show f.source = a.source ∪ b.source + rw [hfs, ha's', hb's'] + +/-- A disconnected overlap of two O-charts closes `M` up into a circle: the glued chart +of `exists_circle_chart` maps `a.source ∪ b.source` onto the whole of `AddCircle 1`; +transfer to `Circle` and apply the compact-target argument. -/ +noncomputable def circle_of_disconnected_overlap (a : OChart M) (b : OChart M) + (h : Overlap a.source b.source) (hc : ¬ IsConnected (a.source ∩ b.source)) : + Homeomorph M Circle := by + have H := exists_circle_chart a b h hc + obtain ⟨hfs, hft⟩ := H.choose_spec + let f' := H.choose.transHomeomorph (AddCircle.homeomorphCircle (one_ne_zero (α := ℝ))) + have hfs' : f'.source = a.source ∪ b.source := hfs + have hft' : f'.target = Set.univ := by + show (AddCircle.homeomorphCircle _).symm ⁻¹' H.choose.target = Set.univ + rw [hft] + exact Set.preimage_univ + have hne : f'.source.Nonempty := by + rw [hfs'] + exact Set.Nonempty.inl (h.1.mono Set.inter_subset_left) + exact f'.toHomeomorphOfCompactTarget hne hft' + +/-- Glue two O-charts: with a connected overlap they merge into an O-chart on the union; +with a disconnected overlap, `M` is a circle. -/ +noncomputable def handle_o_o (a : OChart M) (b : OChart M) (h : Overlap a.source b.source) : + (Homeomorph M Circle) ⊕ { f : OChart M | f.source = a.source ∪ b.source } := by + by_cases hc : IsConnected (a.source ∩ b.source) + · exact Sum.inr ⟨(exists_glue_o_o a b h hc).choose, (exists_glue_o_o a b h hc).choose_spec⟩ + · exact Sum.inl (circle_of_disconnected_overlap a b h hc) diff --git a/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean b/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean new file mode 100644 index 0000000000..136e84494e --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean @@ -0,0 +1,79 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib + +open Set TopologicalSpace + +universe u +variable {α : Type u} +variable {X : Type u} [TopologicalSpace X] +variable {U V : Set X} + +lemma nonempty_closure_inter_diff + (hVconn : IsConnected V) (hUopen : IsOpen U) (hVopen : IsOpen V) + (hUV : (U ∩ V).Nonempty) (hVU : (V \ U).Nonempty) : + ((closure U) ∩ (V \ U)).Nonempty := by + + -- prove by contradiction that `closure U ∩ (V \ U)` can't be empty. + by_contra h + push Not at h + + let A := U ∩ V + let B := V \ U + + have hVconn' : IsPreconnected (V : Set X) := IsConnected.isPreconnected hVconn + + have openA : IsOpen (A : Set X) := IsOpen.inter hUopen hVopen + have openB : IsOpen (B : Set X) := by + have : (V \ U) = (V \ (closure U)) := by + ext x + simp only [mem_sdiff, and_congr_right_iff] + intro hv + constructor + · intro hu + have : x ∈ V \ U := mem_sdiff_of_mem hv hu + by_contra hcu + have : x ∈ closure U ∩ (V \ U) := by exact mem_inter hcu this + rw [h] at this + exact this + · intro hcu + exact notMem_of_notMem_closure hcu + dsimp [B] -- this is needed? + rw [this] + exact IsOpen.sdiff hVopen isClosed_closure + + have coverAB : V ⊆ A ∪ B := by + rintro x hx + simp only [mem_union] + by_cases hxU : x ∈ U + · left + exact mem_inter hxU hx + · right + exact mem_sdiff_of_mem hx hxU + + have nonemptyVA : (V ∩ A).Nonempty := by + have : (V ∩ (U ∩ V)) = U ∩ V := by + simp only [inter_eq_right, inter_subset_right] + rw [this] + exact hUV + + have nonemptyVB : (V ∩ B).Nonempty := by + have : (V ∩ (V \ U)) = (V \ U) := by + simp only [inter_eq_right] + exact sdiff_subset + rw [this] + exact hVU + + have disjointAB : A ∩ B = ∅ := by + ext x + simp only [mem_inter_iff, mem_empty_iff_false, iff_false, not_and] + intro hx + apply notMem_sdiff_of_mem + exact mem_of_mem_inter_left hx + + have nonemptyVAB : (V ∩ (A ∩ B)).Nonempty := hVconn' A B openA openB coverAB nonemptyVA nonemptyVB + rw [disjointAB] at nonemptyVAB + simp only [inter_empty, Set.not_nonempty_empty] at nonemptyVAB diff --git a/LeanPool/OneManifold/OneMfld/Compactness.lean b/LeanPool/OneManifold/OneMfld/Compactness.lean new file mode 100644 index 0000000000..10703423b0 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/Compactness.lean @@ -0,0 +1,101 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts +import LeanPool.OneManifold.OneMfld.Noncompact + +variable + {M : Type*} + [TopologicalSpace M] + +lemma clopen_in_r (s : Set NNReal) : (s ≠ ∅ ∧ s ≠ Set.univ) → ¬ IsClopen s := by + intro h12 + by_contra h' + have h1 := isClopen_iff.mp h' + tauto + +lemma noncompact_nnreal : NoncompactSpace NNReal := by + have := not_compactSpace_NNReal + exact not_compactSpace_iff.mp this + +lemma noncompact_ioo' (x y : NNReal) (hxy : x < y) : NoncompactSpace (Set.Ioo x y) := by + let s := Set.Ioo x y + have h : ¬ CompactSpace s := by + by_contra h' + have hc : IsCompact s := by exact isCompact_iff_compactSpace.mpr h' + have hs : IsClosed s := by exact IsCompact.isClosed hc + have ho : IsOpen s := by exact isOpen_Ioo + have hn : Nonempty s := by exact Set.nonempty_Ioo_subtype hxy + have hc' := clopen_in_r s + apply hc' + constructor + · exact Set.nonempty_iff_ne_empty'.mp hn + · by_contra ha + rw [ha] at h' + have : ¬ IsCompact (Set.univ : Set NNReal) := by + have ht : ¬ CompactSpace (NNReal) := by + exact not_compactSpace_iff.mpr noncompact_nnreal + by_contra ht' + apply ht + exact { isCompact_univ := ht' } + apply this + exact isCompact_iff_compactSpace.mpr h' + exact ⟨ hs, ho ⟩ + exact not_compactSpace_iff.mp h + +lemma noncompact_ioo (x y : NNReal) (hxy : x < y) : ¬ CompactSpace (Set.Ioo x y) := by + have h := noncompact_ioo' x y hxy + exact not_compactSpace_iff.mpr h + +lemma noncompact_iio' (x : NNReal) (hx : 0 < x) : NoncompactSpace (Set.Iio x) := by + let s := Set.Iio x + have h : ¬ CompactSpace s := by + by_contra h' + have hc : IsCompact s := by exact isCompact_iff_compactSpace.mpr h' + have hs : IsClosed s := by exact IsCompact.isClosed hc + have ho : IsOpen s := by exact isOpen_Iio + have hn : Nonempty s := by + apply nonempty_subtype.mpr + exact Exists.intro 0 hx + have hc' := clopen_in_r s + apply hc' + constructor + · exact Set.nonempty_iff_ne_empty'.mp hn + · by_contra ha + rw [ha] at h' + have : ¬ IsCompact (Set.univ : Set NNReal) := by + have ht : ¬ CompactSpace (NNReal) := by + exact not_compactSpace_iff.mpr noncompact_nnreal + by_contra ht' + apply ht + exact { isCompact_univ := ht' } + apply this + exact isCompact_iff_compactSpace.mpr h' + exact ⟨ hs, ho ⟩ + exact not_compactSpace_iff.mp h + +lemma noncompact_iio (x : NNReal) (hx : 0 < x) : ¬ CompactSpace (Set.Iio x) := by + have h:= noncompact_iio' x hx + exact not_compactSpace_iff.mpr h + +lemma noncompact_target (ht : FinitelyIntervalChartedSpace M) (z : M) (a : OpenPartialHomeomorph M NNReal) (ha : a ∈ ht.atlas) (hz : z ∈ a.source) : ¬ CompactSpace (a.target) := by + have := ht.is_interval a ha + rcases this with (h|h) + · rcases h with ⟨ x, y, h ⟩ + rw [←h] + have hz' : a.toFun z ∈ a.target := by exact PartialEquiv.map_source a.toPartialEquiv hz + rw [←h] at hz' + simp only [Set.mem_Ioo] at hz' + rcases hz' with ⟨ hxz, hzy ⟩ + have hxy : x < y := gt_trans hzy hxz + apply noncompact_ioo x y hxy + · rcases h with ⟨ x, h ⟩ + rw [←h] + have hz' : a.toFun z ∈ a.target := by exact PartialEquiv.map_source a.toPartialEquiv hz + rw [←h] at hz' + simp only [Set.mem_Iio] at hz' + have hx : 0 < x := by exact pos_of_gt hz' + apply noncompact_iio x hx diff --git a/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean b/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean new file mode 100644 index 0000000000..fbe8f00e51 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean @@ -0,0 +1,29 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.IntervalCharts +import LeanPool.OneManifold.OneMfld.FinitelyCharted + +class FinitelyIntervalChartedSpace (M : Type*) [TopologicalSpace M] extends IntervalChartedSpace M where + is_finite : Set.Finite atlas + +variable + {M : Type*} + [TopologicalSpace M] + [CompactSpace M] + +@[instance_reducible] noncomputable def finitely_interval_charted (ht : IntervalChartedSpace M) : FinitelyIntervalChartedSpace M := by + have c : { ht' : ChartedSpace NNReal M | Set.Finite ht'.atlas ∧ ht'.atlas ⊆ ht.atlas } := choose_charts + rcases c with ⟨ ht', c1, c2 ⟩ + + exact { ht' with + is_finite := c1 + , is_interval := by + intro x hx + apply ht.is_interval + apply c2 + exact hx + } diff --git a/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean b/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean new file mode 100644 index 0000000000..54bc6e43a3 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean @@ -0,0 +1,61 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib + +variable {H : Type*} [TopologicalSpace H] {M : Type*} [TopologicalSpace M] + +variable + {M : Type*} + [TopologicalSpace M] + +noncomputable def choose_charts [CompactSpace M] [ht : ChartedSpace H M] : { ht' : ChartedSpace H M | Set.Finite ht'.atlas ∧ ht'.atlas ⊆ ht.atlas } := by + let U : M → Set M := by + intro x + exact (ht.chartAt x).source + let hUo : (i : M) → IsOpen (U i) := by + intro x + exact (ChartedSpace.chartAt x).open_source + let hsU : (Set.univ : Set M) ⊆ ⋃ (i : M), U i := by + intro x hx + simp only [Set.mem_iUnion] + use x + exact ChartedSpace.mem_chart_source x + + have hc := IsCompact.elim_finite_subcover CompactSpace.isCompact_univ U hUo hsU + + let t := Classical.choose hc + have t' := Classical.choose_spec hc + + let f (x : M) : { x' : M | x' ∈ t ∧ x ∈ (ht.chartAt x').source } := by + have : x ∈ ⋃ i ∈ t, U i := by exact t' trivial + simp only [Set.mem_iUnion, exists_prop] at this + have hx := Classical.choose_spec this + use Classical.choose this + simp only [Set.mem_ofPred_eq] + apply And.intro + · exact hx.1 + · dsimp [U] at hx + exact hx.2 + + use { chartAt := by + intro x + exact ht.chartAt (f x).1 + , atlas := Set.image ht.chartAt t + , chart_mem_atlas := by + intro x + apply Set.mem_image_of_mem ChartedSpace.chartAt + refine Finset.mem_coe.mpr ?_ + exact (f x).2.1 + , mem_chart_source := by + intro x + exact (f x).2.2 + } + + simp only [Set.mem_ofPred_eq, Set.image_subset_iff] + apply And.intro + · exact Set.toFinite (ht.chartAt '' ↑t) + · intro x hx + simp only [Set.mem_preimage, chart_mem_atlas] diff --git a/LeanPool/OneManifold/OneMfld/GlueBlocks.lean b/LeanPool/OneManifold/OneMfld/GlueBlocks.lean new file mode 100644 index 0000000000..ca036c2c1f --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/GlueBlocks.lean @@ -0,0 +1,210 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.UnitInterval + +/-! # Building blocks for the H-H gluing + +Two overlapping boundary charts glue to a *closed* interval, so the glued chart cannot be +`NNReal`-valued (its target would not be open); it must land in the subtype +`UnitInterval`. The pieces: + +* `halfOPH` — `x ↦ x/2` embedding `Iio 1 ⊆ ℝ≥0` onto the lower half `[0, 1/2)` of the + unit interval (open in the subtype since `0` is an endpoint); +* `mobiusOPH k` — the decreasing Möbius map `x ↦ k/(x+k)` embedding all of `ℝ≥0` onto + the upper piece `(0, 1]` (open in the subtype since `1` is an endpoint) — a decreasing + reparametrization with no truncated-subtraction issues; +* the frontier of `{y ≤ c}` in the unit interval; +* reflection images of end-segments in `ℝ≥0`, used to re-orient `OChart`s. +-/ + +open Set Topology + +noncomputable section + +/-- `x ↦ x/2` as a partial homeomorphism from `ℝ≥0` (source `Iio 1`) to the unit +interval (target the sub-half-interval `[0, 1/2)`, open in the subtype). -/ +def halfOPH : + { e : OpenPartialHomeomorph NNReal UnitInterval // + e.source = Iio 1 ∧ e.target = {y : UnitInterval | (y : ℝ) < 1/2} ∧ + ∀ x : NNReal, x ∈ Iio (1 : NNReal) → ((e x : ℝ) = x / 2) } := by + have hmem : ∀ x : NNReal, min ((x : ℝ) / 2) 1 ∈ UnitInterval := fun x => + ⟨le_min (by positivity) zero_le_one, min_le_right _ _⟩ + refine ⟨{ toFun := fun x => ⟨min ((x : ℝ) / 2) 1, hmem x⟩ + invFun := fun y => Real.toNNReal (2 * (y : ℝ)) + source := Iio 1 + target := {y : UnitInterval | (y : ℝ) < 1/2} + map_source' := ?_ + map_target' := ?_ + left_inv' := ?_ + right_inv' := ?_ + open_source := isOpen_Iio + open_target := ?_ + continuousOn_toFun := + (((NNReal.continuous_coe.div_const 2).min continuous_const).subtype_mk + hmem).continuousOn + continuousOn_invFun := + (continuous_real_toNNReal.comp + (continuous_const.mul continuous_subtype_val)).continuousOn }, + rfl, rfl, fun x hx => ?_⟩ + · -- map_source' + intro x hx + have hx1 : x < (1 : NNReal) := hx + have hx' : (x : ℝ) < 1 := by exact_mod_cast hx1 + show min ((x : ℝ) / 2) 1 < 1/2 + rw [min_eq_left (by linarith : (x : ℝ) / 2 ≤ 1)] + linarith + · -- map_target' + intro y hy + have hy' : (y : ℝ) < 1/2 := hy + have h2 : (0:ℝ) ≤ 2 * (y : ℝ) := mul_nonneg (by norm_num) y.2.1 + show Real.toNNReal (2 * (y : ℝ)) < 1 + rw [Real.toNNReal_lt_iff_lt_coe h2, NNReal.coe_one] + linarith + · -- left_inv' + intro x hx + have hx1 : x < (1 : NNReal) := hx + have hx' : (x : ℝ) < 1 := by exact_mod_cast hx1 + show Real.toNNReal (2 * min ((x : ℝ) / 2) 1) = x + rw [min_eq_left (by linarith : (x : ℝ) / 2 ≤ 1), + show 2 * ((x : ℝ) / 2) = (x : ℝ) from by ring] + exact Real.toNNReal_coe + · -- right_inv' + intro y hy + have hy' : (y : ℝ) < 1/2 := hy + have h2 : (0:ℝ) ≤ 2 * (y : ℝ) := mul_nonneg (by norm_num) y.2.1 + apply Subtype.ext + show min ((Real.toNNReal (2 * (y : ℝ)) : ℝ) / 2) 1 = (y : ℝ) + rw [Real.coe_toNNReal _ h2, + show 2 * (y : ℝ) / 2 = (y : ℝ) from by ring] + exact min_eq_left y.2.2 + · -- open_target + exact isOpen_Iio.preimage continuous_subtype_val + · -- e x = x / 2 on the source + have hx1 : x < (1 : NNReal) := hx + have hx' : (x : ℝ) < 1 := by exact_mod_cast hx1 + exact min_eq_left (by linarith : (x : ℝ) / 2 ≤ 1) + +/-- The Möbius map `x ↦ k/(x+k)` (for `k > 0`) as a partial homeomorphism from `ℝ≥0` +(source everything) to the unit interval (target `(0, 1]`, open in the subtype). It is +strictly decreasing, sends `0 ↦ 1`, and tends to `0` at infinity. -/ +def mobiusOPH (k : NNReal) (hk : 0 < k) : + { e : OpenPartialHomeomorph NNReal UnitInterval // + e.source = univ ∧ e.target = {y : UnitInterval | 0 < (y : ℝ)} ∧ + (∀ x : NNReal, (e x : ℝ) = k / (x + k)) ∧ + (∀ x₁ x₂ : NNReal, x₁ < x₂ → (e x₂ : ℝ) < (e x₁ : ℝ)) } := by + have hk' : (0:ℝ) < (k : ℝ) := by exact_mod_cast hk + have hden : ∀ x : NNReal, (0:ℝ) < (x : ℝ) + (k : ℝ) := fun x => + add_pos_of_nonneg_of_pos x.coe_nonneg hk' + have hmem : ∀ x : NNReal, (k : ℝ) / ((x : ℝ) + (k : ℝ)) ∈ UnitInterval := fun x => + ⟨le_of_lt (div_pos hk' (hden x)), + (div_le_one (hden x)).mpr (le_add_of_nonneg_left x.coe_nonneg)⟩ + have key : ∀ a : ℝ, (k : ℝ) / ((k : ℝ) / a) = a := fun a => by + rw [div_div_eq_mul_div, mul_comm, mul_div_assoc, div_self hk'.ne', mul_one] + refine ⟨{ toFun := fun x => ⟨(k : ℝ) / ((x : ℝ) + (k : ℝ)), hmem x⟩ + invFun := fun y => Real.toNNReal ((k : ℝ) / (y : ℝ) - (k : ℝ)) + source := univ + target := {y : UnitInterval | 0 < (y : ℝ)} + map_source' := fun x _ => div_pos hk' (hden x) + map_target' := fun y _ => mem_univ _ + left_inv' := ?_ + right_inv' := ?_ + open_source := isOpen_univ + open_target := isOpen_Ioi.preimage continuous_subtype_val + continuousOn_toFun := ((Continuous.div continuous_const + (NNReal.continuous_coe.add continuous_const) + (fun x => (hden x).ne')).subtype_mk hmem).continuousOn + continuousOn_invFun := continuous_real_toNNReal.comp_continuousOn + ((continuousOn_const.div continuous_subtype_val.continuousOn + (fun y hy => ne_of_gt (hy : (0:ℝ) < (y : ℝ)))).sub continuousOn_const) }, + rfl, rfl, fun x => rfl, ?_⟩ + · -- left_inv' + intro x _ + show Real.toNNReal ((k : ℝ) / ((k : ℝ) / ((x : ℝ) + (k : ℝ))) - (k : ℝ)) = x + rw [key, show (x : ℝ) + (k : ℝ) - (k : ℝ) = (x : ℝ) from by ring] + exact Real.toNNReal_coe + · -- right_inv' + intro y hy + have hy' : (0:ℝ) < (y : ℝ) := hy + have hy1 : (y : ℝ) ≤ 1 := y.2.2 + have hknn : (k : ℝ) ≤ (k : ℝ) / (y : ℝ) := by + rw [le_div_iff₀ hy'] + exact mul_le_of_le_one_right hk'.le hy1 + apply Subtype.ext + show (k : ℝ) / ((Real.toNNReal ((k : ℝ) / (y : ℝ) - (k : ℝ)) : ℝ) + (k : ℝ)) = (y : ℝ) + rw [Real.coe_toNNReal _ (sub_nonneg.mpr hknn), + show (k : ℝ) / (y : ℝ) - (k : ℝ) + (k : ℝ) = (k : ℝ) / (y : ℝ) from by ring, + key] + · -- strictly decreasing + intro x₁ x₂ h + have h' : (x₁ : ℝ) < (x₂ : ℝ) := by exact_mod_cast h + exact div_lt_div_of_pos_left hk' (hden x₁) + (by linarith : (x₁ : ℝ) + (k : ℝ) < (x₂ : ℝ) + (k : ℝ)) + +/-- The frontier of the closed lower piece `{y ≤ c}` of the unit interval is the single +level `{y = c}`, provided `0 < c < 1`. -/ +lemma frontier_UIIic {c : ℝ} (h0 : 0 < c) (h1 : c < 1) : + frontier {y : UnitInterval | (y : ℝ) ≤ c} = {y : UnitInterval | (y : ℝ) = c} := by + have hclosed : IsClosed {y : UnitInterval | (y : ℝ) ≤ c} := + isClosed_Iic.preimage continuous_subtype_val + have hint : interior {y : UnitInterval | (y : ℝ) ≤ c} + = {y : UnitInterval | (y : ℝ) < c} := by + refine Subset.antisymm ?_ (interior_maximal (fun y (hy : (y : ℝ) < c) => hy.le) + (isOpen_Iio.preimage continuous_subtype_val)) + intro y hy + show (y : ℝ) < c + by_contra hlt + have hymem : y ∈ {y : UnitInterval | (y : ℝ) ≤ c} := interior_subset hy + have hyc : (y : ℝ) = c := le_antisymm hymem (not_lt.mp hlt) + have hS : {y : UnitInterval | (y : ℝ) ≤ c} ∈ 𝓝 y := mem_interior_iff_mem_nhds.mp hy + rw [nhds_subtype] at hS + obtain ⟨V, hV, hVsub⟩ := Filter.mem_comap.mp hS + obtain ⟨ε, hε, hball⟩ := Metric.mem_nhds_iff.mp hV + set δ := min (ε/2) ((1 - c)/2) with hδdef + have hδ0 : 0 < δ := lt_min (by linarith) (by linarith) + have hδε : δ < ε := lt_of_le_of_lt (min_le_left _ _) (by linarith) + have hδ1 : c + δ ≤ 1 := by + have h := min_le_right (ε/2) ((1 - c)/2) + have : δ ≤ (1 - c)/2 := h + linarith + have hmem : c + δ ∈ UnitInterval := ⟨by linarith, hδ1⟩ + have hballmem : c + δ ∈ Metric.ball (y : ℝ) ε := by + rw [Metric.mem_ball, hyc, Real.dist_eq, + show c + δ - c = δ from by ring, abs_of_pos hδ0] + exact hδε + have hin : (⟨c + δ, hmem⟩ : UnitInterval) ∈ Subtype.val ⁻¹' V := hball hballmem + have hle : c + δ ≤ c := hVsub hin + linarith + rw [hclosed.frontier_eq, hint] + ext y + simp only [mem_sdiff, mem_ofPred_eq, not_lt] + exact ⟨fun h => le_antisymm h.1 h.2, fun h => ⟨h.le, h.ge⟩⟩ + +/-- Reflection `y ↦ 1 - y` sends the upper end-segment `Ioo p 1 ⊆ ℝ≥0` to the lower +end-segment `Ioo 0 (1-p)`. -/ +lemma reflect_image_Ioo_upper {p : NNReal} (_hp : p < 1) : + (fun y : NNReal => 1 - y) '' Ioo p 1 = Ioo 0 (1 - p) := by + ext z + constructor + · rintro ⟨y, ⟨hyp, hy1⟩, rfl⟩ + exact ⟨tsub_pos_of_lt hy1, tsub_lt_tsub_left_of_le hy1.le hyp⟩ + · rintro ⟨hz0, hzp⟩ + have hz1 : z ≤ 1 := (hzp.trans_le tsub_le_self).le + exact ⟨1 - z, ⟨lt_tsub_comm.mp hzp, tsub_lt_self one_pos hz0⟩, + tsub_tsub_cancel_of_le hz1⟩ + +/-- Reflection `y ↦ 1 - y` sends the lower end-segment `Ioo 0 q ⊆ ℝ≥0` (for `q ≤ 1`) to +the upper end-segment `Ioo (1-q) 1`. -/ +lemma reflect_image_Ioo_lower {q : NNReal} (_hq0 : 0 < q) (hq1 : q ≤ 1) : + (fun y : NNReal => 1 - y) '' Ioo 0 q = Ioo (1 - q) 1 := by + ext z + constructor + · rintro ⟨y, ⟨hy0, hyq⟩, rfl⟩ + exact ⟨tsub_lt_tsub_left_of_le hq1 hyq, tsub_lt_self one_pos hy0⟩ + · rintro ⟨hzq, hz1⟩ + refine ⟨1 - z, ⟨tsub_pos_of_lt hz1, ?_⟩, tsub_tsub_cancel_of_le hz1.le⟩ + rw [tsub_lt_iff_right hz1.le] + exact (tsub_lt_iff_left hq1).mp hzq diff --git a/LeanPool/OneManifold/OneMfld/GlueCore.lean b/LeanPool/OneManifold/OneMfld/GlueCore.lean new file mode 100644 index 0000000000..47d0a04226 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/GlueCore.lean @@ -0,0 +1,267 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.Outer +import LeanPool.OneManifold.OneMfld.TransitionMono + +/-! # Core lemmas for gluing overlapping charts + +Two results feed the gluing construction: + +* **Connectivity**: if `U` is a boundary chart (target `Iio v`), its overlap with any + other chart is connected — every component's `U`-image is an upper end-segment + `Ioo q v` (outer-overlap lemma), and two upper end-segments always intersect. + +* **End-matching**: the transition map on the overlap is strictly monotone in the + direction forced by which ends of the two chart images are *interior* (the endpoint + belongs to the chart target). If both interior ends were paired with each other, the + overlap would accumulate at two distinct points of `M` at once, contradicting `T2`. +-/ + +open Set Filter Topology + +/-- A strictly antitone map of `Ioo p v` onto `Ioo q w` tends to `q` at the top end. -/ +theorem tendsto_top_of_strictAntiOn_image {p v q w : NNReal} (hpv : p < v) + {f : NNReal → NNReal} (hm : StrictAntiOn f (Ioo p v)) + (himg : f '' Ioo p v = Ioo q w) : + Tendsto f (𝓝[<] v) (𝓝 q) := by + have hne : (Ioo p v).Nonempty := nonempty_Ioo.2 hpv + have hqw : q < w := nonempty_Ioo.1 (himg ▸ hne.image f) + have hbdd : BddBelow (f '' Ioo p v) := himg ▸ bddBelow_Ioo + have h := AntitoneOn.tendsto_nhdsWithin_Ioo_left hne hm.antitoneOn hbdd + rwa [himg, csInf_Ioo hqw] at h + +variable {M : Type*} [TopologicalSpace M] + +/-- The overlap of a boundary chart `U` (target `Iio v`) with any other chart is +connected: every component's `U`-image is an upper end-segment of `Iio v`, and two upper +end-segments intersect, so there is only one component. -/ +theorem overlap_connected [T2Space M] + (U V : OpenPartialHomeomorph M NNReal) {v : NNReal} + (hUt : U.target = Iio v) + (hV : IsConnected V.source) + (hUV : (U.source \ V.source).Nonempty) + (hVU : (V.source \ U.source).Nonempty) + (hne : (U.source ∩ V.source).Nonempty) : + IsConnected (U.source ∩ V.source) := by + set S := U.source ∩ V.source with hSdef + obtain ⟨x, hx⟩ := hne + have hSU : S ⊆ U.source := inter_subset_left + have hkey : S = connectedComponentIn S x := by + apply subset_antisymm _ (connectedComponentIn_subset S x) + intro y hy + obtain ⟨qx, hqx, hix⟩ := overlap_component_outer_Iio U V hUt hV hUV hVU hx + obtain ⟨qy, hqy, hiy⟩ := overlap_component_outer_Iio U V hUt hV hUV hVU hy + obtain ⟨z, hz1, hz2⟩ := exists_between (max_lt hqx hqy) + have hzx : z ∈ U '' connectedComponentIn S x := + hix ▸ mem_Ioo.mpr ⟨lt_of_le_of_lt (le_max_left _ _) hz1, hz2⟩ + have hzy : z ∈ U '' connectedComponentIn S y := + hiy ▸ mem_Ioo.mpr ⟨lt_of_le_of_lt (le_max_right _ _) hz1, hz2⟩ + obtain ⟨w1, hw1, hw1z⟩ := hzx + obtain ⟨w2, hw2, hw2z⟩ := hzy + have hw12 : w1 = w2 := + U.injOn (hSU (connectedComponentIn_subset _ _ hw1)) + (hSU (connectedComponentIn_subset _ _ hw2)) (hw1z.trans hw2z.symm) + have h1 : connectedComponentIn S x = connectedComponentIn S w1 := + connectedComponentIn_eq hw1 + have h2 : connectedComponentIn S y = connectedComponentIn S w2 := + connectedComponentIn_eq hw2 + rw [h1, hw12, ← h2] + exact mem_connectedComponentIn hy + rw [hkey] + exact isConnected_connectedComponentIn_iff.mpr hx + +/-- **End-matching, increasing case.** Suppose the overlap `S = a.source ∩ b.source` has +image `Ioo p r` in chart `a` and `Ioo q w` in chart `b`, where the `r`-end is interior to +`a.target` and the `q`-end is interior to `b.target`. Then the transition is increasing: +`a x < a y → b x < b y` on `S`. (If it were decreasing, the overlap would accumulate at +both `a.symm r` and `b.symm q` along the same filter, forcing them equal — but then that +point would lie in `S`, putting `r` in `Ioo p r`.) -/ +theorem overlap_mono [T2Space M] (a b : OpenPartialHomeomorph M NNReal) + {p r q w : NNReal} + (ha : a '' (a.source ∩ b.source) = Ioo p r) + (hb : b '' (a.source ∩ b.source) = Ioo q w) + (hr : r ∈ a.target) (hq : q ∈ b.target) : + ∀ x ∈ a.source ∩ b.source, ∀ y ∈ a.source ∩ b.source, + a x < a y → b x < b y := by + set S := a.source ∩ b.source with hSdef + have hSa : S ⊆ a.source := inter_subset_left + have hSb : S ⊆ b.source := inter_subset_right + have hacoord : ∀ x ∈ S, a x ∈ Ioo p r := fun x hx => ha ▸ mem_image_of_mem a hx + by_cases hpr : p < r + swap + · intro x hx y hy hxy + exact absurd ((hacoord x hx).1.trans (hacoord x hx).2) hpr + set τ : NNReal → NNReal := fun t => b (a.symm t) with hτdef + have hsymm : ∀ t ∈ Ioo p r, a.symm t ∈ S ∧ a (a.symm t) = t := by + intro t ht + rw [← ha] at ht + obtain ⟨x, hxS, rfl⟩ := ht + rw [a.left_inv (hSa hxS)] + exact ⟨hxS, rfl⟩ + have hkey : ∀ x ∈ S, τ (a x) = b x := by + intro x hx + simp only [hτdef] + rw [a.left_inv (hSa hx)] + have hτmaps : ∀ t ∈ Ioo p r, τ t ∈ Ioo q w := by + intro t ht + have hb' : b (a.symm t) ∈ b '' S := mem_image_of_mem b (hsymm t ht).1 + exact hb ▸ hb' + have hIoo_target : Ioo p r ⊆ a.target := by + rw [← ha] + rintro y ⟨z, hz, rfl⟩ + exact a.map_source (hSa hz) + have hqw_target : Ioo q w ⊆ b.target := by + rw [← hb] + rintro y ⟨z, hz, rfl⟩ + exact b.map_source (hSb hz) + have hcont : ContinuousOn τ (Ioo p r) := + b.continuousOn.comp (a.symm.continuousOn.mono hIoo_target) + (fun t ht => hSb (hsymm t ht).1) + have hinj : InjOn τ (Ioo p r) := by + intro t1 ht1 t2 ht2 heq + obtain ⟨h1S, h1e⟩ := hsymm t1 ht1 + obtain ⟨h2S, h2e⟩ := hsymm t2 ht2 + have h12 : a.symm t1 = a.symm t2 := b.injOn (hSb h1S) (hSb h2S) heq + rw [← h1e, ← h2e, h12] + rcases strictMonoOn_or_strictAntiOn_of_injOn_Ioo hcont hinj with hmono | hanti + · intro x hx y hy hxy + have h := hmono (hacoord x hx) (hacoord y hy) hxy + rwa [hkey x hx, hkey y hy] at h + · exfalso + have himg : τ '' Ioo p r = Ioo q w := by + apply subset_antisymm + · rintro _ ⟨t, ht, rfl⟩ + exact hτmaps t ht + · intro y hy + rw [← hb] at hy + obtain ⟨x, hxS, rfl⟩ := hy + exact ⟨a x, hacoord x hxS, hkey x hxS⟩ + have hτlim : Tendsto τ (𝓝[<] r) (𝓝 q) := + tendsto_top_of_strictAntiOn_image hpr hanti himg + have hF : 𝓝[Ioo p r] r = 𝓝[<] r := nhdsWithin_Ioo_eq_nhdsLT hpr + have hFne : (𝓝[Ioo p r] r).NeBot := by + apply mem_closure_iff_nhdsWithin_neBot.mp + rw [closure_Ioo hpr.ne] + exact ⟨hpr.le, le_refl r⟩ + have hlim1 : Tendsto a.symm (𝓝[Ioo p r] r) (𝓝 (a.symm r)) := + (a.symm.continuousOn r hr).mono hIoo_target + have hτq : Tendsto τ (𝓝[Ioo p r] r) (𝓝 q) := hF ▸ hτlim + have hτq' : Tendsto τ (𝓝[Ioo p r] r) (𝓝[b.target] q) := by + rw [tendsto_nhdsWithin_iff] + refine ⟨hτq, ?_⟩ + filter_upwards [self_mem_nhdsWithin] with t ht + exact hqw_target (hτmaps t ht) + have hlim2 : Tendsto (b.symm ∘ τ) (𝓝[Ioo p r] r) (𝓝 (b.symm q)) := + Tendsto.comp (b.symm.continuousOn q hq) hτq' + have hlim2' : Tendsto a.symm (𝓝[Ioo p r] r) (𝓝 (b.symm q)) := by + apply Tendsto.congr' _ hlim2 + filter_upwards [self_mem_nhdsWithin] with t ht + show b.symm (τ t) = a.symm t + simp only [hτdef] + exact b.left_inv (hSb (hsymm t ht).1) + have hz : a.symm r = b.symm q := tendsto_nhds_unique' hFne hlim1 hlim2' + have hzS : a.symm r ∈ S := by + refine ⟨a.map_target hr, ?_⟩ + rw [hz] + exact b.map_target hq + have hr' : a (a.symm r) ∈ Ioo p r := hacoord _ hzS + rw [a.right_inv hr] at hr' + exact lt_irrefl r hr'.2 + +/-- **End-matching, decreasing case.** Same setting, but now the `p`-end is interior to +`a.target` (and the `q`-end interior to `b.target`): the transition is decreasing. -/ +theorem overlap_anti [T2Space M] (a b : OpenPartialHomeomorph M NNReal) + {p r q w : NNReal} + (ha : a '' (a.source ∩ b.source) = Ioo p r) + (hb : b '' (a.source ∩ b.source) = Ioo q w) + (hp : p ∈ a.target) (hq : q ∈ b.target) : + ∀ x ∈ a.source ∩ b.source, ∀ y ∈ a.source ∩ b.source, + a x < a y → b y < b x := by + set S := a.source ∩ b.source with hSdef + have hSa : S ⊆ a.source := inter_subset_left + have hSb : S ⊆ b.source := inter_subset_right + have hacoord : ∀ x ∈ S, a x ∈ Ioo p r := fun x hx => ha ▸ mem_image_of_mem a hx + by_cases hpr : p < r + swap + · intro x hx y hy hxy + exact absurd ((hacoord x hx).1.trans (hacoord x hx).2) hpr + set τ : NNReal → NNReal := fun t => b (a.symm t) with hτdef + have hsymm : ∀ t ∈ Ioo p r, a.symm t ∈ S ∧ a (a.symm t) = t := by + intro t ht + rw [← ha] at ht + obtain ⟨x, hxS, rfl⟩ := ht + rw [a.left_inv (hSa hxS)] + exact ⟨hxS, rfl⟩ + have hkey : ∀ x ∈ S, τ (a x) = b x := by + intro x hx + simp only [hτdef] + rw [a.left_inv (hSa hx)] + have hτmaps : ∀ t ∈ Ioo p r, τ t ∈ Ioo q w := by + intro t ht + have hb' : b (a.symm t) ∈ b '' S := mem_image_of_mem b (hsymm t ht).1 + exact hb ▸ hb' + have hIoo_target : Ioo p r ⊆ a.target := by + rw [← ha] + rintro y ⟨z, hz, rfl⟩ + exact a.map_source (hSa hz) + have hqw_target : Ioo q w ⊆ b.target := by + rw [← hb] + rintro y ⟨z, hz, rfl⟩ + exact b.map_source (hSb hz) + have hcont : ContinuousOn τ (Ioo p r) := + b.continuousOn.comp (a.symm.continuousOn.mono hIoo_target) + (fun t ht => hSb (hsymm t ht).1) + have hinj : InjOn τ (Ioo p r) := by + intro t1 ht1 t2 ht2 heq + obtain ⟨h1S, h1e⟩ := hsymm t1 ht1 + obtain ⟨h2S, h2e⟩ := hsymm t2 ht2 + have h12 : a.symm t1 = a.symm t2 := b.injOn (hSb h1S) (hSb h2S) heq + rw [← h1e, ← h2e, h12] + rcases strictMonoOn_or_strictAntiOn_of_injOn_Ioo hcont hinj with hmono | hanti + · exfalso + have himg : τ '' Ioo p r = Ioo q w := by + apply subset_antisymm + · rintro _ ⟨t, ht, rfl⟩ + exact hτmaps t ht + · intro y hy + rw [← hb] at hy + obtain ⟨x, hxS, rfl⟩ := hy + exact ⟨a x, hacoord x hxS, hkey x hxS⟩ + have hτlim : Tendsto τ (𝓝[>] p) (𝓝 q) := + tendsto_bot_of_strictMonoOn_image hpr hmono himg + have hF : 𝓝[Ioo p r] p = 𝓝[>] p := nhdsWithin_Ioo_eq_nhdsGT hpr + have hFne : (𝓝[Ioo p r] p).NeBot := by + apply mem_closure_iff_nhdsWithin_neBot.mp + rw [closure_Ioo hpr.ne] + exact ⟨le_refl p, hpr.le⟩ + have hlim1 : Tendsto a.symm (𝓝[Ioo p r] p) (𝓝 (a.symm p)) := + (a.symm.continuousOn p hp).mono hIoo_target + have hτq : Tendsto τ (𝓝[Ioo p r] p) (𝓝 q) := hF ▸ hτlim + have hτq' : Tendsto τ (𝓝[Ioo p r] p) (𝓝[b.target] q) := by + rw [tendsto_nhdsWithin_iff] + refine ⟨hτq, ?_⟩ + filter_upwards [self_mem_nhdsWithin] with t ht + exact hqw_target (hτmaps t ht) + have hlim2 : Tendsto (b.symm ∘ τ) (𝓝[Ioo p r] p) (𝓝 (b.symm q)) := + Tendsto.comp (b.symm.continuousOn q hq) hτq' + have hlim2' : Tendsto a.symm (𝓝[Ioo p r] p) (𝓝 (b.symm q)) := by + apply Tendsto.congr' _ hlim2 + filter_upwards [self_mem_nhdsWithin] with t ht + show b.symm (τ t) = a.symm t + simp only [hτdef] + exact b.left_inv (hSb (hsymm t ht).1) + have hz : a.symm p = b.symm q := tendsto_nhds_unique' hFne hlim1 hlim2' + have hzS : a.symm p ∈ S := by + refine ⟨a.map_target hp, ?_⟩ + rw [hz] + exact b.map_target hq + have hp' : a (a.symm p) ∈ Ioo p r := hacoord _ hzS + rw [a.right_inv hp] at hp' + exact lt_irrefl p hp'.1 + · intro x hx y hy hxy + have h := hanti (hacoord x hx) (hacoord y hy) hxy + rwa [hkey x hx, hkey y hy] at h diff --git a/LeanPool/OneManifold/OneMfld/GlueNNReal.lean b/LeanPool/OneManifold/OneMfld/GlueNNReal.lean new file mode 100644 index 0000000000..deee5624e5 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/GlueNNReal.lean @@ -0,0 +1,208 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.GlueCore +import LeanPool.OneManifold.OneMfld.Normalize + +/-! # Gluing two charts into an `ℝ≥0`-valued chart + +The shared assembly for the O-H and O-O (connected overlap) cases. Chart `a` is +normalized so its target is `Ioo 0 1` and the overlap image is the full lower +end-segment `Ioo 0 r`; chart `b` sees the overlap as an upper end-segment `Ioo q 1` of +its target. Pick a split value `μ ∈ Ioo q 1`, let `m := b.symm μ` be the split point and +`ρ := a m` its `a`-coordinate; glue `b` (kept as-is on the `b`-side `s`, where +`b ≤ μ`) with the rescaled chart `(μ/ρ) • a` (which agrees with `b` at `m`) using +`OpenPartialHomeomorph.piecewise` along `s := b.source ∩ b⁻¹' (Iic μ)`, `t := Iic μ`. +All the frontier conditions come from `IsImage.frontier` and `frontier_Iic`. +-/ + +open Set + +/-- **NNReal gluing.** Given charts `a` (target `Ioo 0 1`, overlap image the lower +end-segment `Ioo 0 r`) and `b` (target inside `Iio 1`, overlap image the upper +end-segment `Ioo q 1` with `q` interior), there is a chart on `a.source ∪ b.source` +whose target is `(b.target ∩ Iic μ) ∪ Ioo μ (μ/ρ)` for some split values +`q < μ < 1`, `0 < ρ < 1`. -/ +theorem glue_nnreal {M : Type*} [TopologicalSpace M] [T2Space M] + (a b : OpenPartialHomeomorph M NNReal) + (hat : a.target = Ioo 0 1) + (hbt : b.target ⊆ Iio 1) + {r q : NNReal} + (ha : a '' (a.source ∩ b.source) = Ioo 0 r) (hr0 : 0 < r) (hr1 : r < 1) + (hb : b '' (a.source ∩ b.source) = Ioo q 1) + (hq : q ∈ b.target) : + ∃ f : OpenPartialHomeomorph M NNReal, f.source = a.source ∪ b.source ∧ + ∃ μ ρ : NNReal, q < μ ∧ μ < 1 ∧ 0 < ρ ∧ ρ < 1 ∧ + f.target = (b.target ∩ Iic μ) ∪ Ioo μ (μ/ρ) := by + classical + -- The overlap is nonempty, so `q < 1`. + have hSne : (a.source ∩ b.source).Nonempty := by + have h : (a '' (a.source ∩ b.source)).Nonempty := by + rw [ha]; exact nonempty_Ioo.2 hr0 + exact h.of_image + have hq1 : q < 1 := by + have h : (b '' (a.source ∩ b.source)).Nonempty := hSne.image _ + rw [hb] at h + exact nonempty_Ioo.1 h + -- Pick the split value `μ` and the split point `m`. + obtain ⟨μ, hqμ, hμ1⟩ := exists_between hq1 + have hμ0 : 0 < μ := lt_of_le_of_lt (zero_le : (0 : NNReal) ≤ q) hqμ + obtain ⟨m, hmS, hbm⟩ : ∃ m ∈ a.source ∩ b.source, b m = μ := by + have h : μ ∈ b '' (a.source ∩ b.source) := by rw [hb]; exact ⟨hqμ, hμ1⟩ + obtain ⟨m, hm, hbm⟩ := h + exact ⟨m, hm, hbm⟩ + have hρmem : a m ∈ Ioo 0 r := by rw [← ha]; exact mem_image_of_mem _ hmS + have hρ0 : 0 < a m := hρmem.1 + have hρr : a m < r := hρmem.2 + have hρ1 : a m < 1 := hρr.trans hr1 + have hc : (0 : NNReal) < μ / a m := div_pos hμ0 hρ0 + have hcρ : μ / a m * a m = μ := div_mul_cancel₀ μ hρ0.ne' + -- The rescaled chart `e' = (μ/ρ) • a`. + set e' := a.transHomeomorph (NNReal.mulHomeomorph (μ / a m) hc) with he'def + have he's : e'.source = a.source := rfl + have he'app : ∀ x, e' x = μ / a m * a x := fun _ => rfl + have he't : e'.target = Ioo 0 (μ / a m) := by + rw [he'def, OpenPartialHomeomorph.transHomeomorph_target, hat] + ext y + simp only [mem_preimage, NNReal.mulHomeomorph_symm_apply, mem_Ioo] + constructor + · rintro ⟨h1, h2⟩ + refine ⟨?_, ?_⟩ + · rcases eq_or_lt_of_le (zero_le : (0 : NNReal) ≤ y) with h | h + · rw [← h, mul_zero] at h1; exact absurd h1 (lt_irrefl 0) + · exact h + · have h3 := mul_lt_mul_of_pos_left h2 hc + rwa [mul_inv_cancel_left₀ hc.ne', mul_one] at h3 + · rintro ⟨h1, h2⟩ + refine ⟨mul_pos (inv_pos.2 hc) h1, ?_⟩ + have h3 := mul_lt_mul_of_pos_left h2 (inv_pos.2 hc) + rwa [inv_mul_cancel₀ hc.ne'] at h3 + -- The transition map is increasing. + have hr' : r ∈ a.target := by rw [hat]; exact ⟨hr0, hr1⟩ + have mono := overlap_mono a b ha hb hr' hq + -- Membership in the overlap via the image descriptions. + have hmem_of_a : ∀ x ∈ a.source, a x < r → x ∈ a.source ∩ b.source := by + intro x hx hxr + have h0 : 0 < a x := by + have h := a.map_source hx + rw [hat] at h + exact h.1 + have h : a x ∈ a '' (a.source ∩ b.source) := by rw [ha]; exact ⟨h0, hxr⟩ + obtain ⟨x', hx', hax'⟩ := h + have hxx : x' = x := a.injOn hx'.1 hx hax' + rwa [hxx] at hx' + have hmem_of_b : ∀ x ∈ b.source, q < b x → x ∈ a.source ∩ b.source := by + intro x hx hqx + have h1 : b x < 1 := hbt (b.map_source hx) + have h : b x ∈ b '' (a.source ∩ b.source) := by rw [hb]; exact ⟨hqx, h1⟩ + obtain ⟨x', hx', hbx'⟩ := h + have hxx : x' = x := b.injOn hx'.2 hx hbx' + rwa [hxx] at hx' + -- The side sets for the piecewise gluing. + set s := b.source ∩ b ⁻¹' (Iic μ) with hsdef + -- Key correspondence between the two descriptions of the `b`-side. + have key : ∀ x ∈ a.source, (a x ≤ a m ↔ x ∈ s) := by + intro x hx + constructor + · intro hle + have hxS : x ∈ a.source ∩ b.source := hmem_of_a x hx (lt_of_le_of_lt hle hρr) + refine ⟨hxS.2, ?_⟩ + simp only [mem_preimage, mem_Iic] + rcases lt_or_eq_of_le hle with hlt | heq + · exact le_of_lt (hbm ▸ mono x hxS m hmS hlt) + · have hxm : x = m := a.injOn hx hmS.1 heq + rw [hxm, hbm] + · rintro ⟨hxb, hxμ⟩ + simp only [mem_preimage, mem_Iic] at hxμ + have hxS : x ∈ a.source ∩ b.source := ⟨hx, hxb⟩ + by_contra hgt + rw [not_le] at hgt + have h := mono m hmS x hxS hgt + rw [hbm] at h + exact absurd hxμ (not_le.2 h) + -- `Iic μ` is the image of `s` under both charts. + have H : b.IsImage s (Iic μ) := by + intro x hx + simp only [hsdef, mem_inter_iff, mem_preimage] + exact ⟨fun h => ⟨hx, h⟩, fun h => h.2⟩ + have H' : e'.IsImage s (Iic μ) := by + intro x hx + rw [he's] at hx + rw [he'app x, ← key x hx, mem_Iic] + constructor + · intro h + have h2 : μ / a m * a x ≤ μ / a m * a m := by rw [hcρ]; exact h + exact le_of_mul_le_mul_left h2 hc + · intro h + calc μ / a m * a x ≤ μ / a m * a m := mul_le_mul_of_nonneg_left h (le_of_lt hc) + _ = μ := hcρ + -- Both frontier intersections are the singleton `{m}`. + have hft : frontier (Iic μ) = {μ} := frontier_Iic + have hbfront : b.source ∩ frontier s = {m} := by + have h1 := H.frontier.preimage_eq + rw [hft] at h1 + rw [← h1] + ext x + simp only [mem_inter_iff, mem_preimage, mem_singleton_iff] + constructor + · rintro ⟨hxb, hbx⟩ + exact b.injOn hxb hmS.2 (hbx.trans hbm.symm) + · rintro rfl + exact ⟨hmS.2, hbm⟩ + have he'front : e'.source ∩ frontier s = {m} := by + have h1 := H'.frontier.preimage_eq + rw [hft] at h1 + rw [← h1] + ext x + simp only [mem_inter_iff, mem_preimage, mem_singleton_iff, he's] + constructor + · rintro ⟨hxa, hex⟩ + rw [he'app x] at hex + have h2 : μ / a m * a x = μ / a m * a m := by rw [hcρ]; exact hex + have h3 : a x = a m := mul_left_cancel₀ hc.ne' h2 + exact a.injOn hxa hmS.1 h3 + · rintro rfl + exact ⟨hmS.1, by rw [he'app, hcρ]⟩ + have Hs : b.source ∩ frontier s = e'.source ∩ frontier s := by + rw [hbfront, he'front] + have Heq : EqOn b e' (b.source ∩ frontier s) := by + rw [hbfront] + intro x hx + rw [mem_singleton_iff] at hx + subst hx + rw [hbm, he'app, hcρ] + -- Glue. + refine ⟨b.piecewise e' s (Iic μ) H H' Hs Heq, ?_, μ, a m, hqμ, hμ1, hρ0, hρ1, ?_⟩ + · show Set.ite s b.source e'.source = a.source ∪ b.source + have hite : Set.ite s b.source e'.source = (b.source ∩ s) ∪ (e'.source \ s) := rfl + rw [hite, he's] + apply Subset.antisymm + · rintro x (⟨hxb, -⟩ | ⟨hxa, -⟩) + · exact Or.inr hxb + · exact Or.inl hxa + · rintro x hx + by_cases hxs : x ∈ s + · exact Or.inl ⟨hxs.1, hxs⟩ + · rcases hx with hxa | hxb + · exact Or.inr ⟨hxa, hxs⟩ + · have hμx : μ < b x := by + by_contra hle + rw [not_lt] at hle + exact hxs ⟨hxb, hle⟩ + have hxS := hmem_of_b x hxb (hqμ.trans hμx) + exact Or.inr ⟨hxS.1, hxs⟩ + · show Set.ite (Iic μ) b.target e'.target = (b.target ∩ Iic μ) ∪ Ioo μ (μ / a m) + have hite : Set.ite (Iic μ) b.target e'.target + = (b.target ∩ Iic μ) ∪ (e'.target \ Iic μ) := rfl + rw [hite, he't] + congr 1 + ext y + simp only [mem_sdiff, mem_Ioo, mem_Iic, not_le] + constructor + · rintro ⟨⟨-, h2⟩, h3⟩ + exact ⟨h3, h2⟩ + · rintro ⟨h1, h2⟩ + exact ⟨⟨lt_of_le_of_lt (zero_le : (0 : NNReal) ≤ μ) h1, h2⟩, h1⟩ diff --git a/LeanPool/OneManifold/OneMfld/GlueUI.lean b/LeanPool/OneManifold/OneMfld/GlueUI.lean new file mode 100644 index 0000000000..efa52841ab --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/GlueUI.lean @@ -0,0 +1,308 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.GlueCore +import LeanPool.OneManifold.OneMfld.GlueBlocks + +/-! # Gluing two boundary charts onto the unit interval + +The H-H assembly. Both charts are normalized to target `Iio 1`; each sees the overlap +as an upper end-segment (`Ioo p 1` in `a`, `Ioo q 1` in `b`), and the transition is +decreasing (`overlap_anti`). Embed `b` into the lower half of the unit interval via +`halfOPH` (`x ↦ x/2`) and `a` into the upper piece via a decreasing Möbius map +`mobiusOPH k` (`x ↦ k/(x+k)`), with `k` chosen so the two embeddings agree at the split +point `m := b.symm μ` (that is, `k/(ρ+k) = μ/2` where `ρ := a m`). Glue with +`OpenPartialHomeomorph.piecewise` along `t := {y ≤ μ/2}`; the two targets +`[0, μ/2]` and `(μ/2, 1]` unite to the whole interval. +-/ + +open Set + +/-- **Unit-interval gluing.** Two boundary charts (targets `Iio 1`) whose overlap is an +upper end-segment in each glue to a chart of `M` onto the whole unit interval, with +source `a.source ∪ b.source`. -/ +theorem glue_hh_ui {M : Type*} [TopologicalSpace M] [T2Space M] + (a b : OpenPartialHomeomorph M NNReal) + (hat : a.target = Iio 1) (hbt : b.target = Iio 1) + {p q : NNReal} + (ha : a '' (a.source ∩ b.source) = Ioo p 1) (hp : p < 1) + (hb : b '' (a.source ∩ b.source) = Ioo q 1) : + ∃ f : OpenPartialHomeomorph M UnitInterval, + f.source = a.source ∪ b.source ∧ f.target = univ := by + classical + -- the overlap is nonempty, so `q < 1` + have hS : (a.source ∩ b.source).Nonempty := by + have h1 : (Ioo p (1 : NNReal)).Nonempty := nonempty_Ioo.2 hp + rw [← ha] at h1 + exact h1.of_image + have hq1 : q < 1 := nonempty_Ioo.1 (hb ▸ hS.image b) + -- choose the split level `μ` and its preimage `m` + obtain ⟨μ, hqμ, hμ1⟩ := exists_between hq1 + have hμpos : 0 < μ := lt_of_le_of_lt zero_le hqμ + have hμS : μ ∈ b '' (a.source ∩ b.source) := by rw [hb]; exact ⟨hqμ, hμ1⟩ + obtain ⟨m, hmS, hbm⟩ := hμS + have hma : m ∈ a.source := hmS.1 + have hme : m ∈ b.source := hmS.2 + set ρ := a m with hρdef + have hρmem : ρ ∈ Ioo p 1 := by rw [← ha]; exact mem_image_of_mem a hmS + have hρp : p < ρ := hρmem.1 + have hρ1 : ρ < 1 := hρmem.2 + have hρpos : 0 < ρ := lt_of_le_of_lt zero_le hρp + -- the Möbius parameter `k` and its key identity `k/(ρ+k) = μ/2` + have h2μ : μ < 2 := hμ1.trans one_lt_two + have h2μpos : 0 < 2 - μ := tsub_pos_of_lt h2μ + set k : NNReal := μ * ρ / (2 - μ) with hkdef + have hkpos : 0 < k := div_pos (mul_pos hμpos hρpos) h2μpos + have hkey2 : 2 * k = μ * (ρ + k) := by + have h1 : k * (2 - μ) = μ * ρ := by + rw [hkdef]; exact div_mul_cancel₀ _ h2μpos.ne' + calc 2 * k = ((2 - μ) + μ) * k := by rw [tsub_add_cancel_of_le h2μ.le] + _ = (2 - μ) * k + μ * k := add_mul _ _ _ + _ = μ * ρ + μ * k := by rw [mul_comm (2 - μ) k, h1] + _ = μ * (ρ + k) := (mul_add μ ρ k).symm + -- real-number versions of the positivity facts and the key identity + have hkR : (0 : ℝ) < (k : ℝ) := NNReal.coe_pos.2 hkpos + have hμR : (0 : ℝ) < (μ : ℝ) := NNReal.coe_pos.2 hμpos + have hρR : (0 : ℝ) < (ρ : ℝ) := NNReal.coe_pos.2 hρpos + have hμ1R : (μ : ℝ) < 1 := by exact_mod_cast hμ1 + have hρ1R : (ρ : ℝ) < 1 := by exact_mod_cast hρ1 + have hρkR : (0 : ℝ) < (ρ : ℝ) + (k : ℝ) := by linarith + have hkeyR : (k : ℝ) / ((ρ : ℝ) + (k : ℝ)) = (μ : ℝ) / 2 := by + have h := congrArg (fun x : NNReal => (x : ℝ)) hkey2 + push_cast at h + rw [div_eq_div_iff hρkR.ne' (two_ne_zero)] + linarith + -- the two building blocks + obtain ⟨eb, hbs, hbt', hbf⟩ := halfOPH + obtain ⟨ea, has, hat', haf, hanti⟩ := mobiusOPH k hkpos + set e := b.trans eb with hedef + set e' := a.trans ea with he'def + have hbmem : ∀ x, x ∈ b.source → b x ∈ Iio (1 : NNReal) := fun x hx => + hbt ▸ b.map_source hx + have hesrc : e.source = b.source := by + rw [hedef, OpenPartialHomeomorph.trans_source, hbs, inter_eq_left] + intro x hx + exact hbmem x hx + have he'src : e'.source = a.source := by + rw [he'def, OpenPartialHomeomorph.trans_source, has, preimage_univ, inter_univ] + have hef : ∀ x ∈ b.source, (e x : ℝ) = (b x : ℝ) / 2 := by + intro x hx + rw [hedef, OpenPartialHomeomorph.trans_apply] + exact hbf (b x) (hbmem x hx) + have he'f : ∀ x : M, (e' x : ℝ) = (k : ℝ) / ((a x : ℝ) + (k : ℝ)) := by + intro x + rw [he'def, OpenPartialHomeomorph.trans_apply] + exact haf (a x) + -- the gluing sets + set tset : Set UnitInterval := {y : UnitInterval | (y : ℝ) ≤ (μ : ℝ) / 2} with htdef + set sset : Set M := b.source ∩ b ⁻¹' (Iic μ) with hsdef + -- the anti correspondence between the two coordinates on the overlap + have hpa : p ∈ a.target := by rw [hat]; exact hp + have hqb : q ∈ b.target := by rw [hbt]; exact hq1 + have anti := overlap_anti a b ha hb hpa hqb + -- `ρ ≤ a x` on `a.source` characterizes `sset` + have hcorr : ∀ x, x ∈ a.source → (ρ ≤ a x ↔ x ∈ sset) := by + intro x hxa + constructor + · intro hle + have hax1 : a x < 1 := by + have h := a.map_source hxa + rwa [hat] at h + have haxS : a x ∈ Ioo p 1 := ⟨hρp.trans_le hle, hax1⟩ + rw [← ha] at haxS + obtain ⟨z, hzS, hz⟩ := haxS + have hzx : z = x := a.injOn hzS.1 hxa hz + subst hzx + rw [hsdef] + refine ⟨hzS.2, ?_⟩ + rcases eq_or_lt_of_le hle with heq | hlt + · have hxm : z = m := a.injOn hxa hma (heq.symm.trans hρdef) + rw [mem_preimage, hxm, hbm] + exact mem_Iic.2 le_rfl + · have h := anti m hmS z hzS (by rw [← hρdef]; exact hlt) + rw [hbm] at h + exact mem_Iic.2 h.le + · intro hxs + rw [hsdef] at hxs + obtain ⟨hxb, hxμ⟩ := hxs + have hxS : x ∈ a.source ∩ b.source := ⟨hxa, hxb⟩ + by_contra hlt + push Not at hlt + have h := anti x hxS m hmS (by rw [← hρdef]; exact hlt) + rw [hbm] at h + rw [mem_preimage, mem_Iic] at hxμ + exact absurd hxμ (not_le.mpr h) + -- `IsImage` for the lower embedding + have H : e.IsImage sset tset := by + intro x hx + rw [hesrc] at hx + have h1 : e x ∈ tset ↔ (b x : ℝ) ≤ (μ : ℝ) := by + rw [htdef, mem_ofPred_eq, hef x hx] + constructor <;> intro h <;> linarith + have h2 : x ∈ sset ↔ b x ≤ μ := by + rw [hsdef] + exact ⟨fun h => h.2, fun h => ⟨hx, h⟩⟩ + rw [h1, h2, NNReal.coe_le_coe] + -- `IsImage` for the upper embedding + have H' : e'.IsImage sset tset := by + intro x hx + rw [he'src] at hx + have haxk : (0 : ℝ) < (a x : ℝ) + (k : ℝ) := + add_pos_of_nonneg_of_pos (a x).coe_nonneg hkR + have h1 : e' x ∈ tset ↔ (k : ℝ) / ((a x : ℝ) + (k : ℝ)) ≤ (μ : ℝ) / 2 := by + rw [htdef, mem_ofPred_eq, he'f x] + have h2 : ((k : ℝ) / ((a x : ℝ) + (k : ℝ)) ≤ (μ : ℝ) / 2) ↔ ρ ≤ a x := by + rw [← hkeyR] + constructor + · intro h + rw [div_le_div_iff₀ haxk hρkR] at h + have h3 : (ρ : ℝ) + (k : ℝ) ≤ (a x : ℝ) + (k : ℝ) := + le_of_mul_le_mul_left h hkR + have h4 : (ρ : ℝ) ≤ (a x : ℝ) := by linarith + exact_mod_cast h4 + · intro h + have h3 : (ρ : ℝ) ≤ (a x : ℝ) := NNReal.coe_le_coe.2 h + rw [div_le_div_iff₀ haxk hρkR] + nlinarith + rw [h1, h2] + exact hcorr x hx + -- the frontier of `tset` is the level `{μ/2}` + have hfront_t : frontier tset = {y : UnitInterval | (y : ℝ) = (μ : ℝ) / 2} := by + rw [htdef] + exact frontier_UIIic (half_pos hμR) (by linarith) + -- both sources meet the frontier of `sset` exactly at `m` + have hfr_e : e.source ∩ frontier sset = {m} := by + rw [← H.frontier.preimage_eq, hfront_t, hesrc] + ext x + simp only [mem_inter_iff, mem_preimage, mem_ofPred_eq, mem_singleton_iff] + constructor + · rintro ⟨hxb, hx2⟩ + rw [hef x hxb] at hx2 + have hbx : b x = μ := by + have h : (b x : ℝ) = (μ : ℝ) := by linarith + exact_mod_cast h + exact b.injOn hxb hme (hbx.trans hbm.symm) + · intro hxm + rw [hxm] + exact ⟨hme, by rw [hef m hme, hbm]⟩ + have hfr_e' : e'.source ∩ frontier sset = {m} := by + rw [← H'.frontier.preimage_eq, hfront_t, he'src] + ext x + simp only [mem_inter_iff, mem_preimage, mem_ofPred_eq, mem_singleton_iff] + constructor + · rintro ⟨hxa, hx2⟩ + rw [he'f x, ← hkeyR] at hx2 + have haxk : (0 : ℝ) < (a x : ℝ) + (k : ℝ) := + add_pos_of_nonneg_of_pos (a x).coe_nonneg hkR + rw [div_eq_div_iff haxk.ne' hρkR.ne'] at hx2 + have h4 : (ρ : ℝ) + (k : ℝ) = (a x : ℝ) + (k : ℝ) := + mul_left_cancel₀ hkR.ne' hx2 + have h5 : a x = ρ := by + have h : (a x : ℝ) = (ρ : ℝ) := by linarith + exact_mod_cast h + exact a.injOn hxa hma (by rw [h5, hρdef]) + · intro hxm + rw [hxm] + refine ⟨hma, ?_⟩ + rw [he'f m, ← hρdef] + exact hkeyR + have Hs : e.source ∩ frontier sset = e'.source ∩ frontier sset := + hfr_e.trans hfr_e'.symm + -- the two embeddings agree at the frontier point `m` + have Heq : Set.EqOn e e' (e.source ∩ frontier sset) := by + rw [hfr_e] + intro x hx + rw [mem_singleton_iff] at hx + subst hx + apply Subtype.ext + rw [hef x hme, hbm, he'f x, ← hρdef, hkeyR] + -- glue + set f := e.piecewise e' sset tset H H' Hs Heq with hfdef + refine ⟨f, ?_, ?_⟩ + · -- source computation + have hfs : f.source = e.source ∩ sset ∪ e'.source \ sset := rfl + rw [hfs, hesrc, he'src] + apply subset_antisymm + · rintro x (⟨hxb, _⟩ | ⟨hxa, _⟩) + · exact Or.inr hxb + · exact Or.inl hxa + · intro x hx + by_cases hxs : x ∈ sset + · have hxb : x ∈ b.source := by + rw [hsdef] at hxs + exact hxs.1 + exact Or.inl ⟨hxb, hxs⟩ + · rcases hx with hxa | hxb + · exact Or.inr ⟨hxa, hxs⟩ + · -- `x ∈ b.source \ sset` implies `x` lies in the overlap + have hμbx : μ < b x := by + by_contra hle + push Not at hle + exact hxs (by rw [hsdef]; exact ⟨hxb, mem_Iic.2 hle⟩) + have hbx1 : b x < 1 := hbmem x hxb + have hbIoo : b x ∈ Ioo q 1 := ⟨hqμ.trans hμbx, hbx1⟩ + rw [← hb] at hbIoo + obtain ⟨z, hzS, hz⟩ := hbIoo + have hzx : z = x := b.injOn hzS.2 hxb hz + subst hzx + exact Or.inr ⟨hzS.1, hxs⟩ + · -- target computation + have hft : f.target = e.target ∩ tset ∪ e'.target \ tset := rfl + rw [hft] + apply eq_univ_of_forall + intro y + by_cases hy : (y : ℝ) ≤ (μ : ℝ) / 2 + · -- lower piece + left + have hyt : y ∈ eb.target := by + rw [hbt'] + show (y : ℝ) < 1 / 2 + linarith + refine ⟨?_, hy⟩ + rw [hedef, OpenPartialHomeomorph.trans_target] + refine ⟨hyt, ?_⟩ + rw [mem_preimage, hbt, ← hbs] + exact eb.map_target hyt + · -- upper piece + right + push Not at hy + refine ⟨?_, fun h => absurd h (not_le.2 hy)⟩ + have hy0 : (0 : ℝ) < (y : ℝ) := lt_trans (half_pos hμR) hy + have hy1 : (y : ℝ) ≤ 1 := y.2.2 + -- the point `w := k/y - k` of `a.target` mapping to `y` + have hknn : (k : ℝ) ≤ (k : ℝ) / (y : ℝ) := by + rw [le_div_iff₀ hy0] + nlinarith + have hnn : (0 : ℝ) ≤ (k : ℝ) / (y : ℝ) - (k : ℝ) := by linarith + have h1k : (0 : ℝ) < 1 + (k : ℝ) := by linarith + have hge : (k : ℝ) / (1 + (k : ℝ)) ≤ (k : ℝ) / ((ρ : ℝ) + (k : ℝ)) := by + rw [div_le_div_iff₀ h1k hρkR] + nlinarith + have hygt : (k : ℝ) / (1 + (k : ℝ)) < (y : ℝ) := + lt_of_le_of_lt (hge.trans (le_of_eq hkeyR)) hy + have hlt1 : (k : ℝ) / (y : ℝ) - (k : ℝ) < 1 := by + rw [div_lt_iff₀ h1k] at hygt + rw [sub_lt_iff_lt_add] + rw [div_lt_iff₀ hy0] + nlinarith + set w : NNReal := Real.toNNReal ((k : ℝ) / (y : ℝ) - (k : ℝ)) with hwdef + have hwcoe : (w : ℝ) = (k : ℝ) / (y : ℝ) - (k : ℝ) := Real.coe_toNNReal _ hnn + have hwtarget : w ∈ a.target := by + rw [hat, mem_Iio, ← NNReal.coe_lt_coe, NNReal.coe_one, hwcoe] + exact hlt1 + set x₀ := a.symm w with hx0def + have hx0src : x₀ ∈ a.source := a.map_target hwtarget + have hax0 : a x₀ = w := a.right_inv hwtarget + have hkne : (k : ℝ) ≠ 0 := hkR.ne' + have hyne : (y : ℝ) ≠ 0 := hy0.ne' + have he'x0 : (e' x₀ : ℝ) = (y : ℝ) := by + rw [he'f x₀, hax0, hwcoe, sub_add_cancel] + rw [div_div_eq_mul_div, mul_comm (k : ℝ) (y : ℝ), mul_div_assoc, + div_self hkne, mul_one] + have hexy : e' x₀ = y := Subtype.ext he'x0 + have hx0src' : x₀ ∈ e'.source := by rw [he'src]; exact hx0src + have := e'.map_source hx0src' + rwa [hexy] at this diff --git a/LeanPool/OneManifold/OneMfld/IntervalCharts.lean b/LeanPool/OneManifold/OneMfld/IntervalCharts.lean new file mode 100644 index 0000000000..aab8e75432 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/IntervalCharts.lean @@ -0,0 +1,56 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.ClassifyInterval +import LeanPool.OneManifold.OneMfld.NiceCharts + +class IntervalChartedSpace (M : Type*) [TopologicalSpace M] extends ChartedSpace NNReal M where + is_interval (φ : OpenPartialHomeomorph M NNReal) (h : φ ∈ atlas) : (∃ x y, (Set.Ioo x y = φ.target)) ∨ (∃ x, (Set.Iio x = φ.target)) + +variable + {M : Type*} + [TopologicalSpace M] + +theorem ioi_unbounded (x : NNReal) : ¬ Bornology.IsBounded (Set.Ioi x) := by + intro h + have h' : BddBelow (Set.Ioi x) ∧ BddAbove (Set.Ioi x) := + (isBounded_iff_bddBelow_bddAbove (s := Set.Ioi x)).1 h + exact (not_bddAbove_Ioi x) h'.2 + +theorem univ_unbounded : ¬ Bornology.IsBounded (Set.univ : Set NNReal) := by + intro h + -- On an `IsOrderBornology`, bounded ⇔ bddBelow ∧ bddAbove. + have h' : + BddBelow (Set.univ : Set NNReal) ∧ + BddAbove (Set.univ : Set NNReal) := + (isBounded_iff_bddBelow_bddAbove + (s := (Set.univ : Set NNReal))).1 h + -- But `univ` is not bounded above on a `NoTopOrder` type like `NNReal`. + exact not_bddAbove_univ h'.2 + +@[instance_reducible] noncomputable def interval_charted (ht : NicelyChartedSpace NNReal M) : IntervalChartedSpace M where + chartAt := ht.chartAt + atlas := ht.atlas + mem_chart_source := ht.mem_chart_source + chart_mem_atlas := ht.chart_mem_atlas + is_interval (φ : OpenPartialHomeomorph M NNReal) := by + intro h + have bounded := ht.is_bounded φ h + have connected := ht.is_connected φ h + + have c := classify_connected_nnreal_interval (φ.target) (φ.open_target) (isConnected_iff_connectedSpace.mpr connected) + rcases c with (h|h|h|h) + · left ; assumption + · right ; assumption + · exfalso + rcases h with ⟨x,h⟩ + apply ioi_unbounded x + rw [h] + exact bounded + · exfalso + apply univ_unbounded + rw [←h] + exact bounded diff --git a/LeanPool/OneManifold/OneMfld/LocallyConnected.lean b/LeanPool/OneManifold/OneMfld/LocallyConnected.lean new file mode 100644 index 0000000000..d0dbe7a526 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/LocallyConnected.lean @@ -0,0 +1,165 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib + +instance : LocallyConnectedSpace Real := by infer_instance + +instance : LocallyConnectedSpace NNReal := by + rw [locallyConnectedSpace_iff_connected_subsets] + intro x U xU + rw [NNReal.isEmbedding_coe.nhds_eq_comap x] at xU + simp only [Filter.mem_comap] at xU + let ⟨t, x_t, t_U⟩ := xU + rw [mem_nhds_iff_exists_Ioo_subset] at x_t + let ⟨l, u, x_ul, ul_t⟩ := x_t + rw [Set.Ioo] at x_ul + dsimp at x_ul + have l_lt_u : l < u := lt_trans x_ul.1 x_ul.2 + have upos : 0 < u := lt_of_lt_of_le' (x_ul.2) x.coe_nonneg + + let V := {y : NNReal | l < ↑y ∧ ↑y < u} + use V + constructor + . rw [NNReal.isEmbedding_coe.nhds_eq_comap x] + simp only [Filter.mem_comap] + use Set.Ioo l u + constructor + . exact Ioo_mem_nhds x_ul.1 x_ul.2 + . intro a a_lu + dsimp [V] + rw [Set.preimage, Set.Ioo] at a_lu + dsimp at a_lu + exact a_lu + constructor + -- . apply Convex.IsConnected + . apply IsConnected.isPreconnected + apply IsPathConnected.isConnected + rw [IsPathConnected] + let z := ((max 0 l) + u) / 2 + have znonneg : 0 ≤ z := by + have nn₁ : 0 ≤ (max 0 l) := le_max_left 0 l + have nn₂ : 0 ≤ u := LT.lt.le upos + have : 0 ≤ (max 0 l) + u := add_nonneg nn₁ nn₂ + exact div_nonneg this zero_le_two + let z' : NNReal := NNReal.mk z znonneg + have l_lt_z : l < z := by + have : l ≤ max 0 l := le_max_right 0 l + show l < (max 0 l + u) / 2 + linarith + have z_lt_u : z < u := by + have : max 0 l < u := max_lt_iff.mpr ⟨upos, l_lt_u⟩ + show (max 0 l + u) / 2 < u + linarith + have : z' ∈ V := ⟨l_lt_z, z_lt_u⟩ + use z' + use this + intro y yV + dsimp [V] at yV + by_cases h : z' = y + . exact Inseparable.joinedIn (congrArg nhds h) this yV + rw [JoinedIn] + let γ : Path z' y := { + toFun := fun t ↦ NNReal.mk ((unitInterval.symm t)*z' + t*y) + (add_nonneg (mul_nonneg unitInterval.nonneg' znonneg) + (mul_nonneg unitInterval.nonneg' y.coe_nonneg)) + continuous_toFun := by + simp only [unitInterval.coe_symm_eq] + refine Metric.continuous_iff.mpr ?_ + intro s ε εpos + let δ := ε / dist y z' + have dyz'pos : 0 < dist y z' := dist_pos.mpr (ne_comm.mpr h) + have δpos : δ > 0 := div_pos εpos dyz'pos + use δ + constructor + . exact δpos + intro a a_s_near + rw [NNReal.dist_eq] + simp only [NNReal.coe_mk] + rw [sub_mul, sub_mul, one_mul] + + let ans : Real := (↑a - ↑s) * (↑y - ↑z') + have : ↑z' - ↑a * ↑z' + ↑a * ↑y - (↑z' - ↑s * ↑z' + ↑s * ↑y) = ans := by ring + rw [this] + dsimp [ans] + + rw [abs_mul] + + + --have : (max 0 l + u) / 2 - ↑a * ((max 0 l + u) / 2) + ↑a * ↑y - ((max 0 l + u) / 2 - ↑s * ((max 0 l + u) / 2) + ↑s * ↑y) + -- = (↑a - ↑s) * (↑y - ((max 0 l + u) / 2)) := by ring + --ring_nf + + have ha : |(a:ℝ) - (s:ℝ)| < δ := by + rw [← Real.dist_eq (a : ℝ) (s : ℝ)] + exact a_s_near + have this' : |↑y - (max 0 l + u) / 2| = dist y z' := rfl + have this : |(y:ℝ) - (z':ℝ)| = dist y z' := by + exact this' + rw [this] + + calc + |↑a - ↑s| * dist y z' + < δ * dist y z' := by exact ((mul_lt_mul_iff_of_pos_right dyz'pos).mpr a_s_near) + _ = ε := by dsimp [δ] + ring_nf + refine mul_inv_cancel_right₀ ?_ ε + exact dist_ne_zero.mpr fun a => h (id (Eq.symm a)) + source' := by + simp only [unitInterval.symm_zero, Set.Icc.coe_one, one_mul, + Set.Icc.coe_zero, zero_mul, add_zero] + exact rfl + target' := by + simp only [unitInterval.symm_one, Set.Icc.coe_zero, zero_mul, Set.Icc.coe_one, one_mul, + zero_add] + trivial + } + use γ + intro t + dsimp [V, γ] + constructor + . show l < ↑(unitInterval.symm t) * ((max 0 l + u) / 2) + ↑t * ↑y + by_cases tpos : t > 0 + . calc + l = ↑(unitInterval.symm t) * l + t * l := by + simp only [unitInterval.coe_symm_eq] + ring + _ < ↑(unitInterval.symm t) * l + t * y := by + have : t * l < t * y := mul_lt_mul_of_pos_left yV.1 tpos + linarith + _ ≤ ↑(unitInterval.symm t) * z + t * y := by + have : ↑(unitInterval.symm t) * l ≤ ↑(unitInterval.symm t) * z + := mul_le_mul_of_nonneg_left (le_of_lt l_lt_z) unitInterval.nonneg' + linarith + . have : t = 0 := le_antisymm (not_lt.mp tpos) (unitInterval.nonneg') + rw [this] + simp only [unitInterval.symm_zero, Set.Icc.coe_one, one_mul, Set.Icc.coe_zero, zero_mul, + add_zero, gt_iff_lt] + exact l_lt_z + . show ↑(unitInterval.symm t) * ((max 0 l + u) / 2) + ↑t * ↑y < u + by_cases tpos : t > 0 + . calc + ↑(unitInterval.symm t) * ((max 0 l + u) / 2) + ↑t * ↑y + < ↑(unitInterval.symm t) * ((max 0 l + u) / 2) + ↑t * u := by + have : ↑t * ↑y < ↑t * u := mul_lt_mul_of_pos_left yV.2 tpos + linarith + _ ≤ ↑(unitInterval.symm t) * u + ↑t * u := by + have : ↑(unitInterval.symm t) * ((max 0 l + u) / 2) ≤ ↑(unitInterval.symm t) * u + := mul_le_mul_of_nonneg_left (le_of_lt z_lt_u) unitInterval.nonneg' + linarith + _ = u := by rw [unitInterval.coe_symm_eq]; ring + . have : t = 0 := le_antisymm (not_lt.mp tpos) (unitInterval.nonneg') + rw [this] + simp only [unitInterval.symm_zero, Set.Icc.coe_one, one_mul, Set.Icc.coe_zero, zero_mul, + add_zero, gt_iff_lt] + exact z_lt_u + . intro a aV + dsimp [V] at aV + apply t_U + rw [Set.preimage] + dsimp + apply ul_t + rw [Set.Ioo] + exact aV diff --git a/LeanPool/OneManifold/OneMfld/NiceCharts.lean b/LeanPool/OneManifold/OneMfld/NiceCharts.lean new file mode 100644 index 0000000000..f39d0fea9f --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/NiceCharts.lean @@ -0,0 +1,202 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.LocallyConnected +import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers + +variable + {M : Type*} + [TopologicalSpace M] + +noncomputable def improved_chart (φ : OpenPartialHomeomorph M NNReal) (x : M) (h : x ∈ φ.source) : + { ψ : OpenPartialHomeomorph M NNReal | (x ∈ ψ.source ∧ Bornology.IsBounded ψ.target) } := by + + let y := φ.toFun x + + by_cases h0 : y > 0 + · let interval := Set.Ioo (y-1) (y+1) + let t := φ.target ∩ interval + let s := φ.symm '' t + let sOpen : IsOpen s := by + apply (OpenPartialHomeomorph.isOpen_symm_image_iff_of_subset_target φ (by exact + Set.inter_subset_left)).mpr + exact IsOpen.inter φ.open_target isOpen_Ioo + let φ' := φ.restrOpen s sOpen + + use φ' + apply And.intro + · dsimp [φ'] + simp only [Set.mem_inter_iff] + apply And.intro + · exact h + · dsimp [s] + simp only [Set.mem_image] + use y + apply And.intro + · apply Set.mem_inter + · exact PartialEquiv.map_source φ.toPartialEquiv h + · apply Set.mem_Ioo.mpr + apply And.intro + · refine NNReal.coe_lt_coe.mp ?_ + simp only [NNReal.coe_lt_coe, tsub_lt_self_iff, zero_lt_one, and_true] + exact h0 + · simp only [lt_add_iff_pos_right, zero_lt_one] + · exact OpenPartialHomeomorph.left_inv φ h + · have bi : Bornology.IsBounded interval := Metric.isBounded_Ioo (y - 1) (y + 1) + apply Bornology.IsBounded.subset bi + intro z hz + have hz' : z ∈ φ.target ∩ ↑φ.symm ⁻¹' (↑φ.symm '' t) := hz + rw [restrOpen_symm_image_target φ (t := t) Set.inter_subset_left] at hz' + exact Set.mem_of_mem_inter_right hz' + + · simp only [gt_iff_lt, not_lt, nonpos_iff_eq_zero] at h0 + let interval := Set.Iio (1 : NNReal) + let t := φ.target ∩ interval + let s := φ.symm '' t + let sOpen : IsOpen s := by + apply (OpenPartialHomeomorph.isOpen_symm_image_iff_of_subset_target φ (by exact + Set.inter_subset_left)).mpr + exact IsOpen.inter φ.open_target isOpen_Iio + let φ' := φ.restrOpen s sOpen + + use φ' + apply And.intro + · dsimp [φ'] + simp only [Set.mem_inter_iff] + apply And.intro + · exact h + · dsimp [s] + simp only [Set.mem_image] + use y + apply And.intro + · apply Set.mem_inter + · exact PartialEquiv.map_source φ.toPartialEquiv h + · exact Set.mem_Iio.mpr (by + rw [h0] + exact zero_lt_one' NNReal) + · exact OpenPartialHomeomorph.left_inv φ h + · have bi : Bornology.IsBounded interval := by + have : interval = Set.Ico 0 1 := by + dsimp [interval] + ext z + simp only [Set.mem_Iio, Set.mem_Ico, zero_le, true_and] + rw [this] + exact Metric.isBounded_Ico 0 1 + apply Bornology.IsBounded.subset bi + intro z hz + have hz' : z ∈ φ.target ∩ ↑φ.symm ⁻¹' (↑φ.symm '' t) := hz + rw [restrOpen_symm_image_target φ (t := t) Set.inter_subset_left] at hz' + exact Set.mem_of_mem_inter_right hz' + +noncomputable def improved_chart' (φ : OpenPartialHomeomorph M NNReal) (x : M) (h : x ∈ φ.source) (bounded : Bornology.IsBounded φ.target) : + { ψ : OpenPartialHomeomorph M NNReal | x ∈ ψ.source ∧ Bornology.IsBounded ψ.target ∧ ConnectedSpace ψ.target } := by + + let y := φ.toFun x + + let t := connectedComponentIn φ.target y + let s := φ.symm '' t + + let sOpen : IsOpen s := by + apply OpenPartialHomeomorph.isOpen_image_symm_of_subset_target φ + apply IsOpen.connectedComponentIn + · exact φ.open_target + · exact connectedComponentIn_subset φ.target y + + let ψ := φ.restrOpen s sOpen + use ψ + + apply And.intro + · dsimp [ψ] + simp only [Set.mem_inter_iff] + apply And.intro + · exact h + · dsimp [s] + simp only [Set.mem_image] + use y + apply And.intro + · apply mem_connectedComponentIn + exact PartialEquiv.map_source φ.toPartialEquiv h + · exact OpenPartialHomeomorph.left_inv φ h + · apply And.intro + · have : ψ.target ⊆ φ.target := by + intro z hz + exact Set.mem_of_mem_inter_left hz + exact Bornology.IsBounded.subset bounded this + · dsimp [ψ] + apply isConnected_iff_connectedSpace.mp + dsimp [s] + have : (φ.target ∩ ↑φ.symm ⁻¹' (↑φ.symm '' t)) = t := + restrOpen_symm_image_target φ (t := t) (connectedComponentIn_subset φ.target y) + rw [this] + apply isConnected_connectedComponentIn_iff.mpr + exact PartialEquiv.map_source φ.toPartialEquiv h + +noncomputable def nice_chart (φ : OpenPartialHomeomorph M NNReal) (x : M) (h : x ∈ φ.source) : + { ψ : OpenPartialHomeomorph M NNReal | x ∈ ψ.source ∧ Bornology.IsBounded ψ.target ∧ ConnectedSpace ψ.target } := by + rcases (improved_chart φ x h) with ⟨ φ', h1, h2 ⟩ + rcases (improved_chart' φ' x h1 h2) with ⟨ φ'', h1, h2, h3 ⟩ + use φ'' + simp only [Set.mem_ofPred_eq] + exact ⟨ h1, ⟨ h2, h3 ⟩ ⟩ + +lemma nice_chart_source {φ : OpenPartialHomeomorph M NNReal} {x : M} {h : x ∈ φ.source} : + x ∈ (nice_chart φ x h).1.source := by + let c := nice_chart φ x h + have : c = nice_chart φ x h := rfl + rw [←this] + exact c.2.1 + +lemma nice_chart_bounded {φ : OpenPartialHomeomorph M NNReal} {x : M} {h : x ∈ φ.source} : + Bornology.IsBounded (nice_chart φ x h).1.target := by + let c := nice_chart φ x h + have : c = nice_chart φ x h := rfl + rw [←this] + exact c.2.2.1 + +lemma nice_chart_connected {φ : OpenPartialHomeomorph M NNReal} {x : M} {h : x ∈ φ.source} : + ConnectedSpace (nice_chart φ x h).1.target := by + let c := nice_chart φ x h + have : c = nice_chart φ x h := rfl + rw [←this] + exact c.2.2.2 + +structure NiceChartAt (x : M) where + chart : OpenPartialHomeomorph M NNReal + mem_chart_source : x ∈ chart.source + bounded : Bornology.IsBounded chart.target + connected : ConnectedSpace chart.target + +class NicelyChartedSpace (H : Type*) [TopologicalSpace H] [Bornology H] (M : Type*) [TopologicalSpace M] extends ChartedSpace H M where + is_bounded (φ : OpenPartialHomeomorph M H) (h : φ ∈ atlas) : Bornology.IsBounded φ.target + is_connected (φ : OpenPartialHomeomorph M H) (h : φ ∈ atlas) : ConnectedSpace φ.target + +@[instance_reducible] noncomputable def nicely_charted (ht : ChartedSpace NNReal M) : NicelyChartedSpace NNReal M where + chartAt := by + intro x + let c := ht.chartAt x + let c' := nice_chart (ht.chartAt x) x (ht.mem_chart_source x) + exact c'.1 + atlas := let f x := (nice_chart (ht.chartAt x) x (ht.mem_chart_source x)).1 + Set.image f (Set.univ : Set M) + mem_chart_source (x : M) := by + simp only [Set.mem_ofPred_eq] + exact nice_chart_source + chart_mem_atlas (x : M) := by + simp only [Set.mem_ofPred_eq, Set.image_univ, Set.mem_range, exists_apply_eq_apply] + is_bounded (φ : OpenPartialHomeomorph M NNReal) := by + intro h + dsimp [atlas] at h + simp at h + rcases h with ⟨ y, hy ⟩ + rw [←hy] + apply nice_chart_bounded + is_connected (φ : OpenPartialHomeomorph M NNReal) := by + intro h + dsimp [atlas] at h + simp at h + rcases h with ⟨ y, hy ⟩ + rw [←hy] + apply nice_chart_connected diff --git a/LeanPool/OneManifold/OneMfld/Noncompact.lean b/LeanPool/OneManifold/OneMfld/Noncompact.lean new file mode 100644 index 0000000000..84091f55ba --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/Noncompact.lean @@ -0,0 +1,89 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib + +open Set + +/-- `[0, ∞) ⊆ ℝ` is not compact. -/ +lemma not_isCompact_Ici_zero_real : ¬ IsCompact (Ici (0 : ℝ)) := by + classical + intro hIci0 + -- Open cover U n = (-∞, n) + let U : ℕ → Set ℝ := fun n => Iio (n : ℝ) + have hUopen : ∀ n, IsOpen (U n) := fun _ => isOpen_Iio + + -- This open cover really does cover `[0, ∞)`. + have hCover : Ici (0 : ℝ) ⊆ ⋃ n : ℕ, U n := by + intro x hx + -- For any real x, there exists n : ℕ with x < n. + obtain ⟨n, hn⟩ := exists_nat_gt x + refine mem_iUnion.mpr ?_ + exact ⟨n, hn⟩ + + -- By compactness, we get a finite subcover. + obtain ⟨s, hs⟩ := hIci0.elim_finite_subcover U hUopen hCover + -- s : Finset ℕ, hs : Ici (0 : ℝ) ⊆ ⋃ n ∈ s, U n + + -- Let N be the supremum (i.e., max) of the finite set s. + let N : ℕ := s.sup id + + -- N (as a real) is in `[0, ∞)`. + have hNmem : (N : ℝ) ∈ Ici (0 : ℝ) := by + have : (0 : ℝ) ≤ N := by exact_mod_cast Nat.zero_le N + exact this + + -- But N is *not* in the finite union ⋃ n ∈ s, U n. + have hNnot : (N : ℝ) ∉ ⋃ n ∈ s, U n := by + intro hmem + -- From membership in the union, pick some n ∈ s with (N : ℝ) < n. + rcases mem_iUnion.mp hmem with ⟨n, hmem'⟩ + rcases mem_iUnion.mp hmem' with ⟨hn_in_s, hmemU⟩ + -- hmemU says (N : ℝ) < n, since U n = Iio n. + have hlt : (N : ℝ) < n := hmemU + -- But by definition of N as sup over s, every n ∈ s satisfies n ≤ N. + have hle : n ≤ N := by + -- `le_sup` says `id n ≤ s.sup id` for n ∈ s. + simpa [N] using (Finset.le_sup (s := s) (f := id) hn_in_s) + -- So we get (N : ℝ) < n ≤ N, hence (N : ℝ) < (N : ℝ), contradiction. + have hcontr : (N : ℝ) < (N : ℝ) := + lt_of_lt_of_le hlt (by exact_mod_cast hle) + exact lt_irrefl _ hcontr + + -- But hs says the finite subcover covers `[0, ∞)`, so it must contain N. + exact hNnot (hs hNmem) + +/-- `NNReal` (the nonnegative reals with the induced topology) is not a compact space. -/ +theorem not_compactSpace_NNReal : ¬ CompactSpace NNReal := by + intro h + -- Use the assumed instance `CompactSpace NNReal`. + have : CompactSpace NNReal := h + + -- The whole space is compact. + have hK : IsCompact (univ : Set NNReal) := isCompact_univ + + -- Consider the inclusion `NNReal → ℝ`. + have hImage : + IsCompact ((fun x : NNReal => (x : ℝ)) '' (univ : Set NNReal)) := + hK.image (by + -- continuity of the inclusion + simpa using NNReal.continuous_coe) + + -- Identify the image with `[0, ∞)` as a subset of ℝ. + have hImage_eq : ((fun x : NNReal => (x : ℝ)) '' (univ : Set NNReal)) + = Ici (0 : ℝ) := by + ext x; constructor + · -- forward direction: any `x = ↑y` with y ≥ 0 lies in `[0,∞)` + rintro ⟨y, -, rfl⟩ + exact y.coe_nonneg + · -- backward: any real x ≥ 0 comes from some nnreal y with y.val = x + intro hx + exact ⟨NNReal.mk x hx, trivial, rfl⟩ + + have hIci0 : IsCompact (Ici (0 : ℝ)) := by + simpa [hImage_eq] using hImage + + -- Contradiction with the previous lemma. + exact not_isCompact_Ici_zero_real hIci0 diff --git a/LeanPool/OneManifold/OneMfld/Normalize.lean b/LeanPool/OneManifold/OneMfld/Normalize.lean new file mode 100644 index 0000000000..b739c89630 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/Normalize.lean @@ -0,0 +1,182 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.Charts + +/-! # Normalization of interval charts + +Affine tools for putting interval charts into standard position without changing their +sources: an `HChart` can be rescaled so its target is `Iio 1`, an `OChart` so its target +is `Ioo 0 1`, and an `OChart` with target `Ioo 0 1` can be orientation-reversed +(`x ↦ 1 - x`). H-charts cannot be flipped: the closed end at `0` is a boundary point. +-/ + +open Set + +noncomputable section + +/-- Multiplication by a positive constant, as a self-homeomorphism of `ℝ≥0`. -/ +def NNReal.mulHomeomorph (c : NNReal) (hc : 0 < c) : NNReal ≃ₜ NNReal where + toFun x := c * x + invFun y := c⁻¹ * y + left_inv := by + intro x + exact inv_mul_cancel_left₀ hc.ne' x + right_inv := by + intro y + exact mul_inv_cancel_left₀ hc.ne' y + continuous_toFun := by + exact continuous_const.mul continuous_id + continuous_invFun := by + exact continuous_const.mul continuous_id + +@[simp] lemma NNReal.mulHomeomorph_apply (c : NNReal) (hc : 0 < c) (x : NNReal) : + NNReal.mulHomeomorph c hc x = c * x := rfl + +@[simp] lemma NNReal.mulHomeomorph_symm_apply (c : NNReal) (hc : 0 < c) (y : NNReal) : + (NNReal.mulHomeomorph c hc).symm y = c⁻¹ * y := rfl + +/-- The affine map `x ↦ (x - u) / (v - u)`, as an `OpenPartialHomeomorph ℝ≥0 ℝ≥0` with +source `Ioo u v` and target `Ioo 0 1`. -/ +def affineIooOPH (u v : NNReal) (h : u < v) : + { e : OpenPartialHomeomorph NNReal NNReal // + e.source = Ioo u v ∧ e.target = Ioo 0 1 ∧ + ∀ x ∈ Ioo u v, e x = (x - u) / (v - u) } := by + have hvu : 0 < v - u := tsub_pos_of_lt h + refine ⟨{ toFun := fun x => (x - u) / (v - u) + invFun := fun y => u + y * (v - u) + source := Ioo u v + target := Ioo 0 1 + map_source' := ?_ + map_target' := ?_ + left_inv' := ?_ + right_inv' := ?_ + open_source := isOpen_Ioo + open_target := isOpen_Ioo + continuousOn_toFun := + ((continuous_id.sub continuous_const).div_const _).continuousOn + continuousOn_invFun := + (continuous_const.add (continuous_id.mul continuous_const)).continuousOn }, + rfl, rfl, fun x _ => rfl⟩ + · intro x hx + exact ⟨div_pos (tsub_pos_of_lt hx.1) hvu, + (div_lt_one hvu).mpr (tsub_lt_tsub_right_of_le hx.1.le hx.2)⟩ + · intro y hy + exact ⟨lt_add_of_pos_right u (mul_pos hy.1 hvu), + lt_tsub_iff_left.mp (mul_lt_of_lt_one_left hvu hy.2)⟩ + · intro x hx + show u + (x - u) / (v - u) * (v - u) = x + rw [div_mul_cancel₀ _ hvu.ne', add_tsub_cancel_of_le hx.1.le] + · intro y _ + show (u + y * (v - u) - u) / (v - u) = y + rw [add_tsub_cancel_left, mul_div_cancel_right₀ _ hvu.ne'] + +/-- The reflection `x ↦ 1 - x`, as an `OpenPartialHomeomorph ℝ≥0 ℝ≥0` with source and +target `Ioo 0 1`. -/ +def reflectIooOPH : + { e : OpenPartialHomeomorph NNReal NNReal // + e.source = Ioo 0 1 ∧ e.target = Ioo 0 1 ∧ + ∀ x ∈ Ioo (0 : NNReal) 1, e x = 1 - x } := by + refine ⟨{ toFun := fun x => 1 - x + invFun := fun y => 1 - y + source := Ioo 0 1 + target := Ioo 0 1 + map_source' := ?_ + map_target' := ?_ + left_inv' := ?_ + right_inv' := ?_ + open_source := isOpen_Ioo + open_target := isOpen_Ioo + continuousOn_toFun := (continuous_const.sub continuous_id).continuousOn + continuousOn_invFun := (continuous_const.sub continuous_id).continuousOn }, + rfl, rfl, fun x _ => rfl⟩ + · intro x hx + exact ⟨tsub_pos_of_lt hx.2, tsub_lt_self one_pos hx.1⟩ + · intro y hy + exact ⟨tsub_pos_of_lt hy.2, tsub_lt_self one_pos hy.1⟩ + · intro x hx + exact tsub_tsub_cancel_of_le hx.2.le + · intro y hy + exact tsub_tsub_cancel_of_le hy.2.le + +variable {M : Type*} [TopologicalSpace M] + +/-- Rescale an `HChart` so its target is `Iio 1`, without changing its source. -/ +def HChart.rescale (a : HChart M) (hne : a.source.Nonempty) : + { b : HChart M // b.source = a.source ∧ b.target = Iio 1 ∧ + ∃ v : NNReal, 0 < v ∧ a.target = Iio v ∧ ∀ x ∈ a.source, b.toFun x = v⁻¹ * a.toFun x } := by + let v := a.target_iio.choose + have hv : Iio v = a.target := a.target_iio.choose_spec + have hvpos : 0 < v := by + obtain ⟨y, hy⟩ := chart_target_nonempty a.toOpenPartialHomeomorph hne + rw [← hv] at hy + exact lt_of_le_of_lt zero_le hy + have hipos : 0 < v⁻¹ := inv_pos.mpr hvpos + have htarget : + (a.toOpenPartialHomeomorph.transHomeomorph (NNReal.mulHomeomorph v⁻¹ hipos)).target + = Iio 1 := by + rw [OpenPartialHomeomorph.transHomeomorph_target, ← hv] + ext y + simp only [mem_preimage, NNReal.mulHomeomorph_symm_apply, mem_Iio, inv_inv] + exact mul_lt_iff_lt_one_right hvpos + exact ⟨⟨a.toOpenPartialHomeomorph.transHomeomorph (NNReal.mulHomeomorph v⁻¹ hipos), + ⟨1, htarget.symm⟩⟩, + rfl, htarget, ⟨v, hvpos, hv.symm, fun x _ => rfl⟩⟩ + +/-- Rescale an `OChart` so its target is `Ioo 0 1`, without changing its source. -/ +def OChart.rescale (a : OChart M) (hne : a.source.Nonempty) : + { b : OChart M // b.source = a.source ∧ b.target = Ioo 0 1 ∧ + ∃ u v : NNReal, u < v ∧ a.target = Ioo u v ∧ + ∀ x ∈ a.source, b.toFun x = (a.toFun x - u) / (v - u) } := by + let u := a.target_ioo.choose + let v := a.target_ioo.choose_spec.choose + have huv : Ioo u v = a.target := a.target_ioo.choose_spec.choose_spec + have h : u < v := by + obtain ⟨y, hy⟩ := chart_target_nonempty a.toOpenPartialHomeomorph hne + rw [← huv] at hy + exact hy.1.trans hy.2 + obtain ⟨e, hes, het, hef⟩ := affineIooOPH u v h + have hsource : (a.toOpenPartialHomeomorph.trans e).source = a.source := by + rw [OpenPartialHomeomorph.trans_source, hes] + refine inter_eq_left.mpr fun x hx => ?_ + rw [mem_preimage, huv] + exact a.toOpenPartialHomeomorph.map_source hx + have htarget : (a.toOpenPartialHomeomorph.trans e).target = Ioo 0 1 := by + rw [OpenPartialHomeomorph.trans_target, het] + refine inter_eq_left.mpr fun y hy => ?_ + rw [mem_preimage, ← huv, ← hes] + exact e.map_target (by rw [het]; exact hy) + refine ⟨⟨a.toOpenPartialHomeomorph.trans e, ⟨0, 1, htarget.symm⟩⟩, hsource, htarget, + ⟨u, v, h, huv.symm, fun x hx => ?_⟩⟩ + have hmem : a.toFun x ∈ Ioo u v := by + rw [huv] + exact a.toOpenPartialHomeomorph.map_source hx + exact hef _ hmem + +/-- Reverse the orientation of an `OChart` with target `Ioo 0 1`, without changing its +source. -/ +def OChart.flip (a : OChart M) (h01 : a.target = Ioo 0 1) : + { b : OChart M // b.source = a.source ∧ b.target = Ioo 0 1 ∧ + ∀ x ∈ a.source, b.toFun x = 1 - a.toFun x } := by + obtain ⟨e, hes, het, hef⟩ := reflectIooOPH + have hsource : (a.toOpenPartialHomeomorph.trans e).source = a.source := by + rw [OpenPartialHomeomorph.trans_source, hes] + refine inter_eq_left.mpr fun x hx => ?_ + rw [mem_preimage, ← h01] + exact a.toOpenPartialHomeomorph.map_source hx + have htarget : (a.toOpenPartialHomeomorph.trans e).target = Ioo 0 1 := by + rw [OpenPartialHomeomorph.trans_target, het] + refine inter_eq_left.mpr fun y hy => ?_ + rw [mem_preimage, h01, ← hes] + exact e.map_target (by rw [het]; exact hy) + refine ⟨⟨a.toOpenPartialHomeomorph.trans e, ⟨0, 1, htarget.symm⟩⟩, hsource, htarget, + fun x hx => ?_⟩ + have hmem : a.toFun x ∈ Ioo (0 : NNReal) 1 := by + rw [← h01] + exact a.toOpenPartialHomeomorph.map_source hx + exact hef _ hmem + +end diff --git a/LeanPool/OneManifold/OneMfld/Outer.lean b/LeanPool/OneManifold/OneMfld/Outer.lean new file mode 100644 index 0000000000..0a218bb731 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/Outer.lean @@ -0,0 +1,364 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.ClosureOverlap +import LeanPool.OneManifold.OneMfld.LocallyConnected +import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers +import LeanPool.OneManifold.OneMfld.ClassifyInterval + +/-! # The outer-overlap lemma + +The structural heart of the classification: when two interval charts `U`, `V` overlap +(neither source containing the other), the image under `U` of any connected component of +`U.source ∩ V.source` is an *end-segment* of `U.target` — its closure reaches an open +endpoint of the target. The mechanism: if the closure of the image stayed inside the +target, the component's closure in `M` would be trapped inside `U.source` (a compactness +argument), contradicting `nonempty_closure_inter_diff`, which forces the component's +closure to escape into `V.source \ U.source`. +-/ + +open Set + +variable {M : Type*} [TopologicalSpace M] + +section ComponentTransport + +/-- A partial homeomorphism maps the connected component of `x` in a subset `S` of its +source onto the connected component of `φ x` in `φ '' S`. -/ +lemma OpenPartialHomeomorph.image_connectedComponentIn + {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] + (φ : OpenPartialHomeomorph X Y) {S : Set X} (hS : S ⊆ φ.source) + {x : X} (hx : x ∈ S) : + φ '' connectedComponentIn S x = connectedComponentIn (φ '' S) (φ x) := by + have hST : φ '' S ⊆ φ.target := by + rintro y ⟨z, hz, rfl⟩ + exact φ.map_source (hS hz) + apply subset_antisymm + · have hW : IsConnected (connectedComponentIn S x) := + isConnected_connectedComponentIn_iff.mpr hx + have hWS : connectedComponentIn S x ⊆ S := connectedComponentIn_subset S x + have himg : IsConnected (φ '' connectedComponentIn S x) := + hW.image _ (φ.continuousOn.mono (hWS.trans hS)) + apply himg.isPreconnected.subset_connectedComponentIn + · exact ⟨x, mem_connectedComponentIn hx, rfl⟩ + · exact image_mono hWS + · have hW' : IsConnected (connectedComponentIn (φ '' S) (φ x)) := + isConnected_connectedComponentIn_iff.mpr ⟨x, hx, rfl⟩ + have hW'T : connectedComponentIn (φ '' S) (φ x) ⊆ φ '' S := + connectedComponentIn_subset _ _ + have hsymm : IsConnected (φ.symm '' connectedComponentIn (φ '' S) (φ x)) := + hW'.image _ (φ.symm.continuousOn.mono (hW'T.trans hST)) + have hsub : φ.symm '' connectedComponentIn (φ '' S) (φ x) + ⊆ connectedComponentIn S x := by + apply hsymm.isPreconnected.subset_connectedComponentIn + · exact ⟨φ x, mem_connectedComponentIn ⟨x, hx, rfl⟩, φ.left_inv (hS hx)⟩ + · calc φ.symm '' connectedComponentIn (φ '' S) (φ x) + ⊆ φ.symm '' (φ '' S) := image_mono hW'T + _ = S := φ.toPartialEquiv.symm_image_image_of_subset_source hS + calc connectedComponentIn (φ '' S) (φ x) + = φ '' (φ.symm '' connectedComponentIn (φ '' S) (φ x)) := + (φ.toPartialEquiv.image_symm_image_of_subset_target (hW'T.trans hST)).symm + _ ⊆ φ '' connectedComponentIn S x := image_mono hsub + +/-- Connected components of an open set contained in a chart source are open, because the +model space is locally connected. -/ +lemma isOpen_connectedComponentIn_chart + {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] [LocallyConnectedSpace Y] + (φ : OpenPartialHomeomorph X Y) {S : Set X} (hS : S ⊆ φ.source) + (hSo : IsOpen S) (x : X) : + IsOpen (connectedComponentIn S x) := by + by_cases hx : x ∈ S + · have key := OpenPartialHomeomorph.image_connectedComponentIn φ hS hx + have hWS : connectedComponentIn S x ⊆ S := connectedComponentIn_subset S x + have hopen : IsOpen (connectedComponentIn (φ '' S) (φ x)) := + (φ.isOpen_image_of_subset_source hSo hS).connectedComponentIn + have hsub : connectedComponentIn (φ '' S) (φ x) ⊆ φ.target := by + intro y hy + obtain ⟨z, hz, rfl⟩ := connectedComponentIn_subset _ _ hy + exact φ.map_source (hS hz) + have hrw : connectedComponentIn S x + = φ.symm '' connectedComponentIn (φ '' S) (φ x) := by + rw [← key] + exact (φ.toPartialEquiv.symm_image_image_of_subset_source (hWS.trans hS)).symm + rw [hrw] + exact φ.isOpen_image_symm_of_subset_target hopen hsub + · rw [connectedComponentIn_eq_empty hx] + exact isOpen_empty + +/-- Components of an open set contained in a chart source are relatively closed: a point +of `S` in the closure of a component of `S` lies in that component. -/ +lemma mem_connectedComponentIn_of_mem_closure + {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] [LocallyConnectedSpace Y] + (φ : OpenPartialHomeomorph X Y) {S : Set X} (hS : S ⊆ φ.source) (hSo : IsOpen S) + {x z : X} (hz : z ∈ closure (connectedComponentIn S x)) (hzS : z ∈ S) : + z ∈ connectedComponentIn S x := by + have hW2open : IsOpen (connectedComponentIn S z) := + isOpen_connectedComponentIn_chart φ hS hSo z + have hzW2 : z ∈ connectedComponentIn S z := mem_connectedComponentIn hzS + obtain ⟨y, hyW2, hyW⟩ := mem_closure_iff.mp hz _ hW2open hzW2 + have h1 : connectedComponentIn S z = connectedComponentIn S y := + connectedComponentIn_eq hyW2 + have h2 : connectedComponentIn S x = connectedComponentIn S y := + connectedComponentIn_eq hyW + rw [h2, ← h1] + exact hzW2 + +end ComponentTransport + +section Escape + +/-- The image under `U` of a component of the overlap is not all of `U.target` +(because `U.source` is not contained in `V.source`). -/ +lemma image_component_ne_target + (U V : OpenPartialHomeomorph M NNReal) + (hUV : (U.source \ V.source).Nonempty) + {x : M} (hx : x ∈ U.source ∩ V.source) : + U '' connectedComponentIn (U.source ∩ V.source) x ≠ U.target := by + intro h + obtain ⟨y, hyU, hyV⟩ := hUV + have hWsub : connectedComponentIn (U.source ∩ V.source) x ⊆ U.source ∩ V.source := + connectedComponentIn_subset _ _ + have hyt : U y ∈ U '' connectedComponentIn (U.source ∩ V.source) x := by + rw [h] + exact U.map_source hyU + obtain ⟨w, hwW, hwy⟩ := hyt + have hwyeq : w = y := U.injOn (hWsub hwW).1 hyU hwy + exact hyV (hwyeq ▸ (hWsub hwW).2) + +/-- The heart of the outer-overlap argument: the closure (in `ℝ≥0`) of the image of an +overlap component cannot stay inside the (bounded) chart target. Otherwise the +component's closure in `M` would be a subset of the compact set +`U.symm '' closure (U '' W)` inside `U.source` — but by `nonempty_closure_inter_diff` +the component's closure must reach a point of `V.source` outside the component, and any +such point trapped in `U.source ∩ V.source` would belong to the component after all. -/ +theorem not_closure_image_subset_target [T2Space M] + (U V : OpenPartialHomeomorph M NNReal) + (hUb : Bornology.IsBounded U.target) + (hV : IsConnected V.source) + (hVU : (V.source \ U.source).Nonempty) + {x : M} (hx : x ∈ U.source ∩ V.source) : + ¬ closure (U '' connectedComponentIn (U.source ∩ V.source) x) ⊆ U.target := by + intro hcl + set S := U.source ∩ V.source with hSdef + set W := connectedComponentIn S x with hWdef + set A := U '' W with hAdef + have hSo : IsOpen S := U.open_source.inter V.open_source + have hSU : S ⊆ U.source := inter_subset_left + have hWS : W ⊆ S := connectedComponentIn_subset _ _ + -- the closure of the image is compact + have hAT : A ⊆ U.target := by + rintro y ⟨w, hw, rfl⟩ + exact U.map_source (hSU (hWS hw)) + have hAcomp : IsCompact (closure A) := (hUb.subset hAT).isCompact_closure + -- its preimage under `U.symm` is compact, hence closed, and lives in `U.source` + have hKcomp : IsCompact (U.symm '' closure A) := + hAcomp.image_of_continuousOn (U.symm.continuousOn.mono hcl) + have hKclosed : IsClosed (U.symm '' closure A) := hKcomp.isClosed + have hKU : U.symm '' closure A ⊆ U.source := by + rintro z ⟨a, ha, rfl⟩ + exact U.map_target (hcl ha) + have hWK : W ⊆ U.symm '' closure A := by + intro w hw + exact ⟨U w, subset_closure ⟨w, hw, rfl⟩, U.left_inv (hSU (hWS hw))⟩ + have hclWU : closure W ⊆ U.source := + (closure_minimal hWK hKclosed).trans hKU + -- the component's closure must escape into `V.source \ W` + have hWo : IsOpen W := isOpen_connectedComponentIn_chart U hSU hSo x + have hWV : (W ∩ V.source).Nonempty := ⟨x, mem_connectedComponentIn hx, hx.2⟩ + obtain ⟨y, hyV, hyU⟩ := hVU + have hVW : (V.source \ W).Nonempty := + ⟨y, hyV, fun hyW => hyU (hSU (hWS hyW))⟩ + obtain ⟨z, hzcl, hzV, hzW⟩ := + nonempty_closure_inter_diff hV hWo V.open_source hWV hVW + have hzS : z ∈ S := ⟨hclWU hzcl, hzV⟩ + exact hzW (mem_connectedComponentIn_of_mem_closure U hSU hSo hzcl hzS) + +end Escape + +section EndpointAnalysis + +/-- A nonempty open connected subset of `Iio v ⊆ ℝ≥0`, other than `Iio v` itself, whose +closure is not contained in `Iio v`, is an upper end-segment `Ioo p v`. -/ +theorem eq_Ioo_of_closure_not_subset_Iio {v : NNReal} {A : Set NNReal} + (hA : A ⊆ Iio v) (hAo : IsOpen A) (hAc : IsConnected A) + (hAne : A ≠ Iio v) + (hesc : ¬ closure A ⊆ Iio v) : + ∃ p, p < v ∧ A = Ioo p v := by + obtain ⟨e, heA, hev⟩ := not_subset.mp hesc + have hve : v ≤ e := not_lt.mp hev + obtain ⟨a, ha⟩ := hAc.nonempty + rcases classify_connected_nnreal_interval A hAo hAc with ⟨p, q, hpq⟩ | ⟨q, hq⟩ | ⟨p, hp⟩ | h + · -- `A = Ioo p q`: the escape forces `q = v` + have hpq' : p < q := by + have ha' : a ∈ Ioo p q := hpq.symm ▸ ha + exact lt_trans ha'.1 ha'.2 + have hqv : q ≤ v := by + by_contra hqv + push Not at hqv + obtain ⟨t, ht1, ht2⟩ := exists_between (max_lt hpq' hqv) + have htA : t ∈ A := hpq ▸ mem_Ioo.mpr ⟨lt_of_le_of_lt (le_max_left p v) ht1, ht2⟩ + exact absurd (mem_Iio.mp (hA htA)) + (not_lt.mpr (le_trans (le_max_right p v) ht1.le)) + have hclA : closure A = Icc p q := by + rw [← hpq] + exact closure_Ioo hpq'.ne + have heIcc : e ∈ Icc p q := hclA ▸ heA + have hqveq : q = v := le_antisymm hqv (le_trans hve heIcc.2) + exact ⟨p, hqveq ▸ hpq', by rw [← hpq, hqveq]⟩ + · -- `A = Iio q`: forces `A = Iio v`, contradiction + exfalso + have hqv : q ≤ v := by + by_contra hqv + push Not at hqv + exact lt_irrefl v (hA (hq ▸ mem_Iio.mpr hqv)) + have hclA : closure A = Iic q := by + rw [← hq] + exact closure_Iio' ⟨a, hq.symm ▸ ha⟩ + have heq : e ≤ q := (hclA ▸ heA : e ∈ Iic q) + have : q = v := le_antisymm hqv (le_trans hve heq) + exact hAne (by rw [← hq, this]) + · -- `A = Ioi p`: unbounded, contradiction + exfalso + have h1 : max (p + 1) v ∈ A := + hp ▸ mem_Ioi.mpr (lt_of_lt_of_le (lt_add_one p) (le_max_left _ _)) + exact absurd (mem_Iio.mp (hA h1)) (not_lt.mpr (le_max_right _ _)) + · -- `A = univ`: unbounded, contradiction + exfalso + have h1 : v ∈ A := h.symm ▸ mem_univ v + exact lt_irrefl v (hA h1) + +/-- A nonempty open connected subset of `Ioo u v ⊆ ℝ≥0` whose closure is not contained in +`Ioo u v` is an end-segment: `Ioo p v` or `Ioo u q`. -/ +theorem eq_end_segment_of_closure_not_subset_Ioo {u v : NNReal} {A : Set NNReal} + (hA : A ⊆ Ioo u v) (hAo : IsOpen A) (hAc : IsConnected A) + (hesc : ¬ closure A ⊆ Ioo u v) : + (∃ p, u ≤ p ∧ p < v ∧ A = Ioo p v) ∨ (∃ q, u < q ∧ q ≤ v ∧ A = Ioo u q) := by + obtain ⟨e, heA, hev⟩ := not_subset.mp hesc + obtain ⟨a, ha⟩ := hAc.nonempty + rcases classify_connected_nnreal_interval A hAo hAc with ⟨p, q, hpq⟩ | ⟨q, hq⟩ | ⟨p, hp⟩ | h + · -- `A = Ioo p q`: the escape point pins one endpoint + have hpq' : p < q := by + have ha' : a ∈ Ioo p q := hpq.symm ▸ ha + exact lt_trans ha'.1 ha'.2 + have hup : u ≤ p := by + by_contra hup + push Not at hup + obtain ⟨t, ht1, ht2⟩ := exists_between (lt_min_iff.mpr ⟨hpq', hup⟩ : p < min q u) + have htA : t ∈ A := hpq ▸ mem_Ioo.mpr ⟨ht1, lt_of_lt_of_le ht2 (min_le_left q u)⟩ + exact absurd (hA htA).1 (not_lt.mpr (le_trans ht2.le (min_le_right q u))) + have hqv : q ≤ v := by + by_contra hqv + push Not at hqv + obtain ⟨t, ht1, ht2⟩ := exists_between (max_lt_iff.mpr ⟨hpq', hqv⟩ : max p v < q) + have htA : t ∈ A := hpq ▸ mem_Ioo.mpr ⟨lt_of_le_of_lt (le_max_left p v) ht1, ht2⟩ + exact absurd (hA htA).2 (not_lt.mpr (le_trans (le_max_right p v) ht1.le)) + have hclA : closure A = Icc p q := by + rw [← hpq] + exact closure_Ioo hpq'.ne + have heIcc : e ∈ Icc p q := hclA ▸ heA + rw [mem_Ioo, not_and_or, not_lt, not_lt] at hev + rcases hev with heu | hve + · -- `e ≤ u`: the lower endpoint is `u` + have hpu : p = u := le_antisymm (le_trans heIcc.1 heu) hup + exact Or.inr ⟨q, hpu ▸ hpq', hqv, by rw [← hpq, hpu]⟩ + · -- `v ≤ e`: the upper endpoint is `v` + have hqveq : q = v := le_antisymm hqv (le_trans hve heIcc.2) + exact Or.inl ⟨p, hup, hqveq ▸ hpq', by rw [← hpq, hqveq]⟩ + · -- `A = Iio q`: contains `0`, but `A ⊆ Ioo u v` — impossible + exfalso + have h0q : (0 : NNReal) < q := + lt_of_le_of_lt (zero_le : (0 : NNReal) ≤ a) + (mem_Iio.mp (hq.symm ▸ ha : a ∈ Iio q)) + have h0A : (0 : NNReal) ∈ A := hq ▸ mem_Iio.mpr h0q + exact absurd (hA h0A).1 (not_lt.mpr (zero_le : (0 : NNReal) ≤ u)) + · -- `A = Ioi p`: unbounded, contradiction + exfalso + have h1 : max (p + 1) v ∈ A := + hp ▸ mem_Ioi.mpr (lt_of_lt_of_le (lt_add_one p) (le_max_left _ _)) + exact absurd (hA h1).2 (not_lt.mpr (le_max_right _ _)) + · -- `A = univ`: unbounded, contradiction + exfalso + have h1 : v ∈ A := h.symm ▸ mem_univ v + exact lt_irrefl v (hA h1).2 + +end EndpointAnalysis + +section Outer + +/-- **Outer-overlap lemma, boundary-chart case.** If `U` has target `Iio v` and overlaps +`V` (neither source containing the other), the image under `U` of any connected component +of the overlap is an upper end-segment `Ioo p v`. -/ +theorem overlap_component_outer_Iio [T2Space M] + (U V : OpenPartialHomeomorph M NNReal) {v : NNReal} + (hUt : U.target = Iio v) + (hV : IsConnected V.source) + (hUV : (U.source \ V.source).Nonempty) + (hVU : (V.source \ U.source).Nonempty) + {x : M} (hx : x ∈ U.source ∩ V.source) : + ∃ p, p < v ∧ U '' connectedComponentIn (U.source ∩ V.source) x = Ioo p v := by + set S := U.source ∩ V.source with hSdef + set W := connectedComponentIn S x with hWdef + set A := U '' W with hAdef + have hSU : S ⊆ U.source := inter_subset_left + have hSo : IsOpen S := U.open_source.inter V.open_source + have hWo : IsOpen W := isOpen_connectedComponentIn_chart U hSU hSo x + have hWS : W ⊆ S := connectedComponentIn_subset _ _ + have hAo : IsOpen A := U.isOpen_image_of_subset_source hWo (hWS.trans hSU) + have hAc : IsConnected A := + (isConnected_connectedComponentIn_iff.mpr hx).image _ + (U.continuousOn.mono (hWS.trans hSU)) + have hAsub : A ⊆ U.target := by + rintro y ⟨w, hw, rfl⟩ + exact U.map_source (hSU (hWS hw)) + have hUb : Bornology.IsBounded U.target := by + rw [hUt] + have : Iio v = Ico 0 v := by + ext z + simp only [mem_Iio, mem_Ico, zero_le, true_and] + rw [this] + exact Metric.isBounded_Ico 0 v + have hAne : A ≠ Iio v := by + rw [← hUt] + exact image_component_ne_target U V hUV hx + have hesc : ¬ closure A ⊆ Iio v := by + rw [← hUt] + exact not_closure_image_subset_target U V hUb hV hVU hx + exact eq_Ioo_of_closure_not_subset_Iio (hUt ▸ hAsub) hAo hAc hAne hesc + +/-- **Outer-overlap lemma, interior-chart case.** If `U` has target `Ioo u v` and +overlaps `V`, the image under `U` of any connected component of the overlap is an +end-segment `Ioo p v` or `Ioo u q`. -/ +theorem overlap_component_outer_Ioo [T2Space M] + (U V : OpenPartialHomeomorph M NNReal) {u v : NNReal} + (hUt : U.target = Ioo u v) + (hV : IsConnected V.source) + (hVU : (V.source \ U.source).Nonempty) + {x : M} (hx : x ∈ U.source ∩ V.source) : + (∃ p, u ≤ p ∧ p < v ∧ U '' connectedComponentIn (U.source ∩ V.source) x = Ioo p v) ∨ + (∃ q, u < q ∧ q ≤ v ∧ U '' connectedComponentIn (U.source ∩ V.source) x = Ioo u q) := by + set S := U.source ∩ V.source with hSdef + set W := connectedComponentIn S x with hWdef + set A := U '' W with hAdef + have hSU : S ⊆ U.source := inter_subset_left + have hSo : IsOpen S := U.open_source.inter V.open_source + have hWo : IsOpen W := isOpen_connectedComponentIn_chart U hSU hSo x + have hWS : W ⊆ S := connectedComponentIn_subset _ _ + have hAo : IsOpen A := U.isOpen_image_of_subset_source hWo (hWS.trans hSU) + have hAc : IsConnected A := + (isConnected_connectedComponentIn_iff.mpr hx).image _ + (U.continuousOn.mono (hWS.trans hSU)) + have hAsub : A ⊆ U.target := by + rintro y ⟨w, hw, rfl⟩ + exact U.map_source (hSU (hWS hw)) + have hUb : Bornology.IsBounded U.target := by + rw [hUt] + exact Metric.isBounded_Ioo u v + have hesc : ¬ closure A ⊆ Ioo u v := by + rw [← hUt] + exact not_closure_image_subset_target U V hUb hV hVU hx + exact eq_end_segment_of_closure_not_subset_Ioo (hUt ▸ hAsub) hAo hAc hesc + +end Outer diff --git a/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean b/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean new file mode 100644 index 0000000000..577b5e6d3c --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean @@ -0,0 +1,48 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib + +lemma partial_homeo_connected {X : Type*} {Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] + (h : OpenPartialHomeomorph X Y) (conn : IsConnected h.source) : (IsConnected h.target) := by + have ht : h.target = h.toFun '' h.source + exact Eq.symm (PartialEquiv.image_source_eq_target h.toPartialEquiv) + rw [ht] + apply IsConnected.image conn ↑h.toPartialEquiv h.continuousOn_toFun + +lemma partial_homeo_connected' {X : Type*} {Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] + (h : OpenPartialHomeomorph X Y) (conn : IsConnected h.target) : (IsConnected h.source) := by + have hst : h.symm.source = h.target := rfl + have hts : h.symm.target = h.source := rfl + have conn' : IsConnected h.symm.source := by + rw [hst] + exact conn + have h'' := partial_homeo_connected h.symm conn' + rw [←hts] + exact h'' + +lemma partial_homeo_source_connected_iff_target_connected {X : Type*} {Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] + (h : OpenPartialHomeomorph X Y) : IsConnected h.source ↔ IsConnected h.target := by + constructor + · exact fun a => partial_homeo_connected h a + · exact fun a => partial_homeo_connected' h a + +/-- For `t ⊆ φ.target`, the target of `φ` restricted to `φ.symm '' t` is exactly `t`; +this computes `(φ.restrOpen (φ.symm '' t) _).target`. -/ +lemma restrOpen_symm_image_target {X : Type*} {Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] + (φ : OpenPartialHomeomorph X Y) {t : Set Y} (ht : t ⊆ φ.target) : + φ.target ∩ ↑φ.symm ⁻¹' (↑φ.symm '' t) = t := by + ext z + apply Iff.intro + · intro hz + simp only [Set.mem_inter_iff, Set.mem_preimage, Set.mem_image] at hz + rcases hz with ⟨hz1, ⟨z', hz2, hz3⟩⟩ + have inj : Set.InjOn φ.symm φ.target := OpenPartialHomeomorph.injOn φ.symm + have : z' = z := inj (ht hz2) hz1 hz3 + rw [←this] + exact hz2 + · intro hz + simp only [Set.mem_inter_iff, Set.mem_preimage, Set.mem_image] + exact ⟨ht hz, z, hz, rfl⟩ diff --git a/LeanPool/OneManifold/OneMfld/RealIntervals.lean b/LeanPool/OneManifold/OneMfld/RealIntervals.lean new file mode 100644 index 0000000000..2bd1356cf8 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/RealIntervals.lean @@ -0,0 +1,486 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib + +open Set + +namespace RealIntervals + +-- Use the order topology on ℝ throughout +lemma ordconn_of_connected {X : Set ℝ} (conn : IsConnected X) + (a : ℝ) (aX : a ∈ X) (b : ℝ) (bX : b ∈ X) : Icc a b ⊆ X := by + have : OrdConnected X := + IsPreconnected.ordConnected (IsConnected.isPreconnected conn) + exact Set.Icc_subset X aX bX + +-- Shouldn't this already be in mathlib? +lemma Real.exists_isGLB {S : Set ℝ} (hne : S.Nonempty) (hbdd : BddBelow S) + : ∃ x, IsGLB S x := by + use sInf S + rw [Real.sInf_def, ← isLUB_neg, Real.sSup_def, dif_pos] + . apply Classical.choose_spec + exact ⟨nonempty_neg.mpr hne, BddBelow.neg hbdd⟩ + +-- classifying real intervals + +-- Note: Much of what's below already exists in mathlib: +-- Use IsPreconnected.mem_intervals +-- and Real.instConditionallyCompleteLinearOrderReal + +lemma connected_bddAbove_subset_contains_Ioo {X : Set ℝ} {supX : ℝ} {x : ℝ} + (conn : IsConnected X) (h_supX : IsLUB X supX) (xX : x ∈ X) + : Ioo x supX ⊆ X := by + intro y ⟨x_lt_y, y_lt_supX⟩ + by_cases h: ∃ z ∈ X, y ≤ z + . rcases h with ⟨z, zX, y_le_z⟩ + have : Icc x z ⊆ X := ordconn_of_connected conn x xX z zX + exact this ⟨LT.lt.le x_lt_y, y_le_z⟩ + . push Not at h + have : y ∈ upperBounds X := fun z ↦ fun zX ↦ LT.lt.le (h z zX) + have : supX ≤ y := h_supX.2 this + linarith + +lemma connected_bddBelow_subset_contains_Ioo {X : Set ℝ} {infX : ℝ} {x : ℝ} + (conn : IsConnected X) (h_infX : IsGLB X infX) (xX : x ∈ X) + : Ioo infX x ⊆ X := by + intro y ⟨infX_lt_y, y_lt_x⟩ + by_cases h: ∃ z ∈ X, z ≤ y + . rcases h with ⟨z, zX, z_le_y⟩ + have : Icc z x ⊆ X := ordconn_of_connected conn z zX x xX + exact this ⟨z_le_y, LT.lt.le y_lt_x⟩ + . push Not at h + have : y ∈ lowerBounds X := fun z ↦ fun zX ↦ LT.lt.le (h z zX) + have : y ≤ infX := h_infX.2 this + linarith + +lemma connected_bdd_subset_contains_Ioo + {X : Set ℝ} {infX supX : ℝ} + (conn : IsConnected X) (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) + : Ioo infX supX ⊆ X := by + let ⟨z, zX⟩ := IsConnected.nonempty conn + have h₁ : Ioo infX z ⊆ X := connected_bddBelow_subset_contains_Ioo conn h_infX zX + have h₂ : Ioo z supX ⊆ X := connected_bddAbove_subset_contains_Ioo conn h_supX zX + have h₃ : Ioo infX supX ⊆ Ioo infX z ∪ {z} ∪ Ioo z supX := by + intro x ⟨infX_lt_x, x_lt_supX⟩ + rcases lt_trichotomy x z with (x_lt_z | x_eq_z | z_lt_z) + . left; left + exact ⟨infX_lt_x, x_lt_z⟩ + . left; right + rw [mem_singleton_iff, x_eq_z] + . right + exact ⟨z_lt_z, x_lt_supX⟩ + have h₄ : Ioo infX z ∪ {z} ∪ Ioo z supX ⊆ X := by + rintro x ((_ | x_eq_z) | _) + . apply h₁; assumption + . rw [mem_singleton_iff] at x_eq_z + rw [x_eq_z] + exact zX + . apply h₂; assumption + intro x x_Ioo + exact h₄ (h₃ x_Ioo) + +lemma bdd_subset_Icc + {X : Set ℝ} {infX supX : ℝ} + (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) + : X ⊆ Icc infX supX := by + intro x xX + exact ⟨h_infX.1 xX, h_supX.1 xX⟩ + +lemma x_lt_excluded_supX {x supX : ℝ} (xX: x ∈ X) + (h_supX: IsLUB X supX) (supX_X : supX ∉ X) : x < supX := by + have : x ≠ supX := by + intro x_eq_supX + rw [← x_eq_supX] at supX_X + contradiction + exact Ne.lt_of_le this (h_supX.1 xX) + +lemma excluded_infX_lt_x {x infX : ℝ} (xX: x ∈ X) + (h_infX: IsGLB X infX) (infX_X : infX ∉ X) : infX < x := by + have : infX ≠ x := by + intro x_eq_supX + rw [x_eq_supX] at infX_X + contradiction + exact Ne.lt_of_le this (h_infX.1 xX) + +lemma Ico_Ioo_with_endpoint {a b : ℝ} (hab : a < b) + : Ico a b = (Ioo a b) ∪ {a} := by + apply Subset.antisymm + . intro x ⟨x_le_a, x_lt_b⟩ + by_cases xa : x = a + . right; exact xa + . left; exact ⟨Ne.lt_of_le' xa x_le_a, x_lt_b⟩ + . rintro x (x_Ioo | x_a) + . exact ⟨LT.lt.le x_Ioo.1, x_Ioo.2⟩ + . exact ⟨Eq.ge x_a, Eq.trans_lt x_a hab⟩ + +lemma Ioc_Ioo_with_endpoint {a b : ℝ} (hab : a < b) + : Ioc a b = (Ioo a b) ∪ {b} := by + apply Subset.antisymm + . intro x ⟨a_lt_x, x_le_b⟩ + by_cases xb : x = b + . right; exact xb + have : x < b := Ne.lt_of_le xb x_le_b + left; exact ⟨a_lt_x, this⟩ + . rintro x (x_Ioo | x_b) + . exact ⟨x_Ioo.1, LT.lt.le x_Ioo.2⟩ + . exact ⟨(by rw [x_b]; exact hab), Eq.le x_b⟩ + +lemma characterize_Ioo {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} + (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) + (infX_X : infX ∉ X) (supX_X : supX ∉ X) + : X = Ioo infX supX := by + apply Subset.antisymm + . intro x xX + exact ⟨excluded_infX_lt_x xX h_infX infX_X, + x_lt_excluded_supX xX h_supX supX_X⟩ + . exact connected_bdd_subset_contains_Ioo conn h_infX h_supX + +lemma characterize_Ioc {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} + (inf_lt_sup : infX < supX) + (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) + (infX_X : infX ∉ X) (supX_X : supX ∈ X) + : X = Ioc infX supX := by + apply Subset.antisymm + . intro x xX + exact ⟨excluded_infX_lt_x xX h_infX infX_X, + h_supX.1 xX⟩ + . rw [Ioc_Ioo_with_endpoint inf_lt_sup, union_subset_iff] + exact ⟨connected_bdd_subset_contains_Ioo conn h_infX h_supX, + singleton_subset_iff.mpr supX_X⟩ + +lemma characterize_Ico {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} + (inf_lt_sup : infX < supX) + (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) + (infX_X : infX ∈ X) (supX_X : supX ∉ X) + : X = Ico infX supX := by + apply Subset.antisymm + . intro x xX + exact ⟨h_infX.1 xX, + x_lt_excluded_supX xX h_supX supX_X⟩ + . rw [Ico_Ioo_with_endpoint inf_lt_sup, union_subset_iff] + exact ⟨connected_bdd_subset_contains_Ioo conn h_infX h_supX, + singleton_subset_iff.mpr infX_X⟩ + +lemma characterize_Icc {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} + (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) + (infX_X : infX ∈ X) (supX_X : supX ∈ X) + : X = Icc infX supX := by + apply Subset.antisymm + . exact bdd_subset_Icc h_infX h_supX + . exact (ordconn_of_connected conn) infX infX_X supX supX_X + +lemma characterize_singleton {X : Set ℝ} {a : ℝ} + (h_infX : IsGLB X a) (h_supX : IsLUB X a) + : (X = {a}) := by + apply Subset.antisymm + . apply subset_trans (bdd_subset_Icc h_infX h_supX) + exact Set.Icc_subset {a} rfl rfl + . rw [singleton_subset_iff] + rcases IsLUB.nonempty h_supX with ⟨x, xX⟩ + have : a = x := LE.le.antisymm (h_infX.1 xX) (h_supX.1 xX) + exact mem_of_eq_of_mem (id this) xX + +inductive BoundedIntervalKind | IooKind | IocKind | IcoKind | IccKind + +open BoundedIntervalKind + +structure BoundedInterval where + left_endpoint : ℝ + right_endpoint : ℝ + left_lt_right : left_endpoint < right_endpoint + kind : BoundedIntervalKind + +@[simp] +def BoundedInterval_as_set : BoundedInterval → Set ℝ + | ⟨a, b, _, IooKind⟩ => Ioo a b + | ⟨a, b, _, IocKind⟩ => Ioc a b + | ⟨a, b, _, IcoKind⟩ => Ico a b + | ⟨a, b, _, IccKind⟩ => Icc a b + +def isBoundedInterval (X : Set ℝ) := + ∃ I : BoundedInterval, X = BoundedInterval_as_set I + +lemma isBoundedInterval_Ioo (a b : ℝ) (lt : a < b) : isBoundedInterval (Ioo a b) := by + use ⟨a, b, lt, IooKind⟩; simp only [BoundedInterval_as_set] +lemma isBoundedInterval_Ioc (a b : ℝ) (lt : a < b) : isBoundedInterval (Ioc a b) := by + use ⟨a, b, lt, IocKind⟩; simp only [BoundedInterval_as_set] +lemma isBoundedInterval_Ico (a b : ℝ) (lt : a < b) : isBoundedInterval (Ico a b) := by + use ⟨a, b, lt, IcoKind⟩; simp only [BoundedInterval_as_set] +lemma isBoundedInterval_Icc (a b : ℝ) (lt : a < b) : isBoundedInterval (Icc a b) := by + use ⟨a, b, lt, IccKind⟩; simp only [BoundedInterval_as_set] + +def isSingleton (X : Set ℝ) := + ∃ a : ℝ, X = {a} + +lemma classify_connected_reals_with_GLB_lt_LUB + {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} + (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) (lt : infX < supX) + : isBoundedInterval X := by + by_cases infX_X : infX ∈ X + . by_cases supX_X : supX ∈ X + . use ⟨infX, supX, lt, IccKind⟩ + exact characterize_Icc conn h_infX h_supX infX_X supX_X + . use ⟨infX, supX, lt, IcoKind⟩ + exact characterize_Ico conn lt h_infX h_supX infX_X supX_X + . by_cases supX_X : supX ∈ X + . use ⟨infX, supX, lt, IocKind⟩ + exact characterize_Ioc conn lt h_infX h_supX infX_X supX_X + . use ⟨infX, supX, lt, IooKind⟩ + exact characterize_Ioo conn h_infX h_supX infX_X supX_X + +theorem classify_connected_bounded_reals + {X : Set ℝ} (conn : IsConnected X) (above : BddAbove X) (below : BddBelow X) + : isSingleton X ∨ isBoundedInterval X := by + have nonempty := IsConnected.nonempty conn + have ⟨supX, h_supX⟩ := Real.exists_isLUB nonempty above + have ⟨infX, h_infX⟩ := Real.exists_isGLB nonempty below + by_cases inf_eq_sup : infX = supX + . left; rw [isSingleton]; use infX + rw [← inf_eq_sup] at h_supX + apply characterize_singleton h_infX h_supX + . right + have : infX ≤ supX := isGLB_le_isLUB h_infX h_supX nonempty + have : infX < supX := Ne.lt_of_le inf_eq_sup this + exact classify_connected_reals_with_GLB_lt_LUB conn h_infX h_supX this + +theorem classify_connected_bounded_reals_nonempty_interior + {X : Set ℝ} (conn : IsConnected X) (above : BddAbove X) (below : BddBelow X) + (h : (interior X) ≠ ∅) + : isBoundedInterval X := by + rcases classify_connected_bounded_reals conn above below with ⟨a, ha⟩ | bdd + . rw [ha, interior_singleton] at h + exact (h rfl).elim + . exact bdd + +-- Some lemmas about bounded intervals in ℝ + +lemma isConnected_BoundedInterval (I : BoundedInterval) + : IsConnected (BoundedInterval_as_set I) := by + rw [BoundedInterval_as_set.eq_def] + have ⟨a, b, lt, kind⟩ := I + match kind with + | IooKind => exact isConnected_Ioo lt + | IocKind => exact isConnected_Ioc lt + | IcoKind => exact isConnected_Ico lt + | IccKind => exact isConnected_Icc (LT.lt.le lt) + +lemma BoundedInterval_subset_Icc (I : BoundedInterval) + : BoundedInterval_as_set I ⊆ Icc I.left_endpoint I.right_endpoint := by + have ⟨a, b, lt, kind⟩ := I + match kind with + | IooKind => exact Ioo_subset_Icc_self + | IocKind => exact Ioc_subset_Icc_self + | IcoKind => exact Ico_subset_Icc_self + | IccKind => exact Eq.subset rfl + +lemma BoundedInterval_contains_Ioo (I : BoundedInterval) + : Ioo I.left_endpoint I.right_endpoint ⊆ BoundedInterval_as_set I := by + have ⟨a, b, lt, kind⟩ := I + match kind with + | IooKind => exact Eq.subset rfl + | IocKind => exact Ioo_subset_Ioc_self + | IcoKind => exact Ioo_subset_Ico_self + | IccKind => exact Ioo_subset_Icc_self + +lemma closure_BoundedInterval (I : BoundedInterval) : closure (BoundedInterval_as_set I) = Icc I.left_endpoint I.right_endpoint := by + apply Subset.antisymm + . calc closure (BoundedInterval_as_set I) + ⊆ closure (Icc I.left_endpoint I.right_endpoint) + := closure_mono (BoundedInterval_subset_Icc I) + _ = Icc I.left_endpoint I.right_endpoint + := IsClosed.closure_eq isClosed_Icc + . calc Icc I.left_endpoint I.right_endpoint + = closure (Ioo I.left_endpoint I.right_endpoint) + := (closure_Ioo (ne_of_lt I.left_lt_right)).symm + _ ⊆ closure (BoundedInterval_as_set I) + := closure_mono (BoundedInterval_contains_Ioo I) + +lemma isBoundedBelow_BoundedInterval (I : BoundedInterval) + : BddBelow (BoundedInterval_as_set I) := + BddBelow.mono (BoundedInterval_subset_Icc I) bddBelow_Icc + +lemma isBoundedAbove_BoundedInterval (I : BoundedInterval) + : BddAbove (BoundedInterval_as_set I) := + BddAbove.mono (BoundedInterval_subset_Icc I) bddAbove_Icc + +@[simp] +lemma interior_BoundedInterval (I : BoundedInterval) + : interior (BoundedInterval_as_set I) = Ioo I.left_endpoint I.right_endpoint := by + rw [BoundedInterval_as_set.eq_def] + have ⟨a, b, lt, kind⟩ := I + match kind with + | IooKind => dsimp; exact interior_Ioo + | IocKind => dsimp; exact interior_Ioc + | IcoKind => dsimp; exact interior_Ico + | IccKind => dsimp; exact interior_Icc + +-- Shouldn't this already be in mathlib? +@[simp] +lemma Icc_diff_Ioo {a b : ℝ} (lt : a < b) : (Icc a b) \ (Ioo a b) = {a, b} := by + apply Subset.antisymm + . rw [← Icc_sdiff_both] + exact sdiff_sdiff_le + . rintro x (xleft | xright) + . rw [mem_sdiff, mem_Icc, mem_Ioo, not_and] + exact ⟨⟨by linarith, by linarith⟩, (by intro _; linarith)⟩ + . simp only [mem_singleton_iff] at xright + rw [xright] + simp only [mem_sdiff, mem_Icc, le_refl, and_true, mem_Ioo, lt_self_iff_false, and_false, + not_false_eq_true] + exact LT.lt.le lt + +@[simp] +lemma frontier_BoundedInterval (I : BoundedInterval) + : frontier (BoundedInterval_as_set I) = {I.left_endpoint, I.right_endpoint} := by + rw [frontier, closure_BoundedInterval I, interior_BoundedInterval I] + exact Icc_diff_Ioo I.left_lt_right + +lemma pair_has_other {a b c : ℝ} (ne : a ≠ b) (h : c ∈ ({a, b} : Set ℝ)) + : ∃ (d : ℝ), d ∈ ({a, b} : Set ℝ) ∧ d ≠ c := by + simp only [mem_insert_iff, mem_singleton_iff, ne_eq, exists_eq_or_imp, exists_eq_left] + simp only [mem_insert_iff, mem_singleton_iff] at h + rcases h with ca | cb + . rw [← ca] at ne; right; exact ne.symm + . rw [← cb] at ne; left; exact ne + +theorem other_endpoint + {X : Set ℝ} (int : (interior X) ≠ ∅) + (conn : IsConnected X) (above : BddAbove X) (below : BddBelow X) + (a : ℝ) (ha: a ∈ frontier X) : ∃b : ℝ, b ∈ frontier X ∧ b ≠ a:= by + have ⟨I, XI⟩ := classify_connected_bounded_reals_nonempty_interior conn above below int + rw [XI, frontier_BoundedInterval] + rw [XI, frontier_BoundedInterval] at ha + have : I.left_endpoint ≠ I.right_endpoint := by + exact ne_of_lt I.left_lt_right + exact pair_has_other (ne_of_lt I.left_lt_right) ha + +-- Continue to classify all connected sets in ℝ +lemma characterize_univ {X : Set ℝ} (conn : IsConnected X) + (below : ¬ BddBelow X) (above : ¬ BddAbove X) + : X = univ := by + rw [bddBelow_def] at below; push Not at below + rw [bddAbove_def] at above; push Not at above + ext x + simp only [mem_univ, iff_true] + have ⟨B, BX, Bbig⟩ := above x + have ⟨A, AX, Asmall⟩ := below x + have : Icc A B ⊆ X := (ordconn_of_connected conn) A AX B BX + exact this ⟨LT.lt.le Asmall, LT.lt.le Bbig⟩ + +lemma characterize_Ioi {X : Set ℝ} (conn : IsConnected X) + {infX : ℝ} (h_infX : IsGLB X infX) (infX_X : infX ∉ X) + (above : ¬ BddAbove X) : X = Ioi infX := by + rw [bddAbove_def] at above; push Not at above + apply Subset.antisymm + . intro x xX + exact excluded_infX_lt_x xX h_infX infX_X + . intro x infX_lt_x + rw [mem_Ioi] at infX_lt_x + let ⟨B, BX, Bbig⟩ := above x + have : Ioo infX B ⊆ X := + connected_bddBelow_subset_contains_Ioo conn h_infX BX + exact this ⟨infX_lt_x, Bbig⟩ + +lemma characterize_Ici {X : Set ℝ} (conn : IsConnected X) + {infX : ℝ} (h_infX : IsGLB X infX) (infX_X : infX ∈ X) + (above : ¬ BddAbove X) : X = Ici infX := by + rw [bddAbove_def] at above; push Not at above + apply Set.Subset.antisymm + . intro x xX + exact h_infX.1 xX + . intro x infX_le_x + have ⟨B, BX, Bbig⟩ := above x + have : Set.Icc infX B ⊆ X := (ordconn_of_connected conn) infX infX_X B BX + exact this ⟨infX_le_x, LT.lt.le Bbig⟩ + +lemma classify_Ixi {X : Set ℝ} (conn : IsConnected X) + (below : BddBelow X) (above : ¬ BddAbove X) + : ∃ a : ℝ, (X = Ioi a ∨ X = Ici a) := by + have ⟨infX, h_infX⟩ := Real.exists_isGLB (IsConnected.nonempty conn) below + use infX + by_cases infX_X : infX ∈ X + . right; exact characterize_Ici conn h_infX infX_X above + . left; exact characterize_Ioi conn h_infX infX_X above + +lemma characterize_Iio {X : Set ℝ} (conn : IsConnected X) + {supX : ℝ} (h_supX : IsLUB X supX) (supX_X : supX ∉ X) + (below : ¬ BddBelow X) : X = Iio supX := by + rw [bddBelow_def] at below; push Not at below + apply Set.Subset.antisymm + . intro x xX + exact x_lt_excluded_supX xX h_supX supX_X + . intro x x_lt_supX + rw [Set.mem_Iio] at x_lt_supX + let ⟨A, AX, Asmall⟩ := below x + have : Set.Ioo A supX ⊆ X := + connected_bddAbove_subset_contains_Ioo conn h_supX AX + exact this ⟨Asmall, x_lt_supX⟩ + +lemma characterize_Iic {X : Set ℝ} (conn : IsConnected X) + {supX : ℝ} (h_supX : IsLUB X supX) (supX_X : supX ∈ X) + (below : ¬ BddBelow X) : X = Iic supX := by + rw [bddBelow_def] at below; push Not at below + apply Set.Subset.antisymm + . intro x xX + exact h_supX.1 xX + . intro x x_le_supX + let ⟨A, AX, Asmall⟩ := below x + have : Set.Icc A supX ⊆ X := (ordconn_of_connected conn) A AX supX supX_X + exact this ⟨LT.lt.le Asmall, x_le_supX⟩ + +lemma classify_Iix {X : Set ℝ} (conn : IsConnected X) + (below : ¬ BddBelow X) (above : BddAbove X) + : ∃ a : ℝ, (X = Iio a ∨ X = Iic a) := by + have ⟨supX, h_supX⟩ := Real.exists_isLUB (IsConnected.nonempty conn) above + use supX + by_cases supX_X : supX ∈ X + . right; exact characterize_Iic conn h_supX supX_X below + . left; exact characterize_Iio conn h_supX supX_X below + +-- Give names to the cases +inductive ConnectedRealClassification + | of_univ : ConnectedRealClassification + | of_Iio : ℝ → ConnectedRealClassification + | of_Iic : ℝ → ConnectedRealClassification + | of_Ioi : ℝ → ConnectedRealClassification + | of_Ici : ℝ → ConnectedRealClassification + | of_singleton : ℝ → ConnectedRealClassification + | of_bounded_interval : BoundedInterval → ConnectedRealClassification + +open ConnectedRealClassification + +def ConnectedRealClassification_as_set : ConnectedRealClassification → Set ℝ + | of_univ => univ + | of_Iio a => Iio a + | of_Iic a => Iic a + | of_Ioi a => Ioi a + | of_Ici a => Ici a + | of_singleton a => {a} + | of_bounded_interval I => BoundedInterval_as_set I + +def isConnectedRealClassification (X : Set ℝ) := + ∃ I : ConnectedRealClassification, X = ConnectedRealClassification_as_set I + +theorem classify_connected_reals {X : Set ℝ} (conn : IsConnected X) + : isConnectedRealClassification X := by + by_cases below : BddBelow X + . by_cases above : BddAbove X + . rcases classify_connected_bounded_reals conn above below with sing | bdd + . let ⟨a, ha⟩ := sing + use of_singleton a; exact ha + . let ⟨I, hI⟩ := bdd + use of_bounded_interval I; exact hI + . rcases classify_Ixi conn below above with ⟨a, hIoi | hIci⟩ + . use of_Ioi a; exact hIoi + . use of_Ici a; exact hIci + . by_cases above : BddAbove X + . rcases classify_Iix conn below above with ⟨a, hIio | hIic⟩ + . use of_Iio a + exact hIio + . use of_Iic a + exact hIic + . use of_univ + exact characterize_univ conn below above diff --git a/LeanPool/OneManifold/OneMfld/TransitionMono.lean b/LeanPool/OneManifold/OneMfld/TransitionMono.lean new file mode 100644 index 0000000000..905fad91e8 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/TransitionMono.lean @@ -0,0 +1,49 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib + +/-! # Monotonicity of transition maps + +A transition map between interval charts, restricted to (the image of) a component of the +overlap, is continuous and injective on an open interval of `ℝ≥0`, hence strictly +monotone or strictly antitone; and a strictly monotone map of one open interval onto +another sends ends to ends. +-/ + +open Set Filter Topology + +/-- A continuous injective function on an open interval of `ℝ≥0` is strictly monotone or +strictly antitone there. -/ +theorem strictMonoOn_or_strictAntiOn_of_injOn_Ioo {p v : NNReal} + {f : NNReal → NNReal} (hc : ContinuousOn f (Ioo p v)) (hi : InjOn f (Ioo p v)) : + StrictMonoOn f (Ioo p v) ∨ StrictAntiOn f (Ioo p v) := by + by_cases hpv : p < v + · exact ContinuousOn.strictMonoOn_of_injOn_Ioo hpv hc hi + · left + intro x hx + simp [Ioo_eq_empty hpv] at hx + +/-- A strictly monotone map of `Ioo p v` onto `Ioo q w` tends to `w` at the top end. -/ +theorem tendsto_top_of_strictMonoOn_image {p v q w : NNReal} (hpv : p < v) + {f : NNReal → NNReal} (hm : StrictMonoOn f (Ioo p v)) + (himg : f '' Ioo p v = Ioo q w) : + Tendsto f (𝓝[<] v) (𝓝 w) := by + have hne : (Ioo p v).Nonempty := nonempty_Ioo.2 hpv + have hqw : q < w := nonempty_Ioo.1 (himg ▸ hne.image f) + have hbdd : BddAbove (f '' Ioo p v) := himg ▸ bddAbove_Ioo + have h := MonotoneOn.tendsto_nhdsWithin_Ioo_left hne hm.monotoneOn hbdd + rwa [himg, csSup_Ioo hqw] at h + +/-- A strictly monotone map of `Ioo p v` onto `Ioo q w` tends to `q` at the bottom end. -/ +theorem tendsto_bot_of_strictMonoOn_image {p v q w : NNReal} (hpv : p < v) + {f : NNReal → NNReal} (hm : StrictMonoOn f (Ioo p v)) + (himg : f '' Ioo p v = Ioo q w) : + Tendsto f (𝓝[>] p) (𝓝 q) := by + have hne : (Ioo p v).Nonempty := nonempty_Ioo.2 hpv + have hqw : q < w := nonempty_Ioo.1 (himg ▸ hne.image f) + have hbdd : BddBelow (f '' Ioo p v) := himg ▸ bddBelow_Ioo + have h := MonotoneOn.tendsto_nhdsWithin_Ioo_right hne hm.monotoneOn hbdd + rwa [himg, csInf_Ioo hqw] at h diff --git a/LeanPool/OneManifold/OneMfld/TwoComponents.lean b/LeanPool/OneManifold/OneMfld/TwoComponents.lean new file mode 100644 index 0000000000..45c0a6ea49 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/TwoComponents.lean @@ -0,0 +1,443 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib +import LeanPool.OneManifold.OneMfld.Outer +import LeanPool.OneManifold.OneMfld.TransitionMono +import LeanPool.OneManifold.OneMfld.GlueCore + +/-! # The two-component structure of a disconnected overlap + +When two interior charts overlap disconnectedly, the overlap has exactly two connected +components, one at each end of each chart (outer-overlap lemma + two end-segments at the +same end must intersect). We also generalize the end-matching theorems of `GlueCore` from +the full overlap to a single component `W`: the extra hypothesis is that the relevant +interior endpoint is not in the image of the *full* overlap. +-/ + +open Set Filter Topology + +/-- A strictly antitone map of `Ioo p v` onto `Ioo q w` tends to `w` at the bottom end. -/ +theorem tendsto_bot_of_strictAntiOn_image {p v q w : NNReal} (hpv : p < v) + {f : NNReal → NNReal} (hm : StrictAntiOn f (Ioo p v)) + (himg : f '' Ioo p v = Ioo q w) : + Tendsto f (𝓝[>] p) (𝓝 w) := by + have hne : (Ioo p v).Nonempty := nonempty_Ioo.2 hpv + have hqw : q < w := nonempty_Ioo.1 (himg ▸ hne.image f) + have hbdd : BddAbove (f '' Ioo p v) := himg ▸ bddAbove_Ioo + have h := AntitoneOn.tendsto_nhdsWithin_Ioo_right hne hm.antitoneOn hbdd + rwa [himg, csSup_Ioo hqw] at h + +variable {M : Type*} [TopologicalSpace M] + +/-- Component version of `overlap_mono`: on a subset `W` of the overlap whose images are +`Ioo p r` and `Ioo q w`, with the `r`-end interior to `a.target`, the `q`-end interior to +`b.target`, and `r` not in the image of the full overlap, the transition is increasing. -/ +theorem overlap_mono_on [T2Space M] (a b : OpenPartialHomeomorph M NNReal) + {W : Set M} (hW : W ⊆ a.source ∩ b.source) + {p r q w : NNReal} + (ha : a '' W = Ioo p r) + (hb : b '' W = Ioo q w) + (hr : r ∈ a.target) (hq : q ∈ b.target) + (hrS : r ∉ a '' (a.source ∩ b.source)) : + ∀ x ∈ W, ∀ y ∈ W, a x < a y → b x < b y := by + have hWa : W ⊆ a.source := hW.trans inter_subset_left + have hWb : W ⊆ b.source := hW.trans inter_subset_right + have hacoord : ∀ x ∈ W, a x ∈ Ioo p r := fun x hx => ha ▸ mem_image_of_mem a hx + by_cases hpr : p < r + swap + · intro x hx y hy hxy + exact absurd ((hacoord x hx).1.trans (hacoord x hx).2) hpr + set τ : NNReal → NNReal := fun t => b (a.symm t) with hτdef + have hsymm : ∀ t ∈ Ioo p r, a.symm t ∈ W ∧ a (a.symm t) = t := by + intro t ht + rw [← ha] at ht + obtain ⟨x, hxW, rfl⟩ := ht + rw [a.left_inv (hWa hxW)] + exact ⟨hxW, rfl⟩ + have hkey : ∀ x ∈ W, τ (a x) = b x := by + intro x hx + simp only [hτdef] + rw [a.left_inv (hWa hx)] + have hτmaps : ∀ t ∈ Ioo p r, τ t ∈ Ioo q w := by + intro t ht + have hb' : b (a.symm t) ∈ b '' W := mem_image_of_mem b (hsymm t ht).1 + exact hb ▸ hb' + have hIoo_target : Ioo p r ⊆ a.target := by + rw [← ha] + rintro y ⟨z, hz, rfl⟩ + exact a.map_source (hWa hz) + have hqw_target : Ioo q w ⊆ b.target := by + rw [← hb] + rintro y ⟨z, hz, rfl⟩ + exact b.map_source (hWb hz) + have hcont : ContinuousOn τ (Ioo p r) := + b.continuousOn.comp (a.symm.continuousOn.mono hIoo_target) + (fun t ht => hWb (hsymm t ht).1) + have hinj : InjOn τ (Ioo p r) := by + intro t1 ht1 t2 ht2 heq + obtain ⟨h1W, h1e⟩ := hsymm t1 ht1 + obtain ⟨h2W, h2e⟩ := hsymm t2 ht2 + have h12 : a.symm t1 = a.symm t2 := b.injOn (hWb h1W) (hWb h2W) heq + rw [← h1e, ← h2e, h12] + rcases strictMonoOn_or_strictAntiOn_of_injOn_Ioo hcont hinj with hmono | hanti + · intro x hx y hy hxy + have h := hmono (hacoord x hx) (hacoord y hy) hxy + rwa [hkey x hx, hkey y hy] at h + · exfalso + have himg : τ '' Ioo p r = Ioo q w := by + apply subset_antisymm + · rintro _ ⟨t, ht, rfl⟩ + exact hτmaps t ht + · intro y hy + rw [← hb] at hy + obtain ⟨x, hxW, rfl⟩ := hy + exact ⟨a x, hacoord x hxW, hkey x hxW⟩ + have hτlim : Tendsto τ (𝓝[<] r) (𝓝 q) := + tendsto_top_of_strictAntiOn_image hpr hanti himg + have hF : 𝓝[Ioo p r] r = 𝓝[<] r := nhdsWithin_Ioo_eq_nhdsLT hpr + have hFne : (𝓝[Ioo p r] r).NeBot := by + apply mem_closure_iff_nhdsWithin_neBot.mp + rw [closure_Ioo hpr.ne] + exact ⟨hpr.le, le_refl r⟩ + have hlim1 : Tendsto a.symm (𝓝[Ioo p r] r) (𝓝 (a.symm r)) := + (a.symm.continuousOn r hr).mono hIoo_target + have hτq : Tendsto τ (𝓝[Ioo p r] r) (𝓝 q) := hF ▸ hτlim + have hτq' : Tendsto τ (𝓝[Ioo p r] r) (𝓝[b.target] q) := by + rw [tendsto_nhdsWithin_iff] + refine ⟨hτq, ?_⟩ + filter_upwards [self_mem_nhdsWithin] with t ht + exact hqw_target (hτmaps t ht) + have hlim2 : Tendsto (b.symm ∘ τ) (𝓝[Ioo p r] r) (𝓝 (b.symm q)) := + Tendsto.comp (b.symm.continuousOn q hq) hτq' + have hlim2' : Tendsto a.symm (𝓝[Ioo p r] r) (𝓝 (b.symm q)) := by + apply Tendsto.congr' _ hlim2 + filter_upwards [self_mem_nhdsWithin] with t ht + show b.symm (τ t) = a.symm t + simp only [hτdef] + exact b.left_inv (hWb (hsymm t ht).1) + have hz : a.symm r = b.symm q := tendsto_nhds_unique' hFne hlim1 hlim2' + have hzS : a.symm r ∈ a.source ∩ b.source := by + refine ⟨a.map_target hr, ?_⟩ + rw [hz] + exact b.map_target hq + exact hrS ⟨a.symm r, hzS, a.right_inv hr⟩ + +/-- Mirror component version: with the `p`-end interior to `a.target`, the `w`-end +interior to `b.target`, and `p` not in the image of the full overlap, the transition is +again increasing. -/ +theorem overlap_mono_on' [T2Space M] (a b : OpenPartialHomeomorph M NNReal) + {W : Set M} (hW : W ⊆ a.source ∩ b.source) + {p r q w : NNReal} + (ha : a '' W = Ioo p r) + (hb : b '' W = Ioo q w) + (hp : p ∈ a.target) (hw : w ∈ b.target) + (hpS : p ∉ a '' (a.source ∩ b.source)) : + ∀ x ∈ W, ∀ y ∈ W, a x < a y → b x < b y := by + have hWa : W ⊆ a.source := hW.trans inter_subset_left + have hWb : W ⊆ b.source := hW.trans inter_subset_right + have hacoord : ∀ x ∈ W, a x ∈ Ioo p r := fun x hx => ha ▸ mem_image_of_mem a hx + by_cases hpr : p < r + swap + · intro x hx y hy hxy + exact absurd ((hacoord x hx).1.trans (hacoord x hx).2) hpr + set τ : NNReal → NNReal := fun t => b (a.symm t) with hτdef + have hsymm : ∀ t ∈ Ioo p r, a.symm t ∈ W ∧ a (a.symm t) = t := by + intro t ht + rw [← ha] at ht + obtain ⟨x, hxW, rfl⟩ := ht + rw [a.left_inv (hWa hxW)] + exact ⟨hxW, rfl⟩ + have hkey : ∀ x ∈ W, τ (a x) = b x := by + intro x hx + simp only [hτdef] + rw [a.left_inv (hWa hx)] + have hτmaps : ∀ t ∈ Ioo p r, τ t ∈ Ioo q w := by + intro t ht + have hb' : b (a.symm t) ∈ b '' W := mem_image_of_mem b (hsymm t ht).1 + exact hb ▸ hb' + have hIoo_target : Ioo p r ⊆ a.target := by + rw [← ha] + rintro y ⟨z, hz, rfl⟩ + exact a.map_source (hWa hz) + have hqw_target : Ioo q w ⊆ b.target := by + rw [← hb] + rintro y ⟨z, hz, rfl⟩ + exact b.map_source (hWb hz) + have hcont : ContinuousOn τ (Ioo p r) := + b.continuousOn.comp (a.symm.continuousOn.mono hIoo_target) + (fun t ht => hWb (hsymm t ht).1) + have hinj : InjOn τ (Ioo p r) := by + intro t1 ht1 t2 ht2 heq + obtain ⟨h1W, h1e⟩ := hsymm t1 ht1 + obtain ⟨h2W, h2e⟩ := hsymm t2 ht2 + have h12 : a.symm t1 = a.symm t2 := b.injOn (hWb h1W) (hWb h2W) heq + rw [← h1e, ← h2e, h12] + rcases strictMonoOn_or_strictAntiOn_of_injOn_Ioo hcont hinj with hmono | hanti + · intro x hx y hy hxy + have h := hmono (hacoord x hx) (hacoord y hy) hxy + rwa [hkey x hx, hkey y hy] at h + · exfalso + have himg : τ '' Ioo p r = Ioo q w := by + apply subset_antisymm + · rintro _ ⟨t, ht, rfl⟩ + exact hτmaps t ht + · intro y hy + rw [← hb] at hy + obtain ⟨x, hxW, rfl⟩ := hy + exact ⟨a x, hacoord x hxW, hkey x hxW⟩ + have hτlim : Tendsto τ (𝓝[>] p) (𝓝 w) := + tendsto_bot_of_strictAntiOn_image hpr hanti himg + have hF : 𝓝[Ioo p r] p = 𝓝[>] p := nhdsWithin_Ioo_eq_nhdsGT hpr + have hFne : (𝓝[Ioo p r] p).NeBot := by + apply mem_closure_iff_nhdsWithin_neBot.mp + rw [closure_Ioo hpr.ne] + exact ⟨le_refl p, hpr.le⟩ + have hlim1 : Tendsto a.symm (𝓝[Ioo p r] p) (𝓝 (a.symm p)) := + (a.symm.continuousOn p hp).mono hIoo_target + have hτw : Tendsto τ (𝓝[Ioo p r] p) (𝓝 w) := hF ▸ hτlim + have hτw' : Tendsto τ (𝓝[Ioo p r] p) (𝓝[b.target] w) := by + rw [tendsto_nhdsWithin_iff] + refine ⟨hτw, ?_⟩ + filter_upwards [self_mem_nhdsWithin] with t ht + exact hqw_target (hτmaps t ht) + have hlim2 : Tendsto (b.symm ∘ τ) (𝓝[Ioo p r] p) (𝓝 (b.symm w)) := + Tendsto.comp (b.symm.continuousOn w hw) hτw' + have hlim2' : Tendsto a.symm (𝓝[Ioo p r] p) (𝓝 (b.symm w)) := by + apply Tendsto.congr' _ hlim2 + filter_upwards [self_mem_nhdsWithin] with t ht + show b.symm (τ t) = a.symm t + simp only [hτdef] + exact b.left_inv (hWb (hsymm t ht).1) + have hz : a.symm p = b.symm w := tendsto_nhds_unique' hFne hlim1 hlim2' + have hzS : a.symm p ∈ a.source ∩ b.source := by + refine ⟨a.map_target hp, ?_⟩ + rw [hz] + exact b.map_target hw + exact hpS ⟨a.symm p, hzS, a.right_inv hp⟩ + +/-- **Two-component structure.** A disconnected overlap of a chart with target `Ioo 0 1` +and a connected-source chart has exactly two components: one whose image is a lower +end-segment `Ioo 0 r` and one whose image is an upper end-segment `Ioo p 1`, with +`r ≤ p`. -/ +theorem two_components_structure [T2Space M] (a b : OpenPartialHomeomorph M NNReal) + (hat : a.target = Ioo 0 1) + (hb : IsConnected b.source) + (_hab : (a.source \ b.source).Nonempty) + (hba : (b.source \ a.source).Nonempty) + (hne : (a.source ∩ b.source).Nonempty) + (hdisc : ¬ IsConnected (a.source ∩ b.source)) : + ∃ (W₀ W₁ : Set M) (r p : NNReal), + a.source ∩ b.source = W₀ ∪ W₁ ∧ + (∀ z ∈ W₀, connectedComponentIn (a.source ∩ b.source) z = W₀) ∧ + (∀ z ∈ W₁, connectedComponentIn (a.source ∩ b.source) z = W₁) ∧ + Disjoint W₀ W₁ ∧ + a '' W₀ = Ioo 0 r ∧ a '' W₁ = Ioo p 1 ∧ + 0 < r ∧ r ≤ p ∧ p < 1 := by + set S := a.source ∩ b.source with hSdef + have hSa : S ⊆ a.source := inter_subset_left + have outer : ∀ x ∈ S, + (∃ p, 0 ≤ p ∧ p < 1 ∧ a '' connectedComponentIn S x = Ioo p 1) ∨ + (∃ q, 0 < q ∧ q ≤ 1 ∧ a '' connectedComponentIn S x = Ioo 0 q) := + fun x hx => overlap_component_outer_Ioo a b hat hb hba hx + -- Two components whose images are both lower end-segments coincide. + have hlow : ∀ x y : M, ∀ r r' : NNReal, 0 < r → 0 < r' → + a '' connectedComponentIn S x = Ioo 0 r → + a '' connectedComponentIn S y = Ioo 0 r' → + connectedComponentIn S x = connectedComponentIn S y := by + intro x y r r' hr hr' hix hiy + obtain ⟨z, hz1, hz2⟩ := exists_between (lt_min hr hr') + have hzx : z ∈ a '' connectedComponentIn S x := + hix ▸ mem_Ioo.mpr ⟨hz1, hz2.trans_le (min_le_left _ _)⟩ + have hzy : z ∈ a '' connectedComponentIn S y := + hiy ▸ mem_Ioo.mpr ⟨hz1, hz2.trans_le (min_le_right _ _)⟩ + obtain ⟨w1, hw1, hw1z⟩ := hzx + obtain ⟨w2, hw2, hw2z⟩ := hzy + have hw12 : w1 = w2 := + a.injOn (hSa (connectedComponentIn_subset _ _ hw1)) + (hSa (connectedComponentIn_subset _ _ hw2)) (hw1z.trans hw2z.symm) + calc connectedComponentIn S x + = connectedComponentIn S w1 := connectedComponentIn_eq hw1 + _ = connectedComponentIn S w2 := by rw [hw12] + _ = connectedComponentIn S y := (connectedComponentIn_eq hw2).symm + -- Two components whose images are both upper end-segments coincide. + have hup : ∀ x y : M, ∀ p p' : NNReal, p < 1 → p' < 1 → + a '' connectedComponentIn S x = Ioo p 1 → + a '' connectedComponentIn S y = Ioo p' 1 → + connectedComponentIn S x = connectedComponentIn S y := by + intro x y p p' hp hp' hix hiy + obtain ⟨z, hz1, hz2⟩ := exists_between (max_lt hp hp') + have hzx : z ∈ a '' connectedComponentIn S x := + hix ▸ mem_Ioo.mpr ⟨(le_max_left _ _).trans_lt hz1, hz2⟩ + have hzy : z ∈ a '' connectedComponentIn S y := + hiy ▸ mem_Ioo.mpr ⟨(le_max_right _ _).trans_lt hz1, hz2⟩ + obtain ⟨w1, hw1, hw1z⟩ := hzx + obtain ⟨w2, hw2, hw2z⟩ := hzy + have hw12 : w1 = w2 := + a.injOn (hSa (connectedComponentIn_subset _ _ hw1)) + (hSa (connectedComponentIn_subset _ _ hw2)) (hw1z.trans hw2z.symm) + calc connectedComponentIn S x + = connectedComponentIn S w1 := connectedComponentIn_eq hw1 + _ = connectedComponentIn S w2 := by rw [hw12] + _ = connectedComponentIn S y := (connectedComponentIn_eq hw2).symm + -- Main construction from one lower-imaged and one upper-imaged (distinct) component. + have main : ∀ x' y' : M, ∀ r p : NNReal, 0 < r → p < 1 → + a '' connectedComponentIn S x' = Ioo 0 r → + a '' connectedComponentIn S y' = Ioo p 1 → + connectedComponentIn S x' ≠ connectedComponentIn S y' → + ∃ (W₀ W₁ : Set M) (r' p' : NNReal), + S = W₀ ∪ W₁ ∧ + (∀ z ∈ W₀, connectedComponentIn S z = W₀) ∧ + (∀ z ∈ W₁, connectedComponentIn S z = W₁) ∧ + Disjoint W₀ W₁ ∧ + a '' W₀ = Ioo 0 r' ∧ a '' W₁ = Ioo p' 1 ∧ + 0 < r' ∧ r' ≤ p' ∧ p' < 1 := by + intro x' y' r p hr0 hp1 hxi hyi hne' + have hcomp₀ : ∀ z ∈ connectedComponentIn S x', + connectedComponentIn S z = connectedComponentIn S x' := + fun z hz => (connectedComponentIn_eq hz).symm + have hcomp₁ : ∀ z ∈ connectedComponentIn S y', + connectedComponentIn S z = connectedComponentIn S y' := + fun z hz => (connectedComponentIn_eq hz).symm + have hdisj : Disjoint (connectedComponentIn S x') (connectedComponentIn S y') := by + rw [Set.disjoint_left] + intro z hz₀ hz₁ + exact hne' ((hcomp₀ z hz₀).symm.trans (hcomp₁ z hz₁)) + have hunion : S = connectedComponentIn S x' ∪ connectedComponentIn S y' := by + apply subset_antisymm + · intro z hz + rcases outer z hz with ⟨p'', _, hp''1, hpi''⟩ | ⟨r'', hr''0, _, hri''⟩ + · right + rw [← hup z y' p'' p hp''1 hp1 hpi'' hyi] + exact mem_connectedComponentIn hz + · left + rw [← hlow z x' r'' r hr''0 hr0 hri'' hxi] + exact mem_connectedComponentIn hz + · exact union_subset (connectedComponentIn_subset _ _) + (connectedComponentIn_subset _ _) + have hrp : r ≤ p := by + by_contra h + rw [not_le] at h + obtain ⟨t, ht1, ht2⟩ := exists_between (lt_min h hp1) + have htW₀ : t ∈ a '' connectedComponentIn S x' := + hxi ▸ mem_Ioo.mpr ⟨(zero_le : (0 : NNReal) ≤ p).trans_lt ht1, + ht2.trans_le (min_le_left _ _)⟩ + have htW₁ : t ∈ a '' connectedComponentIn S y' := + hyi ▸ mem_Ioo.mpr ⟨ht1, ht2.trans_le (min_le_right _ _)⟩ + obtain ⟨w1, hw1, hw1t⟩ := htW₀ + obtain ⟨w2, hw2, hw2t⟩ := htW₁ + have hw12 : w1 = w2 := + a.injOn (hSa (connectedComponentIn_subset _ _ hw1)) + (hSa (connectedComponentIn_subset _ _ hw2)) (hw1t.trans hw2t.symm) + have hw2' : w1 ∈ connectedComponentIn S y' := by rw [hw12]; exact hw2 + exact Set.disjoint_left.mp hdisj hw1 hw2' + exact ⟨connectedComponentIn S x', connectedComponentIn S y', r, p, + hunion, hcomp₀, hcomp₁, hdisj, hxi, hyi, hr0, hrp, hp1⟩ + -- Produce two distinct components. + obtain ⟨x₀, hx₀⟩ := hne + have hSnW : ¬ (S ⊆ connectedComponentIn S x₀) := by + intro h + apply hdisc + have hSW : S = connectedComponentIn S x₀ := + subset_antisymm h (connectedComponentIn_subset S x₀) + rw [hSW] + exact isConnected_connectedComponentIn_iff.mpr hx₀ + obtain ⟨y₀, hy₀S, hy₀W⟩ := not_subset.mp hSnW + have hWW' : connectedComponentIn S x₀ ≠ connectedComponentIn S y₀ := by + intro h + apply hy₀W + rw [h] + exact mem_connectedComponentIn hy₀S + rcases outer x₀ hx₀ with ⟨p, _, hp1, hpi⟩ | ⟨r, hr0, _, hri⟩ <;> + rcases outer y₀ hy₀S with ⟨p', _, hp'1, hpi'⟩ | ⟨r', hr'0, _, hri'⟩ + · exact absurd (hup x₀ y₀ p p' hp1 hp'1 hpi hpi') hWW' + · exact main y₀ x₀ r' p hr'0 hp1 hri' hpi (Ne.symm hWW') + · exact main x₀ y₀ r p' hr0 hp'1 hri hpi' hWW' + · exact absurd (hlow x₀ y₀ r r' hr0 hr'0 hri hri') hWW' + +/-- The other chart also sees the two components as end-segments, one lower and one +upper (in one of the two possible arrangements). -/ +theorem two_components_other_chart [T2Space M] (a b : OpenPartialHomeomorph M NNReal) + (hbt : b.target = Ioo 0 1) + (haconn : IsConnected a.source) + (hab : (a.source \ b.source).Nonempty) + {W₀ W₁ : Set M} + (hW₀ : ∀ z ∈ W₀, connectedComponentIn (a.source ∩ b.source) z = W₀) + (hW₁ : ∀ z ∈ W₁, connectedComponentIn (a.source ∩ b.source) z = W₁) + (hne₀ : W₀.Nonempty) (hne₁ : W₁.Nonempty) (hd : Disjoint W₀ W₁) : + ∃ s q : NNReal, 0 < s ∧ s ≤ q ∧ q < 1 ∧ + ((b '' W₀ = Ioo q 1 ∧ b '' W₁ = Ioo 0 s) ∨ + (b '' W₀ = Ioo 0 s ∧ b '' W₁ = Ioo q 1)) := by + set S := a.source ∩ b.source with hSdef + -- The components are inside the overlap. + have hW₀S : W₀ ⊆ S := by + intro z hz + by_contra hzS + have h1 : W₀ = (∅ : Set M) := + (hW₀ z hz).symm.trans (connectedComponentIn_eq_empty hzS) + rw [h1] at hz + simp at hz + have hW₁S : W₁ ⊆ S := by + intro z hz + by_contra hzS + have h1 : W₁ = (∅ : Set M) := + (hW₁ z hz).symm.trans (connectedComponentIn_eq_empty hzS) + rw [h1] at hz + simp at hz + have hcomm : b.source ∩ a.source = S := by rw [hSdef]; exact inter_comm _ _ + -- The outer-overlap lemma seen from chart `b`. + have outer : ∀ z ∈ S, + (∃ q, 0 ≤ q ∧ q < 1 ∧ b '' connectedComponentIn S z = Ioo q 1) ∨ + (∃ s, 0 < s ∧ s ≤ 1 ∧ b '' connectedComponentIn S z = Ioo 0 s) := by + intro z hz + have hz' : z ∈ b.source ∩ a.source := ⟨hz.2, hz.1⟩ + have h := overlap_component_outer_Ioo b a hbt haconn hab hz' + rwa [hcomm] at h + obtain ⟨z₀, hz₀⟩ := hne₀ + obtain ⟨z₁, hz₁⟩ := hne₁ + have h₀ := outer z₀ (hW₀S hz₀) + rw [hW₀ z₀ hz₀] at h₀ + have h₁ := outer z₁ (hW₁S hz₁) + rw [hW₁ z₁ hz₁] at h₁ + -- A common point of the two `b`-images contradicts disjointness. + have hcommon : ∀ t : NNReal, t ∈ b '' W₀ → t ∈ b '' W₁ → False := by + intro t ht₀ ht₁ + obtain ⟨w1, hw1, hw1t⟩ := ht₀ + obtain ⟨w2, hw2, hw2t⟩ := ht₁ + have h12 : w1 = w2 := + b.injOn ((hW₀S.trans inter_subset_right) hw1) + ((hW₁S.trans inter_subset_right) hw2) (hw1t.trans hw2t.symm) + have hw2' : w1 ∈ W₁ := by rw [h12]; exact hw2 + exact Set.disjoint_left.mp hd hw1 hw2' + rcases h₀ with ⟨q₀, _hq₀0, hq₀1, hbW₀⟩ | ⟨s₀, hs₀0, _hs₀1, hbW₀⟩ <;> + rcases h₁ with ⟨q₁, _hq₁0, hq₁1, hbW₁⟩ | ⟨s₁, hs₁0, _hs₁1, hbW₁⟩ + · -- both upper: impossible + exfalso + obtain ⟨t, ht1, ht2⟩ := exists_between (max_lt hq₀1 hq₁1) + exact hcommon t (hbW₀ ▸ mem_Ioo.mpr ⟨(le_max_left _ _).trans_lt ht1, ht2⟩) + (hbW₁ ▸ mem_Ioo.mpr ⟨(le_max_right _ _).trans_lt ht1, ht2⟩) + · -- `W₀` upper, `W₁` lower + refine ⟨s₁, q₀, hs₁0, ?_, hq₀1, Or.inl ⟨hbW₀, hbW₁⟩⟩ + by_contra h + rw [not_le] at h + obtain ⟨t, ht1, ht2⟩ := exists_between (lt_min h hq₀1) + exact hcommon t + (hbW₀ ▸ mem_Ioo.mpr ⟨ht1, ht2.trans_le (min_le_right _ _)⟩) + (hbW₁ ▸ mem_Ioo.mpr ⟨(zero_le : (0 : NNReal) ≤ q₀).trans_lt ht1, + ht2.trans_le (min_le_left _ _)⟩) + · -- `W₀` lower, `W₁` upper + refine ⟨s₀, q₁, hs₀0, ?_, hq₁1, Or.inr ⟨hbW₀, hbW₁⟩⟩ + by_contra h + rw [not_le] at h + obtain ⟨t, ht1, ht2⟩ := exists_between (lt_min h hq₁1) + exact hcommon t + (hbW₀ ▸ mem_Ioo.mpr ⟨(zero_le : (0 : NNReal) ≤ q₁).trans_lt ht1, + ht2.trans_le (min_le_left _ _)⟩) + (hbW₁ ▸ mem_Ioo.mpr ⟨ht1, ht2.trans_le (min_le_right _ _)⟩) + · -- both lower: impossible + exfalso + obtain ⟨t, ht1, ht2⟩ := exists_between (lt_min hs₀0 hs₁0) + exact hcommon t (hbW₀ ▸ mem_Ioo.mpr ⟨ht1, ht2.trans_le (min_le_left _ _)⟩) + (hbW₁ ▸ mem_Ioo.mpr ⟨ht1, ht2.trans_le (min_le_right _ _)⟩) diff --git a/LeanPool/OneManifold/OneMfld/UnitInterval.lean b/LeanPool/OneManifold/OneMfld/UnitInterval.lean new file mode 100644 index 0000000000..30f174b2cc --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/UnitInterval.lean @@ -0,0 +1,22 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import Mathlib + +def UnitInterval : Set Real := { x : Real | 0 ≤ x ∧ x ≤ 1 } + +/-- `UnitInterval` is definitionally `Set.Icc 0 1`; this bridge unlocks Mathlib's +`Icc` API (e.g. `iccHomeoI`, `isCompact_Icc`) for it. -/ +lemma UnitInterval_eq_Icc : UnitInterval = Set.Icc (0 : Real) 1 := rfl + +lemma isCompact_UnitInterval : IsCompact UnitInterval := by + rw [UnitInterval_eq_Icc] + exact isCompact_Icc + +instance : CompactSpace UnitInterval := + isCompact_iff_compactSpace.mp isCompact_UnitInterval + +instance : Nonempty UnitInterval := + ⟨⟨0, le_refl 0, zero_le_one⟩⟩ diff --git a/LeanPool/OneManifold/Solution.lean b/LeanPool/OneManifold/Solution.lean new file mode 100644 index 0000000000..b3b810ea7d --- /dev/null +++ b/LeanPool/OneManifold/Solution.lean @@ -0,0 +1,25 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +import LeanPool.OneManifold.OneMfld.Classification + +/-! +# Proved solution + +This module imports the full proof development and restates the Challenge +theorem with the identical name and type. The library's `classification` +(in `OneMfld/Classification.lean`) produces the homeomorphism as data, as a +term of `(M ≃ₜ Circle) ⊕ (M ≃ₜ UnitInterval)`; here we only need the +Prop-level disjunction. The Challenge's `{x : ℝ // 0 ≤ x ∧ x ≤ 1}` is +definitionally `↥OneMfld.UnitInterval` (and Mathlib's `↥unitInterval`). +-/ + +theorem OneMfld.homeomorph_circle_or_unitInterval + (M : Type*) [TopologicalSpace M] [CompactSpace M] [ConnectedSpace M] + [T2Space M] [ChartedSpace NNReal M] : + Nonempty (M ≃ₜ Circle) ∨ Nonempty (M ≃ₜ {x : ℝ // 0 ≤ x ∧ x ≤ 1}) := by + rcases classification (M := M) ‹ChartedSpace NNReal M› with e | e + · exact Or.inl ⟨e⟩ + · exact Or.inr ⟨e⟩ diff --git a/LeanPool/projects.yml b/LeanPool/projects.yml index 95e0c8ad83..fc68f9d607 100644 --- a/LeanPool/projects.yml +++ b/LeanPool/projects.yml @@ -9966,3 +9966,36 @@ projects: msc: - '90C35' - '05C21' + - slug: 1mfld + title: The classification of compact 1-manifolds + summary: 'A Lean 4 (mathlib) proof of the classification of 1-manifolds, specifically that + every compact, connected, Hausdorff topological space charted on the half-line [0,∞) is + homeomorphic to the circle S¹ or to the closed unit interval [0,1]. The proof follows + David Gale''s outline: shrink to a finite atlas of interval charts, then induct on the + atlas size, merging two overlapping charts at each step; a connected overlap glues two + charts into one (two boundary charts glue onto [0, 1]), while a disconnected overlap has + exactly two components and yields the circle.' + branch: topology + entry_module: LeanPool.OneManifold + authors: + - Jim Fowler + - Dennis Sweeney + source: + url: https://github.com/sweeneyde/1mfld + github_repo: sweeneyde/1mfld + commit: 83e961ba28dd8182e7bae844756aba614eb1512e + license: Apache-2.0 + status: verified + main_declarations: + - OneMfld.homeomorph_circle_or_unitInterval + main_results: + - declaration: OneMfld.homeomorph_circle_or_unitInterval + informal: Every compact connected Hausdorff space charted on the nonnegative real half-line + is homeomorphic to the circle or the closed unit interval. + tags: + - topology + msc: + - 57N99 + - 54F65 + - 68V20 + provenance: mix From a7b89e8bd88dbb7a5702771b2ec0b748a1f5eca1 Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Mon, 21 Sep 2026 18:48:24 +0000 Subject: [PATCH 02/16] Complete one-manifold classification port and local verification --- LeanPool.lean | 27 ++ LeanPool/OneManifold/OneMfld/Charts.lean | 8 +- .../OneManifold/OneMfld/CircleBlocks.lean | 14 +- LeanPool/OneManifold/OneMfld/CircleGlue.lean | 82 +++--- .../OneManifold/OneMfld/Classification.lean | 186 ++++++------- .../OneManifold/OneMfld/ClassifyInterval.lean | 256 ++++++++---------- .../OneManifold/OneMfld/ClassifyOverlaps.lean | 52 ++-- .../OneManifold/OneMfld/ClosureOverlap.lean | 18 +- LeanPool/OneManifold/OneMfld/Compactness.lean | 11 +- .../OneMfld/FiniteIntervalCharts.lean | 20 +- .../OneManifold/OneMfld/FinitelyCharted.lean | 18 +- LeanPool/OneManifold/OneMfld/GlueBlocks.lean | 17 +- LeanPool/OneManifold/OneMfld/GlueCore.lean | 6 +- LeanPool/OneManifold/OneMfld/GlueNNReal.lean | 6 +- LeanPool/OneManifold/OneMfld/GlueUI.lean | 5 +- .../OneManifold/OneMfld/IntervalCharts.lean | 24 +- .../OneManifold/OneMfld/LocallyConnected.lean | 50 ++-- LeanPool/OneManifold/OneMfld/NiceCharts.lean | 84 +++--- LeanPool/OneManifold/OneMfld/Noncompact.lean | 19 +- LeanPool/OneManifold/OneMfld/Normalize.lean | 4 +- LeanPool/OneManifold/OneMfld/Outer.lean | 6 +- .../OneMfld/PartialHomeomorphHelpers.lean | 15 +- .../OneManifold/OneMfld/RealIntervals.lean | 241 +++++++++-------- .../OneManifold/OneMfld/TransitionMono.lean | 4 +- .../OneManifold/OneMfld/TwoComponents.lean | 6 +- .../OneManifold/OneMfld/UnitInterval.lean | 11 +- 26 files changed, 645 insertions(+), 545 deletions(-) diff --git a/LeanPool.lean b/LeanPool.lean index 2092a32a2d..e7879b3459 100644 --- a/LeanPool.lean +++ b/LeanPool.lean @@ -5668,6 +5668,33 @@ import LeanPool.Odlyzko.Theta.PoissonSummation import LeanPool.Odlyzko.Theta.TraceDualIdeal import LeanPool.Odlyzko.Theta.TraceDualLattice import LeanPool.OneManifold +import LeanPool.OneManifold.OneMfld +import LeanPool.OneManifold.OneMfld.Charts +import LeanPool.OneManifold.OneMfld.CircleBlocks +import LeanPool.OneManifold.OneMfld.CircleGlue +import LeanPool.OneManifold.OneMfld.Classification +import LeanPool.OneManifold.OneMfld.ClassifyInterval +import LeanPool.OneManifold.OneMfld.ClassifyOverlaps +import LeanPool.OneManifold.OneMfld.ClosureOverlap +import LeanPool.OneManifold.OneMfld.Compactness +import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts +import LeanPool.OneManifold.OneMfld.FinitelyCharted +import LeanPool.OneManifold.OneMfld.GlueBlocks +import LeanPool.OneManifold.OneMfld.GlueCore +import LeanPool.OneManifold.OneMfld.GlueNNReal +import LeanPool.OneManifold.OneMfld.GlueUI +import LeanPool.OneManifold.OneMfld.IntervalCharts +import LeanPool.OneManifold.OneMfld.LocallyConnected +import LeanPool.OneManifold.OneMfld.NiceCharts +import LeanPool.OneManifold.OneMfld.Noncompact +import LeanPool.OneManifold.OneMfld.Normalize +import LeanPool.OneManifold.OneMfld.Outer +import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers +import LeanPool.OneManifold.OneMfld.RealIntervals +import LeanPool.OneManifold.OneMfld.TransitionMono +import LeanPool.OneManifold.OneMfld.TwoComponents +import LeanPool.OneManifold.OneMfld.UnitInterval +import LeanPool.OneManifold.Solution import LeanPool.OrderPQ import LeanPool.OrderPQ.Basic import LeanPool.OrderPQ.IsCyclic diff --git a/LeanPool/OneManifold/OneMfld/Charts.lean b/LeanPool/OneManifold/OneMfld/Charts.lean index d052fb421d..7a6d6e63b9 100644 --- a/LeanPool/OneManifold/OneMfld/Charts.lean +++ b/LeanPool/OneManifold/OneMfld/Charts.lean @@ -3,7 +3,7 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers /-! Interval charts on a 1-manifold charted on `ℝ≥0`, and the `Overlap` relation. @@ -12,14 +12,17 @@ An `OChart` has an open-interval target `Ioo x y` (an interior chart); an `HChar half-open target `Iio x` (a boundary chart); an `IChart` is either. -/ +/-- A one-dimensional chart with an open bounded interval as target. -/ structure OChart (M : Type*) [TopologicalSpace M] extends OpenPartialHomeomorph M NNReal where target_ioo : (∃ x y, (Set.Ioo x y = target)) +/-- A boundary chart with a half-open interval as target. -/ structure HChart (M : Type*) [TopologicalSpace M] extends OpenPartialHomeomorph M NNReal where target_iio : (∃ x, (Set.Iio x = target)) +/-- A chart whose target is an open interval or a half-open interval. -/ structure IChart (M : Type*) [TopologicalSpace M] extends OpenPartialHomeomorph M NNReal where is_interval : (∃ x y, (Set.Ioo x y = target)) ∨ (∃ x, (Set.Iio x = target)) @@ -28,12 +31,15 @@ variable {M : Type*} [TopologicalSpace M] +/-- Regard an interior chart as an interval chart. -/ def OChart.toIChart (a : OChart M) : IChart M := { a with is_interval := Or.inl a.target_ioo } +/-- Regard a boundary chart as an interval chart. -/ def HChart.toIChart (a : HChart M) : IChart M := { a with is_interval := Or.inr a.target_iio } +/-- Two sets meet and each has a point outside the other. -/ def Overlap (U : Set α) (V : Set α) : Prop := (U ∩ V).Nonempty ∧ (U \ V).Nonempty ∧ (V \ U).Nonempty diff --git a/LeanPool/OneManifold/OneMfld/CircleBlocks.lean b/LeanPool/OneManifold/OneMfld/CircleBlocks.lean index 1d1db78a2e..40d732d229 100644 --- a/LeanPool/OneManifold/OneMfld/CircleBlocks.lean +++ b/LeanPool/OneManifold/OneMfld/CircleBlocks.lean @@ -3,7 +3,13 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Algebra.Order.Star.Real +import Mathlib.Analysis.Normed.Order.Lattice +import Mathlib.Tactic +import Mathlib.Topology.Algebra.ProperAction.Basic +import Mathlib.Topology.GDelta.MetrizableSpace +import Mathlib.Topology.Instances.AddCircle.Defs +import Mathlib.Topology.Instances.ZMultiples /-! # Building blocks for the circle case @@ -50,7 +56,7 @@ lemma mobiusFun_strictMonoOn (c : NNReal) (hc : 0 < c) : have hxy' : (x:ℝ) < y := hxy nlinarith [mul_pos hc' (sub_pos.mpr hxy')] -lemma mobiusFun_mem (c : NNReal) (hc : 0 < c) {t : NNReal} (ht : t ∈ Ioo (0:NNReal) 1) : +lemma mobiusFun_mem (c : NNReal) (hc : 0 < c) {t : NNReal} (ht : t ∈ Ioo (0 : NNReal) 1) : mobiusFun c t ∈ Ioo (0:NNReal) 1 := by have hden : 0 < t + c * (1 - t) := lt_of_lt_of_le ht.1 le_self_add refine ⟨div_pos ht.1 hden, ?_⟩ @@ -127,7 +133,7 @@ def mobiusOPH' (c : NNReal) (hc : 0 < c) : continuousOn_toFun := ?_ continuousOn_invFun := ?_ }, rfl, rfl, fun x => rfl, ?_, ?_⟩ - · show ContinuousOn (fun x : NNReal => x / (x + c * (1 - x))) (Ioo 0 1) + · change ContinuousOn (fun x : NNReal => x / (x + c * (1 - x))) (Ioo 0 1) exact ContinuousOn.div continuousOn_id ((continuous_id.add (continuous_const.mul (continuous_const.sub continuous_id))).continuousOn) (fun x hx => (lt_of_lt_of_le hx.1 le_self_add).ne') @@ -215,7 +221,7 @@ section AddCircleArith /-- Two reals with the same image in `AddCircle 1` and distance less than `1` are equal. -/ -lemma addCircle_coe_inj {x y : ℝ} (h : (x : AddCircle (1:ℝ)) = (y : AddCircle (1:ℝ))) +lemma addCircle_coe_inj {x y : ℝ} (h : (x : AddCircle (1 : ℝ)) = (y : AddCircle (1 : ℝ))) (hxy : |x - y| < 1) : x = y := by have h0 : ((x - y : ℝ) : AddCircle (1:ℝ)) = 0 := by rw [AddCircle.coe_sub, h, sub_self] diff --git a/LeanPool/OneManifold/OneMfld/CircleGlue.lean b/LeanPool/OneManifold/OneMfld/CircleGlue.lean index a12c42fb21..8dce5ec82e 100644 --- a/LeanPool/OneManifold/OneMfld/CircleGlue.lean +++ b/LeanPool/OneManifold/OneMfld/CircleGlue.lean @@ -3,7 +3,7 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic import LeanPool.OneManifold.OneMfld.Charts import LeanPool.OneManifold.OneMfld.Normalize import LeanPool.OneManifold.OneMfld.GlueBlocks @@ -27,7 +27,7 @@ open Set /-- Two reals with the same image in `AddCircle 1` differ by an integer. -/ private lemma addCircle_coe_eq_iff_int {x y : ℝ} : - (x : AddCircle (1:ℝ)) = (y : AddCircle (1:ℝ)) ↔ ∃ n : ℤ, x - y = (n : ℝ) := by + (x : AddCircle (1 : ℝ)) = (y : AddCircle (1 : ℝ)) ↔ ∃ n : ℤ, x - y = (n : ℝ) := by rw [QuotientAddGroup.eq_iff_sub_mem] constructor · intro h @@ -39,7 +39,7 @@ private lemma addCircle_coe_eq_iff_int {x y : ℝ} : /-- Window analysis: two reals with the same circle image and difference in `(-1, 2)` are equal or differ by exactly one period. -/ private lemma addCircle_eq_or_eq_add_one {x y : ℝ} - (h : (x : AddCircle (1:ℝ)) = (y : AddCircle (1:ℝ))) + (h : (x : AddCircle (1 : ℝ)) = (y : AddCircle (1 : ℝ))) (h1 : -1 < x - y) (h2 : x - y < 2) : x = y ∨ x = y + 1 := by obtain ⟨n, hn⟩ := addCircle_coe_eq_iff_int.mp h have hn1 : (-1 : ℝ) < (n : ℝ) := hn ▸ h1 @@ -102,8 +102,8 @@ private lemma mono_key_ge {M : Type*} [TopologicalSpace M] /-- The real parameters of the circle gluing: slopes `kα`, `kg` and offset `g0` with the matching identities and strict separation inequalities. -/ private lemma circle_params {ρ ν σ μ : ℝ} - (hρ0 : 0 < ρ) (hρ4 : ρ < 1/4) (hν3 : 3/4 < ν) (hν1 : ν < 1) - (hσ0 : 0 < σ) (hσ4 : σ < 1/4) (hμ3 : 3/4 < μ) (hμ1 : μ < 1) : + (hρ0 : 0 < ρ) (hρ4 : ρ < 1 / 4) (hν3 : 3 / 4 < ν) (hν1 : ν < 1) + (hσ0 : 0 < σ) (hσ4 : σ < 1 / 4) (hμ3 : 3 / 4 < μ) (hμ1 : μ < 1) : ∃ kα kg g0 : ℝ, 0 < kα ∧ kα < 1 ∧ 0 < kg ∧ kg < 1 ∧ kg * σ + g0 = kα * ν ∧ kg * μ + g0 = 1 + kα * ρ ∧ @@ -135,7 +135,7 @@ private lemma circle_params {ρ ν σ μ : ℝ} have hid2 : kg * μ + g0 = 1 + kα * ρ := by rw [hg0def]; linear_combination hkgden have hP1 : (1/3 : ℝ) < kα * (ν - ρ) := by nlinarith - have hP2 : (1/4 : ℝ) < kα * (ν - ρ) * μ := by nlinarith + have hP2 : (1 / 4 : ℝ) < kα * (ν - ρ) * μ := by nlinarith have hkey : σ < kα * (ν - ρ) * μ := by linarith have hc₁g0 : kα * ρ < g0 := by have h2 : kg * σ * (μ - σ) = σ * (1 - kα * (ν - ρ)) := by @@ -157,10 +157,10 @@ private lemma circle_params {ρ ν σ μ : ℝ} `Ioo 0 1`) is the arc `coe '' Ioo d (d + k)`. -/ private lemma affine_circle_target {M : Type*} [TopologicalSpace M] (X : OpenPartialHomeomorph M NNReal) (hXt : X.target = Ioo 0 1) - (E : OpenPartialHomeomorph M (AddCircle (1:ℝ))) + (E : OpenPartialHomeomorph M (AddCircle (1 : ℝ))) (hEs : E.source = X.source) {k d : ℝ} (hk : 0 < k) - (hEval : ∀ x ∈ X.source, E x = ((k * ((X x : NNReal) : ℝ) + d : ℝ) : AddCircle (1:ℝ))) : - E.target = ((↑) : ℝ → AddCircle (1:ℝ)) '' (Ioo d (d + k)) := by + (hEval : ∀ x ∈ X.source, E x = ((k * ((X x : NNReal) : ℝ) + d : ℝ) : AddCircle (1 : ℝ))) : + E.target = ((↑) : ℝ → AddCircle (1 : ℝ)) '' (Ioo d (d + k)) := by rw [← E.image_source_eq_target, hEs] ext z constructor @@ -188,7 +188,7 @@ private lemma affine_circle_target {M : Type*} [TopologicalSpace M] /-- Normalize both charts to target `Ioo 0 1`, split the overlap into its two components, orient the second chart so the component lower in `a` is upper in `b`, and -Möbius-shrink both charts so the lower end-segments sit below `1/4`. -/ +Möbius-shrink both charts so the lower end-segments sit below `1 / 4`. -/ private lemma exists_normalized_charts {M : Type*} [TopologicalSpace M] [T2Space M] (a b : OChart M) (h : Overlap a.source b.source) (hdisc : ¬ IsConnected (a.source ∩ b.source)) : @@ -198,8 +198,8 @@ private lemma exists_normalized_charts {M : Type*} [TopologicalSpace M] [T2Space A.source ∩ B.source = W₀ ∪ W₁ ∧ A '' W₀ = Ioo 0 r ∧ A '' W₁ = Ioo p 1 ∧ B '' W₀ = Ioo q 1 ∧ B '' W₁ = Ioo 0 s ∧ - 0 < r ∧ r ≤ p ∧ p < 1 ∧ r < 1/4 ∧ - 0 < s ∧ s ≤ q ∧ q < 1 ∧ s < 1/4 := by + 0 < r ∧ r ≤ p ∧ p < 1 ∧ r < 1 / 4 ∧ + 0 < s ∧ s ≤ q ∧ q < 1 ∧ s < 1 / 4 := by have hane : a.source.Nonempty := h.1.mono inter_subset_left have hbne : b.source.Nonempty := h.1.mono inter_subset_right obtain ⟨a₀, ha₀s, ha₀t, -⟩ := a.rescale hane @@ -250,7 +250,7 @@ private lemma exists_normalized_charts {M : Type*} [TopologicalSpace M] [T2Space obtain ⟨B₁, hB₁s, hB₁t, s₂, q₂, hs₂0, hs₂q, hq₂1, himgB₀, himgB₁⟩ := hBpick -- Möbius-shrink the `a`-side chart. have hr₀1 : r₀ < 1 := lt_of_le_of_lt hr₀p hp₁1 - have hquarter : (0:NNReal) < 1/4 := by norm_num + have hquarter : (0:NNReal) < 1 / 4 := by norm_num obtain ⟨cA, hcA0, hcA⟩ := exists_mobiusFun_lt hr₀0 hr₀1 hquarter obtain ⟨mA, hmAs, hmAt, hmAf, hmAlo, hmAhi⟩ := mobiusOPH' cA hcA0 set A := a₀.toOpenPartialHomeomorph.trans mA with hAdef @@ -324,9 +324,9 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa (hunion : A.source ∩ B.source = W₀ ∪ W₁) (himgA₀ : A '' W₀ = Ioo 0 r) (himgA₁ : A '' W₁ = Ioo p 1) (himgB₀ : B '' W₀ = Ioo q 1) (himgB₁ : B '' W₁ = Ioo 0 s) - (hr0 : 0 < r) (hrp : r ≤ p) (hp1 : p < 1) (hr4 : r < 1/4) - (hs0 : 0 < s) (hsq : s ≤ q) (hq1 : q < 1) (hs4 : s < 1/4) : - ∃ f : OpenPartialHomeomorph M (AddCircle (1:ℝ)), + (hr0 : 0 < r) (hrp : r ≤ p) (hp1 : p < 1) (hr4 : r < 1 / 4) + (hs0 : 0 < s) (hsq : s ≤ q) (hq1 : q < 1) (hs4 : s < 1 / 4) : + ∃ f : OpenPartialHomeomorph M (AddCircle (1 : ℝ)), f.source = A.source ∪ B.source ∧ f.target = univ := by classical have hfact : Fact ((0:ℝ) < 1) := ⟨one_pos⟩ @@ -363,17 +363,17 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa · exact absurd h2 (not_lt.2 hrp) · exact absurd h1 (lt_irrefl p) -- Split points. - have h34lt1 : (3/4 : NNReal) < 1 := by norm_num + have h34lt1 : (3 / 4 : NNReal) < 1 := by norm_num obtain ⟨ν, hν1', hν2⟩ := exists_between (max_lt hp1 h34lt1) have hpν : p < ν := lt_of_le_of_lt (le_max_left _ _) hν1' - have h34ν : (3/4:NNReal) < ν := lt_of_le_of_lt (le_max_right _ _) hν1' + have h34ν : (3 / 4:NNReal) < ν := lt_of_le_of_lt (le_max_right _ _) hν1' obtain ⟨m₁, hm₁W, hm₁ν⟩ : ∃ m₁ ∈ W₁, A m₁ = ν := by have hmem : ν ∈ A '' W₁ := by rw [himgA₁]; exact ⟨hpν, hν2⟩ obtain ⟨m₁, hm₁, he⟩ := hmem exact ⟨m₁, hm₁, he⟩ obtain ⟨μ, hμ1', hμ2⟩ := exists_between (max_lt hq1 h34lt1) have hqμ : q < μ := lt_of_le_of_lt (le_max_left _ _) hμ1' - have h34μ : (3/4:NNReal) < μ := lt_of_le_of_lt (le_max_right _ _) hμ1' + have h34μ : (3 / 4:NNReal) < μ := lt_of_le_of_lt (le_max_right _ _) hμ1' obtain ⟨m₀, hm₀W, hm₀μ⟩ : ∃ m₀ ∈ W₀, B m₀ = μ := by have hmem : μ ∈ B '' W₀ := by rw [himgB₀]; exact ⟨hqμ, hμ2⟩ obtain ⟨m₀, hm₀, he⟩ := hmem @@ -389,12 +389,12 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa have K₁ := mono_key_ge A B hW₁A mono₁ hm₁W -- Real versions of the split data. have hρ'0 : (0:ℝ) < ((A m₀ : NNReal) : ℝ) := by exact_mod_cast hρmem.1 - have hρ'4 : ((A m₀ : NNReal) : ℝ) < 1/4 := by exact_mod_cast hρmem.2.trans hr4 - have hν'3 : (3/4:ℝ) < ((ν : NNReal) : ℝ) := by exact_mod_cast h34ν + have hρ'4 : ((A m₀ : NNReal) : ℝ) < 1 / 4 := by exact_mod_cast hρmem.2.trans hr4 + have hν'3 : (3 / 4:ℝ) < ((ν : NNReal) : ℝ) := by exact_mod_cast h34ν have hν'1 : ((ν : NNReal) : ℝ) < 1 := by exact_mod_cast hν2 have hσ'0 : (0:ℝ) < ((B m₁ : NNReal) : ℝ) := by exact_mod_cast hσmem.1 - have hσ'4 : ((B m₁ : NNReal) : ℝ) < 1/4 := by exact_mod_cast hσmem.2.trans hs4 - have hμ'3 : (3/4:ℝ) < ((μ : NNReal) : ℝ) := by exact_mod_cast h34μ + have hσ'4 : ((B m₁ : NNReal) : ℝ) < 1 / 4 := by exact_mod_cast hσmem.2.trans hs4 + have hμ'3 : (3 / 4:ℝ) < ((μ : NNReal) : ℝ) := by exact_mod_cast h34μ have hμ'1 : ((μ : NNReal) : ℝ) < 1 := by exact_mod_cast hμ2 obtain ⟨kα, kg, g0, hkα0, hkα1, hkg0, hkg1, hid1, hid2, hcg0, hg0d, h1c, hg1d⟩ := circle_params hρ'0 hρ'4 hν'3 hν'1 hσ'0 hσ'4 hμ'3 hμ'1 @@ -412,8 +412,8 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa obtain ⟨eB, heBs, heBt, heBf⟩ := affineNNRealOPH kg g0 hkg0 have heAf' : ∀ x : NNReal, eA x = kα * (x:ℝ) + 0 := heAf have heBf' : ∀ x : NNReal, eB x = kg * (x:ℝ) + g0 := heBf - set CA := AddCircle.openPartialHomeomorphCoe (1:ℝ) (0:ℝ) with hCAdef - set CB := AddCircle.openPartialHomeomorphCoe (1:ℝ) (g0 + kg - 1) with hCBdef + set CA := AddCircle.openPartialHomeomorphCoe (1 : ℝ) (0:ℝ) with hCAdef + set CB := AddCircle.openPartialHomeomorphCoe (1 : ℝ) (g0 + kg - 1) with hCBdef have hCAs : CA.source = Ioo (0:ℝ) (0+1) := rfl have hCBs : CB.source = Ioo (g0 + kg - 1) (g0 + kg - 1 + 1) := rfl set e := (A.trans eA).trans CA with hedef @@ -433,11 +433,11 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa rw [OpenPartialHomeomorph.trans_apply, heAf'] have hBeBval : ∀ x, (B.trans eB) x = kg * ((B x : NNReal):ℝ) + g0 := fun x => by rw [OpenPartialHomeomorph.trans_apply, heBf'] - have heval : ∀ x, e x = ((kα * ((A x : NNReal) : ℝ) : ℝ) : AddCircle (1:ℝ)) := by + have heval : ∀ x, e x = ((kα * ((A x : NNReal) : ℝ) : ℝ) : AddCircle (1 : ℝ)) := by intro x rw [hedef, OpenPartialHomeomorph.trans_apply, hAeAval, add_zero] rfl - have he'val : ∀ x, e' x = ((kg * ((B x : NNReal) : ℝ) + g0 : ℝ) : AddCircle (1:ℝ)) := by + have he'val : ∀ x, e' x = ((kg * ((B x : NNReal) : ℝ) + g0 : ℝ) : AddCircle (1 : ℝ)) := by intro x rw [he'def, OpenPartialHomeomorph.trans_apply, hBeBval] rfl @@ -472,15 +472,15 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa obtain ⟨hb0, hb1⟩ := hb'bounds x hx exact ⟨by linarith, by linarith⟩ -- Targets. - have htargetE : e.target = ((↑) : ℝ → AddCircle (1:ℝ)) '' (Ioo 0 kα) := by + have htargetE : e.target = ((↑) : ℝ → AddCircle (1 : ℝ)) '' (Ioo 0 kα) := by have hgen := affine_circle_target A hAt e hes hkα0 (fun x _ => by rw [heval x, add_zero]) rw [hgen, zero_add] - have htargetE' : e'.target = ((↑) : ℝ → AddCircle (1:ℝ)) '' (Ioo g0 (g0 + kg)) := + have htargetE' : e'.target = ((↑) : ℝ → AddCircle (1 : ℝ)) '' (Ioo g0 (g0 + kg)) := affine_circle_target B hBt e' he's hkg0 (fun x _ => he'val x) -- The gluing sets. set sset := A.source ∩ A ⁻¹' (Icc (A m₀) ν) with hssetdef - set tset := ((↑) : ℝ → AddCircle (1:ℝ)) '' + set tset := ((↑) : ℝ → AddCircle (1 : ℝ)) '' (Icc (kα * ((A m₀ : NNReal):ℝ)) (kα * ((ν : NNReal):ℝ))) with htsetdef have hssub : sset ⊆ A.source := by rw [hssetdef]; exact inter_subset_left -- `e` maps `sset` to `tset`. @@ -515,7 +515,7 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa mul_le_mul_of_nonneg_left h2' hkα0.le⟩ -- Windows: membership of a point of the `e'`-arc in `tset`. have claim1 : ∀ v : ℝ, v ∈ Ioo g0 (g0 + kg) → - (((v : ℝ) : AddCircle (1:ℝ)) ∈ tset ↔ + (((v : ℝ) : AddCircle (1 : ℝ)) ∈ tset ↔ v ∈ Icc (kα * ((A m₀ : NNReal):ℝ)) (kα * ((ν : NNReal):ℝ)) ∨ v ∈ Icc (1 + kα * ((A m₀ : NNReal):ℝ)) (1 + kα * ((ν : NNReal):ℝ))) := by intro v hv @@ -643,13 +643,13 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa exact claim3 y hy -- The frontier of the closed arc consists of at most the two endpoint classes. have hfrontier : frontier tset ⊆ - {((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1:ℝ)), - ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1:ℝ))} := by + {((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)), + ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ))} := by rw [htsetdef] exact addCircle_frontier_arc_subset hc₁d₁ -- The endpoint classes are attained only at the split points. have Pce : ∀ x ∈ A.source, - (e x = ((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1:ℝ)) ↔ x = m₀) := by + (e x = ((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)) ↔ x = m₀) := by intro x hx obtain ⟨hb0, hb1⟩ := hbounds x hx constructor @@ -665,7 +665,7 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa · rintro rfl rw [heval x] have Pde : ∀ x ∈ A.source, - (e x = ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1:ℝ)) ↔ x = m₁) := by + (e x = ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)) ↔ x = m₁) := by intro x hx obtain ⟨hb0, hb1⟩ := hbounds x hx have hd₁0 : (0:ℝ) < kα * ((ν : NNReal):ℝ) := by linarith @@ -683,7 +683,7 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa · rintro rfl rw [heval x, hm₁ν] have Pce' : ∀ y ∈ B.source, - (e' y = ((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1:ℝ)) ↔ y = m₀) := by + (e' y = ((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)) ↔ y = m₀) := by intro y hy obtain ⟨hb0, hb1⟩ := hb'bounds y hy constructor @@ -701,7 +701,7 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa rw [he'val y, hm₀μ, hid2, add_comm 1 (kα * ((A y : NNReal):ℝ))] exact addCircle_coe_add_one _ have Pde' : ∀ y ∈ B.source, - (e' y = ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1:ℝ)) ↔ y = m₁) := by + (e' y = ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)) ↔ y = m₁) := by intro y hy obtain ⟨hb0, hb1⟩ := hb'bounds y hy constructor @@ -770,7 +770,7 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa rw [hdx, (Pde' x hm₁B).mpr rfl] -- Glue. refine ⟨e.piecewise e' sset tset H H' Hs Heq, ?_, ?_⟩ - · show Set.ite sset e.source e'.source = A.source ∪ B.source + · change Set.ite sset e.source e'.source = A.source ∪ B.source have hite : Set.ite sset e.source e'.source = (e.source ∩ sset) ∪ (e'.source \ sset) := rfl rw [hite, hes, he's] @@ -796,7 +796,7 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa exact hW₁B (mem_of_image_mem A hW₁A himgA₁ hxa hmem) exact Or.inr ⟨hxB, hxs⟩ · exact Or.inr ⟨hxb, hxs⟩ - · show Set.ite tset e.target e'.target = univ + · change Set.ite tset e.target e'.target = univ have hite : Set.ite tset e.target e'.target = (e.target ∩ tset) ∪ (e'.target \ tset) := rfl rw [hite] @@ -805,7 +805,7 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa rw [htargetE, htsetdef] exact image_mono (fun u hu => ⟨lt_of_lt_of_le hc₁0 hu.1, lt_of_le_of_lt hu.2 hd₁kα⟩) - have h2 : e'.target \ tset = ((↑) : ℝ → AddCircle (1:ℝ)) '' + have h2 : e'.target \ tset = ((↑) : ℝ → AddCircle (1 : ℝ)) '' (Ioo (kα * ((ν : NNReal):ℝ)) (kα * ((A m₀ : NNReal):ℝ) + 1)) := by rw [htargetE'] ext z @@ -842,7 +842,7 @@ a chart of `M` onto the whole of `AddCircle 1`. -/ theorem exists_circle_chart {M : Type*} [TopologicalSpace M] [T2Space M] (a b : OChart M) (h : Overlap a.source b.source) (hdisc : ¬ IsConnected (a.source ∩ b.source)) : - ∃ f : OpenPartialHomeomorph M (AddCircle (1:ℝ)), + ∃ f : OpenPartialHomeomorph M (AddCircle (1 : ℝ)), f.source = a.source ∪ b.source ∧ f.target = univ := by obtain ⟨A, B, W₀, W₁, r, p, s, q, hAs, hBs, hAt, hBt, hunion, himgA₀, himgA₁, himgB₀, himgB₁, hr0, hrp, hp1, hr4, hs0, hsq, hq1, hs4⟩ := diff --git a/LeanPool/OneManifold/OneMfld/Classification.lean b/LeanPool/OneManifold/OneMfld/Classification.lean index 83c1817588..2ee464d936 100644 --- a/LeanPool/OneManifold/OneMfld/Classification.lean +++ b/LeanPool/OneManifold/OneMfld/Classification.lean @@ -3,7 +3,9 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Algebra.Order.Ring.Star +import Mathlib.Data.Int.Star +import Mathlib.Tactic import LeanPool.OneManifold.OneMfld.UnitInterval import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts import LeanPool.OneManifold.OneMfld.IntervalCharts @@ -11,15 +13,22 @@ import LeanPool.OneManifold.OneMfld.NiceCharts import LeanPool.OneManifold.OneMfld.ClassifyOverlaps import LeanPool.OneManifold.OneMfld.Compactness +/-! +# Classification + +Supporting results for the classification of compact one-dimensional manifolds. +-/ + variable {M : Type*} [TopologicalSpace M] [ConnectedSpace M] -noncomputable def subsume_charts (ht : FinitelyIntervalChartedSpace M) +/-- Remove a chart whose source is contained in another chart, reducing the atlas size. -/ +noncomputable def subsumeCharts (ht : FinitelyIntervalChartedSpace M) {a : OpenPartialHomeomorph M NNReal} (ha : a ∈ ht.atlas) {b : OpenPartialHomeomorph M NNReal} (hb : b ∈ ht.atlas) - (hs : a.source ⊆ b.source) (hab : a ≠ b): + (hs : a.source ⊆ b.source) (hab : a ≠ b) : { ht' : FinitelyIntervalChartedSpace M | Nat.card ht'.atlas = Nat.card ht.atlas - 1 } := by let ht' : FinitelyIntervalChartedSpace M := { chartAt := by @@ -52,24 +61,22 @@ noncomputable def subsume_charts (ht : FinitelyIntervalChartedSpace M) apply ht.is_interval exact Set.mem_of_mem_sdiff hφ } - use ht' exact Set.ncard_sdiff_singleton_of_mem ha -noncomputable def replace_charts (ht : FinitelyIntervalChartedSpace M) +/-- Replace two overlapping charts by a chart on their union, reducing the atlas size. -/ +noncomputable def replaceCharts (ht : FinitelyIntervalChartedSpace M) {a : OpenPartialHomeomorph M NNReal} (ha : a ∈ ht.atlas) {b : OpenPartialHomeomorph M NNReal} (hb : b ∈ ht.atlas) (ho : Overlap a.source b.source) - (f : IChart M) (hf : f.source = a.source ∪ b.source ) : + (f : IChart M) (hf : f.source = a.source ∪ b.source) : { ht' : FinitelyIntervalChartedSpace M | Nat.card ht'.atlas ≤ Nat.card ht.atlas - 1 } := by - let hab : a ≠ b := by by_contra hab rw [hab] at ho let ho1 := ho.2.1 simp only [sdiff_self, Set.bot_eq_empty, Set.not_nonempty_empty] at ho1 - let ht' : FinitelyIntervalChartedSpace M := { chartAt := by intro x @@ -112,49 +119,40 @@ noncomputable def replace_charts (ht : FinitelyIntervalChartedSpace M) intro x hx simp only [Set.union_singleton, Set.mem_insert_iff, Set.mem_sdiff, Set.mem_singleton_iff, not_or] at hx - rcases hx with (hx|hx) · rw [hx] apply f.is_interval · apply ht.is_interval exact hx.1 } - use ht' - have pair : ( { a, b } : Set (OpenPartialHomeomorph M NNReal) ).ncard = 2 := Set.ncard_pair hab - - have equal : ht.atlas \ {a, b} ∪ {a, b} = ht.atlas := Set.sdiff_union_of_subset (Set.pair_subset ha hb) - - have union : ((ht.atlas \ { a, b } : Set _) ∪ {a, b} : Set _).ncard = (ht.atlas \ { a, b } : Set _).ncard + ( { a, b } : Set _ ).ncard := by + have equal : ht.atlas \ {a, b} ∪ {a, b} = ht.atlas := Set.sdiff_union_of_subset + (Set.pair_subset ha hb) + have union : ((ht.atlas \ { a, b } : Set _) ∪ {a, b} : Set _).ncard = (ht.atlas \ { a, b } : + Set _).ncard + ( { a, b } : Set _ ).ncard := by apply Set.ncard_union_eq - exact Set.disjoint_sdiff_left - apply Set.Finite.sdiff - exact ht.is_finite + · exact Set.disjoint_sdiff_left + · apply Set.Finite.sdiff + exact ht.is_finite exact Set.toFinite {a, b} - rw [pair] at union rw [equal] at union - dsimp [ht'] - have : (ht.atlas \ { a, b } : Set _).ncard = (ht.atlas).ncard - 2 := by rw [union] exact rfl - - have t : (ht.atlas \ {a, b} ∪ {f.toOpenPartialHomeomorph}).ncard ≤ (ht.atlas \ { a, b } : Set _).ncard + ({f.toOpenPartialHomeomorph} : Set _).ncard := by + have t : (ht.atlas \ {a, b} ∪ {f.toOpenPartialHomeomorph}).ncard ≤ (ht.atlas \ { a, b } : + Set _).ncard + ({f.toOpenPartialHomeomorph} : Set _).ncard := by apply Set.ncard_union_le - rw [this] at t simp only [Set.ncard_singleton] at t - have t' : ht.atlas.ncard - 2 + 1 ≤ ht.atlas.ncard - 1 := by have nonzero : ht.atlas.ncard ≥ 2 := by rw [←pair] apply Set.ncard_le_ncard - exact Set.pair_subset ha hb + · exact Set.pair_subset ha hb exact ht.is_finite - ring_nf apply Nat.one_add_le_iff.mpr exact Nat.sub_succ_lt_self ht.atlas.ncard 1 nonzero @@ -169,67 +167,62 @@ lemma nonempty_atlas (ht : FinitelyIntervalChartedSpace M) : ht.atlas.Nonempty : exfalso exact nonempty (Set.nonempty_of_mem hc) -lemma more_than_one_chart [CompactSpace M] (ht : FinitelyIntervalChartedSpace M) : Nat.card ht.atlas > 1 := by +lemma more_than_one_chart [CompactSpace M] (ht : FinitelyIntervalChartedSpace M) : Nat.card + ht.atlas > 1 := by have z := (ConnectedSpace.toNonempty : Nonempty M).some let φ := ht.chartAt z - have nonempty := nonempty_atlas ht - have hzero : Nat.card ht.atlas > 0 := by refine (Set.natCard_pos ?_).mpr nonempty exact ht.is_finite by_contra htwo have hone : Nat.card ht.atlas = 1 := by linarith - have he : ∃ (a : OpenPartialHomeomorph M NNReal), ht.atlas = { a } := Set.ncard_eq_one.mp hone rcases he with ⟨a,ha⟩ - have : φ ∈ ht.atlas := ChartedSpace.chart_mem_atlas z rw [ha] at this have hφa : φ = a := by exact this - have h : a.source = Set.univ := by ext x apply Iff.intro · exact fun _ => trivial · intro hx let c := ht.chartAt x - have : c ∈ ht.atlas := ht.chart_mem_atlas x have : c = a := by rw [ha] at this exact this rw [←this] exact ht.mem_chart_source x - -- a.source is homeo to a.target which is not compact have notcompactφ : ¬ CompactSpace (φ.target) := by apply noncompact_target - exact ChartedSpace.chart_mem_atlas z + · exact ChartedSpace.chart_mem_atlas z exact ChartedSpace.mem_chart_source z have notcompact : ¬ CompactSpace (a.target) := by rwa [←hφa] - exfalso apply notcompact refine isCompact_iff_compactSpace.mp ?_ - have : a.target = a.toFun '' a.source := Eq.symm (PartialEquiv.image_source_eq_target a.toPartialEquiv) + have : a.target = a.toFun '' a.source := Eq.symm (PartialEquiv.image_source_eq_target + a.toPartialEquiv) rw [this] apply IsCompact.image_of_continuousOn · rw [h] exact CompactSpace.isCompact_univ · exact a.continuousOn_toFun -lemma find_overlap [CompactSpace M] (ht : FinitelyIntervalChartedSpace M) {a : OpenPartialHomeomorph M NNReal} +lemma find_overlap [CompactSpace M] (ht : FinitelyIntervalChartedSpace M) {a : + OpenPartialHomeomorph M NNReal} (ha : a ∈ ht.atlas) {x : M} (hx : x ∈ a.source) (contains : ∀ c ∈ ChartedSpace.atlas \ {a}, ¬ a.source ⊆ c.source) : ∃ (b : OpenPartialHomeomorph M NNReal), (b ∈ ht.atlas \ {a}) ∧ (Overlap a.source b.source) := by by_contra h push Not at h - have ho : IsOpen a.source := a.open_source have hc : IsClosed a.source := by - have comp : a.sourceᶜ = ⋃ (b ∈ { c ∈ ChartedSpace.atlas \ {a} | ¬ (c.source ⊆ a.source) }), b.source := by + have comp : a.sourceᶜ = ⋃ (b ∈ { c ∈ ChartedSpace.atlas \ {a} | ¬ (c.source ⊆ a.source) + }), b.source := by ext z apply Iff.intro · intro hz @@ -239,12 +232,11 @@ lemma find_overlap [CompactSpace M] (ht : FinitelyIntervalChartedSpace M) {a : O simp only [chart_mem_atlas, true_and, mem_chart_source, and_true] by_contra hza push Not at hza - apply hz apply hza - by_contra hc - rw [←hc] at hz - simp only [Set.mem_compl_iff, mem_chart_source, not_true_eq_false] at hz + · by_contra hc + rw [←hc] at hz + simp only [Set.mem_compl_iff, mem_chart_source, not_true_eq_false] at hz exact ChartedSpace.mem_chart_source z · intro hz simp only [Set.mem_compl_iff] @@ -252,10 +244,8 @@ lemma find_overlap [CompactSpace M] (ht : FinitelyIntervalChartedSpace M) {a : O simp only [Set.mem_sdiff, Set.mem_singleton_iff, Set.mem_iUnion, exists_prop] at hz rcases hz with ⟨ i, ⟨ ⟨ hia, hia' ⟩, his ⟩, hzi ⟩ specialize h i - have hic : i ∈ ChartedSpace.atlas \ {a} := Set.mem_sdiff_of_mem hia hia' specialize h hic - apply h apply does_overlap · use z @@ -263,53 +253,47 @@ lemma find_overlap [CompactSpace M] (ht : FinitelyIntervalChartedSpace M) {a : O tauto · exact contains i hic · exact his - refine { isOpen_compl := ?_ } rw [comp] apply isOpen_biUnion exact fun i a => i.open_source - have hco : IsClopen a.source := ⟨hc, ho⟩ have he : IsPreconnected (Set.univ : Set M) := isPreconnected_univ - have he' := he.subset_isClopen hco - have hn : (Set.univ ∩ a.source).Nonempty := by apply Set.inter_nonempty.mpr use x exact (Set.mem_ite_empty_right (x ∈ Set.univ) a.source x).mp hx have h' := he' hn - have hs : a.source ⊆ Set.univ := by exact fun ⦃a_1⦄ a => trivial - have he : a.source = Set.univ := Set.eq_univ_of_univ_subset (he' hn) - have hcpct : ¬ CompactSpace a.target := by apply noncompact_target - exact ha + · exact ha exact hx - apply hcpct - refine isCompact_iff_compactSpace.mp ?_ - have : a.target = a.toFun '' a.source := Eq.symm (PartialEquiv.image_source_eq_target a.toPartialEquiv) + have : a.target = a.toFun '' a.source := Eq.symm (PartialEquiv.image_source_eq_target + a.toPartialEquiv) rw [this] rw [he] - have hcpctM : IsCompact (Set.univ : Set M) := CompactSpace.isCompact_univ refine IsCompact.image_of_continuousOn hcpctM ?_ rw [←he] exact a.continuousOn_toFun -noncomputable def classification' [T2Space M] [CompactSpace M] (ht : FinitelyIntervalChartedSpace M) : (Homeomorph M Circle) ⊕ (Homeomorph M UnitInterval) := by +/-- Classify a compact connected Hausdorff one-manifold using induction on a finite interval +atlas. -/ +noncomputable def classification' [T2Space M] [CompactSpace M] (ht : + FinitelyIntervalChartedSpace M) : (Homeomorph M Circle) ⊕ (Homeomorph M UnitInterval) := by -- instead, use the fact that M is nonempty and then use chartat have x := (ConnectedSpace.toNonempty : Nonempty M).some let φ := ht.chartAt x - have nonempty := nonempty_atlas ht --let φ := nonempty.some by_cases nonempty' : (ht.atlas \ {φ}).Nonempty - · by_cases contains : ∃ (ψ : OpenPartialHomeomorph M NNReal), (ψ ∈ ht.atlas \ {φ}) ∧ (φ.source ⊆ ψ.source) + · by_cases contains : ∃ (ψ : OpenPartialHomeomorph M NNReal), (ψ ∈ ht.atlas \ {φ}) ∧ + (φ.source ⊆ ψ.source) · let ψ := contains.choose let hψ := contains.choose_spec have hψ' : ψ ∈ ht.atlas := by @@ -323,11 +307,13 @@ noncomputable def classification' [T2Space M] [CompactSpace M] (ht : FinitelyInt rw [←hd] at this have this' : φ ∉ ChartedSpace.atlas \ {φ} := by exact Set.notMem_sdiff_of_mem rfl exact this' this - have ⟨ ht', ht'' ⟩ := subsume_charts ht (ChartedSpace.chart_mem_atlas x) hψ' this hd + have ⟨ ht', ht'' ⟩ := subsumeCharts ht (ChartedSpace.chart_mem_atlas x) hψ' this hd exact classification' ht' - · have : ∃ (ψ : OpenPartialHomeomorph M NNReal), (ψ ∈ ht.atlas \ {φ}) ∧ (Overlap φ.source ψ.source) := by + · have : ∃ (ψ : OpenPartialHomeomorph M NNReal), (ψ ∈ ht.atlas \ {φ}) ∧ (Overlap φ.source + ψ.source) := by simp only [not_exists, not_and] at contains - exact find_overlap ht (ChartedSpace.chart_mem_atlas x) (ChartedSpace.mem_chart_source x) contains + exact find_overlap ht (ChartedSpace.chart_mem_atlas x) (ChartedSpace.mem_chart_source + x) contains let ψ := this.choose let ⟨ hψ, overlap ⟩ := this.choose_spec have hφ := ht.is_interval φ (ChartedSpace.chart_mem_atlas x) @@ -337,47 +323,48 @@ noncomputable def classification' [T2Space M] [CompactSpace M] (ht : FinitelyInt · -- the O O case let a : OChart M := { φ with target_ioo := hφIoo } let b : OChart M := { ψ with target_ioo := hψIoo } - let result := handle_o_o a b overlap + let result := handleOO a b overlap rcases result with (result|result) · left exact result · rcases result with ⟨ f, hf ⟩ let f := f.toIChart - have ⟨ ht', ht'' ⟩ := replace_charts ht (ChartedSpace.chart_mem_atlas x) (Set.mem_of_mem_sdiff hψ) overlap f hf + have ⟨ ht', ht'' ⟩ := replaceCharts ht (ChartedSpace.chart_mem_atlas x) + (Set.mem_of_mem_sdiff hψ) overlap f hf simp only [Set.mem_ofPred_eq] at ht'' exact classification' ht' - · have hψIio : ∃ x, Set.Iio x = ψ.target := Or.elim hψ'' (fun x => False.elim (hψIoo x)) id + · have hψIio : ∃ x, Set.Iio x = ψ.target := Or.elim hψ'' (fun x => False.elim (hψIoo + x)) id -- an O H case let a : OChart M := { φ with target_ioo := hφIoo } let b : HChart M := { ψ with target_iio := hψIio } - let result := handle_o_h a b overlap - + let result := handleOH a b overlap rcases result with ⟨ f, hf ⟩ let f := f.toIChart - have ⟨ ht', ht'' ⟩ := replace_charts ht (ChartedSpace.chart_mem_atlas x) (Set.mem_of_mem_sdiff hψ) overlap f hf + have ⟨ ht', ht'' ⟩ := replaceCharts ht (ChartedSpace.chart_mem_atlas x) + (Set.mem_of_mem_sdiff hψ) overlap f hf simp only [Set.mem_ofPred_eq] at ht'' exact classification' ht' - · have hφIio : ∃ x, Set.Iio x = φ.target := Or.elim hφ (fun x => False.elim (hφIoo x)) id have hψ'' := ht.is_interval ψ (Set.mem_of_mem_sdiff hψ) by_cases hψIoo : ∃ x y, Set.Ioo x y = ψ.target · -- an H O case let a : HChart M := { φ with target_iio := hφIio } let b : OChart M := { ψ with target_ioo := hψIoo } - let result := handle_o_h b a (overlap_symm overlap) - + let result := handleOH b a (overlap_symm overlap) rcases result with ⟨ f, hf ⟩ let f := f.toIChart - have ⟨ ht', ht'' ⟩ := replace_charts ht (Set.mem_of_mem_sdiff hψ) (ChartedSpace.chart_mem_atlas x) (overlap_symm overlap) f hf + have ⟨ ht', ht'' ⟩ := replaceCharts ht (Set.mem_of_mem_sdiff hψ) + (ChartedSpace.chart_mem_atlas x) (overlap_symm overlap) f hf simp only [Set.mem_ofPred_eq] at ht'' exact classification' ht' - - · have hψIio : ∃ x, Set.Iio x = ψ.target := Or.elim hψ'' (fun x => False.elim (hψIoo x)) id + · have hψIio : ∃ x, Set.Iio x = ψ.target := Or.elim hψ'' (fun x => False.elim (hψIoo + x)) id -- the H H case right let a : HChart M := { φ with target_iio := hφIio } let b : HChart M := { ψ with target_iio := hψIio } - exact handle_h_h a b overlap + exact handleHH a b overlap · -- A compact manifold must have more than one chart exfalso apply nonempty' @@ -389,26 +376,25 @@ noncomputable def classification' [T2Space M] [CompactSpace M] (ht : FinitelyInt exact Set.finite_singleton φ have t' := more_than_one_chart ht linarith - termination_by Set.ncard ht.atlas -decreasing_by · simp at ht'' - rw [ht''] - simp only [tsub_lt_self_iff, zero_lt_one, and_true] - exact (Set.natCard_pos (ht.is_finite)).mpr (nonempty_atlas ht) - · simp at ht'' - refine Nat.lt_of_le_pred ?_ ht'' - refine (Set.natCard_pos ?_).mpr nonempty - exact ht.is_finite - · simp at ht'' - refine Nat.lt_of_le_pred ?_ ht'' - refine (Set.natCard_pos ?_).mpr nonempty - exact ht.is_finite - · simp at ht'' - refine Nat.lt_of_le_pred ?_ ht'' - refine (Set.natCard_pos ?_).mpr nonempty - exact ht.is_finite - -noncomputable def classification [T2Space M] [CompactSpace M] (ht : ChartedSpace NNReal M) : (Homeomorph M Circle) ⊕ (Homeomorph M UnitInterval) := - let ht' := nicely_charted ht - let ht'' := interval_charted ht' - classification' (finitely_interval_charted ht'') +decreasing_by + · simp only [Nat.card_coe_set_eq, Set.mem_ofPred_eq] at ht'' + rw [ht''] + simp only [tsub_lt_self_iff, zero_lt_one, and_true] + exact (Set.natCard_pos ht.is_finite).mpr (nonempty_atlas ht) + · simp only [Nat.card_coe_set_eq, Set.mem_ofPred_eq] at ht'' + refine Nat.lt_of_le_pred ?_ ht'' + exact (Set.natCard_pos ht.is_finite).mpr nonempty + · simp only [Nat.card_coe_set_eq, Set.mem_ofPred_eq] at ht'' + refine Nat.lt_of_le_pred ?_ ht'' + exact (Set.natCard_pos ht.is_finite).mpr nonempty + · simp only [Nat.card_coe_set_eq, Set.mem_ofPred_eq] at ht'' + refine Nat.lt_of_le_pred ?_ ht'' + exact (Set.natCard_pos ht.is_finite).mpr nonempty + +/-- A compact connected Hausdorff manifold charted on the half-line is a circle or an interval. -/ +noncomputable def classification [T2Space M] [CompactSpace M] (ht : ChartedSpace NNReal M) : + (Homeomorph M Circle) ⊕ (Homeomorph M UnitInterval) := + let ht' := nicelyCharted ht + let ht'' := intervalCharted ht' + classification' (finitelyIntervalCharted ht'') diff --git a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean index 20dac5747e..b7d2b02594 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean @@ -3,7 +3,17 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Algebra.Order.Star.Real +import Mathlib.Analysis.InnerProductSpace.Basic +import Mathlib.Analysis.SpecialFunctions.Log.Basic +import Mathlib.Order.CompletePartialOrder +import Mathlib.Tactic + +/-! +# ClassifyInterval + +Supporting results for the classification of compact one-dimensional manifolds. +-/ open Function open Set @@ -21,11 +31,10 @@ theorem iic_cap_ioi_empty (y : Real) : (Iic y ∩ Ioi y) = ∅ := by theorem not_ici (U : Set Real) (y : Real) (hu : IsOpen U) : (Ici y ≠ U) := by by_contra h rw [←h] at hu - have h''' : IsClosed (Ici y) := by apply isClosed_Ici have ho : IsOpen (Ici y)ᶜ - exact IsClosed.isOpen_compl + · exact IsClosed.isOpen_compl have hr : IsPreconnected (univ : Set Real) := isPreconnected_univ let hr' := hr (Ici y) ((Ici y)ᶜ) hu ho have huniv : Ici y ∪ (Ici y)ᶜ = univ := union_compl_self (Ici y) @@ -38,11 +47,10 @@ theorem not_ici (U : Set Real) (y : Real) (hu : IsOpen U) : (Ici y ≠ U) := by theorem not_iic (U : Set Real) (y : Real) (hu : IsOpen U) : (Iic y ≠ U) := by by_contra h rw [←h] at hu - have h''' : IsClosed (Iic y) := by apply isClosed_Iic have ho : IsOpen (Iic y)ᶜ - exact IsClosed.isOpen_compl + · exact IsClosed.isOpen_compl have hr : IsPreconnected (univ : Set Real) := isPreconnected_univ let hr' := hr (Iic y) ((Iic y)ᶜ) hu ho have huniv : Iic y ∪ (Iic y)ᶜ = univ := union_compl_self (Iic y) @@ -54,32 +62,29 @@ theorem not_iic (U : Set Real) (y : Real) (hu : IsOpen U) : (Iic y ≠ U) := by lemma ioc_not_open (x y : Real) (hxy : x < y) : ¬ IsOpen (Ioc x y) := by have hu : (Ioc x y) ∪ (Iio y) = (Iic y) - ext p - simp only [mem_union, mem_Ioc, mem_Iio, mem_Iic] - apply Iff.intro - intro h - rcases h with (h1|h2) - tauto - exact le_of_lt h2 - by_cases hp : p = y - intro h - rw [hp] - simp only [le_refl, and_true, lt_self_iff_false, or_false] - exact hxy - intro h - right - exact lt_of_le_of_ne h hp - + · ext p + simp only [mem_union, mem_Ioc, mem_Iio, mem_Iic] + apply Iff.intro + · intro h + rcases h with (h1|h2) + · tauto + · exact le_of_lt h2 + by_cases hp : p = y + · intro h + rw [hp] + simp only [le_refl, and_true, lt_self_iff_false, or_false] + exact hxy + intro h + right + exact lt_of_le_of_ne h hp by_contra hopen have hopen' : IsOpen (Iio y) := isOpen_Iio have hopen'' : IsOpen (Iic y) - rw [←hu] - exact IsOpen.union hopen hopen' - + · rw [←hu] + exact IsOpen.union hopen hopen' have hc : IsOpen ((Iic y)ᶜ) - simp only [compl_Iic] - exact isOpen_Ioi - + · simp only [compl_Iic] + exact isOpen_Ioi have hcon := isPreconnected_univ (Iic y) ((Iic y)ᶜ) hopen'' hc (by simp only [compl_Iic, Iic_union_Ioi, subset_refl]) (by simp only [univ_inter, nonempty_Iic]) @@ -89,49 +94,41 @@ lemma ioc_not_open (x y : Real) (hxy : x < y) : ¬ IsOpen (Ioc x y) := by simp at hx linarith -lemma ico_not_open (x y : Real) (hxy : x < y) : ¬ IsOpen (Ico x y) := by +lemma ico_not_open (x y : Real) (hxy : x < y) : ¬ IsOpen (Ico x y) := by have hxy' : -y < -x := neg_lt_neg_iff.mpr hxy have hn := ioc_not_open (-y) (-x) hxy' - let f : Real → Real := fun x => - x let fb : Bijective f := ⟨ neg_injective, neg_surjective ⟩ let fe := Equiv.ofBijective f fb have fc : Continuous fe := continuous_neg have fo : IsOpenMap fe := isOpenMap_neg ℝ have fh : Homeomorph Real Real - apply Equiv.toHomeomorphOfContinuousOpen - exact fc - exact fo - + · apply Equiv.toHomeomorphOfContinuousOpen + · exact fc + exact fo by_contra h - have p := fo (Ico x y) h have he : fe '' (Ico x y) = Ioc (-y) (-x) · ext t - have ht : ∀ s : Real, fe.symm (-s) = s := fun s => Equiv.ofBijective_symm_apply_apply f fb s have ht' := ht (-t) simp only [neg_neg] at ht' - simp only [mem_image_equiv, mem_Ico, mem_Ioc] apply Iff.intro - simp only [and_imp] - intro h1 - intro h2 - constructor - rw [ht'] at h1 - rw [ht'] at h2 - linarith - - rw [ht'] at h1 - rw [ht'] at h2 - linarith - + · simp only [and_imp] + intro h1 h2 + constructor + · rw [ht'] at h1 + rw [ht'] at h2 + linarith + rw [ht'] at h1 + rw [ht'] at h2 + linarith simp only [and_imp] intro h1 h2 rw [ht'] constructor - linarith + · linarith linarith · rw [he] at p exact hn p @@ -140,68 +137,67 @@ lemma icc_not_open (x y : Real) (hxy : x < y) : ¬ IsOpen (Icc x y) := by by_contra h have hc : IsClosed (Icc x y) := isClosed_Icc have hc'' : IsOpen ((Icc x y)ᶜ) := IsClosed.isOpen_compl - have hcon := isPreconnected_univ (Icc x y) ((Icc x y)ᶜ) h hc'' (by simp only [union_compl_self, subset_refl]) (by simp only [univ_inter, nonempty_Icc] linarith) (by simp only [univ_inter] have hy : ((y + 1) ∈ (Icc x y)ᶜ) - simp only [mem_compl_iff, mem_Icc, add_le_iff_nonpos_right, not_and, not_le, - zero_lt_one, implies_true] + · simp only [mem_compl_iff, mem_Icc, add_le_iff_nonpos_right, not_and, not_le, + zero_lt_one, implies_true] exact nonempty_of_mem hy) simp only [inter_compl_self, inter_empty, Set.not_nonempty_empty] at hcon lemma not_ioc (U : Set Real) (x y : Real) (hu : IsOpen U) (h : Ioc x y = U) : (U = ∅) := by by_cases hxy : (x < y) · have h' : ¬ IsOpen (Ioc x y) - apply ioc_not_open x y - exact hxy + · apply ioc_not_open x y + exact hxy exfalso apply h' rw [h] tauto · have h' : Ioc x y = ∅ - exact Ioc_eq_empty hxy + · exact Ioc_eq_empty hxy rw [h] at h' tauto theorem not_ico (U : Set Real) (x y : Real) (hu : IsOpen U) (h : Ico x y = U) : (U = ∅) := by by_cases hxy : (x < y) · have h' : ¬ IsOpen (Ico x y) - apply ico_not_open x y - exact hxy + · apply ico_not_open x y + exact hxy exfalso apply h' rw [h] tauto · have h' : Ico x y = ∅ - exact Ico_eq_empty hxy + · exact Ico_eq_empty hxy rw [h] at h' tauto theorem not_icc (U : Set Real) (x y : Real) (hu : IsOpen U) (h : Icc x y = U) : (U = ∅) := by by_cases hxy : (x < y) · have h' : ¬ IsOpen (Icc x y) - apply icc_not_open x y - exact hxy + · apply icc_not_open x y + exact hxy exfalso apply h' rw [h] tauto · by_cases hyx : (x > y) · have h' : Icc x y = ∅ - exact Icc_eq_empty_of_lt hyx + · exact Icc_eq_empty_of_lt hyx rw [h] at h' exact h' · have hxy' : x ≥ y := le_of_not_gt hxy have hyx' : x ≤ y := by exact le_of_not_gt hyx have hxx : x = y - have hxy'' : (x = y) ∨ (y < x) := eq_or_gt_of_not_lt hxy - have hyx'' : (x = y) ∨ (x < y) := by exact Or.symm (Decidable.lt_or_eq_of_le hyx') - rcases hyx'' with (h|h) - exact h - tauto + · have hxy'' : (x = y) ∨ (y < x) := eq_or_gt_of_not_lt hxy + have hyx'' : (x = y) ∨ (x < y) := by exact Or.symm (Decidable.lt_or_eq_of_le hyx') + rcases hyx'' with (h|h) + · exact h + tauto rw [←hxx] at h simp only [Icc_self] at h rw [←h] at hu @@ -214,10 +210,10 @@ theorem classify_intervals (U : Set Real) (hu : IsOpen U) (hc : IsPreconnected U (∃ (x : Real), (U = Set.Iio x)) ∨ (∃ (x : Real), (Set.Ioi x = U)) ∨ (U = univ) ∨ (U = ∅) := by - have h : U ∈ (range (uncurry Icc)) ∪ range (uncurry Ico) ∪ range (uncurry Ioc) ∪ range (uncurry Ioo) ∪ (range Ici ∪ range Ioi ∪ range Iic ∪ range Iio ∪ {univ, ∅}) - rw [←setOfPred_isPreconnected_eq_of_ordered] - simp - exact hc + have h : U ∈ (range (uncurry Icc)) ∪ range (uncurry Ico) ∪ range (uncurry Ioc) ∪ range + (uncurry Ioo) ∪ (range Ici ∪ range Ioi ∪ range Iic ∪ range Iio ∪ {univ, ∅}) + · rw [←setOfPred_isPreconnected_eq_of_ordered] + exact hc simp only [union_insert, union_singleton, mem_insert_iff, mem_union, mem_range, Prod.exists, uncurry_apply_pair] at h cases h @@ -234,33 +230,33 @@ theorem classify_intervals (U : Set Real) (hu : IsOpen U) (hc : IsPreconnected U case inr h => by_contra rcases h with ⟨ x', hx ⟩ apply not_iic - exact hu + · exact hu exact hx case inl h => cases h - case inr h => right ; right ; left ; assumption + case inr h => right; right; left; assumption case inl h => by_contra rcases h with ⟨ x', hx ⟩ apply not_ici - exact hu + · exact hu exact hx case inr h => tauto case inl h => cases h - case inr h => left ; tauto + case inr h => left; tauto case inl h => cases h case inl h => cases h case inl h => rcases h with ⟨ x, y, hx ⟩ - right ; right ; right ; right + right; right; right; right apply not_icc - exact hu + · exact hu exact hx case inr h => rcases h with ⟨ x, y, hx ⟩ - right ; right ; right ; right + right; right; right; right apply not_ico - exact hu + · exact hu exact hx case inr h => rcases h with ⟨ x, y, hx ⟩ right @@ -268,10 +264,11 @@ theorem classify_intervals (U : Set Real) (hu : IsOpen U) (hc : IsPreconnected U right right apply not_ioc - exact hu + · exact hu exact hx -macro "solve_disj" : tactic => `(tactic| repeat (apply Or.inl <|> apply Or.inr)) +/-- Select disjuncts repeatedly to reduce a nested disjunction to one of its branches. -/ +macro "solveDisj" : tactic => `(tactic| repeat (apply Or.inl <|> apply Or.inr)) theorem classify_connected_interval (U : Set Real) (hu : IsOpen U) (hc : IsConnected U) : (∃ x y, (Set.Ioo x y = U)) ∨ @@ -286,14 +283,15 @@ theorem classify_connected_interval (U : Set Real) (hu : IsOpen U) (hc : IsConne have he : (∅ : Set Real).Nonempty := IsConnected.nonempty hc exact Set.not_nonempty_empty he rcases hi with (h|h|h|h|h) - left ; assumption - right ; left ; assumption - right ; right ; left ; assumption - right ; right ; right ; assumption + · left; assumption + · right; left; assumption + · right; right; left; assumption + · right; right; right; assumption exfalso exact ho h -noncomputable def homeo_nnreal_real : (Set.Ioi 0 : Set NNReal) ≃ₜ (Set.univ : Set Real) where +/-- The logarithm homeomorphism from positive nonnegative reals to the real line. -/ +noncomputable def homeoNnrealReal : (Set.Ioi 0 : Set NNReal) ≃ₜ (Set.univ : Set Real) where toFun := fun ⟨x,_⟩ => ⟨ Real.log x, trivial ⟩ invFun := fun ⟨x,_⟩ => ⟨ NNReal.mk (Real.exp x) (Real.exp_nonneg x), Real.exp_pos x ⟩ left_inv := fun ⟨ ⟨ x, nn ⟩, p ⟩ => by @@ -306,7 +304,7 @@ noncomputable def homeo_nnreal_real : (Set.Ioi 0 : Set NNReal) ≃ₜ (Set.univ simp only refine Continuous.subtype_mk ?_ fun x => trivial refine Continuous.log ?_ ?_ - exact Isometry.continuous fun x1 => congrFun rfl + · exact Isometry.continuous fun x1 => congrFun rfl intro x rcases x with ⟨x,hx⟩ simp only [ne_eq, NNReal.coe_eq_zero] @@ -318,6 +316,7 @@ noncomputable def homeo_nnreal_real : (Set.Ioi 0 : Set NNReal) ≃ₜ (Set.univ apply Continuous.rexp exact continuous_subtype_val +/-- Truncate a real number at zero and regard the result as a nonnegative real. -/ def relu (x : ℝ) : NNReal := NNReal.mk (max x 0) (by simp) @@ -329,7 +328,7 @@ lemma relu_zero : (relu 0 = 0) := by theorem continuous_relu : Continuous relu := by apply Continuous.subtype_mk apply Continuous.max - exact continuous_id' + · exact continuous_id' exact continuous_const @@ -357,7 +356,6 @@ lemma relu_mono : StrictMonoOn relu (Set.Ici 0) := by simp only [mem_Ici] at hx simp only [mem_Ici] at hy apply NNReal.coe_lt_coe.mp - by_cases hx0 : x = 0 · rw [hx0] simp only [NNReal.coe_lt_coe] @@ -400,7 +398,6 @@ lemma relu_interval_ioo {U : Set NNReal} {a b : Real} (h : Ioo a b = relu ⁻¹' simp only [NNReal.val_eq_coe] rw [relu_proj] simp only [and_true] - by_cases h0 : 0 ∈ U · have hneg : ¬ BddBelow (relu ⁻¹' U) := by by_contra hneg @@ -462,7 +459,7 @@ theorem StrictMonoOn.injOn_Ioo {α : Type u_1} {β : Type u_2} {f : α → β} · have hyx' : x ≤ y := le_of_not_gt hyx have hxy' : y ≤ x := le_of_not_gt hxy apply le_antisymm - assumption + · assumption assumption lemma relu_ioo (a b : Real) : @@ -480,16 +477,16 @@ lemma relu_ioo (a b : Real) : have hax : relu a < relu x := by apply NNReal.coe_lt_coe.mp rw [proj_relu] - rw [proj_relu] - exact hx.1 - linarith + · rw [proj_relu] + · exact hx.1 + linarith linarith have hxb : relu x < relu b := by apply NNReal.coe_lt_coe.mp rw [proj_relu] - rw [proj_relu] - exact hx.2 - linarith + · rw [proj_relu] + · exact hx.2 + linarith linarith rw [hxz] at hax rw [hxz] at hxb @@ -501,9 +498,9 @@ lemma relu_ioo (a b : Real) : have haz' : NNReal.toReal (relu a) < NNReal.toReal z := by exact haz have hzb' : NNReal.toReal z < NNReal.toReal (relu b) := by exact hzb rw [proj_relu] at hzb' - rw [proj_relu] at haz' - exact ⟨haz', hzb'⟩ - exact ha + · rw [proj_relu] at haz' + · exact ⟨haz', hzb'⟩ + exact ha exact hb · have : Ioo a b = ∅ := by ext z @@ -526,15 +523,15 @@ lemma relu_ioo (a b : Real) : · rw [relu_zero] have : 0 < NNReal.toReal (relu y) := by rw [proj_relu] - assumption + · assumption linarith simp only [gt_iff_lt] exact this · have : NNReal.toReal (relu y) < NNReal.toReal (relu b) := by rw [proj_relu] - rw [proj_relu] - assumption - linarith + · rw [proj_relu] + · assumption + linarith linarith exact this · intro ⟨ h0z, hzb ⟩ @@ -546,7 +543,7 @@ lemma relu_ioo (a b : Real) : · have : NNReal.toReal z < NNReal.toReal (relu b) := by exact hzb exact Real.lt_toNNReal_iff_coe_lt.mp hzb · exact relu_proj - · right ; left + · right; left ext z simp only [mem_image, mem_Ioo, mem_Ico, zero_le, true_and] apply Iff.intro @@ -570,7 +567,7 @@ lemma relu_ioo (a b : Real) : assumption · have : NNReal.toReal z < NNReal.toReal (relu b) := by exact hzb rw [proj_relu] at this - assumption + · assumption assumption · rw [relu_proj] · by_cases hab : a ≥ b @@ -578,7 +575,7 @@ lemma relu_ioo (a b : Real) : exact Ioo_eq_empty_of_le hab rw [this] simp only [image_empty, or_true] - · right ; right ; left + · right; right; left ext z simp only [mem_image, mem_Ioo, mem_singleton_iff] constructor @@ -659,8 +656,8 @@ lemma relu_ioi (b : Real) : rw [←hxz] apply NNReal.coe_lt_coe.mp rw [proj_relu, proj_relu] - linarith - linarith + · linarith + · linarith linarith · intro hbz use z.1 @@ -680,13 +677,13 @@ lemma relu_ioi (b : Real) : rw [←hxz] apply NNReal.coe_pos.mp rw [proj_relu] - assumption + · assumption assumption · intro hz use z.1 apply And.intro - rw [relu_zero] at hz - exact hz + · rw [relu_zero] at hz + exact hz apply relu_proj · right ext z @@ -701,7 +698,8 @@ lemma relu_ioi (b : Real) : exact lt_of_le_of_lt' this this' · exact relu_proj -lemma a_and_b (U : Set NNReal) (ε : Real) (εpos : ε > 0) (A : Set NNReal) (B : Set NNReal) (openA : IsOpen A) (openB : IsOpen B) +lemma a_and_b (U : Set NNReal) (ε : Real) (εpos : ε > 0) (A : Set NNReal) (B : Set NNReal) + (openA : IsOpen A) (openB : IsOpen B) (hp : IsPreconnected U) (interval : Set NNReal) (interval_def : interval = Set.Ioo (0 : NNReal) (NNReal.mk ε (by linarith))) @@ -709,7 +707,6 @@ lemma a_and_b (U : Set NNReal) (ε : Real) (εpos : ε > 0) (A : Set NNReal) (B (empty : ¬ (interval ∩ B).Nonempty) (hA : (U \ {0} ∩ A).Nonempty) (hB : (U \ {0} ∩ B).Nonempty) (hAB : U \ {0} ⊆ A ∪ B) : (U \ {0} ∩ (A ∩ B)).Nonempty := by - let interval' := Set.Iio (NNReal.mk ε (by linarith)) let A' := A ∪ interval' have openA' : IsOpen A' := by @@ -762,18 +759,15 @@ lemma a_and_b (U : Set NNReal) (ε : Real) (εpos : ε > 0) (A : Set NNReal) (B have : x ∈ U \ { 0 } := by exact mem_of_mem_inter_left hx have this' : x ∉ ({ 0 } : Set NNReal) := by exact notMem_of_mem_sdiff this exact pos_iff_ne_zero.mpr this' - specialize hp h1 h2 h3 rcases hp with ⟨ x, hx ⟩ use x simp only [mem_inter_iff, mem_sdiff, mem_singleton_iff] - have hn0 : x ≠ 0 := by have : x ∈ A' ∩ B' := by exact mem_of_mem_inter_right hx have : x ∈ B' := by exact mem_of_mem_inter_right this have : x ∈ Set.Ioi 0 := by exact mem_of_mem_inter_right this exact pos_iff_ne_zero.mp this - apply And.intro · apply And.intro · exact mem_of_mem_inter_left hx @@ -834,7 +828,6 @@ lemma remove_zero_connected (U : Set NNReal) (h0 : 0 ∈ U) (hu : IsOpen U) (hc simp only [not_forall] at h rcases h with ⟨ A, B, openA, openB, hAB, hA, hB, hn ⟩ have hp : IsPreconnected U := IsConnected.isPreconnected hc - let interval := Set.Ioo (0 : NNReal) (NNReal.mk ε (by linarith)) have h1' : interval ⊆ A ∪ B := by intro x hx @@ -850,10 +843,8 @@ lemma remove_zero_connected (U : Set NNReal) (h0 : 0 ∈ U) (hu : IsOpen U) (hc · by_contra h0 rw [h0] at hx simp only [interval, mem_Ioo, lt_self_iff_false, false_and] at hx - have cb : IsPreconnected interval := isPreconnected_Ioo specialize cb A B openA openB h1' - have iu : interval ⊆ U := by intro x hx simp only [interval, mem_Ioo] at hx @@ -862,7 +853,6 @@ lemma remove_zero_connected (U : Set NNReal) (h0 : 0 ∈ U) (hu : IsOpen U) (hc rw [NNReal.dist_eq] simp only [NNReal.coe_zero, sub_zero, NNReal.abs_eq] exact hx.right - have hn' : ¬ (interval ∩ (A ∩ B)).Nonempty := by by_contra hn'' rcases hn'' with ⟨ x, hn'' ⟩ @@ -880,7 +870,6 @@ lemma remove_zero_connected (U : Set NNReal) (h0 : 0 ∈ U) (hu : IsOpen U) (hc rw [x0] at this simp only [interval, mem_Ioo, lt_self_iff_false, false_and] at this · exact mem_of_mem_inter_right hn'' - have empty : (¬ (interval ∩ A).Nonempty ∨ ¬ (interval ∩ B).Nonempty) := by tauto apply hn rcases empty with (empty|empty) @@ -944,7 +933,7 @@ lemma zero_in_open (a b : NNReal) (h : IsOpen ((Ioo a b) ∪ {0})) : a ≤ 0 ∧ · rw [hx] have : 0 < a := by exact pos_iff_ne_zero.mpr ha exact half_pos this - · left ; assumption + · left; assumption have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 apply this rwa [U0] at openU' @@ -956,9 +945,7 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc (U = univ) := by let U0 := U ∩ (Set.Ioi 0) have hu0 : IsOpen U0 := IsOpen.inter hu isOpen_Ioi - let U' := relu ⁻¹' U0 - have hr : (relu ⁻¹' U0) = (Set.Ioi (0 : Real)) ∩ (NNReal.toReal '' U) := by ext x simp only [mem_preimage, mem_inter_iff, mem_Ioi, mem_image] @@ -984,9 +971,7 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc apply mem_inter hu rw [←hy] at h1 exact h1 - have hu' : IsOpen U' := Continuous.isOpen_preimage continuous_relu U0 hu0 - have hc' : IsConnected U' := by by_cases h0 : 0 ∈ U · dsimp [U'] @@ -1044,21 +1029,17 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc have : Continuous NNReal.toReal := by exact NNReal.continuous_coe apply Continuous.continuousOn assumption - let c := classify_connected_interval U' hu' hc' - have h0u0 : 0 ∉ U0 := by apply zero_notMem_iff.mpr intro z hz have : z ∈ Set.Ioi (0 : NNReal) := mem_of_mem_inter_right hz exact this - have h0u' : 0 ∉ U' := by dsimp [U'] simp only [mem_preimage] rw [relu_zero] assumption - rcases c with (c|c|c|c) · rcases c with ⟨ a, b, c ⟩ have c' := relu_ioo a b @@ -1073,8 +1054,8 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc dsimp [U0] simp only [mem_inter_iff, mem_Ioi] by_cases h : x = 0 - · left ; exact h - · right ; apply And.intro + · left; exact h + · right; apply And.intro · assumption · exact pos_iff_ne_zero.mpr h · intro hx @@ -1098,7 +1079,7 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc apply Iff.intro · intro hx by_cases h0 : x = 0 - · left ; exact h0 + · left; exact h0 · right apply And.intro · have : 0 < x := by exact pos_iff_ne_zero.mpr h0 @@ -1182,7 +1163,7 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc · rcases c with ⟨ x, c ⟩ by_cases h0 : x = 0 · by_cases hu0 : 0 ∈ U - · right ; right ; right + · right; right; right rw [h0] at c dsimp [U'] at c ext z @@ -1200,7 +1181,7 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc simp only [mem_preimage] at zi' rw [relu_proj] at zi' exact mem_of_mem_inter_left zi' - · right ; right ; left + · right; right; left use 0 have uu0 : U = U0 := by ext z @@ -1240,7 +1221,7 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc assumption exfalso exact h0u' this - · right ; right ; left + · right; right; left by_cases hu0 : 0 ∈ U · have : U = U0 ∪ {0} := by ext z @@ -1248,7 +1229,7 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc apply Iff.intro · intro hz by_cases hz' : z = 0 - · left ; assumption + · left; assumption · right dsimp [U0] refine (mem_inter_iff z U (Ioi 0)).mpr ?_ @@ -1263,7 +1244,6 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc · exact mem_of_mem_inter_left hz dsimp [U'] at c rw [hr] at c - have contra : ¬ IsConnected U := by dsimp [IsConnected] simp only [not_and] diff --git a/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean b/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean index 170bbebfb4..9e15c273dd 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean @@ -3,7 +3,8 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Analysis.SpecialFunctions.Complex.Circle +import Mathlib.Tactic import LeanPool.OneManifold.OneMfld.UnitInterval import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts import LeanPool.OneManifold.OneMfld.IntervalCharts @@ -23,6 +24,12 @@ import LeanPool.OneManifold.OneMfld.TwoComponents import LeanPool.OneManifold.OneMfld.CircleBlocks import LeanPool.OneManifold.OneMfld.CircleGlue +/-! +# ClassifyOverlaps + +Supporting results for the classification of compact one-dimensional manifolds. +-/ + open Set variable @@ -45,14 +52,14 @@ noncomputable def Homeomorph.toOpenPartialHomeomorphOnOpens invFun y := if hy : y ∈ B then (h.symm ⟨y, hy⟩ : X) else Classical.arbitrary X source := A target := B - map_source' x hx := by simp only [dif_pos hx]; exact (h ⟨x, hx⟩).2 - map_target' y hy := by simp only [dif_pos hy]; exact (h.symm ⟨y, hy⟩).2 + map_source' x hx := by simp only [dite_eq_left hx]; exact (h ⟨x, hx⟩).2 + map_target' y hy := by simp only [dite_eq_left hy]; exact (h.symm ⟨y, hy⟩).2 left_inv' x hx := by - simp only [dif_pos hx, dif_pos (h ⟨x, hx⟩).2] + simp only [dite_eq_left hx, dite_eq_left (h ⟨x, hx⟩).2] have : (⟨(h ⟨x, hx⟩ : Y), (h ⟨x, hx⟩).2⟩ : B) = h ⟨x, hx⟩ := rfl rw [this, Homeomorph.symm_apply_apply] right_inv' y hy := by - simp only [dif_pos hy, dif_pos (h.symm ⟨y, hy⟩).2] + simp only [dite_eq_left hy, dite_eq_left (h.symm ⟨y, hy⟩).2] have : (⟨(h.symm ⟨y, hy⟩ : X), (h.symm ⟨y, hy⟩).2⟩ : A) = h.symm ⟨y, hy⟩ := rfl rw [this, Homeomorph.apply_symm_apply] open_source := hA @@ -61,14 +68,15 @@ noncomputable def Homeomorph.toOpenPartialHomeomorphOnOpens rw [continuousOn_iff_continuous_domRestrict] have : (A.domRestrict fun x => if hx : x ∈ A then (h ⟨x, hx⟩ : Y) else Classical.arbitrary Y) = fun x : A => ((h x : B) : Y) := by - funext x; simp only [Set.domRestrict_apply, dif_pos x.2] + funext x; simp only [Set.domRestrict_apply, dite_eq_left x.2] rw [this] exact continuous_subtype_val.comp h.continuous continuousOn_invFun := by rw [continuousOn_iff_continuous_domRestrict] - have : (B.domRestrict fun y => if hy : y ∈ B then (h.symm ⟨y, hy⟩ : X) else Classical.arbitrary X) + have : (B.domRestrict fun y => if hy : y ∈ B then (h.symm ⟨y, hy⟩ : X) else + Classical.arbitrary X) = fun y : B => ((h.symm y : A) : X) := by - funext y; simp only [Set.domRestrict_apply, dif_pos y.2] + funext y; simp only [Set.domRestrict_apply, dite_eq_left y.2] rw [this] exact continuous_subtype_val.comp h.symm.continuous @@ -295,13 +303,15 @@ lemma exists_glue_h_h (a : HChart M) (b : HChart M) (h : Overlap a.source b.sour rw [hfs, ha's, hb's] /-- Glue two overlapping H-charts into a single chart of `M` onto the unit interval. -/ -noncomputable def glue_h_h (a : HChart M) (b : HChart M) (h : Overlap a.source b.source) : - { φ : OpenPartialHomeomorph M UnitInterval | φ.source = a.source ∪ b.source ∧ φ.target = Set.univ } := +noncomputable def glueHH (a : HChart M) (b : HChart M) (h : Overlap a.source b.source) : + { φ : OpenPartialHomeomorph M UnitInterval | φ.source = a.source ∪ b.source ∧ φ.target = + Set.univ } := ⟨(exists_glue_h_h a b h).choose, (exists_glue_h_h a b h).choose_spec⟩ -noncomputable def handle_h_h (a : HChart M) (b : HChart M) (h : Overlap a.source b.source) : +/-- Join overlapping boundary charts into a homeomorphism with the closed unit interval. -/ +noncomputable def handleHH (a : HChart M) (b : HChart M) (h : Overlap a.source b.source) : Homeomorph M UnitInterval := by - obtain ⟨φ, hφ, hs⟩ := glue_h_h a b h + obtain ⟨φ, hφ, hs⟩ := glueHH a b h have hne : φ.source.Nonempty := by rw [hφ] exact Set.Nonempty.inl (h.1.mono Set.inter_subset_left) @@ -349,25 +359,25 @@ lemma exists_glue_o_h (a : OChart M) (b : HChart M) (h : Overlap a.source b.sour inter_eq_right.mpr (fun y hy => lt_of_le_of_lt hy hμ1) rw [h1, Iic_union_Ioo_eq_Iio hμν] refine ⟨⟨f, ⟨μ / ρ, htarget.symm⟩⟩, ?_⟩ - show f.source = a.source ∪ b.source + change f.source = a.source ∪ b.source rw [hfs, ha's', hb's] /-- Glue an O-chart and an H-chart with connected overlap into an H-chart on the union. -/ -noncomputable def handle_o_h' (a : OChart M) (b : HChart M) (h : Overlap a.source b.source) +noncomputable def handleOH' (a : OChart M) (b : HChart M) (h : Overlap a.source b.source) (hc : IsConnected (a.source ∩ b.source)) : { f : HChart M | f.source = a.source ∪ b.source } := ⟨(exists_glue_o_h a b h hc).choose, (exists_glue_o_h a b h hc).choose_spec⟩ /-- Glue an O-chart and an H-chart: the overlap with an H-chart is automatically connected. -/ -noncomputable def handle_o_h (a : OChart M) (b : HChart M) (h : Overlap a.source b.source) : +noncomputable def handleOH (a : OChart M) (b : HChart M) (h : Overlap a.source b.source) : { f : HChart M | f.source = a.source ∪ b.source } := by have hane : a.source.Nonempty := h.1.mono inter_subset_left have hc : IsConnected (a.source ∩ b.source) := by rw [inter_comm] exact hchart_overlap_connected b a.toOpenPartialHomeomorph (a.connected_source hane) h.2.2 h.2.1 (inter_comm a.source b.source ▸ h.1) - exact handle_o_h' a b h hc + exact handleOH' a b h hc omit [ConnectedSpace M] in /-- Two O-charts with connected overlap glue to an O-chart on the union: rescale both, @@ -421,13 +431,13 @@ lemma exists_glue_o_o (a : OChart M) (b : OChart M) (h : Overlap a.source b.sour exact ⟨⟨hy0, lt_of_le_of_lt hy hμ1⟩, hy⟩ rw [h1, Ioc_union_Ioo_eq_Ioo hμν] refine ⟨⟨f, ⟨0, μ / ρ, htarget.symm⟩⟩, ?_⟩ - show f.source = a.source ∪ b.source + change f.source = a.source ∪ b.source rw [hfs, ha's', hb's'] /-- A disconnected overlap of two O-charts closes `M` up into a circle: the glued chart of `exists_circle_chart` maps `a.source ∪ b.source` onto the whole of `AddCircle 1`; transfer to `Circle` and apply the compact-target argument. -/ -noncomputable def circle_of_disconnected_overlap (a : OChart M) (b : OChart M) +noncomputable def circleOfDisconnectedOverlap (a : OChart M) (b : OChart M) (h : Overlap a.source b.source) (hc : ¬ IsConnected (a.source ∩ b.source)) : Homeomorph M Circle := by have H := exists_circle_chart a b h hc @@ -435,7 +445,7 @@ noncomputable def circle_of_disconnected_overlap (a : OChart M) (b : OChart M) let f' := H.choose.transHomeomorph (AddCircle.homeomorphCircle (one_ne_zero (α := ℝ))) have hfs' : f'.source = a.source ∪ b.source := hfs have hft' : f'.target = Set.univ := by - show (AddCircle.homeomorphCircle _).symm ⁻¹' H.choose.target = Set.univ + change (AddCircle.homeomorphCircle _).symm ⁻¹' H.choose.target = Set.univ rw [hft] exact Set.preimage_univ have hne : f'.source.Nonempty := by @@ -445,8 +455,8 @@ noncomputable def circle_of_disconnected_overlap (a : OChart M) (b : OChart M) /-- Glue two O-charts: with a connected overlap they merge into an O-chart on the union; with a disconnected overlap, `M` is a circle. -/ -noncomputable def handle_o_o (a : OChart M) (b : OChart M) (h : Overlap a.source b.source) : +noncomputable def handleOO (a : OChart M) (b : OChart M) (h : Overlap a.source b.source) : (Homeomorph M Circle) ⊕ { f : OChart M | f.source = a.source ∪ b.source } := by by_cases hc : IsConnected (a.source ∩ b.source) · exact Sum.inr ⟨(exists_glue_o_o a b h hc).choose, (exists_glue_o_o a b h hc).choose_spec⟩ - · exact Sum.inl (circle_of_disconnected_overlap a b h hc) + · exact Sum.inl (circleOfDisconnectedOverlap a b h hc) diff --git a/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean b/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean index 136e84494e..2d6f5bf0fa 100644 --- a/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean +++ b/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean @@ -3,7 +3,14 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic +import Mathlib.Topology.Connected.Basic + +/-! +# ClosureOverlap + +Supporting results for the classification of compact one-dimensional manifolds. +-/ open Set TopologicalSpace @@ -16,16 +23,12 @@ lemma nonempty_closure_inter_diff (hVconn : IsConnected V) (hUopen : IsOpen U) (hVopen : IsOpen V) (hUV : (U ∩ V).Nonempty) (hVU : (V \ U).Nonempty) : ((closure U) ∩ (V \ U)).Nonempty := by - -- prove by contradiction that `closure U ∩ (V \ U)` can't be empty. by_contra h push Not at h - let A := U ∩ V let B := V \ U - have hVconn' : IsPreconnected (V : Set X) := IsConnected.isPreconnected hVconn - have openA : IsOpen (A : Set X) := IsOpen.inter hUopen hVopen have openB : IsOpen (B : Set X) := by have : (V \ U) = (V \ (closure U)) := by @@ -44,7 +47,6 @@ lemma nonempty_closure_inter_diff dsimp [B] -- this is needed? rw [this] exact IsOpen.sdiff hVopen isClosed_closure - have coverAB : V ⊆ A ∪ B := by rintro x hx simp only [mem_union] @@ -53,27 +55,23 @@ lemma nonempty_closure_inter_diff exact mem_inter hxU hx · right exact mem_sdiff_of_mem hx hxU - have nonemptyVA : (V ∩ A).Nonempty := by have : (V ∩ (U ∩ V)) = U ∩ V := by simp only [inter_eq_right, inter_subset_right] rw [this] exact hUV - have nonemptyVB : (V ∩ B).Nonempty := by have : (V ∩ (V \ U)) = (V \ U) := by simp only [inter_eq_right] exact sdiff_subset rw [this] exact hVU - have disjointAB : A ∩ B = ∅ := by ext x simp only [mem_inter_iff, mem_empty_iff_false, iff_false, not_and] intro hx apply notMem_sdiff_of_mem exact mem_of_mem_inter_left hx - have nonemptyVAB : (V ∩ (A ∩ B)).Nonempty := hVconn' A B openA openB coverAB nonemptyVA nonemptyVB rw [disjointAB] at nonemptyVAB simp only [inter_empty, Set.not_nonempty_empty] at nonemptyVAB diff --git a/LeanPool/OneManifold/OneMfld/Compactness.lean b/LeanPool/OneManifold/OneMfld/Compactness.lean index 10703423b0..ce1b80be32 100644 --- a/LeanPool/OneManifold/OneMfld/Compactness.lean +++ b/LeanPool/OneManifold/OneMfld/Compactness.lean @@ -3,10 +3,16 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts import LeanPool.OneManifold.OneMfld.Noncompact +/-! +# Compactness + +Supporting results for the classification of compact one-dimensional manifolds. +-/ + variable {M : Type*} [TopologicalSpace M] @@ -81,7 +87,8 @@ lemma noncompact_iio (x : NNReal) (hx : 0 < x) : ¬ CompactSpace (Set.Iio x) := have h:= noncompact_iio' x hx exact not_compactSpace_iff.mpr h -lemma noncompact_target (ht : FinitelyIntervalChartedSpace M) (z : M) (a : OpenPartialHomeomorph M NNReal) (ha : a ∈ ht.atlas) (hz : z ∈ a.source) : ¬ CompactSpace (a.target) := by +lemma noncompact_target (ht : FinitelyIntervalChartedSpace M) (z : M) (a : OpenPartialHomeomorph + M NNReal) (ha : a ∈ ht.atlas) (hz : z ∈ a.source) : ¬ CompactSpace (a.target) := by have := ht.is_interval a ha rcases this with (h|h) · rcases h with ⟨ x, y, h ⟩ diff --git a/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean b/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean index fbe8f00e51..ee772c0562 100644 --- a/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean +++ b/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean @@ -3,11 +3,19 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic import LeanPool.OneManifold.OneMfld.IntervalCharts import LeanPool.OneManifold.OneMfld.FinitelyCharted -class FinitelyIntervalChartedSpace (M : Type*) [TopologicalSpace M] extends IntervalChartedSpace M where +/-! +# FiniteIntervalCharts + +Supporting results for the classification of compact one-dimensional manifolds. +-/ + +/-- A space equipped with a finite atlas of interval charts. -/ +class FinitelyIntervalChartedSpace (M : Type*) [TopologicalSpace M] extends IntervalChartedSpace + M where is_finite : Set.Finite atlas variable @@ -15,10 +23,12 @@ variable [TopologicalSpace M] [CompactSpace M] -@[instance_reducible] noncomputable def finitely_interval_charted (ht : IntervalChartedSpace M) : FinitelyIntervalChartedSpace M := by - have c : { ht' : ChartedSpace NNReal M | Set.Finite ht'.atlas ∧ ht'.atlas ⊆ ht.atlas } := choose_charts +/-- Extract a finite interval atlas from compactness. -/ +@[instance_reducible] noncomputable def finitelyIntervalCharted (ht : IntervalChartedSpace M) : + FinitelyIntervalChartedSpace M := by + have c : { ht' : ChartedSpace NNReal M | Set.Finite ht'.atlas ∧ ht'.atlas ⊆ ht.atlas } := + chooseCharts rcases c with ⟨ ht', c1, c2 ⟩ - exact { ht' with is_finite := c1 , is_interval := by diff --git a/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean b/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean index 54bc6e43a3..f6566271e8 100644 --- a/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean +++ b/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean @@ -3,7 +3,14 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Geometry.Manifold.ChartedSpace +import Mathlib.Tactic + +/-! +# FinitelyCharted + +Supporting results for the classification of compact one-dimensional manifolds. +-/ variable {H : Type*} [TopologicalSpace H] {M : Type*} [TopologicalSpace M] @@ -11,7 +18,9 @@ variable {M : Type*} [TopologicalSpace M] -noncomputable def choose_charts [CompactSpace M] [ht : ChartedSpace H M] : { ht' : ChartedSpace H M | Set.Finite ht'.atlas ∧ ht'.atlas ⊆ ht.atlas } := by +/-- Choose a finite subatlas covering a compact charted space. -/ +noncomputable def chooseCharts [CompactSpace M] [ht : ChartedSpace H M] : { ht' : ChartedSpace H + M | Set.Finite ht'.atlas ∧ ht'.atlas ⊆ ht.atlas } := by let U : M → Set M := by intro x exact (ht.chartAt x).source @@ -23,12 +32,9 @@ noncomputable def choose_charts [CompactSpace M] [ht : ChartedSpace H M] : { ht' simp only [Set.mem_iUnion] use x exact ChartedSpace.mem_chart_source x - have hc := IsCompact.elim_finite_subcover CompactSpace.isCompact_univ U hUo hsU - let t := Classical.choose hc have t' := Classical.choose_spec hc - let f (x : M) : { x' : M | x' ∈ t ∧ x ∈ (ht.chartAt x').source } := by have : x ∈ ⋃ i ∈ t, U i := by exact t' trivial simp only [Set.mem_iUnion, exists_prop] at this @@ -39,7 +45,6 @@ noncomputable def choose_charts [CompactSpace M] [ht : ChartedSpace H M] : { ht' · exact hx.1 · dsimp [U] at hx exact hx.2 - use { chartAt := by intro x exact ht.chartAt (f x).1 @@ -53,7 +58,6 @@ noncomputable def choose_charts [CompactSpace M] [ht : ChartedSpace H M] : { ht' intro x exact (f x).2.2 } - simp only [Set.mem_ofPred_eq, Set.image_subset_iff] apply And.intro · exact Set.toFinite (ht.chartAt '' ↑t) diff --git a/LeanPool/OneManifold/OneMfld/GlueBlocks.lean b/LeanPool/OneManifold/OneMfld/GlueBlocks.lean index ca036c2c1f..db9bc4ee21 100644 --- a/LeanPool/OneManifold/OneMfld/GlueBlocks.lean +++ b/LeanPool/OneManifold/OneMfld/GlueBlocks.lean @@ -3,7 +3,8 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Algebra.Order.Star.Real +import Mathlib.Tactic import LeanPool.OneManifold.OneMfld.UnitInterval /-! # Building blocks for the H-H gluing @@ -54,21 +55,21 @@ def halfOPH : intro x hx have hx1 : x < (1 : NNReal) := hx have hx' : (x : ℝ) < 1 := by exact_mod_cast hx1 - show min ((x : ℝ) / 2) 1 < 1/2 + change min ((x : ℝ) / 2) 1 < 1/2 rw [min_eq_left (by linarith : (x : ℝ) / 2 ≤ 1)] linarith · -- map_target' intro y hy have hy' : (y : ℝ) < 1/2 := hy have h2 : (0:ℝ) ≤ 2 * (y : ℝ) := mul_nonneg (by norm_num) y.2.1 - show Real.toNNReal (2 * (y : ℝ)) < 1 + change Real.toNNReal (2 * (y : ℝ)) < 1 rw [Real.toNNReal_lt_iff_lt_coe h2, NNReal.coe_one] linarith · -- left_inv' intro x hx have hx1 : x < (1 : NNReal) := hx have hx' : (x : ℝ) < 1 := by exact_mod_cast hx1 - show Real.toNNReal (2 * min ((x : ℝ) / 2) 1) = x + change Real.toNNReal (2 * min ((x : ℝ) / 2) 1) = x rw [min_eq_left (by linarith : (x : ℝ) / 2 ≤ 1), show 2 * ((x : ℝ) / 2) = (x : ℝ) from by ring] exact Real.toNNReal_coe @@ -77,7 +78,7 @@ def halfOPH : have hy' : (y : ℝ) < 1/2 := hy have h2 : (0:ℝ) ≤ 2 * (y : ℝ) := mul_nonneg (by norm_num) y.2.1 apply Subtype.ext - show min ((Real.toNNReal (2 * (y : ℝ)) : ℝ) / 2) 1 = (y : ℝ) + change min ((Real.toNNReal (2 * (y : ℝ)) : ℝ) / 2) 1 = (y : ℝ) rw [Real.coe_toNNReal _ h2, show 2 * (y : ℝ) / 2 = (y : ℝ) from by ring] exact min_eq_left y.2.2 @@ -123,7 +124,7 @@ def mobiusOPH (k : NNReal) (hk : 0 < k) : rfl, rfl, fun x => rfl, ?_⟩ · -- left_inv' intro x _ - show Real.toNNReal ((k : ℝ) / ((k : ℝ) / ((x : ℝ) + (k : ℝ))) - (k : ℝ)) = x + change Real.toNNReal ((k : ℝ) / ((k : ℝ) / ((x : ℝ) + (k : ℝ))) - (k : ℝ)) = x rw [key, show (x : ℝ) + (k : ℝ) - (k : ℝ) = (x : ℝ) from by ring] exact Real.toNNReal_coe · -- right_inv' @@ -134,7 +135,7 @@ def mobiusOPH (k : NNReal) (hk : 0 < k) : rw [le_div_iff₀ hy'] exact mul_le_of_le_one_right hk'.le hy1 apply Subtype.ext - show (k : ℝ) / ((Real.toNNReal ((k : ℝ) / (y : ℝ) - (k : ℝ)) : ℝ) + (k : ℝ)) = (y : ℝ) + change (k : ℝ) / ((Real.toNNReal ((k : ℝ) / (y : ℝ) - (k : ℝ)) : ℝ) + (k : ℝ)) = (y : ℝ) rw [Real.coe_toNNReal _ (sub_nonneg.mpr hknn), show (k : ℝ) / (y : ℝ) - (k : ℝ) + (k : ℝ) = (k : ℝ) / (y : ℝ) from by ring, key] @@ -155,7 +156,7 @@ lemma frontier_UIIic {c : ℝ} (h0 : 0 < c) (h1 : c < 1) : refine Subset.antisymm ?_ (interior_maximal (fun y (hy : (y : ℝ) < c) => hy.le) (isOpen_Iio.preimage continuous_subtype_val)) intro y hy - show (y : ℝ) < c + change (y : ℝ) < c by_contra hlt have hymem : y ∈ {y : UnitInterval | (y : ℝ) ≤ c} := interior_subset hy have hyc : (y : ℝ) = c := le_antisymm hymem (not_lt.mp hlt) diff --git a/LeanPool/OneManifold/OneMfld/GlueCore.lean b/LeanPool/OneManifold/OneMfld/GlueCore.lean index 47d0a04226..ab941a6249 100644 --- a/LeanPool/OneManifold/OneMfld/GlueCore.lean +++ b/LeanPool/OneManifold/OneMfld/GlueCore.lean @@ -3,7 +3,7 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic import LeanPool.OneManifold.OneMfld.Outer import LeanPool.OneManifold.OneMfld.TransitionMono @@ -160,7 +160,7 @@ theorem overlap_mono [T2Space M] (a b : OpenPartialHomeomorph M NNReal) have hlim2' : Tendsto a.symm (𝓝[Ioo p r] r) (𝓝 (b.symm q)) := by apply Tendsto.congr' _ hlim2 filter_upwards [self_mem_nhdsWithin] with t ht - show b.symm (τ t) = a.symm t + change b.symm (τ t) = a.symm t simp only [hτdef] exact b.left_inv (hSb (hsymm t ht).1) have hz : a.symm r = b.symm q := tendsto_nhds_unique' hFne hlim1 hlim2' @@ -251,7 +251,7 @@ theorem overlap_anti [T2Space M] (a b : OpenPartialHomeomorph M NNReal) have hlim2' : Tendsto a.symm (𝓝[Ioo p r] p) (𝓝 (b.symm q)) := by apply Tendsto.congr' _ hlim2 filter_upwards [self_mem_nhdsWithin] with t ht - show b.symm (τ t) = a.symm t + change b.symm (τ t) = a.symm t simp only [hτdef] exact b.left_inv (hSb (hsymm t ht).1) have hz : a.symm p = b.symm q := tendsto_nhds_unique' hFne hlim1 hlim2' diff --git a/LeanPool/OneManifold/OneMfld/GlueNNReal.lean b/LeanPool/OneManifold/OneMfld/GlueNNReal.lean index deee5624e5..4d3b89af7b 100644 --- a/LeanPool/OneManifold/OneMfld/GlueNNReal.lean +++ b/LeanPool/OneManifold/OneMfld/GlueNNReal.lean @@ -3,7 +3,7 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic import LeanPool.OneManifold.OneMfld.GlueCore import LeanPool.OneManifold.OneMfld.Normalize @@ -176,7 +176,7 @@ theorem glue_nnreal {M : Type*} [TopologicalSpace M] [T2Space M] rw [hbm, he'app, hcρ] -- Glue. refine ⟨b.piecewise e' s (Iic μ) H H' Hs Heq, ?_, μ, a m, hqμ, hμ1, hρ0, hρ1, ?_⟩ - · show Set.ite s b.source e'.source = a.source ∪ b.source + · change Set.ite s b.source e'.source = a.source ∪ b.source have hite : Set.ite s b.source e'.source = (b.source ∩ s) ∪ (e'.source \ s) := rfl rw [hite, he's] apply Subset.antisymm @@ -194,7 +194,7 @@ theorem glue_nnreal {M : Type*} [TopologicalSpace M] [T2Space M] exact hxs ⟨hxb, hle⟩ have hxS := hmem_of_b x hxb (hqμ.trans hμx) exact Or.inr ⟨hxS.1, hxs⟩ - · show Set.ite (Iic μ) b.target e'.target = (b.target ∩ Iic μ) ∪ Ioo μ (μ / a m) + · change Set.ite (Iic μ) b.target e'.target = (b.target ∩ Iic μ) ∪ Ioo μ (μ / a m) have hite : Set.ite (Iic μ) b.target e'.target = (b.target ∩ Iic μ) ∪ (e'.target \ Iic μ) := rfl rw [hite, he't] diff --git a/LeanPool/OneManifold/OneMfld/GlueUI.lean b/LeanPool/OneManifold/OneMfld/GlueUI.lean index efa52841ab..4726e9aa40 100644 --- a/LeanPool/OneManifold/OneMfld/GlueUI.lean +++ b/LeanPool/OneManifold/OneMfld/GlueUI.lean @@ -3,7 +3,8 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic +import Mathlib.Topology.OpenPartialHomeomorph.Constructions import LeanPool.OneManifold.OneMfld.GlueCore import LeanPool.OneManifold.OneMfld.GlueBlocks @@ -259,7 +260,7 @@ theorem glue_hh_ui {M : Type*} [TopologicalSpace M] [T2Space M] left have hyt : y ∈ eb.target := by rw [hbt'] - show (y : ℝ) < 1 / 2 + change (y : ℝ) < 1 / 2 linarith refine ⟨?_, hy⟩ rw [hedef, OpenPartialHomeomorph.trans_target] diff --git a/LeanPool/OneManifold/OneMfld/IntervalCharts.lean b/LeanPool/OneManifold/OneMfld/IntervalCharts.lean index aab8e75432..5c5e888a3e 100644 --- a/LeanPool/OneManifold/OneMfld/IntervalCharts.lean +++ b/LeanPool/OneManifold/OneMfld/IntervalCharts.lean @@ -3,12 +3,20 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic import LeanPool.OneManifold.OneMfld.ClassifyInterval import LeanPool.OneManifold.OneMfld.NiceCharts +/-! +# IntervalCharts + +Supporting results for the classification of compact one-dimensional manifolds. +-/ + +/-- A space charted on the half-line with interval targets. -/ class IntervalChartedSpace (M : Type*) [TopologicalSpace M] extends ChartedSpace NNReal M where - is_interval (φ : OpenPartialHomeomorph M NNReal) (h : φ ∈ atlas) : (∃ x y, (Set.Ioo x y = φ.target)) ∨ (∃ x, (Set.Iio x = φ.target)) + is_interval (φ : OpenPartialHomeomorph M NNReal) (h : φ ∈ atlas) : (∃ x y, (Set.Ioo x y = + φ.target)) ∨ (∃ x, (Set.Iio x = φ.target)) variable {M : Type*} @@ -31,7 +39,9 @@ theorem univ_unbounded : ¬ Bornology.IsBounded (Set.univ : Set NNReal) := by -- But `univ` is not bounded above on a `NoTopOrder` type like `NNReal`. exact not_bddAbove_univ h'.2 -@[instance_reducible] noncomputable def interval_charted (ht : NicelyChartedSpace NNReal M) : IntervalChartedSpace M where +/-- Regard an atlas with bounded connected targets as an interval atlas. -/ +@[instance_reducible] noncomputable def intervalCharted (ht : NicelyChartedSpace NNReal M) : + IntervalChartedSpace M where chartAt := ht.chartAt atlas := ht.atlas mem_chart_source := ht.mem_chart_source @@ -40,11 +50,11 @@ theorem univ_unbounded : ¬ Bornology.IsBounded (Set.univ : Set NNReal) := by intro h have bounded := ht.is_bounded φ h have connected := ht.is_connected φ h - - have c := classify_connected_nnreal_interval (φ.target) (φ.open_target) (isConnected_iff_connectedSpace.mpr connected) + have c := classify_connected_nnreal_interval (φ.target) (φ.open_target) + (isConnected_iff_connectedSpace.mpr connected) rcases c with (h|h|h|h) - · left ; assumption - · right ; assumption + · left; assumption + · right; assumption · exfalso rcases h with ⟨x,h⟩ apply ioi_unbounded x diff --git a/LeanPool/OneManifold/OneMfld/LocallyConnected.lean b/LeanPool/OneManifold/OneMfld/LocallyConnected.lean index d0dbe7a526..98b6ff245f 100644 --- a/LeanPool/OneManifold/OneMfld/LocallyConnected.lean +++ b/LeanPool/OneManifold/OneMfld/LocallyConnected.lean @@ -3,7 +3,15 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Analysis.InnerProductSpace.Basic +import Mathlib.Analysis.Normed.Order.Lattice +import Mathlib.Tactic + +/-! +# LocallyConnected + +Supporting results for the classification of compact one-dimensional manifolds. +-/ instance : LocallyConnectedSpace Real := by infer_instance @@ -19,23 +27,22 @@ instance : LocallyConnectedSpace NNReal := by dsimp at x_ul have l_lt_u : l < u := lt_trans x_ul.1 x_ul.2 have upos : 0 < u := lt_of_lt_of_le' (x_ul.2) x.coe_nonneg - let V := {y : NNReal | l < ↑y ∧ ↑y < u} use V constructor - . rw [NNReal.isEmbedding_coe.nhds_eq_comap x] + · rw [NNReal.isEmbedding_coe.nhds_eq_comap x] simp only [Filter.mem_comap] use Set.Ioo l u constructor - . exact Ioo_mem_nhds x_ul.1 x_ul.2 - . intro a a_lu + · exact Ioo_mem_nhds x_ul.1 x_ul.2 + · intro a a_lu dsimp [V] rw [Set.preimage, Set.Ioo] at a_lu dsimp at a_lu exact a_lu constructor -- . apply Convex.IsConnected - . apply IsConnected.isPreconnected + · apply IsConnected.isPreconnected apply IsPathConnected.isConnected rw [IsPathConnected] let z := ((max 0 l) + u) / 2 @@ -47,11 +54,11 @@ instance : LocallyConnectedSpace NNReal := by let z' : NNReal := NNReal.mk z znonneg have l_lt_z : l < z := by have : l ≤ max 0 l := le_max_right 0 l - show l < (max 0 l + u) / 2 + change l < (max 0 l + u) / 2 linarith have z_lt_u : z < u := by have : max 0 l < u := max_lt_iff.mpr ⟨upos, l_lt_u⟩ - show (max 0 l + u) / 2 < u + change (max 0 l + u) / 2 < u linarith have : z' ∈ V := ⟨l_lt_z, z_lt_u⟩ use z' @@ -59,7 +66,7 @@ instance : LocallyConnectedSpace NNReal := by intro y yV dsimp [V] at yV by_cases h : z' = y - . exact Inseparable.joinedIn (congrArg nhds h) this yV + · exact Inseparable.joinedIn (congrArg nhds h) this yV rw [JoinedIn] let γ : Path z' y := { toFun := fun t ↦ NNReal.mk ((unitInterval.symm t)*z' + t*y) @@ -74,24 +81,20 @@ instance : LocallyConnectedSpace NNReal := by have δpos : δ > 0 := div_pos εpos dyz'pos use δ constructor - . exact δpos + · exact δpos intro a a_s_near rw [NNReal.dist_eq] simp only [NNReal.coe_mk] rw [sub_mul, sub_mul, one_mul] - let ans : Real := (↑a - ↑s) * (↑y - ↑z') have : ↑z' - ↑a * ↑z' + ↑a * ↑y - (↑z' - ↑s * ↑z' + ↑s * ↑y) = ans := by ring rw [this] dsimp [ans] - rw [abs_mul] - - - --have : (max 0 l + u) / 2 - ↑a * ((max 0 l + u) / 2) + ↑a * ↑y - ((max 0 l + u) / 2 - ↑s * ((max 0 l + u) / 2) + ↑s * ↑y) + -- have : (max 0 l + u) / 2 - ↑a * ((max 0 l + u) / 2) + ↑a * ↑y - ((max 0 l + + -- u) / 2 - ↑s * ((max 0 l + u) / 2) + ↑s * ↑y) -- = (↑a - ↑s) * (↑y - ((max 0 l + u) / 2)) := by ring --ring_nf - have ha : |(a:ℝ) - (s:ℝ)| < δ := by rw [← Real.dist_eq (a : ℝ) (s : ℝ)] exact a_s_near @@ -99,7 +102,6 @@ instance : LocallyConnectedSpace NNReal := by have this : |(y:ℝ) - (z':ℝ)| = dist y z' := by exact this' rw [this] - calc |↑a - ↑s| * dist y z' < δ * dist y z' := by exact ((mul_lt_mul_iff_of_pos_right dyz'pos).mpr a_s_near) @@ -120,9 +122,9 @@ instance : LocallyConnectedSpace NNReal := by intro t dsimp [V, γ] constructor - . show l < ↑(unitInterval.symm t) * ((max 0 l + u) / 2) + ↑t * ↑y + · change l < ↑(unitInterval.symm t) * ((max 0 l + u) / 2) + ↑t * ↑y by_cases tpos : t > 0 - . calc + · calc l = ↑(unitInterval.symm t) * l + t * l := by simp only [unitInterval.coe_symm_eq] ring @@ -133,14 +135,14 @@ instance : LocallyConnectedSpace NNReal := by have : ↑(unitInterval.symm t) * l ≤ ↑(unitInterval.symm t) * z := mul_le_mul_of_nonneg_left (le_of_lt l_lt_z) unitInterval.nonneg' linarith - . have : t = 0 := le_antisymm (not_lt.mp tpos) (unitInterval.nonneg') + · have : t = 0 := le_antisymm (not_lt.mp tpos) (unitInterval.nonneg') rw [this] simp only [unitInterval.symm_zero, Set.Icc.coe_one, one_mul, Set.Icc.coe_zero, zero_mul, add_zero, gt_iff_lt] exact l_lt_z - . show ↑(unitInterval.symm t) * ((max 0 l + u) / 2) + ↑t * ↑y < u + · change ↑(unitInterval.symm t) * ((max 0 l + u) / 2) + ↑t * ↑y < u by_cases tpos : t > 0 - . calc + · calc ↑(unitInterval.symm t) * ((max 0 l + u) / 2) + ↑t * ↑y < ↑(unitInterval.symm t) * ((max 0 l + u) / 2) + ↑t * u := by have : ↑t * ↑y < ↑t * u := mul_lt_mul_of_pos_left yV.2 tpos @@ -150,12 +152,12 @@ instance : LocallyConnectedSpace NNReal := by := mul_le_mul_of_nonneg_left (le_of_lt z_lt_u) unitInterval.nonneg' linarith _ = u := by rw [unitInterval.coe_symm_eq]; ring - . have : t = 0 := le_antisymm (not_lt.mp tpos) (unitInterval.nonneg') + · have : t = 0 := le_antisymm (not_lt.mp tpos) (unitInterval.nonneg') rw [this] simp only [unitInterval.symm_zero, Set.Icc.coe_one, one_mul, Set.Icc.coe_zero, zero_mul, add_zero, gt_iff_lt] exact z_lt_u - . intro a aV + · intro a aV dsimp [V] at aV apply t_U rw [Set.preimage] diff --git a/LeanPool/OneManifold/OneMfld/NiceCharts.lean b/LeanPool/OneManifold/OneMfld/NiceCharts.lean index f39d0fea9f..716eebf604 100644 --- a/LeanPool/OneManifold/OneMfld/NiceCharts.lean +++ b/LeanPool/OneManifold/OneMfld/NiceCharts.lean @@ -3,19 +3,26 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Algebra.Order.Star.Real +import Mathlib.Geometry.Manifold.ChartedSpace +import Mathlib.Tactic import LeanPool.OneManifold.OneMfld.LocallyConnected import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers +/-! +# NiceCharts + +Supporting results for the classification of compact one-dimensional manifolds. +-/ + variable {M : Type*} [TopologicalSpace M] -noncomputable def improved_chart (φ : OpenPartialHomeomorph M NNReal) (x : M) (h : x ∈ φ.source) : +/-- Restrict a chart around the specified point to a bounded target. -/ +noncomputable def improvedChart (φ : OpenPartialHomeomorph M NNReal) (x : M) (h : x ∈ φ.source) : { ψ : OpenPartialHomeomorph M NNReal | (x ∈ ψ.source ∧ Bornology.IsBounded ψ.target) } := by - let y := φ.toFun x - by_cases h0 : y > 0 · let interval := Set.Ioo (y-1) (y+1) let t := φ.target ∩ interval @@ -25,7 +32,6 @@ noncomputable def improved_chart (φ : OpenPartialHomeomorph M NNReal) (x : M) ( Set.inter_subset_left)).mpr exact IsOpen.inter φ.open_target isOpen_Ioo let φ' := φ.restrOpen s sOpen - use φ' apply And.intro · dsimp [φ'] @@ -51,7 +57,6 @@ noncomputable def improved_chart (φ : OpenPartialHomeomorph M NNReal) (x : M) ( have hz' : z ∈ φ.target ∩ ↑φ.symm ⁻¹' (↑φ.symm '' t) := hz rw [restrOpen_symm_image_target φ (t := t) Set.inter_subset_left] at hz' exact Set.mem_of_mem_inter_right hz' - · simp only [gt_iff_lt, not_lt, nonpos_iff_eq_zero] at h0 let interval := Set.Iio (1 : NNReal) let t := φ.target ∩ interval @@ -61,7 +66,6 @@ noncomputable def improved_chart (φ : OpenPartialHomeomorph M NNReal) (x : M) ( Set.inter_subset_left)).mpr exact IsOpen.inter φ.open_target isOpen_Iio let φ' := φ.restrOpen s sOpen - use φ' apply And.intro · dsimp [φ'] @@ -91,23 +95,21 @@ noncomputable def improved_chart (φ : OpenPartialHomeomorph M NNReal) (x : M) ( rw [restrOpen_symm_image_target φ (t := t) Set.inter_subset_left] at hz' exact Set.mem_of_mem_inter_right hz' -noncomputable def improved_chart' (φ : OpenPartialHomeomorph M NNReal) (x : M) (h : x ∈ φ.source) (bounded : Bornology.IsBounded φ.target) : - { ψ : OpenPartialHomeomorph M NNReal | x ∈ ψ.source ∧ Bornology.IsBounded ψ.target ∧ ConnectedSpace ψ.target } := by - +/-- Restrict a bounded chart to the connected component containing the specified point. -/ +noncomputable def improvedChart' (φ : OpenPartialHomeomorph M NNReal) (x : M) (h : x ∈ φ.source) + (bounded : Bornology.IsBounded φ.target) : + { ψ : OpenPartialHomeomorph M NNReal | x ∈ ψ.source ∧ Bornology.IsBounded ψ.target ∧ + ConnectedSpace ψ.target } := by let y := φ.toFun x - let t := connectedComponentIn φ.target y let s := φ.symm '' t - let sOpen : IsOpen s := by apply OpenPartialHomeomorph.isOpen_image_symm_of_subset_target φ - apply IsOpen.connectedComponentIn - · exact φ.open_target + · apply IsOpen.connectedComponentIn + exact φ.open_target · exact connectedComponentIn_subset φ.target y - let ψ := φ.restrOpen s sOpen use ψ - apply And.intro · dsimp [ψ] simp only [Set.mem_inter_iff] @@ -134,52 +136,60 @@ noncomputable def improved_chart' (φ : OpenPartialHomeomorph M NNReal) (x : M) apply isConnected_connectedComponentIn_iff.mpr exact PartialEquiv.map_source φ.toPartialEquiv h -noncomputable def nice_chart (φ : OpenPartialHomeomorph M NNReal) (x : M) (h : x ∈ φ.source) : - { ψ : OpenPartialHomeomorph M NNReal | x ∈ ψ.source ∧ Bornology.IsBounded ψ.target ∧ ConnectedSpace ψ.target } := by - rcases (improved_chart φ x h) with ⟨ φ', h1, h2 ⟩ - rcases (improved_chart' φ' x h1 h2) with ⟨ φ'', h1, h2, h3 ⟩ +/-- Choose a chart around the specified point with a bounded connected target. -/ +noncomputable def niceChart (φ : OpenPartialHomeomorph M NNReal) (x : M) (h : x ∈ φ.source) : + { ψ : OpenPartialHomeomorph M NNReal | x ∈ ψ.source ∧ Bornology.IsBounded ψ.target ∧ + ConnectedSpace ψ.target } := by + rcases (improvedChart φ x h) with ⟨ φ', h1, h2 ⟩ + rcases (improvedChart' φ' x h1 h2) with ⟨ φ'', h1, h2, h3 ⟩ use φ'' simp only [Set.mem_ofPred_eq] exact ⟨ h1, ⟨ h2, h3 ⟩ ⟩ lemma nice_chart_source {φ : OpenPartialHomeomorph M NNReal} {x : M} {h : x ∈ φ.source} : - x ∈ (nice_chart φ x h).1.source := by - let c := nice_chart φ x h - have : c = nice_chart φ x h := rfl + x ∈ (niceChart φ x h).1.source := by + let c := niceChart φ x h + have : c = niceChart φ x h := rfl rw [←this] exact c.2.1 lemma nice_chart_bounded {φ : OpenPartialHomeomorph M NNReal} {x : M} {h : x ∈ φ.source} : - Bornology.IsBounded (nice_chart φ x h).1.target := by - let c := nice_chart φ x h - have : c = nice_chart φ x h := rfl + Bornology.IsBounded (niceChart φ x h).1.target := by + let c := niceChart φ x h + have : c = niceChart φ x h := rfl rw [←this] exact c.2.2.1 lemma nice_chart_connected {φ : OpenPartialHomeomorph M NNReal} {x : M} {h : x ∈ φ.source} : - ConnectedSpace (nice_chart φ x h).1.target := by - let c := nice_chart φ x h - have : c = nice_chart φ x h := rfl + ConnectedSpace (niceChart φ x h).1.target := by + let c := niceChart φ x h + have : c = niceChart φ x h := rfl rw [←this] exact c.2.2.2 +/-- A chart around a specified point with bounded connected target. -/ structure NiceChartAt (x : M) where + /-- The local chart containing the specified point. -/ chart : OpenPartialHomeomorph M NNReal mem_chart_source : x ∈ chart.source bounded : Bornology.IsBounded chart.target connected : ConnectedSpace chart.target -class NicelyChartedSpace (H : Type*) [TopologicalSpace H] [Bornology H] (M : Type*) [TopologicalSpace M] extends ChartedSpace H M where +/-- A charted space whose atlas has bounded connected targets. -/ +class NicelyChartedSpace (H : Type*) [TopologicalSpace H] [Bornology H] (M : Type*) + [TopologicalSpace M] extends ChartedSpace H M where is_bounded (φ : OpenPartialHomeomorph M H) (h : φ ∈ atlas) : Bornology.IsBounded φ.target is_connected (φ : OpenPartialHomeomorph M H) (h : φ ∈ atlas) : ConnectedSpace φ.target -@[instance_reducible] noncomputable def nicely_charted (ht : ChartedSpace NNReal M) : NicelyChartedSpace NNReal M where +/-- Replace an atlas by one with bounded connected chart targets. -/ +@[instance_reducible] noncomputable def nicelyCharted (ht : ChartedSpace NNReal M) : + NicelyChartedSpace NNReal M where chartAt := by intro x let c := ht.chartAt x - let c' := nice_chart (ht.chartAt x) x (ht.mem_chart_source x) + let c' := niceChart (ht.chartAt x) x (ht.mem_chart_source x) exact c'.1 - atlas := let f x := (nice_chart (ht.chartAt x) x (ht.mem_chart_source x)).1 + atlas := let f x := (niceChart (ht.chartAt x) x (ht.mem_chart_source x)).1 Set.image f (Set.univ : Set M) mem_chart_source (x : M) := by simp only [Set.mem_ofPred_eq] @@ -189,14 +199,14 @@ class NicelyChartedSpace (H : Type*) [TopologicalSpace H] [Bornology H] (M : Typ is_bounded (φ : OpenPartialHomeomorph M NNReal) := by intro h dsimp [atlas] at h - simp at h - rcases h with ⟨ y, hy ⟩ + simp only [Set.image_univ, Set.mem_range] at h + rcases h with ⟨y, hy⟩ rw [←hy] apply nice_chart_bounded is_connected (φ : OpenPartialHomeomorph M NNReal) := by intro h dsimp [atlas] at h - simp at h - rcases h with ⟨ y, hy ⟩ + simp only [Set.image_univ, Set.mem_range] at h + rcases h with ⟨y, hy⟩ rw [←hy] apply nice_chart_connected diff --git a/LeanPool/OneManifold/OneMfld/Noncompact.lean b/LeanPool/OneManifold/OneMfld/Noncompact.lean index 84091f55ba..7558665222 100644 --- a/LeanPool/OneManifold/OneMfld/Noncompact.lean +++ b/LeanPool/OneManifold/OneMfld/Noncompact.lean @@ -3,7 +3,14 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Analysis.Normed.Order.Lattice +import Mathlib.Tactic + +/-! +# Noncompact + +Supporting results for the classification of compact one-dimensional manifolds. +-/ open Set @@ -14,7 +21,6 @@ lemma not_isCompact_Ici_zero_real : ¬ IsCompact (Ici (0 : ℝ)) := by -- Open cover U n = (-∞, n) let U : ℕ → Set ℝ := fun n => Iio (n : ℝ) have hUopen : ∀ n, IsOpen (U n) := fun _ => isOpen_Iio - -- This open cover really does cover `[0, ∞)`. have hCover : Ici (0 : ℝ) ⊆ ⋃ n : ℕ, U n := by intro x hx @@ -22,19 +28,16 @@ lemma not_isCompact_Ici_zero_real : ¬ IsCompact (Ici (0 : ℝ)) := by obtain ⟨n, hn⟩ := exists_nat_gt x refine mem_iUnion.mpr ?_ exact ⟨n, hn⟩ - -- By compactness, we get a finite subcover. obtain ⟨s, hs⟩ := hIci0.elim_finite_subcover U hUopen hCover -- s : Finset ℕ, hs : Ici (0 : ℝ) ⊆ ⋃ n ∈ s, U n -- Let N be the supremum (i.e., max) of the finite set s. let N : ℕ := s.sup id - -- N (as a real) is in `[0, ∞)`. have hNmem : (N : ℝ) ∈ Ici (0 : ℝ) := by have : (0 : ℝ) ≤ N := by exact_mod_cast Nat.zero_le N exact this - -- But N is *not* in the finite union ⋃ n ∈ s, U n. have hNnot : (N : ℝ) ∉ ⋃ n ∈ s, U n := by intro hmem @@ -51,7 +54,6 @@ lemma not_isCompact_Ici_zero_real : ¬ IsCompact (Ici (0 : ℝ)) := by have hcontr : (N : ℝ) < (N : ℝ) := lt_of_lt_of_le hlt (by exact_mod_cast hle) exact lt_irrefl _ hcontr - -- But hs says the finite subcover covers `[0, ∞)`, so it must contain N. exact hNnot (hs hNmem) @@ -60,17 +62,14 @@ theorem not_compactSpace_NNReal : ¬ CompactSpace NNReal := by intro h -- Use the assumed instance `CompactSpace NNReal`. have : CompactSpace NNReal := h - -- The whole space is compact. have hK : IsCompact (univ : Set NNReal) := isCompact_univ - -- Consider the inclusion `NNReal → ℝ`. have hImage : IsCompact ((fun x : NNReal => (x : ℝ)) '' (univ : Set NNReal)) := hK.image (by -- continuity of the inclusion simpa using NNReal.continuous_coe) - -- Identify the image with `[0, ∞)` as a subset of ℝ. have hImage_eq : ((fun x : NNReal => (x : ℝ)) '' (univ : Set NNReal)) = Ici (0 : ℝ) := by @@ -81,9 +80,7 @@ theorem not_compactSpace_NNReal : ¬ CompactSpace NNReal := by · -- backward: any real x ≥ 0 comes from some nnreal y with y.val = x intro hx exact ⟨NNReal.mk x hx, trivial, rfl⟩ - have hIci0 : IsCompact (Ici (0 : ℝ)) := by simpa [hImage_eq] using hImage - -- Contradiction with the previous lemma. exact not_isCompact_Ici_zero_real hIci0 diff --git a/LeanPool/OneManifold/OneMfld/Normalize.lean b/LeanPool/OneManifold/OneMfld/Normalize.lean index b739c89630..c41db448dc 100644 --- a/LeanPool/OneManifold/OneMfld/Normalize.lean +++ b/LeanPool/OneManifold/OneMfld/Normalize.lean @@ -3,7 +3,9 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Algebra.Order.Star.Real +import Mathlib.Tactic +import Mathlib.Topology.OpenPartialHomeomorph.Constructions import LeanPool.OneManifold.OneMfld.Charts /-! # Normalization of interval charts diff --git a/LeanPool/OneManifold/OneMfld/Outer.lean b/LeanPool/OneManifold/OneMfld/Outer.lean index 0a218bb731..b7edffb3b1 100644 --- a/LeanPool/OneManifold/OneMfld/Outer.lean +++ b/LeanPool/OneManifold/OneMfld/Outer.lean @@ -3,7 +3,7 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic import LeanPool.OneManifold.OneMfld.ClosureOverlap import LeanPool.OneManifold.OneMfld.LocallyConnected import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers @@ -115,7 +115,7 @@ section Escape lemma image_component_ne_target (U V : OpenPartialHomeomorph M NNReal) (hUV : (U.source \ V.source).Nonempty) - {x : M} (hx : x ∈ U.source ∩ V.source) : + {x : M} : U '' connectedComponentIn (U.source ∩ V.source) x ≠ U.target := by intro h obtain ⟨y, hyU, hyV⟩ := hUV @@ -322,7 +322,7 @@ theorem overlap_component_outer_Iio [T2Space M] exact Metric.isBounded_Ico 0 v have hAne : A ≠ Iio v := by rw [← hUt] - exact image_component_ne_target U V hUV hx + exact image_component_ne_target U V hUV have hesc : ¬ closure A ⊆ Iio v := by rw [← hUt] exact not_closure_image_subset_target U V hUb hV hVU hx diff --git a/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean b/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean index 577b5e6d3c..42543eef8b 100644 --- a/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean +++ b/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean @@ -3,12 +3,20 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic +import Mathlib.Topology.Connected.Basic +import Mathlib.Topology.OpenPartialHomeomorph.Defs + +/-! +# PartialHomeomorphHelpers + +Supporting results for the classification of compact one-dimensional manifolds. +-/ lemma partial_homeo_connected {X : Type*} {Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] (h : OpenPartialHomeomorph X Y) (conn : IsConnected h.source) : (IsConnected h.target) := by have ht : h.target = h.toFun '' h.source - exact Eq.symm (PartialEquiv.image_source_eq_target h.toPartialEquiv) + · exact Eq.symm (PartialEquiv.image_source_eq_target h.toPartialEquiv) rw [ht] apply IsConnected.image conn ↑h.toPartialEquiv h.continuousOn_toFun @@ -23,7 +31,8 @@ lemma partial_homeo_connected' {X : Type*} {Y : Type*} [TopologicalSpace X] [Top rw [←hts] exact h'' -lemma partial_homeo_source_connected_iff_target_connected {X : Type*} {Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] +lemma partial_homeo_source_connected_iff_target_connected {X : Type*} {Y : Type*} + [TopologicalSpace X] [TopologicalSpace Y] (h : OpenPartialHomeomorph X Y) : IsConnected h.source ↔ IsConnected h.target := by constructor · exact fun a => partial_homeo_connected h a diff --git a/LeanPool/OneManifold/OneMfld/RealIntervals.lean b/LeanPool/OneManifold/OneMfld/RealIntervals.lean index 2bd1356cf8..45f69c68dd 100644 --- a/LeanPool/OneManifold/OneMfld/RealIntervals.lean +++ b/LeanPool/OneManifold/OneMfld/RealIntervals.lean @@ -3,7 +3,17 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Analysis.InnerProductSpace.Basic +import Mathlib.Analysis.Normed.Module.RCLike.Real +import Mathlib.Analysis.Normed.Order.Lattice +import Mathlib.Order.CompletePartialOrder +import Mathlib.Tactic + +/-! +# RealIntervals + +Supporting results for the classification of compact one-dimensional manifolds. +-/ open Set @@ -20,8 +30,8 @@ lemma ordconn_of_connected {X : Set ℝ} (conn : IsConnected X) lemma Real.exists_isGLB {S : Set ℝ} (hne : S.Nonempty) (hbdd : BddBelow S) : ∃ x, IsGLB S x := by use sInf S - rw [Real.sInf_def, ← isLUB_neg, Real.sSup_def, dif_pos] - . apply Classical.choose_spec + rw [Real.sInf_def, ← isLUB_neg, Real.sSup_def, dite_eq_left] + · apply Classical.choose_spec exact ⟨nonempty_neg.mpr hne, BddBelow.neg hbdd⟩ -- classifying real intervals @@ -35,10 +45,10 @@ lemma connected_bddAbove_subset_contains_Ioo {X : Set ℝ} {supX : ℝ} {x : ℝ : Ioo x supX ⊆ X := by intro y ⟨x_lt_y, y_lt_supX⟩ by_cases h: ∃ z ∈ X, y ≤ z - . rcases h with ⟨z, zX, y_le_z⟩ + · rcases h with ⟨z, zX, y_le_z⟩ have : Icc x z ⊆ X := ordconn_of_connected conn x xX z zX exact this ⟨LT.lt.le x_lt_y, y_le_z⟩ - . push Not at h + · push Not at h have : y ∈ upperBounds X := fun z ↦ fun zX ↦ LT.lt.le (h z zX) have : supX ≤ y := h_supX.2 this linarith @@ -48,10 +58,10 @@ lemma connected_bddBelow_subset_contains_Ioo {X : Set ℝ} {infX : ℝ} {x : ℝ : Ioo infX x ⊆ X := by intro y ⟨infX_lt_y, y_lt_x⟩ by_cases h: ∃ z ∈ X, z ≤ y - . rcases h with ⟨z, zX, z_le_y⟩ + · rcases h with ⟨z, zX, z_le_y⟩ have : Icc z x ⊆ X := ordconn_of_connected conn z zX x xX exact this ⟨z_le_y, LT.lt.le y_lt_x⟩ - . push Not at h + · push Not at h have : y ∈ lowerBounds X := fun z ↦ fun zX ↦ LT.lt.le (h z zX) have : y ≤ infX := h_infX.2 this linarith @@ -66,19 +76,19 @@ lemma connected_bdd_subset_contains_Ioo have h₃ : Ioo infX supX ⊆ Ioo infX z ∪ {z} ∪ Ioo z supX := by intro x ⟨infX_lt_x, x_lt_supX⟩ rcases lt_trichotomy x z with (x_lt_z | x_eq_z | z_lt_z) - . left; left + · left; left exact ⟨infX_lt_x, x_lt_z⟩ - . left; right + · left; right rw [mem_singleton_iff, x_eq_z] - . right + · right exact ⟨z_lt_z, x_lt_supX⟩ have h₄ : Ioo infX z ∪ {z} ∪ Ioo z supX ⊆ X := by rintro x ((_ | x_eq_z) | _) - . apply h₁; assumption - . rw [mem_singleton_iff] at x_eq_z + · apply h₁; assumption + · rw [mem_singleton_iff] at x_eq_z rw [x_eq_z] exact zX - . apply h₂; assumption + · apply h₂; assumption intro x x_Ioo exact h₄ (h₃ x_Ioo) @@ -89,16 +99,16 @@ lemma bdd_subset_Icc intro x xX exact ⟨h_infX.1 xX, h_supX.1 xX⟩ -lemma x_lt_excluded_supX {x supX : ℝ} (xX: x ∈ X) - (h_supX: IsLUB X supX) (supX_X : supX ∉ X) : x < supX := by +lemma x_lt_excluded_supX {x supX : ℝ} (xX : x ∈ X) + (h_supX : IsLUB X supX) (supX_X : supX ∉ X) : x < supX := by have : x ≠ supX := by intro x_eq_supX rw [← x_eq_supX] at supX_X contradiction exact Ne.lt_of_le this (h_supX.1 xX) -lemma excluded_infX_lt_x {x infX : ℝ} (xX: x ∈ X) - (h_infX: IsGLB X infX) (infX_X : infX ∉ X) : infX < x := by +lemma excluded_infX_lt_x {x infX : ℝ} (xX : x ∈ X) + (h_infX : IsGLB X infX) (infX_X : infX ∉ X) : infX < x := by have : infX ≠ x := by intro x_eq_supX rw [x_eq_supX] at infX_X @@ -108,35 +118,35 @@ lemma excluded_infX_lt_x {x infX : ℝ} (xX: x ∈ X) lemma Ico_Ioo_with_endpoint {a b : ℝ} (hab : a < b) : Ico a b = (Ioo a b) ∪ {a} := by apply Subset.antisymm - . intro x ⟨x_le_a, x_lt_b⟩ + · intro x ⟨x_le_a, x_lt_b⟩ by_cases xa : x = a - . right; exact xa - . left; exact ⟨Ne.lt_of_le' xa x_le_a, x_lt_b⟩ - . rintro x (x_Ioo | x_a) - . exact ⟨LT.lt.le x_Ioo.1, x_Ioo.2⟩ - . exact ⟨Eq.ge x_a, Eq.trans_lt x_a hab⟩ + · right; exact xa + · left; exact ⟨Ne.lt_of_le' xa x_le_a, x_lt_b⟩ + · rintro x (x_Ioo | x_a) + · exact ⟨LT.lt.le x_Ioo.1, x_Ioo.2⟩ + · exact ⟨Eq.ge x_a, Eq.trans_lt x_a hab⟩ lemma Ioc_Ioo_with_endpoint {a b : ℝ} (hab : a < b) : Ioc a b = (Ioo a b) ∪ {b} := by apply Subset.antisymm - . intro x ⟨a_lt_x, x_le_b⟩ + · intro x ⟨a_lt_x, x_le_b⟩ by_cases xb : x = b - . right; exact xb + · right; exact xb have : x < b := Ne.lt_of_le xb x_le_b left; exact ⟨a_lt_x, this⟩ - . rintro x (x_Ioo | x_b) - . exact ⟨x_Ioo.1, LT.lt.le x_Ioo.2⟩ - . exact ⟨(by rw [x_b]; exact hab), Eq.le x_b⟩ + · rintro x (x_Ioo | x_b) + · exact ⟨x_Ioo.1, LT.lt.le x_Ioo.2⟩ + · exact ⟨(by rw [x_b]; exact hab), Eq.le x_b⟩ lemma characterize_Ioo {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) (infX_X : infX ∉ X) (supX_X : supX ∉ X) : X = Ioo infX supX := by apply Subset.antisymm - . intro x xX + · intro x xX exact ⟨excluded_infX_lt_x xX h_infX infX_X, x_lt_excluded_supX xX h_supX supX_X⟩ - . exact connected_bdd_subset_contains_Ioo conn h_infX h_supX + · exact connected_bdd_subset_contains_Ioo conn h_infX h_supX lemma characterize_Ioc {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} (inf_lt_sup : infX < supX) @@ -144,10 +154,10 @@ lemma characterize_Ioc {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} (infX_X : infX ∉ X) (supX_X : supX ∈ X) : X = Ioc infX supX := by apply Subset.antisymm - . intro x xX + · intro x xX exact ⟨excluded_infX_lt_x xX h_infX infX_X, h_supX.1 xX⟩ - . rw [Ioc_Ioo_with_endpoint inf_lt_sup, union_subset_iff] + · rw [Ioc_Ioo_with_endpoint inf_lt_sup, union_subset_iff] exact ⟨connected_bdd_subset_contains_Ioo conn h_infX h_supX, singleton_subset_iff.mpr supX_X⟩ @@ -157,10 +167,10 @@ lemma characterize_Ico {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} (infX_X : infX ∈ X) (supX_X : supX ∉ X) : X = Ico infX supX := by apply Subset.antisymm - . intro x xX + · intro x xX exact ⟨h_infX.1 xX, x_lt_excluded_supX xX h_supX supX_X⟩ - . rw [Ico_Ioo_with_endpoint inf_lt_sup, union_subset_iff] + · rw [Ico_Ioo_with_endpoint inf_lt_sup, union_subset_iff] exact ⟨connected_bdd_subset_contains_Ioo conn h_infX h_supX, singleton_subset_iff.mpr infX_X⟩ @@ -169,49 +179,56 @@ lemma characterize_Icc {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} (infX_X : infX ∈ X) (supX_X : supX ∈ X) : X = Icc infX supX := by apply Subset.antisymm - . exact bdd_subset_Icc h_infX h_supX - . exact (ordconn_of_connected conn) infX infX_X supX supX_X + · exact bdd_subset_Icc h_infX h_supX + · exact (ordconn_of_connected conn) infX infX_X supX supX_X lemma characterize_singleton {X : Set ℝ} {a : ℝ} (h_infX : IsGLB X a) (h_supX : IsLUB X a) : (X = {a}) := by apply Subset.antisymm - . apply subset_trans (bdd_subset_Icc h_infX h_supX) + · apply subset_trans (bdd_subset_Icc h_infX h_supX) exact Set.Icc_subset {a} rfl rfl - . rw [singleton_subset_iff] + · rw [singleton_subset_iff] rcases IsLUB.nonempty h_supX with ⟨x, xX⟩ have : a = x := LE.le.antisymm (h_infX.1 xX) (h_supX.1 xX) exact mem_of_eq_of_mem (id this) xX +/-- The four possibilities for including the two endpoints of a bounded interval. -/ inductive BoundedIntervalKind | IooKind | IocKind | IcoKind | IccKind open BoundedIntervalKind +/-- Two ordered real endpoints together with their inclusion convention. -/ structure BoundedInterval where - left_endpoint : ℝ - right_endpoint : ℝ - left_lt_right : left_endpoint < right_endpoint + /-- The left endpoint of the interval. -/ + leftEndpoint : ℝ + /-- The right endpoint of the interval. -/ + rightEndpoint : ℝ + left_lt_right : leftEndpoint < rightEndpoint + /-- Which endpoints belong to the interval. -/ kind : BoundedIntervalKind -@[simp] -def BoundedInterval_as_set : BoundedInterval → Set ℝ +/-- Interpret the interval's endpoints and inclusion convention as a set of reals. -/ +def BoundedIntervalAsSet : BoundedInterval → Set ℝ | ⟨a, b, _, IooKind⟩ => Ioo a b | ⟨a, b, _, IocKind⟩ => Ioc a b | ⟨a, b, _, IcoKind⟩ => Ico a b | ⟨a, b, _, IccKind⟩ => Icc a b +/-- The set is a nondegenerate bounded interval with some endpoint convention. -/ def isBoundedInterval (X : Set ℝ) := - ∃ I : BoundedInterval, X = BoundedInterval_as_set I + ∃ I : BoundedInterval, X = BoundedIntervalAsSet I lemma isBoundedInterval_Ioo (a b : ℝ) (lt : a < b) : isBoundedInterval (Ioo a b) := by - use ⟨a, b, lt, IooKind⟩; simp only [BoundedInterval_as_set] + use ⟨a, b, lt, IooKind⟩; simp only [BoundedIntervalAsSet] lemma isBoundedInterval_Ioc (a b : ℝ) (lt : a < b) : isBoundedInterval (Ioc a b) := by - use ⟨a, b, lt, IocKind⟩; simp only [BoundedInterval_as_set] + use ⟨a, b, lt, IocKind⟩; simp only [BoundedIntervalAsSet] lemma isBoundedInterval_Ico (a b : ℝ) (lt : a < b) : isBoundedInterval (Ico a b) := by - use ⟨a, b, lt, IcoKind⟩; simp only [BoundedInterval_as_set] + use ⟨a, b, lt, IcoKind⟩; simp only [BoundedIntervalAsSet] lemma isBoundedInterval_Icc (a b : ℝ) (lt : a < b) : isBoundedInterval (Icc a b) := by - use ⟨a, b, lt, IccKind⟩; simp only [BoundedInterval_as_set] + use ⟨a, b, lt, IccKind⟩; simp only [BoundedIntervalAsSet] +/-- The set consists of exactly one real number. -/ def isSingleton (X : Set ℝ) := ∃ a : ℝ, X = {a} @@ -220,15 +237,15 @@ lemma classify_connected_reals_with_GLB_lt_LUB (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) (lt : infX < supX) : isBoundedInterval X := by by_cases infX_X : infX ∈ X - . by_cases supX_X : supX ∈ X - . use ⟨infX, supX, lt, IccKind⟩ + · by_cases supX_X : supX ∈ X + · use ⟨infX, supX, lt, IccKind⟩ exact characterize_Icc conn h_infX h_supX infX_X supX_X - . use ⟨infX, supX, lt, IcoKind⟩ + · use ⟨infX, supX, lt, IcoKind⟩ exact characterize_Ico conn lt h_infX h_supX infX_X supX_X - . by_cases supX_X : supX ∈ X - . use ⟨infX, supX, lt, IocKind⟩ + · by_cases supX_X : supX ∈ X + · use ⟨infX, supX, lt, IocKind⟩ exact characterize_Ioc conn lt h_infX h_supX infX_X supX_X - . use ⟨infX, supX, lt, IooKind⟩ + · use ⟨infX, supX, lt, IooKind⟩ exact characterize_Ioo conn h_infX h_supX infX_X supX_X theorem classify_connected_bounded_reals @@ -238,10 +255,10 @@ theorem classify_connected_bounded_reals have ⟨supX, h_supX⟩ := Real.exists_isLUB nonempty above have ⟨infX, h_infX⟩ := Real.exists_isGLB nonempty below by_cases inf_eq_sup : infX = supX - . left; rw [isSingleton]; use infX + · left; rw [isSingleton]; use infX rw [← inf_eq_sup] at h_supX apply characterize_singleton h_infX h_supX - . right + · right have : infX ≤ supX := isGLB_le_isLUB h_infX h_supX nonempty have : infX < supX := Ne.lt_of_le inf_eq_sup this exact classify_connected_reals_with_GLB_lt_LUB conn h_infX h_supX this @@ -251,15 +268,15 @@ theorem classify_connected_bounded_reals_nonempty_interior (h : (interior X) ≠ ∅) : isBoundedInterval X := by rcases classify_connected_bounded_reals conn above below with ⟨a, ha⟩ | bdd - . rw [ha, interior_singleton] at h + · rw [ha, interior_singleton] at h exact (h rfl).elim - . exact bdd + · exact bdd -- Some lemmas about bounded intervals in ℝ lemma isConnected_BoundedInterval (I : BoundedInterval) - : IsConnected (BoundedInterval_as_set I) := by - rw [BoundedInterval_as_set.eq_def] + : IsConnected (BoundedIntervalAsSet I) := by + rw [BoundedIntervalAsSet.eq_def] have ⟨a, b, lt, kind⟩ := I match kind with | IooKind => exact isConnected_Ioo lt @@ -268,7 +285,7 @@ lemma isConnected_BoundedInterval (I : BoundedInterval) | IccKind => exact isConnected_Icc (LT.lt.le lt) lemma BoundedInterval_subset_Icc (I : BoundedInterval) - : BoundedInterval_as_set I ⊆ Icc I.left_endpoint I.right_endpoint := by + : BoundedIntervalAsSet I ⊆ Icc I.leftEndpoint I.rightEndpoint := by have ⟨a, b, lt, kind⟩ := I match kind with | IooKind => exact Ioo_subset_Icc_self @@ -277,7 +294,7 @@ lemma BoundedInterval_subset_Icc (I : BoundedInterval) | IccKind => exact Eq.subset rfl lemma BoundedInterval_contains_Ioo (I : BoundedInterval) - : Ioo I.left_endpoint I.right_endpoint ⊆ BoundedInterval_as_set I := by + : Ioo I.leftEndpoint I.rightEndpoint ⊆ BoundedIntervalAsSet I := by have ⟨a, b, lt, kind⟩ := I match kind with | IooKind => exact Eq.subset rfl @@ -285,31 +302,32 @@ lemma BoundedInterval_contains_Ioo (I : BoundedInterval) | IcoKind => exact Ioo_subset_Ico_self | IccKind => exact Ioo_subset_Icc_self -lemma closure_BoundedInterval (I : BoundedInterval) : closure (BoundedInterval_as_set I) = Icc I.left_endpoint I.right_endpoint := by +lemma closure_BoundedInterval (I : BoundedInterval) : closure (BoundedIntervalAsSet I) = Icc + I.leftEndpoint I.rightEndpoint := by apply Subset.antisymm - . calc closure (BoundedInterval_as_set I) - ⊆ closure (Icc I.left_endpoint I.right_endpoint) + · calc closure (BoundedIntervalAsSet I) + ⊆ closure (Icc I.leftEndpoint I.rightEndpoint) := closure_mono (BoundedInterval_subset_Icc I) - _ = Icc I.left_endpoint I.right_endpoint + _ = Icc I.leftEndpoint I.rightEndpoint := IsClosed.closure_eq isClosed_Icc - . calc Icc I.left_endpoint I.right_endpoint - = closure (Ioo I.left_endpoint I.right_endpoint) + · calc Icc I.leftEndpoint I.rightEndpoint + = closure (Ioo I.leftEndpoint I.rightEndpoint) := (closure_Ioo (ne_of_lt I.left_lt_right)).symm - _ ⊆ closure (BoundedInterval_as_set I) + _ ⊆ closure (BoundedIntervalAsSet I) := closure_mono (BoundedInterval_contains_Ioo I) lemma isBoundedBelow_BoundedInterval (I : BoundedInterval) - : BddBelow (BoundedInterval_as_set I) := + : BddBelow (BoundedIntervalAsSet I) := BddBelow.mono (BoundedInterval_subset_Icc I) bddBelow_Icc lemma isBoundedAbove_BoundedInterval (I : BoundedInterval) - : BddAbove (BoundedInterval_as_set I) := + : BddAbove (BoundedIntervalAsSet I) := BddAbove.mono (BoundedInterval_subset_Icc I) bddAbove_Icc @[simp] lemma interior_BoundedInterval (I : BoundedInterval) - : interior (BoundedInterval_as_set I) = Ioo I.left_endpoint I.right_endpoint := by - rw [BoundedInterval_as_set.eq_def] + : interior (BoundedIntervalAsSet I) = Ioo I.leftEndpoint I.rightEndpoint := by + rw [BoundedIntervalAsSet.eq_def] have ⟨a, b, lt, kind⟩ := I match kind with | IooKind => dsimp; exact interior_Ioo @@ -321,12 +339,12 @@ lemma interior_BoundedInterval (I : BoundedInterval) @[simp] lemma Icc_diff_Ioo {a b : ℝ} (lt : a < b) : (Icc a b) \ (Ioo a b) = {a, b} := by apply Subset.antisymm - . rw [← Icc_sdiff_both] + · rw [← Icc_sdiff_both] exact sdiff_sdiff_le - . rintro x (xleft | xright) - . rw [mem_sdiff, mem_Icc, mem_Ioo, not_and] + · rintro x (xleft | xright) + · rw [mem_sdiff, mem_Icc, mem_Ioo, not_and] exact ⟨⟨by linarith, by linarith⟩, (by intro _; linarith)⟩ - . simp only [mem_singleton_iff] at xright + · simp only [mem_singleton_iff] at xright rw [xright] simp only [mem_sdiff, mem_Icc, le_refl, and_true, mem_Ioo, lt_self_iff_false, and_false, not_false_eq_true] @@ -334,7 +352,7 @@ lemma Icc_diff_Ioo {a b : ℝ} (lt : a < b) : (Icc a b) \ (Ioo a b) = {a, b} := @[simp] lemma frontier_BoundedInterval (I : BoundedInterval) - : frontier (BoundedInterval_as_set I) = {I.left_endpoint, I.right_endpoint} := by + : frontier (BoundedIntervalAsSet I) = {I.leftEndpoint, I.rightEndpoint} := by rw [frontier, closure_BoundedInterval I, interior_BoundedInterval I] exact Icc_diff_Ioo I.left_lt_right @@ -343,17 +361,17 @@ lemma pair_has_other {a b c : ℝ} (ne : a ≠ b) (h : c ∈ ({a, b} : Set ℝ)) simp only [mem_insert_iff, mem_singleton_iff, ne_eq, exists_eq_or_imp, exists_eq_left] simp only [mem_insert_iff, mem_singleton_iff] at h rcases h with ca | cb - . rw [← ca] at ne; right; exact ne.symm - . rw [← cb] at ne; left; exact ne + · rw [← ca] at ne; right; exact ne.symm + · rw [← cb] at ne; left; exact ne theorem other_endpoint {X : Set ℝ} (int : (interior X) ≠ ∅) (conn : IsConnected X) (above : BddAbove X) (below : BddBelow X) - (a : ℝ) (ha: a ∈ frontier X) : ∃b : ℝ, b ∈ frontier X ∧ b ≠ a:= by + (a : ℝ) (ha : a ∈ frontier X) : ∃b : ℝ, b ∈ frontier X ∧ b ≠ a:= by have ⟨I, XI⟩ := classify_connected_bounded_reals_nonempty_interior conn above below int rw [XI, frontier_BoundedInterval] rw [XI, frontier_BoundedInterval] at ha - have : I.left_endpoint ≠ I.right_endpoint := by + have : I.leftEndpoint ≠ I.rightEndpoint := by exact ne_of_lt I.left_lt_right exact pair_has_other (ne_of_lt I.left_lt_right) ha @@ -375,9 +393,9 @@ lemma characterize_Ioi {X : Set ℝ} (conn : IsConnected X) (above : ¬ BddAbove X) : X = Ioi infX := by rw [bddAbove_def] at above; push Not at above apply Subset.antisymm - . intro x xX + · intro x xX exact excluded_infX_lt_x xX h_infX infX_X - . intro x infX_lt_x + · intro x infX_lt_x rw [mem_Ioi] at infX_lt_x let ⟨B, BX, Bbig⟩ := above x have : Ioo infX B ⊆ X := @@ -389,9 +407,9 @@ lemma characterize_Ici {X : Set ℝ} (conn : IsConnected X) (above : ¬ BddAbove X) : X = Ici infX := by rw [bddAbove_def] at above; push Not at above apply Set.Subset.antisymm - . intro x xX + · intro x xX exact h_infX.1 xX - . intro x infX_le_x + · intro x infX_le_x have ⟨B, BX, Bbig⟩ := above x have : Set.Icc infX B ⊆ X := (ordconn_of_connected conn) infX infX_X B BX exact this ⟨infX_le_x, LT.lt.le Bbig⟩ @@ -402,17 +420,17 @@ lemma classify_Ixi {X : Set ℝ} (conn : IsConnected X) have ⟨infX, h_infX⟩ := Real.exists_isGLB (IsConnected.nonempty conn) below use infX by_cases infX_X : infX ∈ X - . right; exact characterize_Ici conn h_infX infX_X above - . left; exact characterize_Ioi conn h_infX infX_X above + · right; exact characterize_Ici conn h_infX infX_X above + · left; exact characterize_Ioi conn h_infX infX_X above lemma characterize_Iio {X : Set ℝ} (conn : IsConnected X) {supX : ℝ} (h_supX : IsLUB X supX) (supX_X : supX ∉ X) (below : ¬ BddBelow X) : X = Iio supX := by rw [bddBelow_def] at below; push Not at below apply Set.Subset.antisymm - . intro x xX + · intro x xX exact x_lt_excluded_supX xX h_supX supX_X - . intro x x_lt_supX + · intro x x_lt_supX rw [Set.mem_Iio] at x_lt_supX let ⟨A, AX, Asmall⟩ := below x have : Set.Ioo A supX ⊆ X := @@ -424,9 +442,9 @@ lemma characterize_Iic {X : Set ℝ} (conn : IsConnected X) (below : ¬ BddBelow X) : X = Iic supX := by rw [bddBelow_def] at below; push Not at below apply Set.Subset.antisymm - . intro x xX + · intro x xX exact h_supX.1 xX - . intro x x_le_supX + · intro x x_le_supX let ⟨A, AX, Asmall⟩ := below x have : Set.Icc A supX ⊆ X := (ordconn_of_connected conn) A AX supX supX_X exact this ⟨LT.lt.le Asmall, x_le_supX⟩ @@ -437,10 +455,11 @@ lemma classify_Iix {X : Set ℝ} (conn : IsConnected X) have ⟨supX, h_supX⟩ := Real.exists_isLUB (IsConnected.nonempty conn) above use supX by_cases supX_X : supX ∈ X - . right; exact characterize_Iic conn h_supX supX_X below - . left; exact characterize_Iio conn h_supX supX_X below + · right; exact characterize_Iic conn h_supX supX_X below + · left; exact characterize_Iio conn h_supX supX_X below -- Give names to the cases +/-- The possible forms of a nonempty connected subset of the real line. -/ inductive ConnectedRealClassification | of_univ : ConnectedRealClassification | of_Iio : ℝ → ConnectedRealClassification @@ -452,35 +471,39 @@ inductive ConnectedRealClassification open ConnectedRealClassification -def ConnectedRealClassification_as_set : ConnectedRealClassification → Set ℝ +/-- Interpret a connected-set classification as a subset of the real line. -/ +def ConnectedRealClassificationAsSet : ConnectedRealClassification → Set ℝ | of_univ => univ | of_Iio a => Iio a | of_Iic a => Iic a | of_Ioi a => Ioi a | of_Ici a => Ici a | of_singleton a => {a} - | of_bounded_interval I => BoundedInterval_as_set I + | of_bounded_interval I => BoundedIntervalAsSet I +/-- The set is represented by one of the connected real-set forms. -/ def isConnectedRealClassification (X : Set ℝ) := - ∃ I : ConnectedRealClassification, X = ConnectedRealClassification_as_set I + ∃ I : ConnectedRealClassification, X = ConnectedRealClassificationAsSet I theorem classify_connected_reals {X : Set ℝ} (conn : IsConnected X) : isConnectedRealClassification X := by by_cases below : BddBelow X - . by_cases above : BddAbove X - . rcases classify_connected_bounded_reals conn above below with sing | bdd - . let ⟨a, ha⟩ := sing + · by_cases above : BddAbove X + · rcases classify_connected_bounded_reals conn above below with sing | bdd + · let ⟨a, ha⟩ := sing use of_singleton a; exact ha - . let ⟨I, hI⟩ := bdd + · let ⟨I, hI⟩ := bdd use of_bounded_interval I; exact hI - . rcases classify_Ixi conn below above with ⟨a, hIoi | hIci⟩ - . use of_Ioi a; exact hIoi - . use of_Ici a; exact hIci - . by_cases above : BddAbove X - . rcases classify_Iix conn below above with ⟨a, hIio | hIic⟩ - . use of_Iio a + · rcases classify_Ixi conn below above with ⟨a, hIoi | hIci⟩ + · use of_Ioi a; exact hIoi + · use of_Ici a; exact hIci + · by_cases above : BddAbove X + · rcases classify_Iix conn below above with ⟨a, hIio | hIic⟩ + · use of_Iio a exact hIio - . use of_Iic a + · use of_Iic a exact hIic - . use of_univ + · use of_univ exact characterize_univ conn below above + +end RealIntervals diff --git a/LeanPool/OneManifold/OneMfld/TransitionMono.lean b/LeanPool/OneManifold/OneMfld/TransitionMono.lean index 905fad91e8..695b2ccb1c 100644 --- a/LeanPool/OneManifold/OneMfld/TransitionMono.lean +++ b/LeanPool/OneManifold/OneMfld/TransitionMono.lean @@ -3,7 +3,9 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic +import Mathlib.Topology.Bornology.Real +import Mathlib.Topology.UniformSpace.Real /-! # Monotonicity of transition maps diff --git a/LeanPool/OneManifold/OneMfld/TwoComponents.lean b/LeanPool/OneManifold/OneMfld/TwoComponents.lean index 45c0a6ea49..97cef31d5e 100644 --- a/LeanPool/OneManifold/OneMfld/TwoComponents.lean +++ b/LeanPool/OneManifold/OneMfld/TwoComponents.lean @@ -3,7 +3,7 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic import LeanPool.OneManifold.OneMfld.Outer import LeanPool.OneManifold.OneMfld.TransitionMono import LeanPool.OneManifold.OneMfld.GlueCore @@ -115,7 +115,7 @@ theorem overlap_mono_on [T2Space M] (a b : OpenPartialHomeomorph M NNReal) have hlim2' : Tendsto a.symm (𝓝[Ioo p r] r) (𝓝 (b.symm q)) := by apply Tendsto.congr' _ hlim2 filter_upwards [self_mem_nhdsWithin] with t ht - show b.symm (τ t) = a.symm t + change b.symm (τ t) = a.symm t simp only [hτdef] exact b.left_inv (hWb (hsymm t ht).1) have hz : a.symm r = b.symm q := tendsto_nhds_unique' hFne hlim1 hlim2' @@ -208,7 +208,7 @@ theorem overlap_mono_on' [T2Space M] (a b : OpenPartialHomeomorph M NNReal) have hlim2' : Tendsto a.symm (𝓝[Ioo p r] p) (𝓝 (b.symm w)) := by apply Tendsto.congr' _ hlim2 filter_upwards [self_mem_nhdsWithin] with t ht - show b.symm (τ t) = a.symm t + change b.symm (τ t) = a.symm t simp only [hτdef] exact b.left_inv (hWb (hsymm t ht).1) have hz : a.symm p = b.symm w := tendsto_nhds_unique' hFne hlim1 hlim2' diff --git a/LeanPool/OneManifold/OneMfld/UnitInterval.lean b/LeanPool/OneManifold/OneMfld/UnitInterval.lean index 30f174b2cc..d49421d9ef 100644 --- a/LeanPool/OneManifold/OneMfld/UnitInterval.lean +++ b/LeanPool/OneManifold/OneMfld/UnitInterval.lean @@ -3,8 +3,17 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib +import Mathlib.Tactic +import Mathlib.Topology.MetricSpace.Pseudo.Lemmas +import Mathlib.Topology.Order.Compact +/-! +# UnitInterval + +Supporting results for the classification of compact one-dimensional manifolds. +-/ + +/-- The closed unit interval in the real line. -/ def UnitInterval : Set Real := { x : Real | 0 ≤ x ∧ x ≤ 1 } /-- `UnitInterval` is definitionally `Set.Icc 0 1`; this bridge unlocks Mathlib's From 1f4bccc213558fbfe60ecaf0ae32ce603392c7e0 Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Mon, 21 Sep 2026 21:00:35 +0000 Subject: [PATCH 03/16] Split manifold classification and gluing proofs into geometric lemmas --- LeanPool/OneManifold/OneMfld/CircleGlue.lean | 785 ++++++++++-------- .../OneManifold/OneMfld/ClassifyInterval.lean | 618 +++++++------- LeanPool/OneManifold/OneMfld/GlueUI.lean | 163 ++-- 3 files changed, 876 insertions(+), 690 deletions(-) diff --git a/LeanPool/OneManifold/OneMfld/CircleGlue.lean b/LeanPool/OneManifold/OneMfld/CircleGlue.lean index 8dce5ec82e..5793f9360b 100644 --- a/LeanPool/OneManifold/OneMfld/CircleGlue.lean +++ b/LeanPool/OneManifold/OneMfld/CircleGlue.lean @@ -316,6 +316,450 @@ private lemma exists_normalized_charts {M : Type*} [TopologicalSpace M] [T2Space hAs, hBs, hAt, hBt, hunion', himA₀, himA₁, himB₀, himB₁, hr'mem.1, hrp', hp'mem.2, hcA, hs'mem.1, hsq', hq'mem.2, hcB⟩ +private theorem circle_overlap_membership + {M : Type*} + [TopologicalSpace M] + (A B : OpenPartialHomeomorph M NNReal) + (W₀ W₁ : Set M) + (r p s q : NNReal) + (hBt : B.target = Ioo 0 1) + (hunion : A.source ∩ B.source = W₀ ∪ W₁) + (himgA₀ : A '' W₀ = Ioo 0 r) + (himgA₁ : A '' W₁ = Ioo p 1) + (himgB₀ : B '' W₀ = Ioo q 1) + (himgB₁ : B '' W₁ = Ioo 0 s) + (hrp : r ≤ p) + (hsq : s ≤ q) + (hW₀A : W₀ ⊆ A.source) + (hW₀B : W₀ ⊆ B.source) + (hW₁A : W₁ ⊆ A.source) + (hW₁B : W₁ ⊆ B.source) + (ν : NNReal) + (hpν : p < ν) + (m₁ : M) + (hm₁ν : A m₁ = ν) + (μ : NNReal) + (hqμ : q < μ) + (m₀ : M) + (hm₀μ : B m₀ = μ) + (hρmem : A m₀ ∈ Ioo 0 r) + (hσmem : B m₁ ∈ Ioo 0 s) + (K₀ : ∀ x ∈ W₀, A m₀ ≤ A x ↔ B m₀ ≤ B x) + (K₁ : ∀ x ∈ W₁, A x ≤ A m₁ ↔ B x ≤ B m₁) + (sset : Set M) + (hssetdef : sset = A.source ∩ A ⁻¹' Icc (A m₀) ν) : + ∀ y ∈ B.source, B y ≤ B m₁ ∨ B m₀ ≤ B y ↔ y ∈ sset := by + classical + intro y hy + rw [hssetdef] + by_cases hyA : y ∈ A.source + · have hyS : y ∈ W₀ ∪ W₁ := by rw [← hunion]; exact ⟨hyA, hy⟩ + rcases hyS with hyW | hyW + · have hAy : A y ∈ Ioo 0 r := by rw [← himgA₀]; exact mem_image_of_mem _ hyW + have hBy : B y ∈ Ioo q 1 := by rw [← himgB₀]; exact mem_image_of_mem _ hyW + have hnots : ¬ (B y ≤ B m₁) := by + rw [not_le] + exact lt_trans (lt_of_lt_of_le hσmem.2 hsq) hBy.1 + have hK := K₀ y hyW + constructor + · rintro (hc | hc) + · exact absurd hc hnots + · refine ⟨hyA, ?_⟩ + rw [mem_preimage] + exact ⟨hK.mpr hc, le_of_lt (lt_of_lt_of_le hAy.2 (hrp.trans hpν.le))⟩ + · rintro ⟨-, hmem⟩ + rw [mem_preimage] at hmem + exact Or.inr (hK.mp hmem.1) + · have hAy : A y ∈ Ioo p 1 := by rw [← himgA₁]; exact mem_image_of_mem _ hyW + have hBy : B y ∈ Ioo 0 s := by rw [← himgB₁]; exact mem_image_of_mem _ hyW + have hnots : ¬ (B m₀ ≤ B y) := by + rw [not_le, hm₀μ] + exact lt_trans (lt_of_lt_of_le hBy.2 hsq) hqμ + have hK := K₁ y hyW + constructor + · rintro (hc | hc) + · refine ⟨hyA, ?_⟩ + rw [mem_preimage] + refine ⟨le_of_lt (lt_trans (lt_of_lt_of_le hρmem.2 hrp) hAy.1), ?_⟩ + rw [← hm₁ν] + exact hK.mpr hc + · exact absurd hc hnots + · rintro ⟨-, hmem⟩ + rw [mem_preimage] at hmem + refine Or.inl (hK.mp ?_) + rw [hm₁ν] + exact hmem.2 + · constructor + · rintro (hc | hc) + · exfalso + have hBy0 : (0:NNReal) < B y := by + have hmem := B.map_source hy + rw [hBt] at hmem + exact hmem.1 + have hmem : B y ∈ Ioo 0 s := ⟨hBy0, lt_of_le_of_lt hc hσmem.2⟩ + have hyW : y ∈ W₁ := mem_of_image_mem B hW₁B himgB₁ hy hmem + exact hyA (hW₁A hyW) + · exfalso + have hBy1 : B y < 1 := by + have hmem := B.map_source hy + rw [hBt] at hmem + exact hmem.2 + rw [hm₀μ] at hc + have hmem : B y ∈ Ioo q 1 := ⟨lt_of_lt_of_le hqμ hc, hBy1⟩ + have hyW : y ∈ W₀ := mem_of_image_mem B hW₀B himgB₀ hy hmem + exact hyA (hW₀A hyW) + · rintro ⟨hyA', -⟩ + exact absurd hyA' hyA + +private theorem glue_circle_arcs + {M : Type*} + [TopologicalSpace M] + (A B : OpenPartialHomeomorph M NNReal) + (W₀ W₁ : Set M) + (r p : NNReal) + (hAt : A.target = Ioo 0 1) + (himgA₀ : A '' W₀ = Ioo 0 r) + (himgA₁ : A '' W₁ = Ioo p 1) + (hW₀A : W₀ ⊆ A.source) + (hW₀B : W₀ ⊆ B.source) + (hW₁A : W₁ ⊆ A.source) + (hW₁B : W₁ ⊆ B.source) + (ν : NNReal) + (hpν : p < ν) + (m₁ : M) + (hm₁ν : A m₁ = ν) + (μ : NNReal) + (m₀ : M) + (hm₀μ : B m₀ = μ) + (hm₀A : m₀ ∈ A.source) + (hm₀B : m₀ ∈ B.source) + (hm₁A : m₁ ∈ A.source) + (hm₁B : m₁ ∈ B.source) + (hρmem : A m₀ ∈ Ioo 0 r) + (kα kg g0 : ℝ) + (hkα1 : kα < 1) + (hkg1 : kg < 1) + (hid1 : kg * ↑(B m₁) + g0 = kα * ↑ν) + (hid2 : kg * ↑μ + g0 = 1 + kα * ↑(A m₀)) + (hcg0 : kα * ↑(A m₀) < g0) + (hg0d : g0 < kα * ↑ν) + (h1c : 1 + kα * ↑(A m₀) < g0 + kg) + (hc₁0 : 0 < kα * ↑(A m₀)) + (hd₁kα : kα * ↑ν < kα) + (hc₁1 : kα * ↑(A m₀) < 1) + (hc₁d₁ : kα * ↑(A m₀) ≤ kα * ↑ν) + (e e' : OpenPartialHomeomorph M (AddCircle 1)) + (heval : ∀ (x : M), e x = ↑(kα * ↑(A x))) + (he'val : ∀ (x : M), e' x = ↑(kg * ↑(B x) + g0)) + (hes : e.source = A.source) + (he's : e'.source = B.source) + (htargetE : e.target = QuotientAddGroup.mk '' Ioo 0 kα) + (htargetE' : e'.target = QuotientAddGroup.mk '' Ioo g0 (g0 + kg)) + (sset : Set M) + (tset : Set (ℝ ⧸ AddSubgroup.zmultiples 1)) + (hssub : sset ⊆ A.source) + (H : e.IsImage sset tset) + (claim1 : + ∀ v ∈ Ioo g0 (g0 + kg), ↑v ∈ tset ↔ v ∈ Icc (kα * ↑(A m₀)) (kα * ↑ν) ∨ v ∈ Icc (1 + + kα * ↑(A m₀)) (1 + kα * ↑ν)) + (H' : e'.IsImage sset tset) + (hfrontier : frontier tset ⊆ {↑(kα * ↑(A m₀)), ↑(kα * ↑ν)}) + (hssetdef : sset = A.source ∩ A ⁻¹' Icc (A m₀) ν) + (htsetdef : tset = ((↑) : ℝ → AddCircle (1 : ℝ)) '' Icc (kα * (A m₀ : ℝ)) (kα * (ν : ℝ))) : + ∃ f : OpenPartialHomeomorph M (AddCircle (1 : ℝ)), + f.source = A.source ∪ B.source ∧ f.target = univ := by + classical + -- Injectivity of each chart identifies the split-point fibers. + have he₀ : e m₀ = ((kα * ((A m₀ : NNReal) : ℝ) : ℝ) : AddCircle (1 : ℝ)) := + heval m₀ + have he₁ : e m₁ = ((kα * ((ν : NNReal) : ℝ) : ℝ) : AddCircle (1 : ℝ)) := by + rw [heval m₁, hm₁ν] + have he'₀ : e' m₀ = e m₀ := by + rw [he'val m₀, hm₀μ, hid2, heval m₀, add_comm 1] + exact addCircle_coe_add_one _ + have he'₁ : e' m₁ = e m₁ := by + rw [he'val m₁, hid1, heval m₁, hm₁ν] + have Pce : ∀ x ∈ A.source, + (e x = ((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)) ↔ x = m₀) := by + intro x hx + rw [← he₀] + exact ⟨fun h => e.injOn (hes.symm ▸ hx) (hes.symm ▸ hm₀A) h, congrArg e⟩ + have Pde : ∀ x ∈ A.source, + (e x = ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)) ↔ x = m₁) := by + intro x hx + rw [← he₁] + exact ⟨fun h => e.injOn (hes.symm ▸ hx) (hes.symm ▸ hm₁A) h, congrArg e⟩ + have Pce' : ∀ y ∈ B.source, + (e' y = ((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)) ↔ y = m₀) := by + intro y hy + rw [← he₀, ← he'₀] + exact ⟨fun h => e'.injOn (he's.symm ▸ hy) (he's.symm ▸ hm₀B) h, congrArg e'⟩ + have Pde' : ∀ y ∈ B.source, + (e' y = ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)) ↔ y = m₁) := by + intro y hy + rw [← he₁, ← he'₁] + exact ⟨fun h => e'.injOn (he's.symm ▸ hy) (he's.symm ▸ hm₁B) h, congrArg e'⟩ + -- Frontier agreement and equality on the frontier. + have hpre := H.frontier.preimage_eq + have hpre' := H'.frontier.preimage_eq + have Hs : e.source ∩ frontier sset = e'.source ∩ frontier sset := by + rw [← hpre, ← hpre'] + ext x + simp only [mem_inter_iff, mem_preimage] + constructor + · rintro ⟨hx, hfx⟩ + have hx' : x ∈ A.source := by rwa [hes] at hx + have hex := hfrontier hfx + simp only [mem_insert_iff, mem_singleton_iff] at hex + rcases hex with hcx | hdx + · have hxm : x = m₀ := (Pce x hx').mp hcx + subst hxm + refine ⟨by rw [he's]; exact hm₀B, ?_⟩ + rw [(Pce' x hm₀B).mpr rfl, ← hcx] + exact hfx + · have hxm : x = m₁ := (Pde x hx').mp hdx + subst hxm + refine ⟨by rw [he's]; exact hm₁B, ?_⟩ + rw [(Pde' x hm₁B).mpr rfl, ← hdx] + exact hfx + · rintro ⟨hx, hfx⟩ + have hx' : x ∈ B.source := by rwa [he's] at hx + have hex := hfrontier hfx + simp only [mem_insert_iff, mem_singleton_iff] at hex + rcases hex with hcx | hdx + · have hxm : x = m₀ := (Pce' x hx').mp hcx + subst hxm + refine ⟨by rw [hes]; exact hm₀A, ?_⟩ + rw [(Pce x hm₀A).mpr rfl, ← hcx] + exact hfx + · have hxm : x = m₁ := (Pde' x hx').mp hdx + subst hxm + refine ⟨by rw [hes]; exact hm₁A, ?_⟩ + rw [(Pde x hm₁A).mpr rfl, ← hdx] + exact hfx + have Heq : Set.EqOn e e' (e.source ∩ frontier sset) := by + rw [← hpre] + rintro x ⟨hx, hfx⟩ + rw [mem_preimage] at hfx + have hx' : x ∈ A.source := by rwa [hes] at hx + have hex := hfrontier hfx + simp only [mem_insert_iff, mem_singleton_iff] at hex + rcases hex with hcx | hdx + · have hxm : x = m₀ := (Pce x hx').mp hcx + subst hxm + rw [hcx, (Pce' x hm₀B).mpr rfl] + · have hxm : x = m₁ := (Pde x hx').mp hdx + subst hxm + rw [hdx, (Pde' x hm₁B).mpr rfl] + -- Glue. + refine ⟨e.piecewise e' sset tset H H' Hs Heq, ?_, ?_⟩ + · change Set.ite sset e.source e'.source = A.source ∪ B.source + have hite : Set.ite sset e.source e'.source + = (e.source ∩ sset) ∪ (e'.source \ sset) := rfl + rw [hite, hes, he's] + apply Subset.antisymm + · rintro x (⟨hx, -⟩ | ⟨hx, -⟩) + · exact Or.inl hx + · exact Or.inr hx + · rintro x hx + by_cases hxs : x ∈ sset + · exact Or.inl ⟨hssub hxs, hxs⟩ + · rcases hx with hxa | hxb + · have hxB : x ∈ B.source := by + have hAx : A x ∈ Ioo (0:NNReal) 1 := hAt ▸ A.map_source hxa + have hnot : A x ∉ Icc (A m₀) ν := by + intro hmem + exact hxs (by rw [hssetdef]; exact ⟨hxa, hmem⟩) + rcases lt_or_ge (A x) (A m₀) with hlt | hge + · have hmem : A x ∈ Ioo 0 r := ⟨hAx.1, lt_trans hlt hρmem.2⟩ + exact hW₀B (mem_of_image_mem A hW₀A himgA₀ hxa hmem) + · rcases le_or_gt (A x) ν with hle | hgt + · exact absurd ⟨hge, hle⟩ hnot + · have hmem : A x ∈ Ioo p 1 := ⟨lt_trans hpν hgt, hAx.2⟩ + exact hW₁B (mem_of_image_mem A hW₁A himgA₁ hxa hmem) + exact Or.inr ⟨hxB, hxs⟩ + · exact Or.inr ⟨hxb, hxs⟩ + · change Set.ite tset e.target e'.target = univ + have hite : Set.ite tset e.target e'.target + = (e.target ∩ tset) ∪ (e'.target \ tset) := rfl + rw [hite] + have h1 : e.target ∩ tset = tset := by + apply inter_eq_right.mpr + rw [htargetE, htsetdef] + exact image_mono + (fun u hu => ⟨lt_of_lt_of_le hc₁0 hu.1, lt_of_le_of_lt hu.2 hd₁kα⟩) + have h2 : e'.target \ tset = ((↑) : ℝ → AddCircle (1 : ℝ)) '' + (Ioo (kα * ((ν : NNReal):ℝ)) (kα * ((A m₀ : NNReal):ℝ) + 1)) := by + rw [htargetE'] + ext z + constructor + · rintro ⟨⟨v, hv, rfl⟩, hnt⟩ + have hnor : ¬(v ∈ Icc (kα * ((A m₀ : NNReal):ℝ)) (kα * ((ν : NNReal):ℝ)) ∨ + v ∈ Icc (1 + kα * ((A m₀ : NNReal):ℝ)) (1 + kα * ((ν : NNReal):ℝ))) := + fun hor => hnt ((claim1 v hv).mpr hor) + push Not at hnor + obtain ⟨hn1, hn2⟩ := hnor + rw [mem_Icc] at hn1 hn2 + push Not at hn1 hn2 + refine mem_image_of_mem _ ⟨?_, ?_⟩ + · exact hn1 (by linarith [hv.1]) + · by_contra hge + push Not at hge + have := hn2 (by linarith) + linarith [hv.2] + · rintro ⟨u, hu, rfl⟩ + have huv : u ∈ Ioo g0 (g0 + kg) := + ⟨lt_trans hg0d hu.1, by linarith [hu.2]⟩ + refine ⟨mem_image_of_mem _ huv, ?_⟩ + intro ht + rcases (claim1 u huv).mp ht with hin | hin + · rw [mem_Icc] at hin + linarith [hu.1, hin.2] + · rw [mem_Icc] at hin + linarith [hu.2, hin.1] + rw [h1, h2, htsetdef] + exact addCircle_arc_union_covers hc₁d₁ (by linarith) + +private theorem circle_coordinate_H + {M : Type*} + [TopologicalSpace M] + (A : OpenPartialHomeomorph M NNReal) + (ν : NNReal) + (m₀ : M) + (kα : ℝ) + (hkα0 : 0 < kα) + (hkα1 : kα < 1) + (hc₁0 : 0 < kα * ↑(A m₀)) + (hd₁kα : kα * ↑ν < kα) + (e : OpenPartialHomeomorph M (AddCircle 1)) + (heval : ∀ (x : M), e x = ↑(kα * ↑(A x))) + (hbounds : ∀ x ∈ A.source, 0 < kα * ↑(A x) ∧ kα * ↑(A x) < kα) + (hes : e.source = A.source) + (sset : Set M) + (hssetdef : sset = A.source ∩ A ⁻¹' Icc (A m₀) ν) + (tset : Set (ℝ ⧸ AddSubgroup.zmultiples 1)) + (htsetdef : tset = QuotientAddGroup.mk '' Icc (kα * ↑(A m₀)) (kα * ↑ν)) : + e.IsImage sset tset := by + classical + intro x hx + rw [hes] at hx + rw [heval x] + obtain ⟨hb0, hb1⟩ := hbounds x hx + constructor + · intro hy + rw [htsetdef] at hy + rcases hy with ⟨y, hy, hye⟩ + have hyeq : y = kα * ((A x : NNReal):ℝ) := by + apply addCircle_coe_inj hye + rw [abs_lt] + constructor + · linarith [hy.1] + · linarith [hy.2] + rw [hyeq] at hy + have hxle : ((A m₀ : NNReal):ℝ) ≤ ((A x : NNReal):ℝ) := le_of_mul_le_mul_left hy.1 hkα0 + have hxge : ((A x : NNReal):ℝ) ≤ ((ν : NNReal):ℝ) := le_of_mul_le_mul_left hy.2 hkα0 + rw [hssetdef] + refine ⟨hx, ?_⟩ + rw [mem_preimage] + exact ⟨by exact_mod_cast hxle, by exact_mod_cast hxge⟩ + · intro hmem + rw [hssetdef] at hmem + obtain ⟨-, hmem2⟩ := hmem + rw [mem_preimage] at hmem2 + have h1' : ((A m₀ : NNReal):ℝ) ≤ ((A x : NNReal):ℝ) := by exact_mod_cast hmem2.1 + have h2' : ((A x : NNReal):ℝ) ≤ ((ν : NNReal):ℝ) := by exact_mod_cast hmem2.2 + rw [htsetdef] + exact mem_image_of_mem _ ⟨mul_le_mul_of_nonneg_left h1' hkα0.le, + mul_le_mul_of_nonneg_left h2' hkα0.le⟩ + +private theorem circle_coordinate_claim1 + {M : Type*} + [TopologicalSpace M] + (A : OpenPartialHomeomorph M NNReal) + (ν : NNReal) + (m₀ : M) + (kα kg g0 : ℝ) + (hkα1 : kα < 1) + (hkg1 : kg < 1) + (hg0d : g0 < kα * ↑ν) + (h1c : 1 + kα * ↑(A m₀) < g0 + kg) + (hc₁0 : 0 < kα * ↑(A m₀)) + (hd₁kα : kα * ↑ν < kα) + (tset : Set (ℝ ⧸ AddSubgroup.zmultiples 1)) + (htsetdef : tset = QuotientAddGroup.mk '' Icc (kα * ↑(A m₀)) (kα * ↑ν)) : + ∀ v ∈ Ioo g0 (g0 + kg), + ↑v ∈ tset ↔ v ∈ Icc (kα * ↑(A m₀)) (kα * ↑ν) ∨ v ∈ Icc (1 + kα * ↑(A m₀)) (1 + kα * ↑ν) := by + classical + intro v hv + rw [htsetdef] + constructor + · rintro ⟨z, hz, hze⟩ + have h1 : -1 < v - z := by linarith [hz.2, hv.1] + have h2 : v - z < 2 := by linarith [hz.1, hv.2] + rcases addCircle_eq_or_eq_add_one hze.symm h1 h2 with heq | heq + · left; rw [heq]; exact hz + · right; rw [heq]; exact ⟨by linarith [hz.1], by linarith [hz.2]⟩ + · rintro (hv1 | hv2) + · exact mem_image_of_mem _ hv1 + · refine ⟨v - 1, ⟨by linarith [hv2.1], by linarith [hv2.2]⟩, ?_⟩ + rw [← addCircle_coe_add_one (v - 1), sub_add_cancel] + +private theorem circle_coordinate_claim2 + {M : Type*} + [TopologicalSpace M] + (A B : OpenPartialHomeomorph M NNReal) + (ν : NNReal) + (m₁ : M) + (μ : NNReal) + (m₀ : M) + (hm₀μ : B m₀ = μ) + (kα kg g0 : ℝ) + (hkg0 : 0 < kg) + (hkg1 : kg < 1) + (hid1 : kg * ↑(B m₁) + g0 = kα * ↑ν) + (hid2 : kg * ↑μ + g0 = 1 + kα * ↑(A m₀)) + (hg0d : g0 < kα * ↑ν) + (h1c : 1 + kα * ↑(A m₀) < g0 + kg) + (hb'bounds : ∀ x ∈ B.source, g0 < kg * ↑(B x) + g0 ∧ kg * ↑(B x) + g0 < g0 + kg) : + ∀ y ∈ B.source, + kg * ↑(B y) + g0 ∈ Icc (kα * ↑(A m₀)) (kα * ↑ν) ∨ kg * ↑(B y) + g0 ∈ Icc (1 + kα * ↑(A m₀)) + (1 + kα * ↑ν) ↔ + B y ≤ B m₁ ∨ B m₀ ≤ B y := by + classical + intro y hy + obtain ⟨hb0, hb1⟩ := hb'bounds y hy + constructor + · rintro (hc | hc) + · left + have h' : kg * ((B y : NNReal):ℝ) + g0 ≤ kg * ((B m₁ : NNReal):ℝ) + g0 := by + rw [hid1]; exact hc.2 + have hby : ((B y : NNReal):ℝ) ≤ ((B m₁ : NNReal):ℝ) := + le_of_mul_le_mul_left (by linarith) hkg0 + exact_mod_cast hby + · right + have h' : kg * ((μ : NNReal):ℝ) + g0 ≤ kg * ((B y : NNReal):ℝ) + g0 := by + rw [hid2]; exact hc.1 + have hby : ((μ : NNReal):ℝ) ≤ ((B y : NNReal):ℝ) := + le_of_mul_le_mul_left (by linarith) hkg0 + rw [hm₀μ] + exact_mod_cast hby + · rintro (hc | hc) + · left + have hby : ((B y : NNReal):ℝ) ≤ ((B m₁ : NNReal):ℝ) := by exact_mod_cast hc + constructor + · linarith + · rw [← hid1] + have := mul_le_mul_of_nonneg_left hby hkg0.le + linarith + · right + rw [hm₀μ] at hc + have hby : ((μ : NNReal):ℝ) ≤ ((B y : NNReal):ℝ) := by exact_mod_cast hc + constructor + · rw [← hid2] + have := mul_le_mul_of_nonneg_left hby hkg0.le + linarith + · linarith + /-- Assemble the circle chart from the normalized data: embed each chart as an arc of `AddCircle 1` and glue along a closed sub-arc via `piecewise`. -/ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Space M] @@ -484,155 +928,27 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa (Icc (kα * ((A m₀ : NNReal):ℝ)) (kα * ((ν : NNReal):ℝ))) with htsetdef have hssub : sset ⊆ A.source := by rw [hssetdef]; exact inter_subset_left -- `e` maps `sset` to `tset`. - have H : e.IsImage sset tset := by - intro x hx - rw [hes] at hx - rw [heval x] - obtain ⟨hb0, hb1⟩ := hbounds x hx - constructor - · rintro ⟨y, hy, hye⟩ - have hyeq : y = kα * ((A x : NNReal):ℝ) := by - apply addCircle_coe_inj hye - rw [abs_lt] - constructor - · linarith [hy.1] - · linarith [hy.2] - rw [hyeq] at hy - have hxle : ((A m₀ : NNReal):ℝ) ≤ ((A x : NNReal):ℝ) := le_of_mul_le_mul_left hy.1 hkα0 - have hxge : ((A x : NNReal):ℝ) ≤ ((ν : NNReal):ℝ) := le_of_mul_le_mul_left hy.2 hkα0 - rw [hssetdef] - refine ⟨hx, ?_⟩ - rw [mem_preimage] - exact ⟨by exact_mod_cast hxle, by exact_mod_cast hxge⟩ - · intro hmem - rw [hssetdef] at hmem - obtain ⟨-, hmem2⟩ := hmem - rw [mem_preimage] at hmem2 - have h1' : ((A m₀ : NNReal):ℝ) ≤ ((A x : NNReal):ℝ) := by exact_mod_cast hmem2.1 - have h2' : ((A x : NNReal):ℝ) ≤ ((ν : NNReal):ℝ) := by exact_mod_cast hmem2.2 - rw [htsetdef] - exact mem_image_of_mem _ ⟨mul_le_mul_of_nonneg_left h1' hkα0.le, - mul_le_mul_of_nonneg_left h2' hkα0.le⟩ + have H : e.IsImage sset tset := + circle_coordinate_H A ν m₀ kα hkα0 hkα1 hc₁0 hd₁kα e heval hbounds hes sset hssetdef tset + htsetdef -- Windows: membership of a point of the `e'`-arc in `tset`. have claim1 : ∀ v : ℝ, v ∈ Ioo g0 (g0 + kg) → (((v : ℝ) : AddCircle (1 : ℝ)) ∈ tset ↔ v ∈ Icc (kα * ((A m₀ : NNReal):ℝ)) (kα * ((ν : NNReal):ℝ)) ∨ - v ∈ Icc (1 + kα * ((A m₀ : NNReal):ℝ)) (1 + kα * ((ν : NNReal):ℝ))) := by - intro v hv - rw [htsetdef] - constructor - · rintro ⟨z, hz, hze⟩ - have h1 : -1 < v - z := by linarith [hz.2, hv.1] - have h2 : v - z < 2 := by linarith [hz.1, hv.2] - rcases addCircle_eq_or_eq_add_one hze.symm h1 h2 with heq | heq - · left; rw [heq]; exact hz - · right; rw [heq]; exact ⟨by linarith [hz.1], by linarith [hz.2]⟩ - · rintro (hv1 | hv2) - · exact mem_image_of_mem _ hv1 - · refine ⟨v - 1, ⟨by linarith [hv2.1], by linarith [hv2.2]⟩, ?_⟩ - rw [← addCircle_coe_add_one (v - 1), sub_add_cancel] + v ∈ Icc (1 + kα * ((A m₀ : NNReal):ℝ)) (1 + kα * ((ν : NNReal):ℝ))) := + circle_coordinate_claim1 A ν m₀ kα kg g0 hkα1 hkg1 hg0d h1c hc₁0 hd₁kα tset htsetdef -- Translation of the window membership into `B`-coordinate inequalities. have claim2 : ∀ y ∈ B.source, ((kg * ((B y : NNReal):ℝ) + g0 ∈ Icc (kα * ((A m₀ : NNReal):ℝ)) (kα * ((ν : NNReal):ℝ)) ∨ kg * ((B y : NNReal):ℝ) + g0 ∈ Icc (1 + kα * ((A m₀ : NNReal):ℝ)) (1 + kα * ((ν : NNReal):ℝ))) - ↔ (B y ≤ B m₁ ∨ B m₀ ≤ B y)) := by - intro y hy - obtain ⟨hb0, hb1⟩ := hb'bounds y hy - constructor - · rintro (hc | hc) - · left - have h' : kg * ((B y : NNReal):ℝ) + g0 ≤ kg * ((B m₁ : NNReal):ℝ) + g0 := by - rw [hid1]; exact hc.2 - have hby : ((B y : NNReal):ℝ) ≤ ((B m₁ : NNReal):ℝ) := - le_of_mul_le_mul_left (by linarith) hkg0 - exact_mod_cast hby - · right - have h' : kg * ((μ : NNReal):ℝ) + g0 ≤ kg * ((B y : NNReal):ℝ) + g0 := by - rw [hid2]; exact hc.1 - have hby : ((μ : NNReal):ℝ) ≤ ((B y : NNReal):ℝ) := - le_of_mul_le_mul_left (by linarith) hkg0 - rw [hm₀μ] - exact_mod_cast hby - · rintro (hc | hc) - · left - have hby : ((B y : NNReal):ℝ) ≤ ((B m₁ : NNReal):ℝ) := by exact_mod_cast hc - constructor - · linarith - · rw [← hid1] - have := mul_le_mul_of_nonneg_left hby hkg0.le - linarith - · right - rw [hm₀μ] at hc - have hby : ((μ : NNReal):ℝ) ≤ ((B y : NNReal):ℝ) := by exact_mod_cast hc - constructor - · rw [← hid2] - have := mul_le_mul_of_nonneg_left hby hkg0.le - linarith - · linarith + ↔ (B y ≤ B m₁ ∨ B m₀ ≤ B y)) := + circle_coordinate_claim2 A B ν m₁ μ m₀ hm₀μ kα kg g0 hkg0 hkg1 hid1 hid2 hg0d h1c hb'bounds -- The `B`-coordinate inequalities describe exactly `sset`. - have claim3 : ∀ y ∈ B.source, ((B y ≤ B m₁ ∨ B m₀ ≤ B y) ↔ y ∈ sset) := by - intro y hy - rw [hssetdef] - by_cases hyA : y ∈ A.source - · have hyS : y ∈ W₀ ∪ W₁ := by rw [← hunion]; exact ⟨hyA, hy⟩ - rcases hyS with hyW | hyW - · have hAy : A y ∈ Ioo 0 r := by rw [← himgA₀]; exact mem_image_of_mem _ hyW - have hBy : B y ∈ Ioo q 1 := by rw [← himgB₀]; exact mem_image_of_mem _ hyW - have hnots : ¬ (B y ≤ B m₁) := by - rw [not_le] - exact lt_trans (lt_of_lt_of_le hσmem.2 hsq) hBy.1 - have hK := K₀ y hyW - constructor - · rintro (hc | hc) - · exact absurd hc hnots - · refine ⟨hyA, ?_⟩ - rw [mem_preimage] - exact ⟨hK.mpr hc, le_of_lt (lt_of_lt_of_le hAy.2 (hrp.trans hpν.le))⟩ - · rintro ⟨-, hmem⟩ - rw [mem_preimage] at hmem - exact Or.inr (hK.mp hmem.1) - · have hAy : A y ∈ Ioo p 1 := by rw [← himgA₁]; exact mem_image_of_mem _ hyW - have hBy : B y ∈ Ioo 0 s := by rw [← himgB₁]; exact mem_image_of_mem _ hyW - have hnots : ¬ (B m₀ ≤ B y) := by - rw [not_le, hm₀μ] - exact lt_trans (lt_of_lt_of_le hBy.2 hsq) hqμ - have hK := K₁ y hyW - constructor - · rintro (hc | hc) - · refine ⟨hyA, ?_⟩ - rw [mem_preimage] - refine ⟨le_of_lt (lt_trans (lt_of_lt_of_le hρmem.2 hrp) hAy.1), ?_⟩ - rw [← hm₁ν] - exact hK.mpr hc - · exact absurd hc hnots - · rintro ⟨-, hmem⟩ - rw [mem_preimage] at hmem - refine Or.inl (hK.mp ?_) - rw [hm₁ν] - exact hmem.2 - · constructor - · rintro (hc | hc) - · exfalso - have hBy0 : (0:NNReal) < B y := by - have hmem := B.map_source hy - rw [hBt] at hmem - exact hmem.1 - have hmem : B y ∈ Ioo 0 s := ⟨hBy0, lt_of_le_of_lt hc hσmem.2⟩ - have hyW : y ∈ W₁ := mem_of_image_mem B hW₁B himgB₁ hy hmem - exact hyA (hW₁A hyW) - · exfalso - have hBy1 : B y < 1 := by - have hmem := B.map_source hy - rw [hBt] at hmem - exact hmem.2 - rw [hm₀μ] at hc - have hmem : B y ∈ Ioo q 1 := ⟨lt_of_lt_of_le hqμ hc, hBy1⟩ - have hyW : y ∈ W₀ := mem_of_image_mem B hW₀B himgB₀ hy hmem - exact hyA (hW₀A hyW) - · rintro ⟨hyA', -⟩ - exact absurd hyA' hyA + have claim3 : ∀ y ∈ B.source, ((B y ≤ B m₁ ∨ B m₀ ≤ B y) ↔ y ∈ sset) := + circle_overlap_membership A B W₀ W₁ r p s q hBt hunion himgA₀ himgA₁ himgB₀ himgB₁ + hrp hsq hW₀A hW₀B hW₁A hW₁B ν hpν m₁ hm₁ν μ hqμ m₀ hm₀μ hρmem hσmem K₀ K₁ sset hssetdef -- `e'` also maps `sset` to `tset`. have H' : e'.IsImage sset tset := by intro y hy @@ -647,195 +963,10 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ))} := by rw [htsetdef] exact addCircle_frontier_arc_subset hc₁d₁ - -- The endpoint classes are attained only at the split points. - have Pce : ∀ x ∈ A.source, - (e x = ((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)) ↔ x = m₀) := by - intro x hx - obtain ⟨hb0, hb1⟩ := hbounds x hx - constructor - · intro hcoe - rw [heval x] at hcoe - have heq : kα * ((A x : NNReal):ℝ) = kα * ((A m₀ : NNReal):ℝ) := by - apply addCircle_coe_inj hcoe - rw [abs_lt] - exact ⟨by linarith, by linarith⟩ - have hAeq : A x = A m₀ := - NNReal.coe_injective (mul_left_cancel₀ hkα0.ne' heq) - exact A.injOn hx hm₀A hAeq - · rintro rfl - rw [heval x] - have Pde : ∀ x ∈ A.source, - (e x = ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)) ↔ x = m₁) := by - intro x hx - obtain ⟨hb0, hb1⟩ := hbounds x hx - have hd₁0 : (0:ℝ) < kα * ((ν : NNReal):ℝ) := by linarith - constructor - · intro hcoe - rw [heval x] at hcoe - have heq : kα * ((A x : NNReal):ℝ) = kα * ((ν : NNReal):ℝ) := by - apply addCircle_coe_inj hcoe - rw [abs_lt] - exact ⟨by linarith, by linarith⟩ - have hAeq : A x = ν := - NNReal.coe_injective (mul_left_cancel₀ hkα0.ne' heq) - rw [← hm₁ν] at hAeq - exact A.injOn hx hm₁A hAeq - · rintro rfl - rw [heval x, hm₁ν] - have Pce' : ∀ y ∈ B.source, - (e' y = ((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)) ↔ y = m₀) := by - intro y hy - obtain ⟨hb0, hb1⟩ := hb'bounds y hy - constructor - · intro hcoe - rw [he'val y] at hcoe - rcases addCircle_eq_or_eq_add_one hcoe (by linarith) (by linarith) with heq | heq - · exfalso; linarith - · have h' : kg * ((B y : NNReal):ℝ) + g0 = kg * ((μ : NNReal):ℝ) + g0 := by - rw [hid2]; linarith - have hBeq : B y = μ := - NNReal.coe_injective (mul_left_cancel₀ hkg0.ne' (by linarith)) - rw [← hm₀μ] at hBeq - exact B.injOn hy hm₀B hBeq - · rintro rfl - rw [he'val y, hm₀μ, hid2, add_comm 1 (kα * ((A y : NNReal):ℝ))] - exact addCircle_coe_add_one _ - have Pde' : ∀ y ∈ B.source, - (e' y = ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)) ↔ y = m₁) := by - intro y hy - obtain ⟨hb0, hb1⟩ := hb'bounds y hy - constructor - · intro hcoe - rw [he'val y] at hcoe - rcases addCircle_eq_or_eq_add_one hcoe (by linarith) (by linarith) with heq | heq - · have h' : kg * ((B y : NNReal):ℝ) + g0 = kg * ((B m₁ : NNReal):ℝ) + g0 := by - rw [hid1]; linarith - have hBeq : B y = B m₁ := - NNReal.coe_injective (mul_left_cancel₀ hkg0.ne' (by linarith)) - exact B.injOn hy hm₁B hBeq - · exfalso; linarith - · rintro rfl - rw [he'val y, hid1] - -- Frontier agreement and equality on the frontier. - have hpre := H.frontier.preimage_eq - have hpre' := H'.frontier.preimage_eq - have Hs : e.source ∩ frontier sset = e'.source ∩ frontier sset := by - rw [← hpre, ← hpre'] - ext x - simp only [mem_inter_iff, mem_preimage] - constructor - · rintro ⟨hx, hfx⟩ - have hx' : x ∈ A.source := by rwa [hes] at hx - have hex := hfrontier hfx - simp only [mem_insert_iff, mem_singleton_iff] at hex - rcases hex with hcx | hdx - · have hxm : x = m₀ := (Pce x hx').mp hcx - subst hxm - refine ⟨by rw [he's]; exact hm₀B, ?_⟩ - rw [(Pce' x hm₀B).mpr rfl, ← hcx] - exact hfx - · have hxm : x = m₁ := (Pde x hx').mp hdx - subst hxm - refine ⟨by rw [he's]; exact hm₁B, ?_⟩ - rw [(Pde' x hm₁B).mpr rfl, ← hdx] - exact hfx - · rintro ⟨hx, hfx⟩ - have hx' : x ∈ B.source := by rwa [he's] at hx - have hex := hfrontier hfx - simp only [mem_insert_iff, mem_singleton_iff] at hex - rcases hex with hcx | hdx - · have hxm : x = m₀ := (Pce' x hx').mp hcx - subst hxm - refine ⟨by rw [hes]; exact hm₀A, ?_⟩ - rw [(Pce x hm₀A).mpr rfl, ← hcx] - exact hfx - · have hxm : x = m₁ := (Pde' x hx').mp hdx - subst hxm - refine ⟨by rw [hes]; exact hm₁A, ?_⟩ - rw [(Pde x hm₁A).mpr rfl, ← hdx] - exact hfx - have Heq : Set.EqOn e e' (e.source ∩ frontier sset) := by - rw [← hpre] - rintro x ⟨hx, hfx⟩ - rw [mem_preimage] at hfx - have hx' : x ∈ A.source := by rwa [hes] at hx - have hex := hfrontier hfx - simp only [mem_insert_iff, mem_singleton_iff] at hex - rcases hex with hcx | hdx - · have hxm : x = m₀ := (Pce x hx').mp hcx - subst hxm - rw [hcx, (Pce' x hm₀B).mpr rfl] - · have hxm : x = m₁ := (Pde x hx').mp hdx - subst hxm - rw [hdx, (Pde' x hm₁B).mpr rfl] - -- Glue. - refine ⟨e.piecewise e' sset tset H H' Hs Heq, ?_, ?_⟩ - · change Set.ite sset e.source e'.source = A.source ∪ B.source - have hite : Set.ite sset e.source e'.source - = (e.source ∩ sset) ∪ (e'.source \ sset) := rfl - rw [hite, hes, he's] - apply Subset.antisymm - · rintro x (⟨hx, -⟩ | ⟨hx, -⟩) - · exact Or.inl hx - · exact Or.inr hx - · rintro x hx - by_cases hxs : x ∈ sset - · exact Or.inl ⟨hssub hxs, hxs⟩ - · rcases hx with hxa | hxb - · have hxB : x ∈ B.source := by - have hAx : A x ∈ Ioo (0:NNReal) 1 := hAt ▸ A.map_source hxa - have hnot : A x ∉ Icc (A m₀) ν := by - intro hmem - exact hxs (by rw [hssetdef]; exact ⟨hxa, hmem⟩) - rcases lt_or_ge (A x) (A m₀) with hlt | hge - · have hmem : A x ∈ Ioo 0 r := ⟨hAx.1, lt_trans hlt hρmem.2⟩ - exact hW₀B (mem_of_image_mem A hW₀A himgA₀ hxa hmem) - · rcases le_or_gt (A x) ν with hle | hgt - · exact absurd ⟨hge, hle⟩ hnot - · have hmem : A x ∈ Ioo p 1 := ⟨lt_trans hpν hgt, hAx.2⟩ - exact hW₁B (mem_of_image_mem A hW₁A himgA₁ hxa hmem) - exact Or.inr ⟨hxB, hxs⟩ - · exact Or.inr ⟨hxb, hxs⟩ - · change Set.ite tset e.target e'.target = univ - have hite : Set.ite tset e.target e'.target - = (e.target ∩ tset) ∪ (e'.target \ tset) := rfl - rw [hite] - have h1 : e.target ∩ tset = tset := by - apply inter_eq_right.mpr - rw [htargetE, htsetdef] - exact image_mono - (fun u hu => ⟨lt_of_lt_of_le hc₁0 hu.1, lt_of_le_of_lt hu.2 hd₁kα⟩) - have h2 : e'.target \ tset = ((↑) : ℝ → AddCircle (1 : ℝ)) '' - (Ioo (kα * ((ν : NNReal):ℝ)) (kα * ((A m₀ : NNReal):ℝ) + 1)) := by - rw [htargetE'] - ext z - constructor - · rintro ⟨⟨v, hv, rfl⟩, hnt⟩ - have hnor : ¬(v ∈ Icc (kα * ((A m₀ : NNReal):ℝ)) (kα * ((ν : NNReal):ℝ)) ∨ - v ∈ Icc (1 + kα * ((A m₀ : NNReal):ℝ)) (1 + kα * ((ν : NNReal):ℝ))) := - fun hor => hnt ((claim1 v hv).mpr hor) - push Not at hnor - obtain ⟨hn1, hn2⟩ := hnor - rw [mem_Icc] at hn1 hn2 - push Not at hn1 hn2 - refine mem_image_of_mem _ ⟨?_, ?_⟩ - · exact hn1 (by linarith [hv.1]) - · by_contra hge - push Not at hge - have := hn2 (by linarith) - linarith [hv.2] - · rintro ⟨u, hu, rfl⟩ - have huv : u ∈ Ioo g0 (g0 + kg) := - ⟨lt_trans hg0d hu.1, by linarith [hu.2]⟩ - refine ⟨mem_image_of_mem _ huv, ?_⟩ - intro ht - rcases (claim1 u huv).mp ht with hin | hin - · rw [mem_Icc] at hin - linarith [hu.1, hin.2] - · rw [mem_Icc] at hin - linarith [hu.2, hin.1] - rw [h1, h2, htsetdef] - exact addCircle_arc_union_covers hc₁d₁ (by linarith) + exact glue_circle_arcs A B W₀ W₁ r p hAt himgA₀ himgA₁ hW₀A hW₀B hW₁A hW₁B ν hpν m₁ hm₁ν μ m₀ + hm₀μ hm₀A hm₀B hm₁A hm₁B hρmem kα kg g0 hkα1 hkg1 hid1 hid2 hcg0 hg0d h1c hc₁0 hd₁kα hc₁1 + hc₁d₁ e e' heval he'val hes he's htargetE htargetE' sset tset hssub H claim1 H' hfrontier + hssetdef htsetdef /-- **The circle chart.** Two O-charts with `Overlap` and a disconnected overlap glue to a chart of `M` onto the whole of `AddCircle 1`. -/ diff --git a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean index b7d2b02594..8b96e273e6 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean @@ -938,6 +938,328 @@ lemma zero_in_open (a b : NNReal) (h : IsOpen ((Ioo a b) ∪ {0})) : a ≤ 0 ∧ apply this rwa [U0] at openU' +private theorem classify_nnreal_of_real_Ioo (U : Set NNReal) (hu : IsOpen U) + (hr : relu ⁻¹' (U ∩ Ioi 0) = Ioi (0 : ℝ) ∩ NNReal.toReal '' U) + (h0u0 : 0 ∉ U ∩ Ioi 0) (h0u' : 0 ∉ relu ⁻¹' (U ∩ Ioi 0)) + (c : ∃ a b : ℝ, Ioo a b = relu ⁻¹' (U ∩ Ioi 0)) : + (∃ x y, Set.Ioo x y = U) ∨ (∃ x : NNReal, Set.Iio x = U) ∨ + (∃ x : NNReal, Set.Ioi x = U) ∨ U = univ := by + let U0 := U ∩ Ioi 0 + let U' := relu ⁻¹' U0 + change relu ⁻¹' U0 = Ioi (0 : ℝ) ∩ NNReal.toReal '' U at hr + change 0 ∉ U0 at h0u0 + change 0 ∉ U' at h0u' + have hu0 : IsOpen U0 := hu.inter isOpen_Ioi + change ∃ a b : ℝ, Ioo a b = U' at c + rcases c with ⟨ a, b, c ⟩ + have c' := relu_ioo a b + have hc := relu_interval_ioo c + rw [hc] at c' + by_cases hu0' : 0 ∈ U + · have uu0 : U = U0 ∪ { 0 } := by + ext x + simp only [union_singleton, mem_insert_iff] + apply Iff.intro + · intro hx + dsimp [U0] + simp only [mem_inter_iff, mem_Ioi] + by_cases h : x = 0 + · left; exact h + · right; apply And.intro + · assumption + · exact pos_iff_ne_zero.mpr h + · intro hx + rcases hx with (hx|hx) + · rw [hx] + assumption + · dsimp [U0] at hx + simp only [mem_inter_iff, mem_Ioi] at hx + exact hx.1 + rw [uu0] + rcases c' with (c'|c'|c'|c') + · right + left + rw [c'] + rw [c'] at uu0 + rw [uu0] at hu + have hz := zero_in_open (relu a) (relu b) hu + use relu b + ext x + simp only [mem_Iio, union_singleton, mem_insert_iff, mem_Ioo] + apply Iff.intro + · intro hx + by_cases h0 : x = 0 + · left; exact h0 + · right + apply And.intro + · have : 0 < x := by exact pos_iff_ne_zero.mpr h0 + exact lt_of_le_of_lt hz.1 this + · assumption + · intro hx + rcases hx with (hx|hx) + · rw [hx] + exact hz.2 + · exact hx.2 + · by_cases hb : relu b = 0 + · rw [hb] at c' + simp only [lt_self_iff_false, not_false_eq_true, Ico_eq_empty] at c' + rw [c'] at uu0 + simp only [union_singleton, insert_empty_eq] at uu0 + rw [uu0] at hu + have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 + exfalso + exact this hu + · right + left + use relu b + rw [c'] + ext x + simp only [mem_Iio, union_singleton, mem_insert_iff, mem_Ico, zero_le, true_and, + iff_or_self] + intro hx + rw [hx] + exact pos_iff_ne_zero.mpr hb + · rw [c'] at hu0 + exfalso + have this' : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 + exact this' hu0 + · rw [c'] at uu0 + simp only [union_singleton, insert_empty_eq] at uu0 + have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 + rw [uu0] at hu + exfalso + exact this hu + · have uu0 : U = U0 := by + dsimp [U0] + simp only [left_eq_inter] + intro x hx + simp only [mem_Ioi] + have : x ≠ 0 := by exact ne_of_mem_of_not_mem hx hu0' + exact pos_iff_ne_zero.mpr this + rw [←uu0] at c' + rcases c' with (c'|c'|c'|c') + · left + use relu a + use relu b + rw [c'] + · right + left + use (relu b) + rw [c'] + ext x + simp only [mem_Iio, mem_Ico, zero_le, true_and] + · rw [c'] at hu + exfalso + have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 + apply this + exact hu + · left + use 0 + use 0 + rw [c'] + simp only [lt_self_iff_false, not_false_eq_true, Ioo_eq_empty] + +private theorem classify_nnreal_of_real_Ioi (U : Set NNReal) (hu : IsOpen U) (hc : IsConnected U) + (hr : relu ⁻¹' (U ∩ Ioi 0) = Ioi (0 : ℝ) ∩ NNReal.toReal '' U) + (h0u0 : 0 ∉ U ∩ Ioi 0) (h0u' : 0 ∉ relu ⁻¹' (U ∩ Ioi 0)) + (c : ∃ a : ℝ, Ioi a = relu ⁻¹' (U ∩ Ioi 0)) : + (∃ x y, Set.Ioo x y = U) ∨ (∃ x : NNReal, Set.Iio x = U) ∨ + (∃ x : NNReal, Set.Ioi x = U) ∨ U = univ := by + let U0 := U ∩ Ioi 0 + let U' := relu ⁻¹' U0 + change relu ⁻¹' U0 = Ioi (0 : ℝ) ∩ NNReal.toReal '' U at hr + change 0 ∉ U0 at h0u0 + change 0 ∉ U' at h0u' + have hu0 : IsOpen U0 := hu.inter isOpen_Ioi + change ∃ x : ℝ, Ioi x = U' at c + rcases c with ⟨ x, c ⟩ + by_cases h0 : x = 0 + · by_cases hu0 : 0 ∈ U + · right; right; right + rw [h0] at c + dsimp [U'] at c + ext z + simp only [mem_univ, iff_true] + by_cases hz0 : z = 0 + · rw [hz0] + assumption + · have zpos : z > 0 := by + exact pos_iff_ne_zero.mpr hz0 + have zi : z ∈ Set.Ioi 0 := by exact zpos + have zi' : NNReal.toReal z ∈ relu ⁻¹' U0 := by + rw [←c] + simp only [mem_Ioi, NNReal.coe_pos] + assumption + simp only [mem_preimage] at zi' + rw [relu_proj] at zi' + exact mem_of_mem_inter_left zi' + · right; right; left + use 0 + have uu0 : U = U0 := by + ext z + apply Iff.intro + · intro hz + dsimp [U0] + simp only [mem_inter_iff, mem_Ioi] + apply And.intro + · exact hz + · have : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 + exact pos_iff_ne_zero.mpr this + · intro hz + exact mem_of_mem_inter_left hz + rw [uu0] + rw [h0] at c + ext z + simp only [mem_Ioi] + apply Iff.intro + · intro hz + have : NNReal.toReal z > 0 := by exact hz + have this' : NNReal.toReal z ∈ U' := by + rw [←c] + simp only [mem_Ioi, NNReal.coe_pos] + assumption + dsimp [U'] at this' + simp only [mem_preimage] at this' + rw [relu_proj] at this' + assumption + · intro hz + rw [←uu0] at hz + have : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 + exact pos_iff_ne_zero.mpr this + · by_cases hx : x < 0 + · have : 0 ∈ U' := by + have this' : 0 ∈ Set.Ioi x := by exact hx + rw [c] at this' + assumption + exfalso + exact h0u' this + · right; right; left + by_cases hu0 : 0 ∈ U + · have : U = U0 ∪ {0} := by + ext z + simp only [union_singleton, mem_insert_iff] + apply Iff.intro + · intro hz + by_cases hz' : z = 0 + · left; assumption + · right + dsimp [U0] + refine (mem_inter_iff z U (Ioi 0)).mpr ?_ + apply And.intro + · assumption + · simp only [mem_Ioi] + exact pos_iff_ne_zero.mpr hz' + · intro hz + rcases hz with (hz|hz) + · rw [hz] + assumption + · exact mem_of_mem_inter_left hz + dsimp [U'] at c + rw [hr] at c + have contra : ¬ IsConnected U := by + dsimp [IsConnected] + simp only [not_and] + intro hn + dsimp [IsPreconnected] + simp only [not_forall] + have xpos : x ≥ 0 := by linarith + use Set.Iio (NNReal.mk x xpos) + use Set.Ioi (NNReal.mk x xpos) + simp only [exists_prop, Iio_union_Ioi, subset_compl_singleton_iff] + apply And.intro + · exact isOpen_Iio + · apply And.intro + · exact isOpen_Ioi + · apply And.intro + · by_contra h + have h' : NNReal.toReal (NNReal.mk x xpos) ∈ NNReal.toReal '' U := + mem_image_of_mem NNReal.toReal h + have h'' : NNReal.toReal (NNReal.mk x xpos) ∈ Set.Ioi 0 := by + apply mem_Ioi.mpr + exact lt_of_le_of_ne xpos fun a => h0 (id (Eq.symm a)) + have h3 : NNReal.toReal (NNReal.mk x xpos) ∈ Set.Ioi x := by + rw [c] + exact mem_inter h'' h' + simp only [NNReal.coe_mk, mem_Ioi, lt_self_iff_false] at h3 + · apply And.intro + · use 0 + simp only [mem_inter_iff, mem_Iio] + apply And.intro + · assumption + · apply NNReal.coe_pos.mp + simp only [NNReal.coe_mk] + exact lt_of_le_of_ne xpos fun a => h0 (id (Eq.symm a)) + · apply And.intro + · apply inter_nonempty.mpr + use (1 : NNReal) + (NNReal.mk x xpos) + apply And.intro + · have : 1 + x ∈ Set.Ioi x := by + apply mem_Ioi.mpr + exact lt_one_add x + rw [c] at this + simp only [mem_inter_iff, mem_Ioi, mem_image] at this + rcases this with ⟨ tpos, ⟨ t, ⟨ tu, ht ⟩ ⟩ ⟩ + have ht2 : t = 1 + (NNReal.mk x xpos) := by + exact NNReal.eq ht + rw [←ht2] + assumption + · apply mem_Ioi.mpr + exact lt_one_add ((NNReal.mk x xpos) : NNReal) + · refine not_nonempty_iff_eq_empty.mpr ?_ + let x' : NNReal := (NNReal.mk x xpos) + have : (Set.Iio x' ∩ Set.Ioi x') = ∅ := by + ext z + simp only [mem_inter_iff, mem_Iio, mem_Ioi, mem_empty_iff_false, + iff_false, not_and, not_lt] + intro hz + exact le_of_lt hz + rw [this] + simp only [inter_empty] + exfalso + exact contra hc + · have h0' : 0 ∉ Set.Ioi x := by exact Eq.mpr_not (congrFun c 0) h0u' + simp only [mem_Ioi, not_lt] at h0' + use (NNReal.mk x h0') + ext z + simp only [mem_Ioi] + apply Iff.intro + · intro hxz + have hu' : NNReal.toReal z ∈ U' := by + rw [←c] + simp only [mem_Ioi] + exact hxz + have : NNReal.toReal z ∈ Ioi 0 ∩ NNReal.toReal '' U := by + rw [←hr] + exact hu' + have this' : NNReal.toReal z ∈ NNReal.toReal '' U := mem_of_mem_inter_right this + simp only [mem_image, NNReal.coe_inj, exists_eq_right] at this' + assumption + · intro hz + apply NNReal.coe_lt_coe.mp + simp only [NNReal.coe_mk] + dsimp [U'] at c + have z0 : z ∈ U0 := by + refine (mem_inter_iff z U (Ioi 0)).mpr ?_ + apply And.intro + · exact hz + · refine mem_Ioi.mpr ?_ + refine NNReal.coe_pos.mp ?_ + simp only [NNReal.coe_pos] + have hz0 : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 + exact pos_iff_ne_zero.mpr hz0 + have : NNReal.toReal z ∈ Set.Ioi 0 ∩ NNReal.toReal '' U := by + simp only [mem_inter_iff, mem_Ioi, NNReal.coe_pos, mem_image, NNReal.coe_inj, + exists_eq_right] + apply And.intro + · have : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 + have this' : z ≥ 0 := by exact zero_le + exact pos_iff_ne_zero.mpr this + assumption + rw [←hr] at this + rw [←c] at this + simp only [mem_Ioi] at this + assumption + theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc : IsConnected U) : (∃ x y, (Set.Ioo x y = U)) ∨ (∃ (x : NNReal), (Set.Iio x = U)) ∨ @@ -1041,113 +1363,7 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc rw [relu_zero] assumption rcases c with (c|c|c|c) - · rcases c with ⟨ a, b, c ⟩ - have c' := relu_ioo a b - have hc := relu_interval_ioo c - rw [hc] at c' - by_cases hu0' : 0 ∈ U - · have uu0 : U = U0 ∪ { 0 } := by - ext x - simp only [union_singleton, mem_insert_iff] - apply Iff.intro - · intro hx - dsimp [U0] - simp only [mem_inter_iff, mem_Ioi] - by_cases h : x = 0 - · left; exact h - · right; apply And.intro - · assumption - · exact pos_iff_ne_zero.mpr h - · intro hx - rcases hx with (hx|hx) - · rw [hx] - assumption - · dsimp [U0] at hx - simp only [mem_inter_iff, mem_Ioi] at hx - exact hx.1 - rw [uu0] - rcases c' with (c'|c'|c'|c') - · right - left - rw [c'] - rw [c'] at uu0 - rw [uu0] at hu - have hz := zero_in_open (relu a) (relu b) hu - use relu b - ext x - simp only [mem_Iio, union_singleton, mem_insert_iff, mem_Ioo] - apply Iff.intro - · intro hx - by_cases h0 : x = 0 - · left; exact h0 - · right - apply And.intro - · have : 0 < x := by exact pos_iff_ne_zero.mpr h0 - exact lt_of_le_of_lt hz.1 this - · assumption - · intro hx - rcases hx with (hx|hx) - · rw [hx] - exact hz.2 - · exact hx.2 - · by_cases hb : relu b = 0 - · rw [hb] at c' - simp only [lt_self_iff_false, not_false_eq_true, Ico_eq_empty] at c' - rw [c'] at uu0 - simp only [union_singleton, insert_empty_eq] at uu0 - rw [uu0] at hu - have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 - exfalso - exact this hu - · right - left - use relu b - rw [c'] - ext x - simp only [mem_Iio, union_singleton, mem_insert_iff, mem_Ico, zero_le, true_and, - iff_or_self] - intro hx - rw [hx] - exact pos_iff_ne_zero.mpr hb - · rw [c'] at hu0 - exfalso - have this' : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 - exact this' hu0 - · rw [c'] at uu0 - simp only [union_singleton, insert_empty_eq] at uu0 - have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 - rw [uu0] at hu - exfalso - exact this hu - · have uu0 : U = U0 := by - dsimp [U0] - simp only [left_eq_inter] - intro x hx - simp only [mem_Ioi] - have : x ≠ 0 := by exact ne_of_mem_of_not_mem hx hu0' - exact pos_iff_ne_zero.mpr this - rw [←uu0] at c' - rcases c' with (c'|c'|c'|c') - · left - use relu a - use relu b - rw [c'] - · right - left - use (relu b) - rw [c'] - ext x - simp only [mem_Iio, mem_Ico, zero_le, true_and] - · rw [c'] at hu - exfalso - have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 - apply this - exact hu - · left - use 0 - use 0 - rw [c'] - simp only [lt_self_iff_false, not_false_eq_true, Ioo_eq_empty] + · exact classify_nnreal_of_real_Ioo U hu hr h0u0 h0u' c · rcases c with ⟨ x, hx ⟩ rw [hx] at h0u' simp only [mem_Iio, not_lt] at h0u' @@ -1160,193 +1376,7 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc have hc : x - 1 ∈ Set.Ioi 0 := by exact mem_of_mem_inter_left hxi simp only [mem_Ioi, sub_pos] at hc linarith - · rcases c with ⟨ x, c ⟩ - by_cases h0 : x = 0 - · by_cases hu0 : 0 ∈ U - · right; right; right - rw [h0] at c - dsimp [U'] at c - ext z - simp only [mem_univ, iff_true] - by_cases hz0 : z = 0 - · rw [hz0] - assumption - · have zpos : z > 0 := by - exact pos_iff_ne_zero.mpr hz0 - have zi : z ∈ Set.Ioi 0 := by exact zpos - have zi' : NNReal.toReal z ∈ relu ⁻¹' U0 := by - rw [←c] - simp only [mem_Ioi, NNReal.coe_pos] - assumption - simp only [mem_preimage] at zi' - rw [relu_proj] at zi' - exact mem_of_mem_inter_left zi' - · right; right; left - use 0 - have uu0 : U = U0 := by - ext z - apply Iff.intro - · intro hz - dsimp [U0] - simp only [mem_inter_iff, mem_Ioi] - apply And.intro - · exact hz - · have : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 - exact pos_iff_ne_zero.mpr this - · intro hz - exact mem_of_mem_inter_left hz - rw [uu0] - rw [h0] at c - ext z - simp only [mem_Ioi] - apply Iff.intro - · intro hz - have : NNReal.toReal z > 0 := by exact hz - have this' : NNReal.toReal z ∈ U' := by - rw [←c] - simp only [mem_Ioi, NNReal.coe_pos] - assumption - dsimp [U'] at this' - simp only [mem_preimage] at this' - rw [relu_proj] at this' - assumption - · intro hz - rw [←uu0] at hz - have : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 - exact pos_iff_ne_zero.mpr this - · by_cases hx : x < 0 - · have : 0 ∈ U' := by - have this' : 0 ∈ Set.Ioi x := by exact hx - rw [c] at this' - assumption - exfalso - exact h0u' this - · right; right; left - by_cases hu0 : 0 ∈ U - · have : U = U0 ∪ {0} := by - ext z - simp only [union_singleton, mem_insert_iff] - apply Iff.intro - · intro hz - by_cases hz' : z = 0 - · left; assumption - · right - dsimp [U0] - refine (mem_inter_iff z U (Ioi 0)).mpr ?_ - apply And.intro - · assumption - · simp only [mem_Ioi] - exact pos_iff_ne_zero.mpr hz' - · intro hz - rcases hz with (hz|hz) - · rw [hz] - assumption - · exact mem_of_mem_inter_left hz - dsimp [U'] at c - rw [hr] at c - have contra : ¬ IsConnected U := by - dsimp [IsConnected] - simp only [not_and] - intro hn - dsimp [IsPreconnected] - simp only [not_forall] - have xpos : x ≥ 0 := by linarith - use Set.Iio (NNReal.mk x xpos) - use Set.Ioi (NNReal.mk x xpos) - simp only [exists_prop, Iio_union_Ioi, subset_compl_singleton_iff] - apply And.intro - · exact isOpen_Iio - · apply And.intro - · exact isOpen_Ioi - · apply And.intro - · by_contra h - have h' : NNReal.toReal (NNReal.mk x xpos) ∈ NNReal.toReal '' U := - mem_image_of_mem NNReal.toReal h - have h'' : NNReal.toReal (NNReal.mk x xpos) ∈ Set.Ioi 0 := by - apply mem_Ioi.mpr - exact lt_of_le_of_ne xpos fun a => h0 (id (Eq.symm a)) - have h3 : NNReal.toReal (NNReal.mk x xpos) ∈ Set.Ioi x := by - rw [c] - exact mem_inter h'' h' - simp only [NNReal.coe_mk, mem_Ioi, lt_self_iff_false] at h3 - · apply And.intro - · use 0 - simp only [mem_inter_iff, mem_Iio] - apply And.intro - · assumption - · apply NNReal.coe_pos.mp - simp only [NNReal.coe_mk] - exact lt_of_le_of_ne xpos fun a => h0 (id (Eq.symm a)) - · apply And.intro - · apply inter_nonempty.mpr - use (1 : NNReal) + (NNReal.mk x xpos) - apply And.intro - · have : 1 + x ∈ Set.Ioi x := by - apply mem_Ioi.mpr - exact lt_one_add x - rw [c] at this - simp only [mem_inter_iff, mem_Ioi, mem_image] at this - rcases this with ⟨ tpos, ⟨ t, ⟨ tu, ht ⟩ ⟩ ⟩ - have ht2 : t = 1 + (NNReal.mk x xpos) := by - exact NNReal.eq ht - rw [←ht2] - assumption - · apply mem_Ioi.mpr - exact lt_one_add ((NNReal.mk x xpos) : NNReal) - · refine not_nonempty_iff_eq_empty.mpr ?_ - let x' : NNReal := (NNReal.mk x xpos) - have : (Set.Iio x' ∩ Set.Ioi x') = ∅ := by - ext z - simp only [mem_inter_iff, mem_Iio, mem_Ioi, mem_empty_iff_false, - iff_false, not_and, not_lt] - intro hz - exact le_of_lt hz - rw [this] - simp only [inter_empty] - exfalso - exact contra hc - · have h0' : 0 ∉ Set.Ioi x := by exact Eq.mpr_not (congrFun c 0) h0u' - simp only [mem_Ioi, not_lt] at h0' - use (NNReal.mk x h0') - ext z - simp only [mem_Ioi] - apply Iff.intro - · intro hxz - have hu' : NNReal.toReal z ∈ U' := by - rw [←c] - simp only [mem_Ioi] - exact hxz - have : NNReal.toReal z ∈ Ioi 0 ∩ NNReal.toReal '' U := by - rw [←hr] - exact hu' - have this' : NNReal.toReal z ∈ NNReal.toReal '' U := mem_of_mem_inter_right this - simp only [mem_image, NNReal.coe_inj, exists_eq_right] at this' - assumption - · intro hz - apply NNReal.coe_lt_coe.mp - simp only [NNReal.coe_mk] - dsimp [U'] at c - have z0 : z ∈ U0 := by - refine (mem_inter_iff z U (Ioi 0)).mpr ?_ - apply And.intro - · exact hz - · refine mem_Ioi.mpr ?_ - refine NNReal.coe_pos.mp ?_ - simp only [NNReal.coe_pos] - have hz0 : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 - exact pos_iff_ne_zero.mpr hz0 - have : NNReal.toReal z ∈ Set.Ioi 0 ∩ NNReal.toReal '' U := by - simp only [mem_inter_iff, mem_Ioi, NNReal.coe_pos, mem_image, NNReal.coe_inj, - exists_eq_right] - apply And.intro - · have : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 - have this' : z ≥ 0 := by exact zero_le - exact pos_iff_ne_zero.mpr this - assumption - rw [←hr] at this - rw [←c] at this - simp only [mem_Ioi] at this - assumption + · exact classify_nnreal_of_real_Ioi U hu hc hr h0u0 h0u' c · exfalso have h0i : 0 ∉ Set.Ioi (0 : NNReal) := self_notMem_Ioi have this' : 0 ∈ U0 := by diff --git a/LeanPool/OneManifold/OneMfld/GlueUI.lean b/LeanPool/OneManifold/OneMfld/GlueUI.lean index 4726e9aa40..ac1a3ffdb2 100644 --- a/LeanPool/OneManifold/OneMfld/GlueUI.lean +++ b/LeanPool/OneManifold/OneMfld/GlueUI.lean @@ -22,6 +22,95 @@ point `m := b.symm μ` (that is, `k/(ρ+k) = μ/2` where `ρ := a m`). Glue with open Set +/-- The half-scale and Möbius charts cover the unit interval across their common split level. -/ +private theorem half_mobius_target_cover {M : Type*} [TopologicalSpace M] + (a b : OpenPartialHomeomorph M NNReal) + (eb : OpenPartialHomeomorph NNReal UnitInterval) + (e' : OpenPartialHomeomorph M UnitInterval) + (hat : a.target = Iio 1) (hbt : b.target = Iio 1) + (hbs : eb.source = Iio 1) + (hbt' : eb.target = {y : UnitInterval | (y : ℝ) < 1 / 2}) + (he'src : e'.source = a.source) (μ ρ k : NNReal) + (hkR : (0 : ℝ) < (k : ℝ)) (hμR : (0 : ℝ) < (μ : ℝ)) + (hμ1R : (μ : ℝ) < 1) (hρ1R : (ρ : ℝ) < 1) + (hρkR : (0 : ℝ) < (ρ : ℝ) + (k : ℝ)) + (hkeyR : (k : ℝ) / ((ρ : ℝ) + (k : ℝ)) = (μ : ℝ) / 2) + (he'f : ∀ x : M, (e' x : ℝ) = (k : ℝ) / ((a x : ℝ) + (k : ℝ))) : + (b.trans eb).target ∩ {y : UnitInterval | (y : ℝ) ≤ (μ : ℝ) / 2} ∪ + e'.target \ {y : UnitInterval | (y : ℝ) ≤ (μ : ℝ) / 2} = univ := by + classical + apply eq_univ_of_forall + intro y + by_cases hy : (y : ℝ) ≤ (μ : ℝ) / 2 + · -- lower piece + left + have hyt : y ∈ eb.target := by + rw [hbt'] + change (y : ℝ) < 1 / 2 + linarith + refine ⟨?_, hy⟩ + rw [OpenPartialHomeomorph.trans_target] + refine ⟨hyt, ?_⟩ + rw [mem_preimage, hbt, ← hbs] + exact eb.map_target hyt + · -- upper piece + right + push Not at hy + refine ⟨?_, fun h => absurd h (not_le.2 hy)⟩ + have hy0 : (0 : ℝ) < (y : ℝ) := lt_trans (half_pos hμR) hy + have hy1 : (y : ℝ) ≤ 1 := y.2.2 + -- the point `w := k/y - k` of `a.target` mapping to `y` + have hknn : (k : ℝ) ≤ (k : ℝ) / (y : ℝ) := by + rw [le_div_iff₀ hy0] + nlinarith + have hnn : (0 : ℝ) ≤ (k : ℝ) / (y : ℝ) - (k : ℝ) := by linarith + have h1k : (0 : ℝ) < 1 + (k : ℝ) := by linarith + have hge : (k : ℝ) / (1 + (k : ℝ)) ≤ (k : ℝ) / ((ρ : ℝ) + (k : ℝ)) := by + rw [div_le_div_iff₀ h1k hρkR] + nlinarith + have hygt : (k : ℝ) / (1 + (k : ℝ)) < (y : ℝ) := + lt_of_le_of_lt (hge.trans (le_of_eq hkeyR)) hy + have hlt1 : (k : ℝ) / (y : ℝ) - (k : ℝ) < 1 := by + rw [div_lt_iff₀ h1k] at hygt + rw [sub_lt_iff_lt_add] + rw [div_lt_iff₀ hy0] + nlinarith + set w : NNReal := Real.toNNReal ((k : ℝ) / (y : ℝ) - (k : ℝ)) with hwdef + have hwcoe : (w : ℝ) = (k : ℝ) / (y : ℝ) - (k : ℝ) := Real.coe_toNNReal _ hnn + have hwtarget : w ∈ a.target := by + rw [hat, mem_Iio, ← NNReal.coe_lt_coe, NNReal.coe_one, hwcoe] + exact hlt1 + set x₀ := a.symm w with hx0def + have hx0src : x₀ ∈ a.source := a.map_target hwtarget + have hax0 : a x₀ = w := a.right_inv hwtarget + have hkne : (k : ℝ) ≠ 0 := hkR.ne' + have hyne : (y : ℝ) ≠ 0 := hy0.ne' + have he'x0 : (e' x₀ : ℝ) = (y : ℝ) := by + rw [he'f x₀, hax0, hwcoe, sub_add_cancel] + rw [div_div_eq_mul_div, mul_comm (k : ℝ) (y : ℝ), mul_div_assoc, + div_self hkne, mul_one] + have hexy : e' x₀ = y := Subtype.ext he'x0 + have hx0src' : x₀ ∈ e'.source := by rw [he'src]; exact hx0src + have := e'.map_source hx0src' + rwa [hexy] at this + +/-- The Möbius parameter maps the selected upper-chart coordinate to the half-scale split. -/ +private theorem mobius_split_identity (μ ρ k : NNReal) (h2μ : μ < 2) + (hkdef : k = μ * ρ / (2 - μ)) (hρkR : (0 : ℝ) < (ρ : ℝ) + (k : ℝ)) : + (k : ℝ) / ((ρ : ℝ) + (k : ℝ)) = (μ : ℝ) / 2 := by + have h2μpos : 0 < 2 - μ := tsub_pos_of_lt h2μ + have hkey2 : 2 * k = μ * (ρ + k) := by + have h1 : k * (2 - μ) = μ * ρ := by + rw [hkdef]; exact div_mul_cancel₀ _ h2μpos.ne' + calc 2 * k = ((2 - μ) + μ) * k := by rw [tsub_add_cancel_of_le h2μ.le] + _ = (2 - μ) * k + μ * k := add_mul _ _ _ + _ = μ * ρ + μ * k := by rw [mul_comm (2 - μ) k, h1] + _ = μ * (ρ + k) := (mul_add μ ρ k).symm + have h := congrArg (fun x : NNReal => (x : ℝ)) hkey2 + push_cast at h + rw [div_eq_div_iff hρkR.ne' (two_ne_zero)] + linarith + /-- **Unit-interval gluing.** Two boundary charts (targets `Iio 1`) whose overlap is an upper end-segment in each glue to a chart of `M` onto the whole unit interval, with source `a.source ∪ b.source`. -/ @@ -57,13 +146,6 @@ theorem glue_hh_ui {M : Type*} [TopologicalSpace M] [T2Space M] have h2μpos : 0 < 2 - μ := tsub_pos_of_lt h2μ set k : NNReal := μ * ρ / (2 - μ) with hkdef have hkpos : 0 < k := div_pos (mul_pos hμpos hρpos) h2μpos - have hkey2 : 2 * k = μ * (ρ + k) := by - have h1 : k * (2 - μ) = μ * ρ := by - rw [hkdef]; exact div_mul_cancel₀ _ h2μpos.ne' - calc 2 * k = ((2 - μ) + μ) * k := by rw [tsub_add_cancel_of_le h2μ.le] - _ = (2 - μ) * k + μ * k := add_mul _ _ _ - _ = μ * ρ + μ * k := by rw [mul_comm (2 - μ) k, h1] - _ = μ * (ρ + k) := (mul_add μ ρ k).symm -- real-number versions of the positivity facts and the key identity have hkR : (0 : ℝ) < (k : ℝ) := NNReal.coe_pos.2 hkpos have hμR : (0 : ℝ) < (μ : ℝ) := NNReal.coe_pos.2 hμpos @@ -71,11 +153,8 @@ theorem glue_hh_ui {M : Type*} [TopologicalSpace M] [T2Space M] have hμ1R : (μ : ℝ) < 1 := by exact_mod_cast hμ1 have hρ1R : (ρ : ℝ) < 1 := by exact_mod_cast hρ1 have hρkR : (0 : ℝ) < (ρ : ℝ) + (k : ℝ) := by linarith - have hkeyR : (k : ℝ) / ((ρ : ℝ) + (k : ℝ)) = (μ : ℝ) / 2 := by - have h := congrArg (fun x : NNReal => (x : ℝ)) hkey2 - push_cast at h - rw [div_eq_div_iff hρkR.ne' (two_ne_zero)] - linarith + have hkeyR : (k : ℝ) / ((ρ : ℝ) + (k : ℝ)) = (μ : ℝ) / 2 := + mobius_split_identity μ ρ k h2μ hkdef hρkR -- the two building blocks obtain ⟨eb, hbs, hbt', hbf⟩ := halfOPH obtain ⟨ea, has, hat', haf, hanti⟩ := mobiusOPH k hkpos @@ -250,60 +329,6 @@ theorem glue_hh_ui {M : Type*} [TopologicalSpace M] [T2Space M] have hzx : z = x := b.injOn hzS.2 hxb hz subst hzx exact Or.inr ⟨hzS.1, hxs⟩ - · -- target computation - have hft : f.target = e.target ∩ tset ∪ e'.target \ tset := rfl - rw [hft] - apply eq_univ_of_forall - intro y - by_cases hy : (y : ℝ) ≤ (μ : ℝ) / 2 - · -- lower piece - left - have hyt : y ∈ eb.target := by - rw [hbt'] - change (y : ℝ) < 1 / 2 - linarith - refine ⟨?_, hy⟩ - rw [hedef, OpenPartialHomeomorph.trans_target] - refine ⟨hyt, ?_⟩ - rw [mem_preimage, hbt, ← hbs] - exact eb.map_target hyt - · -- upper piece - right - push Not at hy - refine ⟨?_, fun h => absurd h (not_le.2 hy)⟩ - have hy0 : (0 : ℝ) < (y : ℝ) := lt_trans (half_pos hμR) hy - have hy1 : (y : ℝ) ≤ 1 := y.2.2 - -- the point `w := k/y - k` of `a.target` mapping to `y` - have hknn : (k : ℝ) ≤ (k : ℝ) / (y : ℝ) := by - rw [le_div_iff₀ hy0] - nlinarith - have hnn : (0 : ℝ) ≤ (k : ℝ) / (y : ℝ) - (k : ℝ) := by linarith - have h1k : (0 : ℝ) < 1 + (k : ℝ) := by linarith - have hge : (k : ℝ) / (1 + (k : ℝ)) ≤ (k : ℝ) / ((ρ : ℝ) + (k : ℝ)) := by - rw [div_le_div_iff₀ h1k hρkR] - nlinarith - have hygt : (k : ℝ) / (1 + (k : ℝ)) < (y : ℝ) := - lt_of_le_of_lt (hge.trans (le_of_eq hkeyR)) hy - have hlt1 : (k : ℝ) / (y : ℝ) - (k : ℝ) < 1 := by - rw [div_lt_iff₀ h1k] at hygt - rw [sub_lt_iff_lt_add] - rw [div_lt_iff₀ hy0] - nlinarith - set w : NNReal := Real.toNNReal ((k : ℝ) / (y : ℝ) - (k : ℝ)) with hwdef - have hwcoe : (w : ℝ) = (k : ℝ) / (y : ℝ) - (k : ℝ) := Real.coe_toNNReal _ hnn - have hwtarget : w ∈ a.target := by - rw [hat, mem_Iio, ← NNReal.coe_lt_coe, NNReal.coe_one, hwcoe] - exact hlt1 - set x₀ := a.symm w with hx0def - have hx0src : x₀ ∈ a.source := a.map_target hwtarget - have hax0 : a x₀ = w := a.right_inv hwtarget - have hkne : (k : ℝ) ≠ 0 := hkR.ne' - have hyne : (y : ℝ) ≠ 0 := hy0.ne' - have he'x0 : (e' x₀ : ℝ) = (y : ℝ) := by - rw [he'f x₀, hax0, hwcoe, sub_add_cancel] - rw [div_div_eq_mul_div, mul_comm (k : ℝ) (y : ℝ), mul_div_assoc, - div_self hkne, mul_one] - have hexy : e' x₀ = y := Subtype.ext he'x0 - have hx0src' : x₀ ∈ e'.source := by rw [he'src]; exact hx0src - have := e'.map_source hx0src' - rwa [hexy] at this + · change (b.trans eb).target ∩ tset ∪ e'.target \ tset = univ + exact half_mobius_target_cover a b eb e' hat hbt hbs hbt' he'src μ ρ k + hkR hμR hμ1R hρ1R hρkR hkeyR he'f From 641ae65ec4fdc3f18b91c91e0f777aa26e532d78 Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Fri, 25 Sep 2026 08:44:29 +0000 Subject: [PATCH 04/16] Preserve one-manifold API in public modules --- LeanPool/OneManifold.lean | 59 ++++++++++--------- LeanPool/OneManifold/OneMfld.lean | 4 +- LeanPool/OneManifold/OneMfld/Charts.lean | 9 ++- .../OneManifold/OneMfld/CircleBlocks.lean | 19 +++--- LeanPool/OneManifold/OneMfld/CircleGlue.lean | 17 ++++-- .../OneManifold/OneMfld/Classification.lean | 23 +++++--- .../OneManifold/OneMfld/ClassifyInterval.lean | 15 +++-- .../OneManifold/OneMfld/ClassifyOverlaps.lean | 45 +++++++------- .../OneManifold/OneMfld/ClosureOverlap.lean | 9 ++- LeanPool/OneManifold/OneMfld/Compactness.lean | 11 +++- .../OneMfld/FiniteIntervalCharts.lean | 11 +++- .../OneManifold/OneMfld/FinitelyCharted.lean | 9 ++- LeanPool/OneManifold/OneMfld/GlueBlocks.lean | 11 +++- LeanPool/OneManifold/OneMfld/GlueCore.lean | 11 +++- LeanPool/OneManifold/OneMfld/GlueNNReal.lean | 11 +++- LeanPool/OneManifold/OneMfld/GlueUI.lean | 13 ++-- .../OneManifold/OneMfld/IntervalCharts.lean | 11 +++- .../OneManifold/OneMfld/LocallyConnected.lean | 11 +++- LeanPool/OneManifold/OneMfld/NiceCharts.lean | 15 +++-- LeanPool/OneManifold/OneMfld/Noncompact.lean | 9 ++- LeanPool/OneManifold/OneMfld/Normalize.lean | 13 ++-- LeanPool/OneManifold/OneMfld/Outer.lean | 15 +++-- .../OneMfld/PartialHomeomorphHelpers.lean | 11 +++- .../OneManifold/OneMfld/RealIntervals.lean | 20 ++++--- .../OneManifold/OneMfld/TransitionMono.lean | 11 +++- .../OneManifold/OneMfld/TwoComponents.lean | 13 ++-- .../OneManifold/OneMfld/UnitInterval.lean | 11 +++- LeanPool/OneManifold/Solution.lean | 7 ++- 28 files changed, 279 insertions(+), 145 deletions(-) diff --git a/LeanPool/OneManifold.lean b/LeanPool/OneManifold.lean index ad174814ae..88574478ca 100644 --- a/LeanPool/OneManifold.lean +++ b/LeanPool/OneManifold.lean @@ -4,33 +4,36 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import LeanPool.OneManifold.OneMfld -import LeanPool.OneManifold.OneMfld.Charts -import LeanPool.OneManifold.OneMfld.CircleBlocks -import LeanPool.OneManifold.OneMfld.CircleGlue -import LeanPool.OneManifold.OneMfld.Classification -import LeanPool.OneManifold.OneMfld.ClassifyInterval -import LeanPool.OneManifold.OneMfld.ClassifyOverlaps -import LeanPool.OneManifold.OneMfld.ClosureOverlap -import LeanPool.OneManifold.OneMfld.Compactness -import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts -import LeanPool.OneManifold.OneMfld.FinitelyCharted -import LeanPool.OneManifold.OneMfld.GlueBlocks -import LeanPool.OneManifold.OneMfld.GlueCore -import LeanPool.OneManifold.OneMfld.GlueNNReal -import LeanPool.OneManifold.OneMfld.GlueUI -import LeanPool.OneManifold.OneMfld.IntervalCharts -import LeanPool.OneManifold.OneMfld.LocallyConnected -import LeanPool.OneManifold.OneMfld.NiceCharts -import LeanPool.OneManifold.OneMfld.Noncompact -import LeanPool.OneManifold.OneMfld.Normalize -import LeanPool.OneManifold.OneMfld.Outer -import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers -import LeanPool.OneManifold.OneMfld.RealIntervals -import LeanPool.OneManifold.OneMfld.TransitionMono -import LeanPool.OneManifold.OneMfld.TwoComponents -import LeanPool.OneManifold.OneMfld.UnitInterval -import LeanPool.OneManifold.Solution +module + +public import LeanPool.OneManifold.OneMfld +public import LeanPool.OneManifold.OneMfld.Charts +public import LeanPool.OneManifold.OneMfld.CircleBlocks +public import LeanPool.OneManifold.OneMfld.CircleGlue +public import LeanPool.OneManifold.OneMfld.Classification +public import LeanPool.OneManifold.OneMfld.ClassifyInterval +public import LeanPool.OneManifold.OneMfld.ClassifyOverlaps +public import LeanPool.OneManifold.OneMfld.ClosureOverlap +public import LeanPool.OneManifold.OneMfld.Compactness +public import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts +public import LeanPool.OneManifold.OneMfld.FinitelyCharted +public import LeanPool.OneManifold.OneMfld.GlueBlocks +public import LeanPool.OneManifold.OneMfld.GlueCore +public import LeanPool.OneManifold.OneMfld.GlueNNReal +public import LeanPool.OneManifold.OneMfld.GlueUI +public import LeanPool.OneManifold.OneMfld.IntervalCharts +public import LeanPool.OneManifold.OneMfld.LocallyConnected +public import LeanPool.OneManifold.OneMfld.NiceCharts +public import LeanPool.OneManifold.OneMfld.Noncompact +public import LeanPool.OneManifold.OneMfld.Normalize +public import LeanPool.OneManifold.OneMfld.Outer +public import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers +public import LeanPool.OneManifold.OneMfld.RealIntervals +public import LeanPool.OneManifold.OneMfld.TransitionMono +public import LeanPool.OneManifold.OneMfld.TwoComponents +public import LeanPool.OneManifold.OneMfld.UnitInterval +public import LeanPool.OneManifold.Solution + /-! # The classification of compact 1-manifolds @@ -42,3 +45,5 @@ Main declarations: `OneMfld.homeomorph_circle_or_unitInterval` Tags: topology MSC: 57N99, 54F65, 68V20 -/ + +@[expose] public section diff --git a/LeanPool/OneManifold/OneMfld.lean b/LeanPool/OneManifold/OneMfld.lean index 1750f08943..73539efeb5 100644 --- a/LeanPool/OneManifold/OneMfld.lean +++ b/LeanPool/OneManifold/OneMfld.lean @@ -3,5 +3,7 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import LeanPool.OneManifold.OneMfld.Classification +module + +public import LeanPool.OneManifold.OneMfld.Classification diff --git a/LeanPool/OneManifold/OneMfld/Charts.lean b/LeanPool/OneManifold/OneMfld/Charts.lean index 7a6d6e63b9..f369c051d5 100644 --- a/LeanPool/OneManifold/OneMfld/Charts.lean +++ b/LeanPool/OneManifold/OneMfld/Charts.lean @@ -3,8 +3,11 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers +module + +public import Mathlib.Tactic +public import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers + /-! Interval charts on a 1-manifold charted on `ℝ≥0`, and the `Overlap` relation. @@ -12,6 +15,8 @@ An `OChart` has an open-interval target `Ioo x y` (an interior chart); an `HChar half-open target `Iio x` (a boundary chart); an `IChart` is either. -/ +@[expose] public section + /-- A one-dimensional chart with an open bounded interval as target. -/ structure OChart (M : Type*) [TopologicalSpace M] extends OpenPartialHomeomorph M NNReal where diff --git a/LeanPool/OneManifold/OneMfld/CircleBlocks.lean b/LeanPool/OneManifold/OneMfld/CircleBlocks.lean index 40d732d229..b1d9bd79db 100644 --- a/LeanPool/OneManifold/OneMfld/CircleBlocks.lean +++ b/LeanPool/OneManifold/OneMfld/CircleBlocks.lean @@ -3,13 +3,16 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Algebra.Order.Star.Real -import Mathlib.Analysis.Normed.Order.Lattice -import Mathlib.Tactic -import Mathlib.Topology.Algebra.ProperAction.Basic -import Mathlib.Topology.GDelta.MetrizableSpace -import Mathlib.Topology.Instances.AddCircle.Defs -import Mathlib.Topology.Instances.ZMultiples +module + +public import Mathlib.Algebra.Order.Star.Real +public import Mathlib.Analysis.Normed.Order.Lattice +public import Mathlib.Tactic +public import Mathlib.Topology.Algebra.ProperAction.Basic +public import Mathlib.Topology.GDelta.MetrizableSpace +public import Mathlib.Topology.Instances.AddCircle.Defs +public import Mathlib.Topology.Instances.ZMultiples + /-! # Building blocks for the circle case @@ -24,6 +27,8 @@ import Mathlib.Topology.Instances.ZMultiples the circle by a closed arc and its complementary open arc. -/ +@[expose] public section + open Set noncomputable section diff --git a/LeanPool/OneManifold/OneMfld/CircleGlue.lean b/LeanPool/OneManifold/OneMfld/CircleGlue.lean index 5793f9360b..a45715086c 100644 --- a/LeanPool/OneManifold/OneMfld/CircleGlue.lean +++ b/LeanPool/OneManifold/OneMfld/CircleGlue.lean @@ -3,12 +3,15 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import LeanPool.OneManifold.OneMfld.Charts -import LeanPool.OneManifold.OneMfld.Normalize -import LeanPool.OneManifold.OneMfld.GlueBlocks -import LeanPool.OneManifold.OneMfld.TwoComponents -import LeanPool.OneManifold.OneMfld.CircleBlocks +module + +public import Mathlib.Tactic +public import LeanPool.OneManifold.OneMfld.Charts +public import LeanPool.OneManifold.OneMfld.Normalize +public import LeanPool.OneManifold.OneMfld.GlueBlocks +public import LeanPool.OneManifold.OneMfld.TwoComponents +public import LeanPool.OneManifold.OneMfld.CircleBlocks + /-! # The circle chart @@ -21,6 +24,8 @@ whose frontier is the two split points. The result is a chart of `M` onto the wh `AddCircle 1` with source `a.source ∪ b.source`. -/ +@[expose] public section + open Set /-! ### Small helpers -/ diff --git a/LeanPool/OneManifold/OneMfld/Classification.lean b/LeanPool/OneManifold/OneMfld/Classification.lean index 2ee464d936..14295b1b69 100644 --- a/LeanPool/OneManifold/OneMfld/Classification.lean +++ b/LeanPool/OneManifold/OneMfld/Classification.lean @@ -3,15 +3,18 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Algebra.Order.Ring.Star -import Mathlib.Data.Int.Star -import Mathlib.Tactic -import LeanPool.OneManifold.OneMfld.UnitInterval -import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts -import LeanPool.OneManifold.OneMfld.IntervalCharts -import LeanPool.OneManifold.OneMfld.NiceCharts -import LeanPool.OneManifold.OneMfld.ClassifyOverlaps -import LeanPool.OneManifold.OneMfld.Compactness +module + +public import Mathlib.Algebra.Order.Ring.Star +public import Mathlib.Data.Int.Star +public import Mathlib.Tactic +public import LeanPool.OneManifold.OneMfld.UnitInterval +public import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts +public import LeanPool.OneManifold.OneMfld.IntervalCharts +public import LeanPool.OneManifold.OneMfld.NiceCharts +public import LeanPool.OneManifold.OneMfld.ClassifyOverlaps +public import LeanPool.OneManifold.OneMfld.Compactness + /-! # Classification @@ -19,6 +22,8 @@ import LeanPool.OneManifold.OneMfld.Compactness Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + variable {M : Type*} [TopologicalSpace M] diff --git a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean index 8b96e273e6..ca7a24e5bc 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean @@ -3,11 +3,14 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Algebra.Order.Star.Real -import Mathlib.Analysis.InnerProductSpace.Basic -import Mathlib.Analysis.SpecialFunctions.Log.Basic -import Mathlib.Order.CompletePartialOrder -import Mathlib.Tactic +module + +public import Mathlib.Algebra.Order.Star.Real +public import Mathlib.Analysis.InnerProductSpace.Basic +public import Mathlib.Analysis.SpecialFunctions.Log.Basic +public import Mathlib.Order.CompletePartialOrder +public import Mathlib.Tactic + /-! # ClassifyInterval @@ -15,6 +18,8 @@ import Mathlib.Tactic Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + open Function open Set diff --git a/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean b/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean index 9e15c273dd..567adcaa46 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean @@ -3,26 +3,29 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Analysis.SpecialFunctions.Complex.Circle -import Mathlib.Tactic -import LeanPool.OneManifold.OneMfld.UnitInterval -import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts -import LeanPool.OneManifold.OneMfld.IntervalCharts -import LeanPool.OneManifold.OneMfld.NiceCharts -import LeanPool.OneManifold.OneMfld.ClosureOverlap -import LeanPool.OneManifold.OneMfld.RealIntervals -import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers -import LeanPool.OneManifold.OneMfld.Charts -import LeanPool.OneManifold.OneMfld.Outer -import LeanPool.OneManifold.OneMfld.TransitionMono -import LeanPool.OneManifold.OneMfld.Normalize -import LeanPool.OneManifold.OneMfld.GlueCore -import LeanPool.OneManifold.OneMfld.GlueBlocks -import LeanPool.OneManifold.OneMfld.GlueNNReal -import LeanPool.OneManifold.OneMfld.GlueUI -import LeanPool.OneManifold.OneMfld.TwoComponents -import LeanPool.OneManifold.OneMfld.CircleBlocks -import LeanPool.OneManifold.OneMfld.CircleGlue +module + +public import Mathlib.Analysis.SpecialFunctions.Complex.Circle +public import Mathlib.Tactic +public import LeanPool.OneManifold.OneMfld.UnitInterval +public import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts +public import LeanPool.OneManifold.OneMfld.IntervalCharts +public import LeanPool.OneManifold.OneMfld.NiceCharts +public import LeanPool.OneManifold.OneMfld.ClosureOverlap +public import LeanPool.OneManifold.OneMfld.RealIntervals +public import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers +public import LeanPool.OneManifold.OneMfld.Charts +public import LeanPool.OneManifold.OneMfld.Outer +public import LeanPool.OneManifold.OneMfld.TransitionMono +public import LeanPool.OneManifold.OneMfld.Normalize +public import LeanPool.OneManifold.OneMfld.GlueCore +public import LeanPool.OneManifold.OneMfld.GlueBlocks +public import LeanPool.OneManifold.OneMfld.GlueNNReal +public import LeanPool.OneManifold.OneMfld.GlueUI +public import LeanPool.OneManifold.OneMfld.TwoComponents +public import LeanPool.OneManifold.OneMfld.CircleBlocks +public import LeanPool.OneManifold.OneMfld.CircleGlue + /-! # ClassifyOverlaps @@ -30,6 +33,8 @@ import LeanPool.OneManifold.OneMfld.CircleGlue Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + open Set variable diff --git a/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean b/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean index 2d6f5bf0fa..b170d4ec70 100644 --- a/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean +++ b/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean @@ -3,8 +3,11 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import Mathlib.Topology.Connected.Basic +module + +public import Mathlib.Tactic +public import Mathlib.Topology.Connected.Basic + /-! # ClosureOverlap @@ -12,6 +15,8 @@ import Mathlib.Topology.Connected.Basic Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + open Set TopologicalSpace universe u diff --git a/LeanPool/OneManifold/OneMfld/Compactness.lean b/LeanPool/OneManifold/OneMfld/Compactness.lean index ce1b80be32..f9a3651958 100644 --- a/LeanPool/OneManifold/OneMfld/Compactness.lean +++ b/LeanPool/OneManifold/OneMfld/Compactness.lean @@ -3,9 +3,12 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts -import LeanPool.OneManifold.OneMfld.Noncompact +module + +public import Mathlib.Tactic +public import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts +public import LeanPool.OneManifold.OneMfld.Noncompact + /-! # Compactness @@ -13,6 +16,8 @@ import LeanPool.OneManifold.OneMfld.Noncompact Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + variable {M : Type*} [TopologicalSpace M] diff --git a/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean b/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean index ee772c0562..472b254633 100644 --- a/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean +++ b/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean @@ -3,9 +3,12 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import LeanPool.OneManifold.OneMfld.IntervalCharts -import LeanPool.OneManifold.OneMfld.FinitelyCharted +module + +public import Mathlib.Tactic +public import LeanPool.OneManifold.OneMfld.IntervalCharts +public import LeanPool.OneManifold.OneMfld.FinitelyCharted + /-! # FiniteIntervalCharts @@ -13,6 +16,8 @@ import LeanPool.OneManifold.OneMfld.FinitelyCharted Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + /-- A space equipped with a finite atlas of interval charts. -/ class FinitelyIntervalChartedSpace (M : Type*) [TopologicalSpace M] extends IntervalChartedSpace M where diff --git a/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean b/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean index f6566271e8..65d0a07e2d 100644 --- a/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean +++ b/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean @@ -3,8 +3,11 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Geometry.Manifold.ChartedSpace -import Mathlib.Tactic +module + +public import Mathlib.Geometry.Manifold.ChartedSpace +public import Mathlib.Tactic + /-! # FinitelyCharted @@ -12,6 +15,8 @@ import Mathlib.Tactic Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + variable {H : Type*} [TopologicalSpace H] {M : Type*} [TopologicalSpace M] variable diff --git a/LeanPool/OneManifold/OneMfld/GlueBlocks.lean b/LeanPool/OneManifold/OneMfld/GlueBlocks.lean index db9bc4ee21..8986b0aafa 100644 --- a/LeanPool/OneManifold/OneMfld/GlueBlocks.lean +++ b/LeanPool/OneManifold/OneMfld/GlueBlocks.lean @@ -3,9 +3,12 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Algebra.Order.Star.Real -import Mathlib.Tactic -import LeanPool.OneManifold.OneMfld.UnitInterval +module + +public import Mathlib.Algebra.Order.Star.Real +public import Mathlib.Tactic +public import LeanPool.OneManifold.OneMfld.UnitInterval + /-! # Building blocks for the H-H gluing @@ -22,6 +25,8 @@ Two overlapping boundary charts glue to a *closed* interval, so the glued chart * reflection images of end-segments in `ℝ≥0`, used to re-orient `OChart`s. -/ +@[expose] public section + open Set Topology noncomputable section diff --git a/LeanPool/OneManifold/OneMfld/GlueCore.lean b/LeanPool/OneManifold/OneMfld/GlueCore.lean index ab941a6249..80cd9c3665 100644 --- a/LeanPool/OneManifold/OneMfld/GlueCore.lean +++ b/LeanPool/OneManifold/OneMfld/GlueCore.lean @@ -3,9 +3,12 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import LeanPool.OneManifold.OneMfld.Outer -import LeanPool.OneManifold.OneMfld.TransitionMono +module + +public import Mathlib.Tactic +public import LeanPool.OneManifold.OneMfld.Outer +public import LeanPool.OneManifold.OneMfld.TransitionMono + /-! # Core lemmas for gluing overlapping charts @@ -21,6 +24,8 @@ Two results feed the gluing construction: overlap would accumulate at two distinct points of `M` at once, contradicting `T2`. -/ +@[expose] public section + open Set Filter Topology /-- A strictly antitone map of `Ioo p v` onto `Ioo q w` tends to `q` at the top end. -/ diff --git a/LeanPool/OneManifold/OneMfld/GlueNNReal.lean b/LeanPool/OneManifold/OneMfld/GlueNNReal.lean index 4d3b89af7b..99a2b3865b 100644 --- a/LeanPool/OneManifold/OneMfld/GlueNNReal.lean +++ b/LeanPool/OneManifold/OneMfld/GlueNNReal.lean @@ -3,9 +3,12 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import LeanPool.OneManifold.OneMfld.GlueCore -import LeanPool.OneManifold.OneMfld.Normalize +module + +public import Mathlib.Tactic +public import LeanPool.OneManifold.OneMfld.GlueCore +public import LeanPool.OneManifold.OneMfld.Normalize + /-! # Gluing two charts into an `ℝ≥0`-valued chart @@ -19,6 +22,8 @@ its target. Pick a split value `μ ∈ Ioo q 1`, let `m := b.symm μ` be the spl All the frontier conditions come from `IsImage.frontier` and `frontier_Iic`. -/ +@[expose] public section + open Set /-- **NNReal gluing.** Given charts `a` (target `Ioo 0 1`, overlap image the lower diff --git a/LeanPool/OneManifold/OneMfld/GlueUI.lean b/LeanPool/OneManifold/OneMfld/GlueUI.lean index ac1a3ffdb2..8280966620 100644 --- a/LeanPool/OneManifold/OneMfld/GlueUI.lean +++ b/LeanPool/OneManifold/OneMfld/GlueUI.lean @@ -3,10 +3,13 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import Mathlib.Topology.OpenPartialHomeomorph.Constructions -import LeanPool.OneManifold.OneMfld.GlueCore -import LeanPool.OneManifold.OneMfld.GlueBlocks +module + +public import Mathlib.Tactic +public import Mathlib.Topology.OpenPartialHomeomorph.Constructions +public import LeanPool.OneManifold.OneMfld.GlueCore +public import LeanPool.OneManifold.OneMfld.GlueBlocks + /-! # Gluing two boundary charts onto the unit interval @@ -20,6 +23,8 @@ point `m := b.symm μ` (that is, `k/(ρ+k) = μ/2` where `ρ := a m`). Glue with `[0, μ/2]` and `(μ/2, 1]` unite to the whole interval. -/ +@[expose] public section + open Set /-- The half-scale and Möbius charts cover the unit interval across their common split level. -/ diff --git a/LeanPool/OneManifold/OneMfld/IntervalCharts.lean b/LeanPool/OneManifold/OneMfld/IntervalCharts.lean index 5c5e888a3e..74a743d9be 100644 --- a/LeanPool/OneManifold/OneMfld/IntervalCharts.lean +++ b/LeanPool/OneManifold/OneMfld/IntervalCharts.lean @@ -3,9 +3,12 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import LeanPool.OneManifold.OneMfld.ClassifyInterval -import LeanPool.OneManifold.OneMfld.NiceCharts +module + +public import Mathlib.Tactic +public import LeanPool.OneManifold.OneMfld.ClassifyInterval +public import LeanPool.OneManifold.OneMfld.NiceCharts + /-! # IntervalCharts @@ -13,6 +16,8 @@ import LeanPool.OneManifold.OneMfld.NiceCharts Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + /-- A space charted on the half-line with interval targets. -/ class IntervalChartedSpace (M : Type*) [TopologicalSpace M] extends ChartedSpace NNReal M where is_interval (φ : OpenPartialHomeomorph M NNReal) (h : φ ∈ atlas) : (∃ x y, (Set.Ioo x y = diff --git a/LeanPool/OneManifold/OneMfld/LocallyConnected.lean b/LeanPool/OneManifold/OneMfld/LocallyConnected.lean index 98b6ff245f..d09b1dfb7f 100644 --- a/LeanPool/OneManifold/OneMfld/LocallyConnected.lean +++ b/LeanPool/OneManifold/OneMfld/LocallyConnected.lean @@ -3,9 +3,12 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Analysis.InnerProductSpace.Basic -import Mathlib.Analysis.Normed.Order.Lattice -import Mathlib.Tactic +module + +public import Mathlib.Analysis.InnerProductSpace.Basic +public import Mathlib.Analysis.Normed.Order.Lattice +public import Mathlib.Tactic + /-! # LocallyConnected @@ -13,6 +16,8 @@ import Mathlib.Tactic Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + instance : LocallyConnectedSpace Real := by infer_instance instance : LocallyConnectedSpace NNReal := by diff --git a/LeanPool/OneManifold/OneMfld/NiceCharts.lean b/LeanPool/OneManifold/OneMfld/NiceCharts.lean index 716eebf604..25925b7401 100644 --- a/LeanPool/OneManifold/OneMfld/NiceCharts.lean +++ b/LeanPool/OneManifold/OneMfld/NiceCharts.lean @@ -3,11 +3,14 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Algebra.Order.Star.Real -import Mathlib.Geometry.Manifold.ChartedSpace -import Mathlib.Tactic -import LeanPool.OneManifold.OneMfld.LocallyConnected -import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers +module + +public import Mathlib.Algebra.Order.Star.Real +public import Mathlib.Geometry.Manifold.ChartedSpace +public import Mathlib.Tactic +public import LeanPool.OneManifold.OneMfld.LocallyConnected +public import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers + /-! # NiceCharts @@ -15,6 +18,8 @@ import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + variable {M : Type*} [TopologicalSpace M] diff --git a/LeanPool/OneManifold/OneMfld/Noncompact.lean b/LeanPool/OneManifold/OneMfld/Noncompact.lean index 7558665222..271557dd87 100644 --- a/LeanPool/OneManifold/OneMfld/Noncompact.lean +++ b/LeanPool/OneManifold/OneMfld/Noncompact.lean @@ -3,8 +3,11 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Analysis.Normed.Order.Lattice -import Mathlib.Tactic +module + +public import Mathlib.Analysis.Normed.Order.Lattice +public import Mathlib.Tactic + /-! # Noncompact @@ -12,6 +15,8 @@ import Mathlib.Tactic Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + open Set /-- `[0, ∞) ⊆ ℝ` is not compact. -/ diff --git a/LeanPool/OneManifold/OneMfld/Normalize.lean b/LeanPool/OneManifold/OneMfld/Normalize.lean index c41db448dc..590f514a30 100644 --- a/LeanPool/OneManifold/OneMfld/Normalize.lean +++ b/LeanPool/OneManifold/OneMfld/Normalize.lean @@ -3,10 +3,13 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Algebra.Order.Star.Real -import Mathlib.Tactic -import Mathlib.Topology.OpenPartialHomeomorph.Constructions -import LeanPool.OneManifold.OneMfld.Charts +module + +public import Mathlib.Algebra.Order.Star.Real +public import Mathlib.Tactic +public import Mathlib.Topology.OpenPartialHomeomorph.Constructions +public import LeanPool.OneManifold.OneMfld.Charts + /-! # Normalization of interval charts @@ -16,6 +19,8 @@ is `Ioo 0 1`, and an `OChart` with target `Ioo 0 1` can be orientation-reversed (`x ↦ 1 - x`). H-charts cannot be flipped: the closed end at `0` is a boundary point. -/ +@[expose] public section + open Set noncomputable section diff --git a/LeanPool/OneManifold/OneMfld/Outer.lean b/LeanPool/OneManifold/OneMfld/Outer.lean index b7edffb3b1..2635e6983f 100644 --- a/LeanPool/OneManifold/OneMfld/Outer.lean +++ b/LeanPool/OneManifold/OneMfld/Outer.lean @@ -3,11 +3,14 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import LeanPool.OneManifold.OneMfld.ClosureOverlap -import LeanPool.OneManifold.OneMfld.LocallyConnected -import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers -import LeanPool.OneManifold.OneMfld.ClassifyInterval +module + +public import Mathlib.Tactic +public import LeanPool.OneManifold.OneMfld.ClosureOverlap +public import LeanPool.OneManifold.OneMfld.LocallyConnected +public import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers +public import LeanPool.OneManifold.OneMfld.ClassifyInterval + /-! # The outer-overlap lemma @@ -20,6 +23,8 @@ argument), contradicting `nonempty_closure_inter_diff`, which forces the compone closure to escape into `V.source \ U.source`. -/ +@[expose] public section + open Set variable {M : Type*} [TopologicalSpace M] diff --git a/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean b/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean index 42543eef8b..4f1a8c07ad 100644 --- a/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean +++ b/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean @@ -3,9 +3,12 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import Mathlib.Topology.Connected.Basic -import Mathlib.Topology.OpenPartialHomeomorph.Defs +module + +public import Mathlib.Tactic +public import Mathlib.Topology.Connected.Basic +public import Mathlib.Topology.OpenPartialHomeomorph.Defs + /-! # PartialHomeomorphHelpers @@ -13,6 +16,8 @@ import Mathlib.Topology.OpenPartialHomeomorph.Defs Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + lemma partial_homeo_connected {X : Type*} {Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] (h : OpenPartialHomeomorph X Y) (conn : IsConnected h.source) : (IsConnected h.target) := by have ht : h.target = h.toFun '' h.source diff --git a/LeanPool/OneManifold/OneMfld/RealIntervals.lean b/LeanPool/OneManifold/OneMfld/RealIntervals.lean index 45f69c68dd..686cf04782 100644 --- a/LeanPool/OneManifold/OneMfld/RealIntervals.lean +++ b/LeanPool/OneManifold/OneMfld/RealIntervals.lean @@ -3,11 +3,14 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Analysis.InnerProductSpace.Basic -import Mathlib.Analysis.Normed.Module.RCLike.Real -import Mathlib.Analysis.Normed.Order.Lattice -import Mathlib.Order.CompletePartialOrder -import Mathlib.Tactic +module + +public import Mathlib.Analysis.InnerProductSpace.Basic +public import Mathlib.Analysis.Normed.Module.RCLike.Real +public import Mathlib.Analysis.Normed.Order.Lattice +public import Mathlib.Order.CompletePartialOrder +public import Mathlib.Tactic + /-! # RealIntervals @@ -15,6 +18,8 @@ import Mathlib.Tactic Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + open Set namespace RealIntervals @@ -29,10 +34,7 @@ lemma ordconn_of_connected {X : Set ℝ} (conn : IsConnected X) -- Shouldn't this already be in mathlib? lemma Real.exists_isGLB {S : Set ℝ} (hne : S.Nonempty) (hbdd : BddBelow S) : ∃ x, IsGLB S x := by - use sInf S - rw [Real.sInf_def, ← isLUB_neg, Real.sSup_def, dite_eq_left] - · apply Classical.choose_spec - exact ⟨nonempty_neg.mpr hne, BddBelow.neg hbdd⟩ + exact ⟨sInf S, isGLB_csInf hne hbdd⟩ -- classifying real intervals diff --git a/LeanPool/OneManifold/OneMfld/TransitionMono.lean b/LeanPool/OneManifold/OneMfld/TransitionMono.lean index 695b2ccb1c..fb592d9642 100644 --- a/LeanPool/OneManifold/OneMfld/TransitionMono.lean +++ b/LeanPool/OneManifold/OneMfld/TransitionMono.lean @@ -3,9 +3,12 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import Mathlib.Topology.Bornology.Real -import Mathlib.Topology.UniformSpace.Real +module + +public import Mathlib.Tactic +public import Mathlib.Topology.Bornology.Real +public import Mathlib.Topology.UniformSpace.Real + /-! # Monotonicity of transition maps @@ -15,6 +18,8 @@ monotone or strictly antitone; and a strictly monotone map of one open interval another sends ends to ends. -/ +@[expose] public section + open Set Filter Topology /-- A continuous injective function on an open interval of `ℝ≥0` is strictly monotone or diff --git a/LeanPool/OneManifold/OneMfld/TwoComponents.lean b/LeanPool/OneManifold/OneMfld/TwoComponents.lean index 97cef31d5e..5a1bb24b6f 100644 --- a/LeanPool/OneManifold/OneMfld/TwoComponents.lean +++ b/LeanPool/OneManifold/OneMfld/TwoComponents.lean @@ -3,10 +3,13 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import LeanPool.OneManifold.OneMfld.Outer -import LeanPool.OneManifold.OneMfld.TransitionMono -import LeanPool.OneManifold.OneMfld.GlueCore +module + +public import Mathlib.Tactic +public import LeanPool.OneManifold.OneMfld.Outer +public import LeanPool.OneManifold.OneMfld.TransitionMono +public import LeanPool.OneManifold.OneMfld.GlueCore + /-! # The two-component structure of a disconnected overlap @@ -17,6 +20,8 @@ the full overlap to a single component `W`: the extra hypothesis is that the rel interior endpoint is not in the image of the *full* overlap. -/ +@[expose] public section + open Set Filter Topology /-- A strictly antitone map of `Ioo p v` onto `Ioo q w` tends to `w` at the bottom end. -/ diff --git a/LeanPool/OneManifold/OneMfld/UnitInterval.lean b/LeanPool/OneManifold/OneMfld/UnitInterval.lean index d49421d9ef..52b30739c5 100644 --- a/LeanPool/OneManifold/OneMfld/UnitInterval.lean +++ b/LeanPool/OneManifold/OneMfld/UnitInterval.lean @@ -3,9 +3,12 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import Mathlib.Tactic -import Mathlib.Topology.MetricSpace.Pseudo.Lemmas -import Mathlib.Topology.Order.Compact +module + +public import Mathlib.Tactic +public import Mathlib.Topology.MetricSpace.Pseudo.Lemmas +public import Mathlib.Topology.Order.Compact + /-! # UnitInterval @@ -13,6 +16,8 @@ import Mathlib.Topology.Order.Compact Supporting results for the classification of compact one-dimensional manifolds. -/ +@[expose] public section + /-- The closed unit interval in the real line. -/ def UnitInterval : Set Real := { x : Real | 0 ≤ x ∧ x ≤ 1 } diff --git a/LeanPool/OneManifold/Solution.lean b/LeanPool/OneManifold/Solution.lean index b3b810ea7d..d2241cfa1f 100644 --- a/LeanPool/OneManifold/Solution.lean +++ b/LeanPool/OneManifold/Solution.lean @@ -3,7 +3,10 @@ Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jim Fowler, Dennis Sweeney -/ -import LeanPool.OneManifold.OneMfld.Classification +module + +public import LeanPool.OneManifold.OneMfld.Classification + /-! # Proved solution @@ -16,6 +19,8 @@ Prop-level disjunction. The Challenge's `{x : ℝ // 0 ≤ x ∧ x ≤ 1}` is definitionally `↥OneMfld.UnitInterval` (and Mathlib's `↥unitInterval`). -/ +@[expose] public section + theorem OneMfld.homeomorph_circle_or_unitInterval (M : Type*) [TopologicalSpace M] [CompactSpace M] [ConnectedSpace M] [T2Space M] [ChartedSpace NNReal M] : From 4ade9b518815f490b9ce692ead6306247acfec95 Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Fri, 25 Sep 2026 19:21:42 +0000 Subject: [PATCH 05/16] Contain one-manifold API and remove unused interval scaffolding --- LeanPool.lean | 1 - LeanPool/OneManifold.lean | 1 - LeanPool/OneManifold/OneMfld/Charts.lean | 4 + .../OneManifold/OneMfld/CircleBlocks.lean | 4 + LeanPool/OneManifold/OneMfld/CircleGlue.lean | 4 + .../OneManifold/OneMfld/Classification.lean | 4 + .../OneManifold/OneMfld/ClassifyInterval.lean | 4 + .../OneManifold/OneMfld/ClassifyOverlaps.lean | 5 +- .../OneManifold/OneMfld/ClosureOverlap.lean | 4 + LeanPool/OneManifold/OneMfld/Compactness.lean | 4 + .../OneMfld/FiniteIntervalCharts.lean | 4 + .../OneManifold/OneMfld/FinitelyCharted.lean | 4 + LeanPool/OneManifold/OneMfld/GlueBlocks.lean | 6 + LeanPool/OneManifold/OneMfld/GlueCore.lean | 4 + LeanPool/OneManifold/OneMfld/GlueNNReal.lean | 4 + LeanPool/OneManifold/OneMfld/GlueUI.lean | 4 + .../OneManifold/OneMfld/IntervalCharts.lean | 4 + .../OneManifold/OneMfld/LocallyConnected.lean | 4 +- LeanPool/OneManifold/OneMfld/NiceCharts.lean | 4 + LeanPool/OneManifold/OneMfld/Noncompact.lean | 4 + LeanPool/OneManifold/OneMfld/Normalize.lean | 4 + LeanPool/OneManifold/OneMfld/Outer.lean | 4 + .../OneMfld/PartialHomeomorphHelpers.lean | 4 + .../OneManifold/OneMfld/RealIntervals.lean | 511 ------------------ .../OneManifold/OneMfld/TransitionMono.lean | 4 + .../OneManifold/OneMfld/TwoComponents.lean | 4 + .../OneManifold/OneMfld/UnitInterval.lean | 4 + LeanPool/OneManifold/Solution.lean | 10 +- 28 files changed, 104 insertions(+), 518 deletions(-) delete mode 100644 LeanPool/OneManifold/OneMfld/RealIntervals.lean diff --git a/LeanPool.lean b/LeanPool.lean index d8915481ed..5fd88508d6 100644 --- a/LeanPool.lean +++ b/LeanPool.lean @@ -6555,7 +6555,6 @@ public import LeanPool.OneManifold.OneMfld.Noncompact public import LeanPool.OneManifold.OneMfld.Normalize public import LeanPool.OneManifold.OneMfld.Outer public import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers -public import LeanPool.OneManifold.OneMfld.RealIntervals public import LeanPool.OneManifold.OneMfld.TransitionMono public import LeanPool.OneManifold.OneMfld.TwoComponents public import LeanPool.OneManifold.OneMfld.UnitInterval diff --git a/LeanPool/OneManifold.lean b/LeanPool/OneManifold.lean index 88574478ca..ed8031c040 100644 --- a/LeanPool/OneManifold.lean +++ b/LeanPool/OneManifold.lean @@ -28,7 +28,6 @@ public import LeanPool.OneManifold.OneMfld.Noncompact public import LeanPool.OneManifold.OneMfld.Normalize public import LeanPool.OneManifold.OneMfld.Outer public import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers -public import LeanPool.OneManifold.OneMfld.RealIntervals public import LeanPool.OneManifold.OneMfld.TransitionMono public import LeanPool.OneManifold.OneMfld.TwoComponents public import LeanPool.OneManifold.OneMfld.UnitInterval diff --git a/LeanPool/OneManifold/OneMfld/Charts.lean b/LeanPool/OneManifold/OneMfld/Charts.lean index f369c051d5..ea5db4cdf5 100644 --- a/LeanPool/OneManifold/OneMfld/Charts.lean +++ b/LeanPool/OneManifold/OneMfld/Charts.lean @@ -17,6 +17,8 @@ half-open target `Iio x` (a boundary chart); an `IChart` is either. @[expose] public section +namespace OneMfld + /-- A one-dimensional chart with an open bounded interval as target. -/ structure OChart (M : Type*) [TopologicalSpace M] extends OpenPartialHomeomorph M NNReal where @@ -103,3 +105,5 @@ lemma IChart.connected_source (a : IChart M) (h : a.source.Nonempty) : exact isConnected_Ioo (Set.nonempty_Ioo.mp hne) · rw [←hx] at hne ⊢ exact ⟨hne, isPreconnected_Iio⟩ + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/CircleBlocks.lean b/LeanPool/OneManifold/OneMfld/CircleBlocks.lean index b1d9bd79db..3462616e9e 100644 --- a/LeanPool/OneManifold/OneMfld/CircleBlocks.lean +++ b/LeanPool/OneManifold/OneMfld/CircleBlocks.lean @@ -29,6 +29,8 @@ public import Mathlib.Topology.Instances.ZMultiples @[expose] public section +namespace OneMfld + open Set noncomputable section @@ -301,3 +303,5 @@ lemma addCircle_arc_union_covers {c d : ℝ} (hcd : c ≤ d) (hlen : d < c + 1) end AddCircleArith end + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/CircleGlue.lean b/LeanPool/OneManifold/OneMfld/CircleGlue.lean index a45715086c..6f9c425803 100644 --- a/LeanPool/OneManifold/OneMfld/CircleGlue.lean +++ b/LeanPool/OneManifold/OneMfld/CircleGlue.lean @@ -26,6 +26,8 @@ whose frontier is the two split points. The result is a chart of `M` onto the wh @[expose] public section +namespace OneMfld + open Set /-! ### Small helpers -/ @@ -986,3 +988,5 @@ theorem exists_circle_chart {M : Type*} [TopologicalSpace M] [T2Space M] obtain ⟨f, hfs, hft⟩ := circle_chart_of_normalized A B W₀ W₁ r p s q hAt hBt hunion himgA₀ himgA₁ himgB₀ himgB₁ hr0 hrp hp1 hr4 hs0 hsq hq1 hs4 exact ⟨f, by rw [hfs, hAs, hBs], hft⟩ + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/Classification.lean b/LeanPool/OneManifold/OneMfld/Classification.lean index 14295b1b69..190bc339b1 100644 --- a/LeanPool/OneManifold/OneMfld/Classification.lean +++ b/LeanPool/OneManifold/OneMfld/Classification.lean @@ -24,6 +24,8 @@ Supporting results for the classification of compact one-dimensional manifolds. @[expose] public section +namespace OneMfld + variable {M : Type*} [TopologicalSpace M] @@ -403,3 +405,5 @@ noncomputable def classification [T2Space M] [CompactSpace M] (ht : ChartedSpace let ht' := nicelyCharted ht let ht'' := intervalCharted ht' classification' (finitelyIntervalCharted ht'') + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean index ca7a24e5bc..542662b5ae 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean @@ -20,6 +20,8 @@ Supporting results for the classification of compact one-dimensional manifolds. @[expose] public section +namespace OneMfld + open Function open Set @@ -1393,3 +1395,5 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc rw [relu_zero] at this assumption exact h0u0 this' + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean b/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean index 567adcaa46..3b3117e7c2 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean @@ -12,7 +12,6 @@ public import LeanPool.OneManifold.OneMfld.FiniteIntervalCharts public import LeanPool.OneManifold.OneMfld.IntervalCharts public import LeanPool.OneManifold.OneMfld.NiceCharts public import LeanPool.OneManifold.OneMfld.ClosureOverlap -public import LeanPool.OneManifold.OneMfld.RealIntervals public import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers public import LeanPool.OneManifold.OneMfld.Charts public import LeanPool.OneManifold.OneMfld.Outer @@ -35,6 +34,8 @@ Supporting results for the classification of compact one-dimensional manifolds. @[expose] public section +namespace OneMfld + open Set variable @@ -465,3 +466,5 @@ noncomputable def handleOO (a : OChart M) (b : OChart M) (h : Overlap a.source b by_cases hc : IsConnected (a.source ∩ b.source) · exact Sum.inr ⟨(exists_glue_o_o a b h hc).choose, (exists_glue_o_o a b h hc).choose_spec⟩ · exact Sum.inl (circleOfDisconnectedOverlap a b h hc) + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean b/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean index b170d4ec70..6f609e8f16 100644 --- a/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean +++ b/LeanPool/OneManifold/OneMfld/ClosureOverlap.lean @@ -17,6 +17,8 @@ Supporting results for the classification of compact one-dimensional manifolds. @[expose] public section +namespace OneMfld + open Set TopologicalSpace universe u @@ -80,3 +82,5 @@ lemma nonempty_closure_inter_diff have nonemptyVAB : (V ∩ (A ∩ B)).Nonempty := hVconn' A B openA openB coverAB nonemptyVA nonemptyVB rw [disjointAB] at nonemptyVAB simp only [inter_empty, Set.not_nonempty_empty] at nonemptyVAB + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/Compactness.lean b/LeanPool/OneManifold/OneMfld/Compactness.lean index f9a3651958..a8dfe3278b 100644 --- a/LeanPool/OneManifold/OneMfld/Compactness.lean +++ b/LeanPool/OneManifold/OneMfld/Compactness.lean @@ -18,6 +18,8 @@ Supporting results for the classification of compact one-dimensional manifolds. @[expose] public section +namespace OneMfld + variable {M : Type*} [TopologicalSpace M] @@ -111,3 +113,5 @@ lemma noncompact_target (ht : FinitelyIntervalChartedSpace M) (z : M) (a : OpenP simp only [Set.mem_Iio] at hz' have hx : 0 < x := by exact pos_of_gt hz' apply noncompact_iio x hx + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean b/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean index 472b254633..bdf1d29449 100644 --- a/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean +++ b/LeanPool/OneManifold/OneMfld/FiniteIntervalCharts.lean @@ -18,6 +18,8 @@ Supporting results for the classification of compact one-dimensional manifolds. @[expose] public section +namespace OneMfld + /-- A space equipped with a finite atlas of interval charts. -/ class FinitelyIntervalChartedSpace (M : Type*) [TopologicalSpace M] extends IntervalChartedSpace M where @@ -42,3 +44,5 @@ variable apply c2 exact hx } + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean b/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean index 65d0a07e2d..937d2115d8 100644 --- a/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean +++ b/LeanPool/OneManifold/OneMfld/FinitelyCharted.lean @@ -17,6 +17,8 @@ Supporting results for the classification of compact one-dimensional manifolds. @[expose] public section +namespace OneMfld + variable {H : Type*} [TopologicalSpace H] {M : Type*} [TopologicalSpace M] variable @@ -68,3 +70,5 @@ noncomputable def chooseCharts [CompactSpace M] [ht : ChartedSpace H M] : { ht' · exact Set.toFinite (ht.chartAt '' ↑t) · intro x hx simp only [Set.mem_preimage, chart_mem_atlas] + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/GlueBlocks.lean b/LeanPool/OneManifold/OneMfld/GlueBlocks.lean index 8986b0aafa..e6f07e8002 100644 --- a/LeanPool/OneManifold/OneMfld/GlueBlocks.lean +++ b/LeanPool/OneManifold/OneMfld/GlueBlocks.lean @@ -27,6 +27,8 @@ Two overlapping boundary charts glue to a *closed* interval, so the glued chart @[expose] public section +namespace OneMfld + open Set Topology noncomputable section @@ -214,3 +216,7 @@ lemma reflect_image_Ioo_lower {q : NNReal} (_hq0 : 0 < q) (hq1 : q ≤ 1) : refine ⟨1 - z, ⟨tsub_pos_of_lt hz1, ?_⟩, tsub_tsub_cancel_of_le hz1.le⟩ rw [tsub_lt_iff_right hz1.le] exact (tsub_lt_iff_left hq1).mp hzq + +end + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/GlueCore.lean b/LeanPool/OneManifold/OneMfld/GlueCore.lean index 80cd9c3665..b18c518ddb 100644 --- a/LeanPool/OneManifold/OneMfld/GlueCore.lean +++ b/LeanPool/OneManifold/OneMfld/GlueCore.lean @@ -26,6 +26,8 @@ Two results feed the gluing construction: @[expose] public section +namespace OneMfld + open Set Filter Topology /-- A strictly antitone map of `Ioo p v` onto `Ioo q w` tends to `q` at the top end. -/ @@ -270,3 +272,5 @@ theorem overlap_anti [T2Space M] (a b : OpenPartialHomeomorph M NNReal) · intro x hx y hy hxy have h := hanti (hacoord x hx) (hacoord y hy) hxy rwa [hkey x hx, hkey y hy] at h + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/GlueNNReal.lean b/LeanPool/OneManifold/OneMfld/GlueNNReal.lean index 99a2b3865b..bd086202e7 100644 --- a/LeanPool/OneManifold/OneMfld/GlueNNReal.lean +++ b/LeanPool/OneManifold/OneMfld/GlueNNReal.lean @@ -24,6 +24,8 @@ All the frontier conditions come from `IsImage.frontier` and `frontier_Iic`. @[expose] public section +namespace OneMfld + open Set /-- **NNReal gluing.** Given charts `a` (target `Ioo 0 1`, overlap image the lower @@ -211,3 +213,5 @@ theorem glue_nnreal {M : Type*} [TopologicalSpace M] [T2Space M] exact ⟨h3, h2⟩ · rintro ⟨h1, h2⟩ exact ⟨⟨lt_of_le_of_lt (zero_le : (0 : NNReal) ≤ μ) h1, h2⟩, h1⟩ + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/GlueUI.lean b/LeanPool/OneManifold/OneMfld/GlueUI.lean index 8280966620..b3287be75d 100644 --- a/LeanPool/OneManifold/OneMfld/GlueUI.lean +++ b/LeanPool/OneManifold/OneMfld/GlueUI.lean @@ -25,6 +25,8 @@ point `m := b.symm μ` (that is, `k/(ρ+k) = μ/2` where `ρ := a m`). Glue with @[expose] public section +namespace OneMfld + open Set /-- The half-scale and Möbius charts cover the unit interval across their common split level. -/ @@ -337,3 +339,5 @@ theorem glue_hh_ui {M : Type*} [TopologicalSpace M] [T2Space M] · change (b.trans eb).target ∩ tset ∪ e'.target \ tset = univ exact half_mobius_target_cover a b eb e' hat hbt hbs hbt' he'src μ ρ k hkR hμR hμ1R hρ1R hρkR hkeyR he'f + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/IntervalCharts.lean b/LeanPool/OneManifold/OneMfld/IntervalCharts.lean index 74a743d9be..63327680f0 100644 --- a/LeanPool/OneManifold/OneMfld/IntervalCharts.lean +++ b/LeanPool/OneManifold/OneMfld/IntervalCharts.lean @@ -18,6 +18,8 @@ Supporting results for the classification of compact one-dimensional manifolds. @[expose] public section +namespace OneMfld + /-- A space charted on the half-line with interval targets. -/ class IntervalChartedSpace (M : Type*) [TopologicalSpace M] extends ChartedSpace NNReal M where is_interval (φ : OpenPartialHomeomorph M NNReal) (h : φ ∈ atlas) : (∃ x y, (Set.Ioo x y = @@ -69,3 +71,5 @@ theorem univ_unbounded : ¬ Bornology.IsBounded (Set.univ : Set NNReal) := by apply univ_unbounded rw [←h] exact bounded + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/LocallyConnected.lean b/LeanPool/OneManifold/OneMfld/LocallyConnected.lean index d09b1dfb7f..598525142a 100644 --- a/LeanPool/OneManifold/OneMfld/LocallyConnected.lean +++ b/LeanPool/OneManifold/OneMfld/LocallyConnected.lean @@ -18,7 +18,7 @@ Supporting results for the classification of compact one-dimensional manifolds. @[expose] public section -instance : LocallyConnectedSpace Real := by infer_instance +namespace OneMfld instance : LocallyConnectedSpace NNReal := by rw [locallyConnectedSpace_iff_connected_subsets] @@ -170,3 +170,5 @@ instance : LocallyConnectedSpace NNReal := by apply ul_t rw [Set.Ioo] exact aV + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/NiceCharts.lean b/LeanPool/OneManifold/OneMfld/NiceCharts.lean index 25925b7401..3f992ae127 100644 --- a/LeanPool/OneManifold/OneMfld/NiceCharts.lean +++ b/LeanPool/OneManifold/OneMfld/NiceCharts.lean @@ -20,6 +20,8 @@ Supporting results for the classification of compact one-dimensional manifolds. @[expose] public section +namespace OneMfld + variable {M : Type*} [TopologicalSpace M] @@ -215,3 +217,5 @@ class NicelyChartedSpace (H : Type*) [TopologicalSpace H] [Bornology H] (M : Typ rcases h with ⟨y, hy⟩ rw [←hy] apply nice_chart_connected + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/Noncompact.lean b/LeanPool/OneManifold/OneMfld/Noncompact.lean index 271557dd87..f39b1c219c 100644 --- a/LeanPool/OneManifold/OneMfld/Noncompact.lean +++ b/LeanPool/OneManifold/OneMfld/Noncompact.lean @@ -17,6 +17,8 @@ Supporting results for the classification of compact one-dimensional manifolds. @[expose] public section +namespace OneMfld + open Set /-- `[0, ∞) ⊆ ℝ` is not compact. -/ @@ -89,3 +91,5 @@ theorem not_compactSpace_NNReal : ¬ CompactSpace NNReal := by simpa [hImage_eq] using hImage -- Contradiction with the previous lemma. exact not_isCompact_Ici_zero_real hIci0 + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/Normalize.lean b/LeanPool/OneManifold/OneMfld/Normalize.lean index 590f514a30..38281a87b8 100644 --- a/LeanPool/OneManifold/OneMfld/Normalize.lean +++ b/LeanPool/OneManifold/OneMfld/Normalize.lean @@ -21,6 +21,8 @@ is `Ioo 0 1`, and an `OChart` with target `Ioo 0 1` can be orientation-reversed @[expose] public section +namespace OneMfld + open Set noncomputable section @@ -187,3 +189,5 @@ def OChart.flip (a : OChart M) (h01 : a.target = Ioo 0 1) : exact hef _ hmem end + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/Outer.lean b/LeanPool/OneManifold/OneMfld/Outer.lean index 2635e6983f..1f66d81e9c 100644 --- a/LeanPool/OneManifold/OneMfld/Outer.lean +++ b/LeanPool/OneManifold/OneMfld/Outer.lean @@ -25,6 +25,8 @@ closure to escape into `V.source \ U.source`. @[expose] public section +namespace OneMfld + open Set variable {M : Type*} [TopologicalSpace M] @@ -367,3 +369,5 @@ theorem overlap_component_outer_Ioo [T2Space M] exact eq_end_segment_of_closure_not_subset_Ioo (hUt ▸ hAsub) hAo hAc hesc end Outer + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean b/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean index 4f1a8c07ad..c938e42233 100644 --- a/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean +++ b/LeanPool/OneManifold/OneMfld/PartialHomeomorphHelpers.lean @@ -18,6 +18,8 @@ Supporting results for the classification of compact one-dimensional manifolds. @[expose] public section +namespace OneMfld + lemma partial_homeo_connected {X : Type*} {Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] (h : OpenPartialHomeomorph X Y) (conn : IsConnected h.source) : (IsConnected h.target) := by have ht : h.target = h.toFun '' h.source @@ -60,3 +62,5 @@ lemma restrOpen_symm_image_target {X : Type*} {Y : Type*} [TopologicalSpace X] [ · intro hz simp only [Set.mem_inter_iff, Set.mem_preimage, Set.mem_image] exact ⟨ht hz, z, hz, rfl⟩ + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/RealIntervals.lean b/LeanPool/OneManifold/OneMfld/RealIntervals.lean deleted file mode 100644 index 686cf04782..0000000000 --- a/LeanPool/OneManifold/OneMfld/RealIntervals.lean +++ /dev/null @@ -1,511 +0,0 @@ -/- -Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Jim Fowler, Dennis Sweeney --/ -module - -public import Mathlib.Analysis.InnerProductSpace.Basic -public import Mathlib.Analysis.Normed.Module.RCLike.Real -public import Mathlib.Analysis.Normed.Order.Lattice -public import Mathlib.Order.CompletePartialOrder -public import Mathlib.Tactic - - -/-! -# RealIntervals - -Supporting results for the classification of compact one-dimensional manifolds. --/ - -@[expose] public section - -open Set - -namespace RealIntervals - --- Use the order topology on ℝ throughout -lemma ordconn_of_connected {X : Set ℝ} (conn : IsConnected X) - (a : ℝ) (aX : a ∈ X) (b : ℝ) (bX : b ∈ X) : Icc a b ⊆ X := by - have : OrdConnected X := - IsPreconnected.ordConnected (IsConnected.isPreconnected conn) - exact Set.Icc_subset X aX bX - --- Shouldn't this already be in mathlib? -lemma Real.exists_isGLB {S : Set ℝ} (hne : S.Nonempty) (hbdd : BddBelow S) - : ∃ x, IsGLB S x := by - exact ⟨sInf S, isGLB_csInf hne hbdd⟩ - --- classifying real intervals - --- Note: Much of what's below already exists in mathlib: --- Use IsPreconnected.mem_intervals --- and Real.instConditionallyCompleteLinearOrderReal - -lemma connected_bddAbove_subset_contains_Ioo {X : Set ℝ} {supX : ℝ} {x : ℝ} - (conn : IsConnected X) (h_supX : IsLUB X supX) (xX : x ∈ X) - : Ioo x supX ⊆ X := by - intro y ⟨x_lt_y, y_lt_supX⟩ - by_cases h: ∃ z ∈ X, y ≤ z - · rcases h with ⟨z, zX, y_le_z⟩ - have : Icc x z ⊆ X := ordconn_of_connected conn x xX z zX - exact this ⟨LT.lt.le x_lt_y, y_le_z⟩ - · push Not at h - have : y ∈ upperBounds X := fun z ↦ fun zX ↦ LT.lt.le (h z zX) - have : supX ≤ y := h_supX.2 this - linarith - -lemma connected_bddBelow_subset_contains_Ioo {X : Set ℝ} {infX : ℝ} {x : ℝ} - (conn : IsConnected X) (h_infX : IsGLB X infX) (xX : x ∈ X) - : Ioo infX x ⊆ X := by - intro y ⟨infX_lt_y, y_lt_x⟩ - by_cases h: ∃ z ∈ X, z ≤ y - · rcases h with ⟨z, zX, z_le_y⟩ - have : Icc z x ⊆ X := ordconn_of_connected conn z zX x xX - exact this ⟨z_le_y, LT.lt.le y_lt_x⟩ - · push Not at h - have : y ∈ lowerBounds X := fun z ↦ fun zX ↦ LT.lt.le (h z zX) - have : y ≤ infX := h_infX.2 this - linarith - -lemma connected_bdd_subset_contains_Ioo - {X : Set ℝ} {infX supX : ℝ} - (conn : IsConnected X) (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) - : Ioo infX supX ⊆ X := by - let ⟨z, zX⟩ := IsConnected.nonempty conn - have h₁ : Ioo infX z ⊆ X := connected_bddBelow_subset_contains_Ioo conn h_infX zX - have h₂ : Ioo z supX ⊆ X := connected_bddAbove_subset_contains_Ioo conn h_supX zX - have h₃ : Ioo infX supX ⊆ Ioo infX z ∪ {z} ∪ Ioo z supX := by - intro x ⟨infX_lt_x, x_lt_supX⟩ - rcases lt_trichotomy x z with (x_lt_z | x_eq_z | z_lt_z) - · left; left - exact ⟨infX_lt_x, x_lt_z⟩ - · left; right - rw [mem_singleton_iff, x_eq_z] - · right - exact ⟨z_lt_z, x_lt_supX⟩ - have h₄ : Ioo infX z ∪ {z} ∪ Ioo z supX ⊆ X := by - rintro x ((_ | x_eq_z) | _) - · apply h₁; assumption - · rw [mem_singleton_iff] at x_eq_z - rw [x_eq_z] - exact zX - · apply h₂; assumption - intro x x_Ioo - exact h₄ (h₃ x_Ioo) - -lemma bdd_subset_Icc - {X : Set ℝ} {infX supX : ℝ} - (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) - : X ⊆ Icc infX supX := by - intro x xX - exact ⟨h_infX.1 xX, h_supX.1 xX⟩ - -lemma x_lt_excluded_supX {x supX : ℝ} (xX : x ∈ X) - (h_supX : IsLUB X supX) (supX_X : supX ∉ X) : x < supX := by - have : x ≠ supX := by - intro x_eq_supX - rw [← x_eq_supX] at supX_X - contradiction - exact Ne.lt_of_le this (h_supX.1 xX) - -lemma excluded_infX_lt_x {x infX : ℝ} (xX : x ∈ X) - (h_infX : IsGLB X infX) (infX_X : infX ∉ X) : infX < x := by - have : infX ≠ x := by - intro x_eq_supX - rw [x_eq_supX] at infX_X - contradiction - exact Ne.lt_of_le this (h_infX.1 xX) - -lemma Ico_Ioo_with_endpoint {a b : ℝ} (hab : a < b) - : Ico a b = (Ioo a b) ∪ {a} := by - apply Subset.antisymm - · intro x ⟨x_le_a, x_lt_b⟩ - by_cases xa : x = a - · right; exact xa - · left; exact ⟨Ne.lt_of_le' xa x_le_a, x_lt_b⟩ - · rintro x (x_Ioo | x_a) - · exact ⟨LT.lt.le x_Ioo.1, x_Ioo.2⟩ - · exact ⟨Eq.ge x_a, Eq.trans_lt x_a hab⟩ - -lemma Ioc_Ioo_with_endpoint {a b : ℝ} (hab : a < b) - : Ioc a b = (Ioo a b) ∪ {b} := by - apply Subset.antisymm - · intro x ⟨a_lt_x, x_le_b⟩ - by_cases xb : x = b - · right; exact xb - have : x < b := Ne.lt_of_le xb x_le_b - left; exact ⟨a_lt_x, this⟩ - · rintro x (x_Ioo | x_b) - · exact ⟨x_Ioo.1, LT.lt.le x_Ioo.2⟩ - · exact ⟨(by rw [x_b]; exact hab), Eq.le x_b⟩ - -lemma characterize_Ioo {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} - (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) - (infX_X : infX ∉ X) (supX_X : supX ∉ X) - : X = Ioo infX supX := by - apply Subset.antisymm - · intro x xX - exact ⟨excluded_infX_lt_x xX h_infX infX_X, - x_lt_excluded_supX xX h_supX supX_X⟩ - · exact connected_bdd_subset_contains_Ioo conn h_infX h_supX - -lemma characterize_Ioc {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} - (inf_lt_sup : infX < supX) - (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) - (infX_X : infX ∉ X) (supX_X : supX ∈ X) - : X = Ioc infX supX := by - apply Subset.antisymm - · intro x xX - exact ⟨excluded_infX_lt_x xX h_infX infX_X, - h_supX.1 xX⟩ - · rw [Ioc_Ioo_with_endpoint inf_lt_sup, union_subset_iff] - exact ⟨connected_bdd_subset_contains_Ioo conn h_infX h_supX, - singleton_subset_iff.mpr supX_X⟩ - -lemma characterize_Ico {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} - (inf_lt_sup : infX < supX) - (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) - (infX_X : infX ∈ X) (supX_X : supX ∉ X) - : X = Ico infX supX := by - apply Subset.antisymm - · intro x xX - exact ⟨h_infX.1 xX, - x_lt_excluded_supX xX h_supX supX_X⟩ - · rw [Ico_Ioo_with_endpoint inf_lt_sup, union_subset_iff] - exact ⟨connected_bdd_subset_contains_Ioo conn h_infX h_supX, - singleton_subset_iff.mpr infX_X⟩ - -lemma characterize_Icc {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} - (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) - (infX_X : infX ∈ X) (supX_X : supX ∈ X) - : X = Icc infX supX := by - apply Subset.antisymm - · exact bdd_subset_Icc h_infX h_supX - · exact (ordconn_of_connected conn) infX infX_X supX supX_X - -lemma characterize_singleton {X : Set ℝ} {a : ℝ} - (h_infX : IsGLB X a) (h_supX : IsLUB X a) - : (X = {a}) := by - apply Subset.antisymm - · apply subset_trans (bdd_subset_Icc h_infX h_supX) - exact Set.Icc_subset {a} rfl rfl - · rw [singleton_subset_iff] - rcases IsLUB.nonempty h_supX with ⟨x, xX⟩ - have : a = x := LE.le.antisymm (h_infX.1 xX) (h_supX.1 xX) - exact mem_of_eq_of_mem (id this) xX - -/-- The four possibilities for including the two endpoints of a bounded interval. -/ -inductive BoundedIntervalKind | IooKind | IocKind | IcoKind | IccKind - -open BoundedIntervalKind - -/-- Two ordered real endpoints together with their inclusion convention. -/ -structure BoundedInterval where - /-- The left endpoint of the interval. -/ - leftEndpoint : ℝ - /-- The right endpoint of the interval. -/ - rightEndpoint : ℝ - left_lt_right : leftEndpoint < rightEndpoint - /-- Which endpoints belong to the interval. -/ - kind : BoundedIntervalKind - -/-- Interpret the interval's endpoints and inclusion convention as a set of reals. -/ -def BoundedIntervalAsSet : BoundedInterval → Set ℝ - | ⟨a, b, _, IooKind⟩ => Ioo a b - | ⟨a, b, _, IocKind⟩ => Ioc a b - | ⟨a, b, _, IcoKind⟩ => Ico a b - | ⟨a, b, _, IccKind⟩ => Icc a b - -/-- The set is a nondegenerate bounded interval with some endpoint convention. -/ -def isBoundedInterval (X : Set ℝ) := - ∃ I : BoundedInterval, X = BoundedIntervalAsSet I - -lemma isBoundedInterval_Ioo (a b : ℝ) (lt : a < b) : isBoundedInterval (Ioo a b) := by - use ⟨a, b, lt, IooKind⟩; simp only [BoundedIntervalAsSet] -lemma isBoundedInterval_Ioc (a b : ℝ) (lt : a < b) : isBoundedInterval (Ioc a b) := by - use ⟨a, b, lt, IocKind⟩; simp only [BoundedIntervalAsSet] -lemma isBoundedInterval_Ico (a b : ℝ) (lt : a < b) : isBoundedInterval (Ico a b) := by - use ⟨a, b, lt, IcoKind⟩; simp only [BoundedIntervalAsSet] -lemma isBoundedInterval_Icc (a b : ℝ) (lt : a < b) : isBoundedInterval (Icc a b) := by - use ⟨a, b, lt, IccKind⟩; simp only [BoundedIntervalAsSet] - -/-- The set consists of exactly one real number. -/ -def isSingleton (X : Set ℝ) := - ∃ a : ℝ, X = {a} - -lemma classify_connected_reals_with_GLB_lt_LUB - {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} - (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) (lt : infX < supX) - : isBoundedInterval X := by - by_cases infX_X : infX ∈ X - · by_cases supX_X : supX ∈ X - · use ⟨infX, supX, lt, IccKind⟩ - exact characterize_Icc conn h_infX h_supX infX_X supX_X - · use ⟨infX, supX, lt, IcoKind⟩ - exact characterize_Ico conn lt h_infX h_supX infX_X supX_X - · by_cases supX_X : supX ∈ X - · use ⟨infX, supX, lt, IocKind⟩ - exact characterize_Ioc conn lt h_infX h_supX infX_X supX_X - · use ⟨infX, supX, lt, IooKind⟩ - exact characterize_Ioo conn h_infX h_supX infX_X supX_X - -theorem classify_connected_bounded_reals - {X : Set ℝ} (conn : IsConnected X) (above : BddAbove X) (below : BddBelow X) - : isSingleton X ∨ isBoundedInterval X := by - have nonempty := IsConnected.nonempty conn - have ⟨supX, h_supX⟩ := Real.exists_isLUB nonempty above - have ⟨infX, h_infX⟩ := Real.exists_isGLB nonempty below - by_cases inf_eq_sup : infX = supX - · left; rw [isSingleton]; use infX - rw [← inf_eq_sup] at h_supX - apply characterize_singleton h_infX h_supX - · right - have : infX ≤ supX := isGLB_le_isLUB h_infX h_supX nonempty - have : infX < supX := Ne.lt_of_le inf_eq_sup this - exact classify_connected_reals_with_GLB_lt_LUB conn h_infX h_supX this - -theorem classify_connected_bounded_reals_nonempty_interior - {X : Set ℝ} (conn : IsConnected X) (above : BddAbove X) (below : BddBelow X) - (h : (interior X) ≠ ∅) - : isBoundedInterval X := by - rcases classify_connected_bounded_reals conn above below with ⟨a, ha⟩ | bdd - · rw [ha, interior_singleton] at h - exact (h rfl).elim - · exact bdd - --- Some lemmas about bounded intervals in ℝ - -lemma isConnected_BoundedInterval (I : BoundedInterval) - : IsConnected (BoundedIntervalAsSet I) := by - rw [BoundedIntervalAsSet.eq_def] - have ⟨a, b, lt, kind⟩ := I - match kind with - | IooKind => exact isConnected_Ioo lt - | IocKind => exact isConnected_Ioc lt - | IcoKind => exact isConnected_Ico lt - | IccKind => exact isConnected_Icc (LT.lt.le lt) - -lemma BoundedInterval_subset_Icc (I : BoundedInterval) - : BoundedIntervalAsSet I ⊆ Icc I.leftEndpoint I.rightEndpoint := by - have ⟨a, b, lt, kind⟩ := I - match kind with - | IooKind => exact Ioo_subset_Icc_self - | IocKind => exact Ioc_subset_Icc_self - | IcoKind => exact Ico_subset_Icc_self - | IccKind => exact Eq.subset rfl - -lemma BoundedInterval_contains_Ioo (I : BoundedInterval) - : Ioo I.leftEndpoint I.rightEndpoint ⊆ BoundedIntervalAsSet I := by - have ⟨a, b, lt, kind⟩ := I - match kind with - | IooKind => exact Eq.subset rfl - | IocKind => exact Ioo_subset_Ioc_self - | IcoKind => exact Ioo_subset_Ico_self - | IccKind => exact Ioo_subset_Icc_self - -lemma closure_BoundedInterval (I : BoundedInterval) : closure (BoundedIntervalAsSet I) = Icc - I.leftEndpoint I.rightEndpoint := by - apply Subset.antisymm - · calc closure (BoundedIntervalAsSet I) - ⊆ closure (Icc I.leftEndpoint I.rightEndpoint) - := closure_mono (BoundedInterval_subset_Icc I) - _ = Icc I.leftEndpoint I.rightEndpoint - := IsClosed.closure_eq isClosed_Icc - · calc Icc I.leftEndpoint I.rightEndpoint - = closure (Ioo I.leftEndpoint I.rightEndpoint) - := (closure_Ioo (ne_of_lt I.left_lt_right)).symm - _ ⊆ closure (BoundedIntervalAsSet I) - := closure_mono (BoundedInterval_contains_Ioo I) - -lemma isBoundedBelow_BoundedInterval (I : BoundedInterval) - : BddBelow (BoundedIntervalAsSet I) := - BddBelow.mono (BoundedInterval_subset_Icc I) bddBelow_Icc - -lemma isBoundedAbove_BoundedInterval (I : BoundedInterval) - : BddAbove (BoundedIntervalAsSet I) := - BddAbove.mono (BoundedInterval_subset_Icc I) bddAbove_Icc - -@[simp] -lemma interior_BoundedInterval (I : BoundedInterval) - : interior (BoundedIntervalAsSet I) = Ioo I.leftEndpoint I.rightEndpoint := by - rw [BoundedIntervalAsSet.eq_def] - have ⟨a, b, lt, kind⟩ := I - match kind with - | IooKind => dsimp; exact interior_Ioo - | IocKind => dsimp; exact interior_Ioc - | IcoKind => dsimp; exact interior_Ico - | IccKind => dsimp; exact interior_Icc - --- Shouldn't this already be in mathlib? -@[simp] -lemma Icc_diff_Ioo {a b : ℝ} (lt : a < b) : (Icc a b) \ (Ioo a b) = {a, b} := by - apply Subset.antisymm - · rw [← Icc_sdiff_both] - exact sdiff_sdiff_le - · rintro x (xleft | xright) - · rw [mem_sdiff, mem_Icc, mem_Ioo, not_and] - exact ⟨⟨by linarith, by linarith⟩, (by intro _; linarith)⟩ - · simp only [mem_singleton_iff] at xright - rw [xright] - simp only [mem_sdiff, mem_Icc, le_refl, and_true, mem_Ioo, lt_self_iff_false, and_false, - not_false_eq_true] - exact LT.lt.le lt - -@[simp] -lemma frontier_BoundedInterval (I : BoundedInterval) - : frontier (BoundedIntervalAsSet I) = {I.leftEndpoint, I.rightEndpoint} := by - rw [frontier, closure_BoundedInterval I, interior_BoundedInterval I] - exact Icc_diff_Ioo I.left_lt_right - -lemma pair_has_other {a b c : ℝ} (ne : a ≠ b) (h : c ∈ ({a, b} : Set ℝ)) - : ∃ (d : ℝ), d ∈ ({a, b} : Set ℝ) ∧ d ≠ c := by - simp only [mem_insert_iff, mem_singleton_iff, ne_eq, exists_eq_or_imp, exists_eq_left] - simp only [mem_insert_iff, mem_singleton_iff] at h - rcases h with ca | cb - · rw [← ca] at ne; right; exact ne.symm - · rw [← cb] at ne; left; exact ne - -theorem other_endpoint - {X : Set ℝ} (int : (interior X) ≠ ∅) - (conn : IsConnected X) (above : BddAbove X) (below : BddBelow X) - (a : ℝ) (ha : a ∈ frontier X) : ∃b : ℝ, b ∈ frontier X ∧ b ≠ a:= by - have ⟨I, XI⟩ := classify_connected_bounded_reals_nonempty_interior conn above below int - rw [XI, frontier_BoundedInterval] - rw [XI, frontier_BoundedInterval] at ha - have : I.leftEndpoint ≠ I.rightEndpoint := by - exact ne_of_lt I.left_lt_right - exact pair_has_other (ne_of_lt I.left_lt_right) ha - --- Continue to classify all connected sets in ℝ -lemma characterize_univ {X : Set ℝ} (conn : IsConnected X) - (below : ¬ BddBelow X) (above : ¬ BddAbove X) - : X = univ := by - rw [bddBelow_def] at below; push Not at below - rw [bddAbove_def] at above; push Not at above - ext x - simp only [mem_univ, iff_true] - have ⟨B, BX, Bbig⟩ := above x - have ⟨A, AX, Asmall⟩ := below x - have : Icc A B ⊆ X := (ordconn_of_connected conn) A AX B BX - exact this ⟨LT.lt.le Asmall, LT.lt.le Bbig⟩ - -lemma characterize_Ioi {X : Set ℝ} (conn : IsConnected X) - {infX : ℝ} (h_infX : IsGLB X infX) (infX_X : infX ∉ X) - (above : ¬ BddAbove X) : X = Ioi infX := by - rw [bddAbove_def] at above; push Not at above - apply Subset.antisymm - · intro x xX - exact excluded_infX_lt_x xX h_infX infX_X - · intro x infX_lt_x - rw [mem_Ioi] at infX_lt_x - let ⟨B, BX, Bbig⟩ := above x - have : Ioo infX B ⊆ X := - connected_bddBelow_subset_contains_Ioo conn h_infX BX - exact this ⟨infX_lt_x, Bbig⟩ - -lemma characterize_Ici {X : Set ℝ} (conn : IsConnected X) - {infX : ℝ} (h_infX : IsGLB X infX) (infX_X : infX ∈ X) - (above : ¬ BddAbove X) : X = Ici infX := by - rw [bddAbove_def] at above; push Not at above - apply Set.Subset.antisymm - · intro x xX - exact h_infX.1 xX - · intro x infX_le_x - have ⟨B, BX, Bbig⟩ := above x - have : Set.Icc infX B ⊆ X := (ordconn_of_connected conn) infX infX_X B BX - exact this ⟨infX_le_x, LT.lt.le Bbig⟩ - -lemma classify_Ixi {X : Set ℝ} (conn : IsConnected X) - (below : BddBelow X) (above : ¬ BddAbove X) - : ∃ a : ℝ, (X = Ioi a ∨ X = Ici a) := by - have ⟨infX, h_infX⟩ := Real.exists_isGLB (IsConnected.nonempty conn) below - use infX - by_cases infX_X : infX ∈ X - · right; exact characterize_Ici conn h_infX infX_X above - · left; exact characterize_Ioi conn h_infX infX_X above - -lemma characterize_Iio {X : Set ℝ} (conn : IsConnected X) - {supX : ℝ} (h_supX : IsLUB X supX) (supX_X : supX ∉ X) - (below : ¬ BddBelow X) : X = Iio supX := by - rw [bddBelow_def] at below; push Not at below - apply Set.Subset.antisymm - · intro x xX - exact x_lt_excluded_supX xX h_supX supX_X - · intro x x_lt_supX - rw [Set.mem_Iio] at x_lt_supX - let ⟨A, AX, Asmall⟩ := below x - have : Set.Ioo A supX ⊆ X := - connected_bddAbove_subset_contains_Ioo conn h_supX AX - exact this ⟨Asmall, x_lt_supX⟩ - -lemma characterize_Iic {X : Set ℝ} (conn : IsConnected X) - {supX : ℝ} (h_supX : IsLUB X supX) (supX_X : supX ∈ X) - (below : ¬ BddBelow X) : X = Iic supX := by - rw [bddBelow_def] at below; push Not at below - apply Set.Subset.antisymm - · intro x xX - exact h_supX.1 xX - · intro x x_le_supX - let ⟨A, AX, Asmall⟩ := below x - have : Set.Icc A supX ⊆ X := (ordconn_of_connected conn) A AX supX supX_X - exact this ⟨LT.lt.le Asmall, x_le_supX⟩ - -lemma classify_Iix {X : Set ℝ} (conn : IsConnected X) - (below : ¬ BddBelow X) (above : BddAbove X) - : ∃ a : ℝ, (X = Iio a ∨ X = Iic a) := by - have ⟨supX, h_supX⟩ := Real.exists_isLUB (IsConnected.nonempty conn) above - use supX - by_cases supX_X : supX ∈ X - · right; exact characterize_Iic conn h_supX supX_X below - · left; exact characterize_Iio conn h_supX supX_X below - --- Give names to the cases -/-- The possible forms of a nonempty connected subset of the real line. -/ -inductive ConnectedRealClassification - | of_univ : ConnectedRealClassification - | of_Iio : ℝ → ConnectedRealClassification - | of_Iic : ℝ → ConnectedRealClassification - | of_Ioi : ℝ → ConnectedRealClassification - | of_Ici : ℝ → ConnectedRealClassification - | of_singleton : ℝ → ConnectedRealClassification - | of_bounded_interval : BoundedInterval → ConnectedRealClassification - -open ConnectedRealClassification - -/-- Interpret a connected-set classification as a subset of the real line. -/ -def ConnectedRealClassificationAsSet : ConnectedRealClassification → Set ℝ - | of_univ => univ - | of_Iio a => Iio a - | of_Iic a => Iic a - | of_Ioi a => Ioi a - | of_Ici a => Ici a - | of_singleton a => {a} - | of_bounded_interval I => BoundedIntervalAsSet I - -/-- The set is represented by one of the connected real-set forms. -/ -def isConnectedRealClassification (X : Set ℝ) := - ∃ I : ConnectedRealClassification, X = ConnectedRealClassificationAsSet I - -theorem classify_connected_reals {X : Set ℝ} (conn : IsConnected X) - : isConnectedRealClassification X := by - by_cases below : BddBelow X - · by_cases above : BddAbove X - · rcases classify_connected_bounded_reals conn above below with sing | bdd - · let ⟨a, ha⟩ := sing - use of_singleton a; exact ha - · let ⟨I, hI⟩ := bdd - use of_bounded_interval I; exact hI - · rcases classify_Ixi conn below above with ⟨a, hIoi | hIci⟩ - · use of_Ioi a; exact hIoi - · use of_Ici a; exact hIci - · by_cases above : BddAbove X - · rcases classify_Iix conn below above with ⟨a, hIio | hIic⟩ - · use of_Iio a - exact hIio - · use of_Iic a - exact hIic - · use of_univ - exact characterize_univ conn below above - -end RealIntervals diff --git a/LeanPool/OneManifold/OneMfld/TransitionMono.lean b/LeanPool/OneManifold/OneMfld/TransitionMono.lean index fb592d9642..5a42658009 100644 --- a/LeanPool/OneManifold/OneMfld/TransitionMono.lean +++ b/LeanPool/OneManifold/OneMfld/TransitionMono.lean @@ -20,6 +20,8 @@ another sends ends to ends. @[expose] public section +namespace OneMfld + open Set Filter Topology /-- A continuous injective function on an open interval of `ℝ≥0` is strictly monotone or @@ -54,3 +56,5 @@ theorem tendsto_bot_of_strictMonoOn_image {p v q w : NNReal} (hpv : p < v) have hbdd : BddBelow (f '' Ioo p v) := himg ▸ bddBelow_Ioo have h := MonotoneOn.tendsto_nhdsWithin_Ioo_right hne hm.monotoneOn hbdd rwa [himg, csInf_Ioo hqw] at h + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/TwoComponents.lean b/LeanPool/OneManifold/OneMfld/TwoComponents.lean index 5a1bb24b6f..9424a0714d 100644 --- a/LeanPool/OneManifold/OneMfld/TwoComponents.lean +++ b/LeanPool/OneManifold/OneMfld/TwoComponents.lean @@ -22,6 +22,8 @@ interior endpoint is not in the image of the *full* overlap. @[expose] public section +namespace OneMfld + open Set Filter Topology /-- A strictly antitone map of `Ioo p v` onto `Ioo q w` tends to `w` at the bottom end. -/ @@ -446,3 +448,5 @@ theorem two_components_other_chart [T2Space M] (a b : OpenPartialHomeomorph M NN obtain ⟨t, ht1, ht2⟩ := exists_between (lt_min hs₀0 hs₁0) exact hcommon t (hbW₀ ▸ mem_Ioo.mpr ⟨ht1, ht2.trans_le (min_le_left _ _)⟩) (hbW₁ ▸ mem_Ioo.mpr ⟨ht1, ht2.trans_le (min_le_right _ _)⟩) + +end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/UnitInterval.lean b/LeanPool/OneManifold/OneMfld/UnitInterval.lean index 52b30739c5..294796eb6f 100644 --- a/LeanPool/OneManifold/OneMfld/UnitInterval.lean +++ b/LeanPool/OneManifold/OneMfld/UnitInterval.lean @@ -18,6 +18,8 @@ Supporting results for the classification of compact one-dimensional manifolds. @[expose] public section +namespace OneMfld + /-- The closed unit interval in the real line. -/ def UnitInterval : Set Real := { x : Real | 0 ≤ x ∧ x ≤ 1 } @@ -34,3 +36,5 @@ instance : CompactSpace UnitInterval := instance : Nonempty UnitInterval := ⟨⟨0, le_refl 0, zero_le_one⟩⟩ + +end OneMfld diff --git a/LeanPool/OneManifold/Solution.lean b/LeanPool/OneManifold/Solution.lean index d2241cfa1f..da5418177a 100644 --- a/LeanPool/OneManifold/Solution.lean +++ b/LeanPool/OneManifold/Solution.lean @@ -11,8 +11,8 @@ public import LeanPool.OneManifold.OneMfld.Classification /-! # Proved solution -This module imports the full proof development and restates the Challenge -theorem with the identical name and type. The library's `classification` +This module imports the full proof development and restates the upstream Challenge +theorem with the identical name and type. The library's `OneMfld.classification` (in `OneMfld/Classification.lean`) produces the homeomorphism as data, as a term of `(M ≃ₜ Circle) ⊕ (M ≃ₜ UnitInterval)`; here we only need the Prop-level disjunction. The Challenge's `{x : ℝ // 0 ≤ x ∧ x ≤ 1}` is @@ -21,10 +21,14 @@ definitionally `↥OneMfld.UnitInterval` (and Mathlib's `↥unitInterval`). @[expose] public section -theorem OneMfld.homeomorph_circle_or_unitInterval +namespace OneMfld + +theorem homeomorph_circle_or_unitInterval (M : Type*) [TopologicalSpace M] [CompactSpace M] [ConnectedSpace M] [T2Space M] [ChartedSpace NNReal M] : Nonempty (M ≃ₜ Circle) ∨ Nonempty (M ≃ₜ {x : ℝ // 0 ≤ x ∧ x ≤ 1}) := by rcases classification (M := M) ‹ChartedSpace NNReal M› with e | e · exact Or.inl ⟨e⟩ · exact Or.inr ⟨e⟩ + +end OneMfld From a07a240ea4dbf69883493c2e3d462303e026acbb Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Fri, 25 Sep 2026 19:32:18 +0000 Subject: [PATCH 06/16] Qualify namespaced partial-homeomorphism helpers --- LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean b/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean index 3b3117e7c2..6e98e63003 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean @@ -321,7 +321,7 @@ noncomputable def handleHH (a : HChart M) (b : HChart M) (h : Overlap a.source b have hne : φ.source.Nonempty := by rw [hφ] exact Set.Nonempty.inl (h.1.mono Set.inter_subset_left) - exact φ.toHomeomorphOfCompactTarget hne hs + exact OneMfld.OpenPartialHomeomorph.toHomeomorphOfCompactTarget φ hne hs omit [ConnectedSpace M] in /-- An O-chart and an H-chart with connected overlap glue to an H-chart on the union: @@ -457,7 +457,7 @@ noncomputable def circleOfDisconnectedOverlap (a : OChart M) (b : OChart M) have hne : f'.source.Nonempty := by rw [hfs'] exact Set.Nonempty.inl (h.1.mono Set.inter_subset_left) - exact f'.toHomeomorphOfCompactTarget hne hft' + exact OneMfld.OpenPartialHomeomorph.toHomeomorphOfCompactTarget f' hne hft' /-- Glue two O-charts: with a connected overlap they merge into an O-chart on the union; with a disconnected overlap, `M` is a circle. -/ From 83cb928262cc40232304be4d1c52c9a658831530 Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Fri, 25 Sep 2026 19:38:45 +0000 Subject: [PATCH 07/16] Trim the one-manifold import index whitespace --- LeanPool/OneManifold/OneMfld.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/LeanPool/OneManifold/OneMfld.lean b/LeanPool/OneManifold/OneMfld.lean index 73539efeb5..b565116056 100644 --- a/LeanPool/OneManifold/OneMfld.lean +++ b/LeanPool/OneManifold/OneMfld.lean @@ -6,4 +6,3 @@ Authors: Jim Fowler, Dennis Sweeney module public import LeanPool.OneManifold.OneMfld.Classification - From 66db25f61574f5513bcaf74841544f5d06828b05 Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Fri, 25 Sep 2026 19:58:03 +0000 Subject: [PATCH 08/16] Preserve complete real-interval results in the one-manifold namespace --- LeanPool/OneManifold.lean | 1 + LeanPool/OneManifold/OneMfld.lean | 1 + .../OneManifold/OneMfld/RealIntervals.lean | 515 ++++++++++++++++++ 3 files changed, 517 insertions(+) create mode 100644 LeanPool/OneManifold/OneMfld/RealIntervals.lean diff --git a/LeanPool/OneManifold.lean b/LeanPool/OneManifold.lean index ed8031c040..88574478ca 100644 --- a/LeanPool/OneManifold.lean +++ b/LeanPool/OneManifold.lean @@ -28,6 +28,7 @@ public import LeanPool.OneManifold.OneMfld.Noncompact public import LeanPool.OneManifold.OneMfld.Normalize public import LeanPool.OneManifold.OneMfld.Outer public import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers +public import LeanPool.OneManifold.OneMfld.RealIntervals public import LeanPool.OneManifold.OneMfld.TransitionMono public import LeanPool.OneManifold.OneMfld.TwoComponents public import LeanPool.OneManifold.OneMfld.UnitInterval diff --git a/LeanPool/OneManifold/OneMfld.lean b/LeanPool/OneManifold/OneMfld.lean index b565116056..21014042f8 100644 --- a/LeanPool/OneManifold/OneMfld.lean +++ b/LeanPool/OneManifold/OneMfld.lean @@ -6,3 +6,4 @@ Authors: Jim Fowler, Dennis Sweeney module public import LeanPool.OneManifold.OneMfld.Classification +public import LeanPool.OneManifold.OneMfld.RealIntervals diff --git a/LeanPool/OneManifold/OneMfld/RealIntervals.lean b/LeanPool/OneManifold/OneMfld/RealIntervals.lean new file mode 100644 index 0000000000..f7aa1a4966 --- /dev/null +++ b/LeanPool/OneManifold/OneMfld/RealIntervals.lean @@ -0,0 +1,515 @@ +/- +Copyright (c) 2026 Jim Fowler, Dennis Sweeney. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jim Fowler, Dennis Sweeney +-/ +module + +public import Mathlib.Analysis.InnerProductSpace.Basic +public import Mathlib.Analysis.Normed.Module.RCLike.Real +public import Mathlib.Analysis.Normed.Order.Lattice +public import Mathlib.Order.CompletePartialOrder +public import Mathlib.Tactic + + +/-! +# RealIntervals + +Supporting results for the classification of compact one-dimensional manifolds. +-/ + +@[expose] public section + +namespace OneMfld + +open Set + +namespace RealIntervals + +-- Use the order topology on ℝ throughout +lemma ordconn_of_connected {X : Set ℝ} (conn : IsConnected X) + (a : ℝ) (aX : a ∈ X) (b : ℝ) (bX : b ∈ X) : Icc a b ⊆ X := by + have : OrdConnected X := + IsPreconnected.ordConnected (IsConnected.isPreconnected conn) + exact Set.Icc_subset X aX bX + +-- Shouldn't this already be in mathlib? +lemma Real.exists_isGLB {S : Set ℝ} (hne : S.Nonempty) (hbdd : BddBelow S) + : ∃ x, IsGLB S x := by + exact ⟨sInf S, isGLB_csInf hne hbdd⟩ + +-- classifying real intervals + +-- Note: Much of what's below already exists in mathlib: +-- Use IsPreconnected.mem_intervals +-- and Real.instConditionallyCompleteLinearOrderReal + +lemma connected_bddAbove_subset_contains_Ioo {X : Set ℝ} {supX : ℝ} {x : ℝ} + (conn : IsConnected X) (h_supX : IsLUB X supX) (xX : x ∈ X) + : Ioo x supX ⊆ X := by + intro y ⟨x_lt_y, y_lt_supX⟩ + by_cases h: ∃ z ∈ X, y ≤ z + · rcases h with ⟨z, zX, y_le_z⟩ + have : Icc x z ⊆ X := ordconn_of_connected conn x xX z zX + exact this ⟨LT.lt.le x_lt_y, y_le_z⟩ + · push Not at h + have : y ∈ upperBounds X := fun z ↦ fun zX ↦ LT.lt.le (h z zX) + have : supX ≤ y := h_supX.2 this + linarith + +lemma connected_bddBelow_subset_contains_Ioo {X : Set ℝ} {infX : ℝ} {x : ℝ} + (conn : IsConnected X) (h_infX : IsGLB X infX) (xX : x ∈ X) + : Ioo infX x ⊆ X := by + intro y ⟨infX_lt_y, y_lt_x⟩ + by_cases h: ∃ z ∈ X, z ≤ y + · rcases h with ⟨z, zX, z_le_y⟩ + have : Icc z x ⊆ X := ordconn_of_connected conn z zX x xX + exact this ⟨z_le_y, LT.lt.le y_lt_x⟩ + · push Not at h + have : y ∈ lowerBounds X := fun z ↦ fun zX ↦ LT.lt.le (h z zX) + have : y ≤ infX := h_infX.2 this + linarith + +lemma connected_bdd_subset_contains_Ioo + {X : Set ℝ} {infX supX : ℝ} + (conn : IsConnected X) (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) + : Ioo infX supX ⊆ X := by + let ⟨z, zX⟩ := IsConnected.nonempty conn + have h₁ : Ioo infX z ⊆ X := connected_bddBelow_subset_contains_Ioo conn h_infX zX + have h₂ : Ioo z supX ⊆ X := connected_bddAbove_subset_contains_Ioo conn h_supX zX + have h₃ : Ioo infX supX ⊆ Ioo infX z ∪ {z} ∪ Ioo z supX := by + intro x ⟨infX_lt_x, x_lt_supX⟩ + rcases lt_trichotomy x z with (x_lt_z | x_eq_z | z_lt_z) + · left; left + exact ⟨infX_lt_x, x_lt_z⟩ + · left; right + rw [mem_singleton_iff, x_eq_z] + · right + exact ⟨z_lt_z, x_lt_supX⟩ + have h₄ : Ioo infX z ∪ {z} ∪ Ioo z supX ⊆ X := by + rintro x ((_ | x_eq_z) | _) + · apply h₁; assumption + · rw [mem_singleton_iff] at x_eq_z + rw [x_eq_z] + exact zX + · apply h₂; assumption + intro x x_Ioo + exact h₄ (h₃ x_Ioo) + +lemma bdd_subset_Icc + {X : Set ℝ} {infX supX : ℝ} + (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) + : X ⊆ Icc infX supX := by + intro x xX + exact ⟨h_infX.1 xX, h_supX.1 xX⟩ + +lemma x_lt_excluded_supX {x supX : ℝ} (xX : x ∈ X) + (h_supX : IsLUB X supX) (supX_X : supX ∉ X) : x < supX := by + have : x ≠ supX := by + intro x_eq_supX + rw [← x_eq_supX] at supX_X + contradiction + exact Ne.lt_of_le this (h_supX.1 xX) + +lemma excluded_infX_lt_x {x infX : ℝ} (xX : x ∈ X) + (h_infX : IsGLB X infX) (infX_X : infX ∉ X) : infX < x := by + have : infX ≠ x := by + intro x_eq_supX + rw [x_eq_supX] at infX_X + contradiction + exact Ne.lt_of_le this (h_infX.1 xX) + +lemma Ico_Ioo_with_endpoint {a b : ℝ} (hab : a < b) + : Ico a b = (Ioo a b) ∪ {a} := by + apply Subset.antisymm + · intro x ⟨x_le_a, x_lt_b⟩ + by_cases xa : x = a + · right; exact xa + · left; exact ⟨Ne.lt_of_le' xa x_le_a, x_lt_b⟩ + · rintro x (x_Ioo | x_a) + · exact ⟨LT.lt.le x_Ioo.1, x_Ioo.2⟩ + · exact ⟨Eq.ge x_a, Eq.trans_lt x_a hab⟩ + +lemma Ioc_Ioo_with_endpoint {a b : ℝ} (hab : a < b) + : Ioc a b = (Ioo a b) ∪ {b} := by + apply Subset.antisymm + · intro x ⟨a_lt_x, x_le_b⟩ + by_cases xb : x = b + · right; exact xb + have : x < b := Ne.lt_of_le xb x_le_b + left; exact ⟨a_lt_x, this⟩ + · rintro x (x_Ioo | x_b) + · exact ⟨x_Ioo.1, LT.lt.le x_Ioo.2⟩ + · exact ⟨(by rw [x_b]; exact hab), Eq.le x_b⟩ + +lemma characterize_Ioo {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} + (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) + (infX_X : infX ∉ X) (supX_X : supX ∉ X) + : X = Ioo infX supX := by + apply Subset.antisymm + · intro x xX + exact ⟨excluded_infX_lt_x xX h_infX infX_X, + x_lt_excluded_supX xX h_supX supX_X⟩ + · exact connected_bdd_subset_contains_Ioo conn h_infX h_supX + +lemma characterize_Ioc {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} + (inf_lt_sup : infX < supX) + (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) + (infX_X : infX ∉ X) (supX_X : supX ∈ X) + : X = Ioc infX supX := by + apply Subset.antisymm + · intro x xX + exact ⟨excluded_infX_lt_x xX h_infX infX_X, + h_supX.1 xX⟩ + · rw [Ioc_Ioo_with_endpoint inf_lt_sup, union_subset_iff] + exact ⟨connected_bdd_subset_contains_Ioo conn h_infX h_supX, + singleton_subset_iff.mpr supX_X⟩ + +lemma characterize_Ico {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} + (inf_lt_sup : infX < supX) + (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) + (infX_X : infX ∈ X) (supX_X : supX ∉ X) + : X = Ico infX supX := by + apply Subset.antisymm + · intro x xX + exact ⟨h_infX.1 xX, + x_lt_excluded_supX xX h_supX supX_X⟩ + · rw [Ico_Ioo_with_endpoint inf_lt_sup, union_subset_iff] + exact ⟨connected_bdd_subset_contains_Ioo conn h_infX h_supX, + singleton_subset_iff.mpr infX_X⟩ + +lemma characterize_Icc {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} + (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) + (infX_X : infX ∈ X) (supX_X : supX ∈ X) + : X = Icc infX supX := by + apply Subset.antisymm + · exact bdd_subset_Icc h_infX h_supX + · exact (ordconn_of_connected conn) infX infX_X supX supX_X + +lemma characterize_singleton {X : Set ℝ} {a : ℝ} + (h_infX : IsGLB X a) (h_supX : IsLUB X a) + : (X = {a}) := by + apply Subset.antisymm + · apply subset_trans (bdd_subset_Icc h_infX h_supX) + exact Set.Icc_subset {a} rfl rfl + · rw [singleton_subset_iff] + rcases IsLUB.nonempty h_supX with ⟨x, xX⟩ + have : a = x := LE.le.antisymm (h_infX.1 xX) (h_supX.1 xX) + exact mem_of_eq_of_mem (id this) xX + +/-- The four possibilities for including the two endpoints of a bounded interval. -/ +inductive BoundedIntervalKind | IooKind | IocKind | IcoKind | IccKind + +open BoundedIntervalKind + +/-- Two ordered real endpoints together with their inclusion convention. -/ +structure BoundedInterval where + /-- The left endpoint of the interval. -/ + leftEndpoint : ℝ + /-- The right endpoint of the interval. -/ + rightEndpoint : ℝ + left_lt_right : leftEndpoint < rightEndpoint + /-- Which endpoints belong to the interval. -/ + kind : BoundedIntervalKind + +/-- Interpret the interval's endpoints and inclusion convention as a set of reals. -/ +def BoundedIntervalAsSet : BoundedInterval → Set ℝ + | ⟨a, b, _, IooKind⟩ => Ioo a b + | ⟨a, b, _, IocKind⟩ => Ioc a b + | ⟨a, b, _, IcoKind⟩ => Ico a b + | ⟨a, b, _, IccKind⟩ => Icc a b + +/-- The set is a nondegenerate bounded interval with some endpoint convention. -/ +def isBoundedInterval (X : Set ℝ) := + ∃ I : BoundedInterval, X = BoundedIntervalAsSet I + +lemma isBoundedInterval_Ioo (a b : ℝ) (lt : a < b) : isBoundedInterval (Ioo a b) := by + use ⟨a, b, lt, IooKind⟩; simp only [BoundedIntervalAsSet] +lemma isBoundedInterval_Ioc (a b : ℝ) (lt : a < b) : isBoundedInterval (Ioc a b) := by + use ⟨a, b, lt, IocKind⟩; simp only [BoundedIntervalAsSet] +lemma isBoundedInterval_Ico (a b : ℝ) (lt : a < b) : isBoundedInterval (Ico a b) := by + use ⟨a, b, lt, IcoKind⟩; simp only [BoundedIntervalAsSet] +lemma isBoundedInterval_Icc (a b : ℝ) (lt : a < b) : isBoundedInterval (Icc a b) := by + use ⟨a, b, lt, IccKind⟩; simp only [BoundedIntervalAsSet] + +/-- The set consists of exactly one real number. -/ +def isSingleton (X : Set ℝ) := + ∃ a : ℝ, X = {a} + +lemma classify_connected_reals_with_GLB_lt_LUB + {X : Set ℝ} (conn : IsConnected X) {infX supX : ℝ} + (h_infX : IsGLB X infX) (h_supX : IsLUB X supX) (lt : infX < supX) + : isBoundedInterval X := by + by_cases infX_X : infX ∈ X + · by_cases supX_X : supX ∈ X + · use ⟨infX, supX, lt, IccKind⟩ + exact characterize_Icc conn h_infX h_supX infX_X supX_X + · use ⟨infX, supX, lt, IcoKind⟩ + exact characterize_Ico conn lt h_infX h_supX infX_X supX_X + · by_cases supX_X : supX ∈ X + · use ⟨infX, supX, lt, IocKind⟩ + exact characterize_Ioc conn lt h_infX h_supX infX_X supX_X + · use ⟨infX, supX, lt, IooKind⟩ + exact characterize_Ioo conn h_infX h_supX infX_X supX_X + +theorem classify_connected_bounded_reals + {X : Set ℝ} (conn : IsConnected X) (above : BddAbove X) (below : BddBelow X) + : isSingleton X ∨ isBoundedInterval X := by + have nonempty := IsConnected.nonempty conn + have ⟨supX, h_supX⟩ := Real.exists_isLUB nonempty above + have ⟨infX, h_infX⟩ := Real.exists_isGLB nonempty below + by_cases inf_eq_sup : infX = supX + · left; rw [isSingleton]; use infX + rw [← inf_eq_sup] at h_supX + apply characterize_singleton h_infX h_supX + · right + have : infX ≤ supX := isGLB_le_isLUB h_infX h_supX nonempty + have : infX < supX := Ne.lt_of_le inf_eq_sup this + exact classify_connected_reals_with_GLB_lt_LUB conn h_infX h_supX this + +theorem classify_connected_bounded_reals_nonempty_interior + {X : Set ℝ} (conn : IsConnected X) (above : BddAbove X) (below : BddBelow X) + (h : (interior X) ≠ ∅) + : isBoundedInterval X := by + rcases classify_connected_bounded_reals conn above below with ⟨a, ha⟩ | bdd + · rw [ha, interior_singleton] at h + exact (h rfl).elim + · exact bdd + +-- Some lemmas about bounded intervals in ℝ + +lemma isConnected_BoundedInterval (I : BoundedInterval) + : IsConnected (BoundedIntervalAsSet I) := by + rw [BoundedIntervalAsSet.eq_def] + have ⟨a, b, lt, kind⟩ := I + match kind with + | IooKind => exact isConnected_Ioo lt + | IocKind => exact isConnected_Ioc lt + | IcoKind => exact isConnected_Ico lt + | IccKind => exact isConnected_Icc (LT.lt.le lt) + +lemma BoundedInterval_subset_Icc (I : BoundedInterval) + : BoundedIntervalAsSet I ⊆ Icc I.leftEndpoint I.rightEndpoint := by + have ⟨a, b, lt, kind⟩ := I + match kind with + | IooKind => exact Ioo_subset_Icc_self + | IocKind => exact Ioc_subset_Icc_self + | IcoKind => exact Ico_subset_Icc_self + | IccKind => exact Eq.subset rfl + +lemma BoundedInterval_contains_Ioo (I : BoundedInterval) + : Ioo I.leftEndpoint I.rightEndpoint ⊆ BoundedIntervalAsSet I := by + have ⟨a, b, lt, kind⟩ := I + match kind with + | IooKind => exact Eq.subset rfl + | IocKind => exact Ioo_subset_Ioc_self + | IcoKind => exact Ioo_subset_Ico_self + | IccKind => exact Ioo_subset_Icc_self + +lemma closure_BoundedInterval (I : BoundedInterval) : closure (BoundedIntervalAsSet I) = Icc + I.leftEndpoint I.rightEndpoint := by + apply Subset.antisymm + · calc closure (BoundedIntervalAsSet I) + ⊆ closure (Icc I.leftEndpoint I.rightEndpoint) + := closure_mono (BoundedInterval_subset_Icc I) + _ = Icc I.leftEndpoint I.rightEndpoint + := IsClosed.closure_eq isClosed_Icc + · calc Icc I.leftEndpoint I.rightEndpoint + = closure (Ioo I.leftEndpoint I.rightEndpoint) + := (closure_Ioo (ne_of_lt I.left_lt_right)).symm + _ ⊆ closure (BoundedIntervalAsSet I) + := closure_mono (BoundedInterval_contains_Ioo I) + +lemma isBoundedBelow_BoundedInterval (I : BoundedInterval) + : BddBelow (BoundedIntervalAsSet I) := + BddBelow.mono (BoundedInterval_subset_Icc I) bddBelow_Icc + +lemma isBoundedAbove_BoundedInterval (I : BoundedInterval) + : BddAbove (BoundedIntervalAsSet I) := + BddAbove.mono (BoundedInterval_subset_Icc I) bddAbove_Icc + +@[simp] +lemma interior_BoundedInterval (I : BoundedInterval) + : interior (BoundedIntervalAsSet I) = Ioo I.leftEndpoint I.rightEndpoint := by + rw [BoundedIntervalAsSet.eq_def] + have ⟨a, b, lt, kind⟩ := I + match kind with + | IooKind => dsimp; exact interior_Ioo + | IocKind => dsimp; exact interior_Ioc + | IcoKind => dsimp; exact interior_Ico + | IccKind => dsimp; exact interior_Icc + +-- Shouldn't this already be in mathlib? +@[simp] +lemma Icc_diff_Ioo {a b : ℝ} (lt : a < b) : (Icc a b) \ (Ioo a b) = {a, b} := by + apply Subset.antisymm + · rw [← Icc_sdiff_both] + exact sdiff_sdiff_le + · rintro x (xleft | xright) + · rw [mem_sdiff, mem_Icc, mem_Ioo, not_and] + exact ⟨⟨by linarith, by linarith⟩, (by intro _; linarith)⟩ + · simp only [mem_singleton_iff] at xright + rw [xright] + simp only [mem_sdiff, mem_Icc, le_refl, and_true, mem_Ioo, lt_self_iff_false, and_false, + not_false_eq_true] + exact LT.lt.le lt + +@[simp] +lemma frontier_BoundedInterval (I : BoundedInterval) + : frontier (BoundedIntervalAsSet I) = {I.leftEndpoint, I.rightEndpoint} := by + rw [frontier, closure_BoundedInterval I, interior_BoundedInterval I] + exact Icc_diff_Ioo I.left_lt_right + +lemma pair_has_other {a b c : ℝ} (ne : a ≠ b) (h : c ∈ ({a, b} : Set ℝ)) + : ∃ (d : ℝ), d ∈ ({a, b} : Set ℝ) ∧ d ≠ c := by + simp only [mem_insert_iff, mem_singleton_iff, ne_eq, exists_eq_or_imp, exists_eq_left] + simp only [mem_insert_iff, mem_singleton_iff] at h + rcases h with ca | cb + · rw [← ca] at ne; right; exact ne.symm + · rw [← cb] at ne; left; exact ne + +theorem other_endpoint + {X : Set ℝ} (int : (interior X) ≠ ∅) + (conn : IsConnected X) (above : BddAbove X) (below : BddBelow X) + (a : ℝ) (ha : a ∈ frontier X) : ∃b : ℝ, b ∈ frontier X ∧ b ≠ a:= by + have ⟨I, XI⟩ := classify_connected_bounded_reals_nonempty_interior conn above below int + rw [XI, frontier_BoundedInterval] + rw [XI, frontier_BoundedInterval] at ha + have : I.leftEndpoint ≠ I.rightEndpoint := by + exact ne_of_lt I.left_lt_right + exact pair_has_other (ne_of_lt I.left_lt_right) ha + +-- Continue to classify all connected sets in ℝ +lemma characterize_univ {X : Set ℝ} (conn : IsConnected X) + (below : ¬ BddBelow X) (above : ¬ BddAbove X) + : X = univ := by + rw [bddBelow_def] at below; push Not at below + rw [bddAbove_def] at above; push Not at above + ext x + simp only [mem_univ, iff_true] + have ⟨B, BX, Bbig⟩ := above x + have ⟨A, AX, Asmall⟩ := below x + have : Icc A B ⊆ X := (ordconn_of_connected conn) A AX B BX + exact this ⟨LT.lt.le Asmall, LT.lt.le Bbig⟩ + +lemma characterize_Ioi {X : Set ℝ} (conn : IsConnected X) + {infX : ℝ} (h_infX : IsGLB X infX) (infX_X : infX ∉ X) + (above : ¬ BddAbove X) : X = Ioi infX := by + rw [bddAbove_def] at above; push Not at above + apply Subset.antisymm + · intro x xX + exact excluded_infX_lt_x xX h_infX infX_X + · intro x infX_lt_x + rw [mem_Ioi] at infX_lt_x + let ⟨B, BX, Bbig⟩ := above x + have : Ioo infX B ⊆ X := + connected_bddBelow_subset_contains_Ioo conn h_infX BX + exact this ⟨infX_lt_x, Bbig⟩ + +lemma characterize_Ici {X : Set ℝ} (conn : IsConnected X) + {infX : ℝ} (h_infX : IsGLB X infX) (infX_X : infX ∈ X) + (above : ¬ BddAbove X) : X = Ici infX := by + rw [bddAbove_def] at above; push Not at above + apply Set.Subset.antisymm + · intro x xX + exact h_infX.1 xX + · intro x infX_le_x + have ⟨B, BX, Bbig⟩ := above x + have : Set.Icc infX B ⊆ X := (ordconn_of_connected conn) infX infX_X B BX + exact this ⟨infX_le_x, LT.lt.le Bbig⟩ + +lemma classify_Ixi {X : Set ℝ} (conn : IsConnected X) + (below : BddBelow X) (above : ¬ BddAbove X) + : ∃ a : ℝ, (X = Ioi a ∨ X = Ici a) := by + have ⟨infX, h_infX⟩ := Real.exists_isGLB (IsConnected.nonempty conn) below + use infX + by_cases infX_X : infX ∈ X + · right; exact characterize_Ici conn h_infX infX_X above + · left; exact characterize_Ioi conn h_infX infX_X above + +lemma characterize_Iio {X : Set ℝ} (conn : IsConnected X) + {supX : ℝ} (h_supX : IsLUB X supX) (supX_X : supX ∉ X) + (below : ¬ BddBelow X) : X = Iio supX := by + rw [bddBelow_def] at below; push Not at below + apply Set.Subset.antisymm + · intro x xX + exact x_lt_excluded_supX xX h_supX supX_X + · intro x x_lt_supX + rw [Set.mem_Iio] at x_lt_supX + let ⟨A, AX, Asmall⟩ := below x + have : Set.Ioo A supX ⊆ X := + connected_bddAbove_subset_contains_Ioo conn h_supX AX + exact this ⟨Asmall, x_lt_supX⟩ + +lemma characterize_Iic {X : Set ℝ} (conn : IsConnected X) + {supX : ℝ} (h_supX : IsLUB X supX) (supX_X : supX ∈ X) + (below : ¬ BddBelow X) : X = Iic supX := by + rw [bddBelow_def] at below; push Not at below + apply Set.Subset.antisymm + · intro x xX + exact h_supX.1 xX + · intro x x_le_supX + let ⟨A, AX, Asmall⟩ := below x + have : Set.Icc A supX ⊆ X := (ordconn_of_connected conn) A AX supX supX_X + exact this ⟨LT.lt.le Asmall, x_le_supX⟩ + +lemma classify_Iix {X : Set ℝ} (conn : IsConnected X) + (below : ¬ BddBelow X) (above : BddAbove X) + : ∃ a : ℝ, (X = Iio a ∨ X = Iic a) := by + have ⟨supX, h_supX⟩ := Real.exists_isLUB (IsConnected.nonempty conn) above + use supX + by_cases supX_X : supX ∈ X + · right; exact characterize_Iic conn h_supX supX_X below + · left; exact characterize_Iio conn h_supX supX_X below + +-- Give names to the cases +/-- The possible forms of a nonempty connected subset of the real line. -/ +inductive ConnectedRealClassification + | of_univ : ConnectedRealClassification + | of_Iio : ℝ → ConnectedRealClassification + | of_Iic : ℝ → ConnectedRealClassification + | of_Ioi : ℝ → ConnectedRealClassification + | of_Ici : ℝ → ConnectedRealClassification + | of_singleton : ℝ → ConnectedRealClassification + | of_bounded_interval : BoundedInterval → ConnectedRealClassification + +open ConnectedRealClassification + +/-- Interpret a connected-set classification as a subset of the real line. -/ +def ConnectedRealClassificationAsSet : ConnectedRealClassification → Set ℝ + | of_univ => univ + | of_Iio a => Iio a + | of_Iic a => Iic a + | of_Ioi a => Ioi a + | of_Ici a => Ici a + | of_singleton a => {a} + | of_bounded_interval I => BoundedIntervalAsSet I + +/-- The set is represented by one of the connected real-set forms. -/ +def isConnectedRealClassification (X : Set ℝ) := + ∃ I : ConnectedRealClassification, X = ConnectedRealClassificationAsSet I + +theorem classify_connected_reals {X : Set ℝ} (conn : IsConnected X) + : isConnectedRealClassification X := by + by_cases below : BddBelow X + · by_cases above : BddAbove X + · rcases classify_connected_bounded_reals conn above below with sing | bdd + · let ⟨a, ha⟩ := sing + use of_singleton a; exact ha + · let ⟨I, hI⟩ := bdd + use of_bounded_interval I; exact hI + · rcases classify_Ixi conn below above with ⟨a, hIoi | hIci⟩ + · use of_Ioi a; exact hIoi + · use of_Ici a; exact hIci + · by_cases above : BddAbove X + · rcases classify_Iix conn below above with ⟨a, hIio | hIic⟩ + · use of_Iio a + exact hIio + · use of_Iic a + exact hIic + · use of_univ + exact characterize_univ conn below above + +end RealIntervals + +end OneMfld From 50bc0d1f9ae1cdcda81cc83d8e5daf2121aac9d0 Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Fri, 25 Sep 2026 20:23:00 +0000 Subject: [PATCH 09/16] Index the restored real-interval module --- LeanPool.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/LeanPool.lean b/LeanPool.lean index 6a5f0cac2d..fe5a8c489d 100644 --- a/LeanPool.lean +++ b/LeanPool.lean @@ -6578,6 +6578,7 @@ public import LeanPool.OneManifold.OneMfld.Noncompact public import LeanPool.OneManifold.OneMfld.Normalize public import LeanPool.OneManifold.OneMfld.Outer public import LeanPool.OneManifold.OneMfld.PartialHomeomorphHelpers +public import LeanPool.OneManifold.OneMfld.RealIntervals public import LeanPool.OneManifold.OneMfld.TransitionMono public import LeanPool.OneManifold.OneMfld.TwoComponents public import LeanPool.OneManifold.OneMfld.UnitInterval From 50e9f9bc72d4e6622cb63d87725646d22d43aa8d Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Sat, 26 Sep 2026 05:07:21 +0000 Subject: [PATCH 10/16] refactor(OneManifold): share chart overlap and interval arguments --- .../OneManifold/OneMfld/ClassifyInterval.lean | 83 +-------- LeanPool/OneManifold/OneMfld/GlueCore.lean | 175 +++++++++--------- .../OneManifold/OneMfld/LocallyConnected.lean | 39 +--- .../OneManifold/OneMfld/TwoComponents.lean | 128 +------------ 4 files changed, 102 insertions(+), 323 deletions(-) diff --git a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean index 542662b5ae..604b269623 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean @@ -389,85 +389,18 @@ lemma relu_mono : StrictMonoOn relu (Set.Ici 0) := by lemma relu_interval_ioo {U : Set NNReal} {a b : Real} (h : Ioo a b = relu ⁻¹' U) : (relu '' (Set.Ioo a b) = U) := by - ext x - simp only [mem_image, mem_Ioo] - constructor - · intro ⟨y,⟨ hya, hyb ⟩,hy'⟩ - have : y ∈ Set.Ioo a b := by - apply mem_Ioo.mpr - exact ⟨ hya, hyb ⟩ - rw [h] at this - simp only [mem_preimage] at this - rw [hy'] at this - assumption - · intro hx - use x.1 - simp only [NNReal.val_eq_coe] - rw [relu_proj] - simp only [and_true] - by_cases h0 : 0 ∈ U - · have hneg : ¬ BddBelow (relu ⁻¹' U) := by - by_contra hneg - rcases hneg with ⟨ c, hc ⟩ - have hn : Set.Iio 0 ⊆ relu ⁻¹' U := by - intro z - simp only [mem_Iio, mem_preimage] - intro hz - have : (relu z) = 0 := by - apply NNReal.coe_eq_zero.mp - rw [proj_relu'] - linarith - rw [this] - assumption - dsimp [lowerBounds] at hc - have : - 2 ∈ relu ⁻¹' U := by - apply hn - simp only [mem_Iio] - simp only [Left.neg_neg_iff] - linarith - have c2 := hc this - have : c - 1 ∈ relu ⁻¹' U := by - apply hn - simp only [mem_Iio, sub_neg] - linarith - specialize hc this - linarith - rw [←h] at hneg - exfalso - exact hneg bddBelow_Ioo - · have hpos : x > 0 := by - have hnonneg : x ≥ 0 := by exact zero_le - have hzero : x ≠ 0 := by exact ne_of_mem_of_not_mem hx h0 - exact pos_iff_ne_zero.mpr hzero - have : relu (NNReal.toReal x) = x := by exact relu_proj - rw [←this] at hx - have : ↑x ∈ relu ⁻¹' U := by exact hx - rw [←h] at this - exact this + apply subset_antisymm + · rintro _ ⟨y, hy, rfl⟩ + exact h ▸ hy + · intro x hx + refine ⟨(x : ℝ), ?_, relu_proj⟩ + rw [h] + simpa only [mem_preimage, relu_proj] using hx theorem StrictMonoOn.injOn_Ioo {α : Type u_1} {β : Type u_2} {f : α → β} [LinearOrder α] [LinearOrder β] {a : α} {b : α} (h : StrictMonoOn f (Set.Icc a b)) : InjOn f (Set.Ioo a b) := by - intro x hx y hy hf - have hx' : x ∈ Set.Icc a b := by exact mem_Icc_of_Ioo hx - have hy' : y ∈ Set.Icc a b := by exact mem_Icc_of_Ioo hy - by_cases hxy : x < y - · have : f x < f y := by - exact h hx' hy' (hxy) - exfalso - rw [hf] at this - exact (lt_self_iff_false (f y)).mp this - · by_cases hyx : y < x - · have : f y < f x := by - exact h hy' hx' hyx - exfalso - rw [hf] at this - exact (lt_self_iff_false (f y)).mp this - · have hyx' : x ≤ y := le_of_not_gt hyx - have hxy' : y ≤ x := le_of_not_gt hxy - apply le_antisymm - · assumption - assumption + exact (h.mono Ioo_subset_Icc_self).injOn lemma relu_ioo (a b : Real) : (relu '' (Set.Ioo a b) = Set.Ioo (relu a) (relu b)) ∨ diff --git a/LeanPool/OneManifold/OneMfld/GlueCore.lean b/LeanPool/OneManifold/OneMfld/GlueCore.lean index b18c518ddb..07281150f9 100644 --- a/LeanPool/OneManifold/OneMfld/GlueCore.lean +++ b/LeanPool/OneManifold/OneMfld/GlueCore.lean @@ -43,6 +43,37 @@ theorem tendsto_top_of_strictAntiOn_image {p v q w : NNReal} (hpv : p < v) variable {M : Type*} [TopologicalSpace M] +/-- A chart transition is continuous and injective wherever the first inverse chart lands +in the second chart's source. -/ +theorem chartTransition_continuous_injective + (a b : OpenPartialHomeomorph M NNReal) {I : Set NNReal} + (hI : I ⊆ a.target) (hmap : ∀ t ∈ I, a.symm t ∈ b.source) : + ContinuousOn (fun t => b (a.symm t)) I ∧ InjOn (fun t => b (a.symm t)) I := by + constructor + · exact b.continuousOn.comp (a.symm.continuousOn.mono hI) hmap + · intro x hx y hy hxy + exact a.symm.injOn (hI hx) (hI hy) (b.injOn (hmap x hx) (hmap y hy) hxy) + +/-- A transition limit at interior chart endpoints identifies their inverse images. -/ +theorem chartTransition_endpoint_eq [T2Space M] + (a b : OpenPartialHomeomorph M NNReal) {I : Set NNReal} {s t : NNReal} + (hI : I ⊆ a.target) (hmap : ∀ x ∈ I, a.symm x ∈ b.source) + (hs : s ∈ a.target) (ht : t ∈ b.target) (hne : (𝓝[I] s).NeBot) + (hlim : Tendsto (fun x => b (a.symm x)) (𝓝[I] s) (𝓝 t)) : + a.symm s = b.symm t := by + have hleft : Tendsto a.symm (𝓝[I] s) (𝓝 (a.symm s)) := + (a.symm.continuousOn s hs).mono hI + have htarget : Tendsto (fun x => b (a.symm x)) (𝓝[I] s) (𝓝[b.target] t) := by + rw [tendsto_nhdsWithin_iff] + refine ⟨hlim, ?_⟩ + filter_upwards [self_mem_nhdsWithin] with x hx + exact b.map_source (hmap x hx) + have hright := Tendsto.comp (b.symm.continuousOn t ht) htarget + apply tendsto_nhds_unique' hne hleft + apply Tendsto.congr' _ hright + filter_upwards [self_mem_nhdsWithin] with x hx + exact b.left_inv (hmap x hx) + /-- The overlap of a boundary chart `U` (target `Iio v`) with any other chart is connected: every component's `U`-image is an upper end-segment of `Iio v`, and two upper end-segments intersect, so there is only one component. -/ @@ -81,59 +112,46 @@ theorem overlap_connected [T2Space M] rw [hkey] exact isConnected_connectedComponentIn_iff.mpr hx -/-- **End-matching, increasing case.** Suppose the overlap `S = a.source ∩ b.source` has -image `Ioo p r` in chart `a` and `Ioo q w` in chart `b`, where the `r`-end is interior to -`a.target` and the `q`-end is interior to `b.target`. Then the transition is increasing: -`a x < a y → b x < b y` on `S`. (If it were decreasing, the overlap would accumulate at -both `a.symm r` and `b.symm q` along the same filter, forcing them equal — but then that -point would lie in `S`, putting `r` in `Ioo p r`.) -/ -theorem overlap_mono [T2Space M] (a b : OpenPartialHomeomorph M NNReal) +/-- Component version of `overlap_mono`: on a subset `W` of the overlap whose images are +`Ioo p r` and `Ioo q w`, with the `r`-end interior to `a.target`, the `q`-end interior to +`b.target`, and `r` not in the image of the full overlap, the transition is increasing. -/ +theorem overlap_mono_on [T2Space M] (a b : OpenPartialHomeomorph M NNReal) + {W : Set M} (hW : W ⊆ a.source ∩ b.source) {p r q w : NNReal} - (ha : a '' (a.source ∩ b.source) = Ioo p r) - (hb : b '' (a.source ∩ b.source) = Ioo q w) - (hr : r ∈ a.target) (hq : q ∈ b.target) : - ∀ x ∈ a.source ∩ b.source, ∀ y ∈ a.source ∩ b.source, - a x < a y → b x < b y := by - set S := a.source ∩ b.source with hSdef - have hSa : S ⊆ a.source := inter_subset_left - have hSb : S ⊆ b.source := inter_subset_right - have hacoord : ∀ x ∈ S, a x ∈ Ioo p r := fun x hx => ha ▸ mem_image_of_mem a hx + (ha : a '' W = Ioo p r) + (hb : b '' W = Ioo q w) + (hr : r ∈ a.target) (hq : q ∈ b.target) + (hrS : r ∉ a '' (a.source ∩ b.source)) : + ∀ x ∈ W, ∀ y ∈ W, a x < a y → b x < b y := by + have hWa : W ⊆ a.source := hW.trans inter_subset_left + have hWb : W ⊆ b.source := hW.trans inter_subset_right + have hacoord : ∀ x ∈ W, a x ∈ Ioo p r := fun x hx => ha ▸ mem_image_of_mem a hx by_cases hpr : p < r swap · intro x hx y hy hxy exact absurd ((hacoord x hx).1.trans (hacoord x hx).2) hpr set τ : NNReal → NNReal := fun t => b (a.symm t) with hτdef - have hsymm : ∀ t ∈ Ioo p r, a.symm t ∈ S ∧ a (a.symm t) = t := by + have hsymm : ∀ t ∈ Ioo p r, a.symm t ∈ W ∧ a (a.symm t) = t := by intro t ht rw [← ha] at ht - obtain ⟨x, hxS, rfl⟩ := ht - rw [a.left_inv (hSa hxS)] - exact ⟨hxS, rfl⟩ - have hkey : ∀ x ∈ S, τ (a x) = b x := by + obtain ⟨x, hxW, rfl⟩ := ht + rw [a.left_inv (hWa hxW)] + exact ⟨hxW, rfl⟩ + have hkey : ∀ x ∈ W, τ (a x) = b x := by intro x hx simp only [hτdef] - rw [a.left_inv (hSa hx)] + rw [a.left_inv (hWa hx)] have hτmaps : ∀ t ∈ Ioo p r, τ t ∈ Ioo q w := by intro t ht - have hb' : b (a.symm t) ∈ b '' S := mem_image_of_mem b (hsymm t ht).1 + have hb' : b (a.symm t) ∈ b '' W := mem_image_of_mem b (hsymm t ht).1 exact hb ▸ hb' have hIoo_target : Ioo p r ⊆ a.target := by rw [← ha] rintro y ⟨z, hz, rfl⟩ - exact a.map_source (hSa hz) - have hqw_target : Ioo q w ⊆ b.target := by - rw [← hb] - rintro y ⟨z, hz, rfl⟩ - exact b.map_source (hSb hz) - have hcont : ContinuousOn τ (Ioo p r) := - b.continuousOn.comp (a.symm.continuousOn.mono hIoo_target) - (fun t ht => hSb (hsymm t ht).1) - have hinj : InjOn τ (Ioo p r) := by - intro t1 ht1 t2 ht2 heq - obtain ⟨h1S, h1e⟩ := hsymm t1 ht1 - obtain ⟨h2S, h2e⟩ := hsymm t2 ht2 - have h12 : a.symm t1 = a.symm t2 := b.injOn (hSb h1S) (hSb h2S) heq - rw [← h1e, ← h2e, h12] + exact a.map_source (hWa hz) + obtain ⟨hcont, hinj⟩ : ContinuousOn τ (Ioo p r) ∧ InjOn τ (Ioo p r) := + chartTransition_continuous_injective a b hIoo_target + (fun t ht => hWb (hsymm t ht).1) rcases strictMonoOn_or_strictAntiOn_of_injOn_Ioo hcont hinj with hmono | hanti · intro x hx y hy hxy have h := hmono (hacoord x hx) (hacoord y hy) hxy @@ -145,8 +163,8 @@ theorem overlap_mono [T2Space M] (a b : OpenPartialHomeomorph M NNReal) exact hτmaps t ht · intro y hy rw [← hb] at hy - obtain ⟨x, hxS, rfl⟩ := hy - exact ⟨a x, hacoord x hxS, hkey x hxS⟩ + obtain ⟨x, hxW, rfl⟩ := hy + exact ⟨a x, hacoord x hxW, hkey x hxW⟩ have hτlim : Tendsto τ (𝓝[<] r) (𝓝 q) := tendsto_top_of_strictAntiOn_image hpr hanti himg have hF : 𝓝[Ioo p r] r = 𝓝[<] r := nhdsWithin_Ioo_eq_nhdsLT hpr @@ -154,30 +172,32 @@ theorem overlap_mono [T2Space M] (a b : OpenPartialHomeomorph M NNReal) apply mem_closure_iff_nhdsWithin_neBot.mp rw [closure_Ioo hpr.ne] exact ⟨hpr.le, le_refl r⟩ - have hlim1 : Tendsto a.symm (𝓝[Ioo p r] r) (𝓝 (a.symm r)) := - (a.symm.continuousOn r hr).mono hIoo_target - have hτq : Tendsto τ (𝓝[Ioo p r] r) (𝓝 q) := hF ▸ hτlim - have hτq' : Tendsto τ (𝓝[Ioo p r] r) (𝓝[b.target] q) := by - rw [tendsto_nhdsWithin_iff] - refine ⟨hτq, ?_⟩ - filter_upwards [self_mem_nhdsWithin] with t ht - exact hqw_target (hτmaps t ht) - have hlim2 : Tendsto (b.symm ∘ τ) (𝓝[Ioo p r] r) (𝓝 (b.symm q)) := - Tendsto.comp (b.symm.continuousOn q hq) hτq' - have hlim2' : Tendsto a.symm (𝓝[Ioo p r] r) (𝓝 (b.symm q)) := by - apply Tendsto.congr' _ hlim2 - filter_upwards [self_mem_nhdsWithin] with t ht - change b.symm (τ t) = a.symm t - simp only [hτdef] - exact b.left_inv (hSb (hsymm t ht).1) - have hz : a.symm r = b.symm q := tendsto_nhds_unique' hFne hlim1 hlim2' - have hzS : a.symm r ∈ S := by + have hτend : Tendsto τ (𝓝[Ioo p r] r) (𝓝 q) := hF ▸ hτlim + have hz : a.symm r = b.symm q := + chartTransition_endpoint_eq a b hIoo_target + (fun t ht => hWb (hsymm t ht).1) hr hq hFne hτend + have hzS : a.symm r ∈ a.source ∩ b.source := by refine ⟨a.map_target hr, ?_⟩ rw [hz] exact b.map_target hq - have hr' : a (a.symm r) ∈ Ioo p r := hacoord _ hzS - rw [a.right_inv hr] at hr' - exact lt_irrefl r hr'.2 + exact hrS ⟨a.symm r, hzS, a.right_inv hr⟩ + +/-- **End-matching, increasing case.** Suppose the overlap `S = a.source ∩ b.source` has +image `Ioo p r` in chart `a` and `Ioo q w` in chart `b`, where the `r`-end is interior to +`a.target` and the `q`-end is interior to `b.target`. Then the transition is increasing: +`a x < a y → b x < b y` on `S`. (If it were decreasing, the overlap would accumulate at +both `a.symm r` and `b.symm q` along the same filter, forcing them equal — but then that +point would lie in `S`, putting `r` in `Ioo p r`.) -/ +theorem overlap_mono [T2Space M] (a b : OpenPartialHomeomorph M NNReal) + {p r q w : NNReal} + (ha : a '' (a.source ∩ b.source) = Ioo p r) + (hb : b '' (a.source ∩ b.source) = Ioo q w) + (hr : r ∈ a.target) (hq : q ∈ b.target) : + ∀ x ∈ a.source ∩ b.source, ∀ y ∈ a.source ∩ b.source, + a x < a y → b x < b y := by + apply overlap_mono_on a b (Subset.refl _) ha hb hr hq + rw [ha] + exact fun h => lt_irrefl r h.2 /-- **End-matching, decreasing case.** Same setting, but now the `p`-end is interior to `a.target` (and the `q`-end interior to `b.target`): the transition is decreasing. -/ @@ -215,19 +235,9 @@ theorem overlap_anti [T2Space M] (a b : OpenPartialHomeomorph M NNReal) rw [← ha] rintro y ⟨z, hz, rfl⟩ exact a.map_source (hSa hz) - have hqw_target : Ioo q w ⊆ b.target := by - rw [← hb] - rintro y ⟨z, hz, rfl⟩ - exact b.map_source (hSb hz) - have hcont : ContinuousOn τ (Ioo p r) := - b.continuousOn.comp (a.symm.continuousOn.mono hIoo_target) + obtain ⟨hcont, hinj⟩ : ContinuousOn τ (Ioo p r) ∧ InjOn τ (Ioo p r) := + chartTransition_continuous_injective a b hIoo_target (fun t ht => hSb (hsymm t ht).1) - have hinj : InjOn τ (Ioo p r) := by - intro t1 ht1 t2 ht2 heq - obtain ⟨h1S, h1e⟩ := hsymm t1 ht1 - obtain ⟨h2S, h2e⟩ := hsymm t2 ht2 - have h12 : a.symm t1 = a.symm t2 := b.injOn (hSb h1S) (hSb h2S) heq - rw [← h1e, ← h2e, h12] rcases strictMonoOn_or_strictAntiOn_of_injOn_Ioo hcont hinj with hmono | hanti · exfalso have himg : τ '' Ioo p r = Ioo q w := by @@ -245,23 +255,10 @@ theorem overlap_anti [T2Space M] (a b : OpenPartialHomeomorph M NNReal) apply mem_closure_iff_nhdsWithin_neBot.mp rw [closure_Ioo hpr.ne] exact ⟨le_refl p, hpr.le⟩ - have hlim1 : Tendsto a.symm (𝓝[Ioo p r] p) (𝓝 (a.symm p)) := - (a.symm.continuousOn p hp).mono hIoo_target - have hτq : Tendsto τ (𝓝[Ioo p r] p) (𝓝 q) := hF ▸ hτlim - have hτq' : Tendsto τ (𝓝[Ioo p r] p) (𝓝[b.target] q) := by - rw [tendsto_nhdsWithin_iff] - refine ⟨hτq, ?_⟩ - filter_upwards [self_mem_nhdsWithin] with t ht - exact hqw_target (hτmaps t ht) - have hlim2 : Tendsto (b.symm ∘ τ) (𝓝[Ioo p r] p) (𝓝 (b.symm q)) := - Tendsto.comp (b.symm.continuousOn q hq) hτq' - have hlim2' : Tendsto a.symm (𝓝[Ioo p r] p) (𝓝 (b.symm q)) := by - apply Tendsto.congr' _ hlim2 - filter_upwards [self_mem_nhdsWithin] with t ht - change b.symm (τ t) = a.symm t - simp only [hτdef] - exact b.left_inv (hSb (hsymm t ht).1) - have hz : a.symm p = b.symm q := tendsto_nhds_unique' hFne hlim1 hlim2' + have hτend : Tendsto τ (𝓝[Ioo p r] p) (𝓝 q) := hF ▸ hτlim + have hz : a.symm p = b.symm q := + chartTransition_endpoint_eq a b hIoo_target + (fun t ht => hSb (hsymm t ht).1) hp hq hFne hτend have hzS : a.symm p ∈ S := by refine ⟨a.map_target hp, ?_⟩ rw [hz] diff --git a/LeanPool/OneManifold/OneMfld/LocallyConnected.lean b/LeanPool/OneManifold/OneMfld/LocallyConnected.lean index 598525142a..c7822c35cb 100644 --- a/LeanPool/OneManifold/OneMfld/LocallyConnected.lean +++ b/LeanPool/OneManifold/OneMfld/LocallyConnected.lean @@ -70,50 +70,15 @@ instance : LocallyConnectedSpace NNReal := by use this intro y yV dsimp [V] at yV - by_cases h : z' = y - · exact Inseparable.joinedIn (congrArg nhds h) this yV rw [JoinedIn] let γ : Path z' y := { toFun := fun t ↦ NNReal.mk ((unitInterval.symm t)*z' + t*y) (add_nonneg (mul_nonneg unitInterval.nonneg' znonneg) (mul_nonneg unitInterval.nonneg' y.coe_nonneg)) continuous_toFun := by + apply Continuous.subtype_mk simp only [unitInterval.coe_symm_eq] - refine Metric.continuous_iff.mpr ?_ - intro s ε εpos - let δ := ε / dist y z' - have dyz'pos : 0 < dist y z' := dist_pos.mpr (ne_comm.mpr h) - have δpos : δ > 0 := div_pos εpos dyz'pos - use δ - constructor - · exact δpos - intro a a_s_near - rw [NNReal.dist_eq] - simp only [NNReal.coe_mk] - rw [sub_mul, sub_mul, one_mul] - let ans : Real := (↑a - ↑s) * (↑y - ↑z') - have : ↑z' - ↑a * ↑z' + ↑a * ↑y - (↑z' - ↑s * ↑z' + ↑s * ↑y) = ans := by ring - rw [this] - dsimp [ans] - rw [abs_mul] - -- have : (max 0 l + u) / 2 - ↑a * ((max 0 l + u) / 2) + ↑a * ↑y - ((max 0 l + - -- u) / 2 - ↑s * ((max 0 l + u) / 2) + ↑s * ↑y) - -- = (↑a - ↑s) * (↑y - ((max 0 l + u) / 2)) := by ring - --ring_nf - have ha : |(a:ℝ) - (s:ℝ)| < δ := by - rw [← Real.dist_eq (a : ℝ) (s : ℝ)] - exact a_s_near - have this' : |↑y - (max 0 l + u) / 2| = dist y z' := rfl - have this : |(y:ℝ) - (z':ℝ)| = dist y z' := by - exact this' - rw [this] - calc - |↑a - ↑s| * dist y z' - < δ * dist y z' := by exact ((mul_lt_mul_iff_of_pos_right dyz'pos).mpr a_s_near) - _ = ε := by dsimp [δ] - ring_nf - refine mul_inv_cancel_right₀ ?_ ε - exact dist_ne_zero.mpr fun a => h (id (Eq.symm a)) + fun_prop source' := by simp only [unitInterval.symm_zero, Set.Icc.coe_one, one_mul, Set.Icc.coe_zero, zero_mul, add_zero] diff --git a/LeanPool/OneManifold/OneMfld/TwoComponents.lean b/LeanPool/OneManifold/OneMfld/TwoComponents.lean index 9424a0714d..6346a8e7ce 100644 --- a/LeanPool/OneManifold/OneMfld/TwoComponents.lean +++ b/LeanPool/OneManifold/OneMfld/TwoComponents.lean @@ -39,99 +39,6 @@ theorem tendsto_bot_of_strictAntiOn_image {p v q w : NNReal} (hpv : p < v) variable {M : Type*} [TopologicalSpace M] -/-- Component version of `overlap_mono`: on a subset `W` of the overlap whose images are -`Ioo p r` and `Ioo q w`, with the `r`-end interior to `a.target`, the `q`-end interior to -`b.target`, and `r` not in the image of the full overlap, the transition is increasing. -/ -theorem overlap_mono_on [T2Space M] (a b : OpenPartialHomeomorph M NNReal) - {W : Set M} (hW : W ⊆ a.source ∩ b.source) - {p r q w : NNReal} - (ha : a '' W = Ioo p r) - (hb : b '' W = Ioo q w) - (hr : r ∈ a.target) (hq : q ∈ b.target) - (hrS : r ∉ a '' (a.source ∩ b.source)) : - ∀ x ∈ W, ∀ y ∈ W, a x < a y → b x < b y := by - have hWa : W ⊆ a.source := hW.trans inter_subset_left - have hWb : W ⊆ b.source := hW.trans inter_subset_right - have hacoord : ∀ x ∈ W, a x ∈ Ioo p r := fun x hx => ha ▸ mem_image_of_mem a hx - by_cases hpr : p < r - swap - · intro x hx y hy hxy - exact absurd ((hacoord x hx).1.trans (hacoord x hx).2) hpr - set τ : NNReal → NNReal := fun t => b (a.symm t) with hτdef - have hsymm : ∀ t ∈ Ioo p r, a.symm t ∈ W ∧ a (a.symm t) = t := by - intro t ht - rw [← ha] at ht - obtain ⟨x, hxW, rfl⟩ := ht - rw [a.left_inv (hWa hxW)] - exact ⟨hxW, rfl⟩ - have hkey : ∀ x ∈ W, τ (a x) = b x := by - intro x hx - simp only [hτdef] - rw [a.left_inv (hWa hx)] - have hτmaps : ∀ t ∈ Ioo p r, τ t ∈ Ioo q w := by - intro t ht - have hb' : b (a.symm t) ∈ b '' W := mem_image_of_mem b (hsymm t ht).1 - exact hb ▸ hb' - have hIoo_target : Ioo p r ⊆ a.target := by - rw [← ha] - rintro y ⟨z, hz, rfl⟩ - exact a.map_source (hWa hz) - have hqw_target : Ioo q w ⊆ b.target := by - rw [← hb] - rintro y ⟨z, hz, rfl⟩ - exact b.map_source (hWb hz) - have hcont : ContinuousOn τ (Ioo p r) := - b.continuousOn.comp (a.symm.continuousOn.mono hIoo_target) - (fun t ht => hWb (hsymm t ht).1) - have hinj : InjOn τ (Ioo p r) := by - intro t1 ht1 t2 ht2 heq - obtain ⟨h1W, h1e⟩ := hsymm t1 ht1 - obtain ⟨h2W, h2e⟩ := hsymm t2 ht2 - have h12 : a.symm t1 = a.symm t2 := b.injOn (hWb h1W) (hWb h2W) heq - rw [← h1e, ← h2e, h12] - rcases strictMonoOn_or_strictAntiOn_of_injOn_Ioo hcont hinj with hmono | hanti - · intro x hx y hy hxy - have h := hmono (hacoord x hx) (hacoord y hy) hxy - rwa [hkey x hx, hkey y hy] at h - · exfalso - have himg : τ '' Ioo p r = Ioo q w := by - apply subset_antisymm - · rintro _ ⟨t, ht, rfl⟩ - exact hτmaps t ht - · intro y hy - rw [← hb] at hy - obtain ⟨x, hxW, rfl⟩ := hy - exact ⟨a x, hacoord x hxW, hkey x hxW⟩ - have hτlim : Tendsto τ (𝓝[<] r) (𝓝 q) := - tendsto_top_of_strictAntiOn_image hpr hanti himg - have hF : 𝓝[Ioo p r] r = 𝓝[<] r := nhdsWithin_Ioo_eq_nhdsLT hpr - have hFne : (𝓝[Ioo p r] r).NeBot := by - apply mem_closure_iff_nhdsWithin_neBot.mp - rw [closure_Ioo hpr.ne] - exact ⟨hpr.le, le_refl r⟩ - have hlim1 : Tendsto a.symm (𝓝[Ioo p r] r) (𝓝 (a.symm r)) := - (a.symm.continuousOn r hr).mono hIoo_target - have hτq : Tendsto τ (𝓝[Ioo p r] r) (𝓝 q) := hF ▸ hτlim - have hτq' : Tendsto τ (𝓝[Ioo p r] r) (𝓝[b.target] q) := by - rw [tendsto_nhdsWithin_iff] - refine ⟨hτq, ?_⟩ - filter_upwards [self_mem_nhdsWithin] with t ht - exact hqw_target (hτmaps t ht) - have hlim2 : Tendsto (b.symm ∘ τ) (𝓝[Ioo p r] r) (𝓝 (b.symm q)) := - Tendsto.comp (b.symm.continuousOn q hq) hτq' - have hlim2' : Tendsto a.symm (𝓝[Ioo p r] r) (𝓝 (b.symm q)) := by - apply Tendsto.congr' _ hlim2 - filter_upwards [self_mem_nhdsWithin] with t ht - change b.symm (τ t) = a.symm t - simp only [hτdef] - exact b.left_inv (hWb (hsymm t ht).1) - have hz : a.symm r = b.symm q := tendsto_nhds_unique' hFne hlim1 hlim2' - have hzS : a.symm r ∈ a.source ∩ b.source := by - refine ⟨a.map_target hr, ?_⟩ - rw [hz] - exact b.map_target hq - exact hrS ⟨a.symm r, hzS, a.right_inv hr⟩ - /-- Mirror component version: with the `p`-end interior to `a.target`, the `w`-end interior to `b.target`, and `p` not in the image of the full overlap, the transition is again increasing. -/ @@ -169,19 +76,9 @@ theorem overlap_mono_on' [T2Space M] (a b : OpenPartialHomeomorph M NNReal) rw [← ha] rintro y ⟨z, hz, rfl⟩ exact a.map_source (hWa hz) - have hqw_target : Ioo q w ⊆ b.target := by - rw [← hb] - rintro y ⟨z, hz, rfl⟩ - exact b.map_source (hWb hz) - have hcont : ContinuousOn τ (Ioo p r) := - b.continuousOn.comp (a.symm.continuousOn.mono hIoo_target) + obtain ⟨hcont, hinj⟩ : ContinuousOn τ (Ioo p r) ∧ InjOn τ (Ioo p r) := + chartTransition_continuous_injective a b hIoo_target (fun t ht => hWb (hsymm t ht).1) - have hinj : InjOn τ (Ioo p r) := by - intro t1 ht1 t2 ht2 heq - obtain ⟨h1W, h1e⟩ := hsymm t1 ht1 - obtain ⟨h2W, h2e⟩ := hsymm t2 ht2 - have h12 : a.symm t1 = a.symm t2 := b.injOn (hWb h1W) (hWb h2W) heq - rw [← h1e, ← h2e, h12] rcases strictMonoOn_or_strictAntiOn_of_injOn_Ioo hcont hinj with hmono | hanti · intro x hx y hy hxy have h := hmono (hacoord x hx) (hacoord y hy) hxy @@ -202,23 +99,10 @@ theorem overlap_mono_on' [T2Space M] (a b : OpenPartialHomeomorph M NNReal) apply mem_closure_iff_nhdsWithin_neBot.mp rw [closure_Ioo hpr.ne] exact ⟨le_refl p, hpr.le⟩ - have hlim1 : Tendsto a.symm (𝓝[Ioo p r] p) (𝓝 (a.symm p)) := - (a.symm.continuousOn p hp).mono hIoo_target - have hτw : Tendsto τ (𝓝[Ioo p r] p) (𝓝 w) := hF ▸ hτlim - have hτw' : Tendsto τ (𝓝[Ioo p r] p) (𝓝[b.target] w) := by - rw [tendsto_nhdsWithin_iff] - refine ⟨hτw, ?_⟩ - filter_upwards [self_mem_nhdsWithin] with t ht - exact hqw_target (hτmaps t ht) - have hlim2 : Tendsto (b.symm ∘ τ) (𝓝[Ioo p r] p) (𝓝 (b.symm w)) := - Tendsto.comp (b.symm.continuousOn w hw) hτw' - have hlim2' : Tendsto a.symm (𝓝[Ioo p r] p) (𝓝 (b.symm w)) := by - apply Tendsto.congr' _ hlim2 - filter_upwards [self_mem_nhdsWithin] with t ht - change b.symm (τ t) = a.symm t - simp only [hτdef] - exact b.left_inv (hWb (hsymm t ht).1) - have hz : a.symm p = b.symm w := tendsto_nhds_unique' hFne hlim1 hlim2' + have hτend : Tendsto τ (𝓝[Ioo p r] p) (𝓝 w) := hF ▸ hτlim + have hz : a.symm p = b.symm w := + chartTransition_endpoint_eq a b hIoo_target + (fun t ht => hWb (hsymm t ht).1) hp hw hFne hτend have hzS : a.symm p ∈ a.source ∩ b.source := by refine ⟨a.map_target hp, ?_⟩ rw [hz] From 23d1b0b2f23ed38d82efa42a10f6f8641261caa5 Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Sat, 26 Sep 2026 06:01:42 +0000 Subject: [PATCH 11/16] Fix interval membership transport after shared overlap refactor --- LeanPool/OneManifold/OneMfld/ClassifyInterval.lean | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean index 604b269623..5719230c6e 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean @@ -391,7 +391,8 @@ lemma relu_interval_ioo {U : Set NNReal} {a b : Real} (h : Ioo a b = relu ⁻¹' (relu '' (Set.Ioo a b) = U) := by apply subset_antisymm · rintro _ ⟨y, hy, rfl⟩ - exact h ▸ hy + rw [h] at hy + exact hy · intro x hx refine ⟨(x : ℝ), ?_, relu_proj⟩ rw [h] From cc5e2fc1a0c38897b7abb88d4b3a894cb4a271d7 Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Sat, 26 Sep 2026 09:02:48 +0000 Subject: [PATCH 12/16] refactor: factor circle chart construction proofs --- .../OneManifold/OneMfld/CircleBlocks.lean | 209 ++++++++++-------- LeanPool/OneManifold/OneMfld/CircleGlue.lean | 203 +++++++++-------- 2 files changed, 227 insertions(+), 185 deletions(-) diff --git a/LeanPool/OneManifold/OneMfld/CircleBlocks.lean b/LeanPool/OneManifold/OneMfld/CircleBlocks.lean index 3462616e9e..37c9845025 100644 --- a/LeanPool/OneManifold/OneMfld/CircleBlocks.lean +++ b/LeanPool/OneManifold/OneMfld/CircleBlocks.lean @@ -70,6 +70,114 @@ lemma mobiusFun_mem (c : NNReal) (hc : 0 < c) {t : NNReal} (ht : t ∈ Ioo (0 : rw [mobiusFun, div_lt_one hden] exact lt_add_of_pos_right t (mul_pos hc (tsub_pos_of_lt ht.2)) +private lemma mobiusInverse_mem (c : NNReal) (hc : 0 < c) : + ∀ y ∈ Ioo (0 : NNReal) 1, + c * y / ((1 - y) + c * y) ∈ Ioo (0 : NNReal) 1 := by + intro y hy + have hden : 0 < (1 - y) + c * y := + lt_of_lt_of_le (tsub_pos_of_lt hy.2) le_self_add + exact ⟨div_pos (mul_pos hc hy.1) hden, + (div_lt_one hden).mpr (lt_add_of_pos_left _ (tsub_pos_of_lt hy.2))⟩ + +private lemma coe_mobiusFun (c : NNReal) : ∀ x : NNReal, x ≤ 1 → + ((mobiusFun c x : NNReal) : ℝ) = (x : ℝ) / ((x : ℝ) + c * (1 - (x : ℝ))) := by + intro x hx1 + rw [mobiusFun] + push_cast [NNReal.coe_sub hx1] + ring + +private lemma mobiusInverse_left (c : NNReal) (hc : 0 < c) : + ∀ x ∈ Ioo (0 : NNReal) 1, + c * mobiusFun c x / ((1 - mobiusFun c x) + c * mobiusFun c x) = x := by + have hc' : (0 : ℝ) < c := hc + intro x hx + have hfx := mobiusFun_mem c hc hx + have hX0 : (0:ℝ) < x := hx.1 + have hX1 : (x:ℝ) < 1 := hx.2 + have hD : (0:ℝ) < (x:ℝ) + c * (1 - (x:ℝ)) := by nlinarith + apply NNReal.coe_injective + push_cast [NNReal.coe_sub hfx.2.le, coe_mobiusFun c x hx.2.le] + have hkey : (1 - (x:ℝ) / ((x:ℝ) + c * (1 - (x:ℝ)))) + + c * ((x:ℝ) / ((x:ℝ) + c * (1 - (x:ℝ)))) = c / ((x:ℝ) + c * (1 - (x:ℝ))) := by + field_simp + ring + rw [hkey] + field_simp + +private lemma mobiusInverse_right (c : NNReal) (hc : 0 < c) : + ∀ y ∈ Ioo (0 : NNReal) 1, mobiusFun c (c * y / ((1 - y) + c * y)) = y := by + have hc' : (0 : ℝ) < c := hc + intro y hy + have hgy := mobiusInverse_mem c hc y hy + have hY0 : (0:ℝ) < y := hy.1 + have hY1 : (y:ℝ) < 1 := hy.2 + have hE : (0:ℝ) < (1 - (y:ℝ)) + c * (y:ℝ) := by nlinarith + have hgy_coe : ((c * y / ((1 - y) + c * y) : NNReal) : ℝ) + = c * (y:ℝ) / ((1 - (y:ℝ)) + c * (y:ℝ)) := by + push_cast [NNReal.coe_sub hy.2.le] + ring + apply NNReal.coe_injective + rw [coe_mobiusFun c _ hgy.2.le, hgy_coe] + have hkey : c * (y:ℝ) / ((1 - (y:ℝ)) + c * (y:ℝ)) + + c * (1 - c * (y:ℝ) / ((1 - (y:ℝ)) + c * (y:ℝ))) + = c / ((1 - (y:ℝ)) + c * (y:ℝ)) := by + field_simp + ring + rw [hkey] + field_simp + +private lemma continuousOn_mobiusFun (c : NNReal) : + ContinuousOn (mobiusFun c) (Ioo 0 1) := by + change ContinuousOn (fun x : NNReal => x / (x + c * (1 - x))) (Ioo 0 1) + exact ContinuousOn.div continuousOn_id + ((continuous_id.add (continuous_const.mul (continuous_const.sub continuous_id))).continuousOn) + (fun x hx => (lt_of_lt_of_le hx.1 le_self_add).ne') + +private lemma continuousOn_mobiusInverse (c : NNReal) : + ContinuousOn (fun y : NNReal => c * y / ((1 - y) + c * y)) (Ioo 0 1) := by + exact ContinuousOn.div (continuous_const.mul continuous_id).continuousOn + (((continuous_const.sub continuous_id).add + (continuous_const.mul continuous_id)).continuousOn) + (fun y hy => (lt_of_lt_of_le (tsub_pos_of_lt hy.2) le_self_add).ne') + +private lemma mobiusFun_image_lower (c : NNReal) (hc : 0 < c) : + ∀ t ∈ Ioo (0 : NNReal) 1, + mobiusFun c '' (Ioo 0 t) = Ioo 0 (mobiusFun c t) := by + intro t ht + ext z + constructor + · rintro ⟨x, hx, rfl⟩ + have hx1 : x ∈ Ioo (0:NNReal) 1 := ⟨hx.1, hx.2.trans ht.2⟩ + exact ⟨(mobiusFun_mem c hc hx1).1, mobiusFun_strictMonoOn c hc hx1 ht hx.2⟩ + · intro hz + have hz1 : z ∈ Ioo (0:NNReal) 1 := ⟨hz.1, hz.2.trans (mobiusFun_mem c hc ht).2⟩ + have hmem := mobiusInverse_mem c hc z hz1 + refine ⟨c * z / ((1 - z) + c * z), ⟨hmem.1, ?_⟩, mobiusInverse_right c hc z hz1⟩ + by_contra hcon + rw [not_lt] at hcon + have := (mobiusFun_strictMonoOn c hc).monotoneOn ht hmem hcon + rw [mobiusInverse_right c hc z hz1] at this + exact absurd hz.2 (not_lt.mpr this) + +private lemma mobiusFun_image_upper (c : NNReal) (hc : 0 < c) : + ∀ t ∈ Ioo (0 : NNReal) 1, + mobiusFun c '' (Ioo t 1) = Ioo (mobiusFun c t) 1 := by + intro t ht + ext z + constructor + · rintro ⟨x, hx, rfl⟩ + have hx1 : x ∈ Ioo (0:NNReal) 1 := ⟨ht.1.trans hx.1, hx.2⟩ + exact ⟨mobiusFun_strictMonoOn c hc ht hx1 hx.1, (mobiusFun_mem c hc hx1).2⟩ + · intro hz + have hz1 : z ∈ Ioo (0:NNReal) 1 := ⟨lt_trans (mobiusFun_mem c hc ht).1 hz.1, hz.2⟩ + have hmem := mobiusInverse_mem c hc z hz1 + refine ⟨c * z / ((1 - z) + c * z), ⟨?_, hmem.2⟩, mobiusInverse_right c hc z hz1⟩ + by_contra hcon + rw [not_lt] at hcon + have := (mobiusFun_strictMonoOn c hc).monotoneOn hmem ht hcon + rw [mobiusInverse_right c hc z hz1] at this + exact absurd hz.1 (not_lt.mpr this) + /-- The Möbius reparametrization as a partial homeomorphism of `Ioo 0 1 ⊆ ℝ≥0`, with its action on lower and upper end-segments. -/ def mobiusOPH' (c : NNReal) (hc : 0 < c) : @@ -78,108 +186,19 @@ def mobiusOPH' (c : NNReal) (hc : 0 < c) : (∀ x : NNReal, e.toFun x = mobiusFun c x) ∧ (∀ t ∈ Ioo (0:NNReal) 1, e.toFun '' (Ioo 0 t) = Ioo 0 (mobiusFun c t)) ∧ (∀ t ∈ Ioo (0:NNReal) 1, e.toFun '' (Ioo t 1) = Ioo (mobiusFun c t) 1) } := by - have hc' : (0:ℝ) < c := hc - -- the inverse function - have hgmem : ∀ y ∈ Ioo (0:NNReal) 1, c * y / ((1 - y) + c * y) ∈ Ioo (0:NNReal) 1 := by - intro y hy - have hden : 0 < (1 - y) + c * y := - lt_of_lt_of_le (tsub_pos_of_lt hy.2) le_self_add - exact ⟨div_pos (mul_pos hc hy.1) hden, - (div_lt_one hden).mpr (lt_add_of_pos_left _ (tsub_pos_of_lt hy.2))⟩ - have hcoe_mobius : ∀ x : NNReal, x ≤ 1 → - ((mobiusFun c x : NNReal) : ℝ) = (x:ℝ) / ((x:ℝ) + c * (1 - (x:ℝ))) := by - intro x hx1 - rw [mobiusFun] - push_cast [NNReal.coe_sub hx1] - ring - have hleft : ∀ x ∈ Ioo (0:NNReal) 1, - c * mobiusFun c x / ((1 - mobiusFun c x) + c * mobiusFun c x) = x := by - intro x hx - have hfx := mobiusFun_mem c hc hx - have hX0 : (0:ℝ) < x := hx.1 - have hX1 : (x:ℝ) < 1 := hx.2 - have hD : (0:ℝ) < (x:ℝ) + c * (1 - (x:ℝ)) := by nlinarith - apply NNReal.coe_injective - push_cast [NNReal.coe_sub hfx.2.le, hcoe_mobius x hx.2.le] - have hkey : (1 - (x:ℝ) / ((x:ℝ) + c * (1 - (x:ℝ)))) - + c * ((x:ℝ) / ((x:ℝ) + c * (1 - (x:ℝ)))) = c / ((x:ℝ) + c * (1 - (x:ℝ))) := by - field_simp - ring - rw [hkey] - field_simp - have hright : ∀ y ∈ Ioo (0:NNReal) 1, - mobiusFun c (c * y / ((1 - y) + c * y)) = y := by - intro y hy - have hgy := hgmem y hy - have hY0 : (0:ℝ) < y := hy.1 - have hY1 : (y:ℝ) < 1 := hy.2 - have hE : (0:ℝ) < (1 - (y:ℝ)) + c * (y:ℝ) := by nlinarith - have hgy_coe : ((c * y / ((1 - y) + c * y) : NNReal) : ℝ) - = c * (y:ℝ) / ((1 - (y:ℝ)) + c * (y:ℝ)) := by - push_cast [NNReal.coe_sub hy.2.le] - ring - apply NNReal.coe_injective - rw [hcoe_mobius _ hgy.2.le, hgy_coe] - have hkey : c * (y:ℝ) / ((1 - (y:ℝ)) + c * (y:ℝ)) - + c * (1 - c * (y:ℝ) / ((1 - (y:ℝ)) + c * (y:ℝ))) - = c / ((1 - (y:ℝ)) + c * (y:ℝ)) := by - field_simp - ring - rw [hkey] - field_simp refine ⟨{ toFun := mobiusFun c invFun := fun y => c * y / ((1 - y) + c * y) source := Ioo 0 1 target := Ioo 0 1 map_source' := fun x hx => mobiusFun_mem c hc hx - map_target' := hgmem - left_inv' := fun x hx => hleft x hx - right_inv' := fun y hy => hright y hy + map_target' := by exact mobiusInverse_mem c hc + left_inv' := by exact fun x hx => mobiusInverse_left c hc x hx + right_inv' := by exact fun y hy => mobiusInverse_right c hc y hy open_source := isOpen_Ioo open_target := isOpen_Ioo - continuousOn_toFun := ?_ - continuousOn_invFun := ?_ }, - rfl, rfl, fun x => rfl, ?_, ?_⟩ - · change ContinuousOn (fun x : NNReal => x / (x + c * (1 - x))) (Ioo 0 1) - exact ContinuousOn.div continuousOn_id - ((continuous_id.add (continuous_const.mul (continuous_const.sub continuous_id))).continuousOn) - (fun x hx => (lt_of_lt_of_le hx.1 le_self_add).ne') - · exact ContinuousOn.div (continuous_const.mul continuous_id).continuousOn - (((continuous_const.sub continuous_id).add - (continuous_const.mul continuous_id)).continuousOn) - (fun y hy => (lt_of_lt_of_le (tsub_pos_of_lt hy.2) le_self_add).ne') - · -- lower end-segment - intro t ht - ext z - constructor - · rintro ⟨x, hx, rfl⟩ - have hx1 : x ∈ Ioo (0:NNReal) 1 := ⟨hx.1, hx.2.trans ht.2⟩ - exact ⟨(mobiusFun_mem c hc hx1).1, mobiusFun_strictMonoOn c hc hx1 ht hx.2⟩ - · intro hz - have hz1 : z ∈ Ioo (0:NNReal) 1 := ⟨hz.1, hz.2.trans (mobiusFun_mem c hc ht).2⟩ - have hmem := hgmem z hz1 - refine ⟨c * z / ((1 - z) + c * z), ⟨hmem.1, ?_⟩, hright z hz1⟩ - by_contra hcon - rw [not_lt] at hcon - have := (mobiusFun_strictMonoOn c hc).monotoneOn ht hmem hcon - rw [hright z hz1] at this - exact absurd hz.2 (not_lt.mpr this) - · -- upper end-segment - intro t ht - ext z - constructor - · rintro ⟨x, hx, rfl⟩ - have hx1 : x ∈ Ioo (0:NNReal) 1 := ⟨ht.1.trans hx.1, hx.2⟩ - exact ⟨mobiusFun_strictMonoOn c hc ht hx1 hx.1, (mobiusFun_mem c hc hx1).2⟩ - · intro hz - have hz1 : z ∈ Ioo (0:NNReal) 1 := ⟨lt_trans (mobiusFun_mem c hc ht).1 hz.1, hz.2⟩ - have hmem := hgmem z hz1 - refine ⟨c * z / ((1 - z) + c * z), ⟨?_, hmem.2⟩, hright z hz1⟩ - by_contra hcon - rw [not_lt] at hcon - have := (mobiusFun_strictMonoOn c hc).monotoneOn hmem ht hcon - rw [hright z hz1] at this - exact absurd hz.1 (not_lt.mpr this) + continuousOn_toFun := by exact continuousOn_mobiusFun c + continuousOn_invFun := by exact continuousOn_mobiusInverse c }, by + exact ⟨rfl, rfl, fun x => rfl, mobiusFun_image_lower c hc, mobiusFun_image_upper c hc⟩⟩ /-- The affine map `x ↦ k·x + d` as a chart from `Ioo 0 1 ⊆ ℝ≥0` onto `Ioo d (d + k) ⊆ ℝ`. -/ diff --git a/LeanPool/OneManifold/OneMfld/CircleGlue.lean b/LeanPool/OneManifold/OneMfld/CircleGlue.lean index 6f9c425803..27ddbf1aa0 100644 --- a/LeanPool/OneManifold/OneMfld/CircleGlue.lean +++ b/LeanPool/OneManifold/OneMfld/CircleGlue.lean @@ -193,10 +193,38 @@ private lemma affine_circle_target {M : Type*} [TopologicalSpace M] field_simp ring -/-- Normalize both charts to target `Ioo 0 1`, split the overlap into its two -components, orient the second chart so the component lower in `a` is upper in `b`, and -Möbius-shrink both charts so the lower end-segments sit below `1 / 4`. -/ -private lemma exists_normalized_charts {M : Type*} [TopologicalSpace M] [T2Space M] +/-- Choose the orientation whose first component is the upper end-segment. -/ +private lemma exists_oriented_overlap_chart {M : Type*} [TopologicalSpace M] + (b : OChart M) (hbt : b.target = Ioo 0 1) (W₀ W₁ : Set M) + (hW₀ : W₀ ⊆ b.source) (hW₁ : W₁ ⊆ b.source) + (s q : NNReal) (hs0 : 0 < s) (hsq : s ≤ q) (hq1 : q < 1) + (harr : (b.toOpenPartialHomeomorph '' W₀ = Ioo q 1 ∧ + b.toOpenPartialHomeomorph '' W₁ = Ioo 0 s) ∨ + (b.toOpenPartialHomeomorph '' W₀ = Ioo 0 s ∧ + b.toOpenPartialHomeomorph '' W₁ = Ioo q 1)) : + ∃ B : OpenPartialHomeomorph M NNReal, + B.source = b.source ∧ B.target = Ioo 0 1 ∧ + ∃ s' q' : NNReal, 0 < s' ∧ s' ≤ q' ∧ q' < 1 ∧ + B '' W₀ = Ioo q' 1 ∧ B '' W₁ = Ioo 0 s' := by + rcases harr with ⟨h₀, h₁⟩ | ⟨h₀, h₁⟩ + · exact ⟨b.toOpenPartialHomeomorph, rfl, hbt, s, q, hs0, hsq, hq1, h₀, h₁⟩ + · obtain ⟨b₁, hb₁s, hb₁t, hb₁f⟩ := b.flip hbt + have himg₀ : b₁.toOpenPartialHomeomorph '' W₀ + = (fun y => 1 - y) '' (b.toOpenPartialHomeomorph '' W₀) := by + rw [← image_comp] + exact image_congr (fun x hx => hb₁f x (hW₀ hx)) + have himg₁ : b₁.toOpenPartialHomeomorph '' W₁ + = (fun y => 1 - y) '' (b.toOpenPartialHomeomorph '' W₁) := by + rw [← image_comp] + exact image_congr (fun x hx => hb₁f x (hW₁ hx)) + rw [h₀, reflect_image_Ioo_lower hs0 (hsq.trans hq1.le)] at himg₀ + rw [h₁, reflect_image_Ioo_upper hq1] at himg₁ + exact ⟨b₁.toOpenPartialHomeomorph, hb₁s, hb₁t, 1 - q, 1 - s, + tsub_pos_of_lt hq1, tsub_le_tsub_left hsq 1, tsub_lt_self one_pos hs0, + himg₀, himg₁⟩ + +/-- Normalize the two charts and orient their two overlap components oppositely. -/ +private lemma exists_oriented_charts {M : Type*} [TopologicalSpace M] [T2Space M] (a b : OChart M) (h : Overlap a.source b.source) (hdisc : ¬ IsConnected (a.source ∩ b.source)) : ∃ (A B : OpenPartialHomeomorph M NNReal) (W₀ W₁ : Set M) (r p s q : NNReal), @@ -205,8 +233,7 @@ private lemma exists_normalized_charts {M : Type*} [TopologicalSpace M] [T2Space A.source ∩ B.source = W₀ ∪ W₁ ∧ A '' W₀ = Ioo 0 r ∧ A '' W₁ = Ioo p 1 ∧ B '' W₀ = Ioo q 1 ∧ B '' W₁ = Ioo 0 s ∧ - 0 < r ∧ r ≤ p ∧ p < 1 ∧ r < 1 / 4 ∧ - 0 < s ∧ s ≤ q ∧ q < 1 ∧ s < 1 / 4 := by + 0 < r ∧ r ≤ p ∧ p < 1 ∧ 0 < s ∧ s ≤ q ∧ q < 1 := by have hane : a.source.Nonempty := h.1.mono inter_subset_left have hbne : b.source.Nonempty := h.1.mono inter_subset_right obtain ⟨a₀, ha₀s, ha₀t, -⟩ := a.rescale hane @@ -233,95 +260,91 @@ private lemma exists_normalized_charts {M : Type*} [TopologicalSpace M] [T2Space obtain ⟨s₁, q₀, hs₁0, hs₁q₀, hq₀1, harr⟩ := two_components_other_chart a₀.toOpenPartialHomeomorph b₀.toOpenPartialHomeomorph hb₀t haconn hab hcomp₀ hcomp₁ hne₀ hne₁ hdisj - -- Orient the `b`-side chart so that `W₀` is upper and `W₁` is lower. - have hBpick : ∃ B₁ : OpenPartialHomeomorph M NNReal, - B₁.source = b.source ∧ B₁.target = Ioo 0 1 ∧ - ∃ s₂ q₂ : NNReal, 0 < s₂ ∧ s₂ ≤ q₂ ∧ q₂ < 1 ∧ - B₁ '' W₀ = Ioo q₂ 1 ∧ B₁ '' W₁ = Ioo 0 s₂ := by - rcases harr with ⟨h₀, h₁⟩ | ⟨h₀, h₁⟩ - · exact ⟨b₀.toOpenPartialHomeomorph, hb₀s, hb₀t, s₁, q₀, hs₁0, hs₁q₀, hq₀1, h₀, h₁⟩ - · obtain ⟨b₁, hb₁s, hb₁t, hb₁f⟩ := b₀.flip hb₀t - have himg₀ : b₁.toOpenPartialHomeomorph '' W₀ - = (fun y => 1 - y) '' (b₀.toOpenPartialHomeomorph '' W₀) := by - rw [← image_comp] - exact image_congr (fun x hx => hb₁f x (hW₀S hx).2) - have himg₁ : b₁.toOpenPartialHomeomorph '' W₁ - = (fun y => 1 - y) '' (b₀.toOpenPartialHomeomorph '' W₁) := by - rw [← image_comp] - exact image_congr (fun x hx => hb₁f x (hW₁S hx).2) - rw [h₀, reflect_image_Ioo_lower hs₁0 (hs₁q₀.trans hq₀1.le)] at himg₀ - rw [h₁, reflect_image_Ioo_upper hq₀1] at himg₁ - exact ⟨b₁.toOpenPartialHomeomorph, hb₁s.trans hb₀s, hb₁t, 1 - q₀, 1 - s₁, - tsub_pos_of_lt hq₀1, tsub_le_tsub_left hs₁q₀ 1, tsub_lt_self one_pos hs₁0, - himg₀, himg₁⟩ - obtain ⟨B₁, hB₁s, hB₁t, s₂, q₂, hs₂0, hs₂q, hq₂1, himgB₀, himgB₁⟩ := hBpick - -- Möbius-shrink the `a`-side chart. - have hr₀1 : r₀ < 1 := lt_of_le_of_lt hr₀p hp₁1 - have hquarter : (0:NNReal) < 1 / 4 := by norm_num - obtain ⟨cA, hcA0, hcA⟩ := exists_mobiusFun_lt hr₀0 hr₀1 hquarter - obtain ⟨mA, hmAs, hmAt, hmAf, hmAlo, hmAhi⟩ := mobiusOPH' cA hcA0 - set A := a₀.toOpenPartialHomeomorph.trans mA with hAdef - have hAs : A.source = a.source := by - rw [hAdef, OpenPartialHomeomorph.trans_source, hmAs, ← ha₀s] - refine inter_eq_left.mpr fun x hx => ?_ - rw [mem_preimage, ← ha₀t] - exact a₀.toOpenPartialHomeomorph.map_source hx - have hAt : A.target = Ioo 0 1 := by - rw [hAdef, OpenPartialHomeomorph.trans_target, hmAt] - refine inter_eq_left.mpr fun y hy => ?_ - rw [mem_preimage, ha₀t, ← hmAs] - exact mA.map_target (by rw [hmAt]; exact hy) - have hr₀mem : r₀ ∈ Ioo (0:NNReal) 1 := ⟨hr₀0, hr₀1⟩ - have hp₁mem : p₁ ∈ Ioo (0:NNReal) 1 := ⟨lt_of_lt_of_le hr₀0 hr₀p, hp₁1⟩ - have himA₀ : A '' W₀ = Ioo 0 (mobiusFun cA r₀) := by - rw [hAdef, OpenPartialHomeomorph.coe_trans, image_comp, himgA₀] - exact hmAlo r₀ hr₀mem - have himA₁ : A '' W₁ = Ioo (mobiusFun cA p₁) 1 := by - rw [hAdef, OpenPartialHomeomorph.coe_trans, image_comp, himgA₁] - exact hmAhi p₁ hp₁mem - have hmonoA := mobiusFun_strictMonoOn cA hcA0 - have hrp' : mobiusFun cA r₀ ≤ mobiusFun cA p₁ := by - rcases eq_or_lt_of_le hr₀p with heq | hlt - · rw [heq] - · exact (hmonoA hr₀mem hp₁mem hlt).le - have hr'mem := mobiusFun_mem cA hcA0 hr₀mem - have hp'mem := mobiusFun_mem cA hcA0 hp₁mem - -- Möbius-shrink the `b`-side chart. - have hs₂1 : s₂ < 1 := lt_of_le_of_lt hs₂q hq₂1 - obtain ⟨cB, hcB0, hcB⟩ := exists_mobiusFun_lt hs₂0 hs₂1 hquarter - obtain ⟨mB, hmBs, hmBt, hmBf, hmBlo, hmBhi⟩ := mobiusOPH' cB hcB0 - set B := B₁.trans mB with hBdef - have hBs : B.source = b.source := by - rw [hBdef, OpenPartialHomeomorph.trans_source, hmBs, ← hB₁s] + obtain ⟨B₁, hB₁s, hB₁t, s₂, q₂, hs₂0, hs₂q, hq₂1, himgB₀, himgB₁⟩ := + exists_oriented_overlap_chart b₀ hb₀t W₀ W₁ + (fun x hx => (hW₀S hx).2) (fun x hx => (hW₁S hx).2) + s₁ q₀ hs₁0 hs₁q₀ hq₀1 harr + have hunion' : a₀.source ∩ B₁.source = W₀ ∪ W₁ := by rw [hB₁s]; exact hunion + exact ⟨a₀.toOpenPartialHomeomorph, B₁, W₀, W₁, r₀, p₁, s₂, q₂, + ha₀s, hB₁s.trans hb₀s, ha₀t, hB₁t, hunion', himgA₀, himgA₁, himgB₀, himgB₁, + hr₀0, hr₀p, hp₁1, hs₂0, hs₂q, hq₂1⟩ + +/-- Composing charts with the same unit-interval interface preserves both chart sets. -/ +private lemma unitInterval_trans_source_target {M : Type*} [TopologicalSpace M] + (X : OpenPartialHomeomorph M NNReal) (m : OpenPartialHomeomorph NNReal NNReal) + (hXt : X.target = Ioo 0 1) (hms : m.source = Ioo 0 1) (hmt : m.target = Ioo 0 1) : + (X.trans m).source = X.source ∧ (X.trans m).target = Ioo 0 1 := by + constructor + · rw [OpenPartialHomeomorph.trans_source, hms] refine inter_eq_left.mpr fun x hx => ?_ - rw [mem_preimage, ← hB₁t] - exact B₁.map_source hx - have hBt : B.target = Ioo 0 1 := by - rw [hBdef, OpenPartialHomeomorph.trans_target, hmBt] + rw [mem_preimage, ← hXt] + exact X.map_source hx + · rw [OpenPartialHomeomorph.trans_target, hmt] refine inter_eq_left.mpr fun y hy => ?_ - rw [mem_preimage, hB₁t, ← hmBs] - exact mB.map_target (by rw [hmBt]; exact hy) - have hs₂mem : s₂ ∈ Ioo (0:NNReal) 1 := ⟨hs₂0, hs₂1⟩ - have hq₂mem : q₂ ∈ Ioo (0:NNReal) 1 := ⟨lt_of_lt_of_le hs₂0 hs₂q, hq₂1⟩ - have himB₀ : B '' W₀ = Ioo (mobiusFun cB q₂) 1 := by - rw [hBdef, OpenPartialHomeomorph.coe_trans, image_comp, himgB₀] - exact hmBhi q₂ hq₂mem - have himB₁ : B '' W₁ = Ioo 0 (mobiusFun cB s₂) := by - rw [hBdef, OpenPartialHomeomorph.coe_trans, image_comp, himgB₁] - exact hmBlo s₂ hs₂mem - have hmonoB := mobiusFun_strictMonoOn cB hcB0 - have hsq' : mobiusFun cB s₂ ≤ mobiusFun cB q₂ := by - rcases eq_or_lt_of_le hs₂q with heq | hlt + rw [mem_preimage, hXt, ← hms] + exact m.map_target (by rw [hmt]; exact hy) + +/-- Möbius-shrink a chart's lower overlap below one quarter, retaining both end-segments. -/ +private lemma exists_shrunk_interval_chart {M : Type*} [TopologicalSpace M] + (X : OpenPartialHomeomorph M NNReal) (hXt : X.target = Ioo 0 1) + (W₀ W₁ : Set M) (r p : NNReal) + (himg₀ : X '' W₀ = Ioo 0 r) (himg₁ : X '' W₁ = Ioo p 1) + (hr0 : 0 < r) (hrp : r ≤ p) (hp1 : p < 1) : + ∃ (A : OpenPartialHomeomorph M NNReal) (r' p' : NNReal), + A.source = X.source ∧ A.target = Ioo 0 1 ∧ + A '' W₀ = Ioo 0 r' ∧ A '' W₁ = Ioo p' 1 ∧ + 0 < r' ∧ r' ≤ p' ∧ p' < 1 ∧ r' < 1 / 4 := by + have hr1 : r < 1 := lt_of_le_of_lt hrp hp1 + have hquarter : (0 : NNReal) < 1 / 4 := by norm_num + obtain ⟨c, hc0, hc⟩ := exists_mobiusFun_lt hr0 hr1 hquarter + obtain ⟨m, hms, hmt, hmf, hmlo, hmhi⟩ := mobiusOPH' c hc0 + set A := X.trans m with hAdef + obtain ⟨hAs, hAt⟩ := unitInterval_trans_source_target X m hXt hms hmt + have hrmem : r ∈ Ioo (0 : NNReal) 1 := ⟨hr0, hr1⟩ + have hpmem : p ∈ Ioo (0 : NNReal) 1 := ⟨lt_of_lt_of_le hr0 hrp, hp1⟩ + have himA₀ : A '' W₀ = Ioo 0 (mobiusFun c r) := by + rw [hAdef, OpenPartialHomeomorph.coe_trans, image_comp, himg₀] + exact hmlo r hrmem + have himA₁ : A '' W₁ = Ioo (mobiusFun c p) 1 := by + rw [hAdef, OpenPartialHomeomorph.coe_trans, image_comp, himg₁] + exact hmhi p hpmem + have hmono := mobiusFun_strictMonoOn c hc0 + have hrp' : mobiusFun c r ≤ mobiusFun c p := by + rcases eq_or_lt_of_le hrp with heq | hlt · rw [heq] - · exact (hmonoB hs₂mem hq₂mem hlt).le - have hs'mem := mobiusFun_mem cB hcB0 hs₂mem - have hq'mem := mobiusFun_mem cB hcB0 hq₂mem + · exact (hmono hrmem hpmem hlt).le + have hr'mem := mobiusFun_mem c hc0 hrmem + have hp'mem := mobiusFun_mem c hc0 hpmem + exact ⟨A, mobiusFun c r, mobiusFun c p, hAs, hAt, himA₀, himA₁, + hr'mem.1, hrp', hp'mem.2, hc⟩ + +/-- Normalize both charts to target `Ioo 0 1`, split the overlap into its two +components, orient the second chart so the component lower in `a` is upper in `b`, and +Möbius-shrink both charts so the lower end-segments sit below `1 / 4`. -/ +private lemma exists_normalized_charts {M : Type*} [TopologicalSpace M] [T2Space M] + (a b : OChart M) (h : Overlap a.source b.source) + (hdisc : ¬ IsConnected (a.source ∩ b.source)) : + ∃ (A B : OpenPartialHomeomorph M NNReal) (W₀ W₁ : Set M) (r p s q : NNReal), + A.source = a.source ∧ B.source = b.source ∧ + A.target = Ioo 0 1 ∧ B.target = Ioo 0 1 ∧ + A.source ∩ B.source = W₀ ∪ W₁ ∧ + A '' W₀ = Ioo 0 r ∧ A '' W₁ = Ioo p 1 ∧ + B '' W₀ = Ioo q 1 ∧ B '' W₁ = Ioo 0 s ∧ + 0 < r ∧ r ≤ p ∧ p < 1 ∧ r < 1 / 4 ∧ + 0 < s ∧ s ≤ q ∧ q < 1 ∧ s < 1 / 4 := by + obtain ⟨A₀, B₀, W₀, W₁, r₀, p₀, s₀, q₀, hA₀s, hB₀s, hA₀t, hB₀t, + hunion, himgA₀, himgA₁, himgB₀, himgB₁, hr₀0, hr₀p, hp₀1, hs₀0, hs₀q, hq₀1⟩ := + exists_oriented_charts a b h hdisc + obtain ⟨A, r, p, hAs, hAt, himA₀, himA₁, hr0, hrp, hp1, hr4⟩ := + exists_shrunk_interval_chart A₀ hA₀t W₀ W₁ r₀ p₀ himgA₀ himgA₁ hr₀0 hr₀p hp₀1 + obtain ⟨B, s, q, hBs, hBt, himB₁, himB₀, hs0, hsq, hq1, hs4⟩ := + exists_shrunk_interval_chart B₀ hB₀t W₁ W₀ s₀ q₀ himgB₁ himgB₀ hs₀0 hs₀q hq₀1 have hunion' : A.source ∩ B.source = W₀ ∪ W₁ := by - rw [hAs, hBs, ← ha₀s, ← hb₀s] + rw [hAs, hBs] exact hunion - exact ⟨A, B, W₀, W₁, mobiusFun cA r₀, mobiusFun cA p₁, mobiusFun cB s₂, mobiusFun cB q₂, - hAs, hBs, hAt, hBt, hunion', himA₀, himA₁, himB₀, himB₁, - hr'mem.1, hrp', hp'mem.2, hcA, hs'mem.1, hsq', hq'mem.2, hcB⟩ + exact ⟨A, B, W₀, W₁, r, p, s, q, hAs.trans hA₀s, hBs.trans hB₀s, + hAt, hBt, hunion', himA₀, himA₁, himB₀, himB₁, + hr0, hrp, hp1, hr4, hs0, hsq, hq1, hs4⟩ private theorem circle_overlap_membership {M : Type*} From 37c3f613a12f2c596d2bedcda8877ca2109041c1 Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Sat, 26 Sep 2026 17:30:19 +0000 Subject: [PATCH 13/16] refactor(OneManifold): unify bounded chart construction --- LeanPool/OneManifold/OneMfld/NiceCharts.lean | 93 +++----------------- 1 file changed, 13 insertions(+), 80 deletions(-) diff --git a/LeanPool/OneManifold/OneMfld/NiceCharts.lean b/LeanPool/OneManifold/OneMfld/NiceCharts.lean index 3f992ae127..2ccd7353fc 100644 --- a/LeanPool/OneManifold/OneMfld/NiceCharts.lean +++ b/LeanPool/OneManifold/OneMfld/NiceCharts.lean @@ -29,78 +29,19 @@ variable /-- Restrict a chart around the specified point to a bounded target. -/ noncomputable def improvedChart (φ : OpenPartialHomeomorph M NNReal) (x : M) (h : x ∈ φ.source) : { ψ : OpenPartialHomeomorph M NNReal | (x ∈ ψ.source ∧ Bornology.IsBounded ψ.target) } := by - let y := φ.toFun x - by_cases h0 : y > 0 - · let interval := Set.Ioo (y-1) (y+1) - let t := φ.target ∩ interval - let s := φ.symm '' t - let sOpen : IsOpen s := by - apply (OpenPartialHomeomorph.isOpen_symm_image_iff_of_subset_target φ (by exact - Set.inter_subset_left)).mpr - exact IsOpen.inter φ.open_target isOpen_Ioo - let φ' := φ.restrOpen s sOpen - use φ' - apply And.intro - · dsimp [φ'] - simp only [Set.mem_inter_iff] - apply And.intro - · exact h - · dsimp [s] - simp only [Set.mem_image] - use y - apply And.intro - · apply Set.mem_inter - · exact PartialEquiv.map_source φ.toPartialEquiv h - · apply Set.mem_Ioo.mpr - apply And.intro - · refine NNReal.coe_lt_coe.mp ?_ - simp only [NNReal.coe_lt_coe, tsub_lt_self_iff, zero_lt_one, and_true] - exact h0 - · simp only [lt_add_iff_pos_right, zero_lt_one] - · exact OpenPartialHomeomorph.left_inv φ h - · have bi : Bornology.IsBounded interval := Metric.isBounded_Ioo (y - 1) (y + 1) - apply Bornology.IsBounded.subset bi - intro z hz - have hz' : z ∈ φ.target ∩ ↑φ.symm ⁻¹' (↑φ.symm '' t) := hz - rw [restrOpen_symm_image_target φ (t := t) Set.inter_subset_left] at hz' - exact Set.mem_of_mem_inter_right hz' - · simp only [gt_iff_lt, not_lt, nonpos_iff_eq_zero] at h0 - let interval := Set.Iio (1 : NNReal) - let t := φ.target ∩ interval - let s := φ.symm '' t - let sOpen : IsOpen s := by - apply (OpenPartialHomeomorph.isOpen_symm_image_iff_of_subset_target φ (by exact - Set.inter_subset_left)).mpr - exact IsOpen.inter φ.open_target isOpen_Iio - let φ' := φ.restrOpen s sOpen - use φ' - apply And.intro - · dsimp [φ'] - simp only [Set.mem_inter_iff] - apply And.intro - · exact h - · dsimp [s] - simp only [Set.mem_image] - use y - apply And.intro - · apply Set.mem_inter - · exact PartialEquiv.map_source φ.toPartialEquiv h - · exact Set.mem_Iio.mpr (by - rw [h0] - exact zero_lt_one' NNReal) - · exact OpenPartialHomeomorph.left_inv φ h - · have bi : Bornology.IsBounded interval := by - have : interval = Set.Ico 0 1 := by - dsimp [interval] - ext z - simp only [Set.mem_Iio, Set.mem_Ico, zero_le, true_and] - rw [this] - exact Metric.isBounded_Ico 0 1 - apply Bornology.IsBounded.subset bi - intro z hz - have hz' : z ∈ φ.target ∩ ↑φ.symm ⁻¹' (↑φ.symm '' t) := hz - rw [restrOpen_symm_image_target φ (t := t) Set.inter_subset_left] at hz' - exact Set.mem_of_mem_inter_right hz' + let y := φ x + let t := φ.target ∩ Set.Iio (y + 1) + let s := φ.symm '' t + have sOpen : IsOpen s := + (φ.isOpen_symm_image_iff_of_subset_target Set.inter_subset_left).mpr + (φ.open_target.inter isOpen_Iio) + refine ⟨φ.restrOpen s sOpen, ?_, ?_⟩ + · exact ⟨h, ⟨y, ⟨φ.map_source h, lt_add_one y⟩, φ.left_inv h⟩⟩ + · apply (Metric.isBounded_Ico (0 : NNReal) (y + 1)).subset + intro z hz + have hz' : z ∈ φ.target ∩ ↑φ.symm ⁻¹' (↑φ.symm '' t) := hz + rw [restrOpen_symm_image_target φ (t := t) Set.inter_subset_left] at hz' + exact ⟨zero_le, hz'.2⟩ /-- Restrict a bounded chart to the connected component containing the specified point. -/ noncomputable def improvedChart' (φ : OpenPartialHomeomorph M NNReal) (x : M) (h : x ∈ φ.source) @@ -174,14 +115,6 @@ lemma nice_chart_connected {φ : OpenPartialHomeomorph M NNReal} {x : M} {h : x rw [←this] exact c.2.2.2 -/-- A chart around a specified point with bounded connected target. -/ -structure NiceChartAt (x : M) where - /-- The local chart containing the specified point. -/ - chart : OpenPartialHomeomorph M NNReal - mem_chart_source : x ∈ chart.source - bounded : Bornology.IsBounded chart.target - connected : ConnectedSpace chart.target - /-- A charted space whose atlas has bounded connected targets. -/ class NicelyChartedSpace (H : Type*) [TopologicalSpace H] [Bornology H] (M : Type*) [TopologicalSpace M] extends ChartedSpace H M where From cbfb3413d36873744a7b58e628d4e557dd0776a8 Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Sun, 27 Sep 2026 14:37:29 +0000 Subject: [PATCH 14/16] Reuse canonical NNReal and unit-interval interfaces --- .../OneManifold/OneMfld/CircleBlocks.lean | 2 +- LeanPool/OneManifold/OneMfld/CircleGlue.lean | 8 +- .../OneManifold/OneMfld/ClassifyInterval.lean | 85 ++++--------------- .../OneManifold/OneMfld/ClassifyOverlaps.lean | 4 +- LeanPool/OneManifold/OneMfld/Compactness.lean | 64 +++----------- LeanPool/OneManifold/OneMfld/GlueBlocks.lean | 4 +- .../OneManifold/OneMfld/TwoComponents.lean | 1 - .../OneManifold/OneMfld/UnitInterval.lean | 10 +-- 8 files changed, 42 insertions(+), 136 deletions(-) diff --git a/LeanPool/OneManifold/OneMfld/CircleBlocks.lean b/LeanPool/OneManifold/OneMfld/CircleBlocks.lean index 37c9845025..97c84be78f 100644 --- a/LeanPool/OneManifold/OneMfld/CircleBlocks.lean +++ b/LeanPool/OneManifold/OneMfld/CircleBlocks.lean @@ -277,7 +277,7 @@ lemma addCircle_arc_isOpen (c d : ℝ) : QuotientAddGroup.isOpenMap_coe _ isOpen_Ioo /-- The frontier of a closed arc is contained in its two endpoints. -/ -lemma addCircle_frontier_arc_subset {c d : ℝ} (hcd : c ≤ d) : +lemma addCircle_frontier_arc_subset {c d : ℝ} : frontier (((↑) : ℝ → AddCircle (1:ℝ)) '' Icc c d) ⊆ {((c : ℝ) : AddCircle (1:ℝ)), ((d : ℝ) : AddCircle (1:ℝ))} := by have hclosed := addCircle_arc_isClosed c d diff --git a/LeanPool/OneManifold/OneMfld/CircleGlue.lean b/LeanPool/OneManifold/OneMfld/CircleGlue.lean index 27ddbf1aa0..dddd0d3ebb 100644 --- a/LeanPool/OneManifold/OneMfld/CircleGlue.lean +++ b/LeanPool/OneManifold/OneMfld/CircleGlue.lean @@ -217,8 +217,8 @@ private lemma exists_oriented_overlap_chart {M : Type*} [TopologicalSpace M] = (fun y => 1 - y) '' (b.toOpenPartialHomeomorph '' W₁) := by rw [← image_comp] exact image_congr (fun x hx => hb₁f x (hW₁ hx)) - rw [h₀, reflect_image_Ioo_lower hs0 (hsq.trans hq1.le)] at himg₀ - rw [h₁, reflect_image_Ioo_upper hq1] at himg₁ + rw [h₀, reflect_image_Ioo_lower (hsq.trans hq1.le)] at himg₀ + rw [h₁, reflect_image_Ioo_upper] at himg₁ exact ⟨b₁.toOpenPartialHomeomorph, hb₁s, hb₁t, 1 - q, 1 - s, tsub_pos_of_lt hq1, tsub_le_tsub_left hsq 1, tsub_lt_self one_pos hs0, himg₀, himg₁⟩ @@ -245,7 +245,7 @@ private lemma exists_oriented_charts {M : Type*} [TopologicalSpace M] [T2Space M have hbconn : IsConnected b₀.source := b₀.connected_source (hb₀s ▸ hbne) obtain ⟨W₀, W₁, r₀, p₁, hunion, hcomp₀, hcomp₁, hdisj, himgA₀, himgA₁, hr₀0, hr₀p, hp₁1⟩ := two_components_structure a₀.toOpenPartialHomeomorph b₀.toOpenPartialHomeomorph - ha₀t hbconn hab hba hne hdisc' + ha₀t hbconn hba hne hdisc' have hW₀S : W₀ ⊆ a₀.source ∩ b₀.source := by rw [hunion]; exact subset_union_left have hW₁S : W₁ ⊆ a₀.source ∩ b₀.source := by rw [hunion]; exact subset_union_right have hne₀ : W₀.Nonempty := by @@ -992,7 +992,7 @@ private lemma circle_chart_of_normalized {M : Type*} [TopologicalSpace M] [T2Spa {((kα * ((A m₀ : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ)), ((kα * ((ν : NNReal):ℝ) : ℝ) : AddCircle (1 : ℝ))} := by rw [htsetdef] - exact addCircle_frontier_arc_subset hc₁d₁ + exact addCircle_frontier_arc_subset exact glue_circle_arcs A B W₀ W₁ r p hAt himgA₀ himgA₁ hW₀A hW₀B hW₁A hW₁B ν hpν m₁ hm₁ν μ m₀ hm₀μ hm₀A hm₀B hm₁A hm₁B hρmem kα kg g0 hkα1 hkg1 hid1 hid2 hcg0 hg0d h1c hc₁0 hd₁kα hc₁1 hc₁d₁ e e' heval he'val hes he's htargetE htargetE' sset tset hssub H claim1 H' hfrontier diff --git a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean index 5719230c6e..560c966b33 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean @@ -323,69 +323,25 @@ noncomputable def homeoNnrealReal : (Set.Ioi 0 : Set NNReal) ≃ₜ (Set.univ : apply Continuous.rexp exact continuous_subtype_val -/-- Truncate a real number at zero and regard the result as a nonnegative real. -/ -def relu (x : ℝ) : NNReal := - NNReal.mk (max x 0) (by simp) +/-- Compatibility name for Mathlib's truncation to the nonnegative reals. -/ +abbrev relu : ℝ → NNReal := Real.toNNReal -lemma relu_zero : (relu 0 = 0) := by - have : max (0 : Real) (0 : Real) = (0 : Real) := by exact max_self 0 - dsimp [relu] - simp only [max_self, NNReal.mk_zero] +lemma relu_zero : relu 0 = 0 := Real.toNNReal_zero -theorem continuous_relu : Continuous relu := by - apply Continuous.subtype_mk - apply Continuous.max - · exact continuous_id' - exact continuous_const +theorem continuous_relu : Continuous relu := continuous_real_toNNReal +lemma proj_relu {x : ℝ} (h : x > 0) : (relu x).toReal = x := + Real.coe_toNNReal x h.le -lemma proj_relu {x : ℝ} (h : x > 0) : (relu x).toReal = x := by - have : max x 0 = x := max_eq_left_of_lt h - exact this +lemma proj_relu' {x : ℝ} (h : x ≤ 0) : (relu x).toReal = 0 := by + rw [relu, Real.toNNReal_of_nonpos h, NNReal.coe_zero] -lemma proj_relu' {x : ℝ} (h : x <= 0) : (relu x).toReal = 0 := by - have : 0 = max x 0 := right_eq_sup.mpr h - dsimp [relu] - rw [←this] - -lemma relu_proj {x : NNReal} : (relu x.toReal) = x := by - by_cases h0 : x = 0 - · rw [h0] - simp only [NNReal.coe_zero] - rw [relu_zero] - · have : x > 0 := by exact pos_iff_ne_zero.mpr h0 - refine NNReal.eq ?_ - rw [proj_relu] - exact this +lemma relu_proj {x : NNReal} : relu x.toReal = x := Real.toNNReal_coe lemma relu_mono : StrictMonoOn relu (Set.Ici 0) := by intro x hx y hy h - simp only [mem_Ici] at hx - simp only [mem_Ici] at hy - apply NNReal.coe_lt_coe.mp - by_cases hx0 : x = 0 - · rw [hx0] - simp only [NNReal.coe_lt_coe] - by_cases hy0 : y = 0 - · rw [hy0] - simp only [lt_self_iff_false] - linarith - · have hy' : y > 0 := by linarith - apply NNReal.coe_lt_coe.mp - rw [proj_relu hy'] - rw [relu_zero] - simp only [NNReal.coe_zero] - assumption - · have hx' : x > 0 := by exact lt_of_le_of_ne hx fun a => hx0 (id (Eq.symm a)) - rw [proj_relu hx'] - by_cases hy0 : y = 0 - · rw [hy0] - rw [relu_zero] - simp only [NNReal.coe_zero, gt_iff_lt] - linarith - · have hy' : y > 0 := by linarith - rw [proj_relu hy'] - assumption + exact_mod_cast (show ((relu x : NNReal) : ℝ) < ((relu y : NNReal) : ℝ) by + simpa only [relu, Real.coe_toNNReal x hx, Real.coe_toNNReal y hy] using h) lemma relu_interval_ioo {U : Set NNReal} {a b : Real} (h : Ioo a b = relu ⁻¹' U) : (relu '' (Set.Ioo a b) = U) := by @@ -490,7 +446,7 @@ lemma relu_ioo (a b : Real) : apply Iff.intro · intro ⟨ y, ⟨ hay, hyb ⟩ , hyz ⟩ rw [←hyz] - dsimp [relu] + dsimp [relu, Real.toNNReal] simp only [gt_iff_lt] refine NNReal.coe_lt_coe.mp ?_ simp only [NNReal.coe_mk, lt_sup_iff, sup_lt_iff, lt_self_iff_false, and_false, or_false] @@ -548,7 +504,7 @@ lemma relu_iio (b : Real) : · intro ⟨ x, ⟨ hxb, hxz ⟩ ⟩ rw [←hxz] simp only [gt_iff_lt] - dsimp [relu] + dsimp [relu, Real.toNNReal] apply NNReal.coe_lt_coe.mp simp only [NNReal.coe_mk, lt_sup_iff, sup_lt_iff, lt_self_iff_false, and_false, or_false] apply And.intro @@ -880,16 +836,11 @@ lemma zero_in_open (a b : NNReal) (h : IsOpen ((Ioo a b) ∪ {0})) : a ≤ 0 ∧ rwa [U0] at openU' private theorem classify_nnreal_of_real_Ioo (U : Set NNReal) (hu : IsOpen U) - (hr : relu ⁻¹' (U ∩ Ioi 0) = Ioi (0 : ℝ) ∩ NNReal.toReal '' U) - (h0u0 : 0 ∉ U ∩ Ioi 0) (h0u' : 0 ∉ relu ⁻¹' (U ∩ Ioi 0)) (c : ∃ a b : ℝ, Ioo a b = relu ⁻¹' (U ∩ Ioi 0)) : (∃ x y, Set.Ioo x y = U) ∨ (∃ x : NNReal, Set.Iio x = U) ∨ (∃ x : NNReal, Set.Ioi x = U) ∨ U = univ := by let U0 := U ∩ Ioi 0 let U' := relu ⁻¹' U0 - change relu ⁻¹' U0 = Ioi (0 : ℝ) ∩ NNReal.toReal '' U at hr - change 0 ∉ U0 at h0u0 - change 0 ∉ U' at h0u' have hu0 : IsOpen U0 := hu.inter isOpen_Ioi change ∃ a b : ℝ, Ioo a b = U' at c rcases c with ⟨ a, b, c ⟩ @@ -1000,18 +951,16 @@ private theorem classify_nnreal_of_real_Ioo (U : Set NNReal) (hu : IsOpen U) rw [c'] simp only [lt_self_iff_false, not_false_eq_true, Ioo_eq_empty] -private theorem classify_nnreal_of_real_Ioi (U : Set NNReal) (hu : IsOpen U) (hc : IsConnected U) +private theorem classify_nnreal_of_real_Ioi (U : Set NNReal) (hc : IsConnected U) (hr : relu ⁻¹' (U ∩ Ioi 0) = Ioi (0 : ℝ) ∩ NNReal.toReal '' U) - (h0u0 : 0 ∉ U ∩ Ioi 0) (h0u' : 0 ∉ relu ⁻¹' (U ∩ Ioi 0)) + (h0u' : 0 ∉ relu ⁻¹' (U ∩ Ioi 0)) (c : ∃ a : ℝ, Ioi a = relu ⁻¹' (U ∩ Ioi 0)) : (∃ x y, Set.Ioo x y = U) ∨ (∃ x : NNReal, Set.Iio x = U) ∨ (∃ x : NNReal, Set.Ioi x = U) ∨ U = univ := by let U0 := U ∩ Ioi 0 let U' := relu ⁻¹' U0 change relu ⁻¹' U0 = Ioi (0 : ℝ) ∩ NNReal.toReal '' U at hr - change 0 ∉ U0 at h0u0 change 0 ∉ U' at h0u' - have hu0 : IsOpen U0 := hu.inter isOpen_Ioi change ∃ x : ℝ, Ioi x = U' at c rcases c with ⟨ x, c ⟩ by_cases h0 : x = 0 @@ -1304,7 +1253,7 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc rw [relu_zero] assumption rcases c with (c|c|c|c) - · exact classify_nnreal_of_real_Ioo U hu hr h0u0 h0u' c + · exact classify_nnreal_of_real_Ioo U hu c · rcases c with ⟨ x, hx ⟩ rw [hx] at h0u' simp only [mem_Iio, not_lt] at h0u' @@ -1317,7 +1266,7 @@ theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc have hc : x - 1 ∈ Set.Ioi 0 := by exact mem_of_mem_inter_left hxi simp only [mem_Ioi, sub_pos] at hc linarith - · exact classify_nnreal_of_real_Ioi U hu hc hr h0u0 h0u' c + · exact classify_nnreal_of_real_Ioi U hc hr h0u' c · exfalso have h0i : 0 ∉ Set.Ioi (0 : NNReal) := self_notMem_Ioi have this' : 0 ∈ U0 := by diff --git a/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean b/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean index 6e98e63003..2c01b46d0b 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyOverlaps.lean @@ -223,7 +223,7 @@ lemma OChart.exists_orient_lower (a : OChart M) (V : OpenPartialHomeomorph M NNR = (fun y => 1 - y) '' (a.toOpenPartialHomeomorph '' (a.source ∩ V.source)) := by rw [← image_comp] exact image_congr (fun x hx => ha'f x hx.1) - rw [himg, reflect_image_Ioo_upper hp1] at himg' + rw [himg, reflect_image_Ioo_upper] at himg' exact ⟨a', 1 - p, ha's, ha't, tsub_pos_of_lt hp1, tsub_lt_self one_pos hp0, himg'⟩ · -- lower case: already oriented have hr1' : r < 1 := by @@ -270,7 +270,7 @@ lemma OChart.exists_orient_upper (a : OChart M) (V : OpenPartialHomeomorph M NNR = (fun y => 1 - y) '' (a.toOpenPartialHomeomorph '' (a.source ∩ V.source)) := by rw [← image_comp] exact image_congr (fun x hx => ha'f x hx.1) - rw [himg, reflect_image_Ioo_lower hw0 hw1] at himg' + rw [himg, reflect_image_Ioo_lower hw1] at himg' exact ⟨a', 1 - w, ha's, ha't, tsub_pos_of_lt hw1', tsub_lt_self one_pos hw0, himg'⟩ end Orient diff --git a/LeanPool/OneManifold/OneMfld/Compactness.lean b/LeanPool/OneManifold/OneMfld/Compactness.lean index a8dfe3278b..1e1f83d94b 100644 --- a/LeanPool/OneManifold/OneMfld/Compactness.lean +++ b/LeanPool/OneManifold/OneMfld/Compactness.lean @@ -34,61 +34,25 @@ lemma noncompact_nnreal : NoncompactSpace NNReal := by have := not_compactSpace_NNReal exact not_compactSpace_iff.mp this -lemma noncompact_ioo' (x y : NNReal) (hxy : x < y) : NoncompactSpace (Set.Ioo x y) := by - let s := Set.Ioo x y - have h : ¬ CompactSpace s := by - by_contra h' - have hc : IsCompact s := by exact isCompact_iff_compactSpace.mpr h' - have hs : IsClosed s := by exact IsCompact.isClosed hc - have ho : IsOpen s := by exact isOpen_Ioo - have hn : Nonempty s := by exact Set.nonempty_Ioo_subtype hxy - have hc' := clopen_in_r s - apply hc' - constructor - · exact Set.nonempty_iff_ne_empty'.mp hn - · by_contra ha - rw [ha] at h' - have : ¬ IsCompact (Set.univ : Set NNReal) := by - have ht : ¬ CompactSpace (NNReal) := by - exact not_compactSpace_iff.mpr noncompact_nnreal - by_contra ht' - apply ht - exact { isCompact_univ := ht' } - apply this - exact isCompact_iff_compactSpace.mpr h' - exact ⟨ hs, ho ⟩ - exact not_compactSpace_iff.mp h +private lemma noncompact_open_nnreal (s : Set NNReal) (ho : IsOpen s) (hn : s.Nonempty) : + NoncompactSpace s := by + apply not_compactSpace_iff.mp + intro h + have hc := isCompact_iff_compactSpace.mpr h + rcases isClopen_iff.mp ⟨hc.isClosed, ho⟩ with he | hu + · exact hn.ne_empty he + · rw [hu] at hc + exact not_compactSpace_NNReal ⟨hc⟩ + +lemma noncompact_ioo' (x y : NNReal) (hxy : x < y) : NoncompactSpace (Set.Ioo x y) := + noncompact_open_nnreal _ isOpen_Ioo (Set.nonempty_Ioo.mpr hxy) lemma noncompact_ioo (x y : NNReal) (hxy : x < y) : ¬ CompactSpace (Set.Ioo x y) := by have h := noncompact_ioo' x y hxy exact not_compactSpace_iff.mpr h -lemma noncompact_iio' (x : NNReal) (hx : 0 < x) : NoncompactSpace (Set.Iio x) := by - let s := Set.Iio x - have h : ¬ CompactSpace s := by - by_contra h' - have hc : IsCompact s := by exact isCompact_iff_compactSpace.mpr h' - have hs : IsClosed s := by exact IsCompact.isClosed hc - have ho : IsOpen s := by exact isOpen_Iio - have hn : Nonempty s := by - apply nonempty_subtype.mpr - exact Exists.intro 0 hx - have hc' := clopen_in_r s - apply hc' - constructor - · exact Set.nonempty_iff_ne_empty'.mp hn - · by_contra ha - rw [ha] at h' - have : ¬ IsCompact (Set.univ : Set NNReal) := by - have ht : ¬ CompactSpace (NNReal) := by - exact not_compactSpace_iff.mpr noncompact_nnreal - by_contra ht' - apply ht - exact { isCompact_univ := ht' } - apply this - exact isCompact_iff_compactSpace.mpr h' - exact ⟨ hs, ho ⟩ - exact not_compactSpace_iff.mp h +lemma noncompact_iio' (x : NNReal) (hx : 0 < x) : NoncompactSpace (Set.Iio x) := + noncompact_open_nnreal _ isOpen_Iio ⟨0, hx⟩ lemma noncompact_iio (x : NNReal) (hx : 0 < x) : ¬ CompactSpace (Set.Iio x) := by have h:= noncompact_iio' x hx diff --git a/LeanPool/OneManifold/OneMfld/GlueBlocks.lean b/LeanPool/OneManifold/OneMfld/GlueBlocks.lean index e6f07e8002..ac7104ea52 100644 --- a/LeanPool/OneManifold/OneMfld/GlueBlocks.lean +++ b/LeanPool/OneManifold/OneMfld/GlueBlocks.lean @@ -193,7 +193,7 @@ lemma frontier_UIIic {c : ℝ} (h0 : 0 < c) (h1 : c < 1) : /-- Reflection `y ↦ 1 - y` sends the upper end-segment `Ioo p 1 ⊆ ℝ≥0` to the lower end-segment `Ioo 0 (1-p)`. -/ -lemma reflect_image_Ioo_upper {p : NNReal} (_hp : p < 1) : +lemma reflect_image_Ioo_upper {p : NNReal} : (fun y : NNReal => 1 - y) '' Ioo p 1 = Ioo 0 (1 - p) := by ext z constructor @@ -206,7 +206,7 @@ lemma reflect_image_Ioo_upper {p : NNReal} (_hp : p < 1) : /-- Reflection `y ↦ 1 - y` sends the lower end-segment `Ioo 0 q ⊆ ℝ≥0` (for `q ≤ 1`) to the upper end-segment `Ioo (1-q) 1`. -/ -lemma reflect_image_Ioo_lower {q : NNReal} (_hq0 : 0 < q) (hq1 : q ≤ 1) : +lemma reflect_image_Ioo_lower {q : NNReal} (hq1 : q ≤ 1) : (fun y : NNReal => 1 - y) '' Ioo 0 q = Ioo (1 - q) 1 := by ext z constructor diff --git a/LeanPool/OneManifold/OneMfld/TwoComponents.lean b/LeanPool/OneManifold/OneMfld/TwoComponents.lean index 6346a8e7ce..12be9db808 100644 --- a/LeanPool/OneManifold/OneMfld/TwoComponents.lean +++ b/LeanPool/OneManifold/OneMfld/TwoComponents.lean @@ -116,7 +116,6 @@ end-segment `Ioo 0 r` and one whose image is an upper end-segment `Ioo p 1`, wit theorem two_components_structure [T2Space M] (a b : OpenPartialHomeomorph M NNReal) (hat : a.target = Ioo 0 1) (hb : IsConnected b.source) - (_hab : (a.source \ b.source).Nonempty) (hba : (b.source \ a.source).Nonempty) (hne : (a.source ∩ b.source).Nonempty) (hdisc : ¬ IsConnected (a.source ∩ b.source)) : diff --git a/LeanPool/OneManifold/OneMfld/UnitInterval.lean b/LeanPool/OneManifold/OneMfld/UnitInterval.lean index 294796eb6f..73547b8534 100644 --- a/LeanPool/OneManifold/OneMfld/UnitInterval.lean +++ b/LeanPool/OneManifold/OneMfld/UnitInterval.lean @@ -7,7 +7,7 @@ module public import Mathlib.Tactic public import Mathlib.Topology.MetricSpace.Pseudo.Lemmas -public import Mathlib.Topology.Order.Compact +public import Mathlib.Topology.UnitInterval /-! @@ -21,7 +21,7 @@ Supporting results for the classification of compact one-dimensional manifolds. namespace OneMfld /-- The closed unit interval in the real line. -/ -def UnitInterval : Set Real := { x : Real | 0 ≤ x ∧ x ≤ 1 } +abbrev UnitInterval : Set Real := unitInterval /-- `UnitInterval` is definitionally `Set.Icc 0 1`; this bridge unlocks Mathlib's `Icc` API (e.g. `iccHomeoI`, `isCompact_Icc`) for it. -/ @@ -31,10 +31,4 @@ lemma isCompact_UnitInterval : IsCompact UnitInterval := by rw [UnitInterval_eq_Icc] exact isCompact_Icc -instance : CompactSpace UnitInterval := - isCompact_iff_compactSpace.mp isCompact_UnitInterval - -instance : Nonempty UnitInterval := - ⟨⟨0, le_refl 0, zero_le_one⟩⟩ - end OneMfld From 6e34500bfb84b872f25d81b5135491b81307c131 Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Sun, 27 Sep 2026 17:42:38 +0000 Subject: [PATCH 15/16] Share chart transitions and classify NNReal intervals directly --- .../OneManifold/OneMfld/ClassifyInterval.lean | 550 ++---------------- LeanPool/OneManifold/OneMfld/GlueCore.lean | 94 ++- .../OneManifold/OneMfld/TwoComponents.lean | 33 +- 3 files changed, 83 insertions(+), 594 deletions(-) diff --git a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean index 560c966b33..9ba0664367 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean @@ -720,75 +720,12 @@ lemma remove_zero_connected (U : Set NNReal) (h0 : 0 ∈ U) (hu : IsOpen U) (hc apply NNReal.coe_ne_zero.mp simp only [NNReal.coe_mk, ne_eq, div_eq_zero_iff, OfNat.ofNat_ne_zero, or_false] exact ne_of_gt εpos - · dsimp [IsPreconnected] - by_contra h - simp only [not_forall] at h - rcases h with ⟨ A, B, openA, openB, hAB, hA, hB, hn ⟩ - have hp : IsPreconnected U := IsConnected.isPreconnected hc - let interval := Set.Ioo (0 : NNReal) (NNReal.mk ε (by linarith)) - have h1' : interval ⊆ A ∪ B := by - intro x hx - apply hAB - simp only [mem_sdiff, mem_singleton_iff] - apply And.intro - · apply hε - simp only [Metric.mem_ball] - simp only [interval, mem_Ioo] at hx - rw [NNReal.dist_eq] - simp only [NNReal.coe_zero, sub_zero, NNReal.abs_eq] - exact hx.right - · by_contra h0 - rw [h0] at hx - simp only [interval, mem_Ioo, lt_self_iff_false, false_and] at hx - have cb : IsPreconnected interval := isPreconnected_Ioo - specialize cb A B openA openB h1' - have iu : interval ⊆ U := by - intro x hx - simp only [interval, mem_Ioo] at hx - apply hε - simp only [Metric.mem_ball] - rw [NNReal.dist_eq] - simp only [NNReal.coe_zero, sub_zero, NNReal.abs_eq] - exact hx.right - have hn' : ¬ (interval ∩ (A ∩ B)).Nonempty := by - by_contra hn'' - rcases hn'' with ⟨ x, hn'' ⟩ - apply hn - use x - apply (mem_inter_iff x (U \ {0}) (A ∩ B)).mpr - apply And.intro - · apply mem_sdiff_singleton.mpr - apply And.intro - · have : x ∈ interval := by exact mem_of_mem_inter_left hn'' - apply iu - assumption - · have : x ∈ interval := by exact mem_of_mem_inter_left hn'' - by_contra x0 - rw [x0] at this - simp only [interval, mem_Ioo, lt_self_iff_false, false_and] at this - · exact mem_of_mem_inter_right hn'' - have empty : (¬ (interval ∩ A).Nonempty ∨ ¬ (interval ∩ B).Nonempty) := by tauto - apply hn - rcases empty with (empty|empty) - · have h1'' : interval ⊆ B ∪ A := by - intro x hx - simp only [mem_union] - specialize h1' hx - simp only [mem_union] at h1' - tauto - have hBA : U \ {0} ⊆ B ∪ A := by - intro x hx - simp only [mem_union] - specialize hAB hx - simp only [mem_union] at hAB - tauto - have := a_and_b U ε εpos B A openB openA hp interval (by exact rfl) h1'' empty hB hA hBA - rcases this with ⟨ x, hx ⟩ - use x - simp only [mem_inter_iff] - simp only [mem_inter_iff] at hx - tauto - · exact a_and_b U ε εpos A B openA openB hp interval (by exact rfl) h1' empty hA hB hAB + · have hset : U \ {0} = U ∩ Ioi 0 := by + ext x + simp only [mem_sdiff, mem_singleton_iff, mem_inter_iff, mem_Ioi, + pos_iff_ne_zero] + rw [hset] + exact (hc.isPreconnected.ordConnected.inter ordConnected_Ioi).isPreconnected lemma zero_in_open (a b : NNReal) (h : IsOpen ((Ioo a b) ∪ {0})) : a ≤ 0 ∧ 0 < b := by by_contra h' @@ -835,448 +772,47 @@ lemma zero_in_open (a b : NNReal) (h : IsOpen ((Ioo a b) ∪ {0})) : a ≤ 0 ∧ apply this rwa [U0] at openU' -private theorem classify_nnreal_of_real_Ioo (U : Set NNReal) (hu : IsOpen U) - (c : ∃ a b : ℝ, Ioo a b = relu ⁻¹' (U ∩ Ioi 0)) : - (∃ x y, Set.Ioo x y = U) ∨ (∃ x : NNReal, Set.Iio x = U) ∨ - (∃ x : NNReal, Set.Ioi x = U) ∨ U = univ := by - let U0 := U ∩ Ioi 0 - let U' := relu ⁻¹' U0 - have hu0 : IsOpen U0 := hu.inter isOpen_Ioi - change ∃ a b : ℝ, Ioo a b = U' at c - rcases c with ⟨ a, b, c ⟩ - have c' := relu_ioo a b - have hc := relu_interval_ioo c - rw [hc] at c' - by_cases hu0' : 0 ∈ U - · have uu0 : U = U0 ∪ { 0 } := by - ext x - simp only [union_singleton, mem_insert_iff] - apply Iff.intro - · intro hx - dsimp [U0] - simp only [mem_inter_iff, mem_Ioi] - by_cases h : x = 0 - · left; exact h - · right; apply And.intro - · assumption - · exact pos_iff_ne_zero.mpr h - · intro hx - rcases hx with (hx|hx) - · rw [hx] - assumption - · dsimp [U0] at hx - simp only [mem_inter_iff, mem_Ioi] at hx - exact hx.1 - rw [uu0] - rcases c' with (c'|c'|c'|c') - · right - left - rw [c'] - rw [c'] at uu0 - rw [uu0] at hu - have hz := zero_in_open (relu a) (relu b) hu - use relu b - ext x - simp only [mem_Iio, union_singleton, mem_insert_iff, mem_Ioo] - apply Iff.intro - · intro hx - by_cases h0 : x = 0 - · left; exact h0 - · right - apply And.intro - · have : 0 < x := by exact pos_iff_ne_zero.mpr h0 - exact lt_of_le_of_lt hz.1 this - · assumption - · intro hx - rcases hx with (hx|hx) - · rw [hx] - exact hz.2 - · exact hx.2 - · by_cases hb : relu b = 0 - · rw [hb] at c' - simp only [lt_self_iff_false, not_false_eq_true, Ico_eq_empty] at c' - rw [c'] at uu0 - simp only [union_singleton, insert_empty_eq] at uu0 - rw [uu0] at hu - have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 - exfalso - exact this hu - · right - left - use relu b - rw [c'] - ext x - simp only [mem_Iio, union_singleton, mem_insert_iff, mem_Ico, zero_le, true_and, - iff_or_self] - intro hx - rw [hx] - exact pos_iff_ne_zero.mpr hb - · rw [c'] at hu0 - exfalso - have this' : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 - exact this' hu0 - · rw [c'] at uu0 - simp only [union_singleton, insert_empty_eq] at uu0 - have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 - rw [uu0] at hu - exfalso - exact this hu - · have uu0 : U = U0 := by - dsimp [U0] - simp only [left_eq_inter] - intro x hx - simp only [mem_Ioi] - have : x ≠ 0 := by exact ne_of_mem_of_not_mem hx hu0' - exact pos_iff_ne_zero.mpr this - rw [←uu0] at c' - rcases c' with (c'|c'|c'|c') - · left - use relu a - use relu b - rw [c'] - · right - left - use (relu b) - rw [c'] - ext x - simp only [mem_Iio, mem_Ico, zero_le, true_and] - · rw [c'] at hu - exfalso - have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 - apply this - exact hu - · left - use 0 - use 0 - rw [c'] - simp only [lt_self_iff_false, not_false_eq_true, Ioo_eq_empty] - -private theorem classify_nnreal_of_real_Ioi (U : Set NNReal) (hc : IsConnected U) - (hr : relu ⁻¹' (U ∩ Ioi 0) = Ioi (0 : ℝ) ∩ NNReal.toReal '' U) - (h0u' : 0 ∉ relu ⁻¹' (U ∩ Ioi 0)) - (c : ∃ a : ℝ, Ioi a = relu ⁻¹' (U ∩ Ioi 0)) : - (∃ x y, Set.Ioo x y = U) ∨ (∃ x : NNReal, Set.Iio x = U) ∨ - (∃ x : NNReal, Set.Ioi x = U) ∨ U = univ := by - let U0 := U ∩ Ioi 0 - let U' := relu ⁻¹' U0 - change relu ⁻¹' U0 = Ioi (0 : ℝ) ∩ NNReal.toReal '' U at hr - change 0 ∉ U' at h0u' - change ∃ x : ℝ, Ioi x = U' at c - rcases c with ⟨ x, c ⟩ - by_cases h0 : x = 0 - · by_cases hu0 : 0 ∈ U - · right; right; right - rw [h0] at c - dsimp [U'] at c - ext z - simp only [mem_univ, iff_true] - by_cases hz0 : z = 0 - · rw [hz0] - assumption - · have zpos : z > 0 := by - exact pos_iff_ne_zero.mpr hz0 - have zi : z ∈ Set.Ioi 0 := by exact zpos - have zi' : NNReal.toReal z ∈ relu ⁻¹' U0 := by - rw [←c] - simp only [mem_Ioi, NNReal.coe_pos] - assumption - simp only [mem_preimage] at zi' - rw [relu_proj] at zi' - exact mem_of_mem_inter_left zi' - · right; right; left - use 0 - have uu0 : U = U0 := by - ext z - apply Iff.intro - · intro hz - dsimp [U0] - simp only [mem_inter_iff, mem_Ioi] - apply And.intro - · exact hz - · have : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 - exact pos_iff_ne_zero.mpr this - · intro hz - exact mem_of_mem_inter_left hz - rw [uu0] - rw [h0] at c - ext z - simp only [mem_Ioi] - apply Iff.intro - · intro hz - have : NNReal.toReal z > 0 := by exact hz - have this' : NNReal.toReal z ∈ U' := by - rw [←c] - simp only [mem_Ioi, NNReal.coe_pos] - assumption - dsimp [U'] at this' - simp only [mem_preimage] at this' - rw [relu_proj] at this' - assumption - · intro hz - rw [←uu0] at hz - have : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 - exact pos_iff_ne_zero.mpr this - · by_cases hx : x < 0 - · have : 0 ∈ U' := by - have this' : 0 ∈ Set.Ioi x := by exact hx - rw [c] at this' - assumption - exfalso - exact h0u' this - · right; right; left - by_cases hu0 : 0 ∈ U - · have : U = U0 ∪ {0} := by - ext z - simp only [union_singleton, mem_insert_iff] - apply Iff.intro - · intro hz - by_cases hz' : z = 0 - · left; assumption - · right - dsimp [U0] - refine (mem_inter_iff z U (Ioi 0)).mpr ?_ - apply And.intro - · assumption - · simp only [mem_Ioi] - exact pos_iff_ne_zero.mpr hz' - · intro hz - rcases hz with (hz|hz) - · rw [hz] - assumption - · exact mem_of_mem_inter_left hz - dsimp [U'] at c - rw [hr] at c - have contra : ¬ IsConnected U := by - dsimp [IsConnected] - simp only [not_and] - intro hn - dsimp [IsPreconnected] - simp only [not_forall] - have xpos : x ≥ 0 := by linarith - use Set.Iio (NNReal.mk x xpos) - use Set.Ioi (NNReal.mk x xpos) - simp only [exists_prop, Iio_union_Ioi, subset_compl_singleton_iff] - apply And.intro - · exact isOpen_Iio - · apply And.intro - · exact isOpen_Ioi - · apply And.intro - · by_contra h - have h' : NNReal.toReal (NNReal.mk x xpos) ∈ NNReal.toReal '' U := - mem_image_of_mem NNReal.toReal h - have h'' : NNReal.toReal (NNReal.mk x xpos) ∈ Set.Ioi 0 := by - apply mem_Ioi.mpr - exact lt_of_le_of_ne xpos fun a => h0 (id (Eq.symm a)) - have h3 : NNReal.toReal (NNReal.mk x xpos) ∈ Set.Ioi x := by - rw [c] - exact mem_inter h'' h' - simp only [NNReal.coe_mk, mem_Ioi, lt_self_iff_false] at h3 - · apply And.intro - · use 0 - simp only [mem_inter_iff, mem_Iio] - apply And.intro - · assumption - · apply NNReal.coe_pos.mp - simp only [NNReal.coe_mk] - exact lt_of_le_of_ne xpos fun a => h0 (id (Eq.symm a)) - · apply And.intro - · apply inter_nonempty.mpr - use (1 : NNReal) + (NNReal.mk x xpos) - apply And.intro - · have : 1 + x ∈ Set.Ioi x := by - apply mem_Ioi.mpr - exact lt_one_add x - rw [c] at this - simp only [mem_inter_iff, mem_Ioi, mem_image] at this - rcases this with ⟨ tpos, ⟨ t, ⟨ tu, ht ⟩ ⟩ ⟩ - have ht2 : t = 1 + (NNReal.mk x xpos) := by - exact NNReal.eq ht - rw [←ht2] - assumption - · apply mem_Ioi.mpr - exact lt_one_add ((NNReal.mk x xpos) : NNReal) - · refine not_nonempty_iff_eq_empty.mpr ?_ - let x' : NNReal := (NNReal.mk x xpos) - have : (Set.Iio x' ∩ Set.Ioi x') = ∅ := by - ext z - simp only [mem_inter_iff, mem_Iio, mem_Ioi, mem_empty_iff_false, - iff_false, not_and, not_lt] - intro hz - exact le_of_lt hz - rw [this] - simp only [inter_empty] - exfalso - exact contra hc - · have h0' : 0 ∉ Set.Ioi x := by exact Eq.mpr_not (congrFun c 0) h0u' - simp only [mem_Ioi, not_lt] at h0' - use (NNReal.mk x h0') - ext z - simp only [mem_Ioi] - apply Iff.intro - · intro hxz - have hu' : NNReal.toReal z ∈ U' := by - rw [←c] - simp only [mem_Ioi] - exact hxz - have : NNReal.toReal z ∈ Ioi 0 ∩ NNReal.toReal '' U := by - rw [←hr] - exact hu' - have this' : NNReal.toReal z ∈ NNReal.toReal '' U := mem_of_mem_inter_right this - simp only [mem_image, NNReal.coe_inj, exists_eq_right] at this' - assumption - · intro hz - apply NNReal.coe_lt_coe.mp - simp only [NNReal.coe_mk] - dsimp [U'] at c - have z0 : z ∈ U0 := by - refine (mem_inter_iff z U (Ioi 0)).mpr ?_ - apply And.intro - · exact hz - · refine mem_Ioi.mpr ?_ - refine NNReal.coe_pos.mp ?_ - simp only [NNReal.coe_pos] - have hz0 : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 - exact pos_iff_ne_zero.mpr hz0 - have : NNReal.toReal z ∈ Set.Ioi 0 ∩ NNReal.toReal '' U := by - simp only [mem_inter_iff, mem_Ioi, NNReal.coe_pos, mem_image, NNReal.coe_inj, - exists_eq_right] - apply And.intro - · have : z ≠ 0 := by exact ne_of_mem_of_not_mem hz hu0 - have this' : z ≥ 0 := by exact zero_le - exact pos_iff_ne_zero.mpr this - assumption - rw [←hr] at this - rw [←c] at this - simp only [mem_Ioi] at this - assumption - theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc : IsConnected U) : (∃ x y, (Set.Ioo x y = U)) ∨ (∃ (x : NNReal), (Set.Iio x = U)) ∨ (∃ (x : NNReal), (Set.Ioi x = U)) ∨ (U = univ) := by - let U0 := U ∩ (Set.Ioi 0) - have hu0 : IsOpen U0 := IsOpen.inter hu isOpen_Ioi - let U' := relu ⁻¹' U0 - have hr : (relu ⁻¹' U0) = (Set.Ioi (0 : Real)) ∩ (NNReal.toReal '' U) := by - ext x - simp only [mem_preimage, mem_inter_iff, mem_Ioi, mem_image] - constructor - · intro h - have : U0 ⊆ Set.Ioi 0 := inter_subset_right - have hr : relu x ∈ Set.Ioi 0 := this h - simp at hr - have hr' : 0 < x := Real.toNNReal_pos.mp (this h) - constructor - · exact hr' - · use relu x - constructor - · have : U0 ⊆ U := by exact inter_subset_left - exact this h - · have hf : (relu x).1 = x := by - apply proj_relu - assumption - assumption - · rintro ⟨h1,⟨y,⟨hu,hy⟩⟩⟩ - rw [←hy] - rw [relu_proj] - apply mem_inter hu - rw [←hy] at h1 - exact h1 - have hu' : IsOpen U' := Continuous.isOpen_preimage continuous_relu U0 hu0 - have hc' : IsConnected U' := by - by_cases h0 : 0 ∈ U - · dsimp [U'] - rw [hr] - have hs0 : IsConnected (U \ {0}) := by exact remove_zero_connected U h0 hu hc - have he : (Ioi 0 ∩ NNReal.toReal '' U) = NNReal.toReal '' (U \ {0}) := by - ext z - simp only [mem_inter_iff, mem_Ioi, mem_image, mem_sdiff, mem_singleton_iff] - apply Iff.intro - · intro ⟨ zpos, ⟨ x, ⟨ hx, hx' ⟩ ⟩ ⟩ - use x - apply And.intro - · apply And.intro - · assumption - · by_contra h' - rw [h'] at hx' - simp only [NNReal.coe_zero] at hx' - rw [←hx'] at zpos - exact (lt_self_iff_false 0).mp zpos - · assumption - · intro ⟨ x, ⟨ ⟨ h1, h2 ⟩, h3 ⟩ ⟩ - apply And.intro - · rw [←h3] - simp only [NNReal.coe_pos] - exact pos_iff_ne_zero.mpr h2 - · use x - rw [he] - have : Continuous NNReal.toReal := by exact NNReal.continuous_coe - apply IsConnected.image hs0 NNReal.toReal - apply Continuous.continuousOn - exact this - · have he : U' = NNReal.toReal '' U := by - ext z - simp only [mem_image] - apply Iff.intro - · intro hz - dsimp [U'] at hz - rw [hr] at hz - simp only [mem_inter_iff, mem_Ioi, mem_image] at hz - rcases hz with ⟨ hzpos, hz ⟩ - assumption - · rintro ⟨ x, ⟨ hx, hz ⟩ ⟩ - apply mem_preimage.mpr - rw [←hz] - rw [relu_proj] - dsimp [U0] - simp only [mem_inter_iff, mem_Ioi] - apply And.intro - · assumption - · have : x ≥ 0 := by exact zero_le - have this' : x ≠ 0 := by exact ne_of_mem_of_not_mem hx h0 - exact pos_iff_ne_zero.mpr this' - rw [he] - apply IsConnected.image hc NNReal.toReal - have : Continuous NNReal.toReal := by exact NNReal.continuous_coe - apply Continuous.continuousOn - assumption - let c := classify_connected_interval U' hu' hc' - have h0u0 : 0 ∉ U0 := by - apply zero_notMem_iff.mpr - intro z hz - have : z ∈ Set.Ioi (0 : NNReal) := mem_of_mem_inter_right hz - exact this - have h0u' : 0 ∉ U' := by - dsimp [U'] - simp only [mem_preimage] - rw [relu_zero] - assumption - rcases c with (c|c|c|c) - · exact classify_nnreal_of_real_Ioo U hu c - · rcases c with ⟨ x, hx ⟩ - rw [hx] at h0u' - simp only [mem_Iio, not_lt] at h0u' - dsimp [U'] at hx - rw [hr] at hx - have hxi : x - 1 ∈ Set.Iio x := by - apply mem_Iio.mpr - linarith - rw [←hx] at hxi - have hc : x - 1 ∈ Set.Ioi 0 := by exact mem_of_mem_inter_left hxi - simp only [mem_Ioi, sub_pos] at hc - linarith - · exact classify_nnreal_of_real_Ioi U hc hr h0u' c - · exfalso - have h0i : 0 ∉ Set.Ioi (0 : NNReal) := self_notMem_Ioi - have this' : 0 ∈ U0 := by - have : 0 ∈ U' := by - rw [c] - exact trivial - dsimp [U'] at this - simp only [mem_preimage] at this - rw [relu_zero] at this - assumption - exact h0u0 this' + have hzeroInterval : Ici (0 : NNReal) = univ := by + ext x + simp only [mem_Ici, zero_le, mem_univ] + have h := hc.isPreconnected.mem_intervals + simp only [mem_insert_iff, mem_singleton_iff] at h + rcases h with h | h | h | h | h | h | h | h | h | h + · have hi := (congrArg interior h).symm.trans hu.interior_eq + rw [← Ici_inter_Iic, interior_inter, interior_Iic] at hi + by_cases hzero : sInf U = 0 + · exact Or.inr (Or.inl ⟨sSup U, by simpa only [hzero, hzeroInterval, interior_univ, + univ_inter] using hi⟩) + · rw [interior_Ici' ⟨0, pos_iff_ne_zero.mpr hzero⟩, Ioi_inter_Iio] at hi + exact Or.inl ⟨sInf U, sSup U, hi⟩ + · have hi := (congrArg interior h).symm.trans hu.interior_eq + rw [← Ici_inter_Iio, interior_inter, interior_Iio] at hi + by_cases hzero : sInf U = 0 + · exact Or.inr (Or.inl ⟨sSup U, by simpa only [hzero, hzeroInterval, interior_univ, + univ_inter] using hi⟩) + · rw [interior_Ici' ⟨0, pos_iff_ne_zero.mpr hzero⟩, Ioi_inter_Iio] at hi + exact Or.inl ⟨sInf U, sSup U, hi⟩ + · have hi := (congrArg interior h).symm.trans hu.interior_eq + rw [interior_Ioc] at hi + exact Or.inl ⟨sInf U, sSup U, hi⟩ + · exact Or.inl ⟨sInf U, sSup U, h.symm⟩ + · have hi := (congrArg interior h).symm.trans hu.interior_eq + by_cases hzero : sInf U = 0 + · exact Or.inr (Or.inr (Or.inr (by simpa only [hzero, hzeroInterval, + interior_univ] using hi.symm))) + · rw [interior_Ici' ⟨0, pos_iff_ne_zero.mpr hzero⟩] at hi + exact Or.inr (Or.inr (Or.inl ⟨sInf U, hi⟩)) + · exact Or.inr (Or.inr (Or.inl ⟨sInf U, h.symm⟩)) + · have hi := (congrArg interior h).symm.trans hu.interior_eq + rw [interior_Iic] at hi + exact Or.inr (Or.inl ⟨sSup U, hi⟩) + · exact Or.inr (Or.inl ⟨sSup U, h.symm⟩) + · exact Or.inr (Or.inr (Or.inr h)) + · exact (hc.nonempty.ne_empty h).elim end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/GlueCore.lean b/LeanPool/OneManifold/OneMfld/GlueCore.lean index 07281150f9..c3ad1454d0 100644 --- a/LeanPool/OneManifold/OneMfld/GlueCore.lean +++ b/LeanPool/OneManifold/OneMfld/GlueCore.lean @@ -54,6 +54,34 @@ theorem chartTransition_continuous_injective · intro x hx y hy hxy exact a.symm.injOn (hI hx) (hI hy) (b.injOn (hmap x hx) (hmap y hy) hxy) +/-- On a common source subset, chart transitions preserve coordinates and map the +first chart image exactly onto the second. -/ +theorem chartTransition_image_data + (a b : OpenPartialHomeomorph M NNReal) {W : Set M} + (hW : W ⊆ a.source ∩ b.source) {I J : Set NNReal} + (ha : a '' W = I) (hb : b '' W = J) : + (∀ t ∈ I, a.symm t ∈ W ∧ a (a.symm t) = t) ∧ + (∀ x ∈ W, b (a.symm (a x)) = b x) ∧ + I ⊆ a.target ∧ (fun t => b (a.symm t)) '' I = J := by + have hsymm : ∀ t ∈ I, a.symm t ∈ W ∧ a (a.symm t) = t := by + rintro t ht + obtain ⟨x, hx, rfl⟩ := ha.symm ▸ ht + rw [a.left_inv (hW hx).1] + exact ⟨hx, rfl⟩ + have hkey : ∀ x ∈ W, b (a.symm (a x)) = b x := by + intro x hx + rw [a.left_inv (hW hx).1] + refine ⟨hsymm, hkey, ?_, ?_⟩ + · rintro t ht + obtain ⟨x, hx, rfl⟩ := ha.symm ▸ ht + exact a.map_source (hW hx).1 + · apply subset_antisymm + · rintro _ ⟨t, ht, rfl⟩ + exact hb ▸ mem_image_of_mem b (hsymm t ht).1 + · rintro y hy + obtain ⟨x, hx, rfl⟩ := hb.symm ▸ hy + exact ⟨a x, ha ▸ mem_image_of_mem a hx, hkey x hx⟩ + /-- A transition limit at interior chart endpoints identifies their inverse images. -/ theorem chartTransition_endpoint_eq [T2Space M] (a b : OpenPartialHomeomorph M NNReal) {I : Set NNReal} {s t : NNReal} @@ -123,48 +151,23 @@ theorem overlap_mono_on [T2Space M] (a b : OpenPartialHomeomorph M NNReal) (hr : r ∈ a.target) (hq : q ∈ b.target) (hrS : r ∉ a '' (a.source ∩ b.source)) : ∀ x ∈ W, ∀ y ∈ W, a x < a y → b x < b y := by - have hWa : W ⊆ a.source := hW.trans inter_subset_left have hWb : W ⊆ b.source := hW.trans inter_subset_right have hacoord : ∀ x ∈ W, a x ∈ Ioo p r := fun x hx => ha ▸ mem_image_of_mem a hx by_cases hpr : p < r swap · intro x hx y hy hxy exact absurd ((hacoord x hx).1.trans (hacoord x hx).2) hpr - set τ : NNReal → NNReal := fun t => b (a.symm t) with hτdef - have hsymm : ∀ t ∈ Ioo p r, a.symm t ∈ W ∧ a (a.symm t) = t := by - intro t ht - rw [← ha] at ht - obtain ⟨x, hxW, rfl⟩ := ht - rw [a.left_inv (hWa hxW)] - exact ⟨hxW, rfl⟩ - have hkey : ∀ x ∈ W, τ (a x) = b x := by - intro x hx - simp only [hτdef] - rw [a.left_inv (hWa hx)] - have hτmaps : ∀ t ∈ Ioo p r, τ t ∈ Ioo q w := by - intro t ht - have hb' : b (a.symm t) ∈ b '' W := mem_image_of_mem b (hsymm t ht).1 - exact hb ▸ hb' - have hIoo_target : Ioo p r ⊆ a.target := by - rw [← ha] - rintro y ⟨z, hz, rfl⟩ - exact a.map_source (hWa hz) + let τ : NNReal → NNReal := fun t => b (a.symm t) + obtain ⟨hsymm, hkey, hIoo_target, himg⟩ := + chartTransition_image_data a b (hW) ha hb obtain ⟨hcont, hinj⟩ : ContinuousOn τ (Ioo p r) ∧ InjOn τ (Ioo p r) := chartTransition_continuous_injective a b hIoo_target (fun t ht => hWb (hsymm t ht).1) rcases strictMonoOn_or_strictAntiOn_of_injOn_Ioo hcont hinj with hmono | hanti · intro x hx y hy hxy have h := hmono (hacoord x hx) (hacoord y hy) hxy - rwa [hkey x hx, hkey y hy] at h + simpa only [τ, hkey x hx, hkey y hy] using h · exfalso - have himg : τ '' Ioo p r = Ioo q w := by - apply subset_antisymm - · rintro _ ⟨t, ht, rfl⟩ - exact hτmaps t ht - · intro y hy - rw [← hb] at hy - obtain ⟨x, hxW, rfl⟩ := hy - exact ⟨a x, hacoord x hxW, hkey x hxW⟩ have hτlim : Tendsto τ (𝓝[<] r) (𝓝 q) := tendsto_top_of_strictAntiOn_image hpr hanti himg have hF : 𝓝[Ioo p r] r = 𝓝[<] r := nhdsWithin_Ioo_eq_nhdsLT hpr @@ -209,45 +212,20 @@ theorem overlap_anti [T2Space M] (a b : OpenPartialHomeomorph M NNReal) ∀ x ∈ a.source ∩ b.source, ∀ y ∈ a.source ∩ b.source, a x < a y → b y < b x := by set S := a.source ∩ b.source with hSdef - have hSa : S ⊆ a.source := inter_subset_left have hSb : S ⊆ b.source := inter_subset_right have hacoord : ∀ x ∈ S, a x ∈ Ioo p r := fun x hx => ha ▸ mem_image_of_mem a hx by_cases hpr : p < r swap · intro x hx y hy hxy exact absurd ((hacoord x hx).1.trans (hacoord x hx).2) hpr - set τ : NNReal → NNReal := fun t => b (a.symm t) with hτdef - have hsymm : ∀ t ∈ Ioo p r, a.symm t ∈ S ∧ a (a.symm t) = t := by - intro t ht - rw [← ha] at ht - obtain ⟨x, hxS, rfl⟩ := ht - rw [a.left_inv (hSa hxS)] - exact ⟨hxS, rfl⟩ - have hkey : ∀ x ∈ S, τ (a x) = b x := by - intro x hx - simp only [hτdef] - rw [a.left_inv (hSa hx)] - have hτmaps : ∀ t ∈ Ioo p r, τ t ∈ Ioo q w := by - intro t ht - have hb' : b (a.symm t) ∈ b '' S := mem_image_of_mem b (hsymm t ht).1 - exact hb ▸ hb' - have hIoo_target : Ioo p r ⊆ a.target := by - rw [← ha] - rintro y ⟨z, hz, rfl⟩ - exact a.map_source (hSa hz) + let τ : NNReal → NNReal := fun t => b (a.symm t) + obtain ⟨hsymm, hkey, hIoo_target, himg⟩ := + chartTransition_image_data a b (Subset.refl _) ha hb obtain ⟨hcont, hinj⟩ : ContinuousOn τ (Ioo p r) ∧ InjOn τ (Ioo p r) := chartTransition_continuous_injective a b hIoo_target (fun t ht => hSb (hsymm t ht).1) rcases strictMonoOn_or_strictAntiOn_of_injOn_Ioo hcont hinj with hmono | hanti · exfalso - have himg : τ '' Ioo p r = Ioo q w := by - apply subset_antisymm - · rintro _ ⟨t, ht, rfl⟩ - exact hτmaps t ht - · intro y hy - rw [← hb] at hy - obtain ⟨x, hxS, rfl⟩ := hy - exact ⟨a x, hacoord x hxS, hkey x hxS⟩ have hτlim : Tendsto τ (𝓝[>] p) (𝓝 q) := tendsto_bot_of_strictMonoOn_image hpr hmono himg have hF : 𝓝[Ioo p r] p = 𝓝[>] p := nhdsWithin_Ioo_eq_nhdsGT hpr @@ -268,6 +246,6 @@ theorem overlap_anti [T2Space M] (a b : OpenPartialHomeomorph M NNReal) exact lt_irrefl p hp'.1 · intro x hx y hy hxy have h := hanti (hacoord x hx) (hacoord y hy) hxy - rwa [hkey x hx, hkey y hy] at h + simpa only [τ, hkey x hx, hkey y hy] using h end OneMfld diff --git a/LeanPool/OneManifold/OneMfld/TwoComponents.lean b/LeanPool/OneManifold/OneMfld/TwoComponents.lean index 12be9db808..25a1ae68ea 100644 --- a/LeanPool/OneManifold/OneMfld/TwoComponents.lean +++ b/LeanPool/OneManifold/OneMfld/TwoComponents.lean @@ -50,48 +50,23 @@ theorem overlap_mono_on' [T2Space M] (a b : OpenPartialHomeomorph M NNReal) (hp : p ∈ a.target) (hw : w ∈ b.target) (hpS : p ∉ a '' (a.source ∩ b.source)) : ∀ x ∈ W, ∀ y ∈ W, a x < a y → b x < b y := by - have hWa : W ⊆ a.source := hW.trans inter_subset_left have hWb : W ⊆ b.source := hW.trans inter_subset_right have hacoord : ∀ x ∈ W, a x ∈ Ioo p r := fun x hx => ha ▸ mem_image_of_mem a hx by_cases hpr : p < r swap · intro x hx y hy hxy exact absurd ((hacoord x hx).1.trans (hacoord x hx).2) hpr - set τ : NNReal → NNReal := fun t => b (a.symm t) with hτdef - have hsymm : ∀ t ∈ Ioo p r, a.symm t ∈ W ∧ a (a.symm t) = t := by - intro t ht - rw [← ha] at ht - obtain ⟨x, hxW, rfl⟩ := ht - rw [a.left_inv (hWa hxW)] - exact ⟨hxW, rfl⟩ - have hkey : ∀ x ∈ W, τ (a x) = b x := by - intro x hx - simp only [hτdef] - rw [a.left_inv (hWa hx)] - have hτmaps : ∀ t ∈ Ioo p r, τ t ∈ Ioo q w := by - intro t ht - have hb' : b (a.symm t) ∈ b '' W := mem_image_of_mem b (hsymm t ht).1 - exact hb ▸ hb' - have hIoo_target : Ioo p r ⊆ a.target := by - rw [← ha] - rintro y ⟨z, hz, rfl⟩ - exact a.map_source (hWa hz) + let τ : NNReal → NNReal := fun t => b (a.symm t) + obtain ⟨hsymm, hkey, hIoo_target, himg⟩ := + chartTransition_image_data a b (hW) ha hb obtain ⟨hcont, hinj⟩ : ContinuousOn τ (Ioo p r) ∧ InjOn τ (Ioo p r) := chartTransition_continuous_injective a b hIoo_target (fun t ht => hWb (hsymm t ht).1) rcases strictMonoOn_or_strictAntiOn_of_injOn_Ioo hcont hinj with hmono | hanti · intro x hx y hy hxy have h := hmono (hacoord x hx) (hacoord y hy) hxy - rwa [hkey x hx, hkey y hy] at h + simpa only [τ, hkey x hx, hkey y hy] using h · exfalso - have himg : τ '' Ioo p r = Ioo q w := by - apply subset_antisymm - · rintro _ ⟨t, ht, rfl⟩ - exact hτmaps t ht - · intro y hy - rw [← hb] at hy - obtain ⟨x, hxW, rfl⟩ := hy - exact ⟨a x, hacoord x hxW, hkey x hxW⟩ have hτlim : Tendsto τ (𝓝[>] p) (𝓝 w) := tendsto_bot_of_strictAntiOn_image hpr hanti himg have hF : 𝓝[Ioo p r] p = 𝓝[>] p := nhdsWithin_Ioo_eq_nhdsGT hpr From e0d3e8cca6eece3c95aad0c7dcebe1e06d3eb660 Mon Sep 17 00:00:00 2001 From: Vasily Ilin Date: Sun, 27 Sep 2026 17:57:25 +0000 Subject: [PATCH 16/16] Remove obsolete one-manifold interval proof chain --- .../OneManifold/OneMfld/ClassifyInterval.lean | 758 +----------------- 1 file changed, 3 insertions(+), 755 deletions(-) diff --git a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean index 9ba0664367..6af9625c3a 100644 --- a/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean +++ b/LeanPool/OneManifold/OneMfld/ClassifyInterval.lean @@ -5,773 +5,21 @@ Authors: Jim Fowler, Dennis Sweeney -/ module -public import Mathlib.Algebra.Order.Star.Real -public import Mathlib.Analysis.InnerProductSpace.Basic -public import Mathlib.Analysis.SpecialFunctions.Log.Basic -public import Mathlib.Order.CompletePartialOrder -public import Mathlib.Tactic - +public import Mathlib.Topology.Instances.NNReal.Lemmas +public import Mathlib.Topology.Order.IntermediateValue /-! # ClassifyInterval -Supporting results for the classification of compact one-dimensional manifolds. +Classification of connected open subsets of the nonnegative real numbers. -/ @[expose] public section namespace OneMfld -open Function open Set -theorem ici_cap_iio_empty (y : Real) : (Ici y ∩ Iio y) = ∅ := by - have h' : Ici y ∩ Iio y = Ico y y := rfl - rw [h'] - simp only [lt_self_iff_false, not_false_eq_true, Ico_eq_empty] - -theorem iic_cap_ioi_empty (y : Real) : (Iic y ∩ Ioi y) = ∅ := by - have h' : Iic y ∩ Ioi y = Ioc y y := Iic_inter_Ioi - rw [h'] - simp only [lt_self_iff_false, not_false_eq_true, Ioc_eq_empty] - -theorem not_ici (U : Set Real) (y : Real) (hu : IsOpen U) : (Ici y ≠ U) := by - by_contra h - rw [←h] at hu - have h''' : IsClosed (Ici y) := by - apply isClosed_Ici - have ho : IsOpen (Ici y)ᶜ - · exact IsClosed.isOpen_compl - have hr : IsPreconnected (univ : Set Real) := isPreconnected_univ - let hr' := hr (Ici y) ((Ici y)ᶜ) hu ho - have huniv : Ici y ∪ (Ici y)ᶜ = univ := union_compl_self (Ici y) - rw [huniv] at hr' - simp only [subset_refl, univ_inter, nonempty_Ici, compl_Ici, nonempty_Iio, forall_const] at hr' - rw [ici_cap_iio_empty] at hr' - apply Set.not_nonempty_empty - exact hr' - -theorem not_iic (U : Set Real) (y : Real) (hu : IsOpen U) : (Iic y ≠ U) := by - by_contra h - rw [←h] at hu - have h''' : IsClosed (Iic y) := by - apply isClosed_Iic - have ho : IsOpen (Iic y)ᶜ - · exact IsClosed.isOpen_compl - have hr : IsPreconnected (univ : Set Real) := isPreconnected_univ - let hr' := hr (Iic y) ((Iic y)ᶜ) hu ho - have huniv : Iic y ∪ (Iic y)ᶜ = univ := union_compl_self (Iic y) - rw [huniv] at hr' - simp only [subset_refl, univ_inter, nonempty_Iic, compl_Iic, nonempty_Ioi, forall_const] at hr' - rw [iic_cap_ioi_empty] at hr' - apply Set.not_nonempty_empty - exact hr' - -lemma ioc_not_open (x y : Real) (hxy : x < y) : ¬ IsOpen (Ioc x y) := by - have hu : (Ioc x y) ∪ (Iio y) = (Iic y) - · ext p - simp only [mem_union, mem_Ioc, mem_Iio, mem_Iic] - apply Iff.intro - · intro h - rcases h with (h1|h2) - · tauto - · exact le_of_lt h2 - by_cases hp : p = y - · intro h - rw [hp] - simp only [le_refl, and_true, lt_self_iff_false, or_false] - exact hxy - intro h - right - exact lt_of_le_of_ne h hp - by_contra hopen - have hopen' : IsOpen (Iio y) := isOpen_Iio - have hopen'' : IsOpen (Iic y) - · rw [←hu] - exact IsOpen.union hopen hopen' - have hc : IsOpen ((Iic y)ᶜ) - · simp only [compl_Iic] - exact isOpen_Ioi - have hcon := isPreconnected_univ (Iic y) ((Iic y)ᶜ) hopen'' hc - (by simp only [compl_Iic, Iic_union_Ioi, subset_refl]) - (by simp only [univ_inter, nonempty_Iic]) - (by simp only [compl_Iic, univ_inter, nonempty_Ioi]) - simp only [compl_Iic, univ_inter] at hcon - rcases hcon with ⟨x,hx⟩ - simp at hx - linarith - -lemma ico_not_open (x y : Real) (hxy : x < y) : ¬ IsOpen (Ico x y) := by - have hxy' : -y < -x := neg_lt_neg_iff.mpr hxy - have hn := ioc_not_open (-y) (-x) hxy' - let f : Real → Real := fun x => - x - let fb : Bijective f := ⟨ neg_injective, neg_surjective ⟩ - let fe := Equiv.ofBijective f fb - have fc : Continuous fe := continuous_neg - have fo : IsOpenMap fe := isOpenMap_neg ℝ - have fh : Homeomorph Real Real - · apply Equiv.toHomeomorphOfContinuousOpen - · exact fc - exact fo - by_contra h - have p := fo (Ico x y) h - have he : fe '' (Ico x y) = Ioc (-y) (-x) - · ext t - have ht : ∀ s : Real, fe.symm (-s) = s := fun s => Equiv.ofBijective_symm_apply_apply f fb s - have ht' := ht (-t) - simp only [neg_neg] at ht' - simp only [mem_image_equiv, mem_Ico, mem_Ioc] - apply Iff.intro - · simp only [and_imp] - intro h1 h2 - constructor - · rw [ht'] at h1 - rw [ht'] at h2 - linarith - rw [ht'] at h1 - rw [ht'] at h2 - linarith - simp only [and_imp] - intro h1 h2 - rw [ht'] - constructor - · linarith - linarith - · rw [he] at p - exact hn p - -lemma icc_not_open (x y : Real) (hxy : x < y) : ¬ IsOpen (Icc x y) := by - by_contra h - have hc : IsClosed (Icc x y) := isClosed_Icc - have hc'' : IsOpen ((Icc x y)ᶜ) := IsClosed.isOpen_compl - have hcon := isPreconnected_univ (Icc x y) ((Icc x y)ᶜ) h hc'' - (by simp only [union_compl_self, subset_refl]) - (by simp only [univ_inter, nonempty_Icc] - linarith) - (by simp only [univ_inter] - have hy : ((y + 1) ∈ (Icc x y)ᶜ) - · simp only [mem_compl_iff, mem_Icc, add_le_iff_nonpos_right, not_and, not_le, - zero_lt_one, implies_true] - exact nonempty_of_mem hy) - simp only [inter_compl_self, inter_empty, Set.not_nonempty_empty] at hcon - -lemma not_ioc (U : Set Real) (x y : Real) (hu : IsOpen U) (h : Ioc x y = U) : (U = ∅) := by - by_cases hxy : (x < y) - · have h' : ¬ IsOpen (Ioc x y) - · apply ioc_not_open x y - exact hxy - exfalso - apply h' - rw [h] - tauto - · have h' : Ioc x y = ∅ - · exact Ioc_eq_empty hxy - rw [h] at h' - tauto - -theorem not_ico (U : Set Real) (x y : Real) (hu : IsOpen U) (h : Ico x y = U) : (U = ∅) := by - by_cases hxy : (x < y) - · have h' : ¬ IsOpen (Ico x y) - · apply ico_not_open x y - exact hxy - exfalso - apply h' - rw [h] - tauto - · have h' : Ico x y = ∅ - · exact Ico_eq_empty hxy - rw [h] at h' - tauto - -theorem not_icc (U : Set Real) (x y : Real) (hu : IsOpen U) (h : Icc x y = U) : (U = ∅) := by - by_cases hxy : (x < y) - · have h' : ¬ IsOpen (Icc x y) - · apply icc_not_open x y - exact hxy - exfalso - apply h' - rw [h] - tauto - · by_cases hyx : (x > y) - · have h' : Icc x y = ∅ - · exact Icc_eq_empty_of_lt hyx - rw [h] at h' - exact h' - · have hxy' : x ≥ y := le_of_not_gt hxy - have hyx' : x ≤ y := by exact le_of_not_gt hyx - have hxx : x = y - · have hxy'' : (x = y) ∨ (y < x) := eq_or_gt_of_not_lt hxy - have hyx'' : (x = y) ∨ (x < y) := by exact Or.symm (Decidable.lt_or_eq_of_le hyx') - rcases hyx'' with (h|h) - · exact h - tauto - rw [←hxx] at h - simp only [Icc_self] at h - rw [←h] at hu - exfalso - have c : ¬ IsOpen {x} := not_isOpen_singleton x - tauto - -theorem classify_intervals (U : Set Real) (hu : IsOpen U) (hc : IsPreconnected U) : - (∃ x y, (Set.Ioo x y = U)) ∨ - (∃ (x : Real), (U = Set.Iio x)) ∨ - (∃ (x : Real), (Set.Ioi x = U)) ∨ - (U = univ) ∨ (U = ∅) := by - have h : U ∈ (range (uncurry Icc)) ∪ range (uncurry Ico) ∪ range (uncurry Ioc) ∪ range - (uncurry Ioo) ∪ (range Ici ∪ range Ioi ∪ range Iic ∪ range Iio ∪ {univ, ∅}) - · rw [←setOfPred_isPreconnected_eq_of_ordered] - exact hc - simp only [union_insert, union_singleton, mem_insert_iff, mem_union, mem_range, Prod.exists, - uncurry_apply_pair] at h - cases h - case inl h => tauto - case inr h => - cases h - case inl h => tauto - case inr h => - cases h - case inr h => - cases h - case inl h => - cases h - case inr h => by_contra - rcases h with ⟨ x', hx ⟩ - apply not_iic - · exact hu - exact hx - case inl h => - cases h - case inr h => right; right; left; assumption - case inl h => by_contra - rcases h with ⟨ x', hx ⟩ - apply not_ici - · exact hu - exact hx - case inr h => tauto - case inl h => - cases h - case inr h => left; tauto - case inl h => - cases h - case inl h => - cases h - case inl h => rcases h with ⟨ x, y, hx ⟩ - right; right; right; right - apply not_icc - · exact hu - exact hx - case inr h => rcases h with ⟨ x, y, hx ⟩ - right; right; right; right - apply not_ico - · exact hu - exact hx - case inr h => rcases h with ⟨ x, y, hx ⟩ - right - right - right - right - apply not_ioc - · exact hu - exact hx - -/-- Select disjuncts repeatedly to reduce a nested disjunction to one of its branches. -/ -macro "solveDisj" : tactic => `(tactic| repeat (apply Or.inl <|> apply Or.inr)) - -theorem classify_connected_interval (U : Set Real) (hu : IsOpen U) (hc : IsConnected U) : - (∃ x y, (Set.Ioo x y = U)) ∨ - (∃ (x : Real), (U = Set.Iio x)) ∨ - (∃ (x : Real), (Set.Ioi x = U)) ∨ - (U = univ) := by - have hpc : IsPreconnected U := by exact IsConnected.isPreconnected hc - have hi := classify_intervals U hu hpc - have ho : ¬ (U = ∅) := by - by_contra hn - rw [hn] at hc - have he : (∅ : Set Real).Nonempty := IsConnected.nonempty hc - exact Set.not_nonempty_empty he - rcases hi with (h|h|h|h|h) - · left; assumption - · right; left; assumption - · right; right; left; assumption - · right; right; right; assumption - exfalso - exact ho h - -/-- The logarithm homeomorphism from positive nonnegative reals to the real line. -/ -noncomputable def homeoNnrealReal : (Set.Ioi 0 : Set NNReal) ≃ₜ (Set.univ : Set Real) where - toFun := fun ⟨x,_⟩ => ⟨ Real.log x, trivial ⟩ - invFun := fun ⟨x,_⟩ => ⟨ NNReal.mk (Real.exp x) (Real.exp_nonneg x), Real.exp_pos x ⟩ - left_inv := fun ⟨ ⟨ x, nn ⟩, p ⟩ => by - ext - simp only [NNReal.coe_mk] - exact Real.exp_log p - right_inv := fun x => by - simp only [NNReal.coe_mk, Real.log_exp, Subtype.coe_eta] - continuous_toFun := by - simp only - refine Continuous.subtype_mk ?_ fun x => trivial - refine Continuous.log ?_ ?_ - · exact Isometry.continuous fun x1 => congrFun rfl - intro x - rcases x with ⟨x,hx⟩ - simp only [ne_eq, NNReal.coe_eq_zero] - exact pos_iff_ne_zero.mp hx - continuous_invFun := by - simp only - apply Continuous.subtype_mk - apply Continuous.subtype_mk - apply Continuous.rexp - exact continuous_subtype_val - -/-- Compatibility name for Mathlib's truncation to the nonnegative reals. -/ -abbrev relu : ℝ → NNReal := Real.toNNReal - -lemma relu_zero : relu 0 = 0 := Real.toNNReal_zero - -theorem continuous_relu : Continuous relu := continuous_real_toNNReal - -lemma proj_relu {x : ℝ} (h : x > 0) : (relu x).toReal = x := - Real.coe_toNNReal x h.le - -lemma proj_relu' {x : ℝ} (h : x ≤ 0) : (relu x).toReal = 0 := by - rw [relu, Real.toNNReal_of_nonpos h, NNReal.coe_zero] - -lemma relu_proj {x : NNReal} : relu x.toReal = x := Real.toNNReal_coe - -lemma relu_mono : StrictMonoOn relu (Set.Ici 0) := by - intro x hx y hy h - exact_mod_cast (show ((relu x : NNReal) : ℝ) < ((relu y : NNReal) : ℝ) by - simpa only [relu, Real.coe_toNNReal x hx, Real.coe_toNNReal y hy] using h) - -lemma relu_interval_ioo {U : Set NNReal} {a b : Real} (h : Ioo a b = relu ⁻¹' U) : - (relu '' (Set.Ioo a b) = U) := by - apply subset_antisymm - · rintro _ ⟨y, hy, rfl⟩ - rw [h] at hy - exact hy - · intro x hx - refine ⟨(x : ℝ), ?_, relu_proj⟩ - rw [h] - simpa only [mem_preimage, relu_proj] using hx - -theorem StrictMonoOn.injOn_Ioo {α : Type u_1} {β : Type u_2} {f : α → β} - [LinearOrder α] [LinearOrder β] {a : α} {b : α} (h : StrictMonoOn f (Set.Icc a b)) : - InjOn f (Set.Ioo a b) := by - exact (h.mono Ioo_subset_Icc_self).injOn - -lemma relu_ioo (a b : Real) : - (relu '' (Set.Ioo a b) = Set.Ioo (relu a) (relu b)) ∨ - (relu '' (Set.Ioo a b) = Set.Ico 0 (relu b)) ∨ - (relu '' (Set.Ioo a b) = { 0 }) ∨ - (relu '' (Set.Ioo a b) = ∅) := by - by_cases ha : a > 0 - · by_cases hb : b > 0 - · left - ext z - simp only [mem_image, mem_Ioo] - constructor - · intro ⟨ x, ⟨ hx, hxz ⟩ ⟩ - have hax : relu a < relu x := by - apply NNReal.coe_lt_coe.mp - rw [proj_relu] - · rw [proj_relu] - · exact hx.1 - linarith - linarith - have hxb : relu x < relu b := by - apply NNReal.coe_lt_coe.mp - rw [proj_relu] - · rw [proj_relu] - · exact hx.2 - linarith - linarith - rw [hxz] at hax - rw [hxz] at hxb - exact ⟨hax, hxb⟩ - · intro ⟨ haz, hzb ⟩ - use z - rw [relu_proj] - simp only [and_true] - have haz' : NNReal.toReal (relu a) < NNReal.toReal z := by exact haz - have hzb' : NNReal.toReal z < NNReal.toReal (relu b) := by exact hzb - rw [proj_relu] at hzb' - · rw [proj_relu] at haz' - · exact ⟨haz', hzb'⟩ - exact ha - exact hb - · have : Ioo a b = ∅ := by - ext z - simp only [mem_Ioo, mem_empty_iff_false, iff_false, not_and, not_lt] - intro ha - linarith - rw [this] - simp only [image_empty] - simp only [or_true] - · by_cases hb : b > 0 - · by_cases ha0 : a = 0 - · rw [ha0] - left - ext z - simp only [mem_image, mem_Ioo] - apply Iff.intro - · intro ⟨ y, ⟨ h0y, hyb ⟩, hyz ⟩ - rw [←hyz] - apply And.intro - · rw [relu_zero] - have : 0 < NNReal.toReal (relu y) := by - rw [proj_relu] - · assumption - linarith - simp only [gt_iff_lt] - exact this - · have : NNReal.toReal (relu y) < NNReal.toReal (relu b) := by - rw [proj_relu] - · rw [proj_relu] - · assumption - linarith - linarith - exact this - · intro ⟨ h0z, hzb ⟩ - use z.toReal - apply And.intro - · apply And.intro - · simp only [NNReal.coe_pos] - exact pos_of_gt h0z - · have : NNReal.toReal z < NNReal.toReal (relu b) := by exact hzb - exact Real.lt_toNNReal_iff_coe_lt.mp hzb - · exact relu_proj - · right; left - ext z - simp only [mem_image, mem_Ioo, mem_Ico, zero_le, true_and] - apply Iff.intro - · intro ⟨ y, ⟨ hay, hyb ⟩ , hyz ⟩ - rw [←hyz] - dsimp [relu, Real.toNNReal] - simp only [gt_iff_lt] - refine NNReal.coe_lt_coe.mp ?_ - simp only [NNReal.coe_mk, lt_sup_iff, sup_lt_iff, lt_self_iff_false, and_false, or_false] - apply And.intro <;> linarith - · intro hzb - use NNReal.toReal z - apply And.intro - · apply And.intro - · have ha0' : a < 0 := by - simp only [gt_iff_lt, not_lt] at ha - exact lt_of_le_of_ne ha ha0 - have h0z : 0 ≤ (relu z) := by exact zero_le - have h0z' : a < relu z := by exact lt_of_le_of_lt' h0z ha0' - rw [relu_proj] at h0z' - assumption - · have : NNReal.toReal z < NNReal.toReal (relu b) := by exact hzb - rw [proj_relu] at this - · assumption - assumption - · rw [relu_proj] - · by_cases hab : a ≥ b - · have : Ioo a b = ∅ := by - exact Ioo_eq_empty_of_le hab - rw [this] - simp only [image_empty, or_true] - · right; right; left - ext z - simp only [mem_image, mem_Ioo, mem_singleton_iff] - constructor - · rintro ⟨ y, hy, hyz ⟩ - have : y ≤ 0 := by linarith - have h' := proj_relu' this - rw [hyz] at h' - exact NNReal.coe_eq_zero.mp h' - · intro hz - have hab' : a < b := by linarith - use (a + b) / 2 - apply And.intro - · apply And.intro - · exact left_lt_add_div_two.mpr hab' - · exact add_div_two_lt_right.mpr hab' - · have hn : (a + b) / 2 ≤ 0 := by linarith - rw [hz] - apply NNReal.coe_eq_zero.mp - exact proj_relu' hn - -lemma relu_iio (b : Real) : - ((relu '' (Set.Iio b) = Set.Ico 0 (relu b)) ∨ - (relu '' (Set.Iio b) = { 0 })) := by - by_cases hb : b > 0 - · left - ext z - simp only [mem_image, mem_Iio, mem_Ico, zero_le, true_and] - apply Iff.intro - · intro ⟨ x, ⟨ hxb, hxz ⟩ ⟩ - rw [←hxz] - simp only [gt_iff_lt] - dsimp [relu, Real.toNNReal] - apply NNReal.coe_lt_coe.mp - simp only [NNReal.coe_mk, lt_sup_iff, sup_lt_iff, lt_self_iff_false, and_false, or_false] - apply And.intro - · assumption - · assumption - · intro hzb - use z.1 - apply And.intro - · exact Nonneg.toNonneg_lt.mp hzb - · have : z ≥ 0 := by exact zero_le - simp only [NNReal.val_eq_coe] - exact relu_proj - · right - ext z - simp only [mem_image, mem_Iio, mem_singleton_iff] - apply Iff.intro - · intro ⟨ x, ⟨ hxb, hxz ⟩ ⟩ - have : x ≤ 0 := by linarith - have hn := proj_relu' this - rw [hxz] at hn - exact NNReal.coe_eq_zero.mp hn - · intro hz - use b - 1 - simp only [sub_lt_self_iff, zero_lt_one, true_and] - have : b - 1 ≤ 0 := by linarith - have hn := proj_relu' this - rw [hz] - simp only [NNReal.coe_eq_zero] at hn - assumption - -lemma relu_univ : (relu '' univ = univ) := by - ext z - simp only [image_univ, mem_range, mem_univ, iff_true] - use z.1 - apply relu_proj - -lemma relu_ioi (b : Real) : - ((relu '' (Set.Ioi b) = Set.Ioi (relu b)) ∨ - (relu '' (Set.Ioi b) = univ)) := by - by_cases hb : b > 0 - · left - ext z - simp only [mem_image, mem_Ioi] - apply Iff.intro - · intro ⟨ x, ⟨ hbx, hxz ⟩ ⟩ - rw [←hxz] - apply NNReal.coe_lt_coe.mp - rw [proj_relu, proj_relu] - · linarith - · linarith - linarith - · intro hbz - use z.1 - apply And.intro - · simp only [NNReal.val_eq_coe] - refine (Real.toNNReal_lt_iff_lt_coe ?_).mp hbz - linarith - · apply relu_proj - · by_cases hb' : b = 0 - · left - rw [hb'] - ext z - simp only [mem_image, mem_Ioi] - apply Iff.intro - · intro ⟨ x, ⟨ hbx, hxz ⟩ ⟩ - rw [relu_zero] - rw [←hxz] - apply NNReal.coe_pos.mp - rw [proj_relu] - · assumption - assumption - · intro hz - use z.1 - apply And.intro - · rw [relu_zero] at hz - exact hz - apply relu_proj - · right - ext z - simp only [mem_image, mem_Ioi, mem_univ, iff_true] - use z.1 - simp only [NNReal.val_eq_coe] - apply And.intro - · have : 0 ≤ NNReal.toReal z := by exact NNReal.zero_le_coe - have this' : b < 0 := by - simp only [gt_iff_lt, not_lt] at hb - exact lt_of_le_of_ne hb hb' - exact lt_of_le_of_lt' this this' - · exact relu_proj - -lemma a_and_b (U : Set NNReal) (ε : Real) (εpos : ε > 0) (A : Set NNReal) (B : Set NNReal) - (openA : IsOpen A) (openB : IsOpen B) - (hp : IsPreconnected U) - (interval : Set NNReal) - (interval_def : interval = Set.Ioo (0 : NNReal) (NNReal.mk ε (by linarith))) - (h1' : interval ⊆ A ∪ B) - (empty : ¬ (interval ∩ B).Nonempty) - (hA : (U \ {0} ∩ A).Nonempty) (hB : (U \ {0} ∩ B).Nonempty) - (hAB : U \ {0} ⊆ A ∪ B) : (U \ {0} ∩ (A ∩ B)).Nonempty := by - let interval' := Set.Iio (NNReal.mk ε (by linarith)) - let A' := A ∪ interval' - have openA' : IsOpen A' := by - apply IsOpen.union openA - exact isOpen_Iio - let B' := B ∩ Set.Ioi 0 - have openB' : IsOpen B' := by - exact IsOpen.inter openB isOpen_Ioi - specialize hp A' B' openA' openB' - have h1 : U ⊆ A' ∪ B' := by - intro x hx - by_cases h0' : x = 0 - · rw [h0'] - simp only [mem_union] - left - exact mem_union_right A εpos - · have : x ∈ U \ { 0 } := by exact mem_sdiff_of_mem hx h0' - specialize hAB this - simp only [mem_union] - rcases hAB with (hAB|hAB) - · left - exact mem_union_left interval' hAB - · right - apply (mem_inter_iff x B (Ioi 0)).mpr - apply And.intro - · assumption - · apply mem_Ioi.mpr - exact pos_iff_ne_zero.mpr h0' - have h2 : (U ∩ A').Nonempty := by - rcases hA with ⟨ x, hx ⟩ - use x - simp only [mem_inter_iff] - apply And.intro - · have : x ∈ U \ {0} := by exact mem_of_mem_inter_left hx - exact mem_of_mem_sdiff this - · apply (mem_union x A interval').mpr - left - exact mem_of_mem_inter_right hx - have h3 : (U ∩ B').Nonempty := by - rcases hB with ⟨ x, hx ⟩ - use x - simp only [mem_inter_iff] - apply And.intro - · have : x ∈ U \ { 0 } := by exact mem_of_mem_inter_left hx - exact mem_of_mem_sdiff this - · apply (mem_inter_iff x B (Ioi 0)).mpr - apply And.intro - · exact mem_of_mem_inter_right hx - · apply mem_Ioi.mpr - have : x ∈ U \ { 0 } := by exact mem_of_mem_inter_left hx - have this' : x ∉ ({ 0 } : Set NNReal) := by exact notMem_of_mem_sdiff this - exact pos_iff_ne_zero.mpr this' - specialize hp h1 h2 h3 - rcases hp with ⟨ x, hx ⟩ - use x - simp only [mem_inter_iff, mem_sdiff, mem_singleton_iff] - have hn0 : x ≠ 0 := by - have : x ∈ A' ∩ B' := by exact mem_of_mem_inter_right hx - have : x ∈ B' := by exact mem_of_mem_inter_right this - have : x ∈ Set.Ioi 0 := by exact mem_of_mem_inter_right this - exact pos_iff_ne_zero.mp this - apply And.intro - · apply And.intro - · exact mem_of_mem_inter_left hx - · exact hn0 - · apply And.intro - · have : x ∈ A' ∩ B' := by exact mem_of_mem_inter_right hx - have : x ∈ A' := by exact mem_of_mem_inter_left this - simp only [A'] at this - rcases this with (this|this) - · assumption - · have hi : x ∈ interval := by - rw [interval_def] - simp only [mem_Ioo] - dsimp [interval'] at this - simp only [mem_Iio] at this - apply And.intro - · exact pos_iff_ne_zero.mpr hn0 - · exact this - have this' := h1' hi - rcases this' with (this'|this') - · assumption - · exfalso - apply empty - use x - exact mem_inter hi this' - · have : x ∈ A' ∩ B' := by exact mem_of_mem_inter_right hx - have : x ∈ B' := by exact mem_of_mem_inter_right this - exact mem_of_mem_inter_left this - -lemma remove_zero_connected (U : Set NNReal) (h0 : 0 ∈ U) (hu : IsOpen U) (hc : IsConnected U) : - IsConnected (U \ {0}) := by - rcases Metric.isOpen_iff.mp hu 0 h0 with ⟨ ε, εpos, hε ⟩ - dsimp [IsConnected] - apply And.intro - · let ε' : NNReal := NNReal.mk (ε/2) (by linarith) - have : ε' ∈ Metric.ball 0 ε := by - simp only [Metric.mem_ball] - dsimp [ε'] - have hd : dist ε' 0 = ε/2 := by - rw [NNReal.dist_eq] - simp only [ε', NNReal.coe_mk, NNReal.coe_zero, sub_zero] - exact abs_of_nonneg (by linarith) - rw [hd] - simp only [half_lt_self_iff, gt_iff_lt] - linarith - use ε' - apply mem_sdiff_singleton.mpr - apply And.intro - · exact hε this - · apply NNReal.coe_ne_zero.mp - simp only [ne_eq, NNReal.coe_eq_zero] - dsimp [ε'] - apply NNReal.coe_ne_zero.mp - simp only [NNReal.coe_mk, ne_eq, div_eq_zero_iff, OfNat.ofNat_ne_zero, or_false] - exact ne_of_gt εpos - · have hset : U \ {0} = U ∩ Ioi 0 := by - ext x - simp only [mem_sdiff, mem_singleton_iff, mem_inter_iff, mem_Ioi, - pos_iff_ne_zero] - rw [hset] - exact (hc.isPreconnected.ordConnected.inter ordConnected_Ioi).isPreconnected - -lemma zero_in_open (a b : NNReal) (h : IsOpen ((Ioo a b) ∪ {0})) : a ≤ 0 ∧ 0 < b := by - by_contra h' - simp only [nonpos_iff_eq_zero, not_and, not_lt] at h' - by_cases ha : a = 0 - · specialize h' ha - rw [ha] at h - rw [h'] at h - simp only [lt_self_iff_false, not_false_eq_true, Ioo_eq_empty, union_singleton, - insert_empty_eq] at h - have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 - apply this - assumption - · let U := Set.Iio (a / 2) - have openU : IsOpen U := by exact isOpen_Iio - let U' := U ∩ (Ioo a b ∪ {0}) - let openU' : IsOpen U' := by exact IsOpen.inter openU h - have U0 : U' = { 0 } := by - ext x - simp only [mem_singleton_iff] - apply Iff.intro - · intro hx - dsimp [U, U'] at hx - simp only [union_singleton, mem_inter_iff, mem_Iio, mem_insert_iff, mem_Ioo] at hx - have hx1 := hx.1 - have hx2 := hx.2 - rcases hx2 with (hx2|hx2) - · exact hx2 - · have : a < x := hx2.1 - exfalso - have this' : a < a / 2 := by exact gt_trans hx1 this - have this'' : a.toReal < a.toReal / 2 := by exact this' - have this3 : 0 ≤ a.toReal := by exact NNReal.zero_le_coe - linarith - · intro hx - dsimp [U, U'] - simp only [union_singleton, mem_inter_iff, mem_Iio, mem_insert_iff, mem_Ioo] - apply And.intro - · rw [hx] - have : 0 < a := by exact pos_iff_ne_zero.mpr ha - exact half_pos this - · left; assumption - have : ¬ IsOpen ({ 0 } : Set NNReal) := not_isOpen_singleton 0 - apply this - rwa [U0] at openU' - theorem classify_connected_nnreal_interval (U : Set NNReal) (hu : IsOpen U) (hc : IsConnected U) : (∃ x y, (Set.Ioo x y = U)) ∨ (∃ (x : NNReal), (Set.Iio x = U)) ∨