Skip to content

Commit 33d9a86

Browse files
committed
feat: the disjoint union of smooth manifolds (#20659)
- the disjoint union of smooth manifolds is a smooth manifold - the interior and boundary are the disjoint union of the interior and boundary; the disjoint union of boundaryless manifolds is boundaryless A future PR will prove that `Sum.inl` and `Sum.inr` between `C^n` manifolds are C^n. From my bordism theory branch.
1 parent f8fdf24 commit 33d9a86

File tree

5 files changed

+221
-8
lines changed

5 files changed

+221
-8
lines changed

Mathlib/Data/Set/Basic.lean

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,6 +1353,11 @@ theorem compl_univ_iff {s : Set α} : sᶜ = univ ↔ s = ∅ :=
13531353
theorem compl_ne_univ : sᶜ ≠ univ ↔ s.Nonempty :=
13541354
compl_univ_iff.not.trans nonempty_iff_ne_empty.symm
13551355

1356+
lemma inl_compl_union_inr_compl {α β : Type*} {s : Set α} {t : Set β} :
1357+
Sum.inl '' sᶜ ∪ Sum.inr '' tᶜ = (Sum.inl '' s ∪ Sum.inr '' t)ᶜ := by
1358+
rw [compl_union]
1359+
aesop
1360+
13561361
theorem nonempty_compl : sᶜ.Nonempty ↔ s ≠ univ :=
13571362
(ne_univ_iff_exists_not_mem s).symm
13581363

Mathlib/Data/Sum/Basic.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ universe u v w x
1717

1818
variable {α : Type u} {α' : Type w} {β : Type v} {β' : Type x} {γ δ : Type*}
1919

20+
lemma not_isLeft_and_isRight {x : α ⊕ β} : ¬(x.isLeft ∧ x.isRight) := by simp
21+
2022
namespace Sum
2123

2224
-- Lean has removed the `@[simp]` attribute on these. For now Mathlib adds it back.

Mathlib/Geometry/Manifold/InteriorBoundary.lean

Lines changed: 130 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ of `M` and `N`.
2828
- `ModelWithCorners.boundary_prod`: the boundary of `M × N` is `∂M × N ∪ (M × ∂N)`.
2929
- `ModelWithCorners.BoundarylessManifold.prod`: if `M` and `N` are boundaryless, so is `M × N`
3030
31+
- `ModelWithCorners.interior_disjointUnion`: the interior of a disjoint union `M ⊔ M'`
32+
is the union of the interior of `M` and `M'`
33+
- `ModelWithCorners.boundary_disjointUnion`: the boundary of a disjoint union `M ⊔ M'`
34+
is the union of the boundaries of `M` and `M'`
35+
- `ModelWithCorners.boundaryless_disjointUnion`: if `M` and `M'` are boundaryless,
36+
so is their disjoint union `M ⊔ M'`
37+
3138
## Tags
3239
manifold, interior, boundary
3340
@@ -85,7 +92,7 @@ lemma isBoundaryPoint_iff {x : M} : I.IsBoundaryPoint x ↔ extChartAt I x x ∈
8592
lemma isInteriorPoint_or_isBoundaryPoint (x : M) : I.IsInteriorPoint x ∨ I.IsBoundaryPoint x := by
8693
rw [IsInteriorPoint, or_iff_not_imp_left, I.isBoundaryPoint_iff, ← closure_diff_interior,
8794
I.isClosed_range.closure_eq, mem_diff]
88-
exact fun h => ⟨mem_range_self _, h⟩
95+
exact fun h ⟨mem_range_self _, h⟩
8996

9097
/-- A manifold decomposes into interior and boundary. -/
9198
lemma interior_union_boundary_eq_univ : (I.interior M) ∪ (I.boundary M) = (univ : Set M) :=
@@ -97,13 +104,22 @@ lemma disjoint_interior_boundary : Disjoint (I.interior M) (I.boundary M) := by
97104
-- Choose some x in the intersection of interior and boundary.
98105
obtain ⟨x, h1, h2⟩ := not_disjoint_iff.mp h
99106
rw [← mem_empty_iff_false (extChartAt I x x),
100-
← disjoint_iff_inter_eq_empty.mp (disjoint_interior_frontier (s := range I)), mem_inter_iff]
107+
← disjoint_iff_inter_eq_empty.mp disjoint_interior_frontier, mem_inter_iff]
101108
exact ⟨h1, h2⟩
102109

110+
lemma isInteriorPoint_iff_not_isBoundaryPoint (x : M) :
111+
I.IsInteriorPoint x ↔ ¬I.IsBoundaryPoint x := by
112+
refine ⟨?_,
113+
by simpa only [or_iff_not_imp_right] using isInteriorPoint_or_isBoundaryPoint x (I := I)⟩
114+
by_contra! h
115+
rw [← mem_empty_iff_false (extChartAt I x x),
116+
← disjoint_iff_inter_eq_empty.mp disjoint_interior_frontier, mem_inter_iff]
117+
exact h
118+
103119
/-- The boundary is the complement of the interior. -/
104120
lemma compl_interior : (I.interior M)ᶜ = I.boundary M:= by
105121
apply compl_unique ?_ I.interior_union_boundary_eq_univ
106-
exact disjoint_iff_inter_eq_empty.mp (I.disjoint_interior_boundary)
122+
exact disjoint_iff_inter_eq_empty.mp I.disjoint_interior_boundary
107123

108124
/-- The interior is the complement of the boundary. -/
109125
lemma compl_boundary : (I.boundary M)ᶜ = I.interior M:= by
@@ -231,4 +247,115 @@ instance BoundarylessManifold.prod [BoundarylessManifold I M] [BoundarylessManif
231247

232248
end prod
233249

250+
section disjointUnion
251+
252+
variable {M' : Type*} [TopologicalSpace M'] [ChartedSpace H M'] {n : WithTop ℕ∞}
253+
[hM : IsManifold I n M] [hM' : IsManifold I n M']
254+
[Nonempty M] [Nonempty M'] [Nonempty H]
255+
{E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H']
256+
{J : Type*} {J : ModelWithCorners 𝕜 E' H'}
257+
{N N' : Type*} [TopologicalSpace N] [TopologicalSpace N'] [ChartedSpace H' N] [ChartedSpace H' N']
258+
[IsManifold J n N] [IsManifold J n N'] [Nonempty N] [Nonempty N'] [Nonempty H']
259+
260+
open Topology
261+
262+
lemma interiorPoint_inl (x : M) (hx : I.IsInteriorPoint x) :
263+
I.IsInteriorPoint (.inl x: M ⊕ M') := by
264+
rw [I.isInteriorPoint_iff, extChartAt, ChartedSpace.sum_chartAt_inl]
265+
dsimp only [PartialHomeomorph.extend.eq_1, PartialEquiv.trans_target, toPartialEquiv_coe_symm,
266+
PartialHomeomorph.lift_openEmbedding_target, PartialEquiv.coe_trans, toPartialEquiv_coe,
267+
PartialHomeomorph.toFun_eq_coe, PartialHomeomorph.lift_openEmbedding_toFun, Function.comp_apply]
268+
rw [Sum.inl_injective.extend_apply (chartAt H x)]
269+
simpa [I.isInteriorPoint_iff, extChartAt] using hx
270+
271+
lemma boundaryPoint_inl (x : M) (hx : I.IsBoundaryPoint x) :
272+
I.IsBoundaryPoint (.inl x: M ⊕ M') := by
273+
rw [I.isBoundaryPoint_iff, extChartAt, ChartedSpace.sum_chartAt_inl]
274+
dsimp
275+
rw [Sum.inl_injective.extend_apply (chartAt H x)]
276+
simpa [I.isBoundaryPoint_iff, extChartAt] using hx
277+
278+
lemma interiorPoint_inr (x : M') (hx : I.IsInteriorPoint x) :
279+
I.IsInteriorPoint (.inr x : M ⊕ M') := by
280+
rw [I.isInteriorPoint_iff, extChartAt, ChartedSpace.sum_chartAt_inr]
281+
dsimp
282+
rw [Sum.inr_injective.extend_apply (chartAt H x)]
283+
simpa [I.isInteriorPoint_iff, extChartAt] using hx
284+
285+
lemma boundaryPoint_inr (x : M') (hx : I.IsBoundaryPoint x) :
286+
I.IsBoundaryPoint (.inr x : M ⊕ M') := by
287+
rw [I.isBoundaryPoint_iff, extChartAt, ChartedSpace.sum_chartAt_inr]
288+
dsimp
289+
rw [Sum.inr_injective.extend_apply (chartAt H x)]
290+
simpa [I.isBoundaryPoint_iff, extChartAt] using hx
291+
292+
-- Converse to the previous direction: if `x` were not an interior point,
293+
-- it had to be a boundary point, hence `p` were a boundary point also, contradiction.
294+
lemma isInteriorPoint_disjointUnion_left {p : M ⊕ M'} (hp : I.IsInteriorPoint p)
295+
(hleft : Sum.isLeft p) : I.IsInteriorPoint (Sum.getLeft p hleft) := by
296+
by_contra h
297+
set x := Sum.getLeft p hleft
298+
rw [isInteriorPoint_iff_not_isBoundaryPoint x, not_not] at h
299+
rw [isInteriorPoint_iff_not_isBoundaryPoint p] at hp
300+
have := boundaryPoint_inl (M' := M') x (by tauto)
301+
rw [← Sum.eq_left_getLeft_of_isLeft hleft] at this
302+
exact hp this
303+
304+
lemma isInteriorPoint_disjointUnion_right {p : M ⊕ M'} (hp : I.IsInteriorPoint p)
305+
(hright : Sum.isRight p) : I.IsInteriorPoint (Sum.getRight p hright) := by
306+
by_contra h
307+
set x := Sum.getRight p hright
308+
rw [← mem_empty_iff_false p, ← (disjoint_interior_boundary (I := I)).inter_eq]
309+
constructor
310+
· rw [ModelWithCorners.interior, mem_setOf]; exact hp
311+
· rw [ModelWithCorners.boundary, mem_setOf, Sum.eq_right_getRight_of_isRight hright]
312+
have := isInteriorPoint_or_isBoundaryPoint (I := I) x
313+
exact boundaryPoint_inr (M' := M') x (by tauto)
314+
315+
lemma interior_disjointUnion :
316+
ModelWithCorners.interior (I := I) (M ⊕ M') =
317+
Sum.inl '' (ModelWithCorners.interior (I := I) M)
318+
∪ Sum.inr '' (ModelWithCorners.interior (I := I) M') := by
319+
ext p
320+
constructor
321+
· intro hp
322+
by_cases h : Sum.isLeft p
323+
· left
324+
exact ⟨Sum.getLeft p h, isInteriorPoint_disjointUnion_left hp h, Sum.inl_getLeft p h⟩
325+
· replace h := Sum.not_isLeft.mp h
326+
right
327+
exact ⟨Sum.getRight p h, isInteriorPoint_disjointUnion_right hp h, Sum.inr_getRight p h⟩
328+
· intro hp
329+
by_cases h : Sum.isLeft p
330+
· set x := Sum.getLeft p h with x_eq
331+
rw [Sum.eq_left_getLeft_of_isLeft h]
332+
apply interiorPoint_inl x
333+
have hp : p ∈ Sum.inl '' (ModelWithCorners.interior (I := I) M) := by
334+
obtain (good | ⟨y, hy, hxy⟩) := hp
335+
exacts [good, (not_isLeft_and_isRight ⟨h, by rw [← hxy]; exact rfl⟩).elim]
336+
obtain ⟨x', hx', hx'p⟩ := hp
337+
simpa [x_eq, ← hx'p, Sum.getLeft_inl]
338+
· set x := Sum.getRight p (Sum.not_isLeft.mp h) with x_eq
339+
rw [Sum.eq_right_getRight_of_isRight (Sum.not_isLeft.mp h)]
340+
apply interiorPoint_inr x
341+
have hp : p ∈ Sum.inr '' (ModelWithCorners.interior (I := I) M') := by
342+
obtain (⟨y, hy, hxy⟩ | good) := hp
343+
exacts [(not_isLeft_and_isRight ⟨by rw [← hxy]; exact rfl, Sum.not_isLeft.mp h⟩).elim, good]
344+
obtain ⟨x', hx', hx'p⟩ := hp
345+
simpa [x_eq, ← hx'p, Sum.getRight_inr]
346+
347+
lemma boundary_disjointUnion : ModelWithCorners.boundary (I := I) (M ⊕ M') =
348+
Sum.inl '' (ModelWithCorners.boundary (I := I) M)
349+
∪ Sum.inr '' (ModelWithCorners.boundary (I := I) M') := by
350+
simp only [← ModelWithCorners.compl_interior, interior_disjointUnion, inl_compl_union_inr_compl]
351+
352+
/-- If `M` and `M'` are boundaryless, so is their disjoint union `M ⊔ M'`. -/
353+
instance boundaryless_disjointUnion
354+
[hM: BoundarylessManifold I M] [hM': BoundarylessManifold I M'] :
355+
BoundarylessManifold I (M ⊕ M') := by
356+
rw [← Boundaryless.iff_boundary_eq_empty] at hM hM' ⊢
357+
simp [boundary_disjointUnion, hM, hM']
358+
359+
end disjointUnion
360+
234361
end ModelWithCorners

Mathlib/Geometry/Manifold/IsManifold.lean

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ but add these assumptions later as needed. (Quite a few results still do not req
4646
we register them as `PartialEquiv`s.
4747
`extChartAt I x` is the canonical such partial equiv around `x`.
4848
49+
We define a few constructions of smooth manifolds:
50+
* every empty type is a smooth manifold
51+
* the product of two smooth manifolds
52+
* the disjoint union of two manifolds (over the same charted space)
53+
4954
As specific examples of models with corners, we define (in `Geometry.Manifold.Instances.Real`)
5055
* `modelWithCornersEuclideanHalfSpace n :
5156
ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanHalfSpace n)` for the model space used to
@@ -598,6 +603,26 @@ theorem contDiffGroupoid_zero_eq : contDiffGroupoid 0 I = continuousGroupoid H :
598603
· refine I.continuous.comp_continuousOn (u.symm.continuousOn.comp I.continuousOn_symm ?_)
599604
exact (mapsTo_preimage _ _).mono_left inter_subset_left
600605

606+
-- FIXME: does this generalise to other groupoids? The argument is not specific
607+
-- to C^n functions, but uses something about the groupoid's property that is not easy to abstract.
608+
/-- Any change of coordinates with empty source belongs to `contDiffGroupoid`. -/
609+
lemma ContDiffGroupoid.mem_of_source_eq_empty (f : PartialHomeomorph H H)
610+
(hf : f.source = ∅) : f ∈ contDiffGroupoid n I := by
611+
constructor
612+
· intro x ⟨hx, _⟩
613+
rw [mem_preimage] at hx
614+
simp_all only [mem_empty_iff_false]
615+
· intro x ⟨hx, _⟩
616+
have : f.target = ∅ := by simp [← f.image_source_eq_target, hf]
617+
simp_all [hx]
618+
619+
include I in
620+
/-- Any change of coordinates with empty source belongs to `continuousGroupoid`. -/
621+
lemma ContinuousGroupoid.mem_of_source_eq_empty (f : PartialHomeomorph H H)
622+
(hf : f.source = ∅) : f ∈ continuousGroupoid H := by
623+
rw [← contDiffGroupoid_zero_eq (I := I)]
624+
exact ContDiffGroupoid.mem_of_source_eq_empty f hf
625+
601626
/-- An identity partial homeomorphism belongs to the `C^n` groupoid. -/
602627
theorem ofSet_mem_contDiffGroupoid {s : Set H} (hs : IsOpen s) :
603628
PartialHomeomorph.ofSet s hs ∈ contDiffGroupoid n I := by
@@ -797,6 +822,34 @@ instance prod {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedA
797822
have h2 := (contDiffGroupoid n I').compatible hf2 hg2
798823
exact contDiffGroupoid_prod h1 h2
799824

825+
section DisjointUnion
826+
827+
variable {M' : Type*} [TopologicalSpace M'] [ChartedSpace H M']
828+
[hM : IsManifold I n M] [hM' : IsManifold I n M']
829+
830+
/-- The disjoint union of two `C^n` manifolds modelled on `(E, H)`
831+
is a `C^n` manifold modeled on `(E, H)`. -/
832+
instance disjointUnion [Nonempty M] [Nonempty M'] [Nonempty H] : IsManifold I n (M ⊕ M') where
833+
compatible {e} e' he he' := by
834+
obtain (⟨f, hf, hef⟩ | ⟨f, hf, hef⟩) := ChartedSpace.mem_atlas_sum he
835+
· obtain (⟨f', hf', he'f'⟩ | ⟨f', hf', he'f'⟩) := ChartedSpace.mem_atlas_sum he'
836+
· rw [hef, he'f', f.lift_openEmbedding_trans f' IsOpenEmbedding.inl]
837+
exact hM.compatible hf hf'
838+
· rw [hef, he'f']
839+
apply ContDiffGroupoid.mem_of_source_eq_empty
840+
ext x
841+
exact ⟨fun ⟨hx₁, hx₂⟩ ↦ by simp_all [hx₂], fun hx ↦ hx.elim⟩
842+
· -- Analogous argument to the first case: is there a way to deduplicate?
843+
obtain (⟨f', hf', he'f'⟩ | ⟨f', hf', he'f'⟩) := ChartedSpace.mem_atlas_sum he'
844+
· rw [hef, he'f']
845+
apply ContDiffGroupoid.mem_of_source_eq_empty
846+
ext x
847+
exact ⟨fun ⟨hx₁, hx₂⟩ ↦ by simp_all [hx₂], fun hx ↦ hx.elim⟩
848+
· rw [hef, he'f', f.lift_openEmbedding_trans f' IsOpenEmbedding.inr]
849+
exact hM'.compatible hf hf'
850+
851+
end DisjointUnion
852+
800853
end IsManifold
801854

802855
theorem PartialHomeomorph.isManifold_singleton
@@ -1675,4 +1728,4 @@ instance : PathConnectedSpace (TangentSpace I x) := inferInstanceAs (PathConnect
16751728

16761729
end Real
16771730

1678-
set_option linter.style.longFile 1700
1731+
set_option linter.style.longFile 1900

Mathlib/Topology/PartialHomeomorph.lean

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,10 +1374,6 @@ lemma lift_openEmbedding_apply (e : PartialHomeomorph X Z) (hf : IsOpenEmbedding
13741374
simp_rw [e.lift_openEmbedding_toFun]
13751375
apply hf.injective.extend_apply
13761376

1377-
@[simp]
1378-
lemma lift_openEmbedding_symm (e : PartialHomeomorph X Z) (hf : IsOpenEmbedding f) :
1379-
(e.lift_openEmbedding hf).symm = f ∘ e.symm := rfl
1380-
13811377
@[simp]
13821378
lemma lift_openEmbedding_source (e : PartialHomeomorph X Z) (hf : IsOpenEmbedding f) :
13831379
(e.lift_openEmbedding hf).source = f '' e.source := rfl
@@ -1386,4 +1382,34 @@ lemma lift_openEmbedding_source (e : PartialHomeomorph X Z) (hf : IsOpenEmbeddin
13861382
lemma lift_openEmbedding_target (e : PartialHomeomorph X Z) (hf : IsOpenEmbedding f) :
13871383
(e.lift_openEmbedding hf).target = e.target := rfl
13881384

1385+
@[simp]
1386+
lemma lift_openEmbedding_symm (e : PartialHomeomorph X Z) (hf : IsOpenEmbedding f) :
1387+
(e.lift_openEmbedding hf).symm = f ∘ e.symm := rfl
1388+
1389+
@[simp]
1390+
lemma lift_openEmbedding_symm_source (e : PartialHomeomorph X Z) (hf : IsOpenEmbedding f) :
1391+
(e.lift_openEmbedding hf).symm.source = e.target := rfl
1392+
1393+
@[simp]
1394+
lemma lift_openEmbedding_symm_target (e : PartialHomeomorph X Z) (hf : IsOpenEmbedding f) :
1395+
(e.lift_openEmbedding hf).symm.target = f '' e.source := by
1396+
rw [PartialHomeomorph.symm_target, e.lift_openEmbedding_source]
1397+
1398+
lemma lift_openEmbedding_trans_apply
1399+
(e e' : PartialHomeomorph X Z) (hf : IsOpenEmbedding f) (z : Z) :
1400+
(e.lift_openEmbedding hf).symm.trans (e'.lift_openEmbedding hf) z = (e.symm.trans e') z := by
1401+
simp [hf.injective.extend_apply e']
1402+
1403+
@[simp]
1404+
lemma lift_openEmbedding_trans (e e' : PartialHomeomorph X Z) (hf : IsOpenEmbedding f) :
1405+
(e.lift_openEmbedding hf).symm.trans (e'.lift_openEmbedding hf) = e.symm.trans e' := by
1406+
ext x
1407+
· exact e.lift_openEmbedding_trans_apply e' hf x
1408+
· simp [hf.injective.extend_apply e]
1409+
· simp_rw [PartialHomeomorph.trans_source, e.lift_openEmbedding_symm_source, e.symm_source,
1410+
e.lift_openEmbedding_symm, e'.lift_openEmbedding_source]
1411+
refine ⟨fun ⟨hx, ⟨y, hy, hxy⟩⟩ ↦ ⟨hx, ?_⟩, fun ⟨hx, hx'⟩ ↦ ⟨hx, mem_image_of_mem f hx'⟩⟩
1412+
rw [mem_preimage]; rw [comp_apply] at hxy
1413+
exact (hf.injective hxy) ▸ hy
1414+
13891415
end PartialHomeomorph

0 commit comments

Comments
 (0)